mirror of
https://github.com/rclone/rclone
synced 2024-11-29 07:55:12 +01:00
vfs: factor duplicated Open code into vfs from mount/cmount
This commit is contained in:
parent
a5dc62f6c1
commit
190367d917
@ -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
|
||||
}
|
||||
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
|
||||
|
||||
switch fh := handle.(type) {
|
||||
case *vfs.WriteFileHandle:
|
||||
return 0, fsys.openFilesWr.Open(fh)
|
||||
case *vfs.ReadFileHandle:
|
||||
return 0, fsys.openFilesRd.Open(fh)
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
30
vfs/dir.go
30
vfs/dir.go
@ -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()
|
||||
|
@ -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
|
||||
|
32
vfs/file.go
32
vfs/file.go
@ -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
|
||||
}
|
||||
|
40
vfs/vfs.go
40
vfs/vfs.go
@ -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,41 +248,9 @@ 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)
|
||||
}
|
||||
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) {
|
||||
if err == ENOENT && flags&os.O_CREATE != 0 {
|
||||
dir, leaf, err := vfs.StatParent(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -288,6 +258,10 @@ func (vfs *VFS) createFile(name string, flags int, perm os.FileMode) (fd Handle,
|
||||
_, fd, err = dir.Create(leaf)
|
||||
return fd, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return node.Open(flags)
|
||||
}
|
||||
|
||||
// Rename oldName to newName
|
||||
func (vfs *VFS) Rename(oldName, newName string) error {
|
||||
|
Loading…
Reference in New Issue
Block a user