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_root.go 5.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package vfs
  2. import (
  3. "context"
  4. "os"
  5. "time"
  6. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  7. "gitlink.org.cn/cloudream/storage2/client2/internal/mount/fuse"
  8. "gitlink.org.cn/cloudream/storage2/client2/internal/mount/vfs/cache"
  9. "gitlink.org.cn/cloudream/storage2/common/pkgs/db2"
  10. "gorm.io/gorm"
  11. )
  12. type FuseRoot struct {
  13. vfs *Vfs
  14. }
  15. func newRoot(vfs *Vfs) *FuseRoot {
  16. return &FuseRoot{
  17. vfs: vfs,
  18. }
  19. }
  20. func (r *FuseRoot) PathComps() []string {
  21. return []string{}
  22. }
  23. func (r *FuseRoot) Name() string {
  24. return ""
  25. }
  26. func (r *FuseRoot) Size() int64 {
  27. return 0
  28. }
  29. func (r *FuseRoot) Mode() os.FileMode {
  30. return os.ModeDir | 0755
  31. }
  32. func (r *FuseRoot) ModTime() time.Time {
  33. return time.Now()
  34. }
  35. func (r *FuseRoot) IsDir() bool {
  36. return true
  37. }
  38. func (r *FuseRoot) SetModTime(time time.Time) error {
  39. return nil
  40. }
  41. // 如果不存在,应该返回ErrNotExists
  42. func (r *FuseRoot) Child(ctx context.Context, name string) (fuse.FsEntry, error) {
  43. ca := r.vfs.cache.Stat([]string{name})
  44. if ca == nil {
  45. bkt, err := r.vfs.db.Bucket().GetByName(r.vfs.db.DefCtx(), name)
  46. if err == nil {
  47. dir := r.vfs.cache.LoadDir([]string{name}, &cache.CreateDirOption{
  48. ModTime: bkt.CreateTime,
  49. })
  50. if dir == nil {
  51. return nil, fuse.ErrNotExists
  52. }
  53. return newBucketFromCache(dir.Info(), r.vfs), nil
  54. }
  55. if err == gorm.ErrRecordNotFound {
  56. return nil, fuse.ErrNotExists
  57. }
  58. return nil, err
  59. }
  60. if ca.IsDir {
  61. return newBucketFromCache(*ca, r.vfs), nil
  62. }
  63. return newFileFromCache(*ca, r.vfs), nil
  64. }
  65. func (r *FuseRoot) Children(ctx context.Context) ([]fuse.FsEntry, error) {
  66. return r.listChildren()
  67. }
  68. func (r *FuseRoot) ReadChildren() (fuse.DirReader, error) {
  69. ens, err := r.listChildren()
  70. if err != nil {
  71. return nil, err
  72. }
  73. return newFuseDirReader(ens), nil
  74. }
  75. func (r *FuseRoot) listChildren() ([]fuse.FsEntry, error) {
  76. var ens []fuse.FsEntry
  77. infos := r.vfs.cache.StatMany([]string{})
  78. bkts, err := r.vfs.db.Bucket().GetAll(r.vfs.db.DefCtx())
  79. if err != nil {
  80. return nil, err
  81. }
  82. bktMap := make(map[string]*cdssdk.Bucket)
  83. for _, bkt := range bkts {
  84. b := bkt
  85. bktMap[bkt.Name] = &b
  86. }
  87. for _, c := range infos {
  88. delete(bktMap, c.PathComps[len(c.PathComps)-1])
  89. if c.IsDir {
  90. ens = append(ens, newBucketFromCache(c, r.vfs))
  91. } else {
  92. ens = append(ens, newFileFromCache(c, r.vfs))
  93. }
  94. }
  95. // 将远端目录同步到本地缓存中,防止在给目录中的远端对象创建本地缓存时,顺便创建的目录的元数据不对的情况
  96. for _, bkt := range bktMap {
  97. dir := r.vfs.cache.LoadDir([]string{bkt.Name}, &cache.CreateDirOption{
  98. ModTime: bkt.CreateTime,
  99. })
  100. if dir == nil {
  101. continue
  102. }
  103. ens = append(ens, newBucketFromCache(dir.Info(), r.vfs))
  104. }
  105. return ens, nil
  106. }
  107. func (r *FuseRoot) NewDir(ctx context.Context, name string) (fuse.FsDir, error) {
  108. cache := r.vfs.cache.CreateDir([]string{name})
  109. if cache == nil {
  110. return nil, fuse.ErrPermission
  111. }
  112. // TODO 用户ID,失败了可以打个日志
  113. // TODO 生成系统事件
  114. // 不关注创建是否成功,仅尝试一下
  115. r.vfs.db.Bucket().Create(r.vfs.db.DefCtx(), 1, name, cache.ModTime())
  116. return newBucketFromCache(cache.Info(), r.vfs), nil
  117. }
  118. func (r *FuseRoot) NewFile(ctx context.Context, name string, flags uint32) (fuse.FileHandle, uint32, error) {
  119. cache := r.vfs.cache.CreateFile([]string{name})
  120. if cache == nil {
  121. return nil, 0, fuse.ErrPermission
  122. }
  123. defer cache.Release()
  124. // Open之后会给cache的引用计数额外+1,即使cache先于FileHandle被关闭,
  125. // 也有有FileHandle的计数保持cache的有效性
  126. fileNode := newFileFromCache(cache.Info(), r.vfs)
  127. hd := cache.Open(flags)
  128. return newFileHandle(fileNode, hd), flags, nil
  129. }
  130. func (r *FuseRoot) RemoveChild(ctx context.Context, name string) error {
  131. // TODO 生成系统事件
  132. db := r.vfs.db
  133. return r.vfs.db.DoTx(func(tx db2.SQLContext) error {
  134. bkt, err := db.Bucket().GetByName(tx, name)
  135. if err == nil {
  136. has, err := db.Package().HasPackageIn(tx, bkt.BucketID)
  137. if err != nil {
  138. return err
  139. }
  140. if has {
  141. return fuse.ErrNotEmpty
  142. }
  143. } else if err != gorm.ErrRecordNotFound {
  144. return err
  145. }
  146. err = r.vfs.cache.Remove([]string{name})
  147. if err != nil {
  148. return err
  149. }
  150. if bkt.BucketID != 0 {
  151. // 不管是否成功
  152. db.Bucket().DeleteComplete(tx, bkt.BucketID)
  153. }
  154. return nil
  155. })
  156. }
  157. func (r *FuseRoot) MoveChild(ctx context.Context, oldName string, newName string, newParent fuse.FsDir) error {
  158. newParentNode := newParent.(FuseNode)
  159. newParentPath := newParentNode.PathComps()
  160. // 只允许同层级内改名
  161. if len(newParentPath) != 0 {
  162. return fuse.ErrNotSupported
  163. }
  164. d := r.vfs.db
  165. return d.DoTx(func(tx db2.SQLContext) error {
  166. _, err := d.Bucket().GetByName(tx, newName)
  167. if err == nil {
  168. // 目标节点已经存在,不能重命名,直接退出
  169. return fuse.ErrExists
  170. }
  171. oldBkt, err := d.Bucket().GetByName(tx, oldName)
  172. if err == nil {
  173. err = d.Bucket().Rename(tx, oldBkt.BucketID, newName)
  174. if err != nil {
  175. return err
  176. }
  177. } else if err != gorm.ErrRecordNotFound {
  178. return err
  179. }
  180. return r.vfs.cache.Move([]string{oldName}, []string{newName})
  181. })
  182. }
  183. var _ fuse.FsDir = (*FuseRoot)(nil)
  184. var _ FuseNode = (*FuseRoot)(nil)

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