filesystem.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //go:build unix
  2. package nfs
  3. import (
  4. "os"
  5. "path"
  6. "strings"
  7. "time"
  8. billy "github.com/go-git/go-billy/v5"
  9. "github.com/rclone/rclone/fs"
  10. "github.com/rclone/rclone/vfs"
  11. "github.com/rclone/rclone/vfs/vfscommon"
  12. )
  13. // FS is our wrapper around the VFS to properly support billy.Filesystem interface
  14. type FS struct {
  15. vfs *vfs.VFS
  16. }
  17. // ReadDir implements read dir
  18. func (f *FS) ReadDir(path string) (dir []os.FileInfo, err error) {
  19. fs.Debugf("nfs", "ReadDir %v", path)
  20. return f.vfs.ReadDir(path)
  21. }
  22. // Create implements creating new files
  23. func (f *FS) Create(filename string) (billy.File, error) {
  24. fs.Debugf("nfs", "Create %v", filename)
  25. return f.vfs.Create(filename)
  26. }
  27. // Open opens a file
  28. func (f *FS) Open(filename string) (billy.File, error) {
  29. file, err := f.vfs.Open(filename)
  30. fs.Debugf("nfs", "Open %v file: %v err: %v", filename, file, err)
  31. return file, err
  32. }
  33. // OpenFile opens a file
  34. func (f *FS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
  35. file, err := f.vfs.OpenFile(filename, flag, perm)
  36. fs.Debugf("nfs", "OpenFile %v flag: %v perm: %v file: %v err: %v", filename, flag, perm, file, err)
  37. return file, err
  38. }
  39. // Stat gets the file stat
  40. func (f *FS) Stat(filename string) (os.FileInfo, error) {
  41. node, err := f.vfs.Stat(filename)
  42. fs.Debugf("nfs", "Stat %v node: %v err: %v", filename, node, err)
  43. return node, err
  44. }
  45. // Rename renames a file
  46. func (f *FS) Rename(oldpath, newpath string) error {
  47. return f.vfs.Rename(oldpath, newpath)
  48. }
  49. // Remove deletes a file
  50. func (f *FS) Remove(filename string) error {
  51. return f.vfs.Remove(filename)
  52. }
  53. // Join joins path elements
  54. func (f *FS) Join(elem ...string) string {
  55. return path.Join(elem...)
  56. }
  57. // TempFile is not implemented
  58. func (f *FS) TempFile(dir, prefix string) (billy.File, error) {
  59. return nil, os.ErrInvalid
  60. }
  61. // MkdirAll creates a directory and all the ones above it
  62. // it does not redirect to VFS.MkDirAll because that one doesn't
  63. // honor the permissions
  64. func (f *FS) MkdirAll(filename string, perm os.FileMode) error {
  65. parts := strings.Split(filename, "/")
  66. for i := range parts {
  67. current := strings.Join(parts[:i+1], "/")
  68. _, err := f.Stat(current)
  69. if err == vfs.ENOENT {
  70. err = f.vfs.Mkdir(current, perm)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. }
  76. return nil
  77. }
  78. // Lstat gets the stats for symlink
  79. func (f *FS) Lstat(filename string) (os.FileInfo, error) {
  80. node, err := f.vfs.Stat(filename)
  81. fs.Debugf("nfs", "Lstat %v node: %v err: %v", filename, node, err)
  82. return node, err
  83. }
  84. // Symlink is not supported over NFS
  85. func (f *FS) Symlink(target, link string) error {
  86. return os.ErrInvalid
  87. }
  88. // Readlink is not supported
  89. func (f *FS) Readlink(link string) (string, error) {
  90. return "", os.ErrInvalid
  91. }
  92. // Chmod changes the file modes
  93. func (f *FS) Chmod(name string, mode os.FileMode) error {
  94. file, err := f.vfs.Open(name)
  95. if err != nil {
  96. return err
  97. }
  98. defer func() {
  99. if err := file.Close(); err != nil {
  100. fs.Logf(f, "Error while closing file: %e", err)
  101. }
  102. }()
  103. return file.Chmod(mode)
  104. }
  105. // Lchown changes the owner of symlink
  106. func (f *FS) Lchown(name string, uid, gid int) error {
  107. return f.Chown(name, uid, gid)
  108. }
  109. // Chown changes owner of the file
  110. func (f *FS) Chown(name string, uid, gid int) error {
  111. file, err := f.vfs.Open(name)
  112. if err != nil {
  113. return err
  114. }
  115. defer func() {
  116. if err := file.Close(); err != nil {
  117. fs.Logf(f, "Error while closing file: %e", err)
  118. }
  119. }()
  120. return file.Chown(uid, gid)
  121. }
  122. // Chtimes changes the acces time and modified time
  123. func (f *FS) Chtimes(name string, atime time.Time, mtime time.Time) error {
  124. return f.vfs.Chtimes(name, atime, mtime)
  125. }
  126. // Chroot is not supported in VFS
  127. func (f *FS) Chroot(path string) (billy.Filesystem, error) {
  128. return nil, os.ErrInvalid
  129. }
  130. // Root returns the root of a VFS
  131. func (f *FS) Root() string {
  132. return f.vfs.Fs().Root()
  133. }
  134. // Capabilities exports the filesystem capabilities
  135. func (f *FS) Capabilities() billy.Capability {
  136. if f.vfs.Opt.CacheMode == vfscommon.CacheModeOff {
  137. return billy.ReadCapability | billy.SeekCapability
  138. }
  139. return billy.WriteCapability | billy.ReadCapability |
  140. billy.ReadAndWriteCapability | billy.SeekCapability | billy.TruncateCapability
  141. }
  142. // Interface check
  143. var _ billy.Filesystem = (*FS)(nil)