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.

206 lines
4.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. )
  14. type Dir struct {
  15. Path string
  16. NodeMap map[string]fs.Node
  17. NodeMapLock sync.Mutex
  18. wfs *WFS
  19. }
  20. var _ = fs.Node(&Dir{})
  21. var _ = fs.HandleReadDirAller(&Dir{})
  22. func (dir *Dir) Attr(context context.Context, attr *fuse.Attr) error {
  23. attr.Mode = os.ModeDir | 0777
  24. return nil
  25. }
  26. func (dir *Dir) Create(ctx context.Context, req *fuse.CreateRequest,
  27. resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
  28. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  29. request := &filer_pb.CreateEntryRequest{
  30. Directory: dir.Path,
  31. Entry: &filer_pb.Entry{
  32. Name: req.Name,
  33. IsDirectory: req.Mode&os.ModeDir > 0,
  34. Attributes: &filer_pb.FuseAttributes{
  35. Mtime: time.Now().Unix(),
  36. FileMode: uint32(req.Mode),
  37. Uid: req.Uid,
  38. Gid: req.Gid,
  39. },
  40. },
  41. }
  42. glog.V(1).Infof("create: %v", request)
  43. if _, err := client.CreateEntry(ctx, request); err != nil {
  44. return fmt.Errorf("create file: %v", err)
  45. }
  46. return nil
  47. })
  48. if err == nil {
  49. node := &File{Name: req.Name, dir: dir, wfs: dir.wfs}
  50. dir.NodeMap[req.Name] = node
  51. return node, node, nil
  52. }
  53. return nil, nil, err
  54. }
  55. func (dir *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
  56. dir.NodeMapLock.Lock()
  57. defer dir.NodeMapLock.Unlock()
  58. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  59. request := &filer_pb.CreateEntryRequest{
  60. Directory: dir.Path,
  61. Entry: &filer_pb.Entry{
  62. Name: req.Name,
  63. IsDirectory: true,
  64. Attributes: &filer_pb.FuseAttributes{
  65. Mtime: time.Now().Unix(),
  66. FileMode: uint32(req.Mode),
  67. Uid: req.Uid,
  68. Gid: req.Gid,
  69. },
  70. },
  71. }
  72. glog.V(1).Infof("mkdir: %v", request)
  73. if _, err := client.CreateEntry(ctx, request); err != nil {
  74. glog.V(0).Infof("mkdir %v: %v", request, err)
  75. return fmt.Errorf("make dir: %v", err)
  76. }
  77. return nil
  78. })
  79. if err == nil {
  80. node := &Dir{Path: path.Join(dir.Path, req.Name), wfs: dir.wfs}
  81. dir.NodeMap[req.Name] = node
  82. return node, nil
  83. }
  84. return nil, err
  85. }
  86. func (dir *Dir) Lookup(ctx context.Context, name string) (node fs.Node, err error) {
  87. dir.NodeMapLock.Lock()
  88. defer dir.NodeMapLock.Unlock()
  89. if dir.NodeMap == nil {
  90. dir.NodeMap = make(map[string]fs.Node)
  91. }
  92. if node, ok := dir.NodeMap[name]; ok {
  93. return node, nil
  94. }
  95. var entry *filer_pb.Entry
  96. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  97. request := &filer_pb.LookupDirectoryEntryRequest{
  98. Directory: dir.Path,
  99. Name: name,
  100. }
  101. glog.V(1).Infof("lookup directory entry: %v", request)
  102. resp, err := client.LookupDirectoryEntry(ctx, request)
  103. if err != nil {
  104. return err
  105. }
  106. entry = resp.Entry
  107. return nil
  108. })
  109. if entry != nil {
  110. if entry.IsDirectory {
  111. node = &Dir{Path: path.Join(dir.Path, name), wfs: dir.wfs}
  112. } else {
  113. node = &File{Chunks: entry.Chunks, Name: name, dir: dir, wfs: dir.wfs}
  114. }
  115. dir.NodeMap[name] = node
  116. return node, nil
  117. }
  118. return nil, fuse.ENOENT
  119. }
  120. func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
  121. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  122. request := &filer_pb.ListEntriesRequest{
  123. Directory: dir.Path,
  124. }
  125. glog.V(1).Infof("read directory: %v", request)
  126. resp, err := client.ListEntries(ctx, request)
  127. if err != nil {
  128. return err
  129. }
  130. for _, entry := range resp.Entries {
  131. if entry.IsDirectory {
  132. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_Dir}
  133. ret = append(ret, dirent)
  134. } else {
  135. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_File}
  136. ret = append(ret, dirent)
  137. dir.wfs.listDirectoryEntriesCache.Set(dir.Path+"/"+entry.Name, entry.Attributes, 3*time.Second)
  138. }
  139. }
  140. return nil
  141. })
  142. return ret, err
  143. }
  144. func (dir *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
  145. dir.NodeMapLock.Lock()
  146. defer dir.NodeMapLock.Unlock()
  147. return dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  148. request := &filer_pb.DeleteEntryRequest{
  149. Directory: dir.Path,
  150. Name: req.Name,
  151. IsDirectory: req.Dir,
  152. }
  153. glog.V(1).Infof("remove directory entry: %v", request)
  154. _, err := client.DeleteEntry(ctx, request)
  155. if err != nil {
  156. return err
  157. }
  158. delete(dir.NodeMap, req.Name)
  159. return nil
  160. })
  161. }