1
0
mirror of https://github.com/rclone/rclone.git synced 2025-12-15 07:43:35 +00:00

vfs: move writeback of dirty data out of close() method into its own method (FlushWrites) and remove close() call from Flush()

If a file handle is duplicated with dup() and the duplicate handle is
flushed, rclone will go ahead and close the file, making the original
file handle stale. This change removes the close() call from Flush() and
replaces it with FlushWrites() so that the file only gets closed when
Release() is called. The new FlushWrites method takes care of actually
writing the file back to the underlying storage.

Fixes #3381
This commit is contained in:
Brett Dutro
2019-10-06 15:05:21 -05:00
committed by Nick Craig-Wood
parent 0cac9d9bd0
commit 7d0d7e66ca
7 changed files with 131 additions and 34 deletions

View File

@@ -4,10 +4,12 @@ package mounttest
import (
"runtime"
"syscall"
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/sys/unix"
"github.com/rclone/rclone/vfs"
)
// TestWriteFileDoubleClose tests double close on write
@@ -21,14 +23,14 @@ func TestWriteFileDoubleClose(t *testing.T) {
assert.NoError(t, err)
fd := out.Fd()
fd1, err := syscall.Dup(int(fd))
fd1, err := unix.Dup(int(fd))
assert.NoError(t, err)
fd2, err := syscall.Dup(int(fd))
fd2, err := unix.Dup(int(fd))
assert.NoError(t, err)
// close one of the dups - should produce no error
err = syscall.Close(fd1)
err = unix.Close(fd1)
assert.NoError(t, err)
// write to the file
@@ -41,14 +43,26 @@ func TestWriteFileDoubleClose(t *testing.T) {
err = out.Close()
assert.NoError(t, err)
// write to the other dup - should produce an error
_, err = syscall.Write(fd2, buf)
assert.Error(t, err, "input/output error")
// write to the other dup
_, err = unix.Write(fd2, buf)
if run.vfs.Opt.CacheMode < vfs.CacheModeWrites {
// produces an error if cache mode < writes
assert.Error(t, err, "input/output error")
} else {
// otherwise does not produce an error
assert.NoError(t, err)
}
// close the dup - should not produce an error
err = syscall.Close(fd2)
err = unix.Close(fd2)
assert.NoError(t, err)
run.waitForWriters()
run.rm(t, "testdoubleclose")
}
// writeTestDup performs the platform-specific implementation of the dup() unix
func writeTestDup(oldfd uintptr) (uintptr, error) {
newfd, err := unix.Dup(int(oldfd))
return uintptr(newfd), err
}