You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.5 KiB

7 years ago
7 years ago
  1. package filesys
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "path"
  7. "sync"
  8. "bazil.org/fuse/fs"
  9. "bazil.org/fuse"
  10. "github.com/chrislusf/seaweedfs/weed/glog"
  11. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  12. "time"
  13. "path/filepath"
  14. )
  15. type Dir struct {
  16. Path string
  17. NodeMap map[string]fs.Node
  18. NodeMapLock sync.Mutex
  19. wfs *WFS
  20. }
  21. var _ = fs.Node(&Dir{})
  22. var _ = fs.HandleReadDirAller(&Dir{})
  23. func (dir *Dir) Attr(context context.Context, attr *fuse.Attr) error {
  24. if dir.Path == "/" {
  25. attr.Valid = time.Second
  26. attr.Mode = os.ModeDir | 0777
  27. return nil
  28. }
  29. parent, name := filepath.Split(dir.Path)
  30. var attributes *filer_pb.FuseAttributes
  31. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  32. request := &filer_pb.GetEntryAttributesRequest{
  33. Name: name,
  34. ParentDir: parent,
  35. }
  36. glog.V(1).Infof("read dir attr: %v", request)
  37. resp, err := client.GetEntryAttributes(context, request)
  38. if err != nil {
  39. glog.V(0).Infof("read dir attr %v: %v", request, err)
  40. return err
  41. }
  42. attributes = resp.Attributes
  43. return nil
  44. })
  45. if err != nil {
  46. return err
  47. }
  48. // glog.V(1).Infof("dir %s: %v", dir.Path, attributes)
  49. // glog.V(1).Infof("dir %s permission: %v", dir.Path, os.FileMode(attributes.FileMode))
  50. attr.Mode = os.FileMode(attributes.FileMode) | os.ModeDir
  51. if dir.Path == "/" && attributes.FileMode == 0 {
  52. attr.Valid = time.Second
  53. }
  54. attr.Mtime = time.Unix(attributes.Mtime, 0)
  55. attr.Ctime = time.Unix(attributes.Mtime, 0)
  56. attr.Gid = attributes.Gid
  57. attr.Uid = attributes.Uid
  58. return nil
  59. }
  60. func (dir *Dir) Create(ctx context.Context, req *fuse.CreateRequest,
  61. resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
  62. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  63. request := &filer_pb.CreateEntryRequest{
  64. Directory: dir.Path,
  65. Entry: &filer_pb.Entry{
  66. Name: req.Name,
  67. IsDirectory: req.Mode&os.ModeDir > 0,
  68. Attributes: &filer_pb.FuseAttributes{
  69. Mtime: time.Now().Unix(),
  70. FileMode: uint32(req.Mode),
  71. Uid: req.Uid,
  72. Gid: req.Gid,
  73. },
  74. },
  75. }
  76. glog.V(1).Infof("create: %v", request)
  77. if _, err := client.CreateEntry(ctx, request); err != nil {
  78. return fmt.Errorf("create file: %v", err)
  79. }
  80. return nil
  81. })
  82. if err == nil {
  83. node := &File{Name: req.Name, dir: dir, wfs: dir.wfs}
  84. dir.NodeMap[req.Name] = node
  85. return node, node, nil
  86. }
  87. return nil, nil, err
  88. }
  89. func (dir *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
  90. dir.NodeMapLock.Lock()
  91. defer dir.NodeMapLock.Unlock()
  92. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  93. request := &filer_pb.CreateEntryRequest{
  94. Directory: dir.Path,
  95. Entry: &filer_pb.Entry{
  96. Name: req.Name,
  97. IsDirectory: true,
  98. Attributes: &filer_pb.FuseAttributes{
  99. Mtime: time.Now().Unix(),
  100. FileMode: uint32(req.Mode),
  101. Uid: req.Uid,
  102. Gid: req.Gid,
  103. },
  104. },
  105. }
  106. glog.V(1).Infof("mkdir: %v", request)
  107. if _, err := client.CreateEntry(ctx, request); err != nil {
  108. glog.V(0).Infof("mkdir %v: %v", request, err)
  109. return fmt.Errorf("make dir: %v", err)
  110. }
  111. return nil
  112. })
  113. if err == nil {
  114. node := &Dir{Path: path.Join(dir.Path, req.Name), wfs: dir.wfs}
  115. dir.NodeMap[req.Name] = node
  116. return node, nil
  117. }
  118. return nil, err
  119. }
  120. func (dir *Dir) Lookup(ctx context.Context, name string) (node fs.Node, err error) {
  121. dir.NodeMapLock.Lock()
  122. defer dir.NodeMapLock.Unlock()
  123. if dir.NodeMap == nil {
  124. dir.NodeMap = make(map[string]fs.Node)
  125. }
  126. if node, ok := dir.NodeMap[name]; ok {
  127. return node, nil
  128. }
  129. var entry *filer_pb.Entry
  130. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  131. request := &filer_pb.LookupDirectoryEntryRequest{
  132. Directory: dir.Path,
  133. Name: name,
  134. }
  135. glog.V(1).Infof("lookup directory entry: %v", request)
  136. resp, err := client.LookupDirectoryEntry(ctx, request)
  137. if err != nil {
  138. return err
  139. }
  140. entry = resp.Entry
  141. return nil
  142. })
  143. if entry != nil {
  144. if entry.IsDirectory {
  145. node = &Dir{Path: path.Join(dir.Path, name), wfs: dir.wfs}
  146. } else {
  147. node = &File{Chunks: entry.Chunks, Name: name, dir: dir, wfs: dir.wfs}
  148. }
  149. dir.NodeMap[name] = node
  150. return node, nil
  151. }
  152. return nil, fuse.ENOENT
  153. }
  154. func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
  155. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  156. request := &filer_pb.ListEntriesRequest{
  157. Directory: dir.Path,
  158. }
  159. glog.V(1).Infof("read directory: %v", request)
  160. resp, err := client.ListEntries(ctx, request)
  161. if err != nil {
  162. return err
  163. }
  164. for _, entry := range resp.Entries {
  165. if entry.IsDirectory {
  166. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_Dir}
  167. ret = append(ret, dirent)
  168. } else {
  169. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_File}
  170. ret = append(ret, dirent)
  171. dir.wfs.listDirectoryEntriesCache.Set(dir.Path+"/"+entry.Name, entry.Attributes, 300*time.Millisecond)
  172. }
  173. }
  174. return nil
  175. })
  176. return ret, err
  177. }
  178. func (dir *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
  179. dir.NodeMapLock.Lock()
  180. defer dir.NodeMapLock.Unlock()
  181. return dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  182. request := &filer_pb.DeleteEntryRequest{
  183. Directory: dir.Path,
  184. Name: req.Name,
  185. IsDirectory: req.Dir,
  186. }
  187. glog.V(1).Infof("remove directory entry: %v", request)
  188. _, err := client.DeleteEntry(ctx, request)
  189. if err != nil {
  190. return err
  191. }
  192. delete(dir.NodeMap, req.Name)
  193. return nil
  194. })
  195. }