github.com/pachyderm/pachyderm@v1.13.4/src/server/pfs/fuse/files.go (about)

     1  // Copyright 2019 the Go-FUSE Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fuse
     6  
     7  import (
     8  	"context"
     9  	"sync"
    10  	"syscall"
    11  
    12  	"github.com/hanwen/go-fuse/v2/fs"
    13  	"github.com/hanwen/go-fuse/v2/fuse"
    14  	"golang.org/x/sys/unix"
    15  )
    16  
    17  // NewLoopbackFile creates a FileHandle out of a file descriptor. All
    18  // operations are implemented.
    19  func NewLoopbackFile(fd int) fs.FileHandle {
    20  	return &loopbackFile{fd: fd}
    21  }
    22  
    23  type loopbackFile struct {
    24  	mu sync.Mutex
    25  	fd int
    26  }
    27  
    28  var _ = (fs.FileHandle)((*loopbackFile)(nil))
    29  var _ = (fs.FileReleaser)((*loopbackFile)(nil))
    30  var _ = (fs.FileGetattrer)((*loopbackFile)(nil))
    31  var _ = (fs.FileReader)((*loopbackFile)(nil))
    32  var _ = (fs.FileWriter)((*loopbackFile)(nil))
    33  var _ = (fs.FileGetlker)((*loopbackFile)(nil))
    34  var _ = (fs.FileSetlker)((*loopbackFile)(nil))
    35  var _ = (fs.FileSetlkwer)((*loopbackFile)(nil))
    36  var _ = (fs.FileLseeker)((*loopbackFile)(nil))
    37  var _ = (fs.FileFlusher)((*loopbackFile)(nil))
    38  var _ = (fs.FileFsyncer)((*loopbackFile)(nil))
    39  var _ = (fs.FileSetattrer)((*loopbackFile)(nil))
    40  var _ = (fs.FileAllocater)((*loopbackFile)(nil))
    41  
    42  func (f *loopbackFile) Read(ctx context.Context, buf []byte, off int64) (res fuse.ReadResult, errno syscall.Errno) {
    43  	f.mu.Lock()
    44  	defer f.mu.Unlock()
    45  	r := fuse.ReadResultFd(uintptr(f.fd), off, len(buf))
    46  	return r, fs.OK
    47  }
    48  
    49  func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint32, syscall.Errno) {
    50  	f.mu.Lock()
    51  	defer f.mu.Unlock()
    52  	n, err := syscall.Pwrite(f.fd, data, off)
    53  	return uint32(n), fs.ToErrno(err)
    54  }
    55  
    56  func (f *loopbackFile) Release(ctx context.Context) syscall.Errno {
    57  	f.mu.Lock()
    58  	defer f.mu.Unlock()
    59  	if f.fd != -1 {
    60  		err := syscall.Close(f.fd)
    61  		f.fd = -1
    62  		return fs.ToErrno(err)
    63  	}
    64  	return syscall.EBADF
    65  }
    66  
    67  func (f *loopbackFile) Flush(ctx context.Context) syscall.Errno {
    68  	f.mu.Lock()
    69  	defer f.mu.Unlock()
    70  	// Since Flush() may be called for each dup'd fd, we don't
    71  	// want to really close the file, we just want to flush. This
    72  	// is achieved by closing a dup'd fd.
    73  	newFd, err := syscall.Dup(f.fd)
    74  
    75  	if err != nil {
    76  		return fs.ToErrno(err)
    77  	}
    78  	err = syscall.Close(newFd)
    79  	return fs.ToErrno(err)
    80  }
    81  
    82  func (f *loopbackFile) Fsync(ctx context.Context, flags uint32) (errno syscall.Errno) {
    83  	f.mu.Lock()
    84  	defer f.mu.Unlock()
    85  	r := fs.ToErrno(syscall.Fsync(f.fd))
    86  
    87  	return r
    88  }
    89  
    90  const (
    91  	// GETLK is constant for F_OFD_GETLK
    92  	GETLK = 36
    93  	// SETLK is constant for F_OFD_SETLK
    94  	SETLK = 37
    95  	// SETLKW is constant for F_OFD_SETLKW
    96  	SETLKW = 38
    97  )
    98  
    99  func (f *loopbackFile) Getlk(ctx context.Context, owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (errno syscall.Errno) {
   100  	f.mu.Lock()
   101  	defer f.mu.Unlock()
   102  	flk := syscall.Flock_t{}
   103  	lk.ToFlockT(&flk)
   104  	errno = fs.ToErrno(syscall.FcntlFlock(uintptr(f.fd), GETLK, &flk))
   105  	out.FromFlockT(&flk)
   106  	return
   107  }
   108  
   109  func (f *loopbackFile) Setlk(ctx context.Context, owner uint64, lk *fuse.FileLock, flags uint32) (errno syscall.Errno) {
   110  	return f.setLock(ctx, owner, lk, flags, false)
   111  }
   112  
   113  func (f *loopbackFile) Setlkw(ctx context.Context, owner uint64, lk *fuse.FileLock, flags uint32) (errno syscall.Errno) {
   114  	return f.setLock(ctx, owner, lk, flags, true)
   115  }
   116  
   117  func (f *loopbackFile) setLock(ctx context.Context, owner uint64, lk *fuse.FileLock, flags uint32, blocking bool) (errno syscall.Errno) {
   118  	f.mu.Lock()
   119  	defer f.mu.Unlock()
   120  	if (flags & fuse.FUSE_LK_FLOCK) != 0 {
   121  		var op int
   122  		switch lk.Typ {
   123  		case syscall.F_RDLCK:
   124  			op = syscall.LOCK_SH
   125  		case syscall.F_WRLCK:
   126  			op = syscall.LOCK_EX
   127  		case syscall.F_UNLCK:
   128  			op = syscall.LOCK_UN
   129  		default:
   130  			return syscall.EINVAL
   131  		}
   132  		if !blocking {
   133  			op |= syscall.LOCK_NB
   134  		}
   135  		return fs.ToErrno(syscall.Flock(f.fd, op))
   136  	}
   137  	flk := syscall.Flock_t{}
   138  	lk.ToFlockT(&flk)
   139  	var op int
   140  	if blocking {
   141  		op = SETLKW
   142  	} else {
   143  		op = SETLK
   144  	}
   145  	return fs.ToErrno(syscall.FcntlFlock(uintptr(f.fd), op, &flk))
   146  }
   147  
   148  func (f *loopbackFile) Setattr(ctx context.Context, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
   149  	if errno := f.setAttr(ctx, in); errno != 0 {
   150  		return errno
   151  	}
   152  
   153  	return f.Getattr(ctx, out)
   154  }
   155  
   156  func (f *loopbackFile) setAttr(ctx context.Context, in *fuse.SetAttrIn) syscall.Errno {
   157  	f.mu.Lock()
   158  	defer f.mu.Unlock()
   159  	var errno syscall.Errno
   160  	if mode, ok := in.GetMode(); ok {
   161  		errno = fs.ToErrno(syscall.Fchmod(f.fd, mode))
   162  		if errno != 0 {
   163  			return errno
   164  		}
   165  	}
   166  
   167  	uid32, uOk := in.GetUID()
   168  	gid32, gOk := in.GetGID()
   169  	if uOk || gOk {
   170  		uid := -1
   171  		gid := -1
   172  
   173  		if uOk {
   174  			uid = int(uid32)
   175  		}
   176  		if gOk {
   177  			gid = int(gid32)
   178  		}
   179  		errno = fs.ToErrno(syscall.Fchown(f.fd, uid, gid))
   180  		if errno != 0 {
   181  			return errno
   182  		}
   183  	}
   184  
   185  	mtime, mok := in.GetMTime()
   186  	atime, aok := in.GetATime()
   187  
   188  	if mok || aok {
   189  		ap := &atime
   190  		mp := &mtime
   191  		if !aok {
   192  			ap = nil
   193  		}
   194  		if !mok {
   195  			mp = nil
   196  		}
   197  		errno = f.utimens(ap, mp)
   198  		if errno != 0 {
   199  			return errno
   200  		}
   201  	}
   202  
   203  	if sz, ok := in.GetSize(); ok {
   204  		errno = fs.ToErrno(syscall.Ftruncate(f.fd, int64(sz)))
   205  		if errno != 0 {
   206  			return errno
   207  		}
   208  	}
   209  	return fs.OK
   210  }
   211  
   212  func (f *loopbackFile) Getattr(ctx context.Context, a *fuse.AttrOut) syscall.Errno {
   213  	f.mu.Lock()
   214  	defer f.mu.Unlock()
   215  	st := syscall.Stat_t{}
   216  	err := syscall.Fstat(f.fd, &st)
   217  	if err != nil {
   218  		return fs.ToErrno(err)
   219  	}
   220  	a.FromStat(&st)
   221  
   222  	return fs.OK
   223  }
   224  
   225  func (f *loopbackFile) Lseek(ctx context.Context, off uint64, whence uint32) (uint64, syscall.Errno) {
   226  	f.mu.Lock()
   227  	defer f.mu.Unlock()
   228  	n, err := unix.Seek(f.fd, int64(off), int(whence))
   229  	return uint64(n), fs.ToErrno(err)
   230  }