mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
vfs: fix Create causing windows explorer to truncate files on CTRL-C CTRL-V
Before this fix, doing CTRL-C and CTRL-V on a file in Windows explorer caused the **source** and the the destination to be truncated to 0. This is because Windows opens the source file with Create with flags `O_RDWR|O_CREATE|O_EXCL` but doesn't write to it - it only reads from it. Rclone was taking the call to Create as a signal to always make a new file, but this is incorrect. This fix reads an existing file from the directory if it exists when Create is called rather than always creating a new one. This fixes the problem. Fixes #5181
This commit is contained in:
parent
d0f8b4f479
commit
20e15e52a9
17
vfs/dir.go
17
vfs/dir.go
@ -843,6 +843,23 @@ func (d *Dir) Open(flags int) (fd Handle, err error) {
|
|||||||
// Create makes a new file node
|
// Create makes a new file node
|
||||||
func (d *Dir) Create(name string, flags int) (*File, error) {
|
func (d *Dir) Create(name string, flags int) (*File, error) {
|
||||||
// fs.Debugf(path, "Dir.Create")
|
// fs.Debugf(path, "Dir.Create")
|
||||||
|
// Return existing node if one exists
|
||||||
|
node, err := d.stat(name)
|
||||||
|
switch err {
|
||||||
|
case ENOENT:
|
||||||
|
// not found, carry on
|
||||||
|
case nil:
|
||||||
|
// found so check what it is
|
||||||
|
if node.IsFile() {
|
||||||
|
return node.(*File), err
|
||||||
|
}
|
||||||
|
return nil, EEXIST // EISDIR would be better but we don't have that
|
||||||
|
default:
|
||||||
|
// a different error - report
|
||||||
|
fs.Errorf(d, "Dir.Create stat failed: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// node doesn't exist so create it
|
||||||
if d.vfs.Opt.ReadOnly {
|
if d.vfs.Opt.ReadOnly {
|
||||||
return nil, EROFS
|
return nil, EROFS
|
||||||
}
|
}
|
||||||
|
@ -375,6 +375,13 @@ func TestDirCreate(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, int64(5), file2.Size())
|
assert.Equal(t, int64(5), file2.Size())
|
||||||
|
|
||||||
|
// Try creating the file again - make sure we get the same file node
|
||||||
|
file3, err := dir.Create("potato", os.O_RDWR|os.O_CREATE)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(5), file3.Size())
|
||||||
|
assert.Equal(t, fmt.Sprintf("%p", file), fmt.Sprintf("%p", file3), "didn't return same node")
|
||||||
|
|
||||||
|
// Test read only fs creating new
|
||||||
vfs.Opt.ReadOnly = true
|
vfs.Opt.ReadOnly = true
|
||||||
_, err = dir.Create("sausage", os.O_WRONLY|os.O_CREATE)
|
_, err = dir.Create("sausage", os.O_WRONLY|os.O_CREATE)
|
||||||
assert.Equal(t, EROFS, err)
|
assert.Equal(t, EROFS, err)
|
||||||
|
Loading…
Reference in New Issue
Block a user