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:
parent
e18122e88b
commit
5634659ea3
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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())
|
||||||
}
|
}
|
@ -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())
|
|
||||||
}
|
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user