github.com/swiftstack/proxyfs@v0.0.0-20201223034610-5434d919416e/fuse/symlink.go (about) 1 package fuse 2 3 import ( 4 "fmt" 5 "os" 6 "time" 7 8 fuselib "bazil.org/fuse" 9 "golang.org/x/net/context" 10 11 "github.com/swiftstack/ProxyFS/blunder" 12 "github.com/swiftstack/ProxyFS/fs" 13 "github.com/swiftstack/ProxyFS/inode" 14 ) 15 16 type Symlink struct { 17 volumeHandle fs.VolumeHandle 18 inodeNumber inode.InodeNumber 19 } 20 21 func (s Symlink) Attr(ctx context.Context, attr *fuselib.Attr) (err error) { 22 var ( 23 stat fs.Stat 24 ) 25 26 enterGate() 27 defer leaveGate() 28 29 stat, err = s.volumeHandle.Getstat(inode.InodeRootUserID, inode.InodeGroupID(0), nil, s.inodeNumber) 30 if nil != err { 31 err = newFuseError(err) 32 return 33 } 34 if uint64(inode.SymlinkType) != stat[fs.StatFType] { 35 err = fmt.Errorf("[fuse]Dir.Attr() called on non-Symlink") 36 err = blunder.AddError(err, blunder.InvalidInodeTypeError) 37 err = newFuseError(err) 38 return 39 } 40 41 attr.Valid = time.Duration(time.Microsecond) // TODO: Make this settable if FUSE inside ProxyFS endures 42 attr.Inode = uint64(s.inodeNumber) // or stat[fs.StatINum] 43 attr.Size = stat[fs.StatSize] 44 attr.Atime = time.Unix(0, int64(stat[fs.StatATime])) 45 attr.Mtime = time.Unix(0, int64(stat[fs.StatMTime])) 46 attr.Ctime = time.Unix(0, int64(stat[fs.StatCTime])) 47 attr.Crtime = time.Unix(0, int64(stat[fs.StatCRTime])) 48 attr.Mode = os.ModeSymlink | os.FileMode(stat[fs.StatMode]&0777) 49 attr.Nlink = uint32(stat[fs.StatNLink]) 50 attr.Uid = uint32(stat[fs.StatUserID]) 51 attr.Gid = uint32(stat[fs.StatGroupID]) 52 53 return 54 } 55 56 func (s Symlink) Setattr(ctx context.Context, req *fuselib.SetattrRequest, resp *fuselib.SetattrResponse) (err error) { 57 var ( 58 stat fs.Stat 59 statUpdates fs.Stat 60 ) 61 62 enterGate() 63 defer leaveGate() 64 65 stat, err = s.volumeHandle.Getstat(inode.InodeUserID(req.Header.Uid), inode.InodeGroupID(req.Header.Gid), nil, s.inodeNumber) 66 if nil != err { 67 err = newFuseError(err) 68 return 69 } 70 if uint64(inode.SymlinkType) != stat[fs.StatFType] { 71 err = fmt.Errorf("[fuse]Dir.Attr() called on non-Symlink") 72 err = blunder.AddError(err, blunder.InvalidInodeTypeError) 73 err = newFuseError(err) 74 return 75 } 76 77 statUpdates = make(fs.Stat) 78 79 if 0 != (fuselib.SetattrMode & req.Valid) { 80 statUpdates[fs.StatMode] = uint64(req.Mode & 0777) 81 } 82 if 0 != (fuselib.SetattrUid & req.Valid) { 83 statUpdates[fs.StatUserID] = uint64(req.Uid) 84 } 85 if 0 != (fuselib.SetattrGid & req.Valid) { 86 statUpdates[fs.StatGroupID] = uint64(req.Gid) 87 } 88 if 0 != (fuselib.SetattrAtime & req.Valid) { 89 statUpdates[fs.StatATime] = uint64(req.Atime.UnixNano()) 90 } 91 if 0 != (fuselib.SetattrMtime & req.Valid) { 92 statUpdates[fs.StatMTime] = uint64(req.Mtime.UnixNano()) 93 } 94 if 0 != (fuselib.SetattrAtimeNow & req.Valid) { 95 statUpdates[fs.StatATime] = uint64(time.Now().UnixNano()) 96 } 97 if 0 != (fuselib.SetattrMtimeNow & req.Valid) { 98 statUpdates[fs.StatMTime] = uint64(time.Now().UnixNano()) 99 } 100 if 0 != (fuselib.SetattrCrtime & req.Valid) { 101 statUpdates[fs.StatCRTime] = uint64(req.Crtime.UnixNano()) 102 } 103 104 err = s.volumeHandle.Setstat(inode.InodeUserID(req.Header.Uid), inode.InodeGroupID(req.Header.Gid), nil, s.inodeNumber, statUpdates) 105 if nil != err { 106 err = newFuseError(err) 107 } 108 109 return 110 } 111 112 func (s Symlink) Fsync(ctx context.Context, req *fuselib.FsyncRequest) error { 113 return fuselib.ENOSYS 114 } 115 116 func (s Symlink) Readlink(ctx context.Context, req *fuselib.ReadlinkRequest) (string, error) { 117 target, err := s.volumeHandle.Readsymlink(inode.InodeUserID(req.Header.Uid), inode.InodeGroupID(req.Header.Gid), nil, s.inodeNumber) 118 if nil != err { 119 err = newFuseError(err) 120 } 121 return target, err 122 }