1
mirror of https://github.com/rclone/rclone synced 2024-11-26 04:07:22 +01:00

vfs: factor duplicated Open code into vfs from mount/cmount

This commit is contained in:
Nick Craig-Wood 2017-10-30 10:14:39 +00:00
parent a5dc62f6c1
commit 190367d917
7 changed files with 106 additions and 104 deletions

View File

@ -337,31 +337,21 @@ func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
// Open opens a file
func (fsys *FS) Open(path string, flags int) (errc int, fh uint64) {
defer fs.Trace(path, "flags=0x%X", flags)("errc=%d, fh=0x%X", &errc, &fh)
file, errc := fsys.lookupFile(path)
// fuse flags are based off syscall flags as are os flags, so
// should be compatible
handle, err := fsys.VFS.OpenFile(path, flags, 0777)
if errc != 0 {
return errc, fhUnset
return translateError(err), fhUnset
}
rdwrMode := flags & fuse.O_ACCMODE
var err error
var handle vfs.Noder
switch {
case rdwrMode == fuse.O_RDONLY:
handle, err = file.OpenRead()
if err != nil {
return translateError(err), fhUnset
}
return 0, fsys.openFilesRd.Open(handle)
case rdwrMode == fuse.O_WRONLY || (rdwrMode == fuse.O_RDWR && (flags&fuse.O_TRUNC) != 0):
handle, err = file.OpenWrite()
if err != nil {
return translateError(err), fhUnset
}
return 0, fsys.openFilesWr.Open(handle)
case rdwrMode == fuse.O_RDWR:
fs.Errorf(path, "Can't open for Read and Write")
return -fuse.EPERM, fhUnset
switch fh := handle.(type) {
case *vfs.WriteFileHandle:
return 0, fsys.openFilesWr.Open(fh)
case *vfs.ReadFileHandle:
return 0, fsys.openFilesRd.Open(fh)
}
fs.Errorf(path, "Can't figure out how to open with flags: 0x%X", flags)
return -fuse.EPERM, fhUnset
}
@ -648,6 +638,8 @@ func translateError(err error) (errc int) {
return -fuse.EBADF
case vfs.EROFS:
return -fuse.EROFS
case vfs.ENOSYS:
return -fuse.ENOSYS
}
fs.Errorf(nil, "IO error: %v", err)
return -fuse.EIO

View File

@ -9,7 +9,6 @@ import (
fusefs "bazil.org/fuse/fs"
"github.com/ncw/rclone/fs"
"github.com/ncw/rclone/vfs"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
@ -62,40 +61,27 @@ var _ fusefs.NodeOpener = (*File)(nil)
// Open the file for read or write
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fh fusefs.Handle, err error) {
defer fs.Trace(f, "flags=%v", req.Flags)("fh=%v, err=%v", &fh, &err)
switch {
case req.Flags.IsReadOnly():
if f.VFS().Opt.NoSeek {
resp.Flags |= fuse.OpenNonSeekable
}
var rfh *vfs.ReadFileHandle
rfh, err = f.File.OpenRead()
fh = &ReadFileHandle{rfh}
case req.Flags.IsWriteOnly() || (req.Flags.IsReadWrite() && (req.Flags&fuse.OpenTruncate) != 0):
resp.Flags |= fuse.OpenNonSeekable
var wfh *vfs.WriteFileHandle
wfh, err = f.File.OpenWrite()
fh = &WriteFileHandle{wfh}
case req.Flags.IsReadWrite():
err = errors.New("can't open for read and write simultaneously")
default:
err = errors.Errorf("can't figure out how to open with flags %v", req.Flags)
}
/*
// File was opened in append-only mode, all writes will go to end
// of file. OS X does not provide this information.
OpenAppend OpenFlags = syscall.O_APPEND
OpenCreate OpenFlags = syscall.O_CREAT
OpenDirectory OpenFlags = syscall.O_DIRECTORY
OpenExclusive OpenFlags = syscall.O_EXCL
OpenNonblock OpenFlags = syscall.O_NONBLOCK
OpenSync OpenFlags = syscall.O_SYNC
OpenTruncate OpenFlags = syscall.O_TRUNC
*/
// fuse flags are based off syscall flags as are os flags, so
// should be compatible
handle, err := f.File.Open(int(resp.Flags))
if err != nil {
return nil, translateError(err)
}
switch h := handle.(type) {
case *vfs.ReadFileHandle:
if f.VFS().Opt.NoSeek {
resp.Flags |= fuse.OpenNonSeekable
}
fh = &ReadFileHandle{h}
case *vfs.WriteFileHandle:
resp.Flags |= fuse.OpenNonSeekable
fh = &WriteFileHandle{h}
default:
panic("unknown file handle type")
}
return fh, nil
}

View File

@ -84,6 +84,8 @@ func translateError(err error) error {
return fuse.Errno(syscall.EBADF)
case vfs.EROFS:
return fuse.Errno(syscall.EROFS)
case vfs.ENOSYS:
return fuse.Errno(syscall.ENOSYS)
}
return err
}

View File

@ -211,7 +211,7 @@ func (d *Dir) _readDir() error {
d.items[name] = newDir(d.vfs, d.f, d, dir)
default:
err = errors.Errorf("unknown type %T", item)
fs.Errorf(d.path, "readDir error: %v", err)
fs.Errorf(d, "readDir error: %v", err)
return err
}
}
@ -276,12 +276,11 @@ func (d *Dir) SetModTime(modTime time.Time) error {
//
// Stat need not to handle the names "." and "..".
func (d *Dir) Stat(name string) (node Node, err error) {
path := path.Join(d.path, name)
// fs.Debugf(path, "Dir.Stat")
node, err = d.stat(name)
if err != nil {
if err != ENOENT {
fs.Errorf(path, "Dir.Stat error: %v", err)
fs.Errorf(d, "Dir.Stat error: %v", err)
}
return nil, err
}
@ -307,6 +306,16 @@ func (d *Dir) ReadDirAll() (items Nodes, err error) {
return items, nil
}
// Open the directory according to the flags provided
func (d *Dir) Open(flags int) (fd Handle, err error) {
rdwrMode := flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
if rdwrMode != os.O_RDONLY {
fs.Errorf(d, "Can only open directories read only")
return nil, os.ErrPermission
}
return newDirHandle(d), nil
}
// Create makes a new file
func (d *Dir) Create(name string) (*File, *WriteFileHandle, error) {
if d.vfs.Opt.ReadOnly {
@ -319,7 +328,7 @@ func (d *Dir) Create(name string) (*File, *WriteFileHandle, error) {
file := newFile(d, nil, name)
fh, err := newWriteFileHandle(d, file, src)
if err != nil {
fs.Errorf(path, "Dir.Create error: %v", err)
fs.Errorf(d, "Dir.Create error: %v", err)
return nil, nil, err
}
// fs.Debugf(path, "Dir.Create OK")
@ -335,7 +344,7 @@ func (d *Dir) Mkdir(name string) (*Dir, error) {
// fs.Debugf(path, "Dir.Mkdir")
err := d.f.Mkdir(path)
if err != nil {
fs.Errorf(path, "Dir.Mkdir failed to create directory: %v", err)
fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err)
return nil, err
}
fsDir := fs.NewDir(path, time.Now())
@ -353,17 +362,17 @@ func (d *Dir) Remove() error {
// Check directory is empty first
empty, err := d.isEmpty()
if err != nil {
fs.Errorf(d.path, "Dir.Remove dir error: %v", err)
fs.Errorf(d, "Dir.Remove dir error: %v", err)
return err
}
if !empty {
fs.Errorf(d.path, "Dir.Remove not empty")
fs.Errorf(d, "Dir.Remove not empty")
return ENOTEMPTY
}
// remove directory
err = d.f.Rmdir(d.path)
if err != nil {
fs.Errorf(d.path, "Dir.Remove failed to remove directory: %v", err)
fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err)
return err
}
// Remove the item from the parent directory listing
@ -381,7 +390,7 @@ func (d *Dir) RemoveAll() error {
// Remove contents of the directory
nodes, err := d.ReadDirAll()
if err != nil {
fs.Errorf(d.path, "Dir.RemoveAll failed to read directory: %v", err)
fs.Errorf(d, "Dir.RemoveAll failed to read directory: %v", err)
return err
}
for _, node := range nodes {
@ -406,11 +415,10 @@ func (d *Dir) RemoveName(name string) error {
if d.vfs.Opt.ReadOnly {
return EROFS
}
path := path.Join(d.path, name)
// fs.Debugf(path, "Dir.Remove")
node, err := d.stat(name)
if err != nil {
fs.Errorf(path, "Dir.Remove error: %v", err)
fs.Errorf(d, "Dir.Remove error: %v", err)
return err
}
return node.Remove()

View File

@ -19,11 +19,27 @@ func newDirHandle(d *Dir) *DirHandle {
}
}
// String converts it to printable
func (fh *DirHandle) String() string {
if fh == nil {
return "<nil *DirHandle>"
}
if fh.d == nil {
return "<nil *DirHandle.d>"
}
return fh.d.String() + " (r)"
}
// Stat returns info about the current directory
func (fh *DirHandle) Stat() (fi os.FileInfo, err error) {
return fh.d, nil
}
// Node returns the Node assocuated with this - satisfies Noder interface
func (fh *DirHandle) Node() Node {
return fh.d
}
// Readdir reads the contents of the directory associated with file and returns
// a slice of up to n FileInfo values, as would be returned by Lstat, in
// directory order. Subsequent calls on the same file will yield further

View File

@ -161,7 +161,7 @@ func (f *File) applyPendingModTime() error {
case fs.ErrorCantSetModTime, fs.ErrorCantSetModTimeWithoutDelete:
// do nothing, in order to not break "touch somefile" if it exists already
default:
fs.Errorf(f.o, "File.applyPendingModTime error: %v", err)
fs.Errorf(f, "File.applyPendingModTime error: %v", err)
return err
}
@ -216,7 +216,7 @@ func (f *File) OpenRead() (fh *ReadFileHandle, err error) {
err = errors.Wrap(err, "open for read")
if err != nil {
fs.Errorf(o, "File.OpenRead failed: %v", err)
fs.Errorf(f, "File.OpenRead failed: %v", err)
return nil, err
}
return fh, nil
@ -239,7 +239,7 @@ func (f *File) OpenWrite() (fh *WriteFileHandle, err error) {
err = errors.Wrap(err, "open for write")
if err != nil {
fs.Errorf(o, "File.OpenWrite failed: %v", err)
fs.Errorf(f, "File.OpenWrite failed: %v", err)
return nil, err
}
return fh, nil
@ -259,7 +259,7 @@ func (f *File) Remove() error {
}
err := f.o.Remove()
if err != nil {
fs.Errorf(f.o, "File.Remove file error: %v", err)
fs.Errorf(f, "File.Remove file error: %v", err)
return err
}
// Remove the item from the directory listing
@ -286,3 +286,27 @@ func (f *File) Dir() *Dir {
func (f *File) VFS() *VFS {
return f.d.vfs
}
// Open a file according to the flags provided
func (f *File) Open(flags int) (fd Handle, err error) {
rdwrMode := flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
var read bool
switch {
case rdwrMode == os.O_RDONLY:
read = true
case rdwrMode == os.O_WRONLY || (rdwrMode == os.O_RDWR && (flags&os.O_TRUNC) != 0):
read = false
case rdwrMode == os.O_RDWR:
fs.Errorf(f, "Can't open for Read and Write")
return nil, os.ErrPermission
default:
fs.Errorf(f, "Can't figure out how to open with flags: 0x%X", flags)
return nil, os.ErrPermission
}
if read {
fd, err = f.OpenRead()
} else {
fd, err = f.OpenWrite()
}
return fd, err
}

View File

@ -50,6 +50,7 @@ type Node interface {
RemoveAll() error
DirEntry() fs.DirEntry
VFS() *VFS
Open(flags int) (Handle, error)
}
// Check interfaces
@ -78,6 +79,7 @@ var (
_ Noder = (*Dir)(nil)
_ Noder = (*ReadFileHandle)(nil)
_ Noder = (*WriteFileHandle)(nil)
_ Noder = (*DirHandle)(nil)
)
// Handle is the interface statisified by open files or directories.
@ -246,47 +248,19 @@ func (vfs *VFS) StatParent(name string) (dir *Dir, leaf string, err error) {
// OpenFile a file according to the flags and perm provided
func (vfs *VFS) OpenFile(name string, flags int, perm os.FileMode) (fd Handle, err error) {
rdwrMode := flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
var read bool
switch {
case rdwrMode == os.O_RDONLY:
read = true
case rdwrMode == os.O_WRONLY || (rdwrMode == os.O_RDWR && (flags&os.O_TRUNC) != 0):
read = false
case rdwrMode == os.O_RDWR:
fs.Errorf(name, "Can't open for Read and Write")
return nil, os.ErrPermission
default:
fs.Errorf(name, "Can't figure out how to open with flags: 0x%X", flags)
return nil, os.ErrPermission
}
node, err := vfs.Stat(name)
if err != nil {
if err == os.ErrNotExist && !read {
return vfs.createFile(name, flags, perm)
if err == ENOENT && flags&os.O_CREATE != 0 {
dir, leaf, err := vfs.StatParent(name)
if err != nil {
return nil, err
}
_, fd, err = dir.Create(leaf)
return fd, err
}
return nil, err
}
if node.IsFile() {
file := node.(*File)
if read {
fd, err = file.OpenRead()
} else {
fd, err = file.OpenWrite()
}
} else {
fd, err = newDirHandle(node.(*Dir)), nil
}
return fd, err
}
func (vfs *VFS) createFile(name string, flags int, perm os.FileMode) (fd Handle, err error) {
dir, leaf, err := vfs.StatParent(name)
if err != nil {
return nil, err
}
_, fd, err = dir.Create(leaf)
return fd, err
return node.Open(flags)
}
// Rename oldName to newName