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)