From 46b080c0922fc7e811fa53547b2d8d0b2e71383e Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 24 Nov 2022 10:30:01 +0000 Subject: [PATCH] vfs: Fix IO Error opening a file with O_CREATE|O_RDONLY in --vfs-cache-mode not full Before this fix, opening a file with `O_CREATE|O_RDONLY` caused an IO error to be returned when using `--vfs-cache-mode off` or `--vfs-cache-mode writes`. This was because the file was opened with read intent, but the `O_CREATE` implies write intent to create the file even though the file is opened `O_RDONLY`. This fix sets write intent for the file if `O_CREATE` is passed in which fixes the problem for all the VFS cache modes. It also extends the exhaustive open flags testing to `--vfs-cache-mode writes` as well as `--vfs-cache-mode full` which would have caught this problem. See: https://forum.rclone.org/t/i-o-error-trashing-file-on-sftp-mount/34317/ --- vfs/file.go | 5 +++++ vfs/read_write_test.go | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/vfs/file.go b/vfs/file.go index 4e59aee74..aa2493a5f 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -698,6 +698,11 @@ func (f *File) Open(flags int) (fd Handle, err error) { write = true } + // If create is set then set write to force openRW + if flags&os.O_CREATE != 0 { + write = true + } + // Open the correct sort of handle f.mu.RLock() d := f.d diff --git a/vfs/read_write_test.go b/vfs/read_write_test.go index ee8051c86..d9dac353f 100644 --- a/vfs/read_write_test.go +++ b/vfs/read_write_test.go @@ -642,15 +642,19 @@ func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) { } func TestRWFileHandleOpenTests(t *testing.T) { - opt := vfscommon.DefaultOpt - opt.CacheMode = vfscommon.CacheModeFull - opt.WriteBack = writeBackDelay - _, vfs, cleanup := newTestVFSOpt(t, &opt) - defer cleanup() + for _, cacheMode := range []vfscommon.CacheMode{vfscommon.CacheModeWrites, vfscommon.CacheModeFull} { + t.Run(cacheMode.String(), func(t *testing.T) { + opt := vfscommon.DefaultOpt + opt.CacheMode = cacheMode + opt.WriteBack = writeBackDelay + _, vfs, cleanup := newTestVFSOpt(t, &opt) + defer cleanup() - for _, test := range openTests { - t.Run(test.what, func(t *testing.T) { - testRWFileHandleOpenTest(t, vfs, &test) + for _, test := range openTests { + t.Run(test.what, func(t *testing.T) { + testRWFileHandleOpenTest(t, vfs, &test) + }) + } }) } }