vfs: make sure existing files opened for write show correct size

Before this change if an existing file was opened for write without
truncate its size would show as 0 rather than the full size of the
file.
This commit is contained in:
Nick Craig-Wood 2019-11-25 11:31:44 +00:00
parent a7d65bd519
commit 420ae905b5
2 changed files with 110 additions and 16 deletions

View File

@ -37,13 +37,19 @@ type File struct {
} }
// newFile creates a new File // newFile creates a new File
//
// o may be nil
func newFile(d *Dir, o fs.Object, leaf string) *File { func newFile(d *Dir, o fs.Object, leaf string) *File {
return &File{ f := &File{
d: d, d: d,
o: o, o: o,
leaf: leaf, leaf: leaf,
inode: newInode(), inode: newInode(),
} }
if o != nil {
f.size = o.Size()
}
return f
} }
// String converts it to printable // String converts it to printable

View File

@ -21,16 +21,18 @@ func cleanup(t *testing.T, r *fstest.Run, vfs *VFS) {
r.Finalise() r.Finalise()
} }
// Open a file for write // Create a file and open it with the flags passed in
func rwHandleCreateReadOnly(t *testing.T, r *fstest.Run) (*VFS, *RWFileHandle) { func rwHandleCreateFlags(t *testing.T, r *fstest.Run, create bool, filename string, flags int) (*VFS, *RWFileHandle) {
opt := DefaultOpt opt := DefaultOpt
opt.CacheMode = CacheModeFull opt.CacheMode = CacheModeFull
vfs := New(r.Fremote, &opt) vfs := New(r.Fremote, &opt)
file1 := r.WriteObject(context.Background(), "dir/file1", "0123456789abcdef", t1) if create {
fstest.CheckItems(t, r.Fremote, file1) file1 := r.WriteObject(context.Background(), filename, "0123456789abcdef", t1)
fstest.CheckItems(t, r.Fremote, file1)
}
h, err := vfs.OpenFile("dir/file1", os.O_RDONLY, 0777) h, err := vfs.OpenFile(filename, flags, 0777)
require.NoError(t, err) require.NoError(t, err)
fh, ok := h.(*RWFileHandle) fh, ok := h.(*RWFileHandle)
require.True(t, ok) require.True(t, ok)
@ -38,18 +40,14 @@ func rwHandleCreateReadOnly(t *testing.T, r *fstest.Run) (*VFS, *RWFileHandle) {
return vfs, fh return vfs, fh
} }
// Open a file for read
func rwHandleCreateReadOnly(t *testing.T, r *fstest.Run) (*VFS, *RWFileHandle) {
return rwHandleCreateFlags(t, r, true, "dir/file1", os.O_RDONLY)
}
// Open a file for write // Open a file for write
func rwHandleCreateWriteOnly(t *testing.T, r *fstest.Run) (*VFS, *RWFileHandle) { func rwHandleCreateWriteOnly(t *testing.T, r *fstest.Run) (*VFS, *RWFileHandle) {
opt := DefaultOpt return rwHandleCreateFlags(t, r, false, "file1", os.O_WRONLY|os.O_CREATE)
opt.CacheMode = CacheModeFull
vfs := New(r.Fremote, &opt)
h, err := vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777)
require.NoError(t, err)
fh, ok := h.(*RWFileHandle)
require.True(t, ok)
return vfs, fh
} }
// read data from the string // read data from the string
@ -494,6 +492,96 @@ func TestRWFileHandleReleaseWrite(t *testing.T) {
assert.True(t, fh.closed) assert.True(t, fh.closed)
} }
// check the size of the file through the open file (if not nil) and via stat
func assertSize(t *testing.T, vfs *VFS, fh *RWFileHandle, filepath string, size int64) {
if fh != nil {
assert.Equal(t, size, fh.Size())
}
fi, err := vfs.Stat(filepath)
require.NoError(t, err)
assert.Equal(t, size, fi.Size())
}
func TestRWFileHandleSizeTruncateExisting(t *testing.T) {
r := fstest.NewRun(t)
vfs, fh := rwHandleCreateFlags(t, r, true, "dir/file1", os.O_WRONLY|os.O_TRUNC)
defer cleanup(t, r, vfs)
// check initial size after opening
assertSize(t, vfs, fh, "dir/file1", 0)
// write some bytes
n, err := fh.Write([]byte("hello"))
assert.NoError(t, err)
assert.Equal(t, 5, n)
// check size after writing
assertSize(t, vfs, fh, "dir/file1", 5)
// close
assert.NoError(t, fh.Close())
// check size after close
assertSize(t, vfs, nil, "dir/file1", 5)
}
func TestRWFileHandleSizeCreateExisting(t *testing.T) {
r := fstest.NewRun(t)
vfs, fh := rwHandleCreateFlags(t, r, true, "dir/file1", os.O_WRONLY|os.O_CREATE)
defer cleanup(t, r, vfs)
// check initial size after opening
assertSize(t, vfs, fh, "dir/file1", 16)
// write some bytes
n, err := fh.Write([]byte("hello"))
assert.NoError(t, err)
assert.Equal(t, 5, n)
// check size after writing
assertSize(t, vfs, fh, "dir/file1", 16)
// write some more bytes
n, err = fh.Write([]byte("helloHELLOhello"))
assert.NoError(t, err)
assert.Equal(t, 15, n)
// check size after writing
assertSize(t, vfs, fh, "dir/file1", 20)
// close
assert.NoError(t, fh.Close())
// check size after close
assertSize(t, vfs, nil, "dir/file1", 20)
}
func TestRWFileHandleSizeCreateNew(t *testing.T) {
r := fstest.NewRun(t)
vfs, fh := rwHandleCreateFlags(t, r, false, "file1", os.O_WRONLY|os.O_CREATE)
defer cleanup(t, r, vfs)
// check initial size after opening
assertSize(t, vfs, fh, "file1", 0)
// write some bytes
n, err := fh.Write([]byte("hello"))
assert.NoError(t, err)
assert.Equal(t, 5, n)
// check size after writing
assertSize(t, vfs, fh, "file1", 5)
// check size after writing
assertSize(t, vfs, fh, "file1", 5)
// close
assert.NoError(t, fh.Close())
// check size after close
assertSize(t, vfs, nil, "file1", 5)
}
func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) { func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) {
fileName := "open-test-file" fileName := "open-test-file"