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.

263 lines
5.6 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) newFile(name string, chunks []*filer_pb.FileChunk) *File {
  61. return &File{
  62. Name: name,
  63. dir: dir,
  64. wfs: dir.wfs,
  65. // attributes: &filer_pb.FuseAttributes{},
  66. Chunks: chunks,
  67. }
  68. }
  69. func (dir *Dir) Create(ctx context.Context, req *fuse.CreateRequest,
  70. resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
  71. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  72. request := &filer_pb.CreateEntryRequest{
  73. Directory: dir.Path,
  74. Entry: &filer_pb.Entry{
  75. Name: req.Name,
  76. IsDirectory: req.Mode&os.ModeDir > 0,
  77. Attributes: &filer_pb.FuseAttributes{
  78. Mtime: time.Now().Unix(),
  79. FileMode: uint32(req.Mode),
  80. Uid: req.Uid,
  81. Gid: req.Gid,
  82. },
  83. },
  84. }
  85. glog.V(1).Infof("create: %v", request)
  86. if _, err := client.CreateEntry(ctx, request); err != nil {
  87. return fmt.Errorf("create file: %v", err)
  88. }
  89. return nil
  90. })
  91. if err == nil {
  92. node := dir.newFile(req.Name, nil)
  93. dir.NodeMap[req.Name] = node
  94. return node, node, nil
  95. }
  96. return nil, nil, err
  97. }
  98. func (dir *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
  99. dir.NodeMapLock.Lock()
  100. defer dir.NodeMapLock.Unlock()
  101. err := dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  102. request := &filer_pb.CreateEntryRequest{
  103. Directory: dir.Path,
  104. Entry: &filer_pb.Entry{
  105. Name: req.Name,
  106. IsDirectory: true,
  107. Attributes: &filer_pb.FuseAttributes{
  108. Mtime: time.Now().Unix(),
  109. FileMode: uint32(req.Mode),
  110. Uid: req.Uid,
  111. Gid: req.Gid,
  112. },
  113. },
  114. }
  115. glog.V(1).Infof("mkdir: %v", request)
  116. if _, err := client.CreateEntry(ctx, request); err != nil {
  117. glog.V(0).Infof("mkdir %v: %v", request, err)
  118. return fmt.Errorf("make dir: %v", err)
  119. }
  120. return nil
  121. })
  122. if err == nil {
  123. node := &Dir{Path: path.Join(dir.Path, req.Name), wfs: dir.wfs}
  124. dir.NodeMap[req.Name] = node
  125. return node, nil
  126. }
  127. return nil, err
  128. }
  129. func (dir *Dir) Lookup(ctx context.Context, name string) (node fs.Node, err error) {
  130. dir.NodeMapLock.Lock()
  131. defer dir.NodeMapLock.Unlock()
  132. if dir.NodeMap == nil {
  133. dir.NodeMap = make(map[string]fs.Node)
  134. }
  135. if node, ok := dir.NodeMap[name]; ok {
  136. return node, nil
  137. }
  138. var entry *filer_pb.Entry
  139. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  140. request := &filer_pb.LookupDirectoryEntryRequest{
  141. Directory: dir.Path,
  142. Name: name,
  143. }
  144. glog.V(4).Infof("lookup directory entry: %v", request)
  145. resp, err := client.LookupDirectoryEntry(ctx, request)
  146. if err != nil {
  147. return err
  148. }
  149. entry = resp.Entry
  150. return nil
  151. })
  152. if entry != nil {
  153. if entry.IsDirectory {
  154. node = &Dir{Path: path.Join(dir.Path, name), wfs: dir.wfs}
  155. } else {
  156. node = dir.newFile(name, entry.Chunks)
  157. }
  158. dir.NodeMap[name] = node
  159. return node, nil
  160. }
  161. return nil, fuse.ENOENT
  162. }
  163. func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
  164. err = dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  165. request := &filer_pb.ListEntriesRequest{
  166. Directory: dir.Path,
  167. }
  168. glog.V(4).Infof("read directory: %v", request)
  169. resp, err := client.ListEntries(ctx, request)
  170. if err != nil {
  171. return err
  172. }
  173. for _, entry := range resp.Entries {
  174. if entry.IsDirectory {
  175. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_Dir}
  176. ret = append(ret, dirent)
  177. } else {
  178. dirent := fuse.Dirent{Name: entry.Name, Type: fuse.DT_File}
  179. ret = append(ret, dirent)
  180. dir.wfs.listDirectoryEntriesCache.Set(dir.Path+"/"+entry.Name, entry, 300*time.Millisecond)
  181. }
  182. }
  183. return nil
  184. })
  185. return ret, err
  186. }
  187. func (dir *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
  188. dir.NodeMapLock.Lock()
  189. defer dir.NodeMapLock.Unlock()
  190. return dir.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  191. request := &filer_pb.DeleteEntryRequest{
  192. Directory: dir.Path,
  193. Name: req.Name,
  194. IsDirectory: req.Dir,
  195. }
  196. glog.V(1).Infof("remove directory entry: %v", request)
  197. _, err := client.DeleteEntry(ctx, request)
  198. if err != nil {
  199. return err
  200. }
  201. delete(dir.NodeMap, req.Name)
  202. return nil
  203. })
  204. }