package vfs import ( "os" "time" "gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/fuse" "gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/vfs/cache" clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" "gorm.io/gorm" ) type FuseFileNode struct { vfs *Vfs pathComps []string size int64 modTime time.Time perm os.FileMode } func newFileFromCache(info cache.CacheEntryInfo, vfs *Vfs) *FuseFileNode { return &FuseFileNode{ vfs: vfs, pathComps: info.PathComps, size: info.Size, modTime: info.ModTime, perm: info.Perm, } } func newFileFromObject(vfs *Vfs, pathComps []string, obj clitypes.Object) *FuseFileNode { return &FuseFileNode{ vfs: vfs, pathComps: pathComps, size: obj.Size, modTime: obj.UpdateTime, perm: os.FileMode(0755), // TODO Object元数据中是没有保存权限的 } } func (n *FuseFileNode) Name() string { return n.pathComps[len(n.pathComps)-1] } func (n *FuseFileNode) Size() int64 { info := n.vfs.cache.Stat(n.pathComps) if info == nil { return n.size } return info.Size } func (n *FuseFileNode) Perm() os.FileMode { return n.perm } func (n *FuseFileNode) ModTime() time.Time { info := n.vfs.cache.Stat(n.pathComps) if info == nil { return n.modTime } return info.ModTime } func (n *FuseFileNode) IsDir() bool { return false } func (n *FuseFileNode) Truncate(size uint64) error { ch := n.loadCacheFile() if ch == nil { return fuse.ErrNotExists } defer ch.Release() if !ch.LevelUp(cache.LevelComplete) { return fuse.ErrIOError } return ch.Truncate(int64(size)) } func (n *FuseFileNode) SetModTime(time time.Time) error { ch := n.loadCacheFile() if ch == nil { return fuse.ErrNotExists } defer ch.Release() if !ch.LevelUp(cache.LevelMetaLoaded) { return fuse.ErrIOError } return ch.SetModTime(time) } func (n *FuseFileNode) Open(flags uint32) (fuse.FileHandle, uint32, error) { ch := n.loadCacheFile() if ch == nil { // 如果文件不存在,也不进行创建,因为创建不应该调用这个接口 return nil, 0, fuse.ErrNotExists } defer ch.Release() if !ch.LevelUp(cache.LevelComplete) { return nil, 0, fuse.ErrIOError } hd := ch.Open(flags) return newFileHandle(n, hd), flags, nil } func (n *FuseFileNode) loadCacheFile() *cache.CacheFile { if len(n.pathComps) <= 2 { return n.vfs.cache.LoadFile(n.pathComps, nil) } cdsObj, err := n.vfs.db.Object().GetByFullPath(n.vfs.db.DefCtx(), n.pathComps[0], n.pathComps[1], clitypes.JoinObjectPath(n.pathComps[2:]...)) if err == nil { file := n.vfs.cache.LoadFile(n.pathComps, &cdsObj) if file == nil { return nil } return file } if err == gorm.ErrRecordNotFound { return n.vfs.cache.LoadFile(n.pathComps, nil) } return nil } type FuseFileHandle struct { entry *FuseFileNode chd *cache.CacheFileHandle } func newFileHandle(entry *FuseFileNode, chd *cache.CacheFileHandle) *FuseFileHandle { return &FuseFileHandle{ entry: entry, chd: chd, } } func (hd *FuseFileHandle) Entry() fuse.FsFile { return hd.entry } func (hd *FuseFileHandle) ReadAt(buf []byte, off int64) (int, error) { return hd.chd.ReadAt(buf, off) } func (hd *FuseFileHandle) WriteAt(buf []byte, off int64) (int, error) { return hd.chd.WriteAt(buf, off) } func (hd *FuseFileHandle) Sync() error { return hd.chd.Sync() } func (hd *FuseFileHandle) Flush() error { return nil } func (hd *FuseFileHandle) Close() error { return hd.chd.Close() }