1
mirror of https://github.com/rclone/rclone synced 2024-12-26 18:23:45 +01:00

mount,vfs: unify Read and Write handles in preparation for ReadWrite handles

This commit is contained in:
Nick Craig-Wood 2017-11-02 18:22:26 +00:00
parent e18122e88b
commit 5634659ea3
6 changed files with 27 additions and 85 deletions

View File

@ -126,7 +126,7 @@ func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.Cr
if err != nil { if err != nil {
return nil, nil, translateError(err) return nil, nil, translateError(err)
} }
return &File{file}, &WriteFileHandle{fh}, err return &File{file}, &FileHandle{fh}, err
} }
var _ fusefs.NodeMkdirer = (*Dir)(nil) var _ fusefs.NodeMkdirer = (*Dir)(nil)

View File

@ -69,20 +69,12 @@ func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR
return nil, translateError(err) return nil, translateError(err)
} }
switch h := handle.(type) { // See if seeking is supported and set FUSE hint accordingly
case *vfs.ReadFileHandle: if _, err = handle.Seek(0, 1); err != nil {
if f.VFS().Opt.NoSeek {
resp.Flags |= fuse.OpenNonSeekable 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 return &FileHandle{handle}, nil
} }
// Check interface satisfied // Check interface satisfied

View File

@ -3,7 +3,6 @@
package mount package mount
import ( import (
"errors"
"io" "io"
"bazil.org/fuse" "bazil.org/fuse"
@ -13,11 +12,9 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
) )
var errClosedFileHandle = errors.New("Attempt to use closed file handle") // FileHandle is an open for read file handle on a File
type FileHandle struct {
// WriteFileHandle is an open for write handle on a File vfs.Handle
type WriteFileHandle struct {
*vfs.WriteFileHandle
} }
// Check interface satisfied // Check interface satisfied
@ -39,12 +36,12 @@ func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fus
} }
// Check interface satisfied // Check interface satisfied
var _ fusefs.HandleWriter = (*WriteFileHandle)(nil) var _ fusefs.HandleWriter = (*FileHandle)(nil)
// Write data to the file handle // Write data to the file handle
func (fh *WriteFileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) (err error) { func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) (err error) {
defer fs.Trace(fh, "len=%d, offset=%d", len(req.Data), req.Offset)("written=%d, err=%v", &resp.Size, &err) defer fs.Trace(fh, "len=%d, offset=%d", len(req.Data), req.Offset)("written=%d, err=%v", &resp.Size, &err)
n, err := fh.WriteFileHandle.WriteAt(req.Data, req.Offset) n, err := fh.Handle.WriteAt(req.Data, req.Offset)
if err != nil { if err != nil {
return translateError(err) return translateError(err)
} }
@ -52,6 +49,9 @@ func (fh *WriteFileHandle) Write(ctx context.Context, req *fuse.WriteRequest, re
return nil return nil
} }
// Check interface satisfied
var _ fusefs.HandleFlusher = (*FileHandle)(nil)
// Flush is called on each close() of a file descriptor. So if a // Flush is called on each close() of a file descriptor. So if a
// filesystem wants to return write errors in close() and the file has // filesystem wants to return write errors in close() and the file has
// cached dirty data, this is a good place to write back data and // cached dirty data, this is a good place to write back data and
@ -67,18 +67,18 @@ func (fh *WriteFileHandle) Write(ctx context.Context, req *fuse.WriteRequest, re
// //
// Filesystems shouldn't assume that flush will always be called after // Filesystems shouldn't assume that flush will always be called after
// some writes, or that if will be called at all. // some writes, or that if will be called at all.
func (fh *WriteFileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) (err error) { func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) (err error) {
defer fs.Trace(fh, "")("err=%v", &err) defer fs.Trace(fh, "")("err=%v", &err)
return translateError(fh.WriteFileHandle.Flush()) return translateError(fh.Handle.Flush())
} }
var _ fusefs.HandleReleaser = (*WriteFileHandle)(nil) var _ fusefs.HandleReleaser = (*FileHandle)(nil)
// Release is called when we are finished with the file handle // Release is called when we are finished with the file handle
// //
// It isn't called directly from userspace so the error is ignored by // It isn't called directly from userspace so the error is ignored by
// the kernel // the kernel
func (fh *WriteFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) (err error) { func (fh *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) (err error) {
defer fs.Trace(fh, "")("err=%v", &err) defer fs.Trace(fh, "")("err=%v", &err)
return translateError(fh.WriteFileHandle.Release()) return translateError(fh.Handle.Release())
} }

View File

@ -1,57 +0,0 @@
// +build linux darwin freebsd
package mount
import (
"bazil.org/fuse"
fusefs "bazil.org/fuse/fs"
"github.com/ncw/rclone/fs"
"github.com/ncw/rclone/vfs"
"golang.org/x/net/context"
)
// ReadFileHandle is an open for read file handle on a File
type ReadFileHandle struct {
*vfs.ReadFileHandle
}
// Check interface satisfied
var _ fusefs.Handle = (*ReadFileHandle)(nil)
// Check interface satisfied
var _ fusefs.HandleReader = (*ReadFileHandle)(nil)
// Read from the file handle
func (fh *ReadFileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) (err error) {
var n int
defer fs.Trace(fh, "len=%d, offset=%d", req.Size, req.Offset)("read=%d, err=%v", &n, &err)
data := make([]byte, req.Size)
n, err = fh.ReadFileHandle.ReadAt(data, req.Offset)
if err != nil {
return translateError(err)
}
resp.Data = data[:n]
return nil
}
// Check interface satisfied
var _ fusefs.HandleFlusher = (*ReadFileHandle)(nil)
// Flush is called each time the file or directory is closed.
// Because there can be multiple file descriptors referring to a
// single opened file, Flush can be called multiple times.
func (fh *ReadFileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) (err error) {
defer fs.Trace(fh, "")("err=%v", &err)
return translateError(fh.ReadFileHandle.Flush())
}
var _ fusefs.HandleReleaser = (*ReadFileHandle)(nil)
// Release is called when we are finished with the file handle
//
// It isn't called directly from userspace so the error is ignored by
// the kernel
func (fh *ReadFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) (err error) {
defer fs.Trace(fh, "")("err=%v", &err)
return translateError(fh.ReadFileHandle.Release())
}

View File

@ -124,8 +124,11 @@ func (fh *ReadFileHandle) seek(offset int64, reopen bool) (err error) {
return nil return nil
} }
// Seek the file // Seek the file - returns ESPIPE if seeking isn't possible
func (fh *ReadFileHandle) Seek(offset int64, whence int) (n int64, err error) { func (fh *ReadFileHandle) Seek(offset int64, whence int) (n int64, err error) {
if fh.noSeek {
return 0, ESPIPE
}
size := fh.o.Size() size := fh.o.Size()
switch whence { switch whence {
case 0: case 0:

View File

@ -102,6 +102,9 @@ type Handle interface {
Write(b []byte) (n int, err error) Write(b []byte) (n int, err error)
WriteAt(b []byte, off int64) (n int, err error) WriteAt(b []byte, off int64) (n int, err error)
WriteString(s string) (n int, err error) WriteString(s string) (n int, err error)
// Additional methods useful for FUSE filesystems
Flush() error
Release() error
} }
// baseHandle implements all the missing methods // baseHandle implements all the missing methods
@ -124,6 +127,8 @@ func (h baseHandle) Truncate(size int64) error { retu
func (h baseHandle) Write(b []byte) (n int, err error) { return 0, ENOSYS } func (h baseHandle) Write(b []byte) (n int, err error) { return 0, ENOSYS }
func (h baseHandle) WriteAt(b []byte, off int64) (n int, err error) { return 0, ENOSYS } func (h baseHandle) WriteAt(b []byte, off int64) (n int, err error) { return 0, ENOSYS }
func (h baseHandle) WriteString(s string) (n int, err error) { return 0, ENOSYS } func (h baseHandle) WriteString(s string) (n int, err error) { return 0, ENOSYS }
func (h baseHandle) Flush() (err error) { return ENOSYS }
func (h baseHandle) Release() (err error) { return ENOSYS }
// Check interfaces // Check interfaces
var ( var (
@ -131,7 +136,6 @@ var (
_ Handle = (*ReadFileHandle)(nil) _ Handle = (*ReadFileHandle)(nil)
_ Handle = (*WriteFileHandle)(nil) _ Handle = (*WriteFileHandle)(nil)
_ Handle = (*DirHandle)(nil) _ Handle = (*DirHandle)(nil)
_ Handle = (*os.File)(nil)
) )
// VFS represents the top level filing system // VFS represents the top level filing system