weedfs_dir_read.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package mount
  2. import (
  3. "context"
  4. "github.com/chrislusf/seaweedfs/weed/filer"
  5. "github.com/chrislusf/seaweedfs/weed/glog"
  6. "github.com/chrislusf/seaweedfs/weed/mount/meta_cache"
  7. "github.com/chrislusf/seaweedfs/weed/util"
  8. "github.com/hanwen/go-fuse/v2/fuse"
  9. "math"
  10. "os"
  11. )
  12. // Directory handling
  13. /** Open directory
  14. *
  15. * Unless the 'default_permissions' mount option is given,
  16. * this method should check if opendir is permitted for this
  17. * directory. Optionally opendir may also return an arbitrary
  18. * filehandle in the fuse_file_info structure, which will be
  19. * passed to readdir, releasedir and fsyncdir.
  20. */
  21. func (wfs *WFS) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
  22. if !wfs.inodeToPath.HasInode(input.NodeId) {
  23. return fuse.ENOENT
  24. }
  25. return fuse.OK
  26. }
  27. /** Release directory
  28. *
  29. * If the directory has been removed after the call to opendir, the
  30. * path parameter will be NULL.
  31. */
  32. func (wfs *WFS) ReleaseDir(input *fuse.ReleaseIn) {
  33. }
  34. /** Synchronize directory contents
  35. *
  36. * If the directory has been removed after the call to opendir, the
  37. * path parameter will be NULL.
  38. *
  39. * If the datasync parameter is non-zero, then only the user data
  40. * should be flushed, not the meta data
  41. */
  42. func (wfs *WFS) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) (code fuse.Status) {
  43. return fuse.OK
  44. }
  45. /** Read directory
  46. *
  47. * The filesystem may choose between two modes of operation:
  48. *
  49. * 1) The readdir implementation ignores the offset parameter, and
  50. * passes zero to the filler function's offset. The filler
  51. * function will not return '1' (unless an error happens), so the
  52. * whole directory is read in a single readdir operation.
  53. *
  54. * 2) The readdir implementation keeps track of the offsets of the
  55. * directory entries. It uses the offset parameter and always
  56. * passes non-zero offset to the filler function. When the buffer
  57. * is full (or an error happens) the filler function will return
  58. * '1'.
  59. */
  60. func (wfs *WFS) ReadDir(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
  61. return wfs.doReadDirectory(input, out, false)
  62. }
  63. func (wfs *WFS) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
  64. return wfs.doReadDirectory(input, out, true)
  65. }
  66. func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPlusMode bool) fuse.Status {
  67. dirPath := wfs.inodeToPath.GetPath(input.NodeId)
  68. var counter uint64
  69. var dirEntry fuse.DirEntry
  70. if input.Offset == 0 {
  71. counter++
  72. dirEntry.Ino = input.NodeId
  73. dirEntry.Name = "."
  74. dirEntry.Mode = toSystemMode(os.ModeDir)
  75. out.AddDirEntry(dirEntry)
  76. counter++
  77. parentDir, _ := dirPath.DirAndName()
  78. parentInode := wfs.inodeToPath.GetInode(util.FullPath(parentDir))
  79. dirEntry.Ino = parentInode
  80. dirEntry.Name = ".."
  81. dirEntry.Mode = toSystemMode(os.ModeDir)
  82. out.AddDirEntry(dirEntry)
  83. }
  84. processEachEntryFn := func(entry *filer.Entry, isLast bool) bool {
  85. counter++
  86. if counter <= input.Offset {
  87. return true
  88. }
  89. dirEntry.Name = entry.Name()
  90. inode := wfs.inodeToPath.GetInode(dirPath.Child(dirEntry.Name))
  91. dirEntry.Ino = inode
  92. dirEntry.Mode = toSystemMode(entry.Mode)
  93. if !isPlusMode {
  94. if !out.AddDirEntry(dirEntry) {
  95. return false
  96. }
  97. } else {
  98. entryOut := out.AddDirLookupEntry(dirEntry)
  99. if entryOut == nil {
  100. return false
  101. }
  102. wfs.outputFilerEntry(entryOut, inode, entry)
  103. }
  104. return true
  105. }
  106. if err := meta_cache.EnsureVisited(wfs.metaCache, wfs, dirPath); err != nil {
  107. glog.Errorf("dir ReadDirAll %s: %v", dirPath, err)
  108. return fuse.EIO
  109. }
  110. listErr := wfs.metaCache.ListDirectoryEntries(context.Background(), dirPath, "", false, int64(math.MaxInt32), func(entry *filer.Entry) bool {
  111. return processEachEntryFn(entry, false)
  112. })
  113. if listErr != nil {
  114. glog.Errorf("list meta cache: %v", listErr)
  115. return fuse.EIO
  116. }
  117. return fuse.OK
  118. }