vfs.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. // Package vfs provides a virtual filing system layer over rclone's
  2. // native objects.
  3. //
  4. // It attempts to behave in a similar way to Go's filing system
  5. // manipulation code in the os package. The same named function
  6. // should behave in an identical fashion. The objects also obey Go's
  7. // standard interfaces.
  8. //
  9. // Note that paths don't start or end with /, so the root directory
  10. // may be referred to as "". However Stat strips slashes so you can
  11. // use paths with slashes in.
  12. //
  13. // # It also includes directory caching
  14. //
  15. // The vfs package returns Error values to signal precisely which
  16. // error conditions have occurred. It may also return general errors
  17. // it receives. It tries to use os Error values (e.g. os.ErrExist)
  18. // where possible.
  19. //
  20. //go:generate sh -c "go run make_open_tests.go | gofmt > open_test.go"
  21. package vfs
  22. import (
  23. "context"
  24. _ "embed"
  25. "fmt"
  26. "io"
  27. "os"
  28. "path"
  29. "sort"
  30. "strings"
  31. "sync"
  32. "sync/atomic"
  33. "time"
  34. "github.com/go-git/go-billy/v5"
  35. "github.com/rclone/rclone/fs"
  36. "github.com/rclone/rclone/fs/cache"
  37. "github.com/rclone/rclone/fs/log"
  38. "github.com/rclone/rclone/fs/rc"
  39. "github.com/rclone/rclone/fs/walk"
  40. "github.com/rclone/rclone/vfs/vfscache"
  41. "github.com/rclone/rclone/vfs/vfscommon"
  42. )
  43. //go:embed vfs.md
  44. var help string
  45. // Help returns the help string cleaned up to simplify appending
  46. func Help() string {
  47. return strings.TrimSpace(help) + "\n\n"
  48. }
  49. // Node represents either a directory (*Dir) or a file (*File)
  50. type Node interface {
  51. os.FileInfo
  52. IsFile() bool
  53. Inode() uint64
  54. SetModTime(modTime time.Time) error
  55. Sync() error
  56. Remove() error
  57. RemoveAll() error
  58. DirEntry() fs.DirEntry
  59. VFS() *VFS
  60. Open(flags int) (Handle, error)
  61. Truncate(size int64) error
  62. Path() string
  63. SetSys(interface{})
  64. }
  65. // Check interfaces
  66. var (
  67. _ Node = (*File)(nil)
  68. _ Node = (*Dir)(nil)
  69. )
  70. // Nodes is a slice of Node
  71. type Nodes []Node
  72. // Sort functions
  73. func (ns Nodes) Len() int { return len(ns) }
  74. func (ns Nodes) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
  75. func (ns Nodes) Less(i, j int) bool { return ns[i].Path() < ns[j].Path() }
  76. // Noder represents something which can return a node
  77. type Noder interface {
  78. fmt.Stringer
  79. Node() Node
  80. }
  81. // Check interfaces
  82. var (
  83. _ Noder = (*File)(nil)
  84. _ Noder = (*Dir)(nil)
  85. _ Noder = (*ReadFileHandle)(nil)
  86. _ Noder = (*WriteFileHandle)(nil)
  87. _ Noder = (*RWFileHandle)(nil)
  88. _ Noder = (*DirHandle)(nil)
  89. )
  90. // OsFiler is the methods on *os.File
  91. type OsFiler interface {
  92. Chdir() error
  93. Chmod(mode os.FileMode) error
  94. Chown(uid, gid int) error
  95. Close() error
  96. Fd() uintptr
  97. Name() string
  98. Read(b []byte) (n int, err error)
  99. ReadAt(b []byte, off int64) (n int, err error)
  100. Readdir(n int) ([]os.FileInfo, error)
  101. Readdirnames(n int) (names []string, err error)
  102. Seek(offset int64, whence int) (ret int64, err error)
  103. Stat() (os.FileInfo, error)
  104. Sync() error
  105. Truncate(size int64) error
  106. Write(b []byte) (n int, err error)
  107. WriteAt(b []byte, off int64) (n int, err error)
  108. WriteString(s string) (n int, err error)
  109. }
  110. // Handle is the interface satisfied by open files or directories.
  111. // It is the methods on *os.File, plus a few more useful for FUSE
  112. // filingsystems. Not all of them are supported.
  113. type Handle interface {
  114. OsFiler
  115. // Additional methods useful for FUSE filesystems
  116. Flush() error
  117. Release() error
  118. Node() Node
  119. // Size() int64
  120. Lock() error
  121. Unlock() error
  122. }
  123. // baseHandle implements all the missing methods
  124. type baseHandle struct{}
  125. func (h baseHandle) Chdir() error { return ENOSYS }
  126. func (h baseHandle) Chmod(mode os.FileMode) error { return ENOSYS }
  127. func (h baseHandle) Chown(uid, gid int) error { return ENOSYS }
  128. func (h baseHandle) Close() error { return ENOSYS }
  129. func (h baseHandle) Fd() uintptr { return 0 }
  130. func (h baseHandle) Name() string { return "" }
  131. func (h baseHandle) Read(b []byte) (n int, err error) { return 0, ENOSYS }
  132. func (h baseHandle) ReadAt(b []byte, off int64) (n int, err error) { return 0, ENOSYS }
  133. func (h baseHandle) Readdir(n int) ([]os.FileInfo, error) { return nil, ENOSYS }
  134. func (h baseHandle) Readdirnames(n int) (names []string, err error) { return nil, ENOSYS }
  135. func (h baseHandle) Seek(offset int64, whence int) (ret int64, err error) { return 0, ENOSYS }
  136. func (h baseHandle) Stat() (os.FileInfo, error) { return nil, ENOSYS }
  137. func (h baseHandle) Sync() error { return nil }
  138. func (h baseHandle) Truncate(size int64) error { return ENOSYS }
  139. func (h baseHandle) Write(b []byte) (n int, err error) { return 0, ENOSYS }
  140. func (h baseHandle) WriteAt(b []byte, off int64) (n int, err error) { return 0, ENOSYS }
  141. func (h baseHandle) WriteString(s string) (n int, err error) { return 0, ENOSYS }
  142. func (h baseHandle) Flush() (err error) { return ENOSYS }
  143. func (h baseHandle) Release() (err error) { return ENOSYS }
  144. func (h baseHandle) Node() Node { return nil }
  145. func (h baseHandle) Unlock() error { return os.ErrInvalid }
  146. func (h baseHandle) Lock() error { return os.ErrInvalid }
  147. //func (h baseHandle) Size() int64 { return 0 }
  148. // Check interfaces
  149. var (
  150. _ OsFiler = (*os.File)(nil)
  151. _ Handle = (*baseHandle)(nil)
  152. _ Handle = (*ReadFileHandle)(nil)
  153. _ Handle = (*WriteFileHandle)(nil)
  154. _ Handle = (*DirHandle)(nil)
  155. _ billy.File = (Handle)(nil)
  156. )
  157. // VFS represents the top level filing system
  158. type VFS struct {
  159. f fs.Fs
  160. root *Dir
  161. Opt vfscommon.Options
  162. cache *vfscache.Cache
  163. cancelCache context.CancelFunc
  164. usageMu sync.Mutex
  165. usageTime time.Time
  166. usage *fs.Usage
  167. pollChan chan time.Duration
  168. inUse atomic.Int32 // count of number of opens
  169. }
  170. // Keep track of active VFS keyed on fs.ConfigString(f)
  171. var (
  172. activeMu sync.Mutex
  173. active = map[string][]*VFS{}
  174. )
  175. // New creates a new VFS and root directory. If opt is nil, then
  176. // DefaultOpt will be used
  177. func New(f fs.Fs, opt *vfscommon.Options) *VFS {
  178. fsDir := fs.NewDir("", time.Now())
  179. vfs := &VFS{
  180. f: f,
  181. }
  182. vfs.inUse.Store(1)
  183. // Make a copy of the options
  184. if opt != nil {
  185. vfs.Opt = *opt
  186. } else {
  187. vfs.Opt = vfscommon.DefaultOpt
  188. }
  189. // Fill out anything else
  190. vfs.Opt.Init()
  191. // Find a VFS with the same name and options and return it if possible
  192. activeMu.Lock()
  193. defer activeMu.Unlock()
  194. configName := fs.ConfigString(f)
  195. for _, activeVFS := range active[configName] {
  196. if vfs.Opt == activeVFS.Opt {
  197. fs.Debugf(f, "Re-using VFS from active cache")
  198. activeVFS.inUse.Add(1)
  199. return activeVFS
  200. }
  201. }
  202. // Put the VFS into the active cache
  203. active[configName] = append(active[configName], vfs)
  204. // Create root directory
  205. vfs.root = newDir(vfs, f, nil, fsDir)
  206. // Start polling function
  207. features := vfs.f.Features()
  208. if do := features.ChangeNotify; do != nil {
  209. vfs.pollChan = make(chan time.Duration)
  210. do(context.TODO(), vfs.root.changeNotify, vfs.pollChan)
  211. vfs.pollChan <- vfs.Opt.PollInterval
  212. } else if vfs.Opt.PollInterval > 0 {
  213. fs.Infof(f, "poll-interval is not supported by this remote")
  214. }
  215. // Warn if can't stream
  216. if !vfs.Opt.ReadOnly && vfs.Opt.CacheMode < vfscommon.CacheModeWrites && features.PutStream == nil {
  217. fs.Logf(f, "--vfs-cache-mode writes or full is recommended for this remote as it can't stream")
  218. }
  219. // Pin the Fs into the cache so that when we use cache.NewFs
  220. // with the same remote string we get this one. The Pin is
  221. // removed when the vfs is finalized
  222. cache.PinUntilFinalized(f, vfs)
  223. // Refresh the dircache if required
  224. if vfs.Opt.Refresh {
  225. go vfs.refresh()
  226. }
  227. // This can take some time so do it after the Pin
  228. vfs.SetCacheMode(vfs.Opt.CacheMode)
  229. return vfs
  230. }
  231. // refresh the directory cache for all directories
  232. func (vfs *VFS) refresh() {
  233. fs.Debugf(vfs.f, "Refreshing VFS directory cache")
  234. err := vfs.root.readDirTree()
  235. if err != nil {
  236. fs.Errorf(vfs.f, "Error refreshing VFS directory cache: %v", err)
  237. }
  238. }
  239. // Stats returns info about the VFS
  240. func (vfs *VFS) Stats() (out rc.Params) {
  241. out = make(rc.Params)
  242. out["fs"] = fs.ConfigString(vfs.f)
  243. out["opt"] = vfs.Opt
  244. out["inUse"] = vfs.inUse.Load()
  245. var (
  246. dirs int
  247. files int
  248. )
  249. vfs.root.walk(func(d *Dir) {
  250. dirs++
  251. files += len(d.items)
  252. })
  253. inf := make(rc.Params)
  254. out["metadataCache"] = inf
  255. inf["dirs"] = dirs
  256. inf["files"] = files
  257. if vfs.cache != nil {
  258. out["diskCache"] = vfs.cache.Stats()
  259. }
  260. return out
  261. }
  262. // Return the number of active cache entries and a VFS if any are in
  263. // the cache.
  264. func activeCacheEntries() (vfs *VFS, count int) {
  265. activeMu.Lock()
  266. for _, vfses := range active {
  267. count += len(vfses)
  268. if len(vfses) > 0 {
  269. vfs = vfses[0]
  270. }
  271. }
  272. activeMu.Unlock()
  273. return vfs, count
  274. }
  275. // Fs returns the Fs passed into the New call
  276. func (vfs *VFS) Fs() fs.Fs {
  277. return vfs.f
  278. }
  279. // SetCacheMode change the cache mode
  280. func (vfs *VFS) SetCacheMode(cacheMode vfscommon.CacheMode) {
  281. vfs.shutdownCache()
  282. vfs.cache = nil
  283. if cacheMode > vfscommon.CacheModeOff {
  284. ctx, cancel := context.WithCancel(context.Background())
  285. cache, err := vfscache.New(ctx, vfs.f, &vfs.Opt, vfs.AddVirtual) // FIXME pass on context or get from Opt?
  286. if err != nil {
  287. fs.Errorf(nil, "Failed to create vfs cache - disabling: %v", err)
  288. vfs.Opt.CacheMode = vfscommon.CacheModeOff
  289. cancel()
  290. return
  291. }
  292. vfs.Opt.CacheMode = cacheMode
  293. vfs.cancelCache = cancel
  294. vfs.cache = cache
  295. }
  296. }
  297. // shutdown the cache if it was running
  298. func (vfs *VFS) shutdownCache() {
  299. if vfs.cancelCache != nil {
  300. vfs.cancelCache()
  301. vfs.cancelCache = nil
  302. }
  303. }
  304. // Shutdown stops any background go-routines and removes the VFS from
  305. // the active ache.
  306. func (vfs *VFS) Shutdown() {
  307. if vfs.inUse.Add(-1) > 0 {
  308. return
  309. }
  310. // Remove from active cache
  311. activeMu.Lock()
  312. configName := fs.ConfigString(vfs.f)
  313. activeVFSes := active[configName]
  314. for i, activeVFS := range activeVFSes {
  315. if activeVFS == vfs {
  316. activeVFSes[i] = nil
  317. active[configName] = append(activeVFSes[:i], activeVFSes[i+1:]...)
  318. break
  319. }
  320. }
  321. activeMu.Unlock()
  322. vfs.shutdownCache()
  323. }
  324. // CleanUp deletes the contents of the on disk cache
  325. func (vfs *VFS) CleanUp() error {
  326. if vfs.Opt.CacheMode == vfscommon.CacheModeOff {
  327. return nil
  328. }
  329. return vfs.cache.CleanUp()
  330. }
  331. // FlushDirCache empties the directory cache
  332. func (vfs *VFS) FlushDirCache() {
  333. vfs.root.ForgetAll()
  334. }
  335. // WaitForWriters sleeps until all writers have finished or
  336. // time.Duration has elapsed
  337. func (vfs *VFS) WaitForWriters(timeout time.Duration) {
  338. defer log.Trace(nil, "timeout=%v", timeout)("")
  339. tickTime := 10 * time.Millisecond
  340. deadline := time.NewTimer(timeout)
  341. defer deadline.Stop()
  342. tick := time.NewTimer(tickTime)
  343. defer tick.Stop()
  344. tick.Stop()
  345. for {
  346. writers := vfs.root.countActiveWriters()
  347. cacheInUse := 0
  348. if vfs.cache != nil {
  349. cacheInUse = vfs.cache.TotalInUse()
  350. }
  351. if writers == 0 && cacheInUse == 0 {
  352. return
  353. }
  354. fs.Debugf(nil, "Still %d writers active and %d cache items in use, waiting %v", writers, cacheInUse, tickTime)
  355. tick.Reset(tickTime)
  356. select {
  357. case <-tick.C:
  358. case <-deadline.C:
  359. fs.Errorf(nil, "Exiting even though %d writers active and %d cache items in use after %v\n%s", writers, cacheInUse, timeout, vfs.cache.Dump())
  360. return
  361. }
  362. tickTime *= 2
  363. if tickTime > time.Second {
  364. tickTime = time.Second
  365. }
  366. }
  367. }
  368. // Root returns the root node
  369. func (vfs *VFS) Root() (*Dir, error) {
  370. // fs.Debugf(vfs.f, "Root()")
  371. return vfs.root, nil
  372. }
  373. var inodeCount atomic.Uint64
  374. // newInode creates a new unique inode number
  375. func newInode() (inode uint64) {
  376. return inodeCount.Add(1)
  377. }
  378. // Stat finds the Node by path starting from the root
  379. //
  380. // It is the equivalent of os.Stat - Node contains the os.FileInfo
  381. // interface.
  382. func (vfs *VFS) Stat(path string) (node Node, err error) {
  383. path = strings.Trim(path, "/")
  384. node = vfs.root
  385. for path != "" {
  386. i := strings.IndexRune(path, '/')
  387. var name string
  388. if i < 0 {
  389. name, path = path, ""
  390. } else {
  391. name, path = path[:i], path[i+1:]
  392. }
  393. if name == "" {
  394. continue
  395. }
  396. dir, ok := node.(*Dir)
  397. if !ok {
  398. // We need to look in a directory, but found a file
  399. return nil, ENOENT
  400. }
  401. node, err = dir.Stat(name)
  402. if err != nil {
  403. return nil, err
  404. }
  405. }
  406. return
  407. }
  408. // StatParent finds the parent directory and the leaf name of a path
  409. func (vfs *VFS) StatParent(name string) (dir *Dir, leaf string, err error) {
  410. name = strings.Trim(name, "/")
  411. parent, leaf := path.Split(name)
  412. node, err := vfs.Stat(parent)
  413. if err != nil {
  414. return nil, "", err
  415. }
  416. if node.IsFile() {
  417. return nil, "", os.ErrExist
  418. }
  419. dir = node.(*Dir)
  420. return dir, leaf, nil
  421. }
  422. // decodeOpenFlags returns a string representing the open flags
  423. func decodeOpenFlags(flags int) string {
  424. var out []string
  425. rdwrMode := flags & accessModeMask
  426. switch rdwrMode {
  427. case os.O_RDONLY:
  428. out = append(out, "O_RDONLY")
  429. case os.O_WRONLY:
  430. out = append(out, "O_WRONLY")
  431. case os.O_RDWR:
  432. out = append(out, "O_RDWR")
  433. default:
  434. out = append(out, fmt.Sprintf("0x%X", rdwrMode))
  435. }
  436. if flags&os.O_APPEND != 0 {
  437. out = append(out, "O_APPEND")
  438. }
  439. if flags&os.O_CREATE != 0 {
  440. out = append(out, "O_CREATE")
  441. }
  442. if flags&os.O_EXCL != 0 {
  443. out = append(out, "O_EXCL")
  444. }
  445. if flags&os.O_SYNC != 0 {
  446. out = append(out, "O_SYNC")
  447. }
  448. if flags&os.O_TRUNC != 0 {
  449. out = append(out, "O_TRUNC")
  450. }
  451. flags &^= accessModeMask | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC
  452. if flags != 0 {
  453. out = append(out, fmt.Sprintf("0x%X", flags))
  454. }
  455. return strings.Join(out, "|")
  456. }
  457. // OpenFile a file according to the flags and perm provided
  458. func (vfs *VFS) OpenFile(name string, flags int, perm os.FileMode) (fd Handle, err error) {
  459. defer log.Trace(name, "flags=%s, perm=%v", decodeOpenFlags(flags), perm)("fd=%v, err=%v", &fd, &err)
  460. // http://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html
  461. // The result of using O_TRUNC with O_RDONLY is undefined.
  462. // Linux seems to truncate the file, but we prefer to return EINVAL
  463. if flags&accessModeMask == os.O_RDONLY && flags&os.O_TRUNC != 0 {
  464. return nil, EINVAL
  465. }
  466. node, err := vfs.Stat(name)
  467. if err != nil {
  468. if err != ENOENT || flags&os.O_CREATE == 0 {
  469. return nil, err
  470. }
  471. // If not found and O_CREATE then create the file
  472. dir, leaf, err := vfs.StatParent(name)
  473. if err != nil {
  474. return nil, err
  475. }
  476. node, err = dir.Create(leaf, flags)
  477. if err != nil {
  478. return nil, err
  479. }
  480. }
  481. return node.Open(flags)
  482. }
  483. // Open opens the named file for reading. If successful, methods on
  484. // the returned file can be used for reading; the associated file
  485. // descriptor has mode O_RDONLY.
  486. func (vfs *VFS) Open(name string) (Handle, error) {
  487. return vfs.OpenFile(name, os.O_RDONLY, 0)
  488. }
  489. // Create creates the named file with mode 0666 (before umask), truncating
  490. // it if it already exists. If successful, methods on the returned
  491. // File can be used for I/O; the associated file descriptor has mode
  492. // O_RDWR.
  493. func (vfs *VFS) Create(name string) (Handle, error) {
  494. return vfs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
  495. }
  496. // Rename oldName to newName
  497. func (vfs *VFS) Rename(oldName, newName string) error {
  498. // find the parent directories
  499. oldDir, oldLeaf, err := vfs.StatParent(oldName)
  500. if err != nil {
  501. return err
  502. }
  503. newDir, newLeaf, err := vfs.StatParent(newName)
  504. if err != nil {
  505. return err
  506. }
  507. err = oldDir.Rename(oldLeaf, newLeaf, newDir)
  508. if err != nil {
  509. return err
  510. }
  511. return nil
  512. }
  513. // This works out the missing values from (total, used, free) using
  514. // unknownFree as the intended free space
  515. func fillInMissingSizes(total, used, free, unknownFree int64) (newTotal, newUsed, newFree int64) {
  516. if total < 0 {
  517. if free >= 0 {
  518. total = free
  519. } else {
  520. total = unknownFree
  521. }
  522. if used >= 0 {
  523. total += used
  524. }
  525. }
  526. // total is now defined
  527. if used < 0 {
  528. if free >= 0 {
  529. used = total - free
  530. } else {
  531. used = 0
  532. }
  533. }
  534. // used is now defined
  535. if free < 0 {
  536. free = total - used
  537. }
  538. return total, used, free
  539. }
  540. // If the total size isn't known then we will aim for this many bytes free (1 PiB)
  541. const unknownFreeBytes = 1 << 50
  542. // Statfs returns into about the filing system if known
  543. //
  544. // The values will be -1 if they aren't known
  545. //
  546. // This information is cached for the DirCacheTime interval
  547. func (vfs *VFS) Statfs() (total, used, free int64) {
  548. // defer log.Trace("/", "")("total=%d, used=%d, free=%d", &total, &used, &free)
  549. vfs.usageMu.Lock()
  550. defer vfs.usageMu.Unlock()
  551. total, used, free = -1, -1, -1
  552. doAbout := vfs.f.Features().About
  553. if (doAbout != nil || vfs.Opt.UsedIsSize) && (vfs.usageTime.IsZero() || time.Since(vfs.usageTime) >= vfs.Opt.DirCacheTime) {
  554. var err error
  555. ctx := context.TODO()
  556. if doAbout == nil {
  557. vfs.usage = &fs.Usage{}
  558. } else {
  559. vfs.usage, err = doAbout(ctx)
  560. }
  561. if vfs.Opt.UsedIsSize {
  562. var usedBySizeAlgorithm int64
  563. // Algorithm from `rclone size`
  564. err = walk.ListR(ctx, vfs.f, "", true, -1, walk.ListObjects, func(entries fs.DirEntries) error {
  565. entries.ForObject(func(o fs.Object) {
  566. usedBySizeAlgorithm += o.Size()
  567. })
  568. return nil
  569. })
  570. vfs.usage.Used = &usedBySizeAlgorithm
  571. }
  572. vfs.usageTime = time.Now()
  573. if err != nil {
  574. fs.Errorf(vfs.f, "Statfs failed: %v", err)
  575. return
  576. }
  577. }
  578. if u := vfs.usage; u != nil {
  579. if u.Total != nil {
  580. total = *u.Total
  581. }
  582. if u.Free != nil {
  583. free = *u.Free
  584. }
  585. if u.Used != nil {
  586. used = *u.Used
  587. }
  588. }
  589. if int64(vfs.Opt.DiskSpaceTotalSize) >= 0 {
  590. total = int64(vfs.Opt.DiskSpaceTotalSize)
  591. }
  592. total, used, free = fillInMissingSizes(total, used, free, unknownFreeBytes)
  593. return
  594. }
  595. // Remove removes the named file or (empty) directory.
  596. func (vfs *VFS) Remove(name string) error {
  597. node, err := vfs.Stat(name)
  598. if err != nil {
  599. return err
  600. }
  601. err = node.Remove()
  602. if err != nil {
  603. return err
  604. }
  605. return nil
  606. }
  607. // Chtimes changes the access and modification times of the named file, similar
  608. // to the Unix utime() or utimes() functions.
  609. //
  610. // The underlying filesystem may truncate or round the values to a less precise
  611. // time unit.
  612. func (vfs *VFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
  613. node, err := vfs.Stat(name)
  614. if err != nil {
  615. return err
  616. }
  617. err = node.SetModTime(mtime)
  618. if err != nil {
  619. return err
  620. }
  621. return nil
  622. }
  623. // mkdir creates a new directory with the specified name and permission bits
  624. // (before umask) returning the new directory node.
  625. func (vfs *VFS) mkdir(name string, perm os.FileMode) (*Dir, error) {
  626. dir, leaf, err := vfs.StatParent(name)
  627. if err != nil {
  628. return nil, err
  629. }
  630. return dir.Mkdir(leaf)
  631. }
  632. // Mkdir creates a new directory with the specified name and permission bits
  633. // (before umask).
  634. func (vfs *VFS) Mkdir(name string, perm os.FileMode) error {
  635. _, err := vfs.mkdir(name, perm)
  636. return err
  637. }
  638. // mkdirAll creates a new directory with the specified name and
  639. // permission bits (before umask) and all of its parent directories up
  640. // to the root.
  641. func (vfs *VFS) mkdirAll(name string, perm os.FileMode) (dir *Dir, err error) {
  642. name = strings.Trim(name, "/")
  643. // the root directory node already exists even if the directory isn't created yet
  644. if name == "" {
  645. return vfs.root, nil
  646. }
  647. var parent, leaf string
  648. dir, leaf, err = vfs.StatParent(name)
  649. if err == ENOENT {
  650. parent, leaf = path.Split(name)
  651. dir, err = vfs.mkdirAll(parent, perm)
  652. }
  653. if err != nil {
  654. return nil, err
  655. }
  656. dir, err = dir.Mkdir(leaf)
  657. if err != nil {
  658. return nil, err
  659. }
  660. return dir, nil
  661. }
  662. // MkdirAll creates a new directory with the specified name and
  663. // permission bits (before umask) and all of its parent directories up
  664. // to the root.
  665. func (vfs *VFS) MkdirAll(name string, perm os.FileMode) error {
  666. _, err := vfs.mkdirAll(name, perm)
  667. return err
  668. }
  669. // ReadDir reads the directory named by dirname and returns
  670. // a list of directory entries sorted by filename.
  671. func (vfs *VFS) ReadDir(dirname string) ([]os.FileInfo, error) {
  672. f, err := vfs.Open(dirname)
  673. if err != nil {
  674. return nil, err
  675. }
  676. list, err := f.Readdir(-1)
  677. closeErr := f.Close()
  678. if err != nil {
  679. return nil, err
  680. }
  681. if closeErr != nil {
  682. return nil, closeErr
  683. }
  684. sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
  685. return list, nil
  686. }
  687. // ReadFile reads the file named by filename and returns the contents.
  688. // A successful call returns err == nil, not err == EOF. Because ReadFile
  689. // reads the whole file, it does not treat an EOF from Read as an error
  690. // to be reported.
  691. func (vfs *VFS) ReadFile(filename string) (b []byte, err error) {
  692. f, err := vfs.Open(filename)
  693. if err != nil {
  694. return nil, err
  695. }
  696. defer fs.CheckClose(f, &err)
  697. return io.ReadAll(f)
  698. }
  699. // AddVirtual adds the object (file or dir) to the directory cache
  700. func (vfs *VFS) AddVirtual(remote string, size int64, isDir bool) (err error) {
  701. remote = strings.TrimRight(remote, "/")
  702. var dir *Dir
  703. var parent, leaf string
  704. if vfs.f.Features().CanHaveEmptyDirectories {
  705. dir, leaf, err = vfs.StatParent(remote)
  706. } else {
  707. // Create parent of virtual directory since backend can't have empty directories
  708. parent, leaf = path.Split(remote)
  709. dir, err = vfs.mkdirAll(parent, vfs.Opt.DirPerms)
  710. }
  711. if err != nil {
  712. return err
  713. }
  714. dir.AddVirtual(leaf, size, false)
  715. return nil
  716. }