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