mirror of
https://github.com/rclone/rclone.git
synced 2025-01-08 23:40:29 +01:00
8fd2577694
Before this change the mount and cmount would run Release synchronously. This would mean that it would wait for files to be closed (eg uploaded) before returning to the kernel. However Release is already running asynchronously from userspace so this commit changes it to do the functionality of Release asynchronously too. This should fix libfuse blocking when Release is active and it is asked to do something else with a file. Forum: https://forum.rclone.org/t/vfs-cache-mode-writes-upload-expected-behaviour/8014
89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
// +build linux darwin freebsd
|
|
|
|
package mount
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
|
|
"bazil.org/fuse"
|
|
fusefs "bazil.org/fuse/fs"
|
|
"github.com/ncw/rclone/fs/log"
|
|
"github.com/ncw/rclone/vfs"
|
|
)
|
|
|
|
// FileHandle is an open for read file handle on a File
|
|
type FileHandle struct {
|
|
vfs.Handle
|
|
}
|
|
|
|
// Check interface satisfied
|
|
var _ fusefs.HandleReader = (*FileHandle)(nil)
|
|
|
|
// Read from the file handle
|
|
func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) (err error) {
|
|
var n int
|
|
defer log.Trace(fh, "len=%d, offset=%d", req.Size, req.Offset)("read=%d, err=%v", &n, &err)
|
|
data := make([]byte, req.Size)
|
|
n, err = fh.Handle.ReadAt(data, req.Offset)
|
|
if err == io.EOF {
|
|
err = nil
|
|
} else if err != nil {
|
|
return translateError(err)
|
|
}
|
|
resp.Data = data[:n]
|
|
return nil
|
|
}
|
|
|
|
// Check interface satisfied
|
|
var _ fusefs.HandleWriter = (*FileHandle)(nil)
|
|
|
|
// Write data to the file handle
|
|
func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) (err error) {
|
|
defer log.Trace(fh, "len=%d, offset=%d", len(req.Data), req.Offset)("written=%d, err=%v", &resp.Size, &err)
|
|
n, err := fh.Handle.WriteAt(req.Data, req.Offset)
|
|
if err != nil {
|
|
return translateError(err)
|
|
}
|
|
resp.Size = n
|
|
return nil
|
|
}
|
|
|
|
// Check interface satisfied
|
|
var _ fusefs.HandleFlusher = (*FileHandle)(nil)
|
|
|
|
// 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
|
|
// cached dirty data, this is a good place to write back data and
|
|
// return any errors. Since many applications ignore close() errors
|
|
// this is not always useful.
|
|
//
|
|
// NOTE: The flush() method may be called more than once for each
|
|
// open(). This happens if more than one file descriptor refers to an
|
|
// opened file due to dup(), dup2() or fork() calls. It is not
|
|
// possible to determine if a flush is final, so each flush should be
|
|
// treated equally. Multiple write-flush sequences are relatively
|
|
// rare, so this shouldn't be a problem.
|
|
//
|
|
// Filesystems shouldn't assume that flush will always be called after
|
|
// some writes, or that if will be called at all.
|
|
func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) (err error) {
|
|
defer log.Trace(fh, "")("err=%v", &err)
|
|
return translateError(fh.Handle.Flush())
|
|
}
|
|
|
|
var _ fusefs.HandleReleaser = (*FileHandle)(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 *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) (err error) {
|
|
defer log.Trace(fh, "")("err=%v", &err)
|
|
// Run the Release asynchronously, ignoring errors
|
|
go func() {
|
|
_ = fh.Handle.Release()
|
|
}()
|
|
return nil
|
|
}
|