github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/files.go (about) 1 // Copyright 2016 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 nodefs 6 7 import ( 8 "fmt" 9 "os" 10 "sync" 11 "syscall" 12 13 "github.com/hanwen/go-fuse/fuse" 14 ) 15 16 // DataFile is for implementing read-only filesystems. This 17 // assumes we already have the data in memory. 18 type dataFile struct { 19 data []byte 20 21 File 22 } 23 24 func (f *dataFile) String() string { 25 l := len(f.data) 26 if l > 10 { 27 l = 10 28 } 29 30 return fmt.Sprintf("dataFile(%x)", f.data[:l]) 31 } 32 33 func (f *dataFile) GetAttr(out *fuse.Attr) fuse.Status { 34 out.Mode = fuse.S_IFREG | 0644 35 out.Size = uint64(len(f.data)) 36 return fuse.OK 37 } 38 39 func NewDataFile(data []byte) File { 40 f := new(dataFile) 41 f.data = data 42 f.File = NewDefaultFile() 43 return f 44 } 45 46 func (f *dataFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) { 47 end := int(off) + int(len(buf)) 48 if end > len(f.data) { 49 end = len(f.data) 50 } 51 52 return fuse.ReadResultData(f.data[off:end]), fuse.OK 53 } 54 55 type devNullFile struct { 56 File 57 } 58 59 // NewDevNullFile returns a file that accepts any write, and always 60 // returns EOF for reads. 61 func NewDevNullFile() File { 62 return &devNullFile{ 63 File: NewDefaultFile(), 64 } 65 } 66 67 func (f *devNullFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) { 68 return fuse.OK 69 } 70 71 func (f *devNullFile) String() string { 72 return "devNullFile" 73 } 74 75 func (f *devNullFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) { 76 return fuse.ReadResultData(nil), fuse.OK 77 } 78 79 func (f *devNullFile) Write(content []byte, off int64) (uint32, fuse.Status) { 80 return uint32(len(content)), fuse.OK 81 } 82 83 func (f *devNullFile) Flush() fuse.Status { 84 return fuse.OK 85 } 86 87 func (f *devNullFile) Fsync(flags int) (code fuse.Status) { 88 return fuse.OK 89 } 90 91 func (f *devNullFile) Truncate(size uint64) (code fuse.Status) { 92 return fuse.OK 93 } 94 95 //////////////// 96 97 // LoopbackFile delegates all operations back to an underlying os.File. 98 func NewLoopbackFile(f *os.File) File { 99 return &loopbackFile{File: f} 100 } 101 102 type loopbackFile struct { 103 File *os.File 104 105 // os.File is not threadsafe. Although fd themselves are 106 // constant during the lifetime of an open file, the OS may 107 // reuse the fd number after it is closed. When open races 108 // with another close, they may lead to confusion as which 109 // file gets written in the end. 110 lock sync.Mutex 111 } 112 113 func (f *loopbackFile) InnerFile() File { 114 return nil 115 } 116 117 func (f *loopbackFile) SetInode(n *Inode) { 118 } 119 120 func (f *loopbackFile) String() string { 121 return fmt.Sprintf("loopbackFile(%s)", f.File.Name()) 122 } 123 124 func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) { 125 f.lock.Lock() 126 // This is not racy by virtue of the kernel properly 127 // synchronizing the open/write/close. 128 r := fuse.ReadResultFd(f.File.Fd(), off, len(buf)) 129 f.lock.Unlock() 130 return r, fuse.OK 131 } 132 133 func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) { 134 f.lock.Lock() 135 n, err := f.File.WriteAt(data, off) 136 f.lock.Unlock() 137 return uint32(n), fuse.ToStatus(err) 138 } 139 140 func (f *loopbackFile) Release() { 141 f.lock.Lock() 142 f.File.Close() 143 f.lock.Unlock() 144 } 145 146 func (f *loopbackFile) Flush() fuse.Status { 147 f.lock.Lock() 148 149 // Since Flush() may be called for each dup'd fd, we don't 150 // want to really close the file, we just want to flush. This 151 // is achieved by closing a dup'd fd. 152 newFd, err := syscall.Dup(int(f.File.Fd())) 153 f.lock.Unlock() 154 155 if err != nil { 156 return fuse.ToStatus(err) 157 } 158 err = syscall.Close(newFd) 159 return fuse.ToStatus(err) 160 } 161 162 func (f *loopbackFile) Fsync(flags int) (code fuse.Status) { 163 f.lock.Lock() 164 r := fuse.ToStatus(syscall.Fsync(int(f.File.Fd()))) 165 f.lock.Unlock() 166 167 return r 168 } 169 170 const ( 171 F_OFD_GETLK = 36 172 F_OFD_SETLK = 37 173 F_OFD_SETLKW = 38 174 ) 175 176 func (f *loopbackFile) GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status) { 177 flk := syscall.Flock_t{} 178 lk.ToFlockT(&flk) 179 code = fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), F_OFD_GETLK, &flk)) 180 out.FromFlockT(&flk) 181 return 182 } 183 184 func (f *loopbackFile) SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) { 185 return f.setLock(owner, lk, flags, false) 186 } 187 188 func (f *loopbackFile) SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) { 189 return f.setLock(owner, lk, flags, true) 190 } 191 192 func (f *loopbackFile) setLock(owner uint64, lk *fuse.FileLock, flags uint32, blocking bool) (code fuse.Status) { 193 if (flags & fuse.FUSE_LK_FLOCK) != 0 { 194 var op int 195 switch lk.Typ { 196 case syscall.F_RDLCK: 197 op = syscall.LOCK_SH 198 case syscall.F_WRLCK: 199 op = syscall.LOCK_EX 200 case syscall.F_UNLCK: 201 op = syscall.LOCK_UN 202 default: 203 return fuse.EINVAL 204 } 205 if !blocking { 206 op |= syscall.LOCK_NB 207 } 208 return fuse.ToStatus(syscall.Flock(int(f.File.Fd()), op)) 209 } else { 210 flk := syscall.Flock_t{} 211 lk.ToFlockT(&flk) 212 var op int 213 if blocking { 214 op = F_OFD_SETLKW 215 } else { 216 op = F_OFD_SETLK 217 } 218 return fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), op, &flk)) 219 } 220 } 221 222 func (f *loopbackFile) Truncate(size uint64) fuse.Status { 223 f.lock.Lock() 224 r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size))) 225 f.lock.Unlock() 226 227 return r 228 } 229 230 func (f *loopbackFile) Chmod(mode uint32) fuse.Status { 231 f.lock.Lock() 232 r := fuse.ToStatus(f.File.Chmod(os.FileMode(mode))) 233 f.lock.Unlock() 234 235 return r 236 } 237 238 func (f *loopbackFile) Chown(uid uint32, gid uint32) fuse.Status { 239 f.lock.Lock() 240 r := fuse.ToStatus(f.File.Chown(int(uid), int(gid))) 241 f.lock.Unlock() 242 243 return r 244 } 245 246 func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status { 247 st := syscall.Stat_t{} 248 f.lock.Lock() 249 err := syscall.Fstat(int(f.File.Fd()), &st) 250 f.lock.Unlock() 251 if err != nil { 252 return fuse.ToStatus(err) 253 } 254 a.FromStat(&st) 255 256 return fuse.OK 257 } 258 259 // Utimens implemented in files_linux.go 260 261 // Allocate implemented in files_linux.go 262 263 //////////////////////////////////////////////////////////////// 264 265 // NewReadOnlyFile wraps a File so all write operations are denied. 266 func NewReadOnlyFile(f File) File { 267 return &readOnlyFile{File: f} 268 } 269 270 type readOnlyFile struct { 271 File 272 } 273 274 func (f *readOnlyFile) InnerFile() File { 275 return f.File 276 } 277 278 func (f *readOnlyFile) String() string { 279 return fmt.Sprintf("readOnlyFile(%s)", f.File.String()) 280 } 281 282 func (f *readOnlyFile) Write(data []byte, off int64) (uint32, fuse.Status) { 283 return 0, fuse.EPERM 284 } 285 286 func (f *readOnlyFile) Fsync(flag int) (code fuse.Status) { 287 return fuse.OK 288 } 289 290 func (f *readOnlyFile) Truncate(size uint64) fuse.Status { 291 return fuse.EPERM 292 } 293 294 func (f *readOnlyFile) Chmod(mode uint32) fuse.Status { 295 return fuse.EPERM 296 } 297 298 func (f *readOnlyFile) Chown(uid uint32, gid uint32) fuse.Status { 299 return fuse.EPERM 300 } 301 302 func (f *readOnlyFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status { 303 return fuse.EPERM 304 }