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  }