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

fuse_bucket.go 5.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package vfs
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "time"
  7. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  8. "gitlink.org.cn/cloudream/storage/client2/internal/mount/fuse"
  9. "gitlink.org.cn/cloudream/storage/client2/internal/mount/vfs/cache"
  10. "gitlink.org.cn/cloudream/storage/common/pkgs/db2"
  11. "gorm.io/gorm"
  12. )
  13. type FuseBucket struct {
  14. vfs *Vfs
  15. name string
  16. modTime time.Time
  17. }
  18. func newBucketFromCache(c cache.CacheEntryInfo, vfs *Vfs) fuse.FsDir {
  19. return &FuseBucket{
  20. vfs: vfs,
  21. name: c.PathComps[len(c.PathComps)-1],
  22. modTime: c.ModTime,
  23. }
  24. }
  25. func (r *FuseBucket) PathComps() []string {
  26. return []string{r.name}
  27. }
  28. func (r *FuseBucket) Name() string {
  29. return r.name
  30. }
  31. func (r *FuseBucket) Size() int64 {
  32. return 0
  33. }
  34. func (r *FuseBucket) Mode() os.FileMode {
  35. return os.ModeDir | 0755
  36. }
  37. func (r *FuseBucket) ModTime() time.Time {
  38. return r.modTime
  39. }
  40. func (r *FuseBucket) IsDir() bool {
  41. return true
  42. }
  43. func (r *FuseBucket) SetModTime(time time.Time) error {
  44. dir := r.loadCacheDir()
  45. if dir == nil {
  46. return fuse.ErrNotExists
  47. }
  48. return dir.SetModTime(time)
  49. }
  50. // 如果不存在,应该返回ErrNotExists
  51. func (r *FuseBucket) Child(ctx context.Context, name string) (fuse.FsEntry, error) {
  52. childPathComps := []string{r.name, name}
  53. ca := r.vfs.cache.Stat(childPathComps)
  54. if ca == nil {
  55. // TODO UserID
  56. pkg, err := r.vfs.db.Package().GetUserPackageByName(r.vfs.db.DefCtx(), 1, r.name, name)
  57. if err == nil {
  58. dir := r.vfs.cache.LoadDir(childPathComps, &cache.CreateDirOption{
  59. ModTime: pkg.CreateTime,
  60. })
  61. if dir == nil {
  62. return nil, fuse.ErrNotExists
  63. }
  64. return newPackageFromCache(dir.Info(), r.vfs), nil
  65. }
  66. if err == gorm.ErrRecordNotFound {
  67. return nil, fuse.ErrNotExists
  68. }
  69. return nil, err
  70. }
  71. if ca.IsDir {
  72. return newPackageFromCache(*ca, r.vfs), nil
  73. }
  74. return newFileFromCache(*ca, r.vfs), nil
  75. }
  76. func (r *FuseBucket) Children(ctx context.Context) ([]fuse.FsEntry, error) {
  77. return r.listChildren()
  78. }
  79. func (r *FuseBucket) ReadChildren() (fuse.DirReader, error) {
  80. ens, err := r.listChildren()
  81. if err != nil {
  82. return nil, err
  83. }
  84. return newFuseDirReader(ens), nil
  85. }
  86. func (r *FuseBucket) listChildren() ([]fuse.FsEntry, error) {
  87. var ens []fuse.FsEntry
  88. infos := r.vfs.cache.StatMany([]string{r.name})
  89. pkgs, err := r.vfs.db.Package().GetBucketPackagesByName(r.vfs.db.DefCtx(), r.name)
  90. if err != nil {
  91. return nil, err
  92. }
  93. pkgMap := make(map[string]*cdssdk.Package)
  94. for _, pkg := range pkgs {
  95. p := pkg
  96. pkgMap[pkg.Name] = &p
  97. }
  98. for _, c := range infos {
  99. delete(pkgMap, c.PathComps[len(c.PathComps)-1])
  100. if c.IsDir {
  101. ens = append(ens, newPackageFromCache(c, r.vfs))
  102. } else {
  103. ens = append(ens, newFileFromCache(c, r.vfs))
  104. }
  105. }
  106. for _, pkg := range pkgMap {
  107. dir := r.vfs.cache.LoadDir([]string{r.name, pkg.Name}, &cache.CreateDirOption{
  108. ModTime: pkg.CreateTime,
  109. })
  110. if dir == nil {
  111. continue
  112. }
  113. ens = append(ens, newPackageFromCache(dir.Info(), r.vfs))
  114. }
  115. return ens, nil
  116. }
  117. func (r *FuseBucket) NewDir(ctx context.Context, name string) (fuse.FsDir, error) {
  118. cache := r.vfs.cache.CreateDir([]string{r.name, name})
  119. if cache == nil {
  120. return nil, fuse.ErrPermission
  121. }
  122. // TODO 用户ID,失败了可以打个日志
  123. // TODO 生成系统事件
  124. // 不关注创建是否成功,仅尝试一下
  125. r.vfs.db.DoTx(func(tx db2.SQLContext) error {
  126. db := r.vfs.db
  127. bkt, err := db.Bucket().GetByName(tx, name)
  128. if err != nil {
  129. return fmt.Errorf("get bucket: %v", err)
  130. }
  131. _, err = db.Package().Create(tx, bkt.BucketID, name)
  132. if err != nil {
  133. return fmt.Errorf("create package: %v", err)
  134. }
  135. return err
  136. })
  137. return newPackageFromCache(cache.Info(), r.vfs), nil
  138. }
  139. func (r *FuseBucket) NewFile(ctx context.Context, name string, flags uint32) (fuse.FileHandle, error) {
  140. cache := r.vfs.cache.CreateFile([]string{r.name, name})
  141. if cache == nil {
  142. return nil, fuse.ErrPermission
  143. }
  144. // Open之后会给cache的引用计数额外+1,即使cache先于FileHandle被关闭,
  145. // 也有有FileHandle的计数保持cache的有效性
  146. fileNode := newFileFromCache(cache.Info(), r.vfs)
  147. if flags&uint32(os.O_WRONLY) != 0 {
  148. hd := cache.Open(false)
  149. return newFileHandle(fileNode, hd), nil
  150. }
  151. if flags&uint32(os.O_RDONLY) != 0 {
  152. hd := cache.Open(true)
  153. return newFileHandle(fileNode, hd), nil
  154. }
  155. return nil, fuse.ErrPermission
  156. }
  157. func (r *FuseBucket) RemoveChild(ctx context.Context, name string) error {
  158. err := r.vfs.cache.Remove([]string{r.name, name})
  159. if err != nil {
  160. return err
  161. }
  162. // TODO 生成系统事件
  163. // 不关心是否成功
  164. r.vfs.db.DoTx(func(tx db2.SQLContext) error {
  165. d := r.vfs.db
  166. pkg, err := d.Package().GetUserPackageByName(tx, 1, r.name, name)
  167. if err != nil {
  168. if err == gorm.ErrRecordNotFound {
  169. return nil
  170. }
  171. }
  172. return d.Package().DeleteComplete(tx, pkg.PackageID)
  173. })
  174. return nil
  175. }
  176. func (r *FuseBucket) MoveChild(ctx context.Context, oldName string, newName string, newParent fuse.FsDir) error {
  177. // TODO 有问题
  178. newParentNode := newParent.(FuseNode)
  179. _, err := r.vfs.cache.Move([]string{r.name, oldName}, append(newParentNode.PathComps(), newName))
  180. if err != nil {
  181. return err
  182. }
  183. return nil
  184. }
  185. func (r *FuseBucket) loadCacheDir() *cache.CacheDir {
  186. var createOpt *cache.CreateDirOption
  187. bkt, err := r.vfs.db.Bucket().GetByName(r.vfs.db.DefCtx(), r.name)
  188. if err == nil {
  189. createOpt = &cache.CreateDirOption{
  190. ModTime: bkt.CreateTime,
  191. }
  192. }
  193. return r.vfs.cache.LoadDir([]string{r.name}, createOpt)
  194. }
  195. var _ fuse.FsDir = (*FuseBucket)(nil)
  196. var _ FuseNode = (*FuseBucket)(nil)

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。