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  }