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