|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- package vfs
-
- import (
- "context"
- "os"
- "time"
-
- cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
- "gitlink.org.cn/cloudream/storage2/client2/internal/mount/fuse"
- "gitlink.org.cn/cloudream/storage2/client2/internal/mount/vfs/cache"
- "gitlink.org.cn/cloudream/storage2/common/pkgs/db2"
- "gorm.io/gorm"
- )
-
- type FuseRoot struct {
- vfs *Vfs
- }
-
- func newRoot(vfs *Vfs) *FuseRoot {
- return &FuseRoot{
- vfs: vfs,
- }
- }
-
- func (r *FuseRoot) PathComps() []string {
- return []string{}
- }
-
- func (r *FuseRoot) Name() string {
- return ""
- }
-
- func (r *FuseRoot) Size() int64 {
- return 0
- }
-
- func (r *FuseRoot) Mode() os.FileMode {
- return os.ModeDir | 0755
- }
-
- func (r *FuseRoot) ModTime() time.Time {
- return time.Now()
- }
-
- func (r *FuseRoot) IsDir() bool {
- return true
- }
-
- func (r *FuseRoot) SetModTime(time time.Time) error {
- return nil
- }
-
- // 如果不存在,应该返回ErrNotExists
- func (r *FuseRoot) Child(ctx context.Context, name string) (fuse.FsEntry, error) {
- ca := r.vfs.cache.Stat([]string{name})
-
- if ca == nil {
- bkt, err := r.vfs.db.Bucket().GetByName(r.vfs.db.DefCtx(), name)
- if err == nil {
- dir := r.vfs.cache.LoadDir([]string{name}, &cache.CreateDirOption{
- ModTime: bkt.CreateTime,
- })
- if dir == nil {
- return nil, fuse.ErrNotExists
- }
-
- return newBucketFromCache(dir.Info(), r.vfs), nil
- }
-
- if err == gorm.ErrRecordNotFound {
- return nil, fuse.ErrNotExists
- }
-
- return nil, err
- }
-
- if ca.IsDir {
- return newBucketFromCache(*ca, r.vfs), nil
- }
-
- return newFileFromCache(*ca, r.vfs), nil
- }
-
- func (r *FuseRoot) Children(ctx context.Context) ([]fuse.FsEntry, error) {
- return r.listChildren()
- }
-
- func (r *FuseRoot) ReadChildren() (fuse.DirReader, error) {
- ens, err := r.listChildren()
- if err != nil {
- return nil, err
- }
-
- return newFuseDirReader(ens), nil
- }
-
- func (r *FuseRoot) listChildren() ([]fuse.FsEntry, error) {
- var ens []fuse.FsEntry
-
- infos := r.vfs.cache.StatMany([]string{})
-
- bkts, err := r.vfs.db.Bucket().GetAll(r.vfs.db.DefCtx())
- if err != nil {
- return nil, err
- }
-
- bktMap := make(map[string]*cdssdk.Bucket)
- for _, bkt := range bkts {
- b := bkt
- bktMap[bkt.Name] = &b
- }
-
- for _, c := range infos {
- delete(bktMap, c.PathComps[len(c.PathComps)-1])
-
- if c.IsDir {
- ens = append(ens, newBucketFromCache(c, r.vfs))
- } else {
- ens = append(ens, newFileFromCache(c, r.vfs))
- }
- }
-
- // 将远端目录同步到本地缓存中,防止在给目录中的远端对象创建本地缓存时,顺便创建的目录的元数据不对的情况
- for _, bkt := range bktMap {
- dir := r.vfs.cache.LoadDir([]string{bkt.Name}, &cache.CreateDirOption{
- ModTime: bkt.CreateTime,
- })
-
- if dir == nil {
- continue
- }
-
- ens = append(ens, newBucketFromCache(dir.Info(), r.vfs))
- }
-
- return ens, nil
- }
-
- func (r *FuseRoot) NewDir(ctx context.Context, name string) (fuse.FsDir, error) {
- cache := r.vfs.cache.CreateDir([]string{name})
- if cache == nil {
- return nil, fuse.ErrPermission
- }
-
- // TODO 用户ID,失败了可以打个日志
- // TODO 生成系统事件
- // 不关注创建是否成功,仅尝试一下
- r.vfs.db.Bucket().Create(r.vfs.db.DefCtx(), 1, name, cache.ModTime())
-
- return newBucketFromCache(cache.Info(), r.vfs), nil
- }
-
- func (r *FuseRoot) NewFile(ctx context.Context, name string, flags uint32) (fuse.FileHandle, uint32, error) {
- cache := r.vfs.cache.CreateFile([]string{name})
- if cache == nil {
- return nil, 0, fuse.ErrPermission
- }
- defer cache.Release()
- // Open之后会给cache的引用计数额外+1,即使cache先于FileHandle被关闭,
- // 也有有FileHandle的计数保持cache的有效性
-
- fileNode := newFileFromCache(cache.Info(), r.vfs)
- hd := cache.Open(flags)
- return newFileHandle(fileNode, hd), flags, nil
- }
-
- func (r *FuseRoot) RemoveChild(ctx context.Context, name string) error {
- // TODO 生成系统事件
- db := r.vfs.db
- return r.vfs.db.DoTx(func(tx db2.SQLContext) error {
-
- bkt, err := db.Bucket().GetByName(tx, name)
- if err == nil {
- has, err := db.Package().HasPackageIn(tx, bkt.BucketID)
- if err != nil {
- return err
- }
- if has {
- return fuse.ErrNotEmpty
- }
-
- } else if err != gorm.ErrRecordNotFound {
- return err
- }
-
- err = r.vfs.cache.Remove([]string{name})
- if err != nil {
- return err
- }
-
- if bkt.BucketID != 0 {
- // 不管是否成功
- db.Bucket().DeleteComplete(tx, bkt.BucketID)
- }
-
- return nil
- })
- }
-
- func (r *FuseRoot) MoveChild(ctx context.Context, oldName string, newName string, newParent fuse.FsDir) error {
- newParentNode := newParent.(FuseNode)
- newParentPath := newParentNode.PathComps()
-
- // 只允许同层级内改名
- if len(newParentPath) != 0 {
- return fuse.ErrNotSupported
- }
-
- d := r.vfs.db
- return d.DoTx(func(tx db2.SQLContext) error {
- _, err := d.Bucket().GetByName(tx, newName)
- if err == nil {
- // 目标节点已经存在,不能重命名,直接退出
- return fuse.ErrExists
- }
-
- oldBkt, err := d.Bucket().GetByName(tx, oldName)
- if err == nil {
- err = d.Bucket().Rename(tx, oldBkt.BucketID, newName)
- if err != nil {
- return err
- }
- } else if err != gorm.ErrRecordNotFound {
- return err
- }
-
- return r.vfs.cache.Move([]string{oldName}, []string{newName})
- })
- }
-
- var _ fuse.FsDir = (*FuseRoot)(nil)
- var _ FuseNode = (*FuseRoot)(nil)
|