github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/cmd/cmount/fs.go (about) 1 // +build cmount 2 // +build cgo 3 // +build linux darwin freebsd windows 4 5 package cmount 6 7 import ( 8 "io" 9 "os" 10 "path" 11 "sync" 12 "time" 13 14 "github.com/billziss-gh/cgofuse/fuse" 15 "github.com/ncw/rclone/cmd/mountlib" 16 "github.com/ncw/rclone/fs" 17 "github.com/ncw/rclone/fs/log" 18 "github.com/ncw/rclone/vfs" 19 "github.com/ncw/rclone/vfs/vfsflags" 20 "github.com/pkg/errors" 21 ) 22 23 const fhUnset = ^uint64(0) 24 25 // FS represents the top level filing system 26 type FS struct { 27 VFS *vfs.VFS 28 f fs.Fs 29 ready chan (struct{}) 30 mu sync.Mutex // to protect the below 31 handles []vfs.Handle 32 } 33 34 // NewFS makes a new FS 35 func NewFS(f fs.Fs) *FS { 36 fsys := &FS{ 37 VFS: vfs.New(f, &vfsflags.Opt), 38 f: f, 39 ready: make(chan (struct{})), 40 } 41 return fsys 42 } 43 44 // Open a handle returning an integer file handle 45 func (fsys *FS) openHandle(handle vfs.Handle) (fh uint64) { 46 fsys.mu.Lock() 47 defer fsys.mu.Unlock() 48 var i int 49 var oldHandle vfs.Handle 50 for i, oldHandle = range fsys.handles { 51 if oldHandle == nil { 52 fsys.handles[i] = handle 53 goto found 54 } 55 } 56 fsys.handles = append(fsys.handles, handle) 57 i = len(fsys.handles) - 1 58 found: 59 return uint64(i) 60 } 61 62 // get the handle for fh, call with the lock held 63 func (fsys *FS) _getHandle(fh uint64) (i int, handle vfs.Handle, errc int) { 64 if fh > uint64(len(fsys.handles)) { 65 fs.Debugf(nil, "Bad file handle: too big: 0x%X", fh) 66 return i, nil, -fuse.EBADF 67 } 68 i = int(fh) 69 handle = fsys.handles[i] 70 if handle == nil { 71 fs.Debugf(nil, "Bad file handle: nil handle: 0x%X", fh) 72 return i, nil, -fuse.EBADF 73 } 74 return i, handle, 0 75 } 76 77 // Get the handle for the file handle 78 func (fsys *FS) getHandle(fh uint64) (handle vfs.Handle, errc int) { 79 fsys.mu.Lock() 80 _, handle, errc = fsys._getHandle(fh) 81 fsys.mu.Unlock() 82 return 83 } 84 85 // Close the handle 86 func (fsys *FS) closeHandle(fh uint64) (errc int) { 87 fsys.mu.Lock() 88 i, _, errc := fsys._getHandle(fh) 89 if errc == 0 { 90 fsys.handles[i] = nil 91 } 92 fsys.mu.Unlock() 93 return 94 } 95 96 // lookup a Node given a path 97 func (fsys *FS) lookupNode(path string) (node vfs.Node, errc int) { 98 node, err := fsys.VFS.Stat(path) 99 return node, translateError(err) 100 } 101 102 // lookup a Dir given a path 103 func (fsys *FS) lookupDir(path string) (dir *vfs.Dir, errc int) { 104 node, errc := fsys.lookupNode(path) 105 if errc != 0 { 106 return nil, errc 107 } 108 dir, ok := node.(*vfs.Dir) 109 if !ok { 110 return nil, -fuse.ENOTDIR 111 } 112 return dir, 0 113 } 114 115 // lookup a parent Dir given a path returning the dir and the leaf 116 func (fsys *FS) lookupParentDir(filePath string) (leaf string, dir *vfs.Dir, errc int) { 117 parentDir, leaf := path.Split(filePath) 118 dir, errc = fsys.lookupDir(parentDir) 119 return leaf, dir, errc 120 } 121 122 // lookup a File given a path 123 func (fsys *FS) lookupFile(path string) (file *vfs.File, errc int) { 124 node, errc := fsys.lookupNode(path) 125 if errc != 0 { 126 return nil, errc 127 } 128 file, ok := node.(*vfs.File) 129 if !ok { 130 return nil, -fuse.EISDIR 131 } 132 return file, 0 133 } 134 135 // get a node and handle from the path or from the fh if not fhUnset 136 // 137 // handle may be nil 138 func (fsys *FS) getNode(path string, fh uint64) (node vfs.Node, handle vfs.Handle, errc int) { 139 if fh == fhUnset { 140 node, errc = fsys.lookupNode(path) 141 } else { 142 handle, errc = fsys.getHandle(fh) 143 if errc == 0 { 144 node = handle.Node() 145 } 146 } 147 return 148 } 149 150 // stat fills up the stat block for Node 151 func (fsys *FS) stat(node vfs.Node, stat *fuse.Stat_t) (errc int) { 152 Size := uint64(node.Size()) 153 Blocks := (Size + 511) / 512 154 modTime := node.ModTime() 155 Mode := node.Mode().Perm() 156 if node.IsDir() { 157 Mode |= fuse.S_IFDIR 158 } else { 159 Mode |= fuse.S_IFREG 160 } 161 //stat.Dev = 1 162 stat.Ino = node.Inode() // FIXME do we need to set the inode number? 163 stat.Mode = uint32(Mode) 164 stat.Nlink = 1 165 stat.Uid = fsys.VFS.Opt.UID 166 stat.Gid = fsys.VFS.Opt.GID 167 //stat.Rdev 168 stat.Size = int64(Size) 169 t := fuse.NewTimespec(modTime) 170 stat.Atim = t 171 stat.Mtim = t 172 stat.Ctim = t 173 stat.Blksize = 512 174 stat.Blocks = int64(Blocks) 175 stat.Birthtim = t 176 // fs.Debugf(nil, "stat = %+v", *stat) 177 return 0 178 } 179 180 // Init is called after the filesystem is ready 181 func (fsys *FS) Init() { 182 defer log.Trace(fsys.f, "")("") 183 close(fsys.ready) 184 } 185 186 // Destroy is called when it is unmounted (note that depending on how 187 // the file system is terminated the file system may not receive the 188 // Destroy call). 189 func (fsys *FS) Destroy() { 190 defer log.Trace(fsys.f, "")("") 191 } 192 193 // Getattr reads the attributes for path 194 func (fsys *FS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) { 195 defer log.Trace(path, "fh=0x%X", fh)("errc=%v", &errc) 196 node, _, errc := fsys.getNode(path, fh) 197 if errc == 0 { 198 errc = fsys.stat(node, stat) 199 } 200 return 201 } 202 203 // Opendir opens path as a directory 204 func (fsys *FS) Opendir(path string) (errc int, fh uint64) { 205 defer log.Trace(path, "")("errc=%d, fh=0x%X", &errc, &fh) 206 handle, err := fsys.VFS.OpenFile(path, os.O_RDONLY, 0777) 207 if err != nil { 208 return translateError(err), fhUnset 209 } 210 return 0, fsys.openHandle(handle) 211 } 212 213 // Readdir reads the directory at dirPath 214 func (fsys *FS) Readdir(dirPath string, 215 fill func(name string, stat *fuse.Stat_t, ofst int64) bool, 216 ofst int64, 217 fh uint64) (errc int) { 218 itemsRead := -1 219 defer log.Trace(dirPath, "ofst=%d, fh=0x%X", ofst, fh)("items=%d, errc=%d", &itemsRead, &errc) 220 221 node, errc := fsys.getHandle(fh) 222 if errc != 0 { 223 return errc 224 } 225 226 items, err := node.Readdir(-1) 227 if err != nil { 228 return translateError(err) 229 } 230 231 // Optionally, create a struct stat that describes the file as 232 // for getattr (but FUSE only looks at st_ino and the 233 // file-type bits of st_mode). 234 // 235 // FIXME If you call host.SetCapReaddirPlus() then WinFsp will 236 // use the full stat information - a Useful optimization on 237 // Windows. 238 // 239 // NB we are using the first mode for readdir: The readdir 240 // implementation ignores the offset parameter, and passes 241 // zero to the filler function's offset. The filler function 242 // will not return '1' (unless an error happens), so the whole 243 // directory is read in a single readdir operation. 244 fill(".", nil, 0) 245 fill("..", nil, 0) 246 for _, item := range items { 247 node, ok := item.(vfs.Node) 248 if ok { 249 fill(node.Name(), nil, 0) 250 } 251 } 252 itemsRead = len(items) 253 return 0 254 } 255 256 // Releasedir finished reading the directory 257 func (fsys *FS) Releasedir(path string, fh uint64) (errc int) { 258 defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc) 259 return fsys.closeHandle(fh) 260 } 261 262 // Statfs reads overall stats on the filessystem 263 func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) { 264 defer log.Trace(path, "")("stat=%+v, errc=%d", stat, &errc) 265 const blockSize = 4096 266 const fsBlocks = (1 << 50) / blockSize 267 stat.Blocks = fsBlocks // Total data blocks in file system. 268 stat.Bfree = fsBlocks // Free blocks in file system. 269 stat.Bavail = fsBlocks // Free blocks in file system if you're not root. 270 stat.Files = 1E9 // Total files in file system. 271 stat.Ffree = 1E9 // Free files in file system. 272 stat.Bsize = blockSize // Block size 273 stat.Namemax = 255 // Maximum file name length? 274 stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system. 275 total, used, free := fsys.VFS.Statfs() 276 if total >= 0 { 277 stat.Blocks = uint64(total) / blockSize 278 } 279 if used >= 0 { 280 stat.Bfree = stat.Blocks - uint64(used)/blockSize 281 } 282 if free >= 0 { 283 stat.Bavail = uint64(free) / blockSize 284 } 285 mountlib.ClipBlocks(&stat.Blocks) 286 mountlib.ClipBlocks(&stat.Bfree) 287 mountlib.ClipBlocks(&stat.Bavail) 288 return 0 289 } 290 291 // Open opens a file 292 func (fsys *FS) Open(path string, flags int) (errc int, fh uint64) { 293 defer log.Trace(path, "flags=0x%X", flags)("errc=%d, fh=0x%X", &errc, &fh) 294 295 // translate the fuse flags to os flags 296 flags = translateOpenFlags(flags) 297 handle, err := fsys.VFS.OpenFile(path, flags, 0777) 298 if err != nil { 299 return translateError(err), fhUnset 300 } 301 302 return 0, fsys.openHandle(handle) 303 } 304 305 // Create creates and opens a file. 306 func (fsys *FS) Create(filePath string, flags int, mode uint32) (errc int, fh uint64) { 307 defer log.Trace(filePath, "flags=0x%X, mode=0%o", flags, mode)("errc=%d, fh=0x%X", &errc, &fh) 308 leaf, parentDir, errc := fsys.lookupParentDir(filePath) 309 if errc != 0 { 310 return errc, fhUnset 311 } 312 file, err := parentDir.Create(leaf, flags) 313 if err != nil { 314 return translateError(err), fhUnset 315 } 316 // translate the fuse flags to os flags 317 flags = translateOpenFlags(flags) | os.O_CREATE 318 handle, err := file.Open(flags) 319 if err != nil { 320 return translateError(err), fhUnset 321 } 322 return 0, fsys.openHandle(handle) 323 } 324 325 // Truncate truncates a file to size 326 func (fsys *FS) Truncate(path string, size int64, fh uint64) (errc int) { 327 defer log.Trace(path, "size=%d, fh=0x%X", size, fh)("errc=%d", &errc) 328 node, handle, errc := fsys.getNode(path, fh) 329 if errc != 0 { 330 return errc 331 } 332 var err error 333 if handle != nil { 334 err = handle.Truncate(size) 335 } else { 336 err = node.Truncate(size) 337 } 338 if err != nil { 339 return translateError(err) 340 } 341 return 0 342 } 343 344 // Read data from file handle 345 func (fsys *FS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) { 346 defer log.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n) 347 handle, errc := fsys.getHandle(fh) 348 if errc != 0 { 349 return errc 350 } 351 n, err := handle.ReadAt(buff, ofst) 352 if err == io.EOF { 353 } else if err != nil { 354 return translateError(err) 355 } 356 return n 357 } 358 359 // Write data to file handle 360 func (fsys *FS) Write(path string, buff []byte, ofst int64, fh uint64) (n int) { 361 defer log.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n) 362 handle, errc := fsys.getHandle(fh) 363 if errc != 0 { 364 return errc 365 } 366 n, err := handle.WriteAt(buff, ofst) 367 if err != nil { 368 return translateError(err) 369 } 370 return n 371 } 372 373 // Flush flushes an open file descriptor or path 374 func (fsys *FS) Flush(path string, fh uint64) (errc int) { 375 defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc) 376 handle, errc := fsys.getHandle(fh) 377 if errc != 0 { 378 return errc 379 } 380 return translateError(handle.Flush()) 381 } 382 383 // Release closes the file if still open 384 func (fsys *FS) Release(path string, fh uint64) (errc int) { 385 defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc) 386 handle, errc := fsys.getHandle(fh) 387 if errc != 0 { 388 return errc 389 } 390 _ = fsys.closeHandle(fh) 391 return translateError(handle.Release()) 392 } 393 394 // Unlink removes a file. 395 func (fsys *FS) Unlink(filePath string) (errc int) { 396 defer log.Trace(filePath, "")("errc=%d", &errc) 397 leaf, parentDir, errc := fsys.lookupParentDir(filePath) 398 if errc != 0 { 399 return errc 400 } 401 return translateError(parentDir.RemoveName(leaf)) 402 } 403 404 // Mkdir creates a directory. 405 func (fsys *FS) Mkdir(dirPath string, mode uint32) (errc int) { 406 defer log.Trace(dirPath, "mode=0%o", mode)("errc=%d", &errc) 407 leaf, parentDir, errc := fsys.lookupParentDir(dirPath) 408 if errc != 0 { 409 return errc 410 } 411 _, err := parentDir.Mkdir(leaf) 412 return translateError(err) 413 } 414 415 // Rmdir removes a directory 416 func (fsys *FS) Rmdir(dirPath string) (errc int) { 417 defer log.Trace(dirPath, "")("errc=%d", &errc) 418 leaf, parentDir, errc := fsys.lookupParentDir(dirPath) 419 if errc != 0 { 420 return errc 421 } 422 return translateError(parentDir.RemoveName(leaf)) 423 } 424 425 // Rename renames a file. 426 func (fsys *FS) Rename(oldPath string, newPath string) (errc int) { 427 defer log.Trace(oldPath, "newPath=%q", newPath)("errc=%d", &errc) 428 return translateError(fsys.VFS.Rename(oldPath, newPath)) 429 } 430 431 // Utimens changes the access and modification times of a file. 432 func (fsys *FS) Utimens(path string, tmsp []fuse.Timespec) (errc int) { 433 defer log.Trace(path, "tmsp=%+v", tmsp)("errc=%d", &errc) 434 node, errc := fsys.lookupNode(path) 435 if errc != 0 { 436 return errc 437 } 438 var t time.Time 439 if tmsp == nil || len(tmsp) < 2 { 440 t = time.Now() 441 } else { 442 t = tmsp[1].Time() 443 } 444 return translateError(node.SetModTime(t)) 445 } 446 447 // Mknod creates a file node. 448 func (fsys *FS) Mknod(path string, mode uint32, dev uint64) (errc int) { 449 defer log.Trace(path, "mode=0x%X, dev=0x%X", mode, dev)("errc=%d", &errc) 450 return -fuse.ENOSYS 451 } 452 453 // Fsync synchronizes file contents. 454 func (fsys *FS) Fsync(path string, datasync bool, fh uint64) (errc int) { 455 defer log.Trace(path, "datasync=%v, fh=0x%X", datasync, fh)("errc=%d", &errc) 456 // This is a no-op for rclone 457 return 0 458 } 459 460 // Link creates a hard link to a file. 461 func (fsys *FS) Link(oldpath string, newpath string) (errc int) { 462 defer log.Trace(oldpath, "newpath=%q", newpath)("errc=%d", &errc) 463 return -fuse.ENOSYS 464 } 465 466 // Symlink creates a symbolic link. 467 func (fsys *FS) Symlink(target string, newpath string) (errc int) { 468 defer log.Trace(target, "newpath=%q", newpath)("errc=%d", &errc) 469 return -fuse.ENOSYS 470 } 471 472 // Readlink reads the target of a symbolic link. 473 func (fsys *FS) Readlink(path string) (errc int, linkPath string) { 474 defer log.Trace(path, "")("linkPath=%q, errc=%d", &linkPath, &errc) 475 return -fuse.ENOSYS, "" 476 } 477 478 // Chmod changes the permission bits of a file. 479 func (fsys *FS) Chmod(path string, mode uint32) (errc int) { 480 defer log.Trace(path, "mode=0%o", mode)("errc=%d", &errc) 481 // This is a no-op for rclone 482 return 0 483 } 484 485 // Chown changes the owner and group of a file. 486 func (fsys *FS) Chown(path string, uid uint32, gid uint32) (errc int) { 487 defer log.Trace(path, "uid=%d, gid=%d", uid, gid)("errc=%d", &errc) 488 // This is a no-op for rclone 489 return 0 490 } 491 492 // Access checks file access permissions. 493 func (fsys *FS) Access(path string, mask uint32) (errc int) { 494 defer log.Trace(path, "mask=0%o", mask)("errc=%d", &errc) 495 // This is a no-op for rclone 496 return 0 497 } 498 499 // Fsyncdir synchronizes directory contents. 500 func (fsys *FS) Fsyncdir(path string, datasync bool, fh uint64) (errc int) { 501 defer log.Trace(path, "datasync=%v, fh=0x%X", datasync, fh)("errc=%d", &errc) 502 // This is a no-op for rclone 503 return 0 504 } 505 506 // Setxattr sets extended attributes. 507 func (fsys *FS) Setxattr(path string, name string, value []byte, flags int) (errc int) { 508 return -fuse.ENOSYS 509 } 510 511 // Getxattr gets extended attributes. 512 func (fsys *FS) Getxattr(path string, name string) (errc int, value []byte) { 513 return -fuse.ENOSYS, nil 514 } 515 516 // Removexattr removes extended attributes. 517 func (fsys *FS) Removexattr(path string, name string) (errc int) { 518 return -fuse.ENOSYS 519 } 520 521 // Listxattr lists extended attributes. 522 func (fsys *FS) Listxattr(path string, fill func(name string) bool) (errc int) { 523 return -fuse.ENOSYS 524 } 525 526 // Translate errors from mountlib 527 func translateError(err error) (errc int) { 528 if err == nil { 529 return 0 530 } 531 switch errors.Cause(err) { 532 case vfs.OK: 533 return 0 534 case vfs.ENOENT: 535 return -fuse.ENOENT 536 case vfs.EEXIST: 537 return -fuse.EEXIST 538 case vfs.EPERM: 539 return -fuse.EPERM 540 case vfs.ECLOSED: 541 return -fuse.EBADF 542 case vfs.ENOTEMPTY: 543 return -fuse.ENOTEMPTY 544 case vfs.ESPIPE: 545 return -fuse.ESPIPE 546 case vfs.EBADF: 547 return -fuse.EBADF 548 case vfs.EROFS: 549 return -fuse.EROFS 550 case vfs.ENOSYS: 551 return -fuse.ENOSYS 552 case vfs.EINVAL: 553 return -fuse.EINVAL 554 } 555 fs.Errorf(nil, "IO error: %v", err) 556 return -fuse.EIO 557 } 558 559 // Translate Open Flags from FUSE to os (as used in the vfs layer) 560 func translateOpenFlags(inFlags int) (outFlags int) { 561 switch inFlags & fuse.O_ACCMODE { 562 case fuse.O_RDONLY: 563 outFlags = os.O_RDONLY 564 case fuse.O_WRONLY: 565 outFlags = os.O_WRONLY 566 case fuse.O_RDWR: 567 outFlags = os.O_RDWR 568 } 569 if inFlags&fuse.O_APPEND != 0 { 570 outFlags |= os.O_APPEND 571 } 572 if inFlags&fuse.O_CREAT != 0 { 573 outFlags |= os.O_CREATE 574 } 575 if inFlags&fuse.O_EXCL != 0 { 576 outFlags |= os.O_EXCL 577 } 578 if inFlags&fuse.O_TRUNC != 0 { 579 outFlags |= os.O_TRUNC 580 } 581 // NB O_SYNC isn't defined by fuse 582 return outFlags 583 }