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 }