cephfs: add File method Truncate implementing ceph_ftruncate

Add a Truncate method to File type. Note the doc comment as I hit
a bug in ceph when writing the first test cases. Go-ceph will behave
as ceph here - so using go-ceph with an unfixed version of the
ceph libs will also exhibit the bug.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2020-11-11 16:26:27 -05:00 committed by mergify[bot]
parent 0afcf98b34
commit e2de2b6e58
2 changed files with 73 additions and 0 deletions

View File

@ -391,3 +391,25 @@ func (f *File) Fsync(sync SyncChoice) error {
func (f *File) Sync() error { func (f *File) Sync() error {
return f.Fsync(SyncAll) return f.Fsync(SyncAll)
} }
// Truncate sets the size of the open file.
// NOTE: In some versions of ceph a bug exists where calling ftruncate on a
// file open for read-only is permitted. The go-ceph wrapper does no additional
// checking and will inherit the issue on affected versions of ceph. Please
// refer to the following issue for details:
// https://tracker.ceph.com/issues/48202
//
// Implements:
// int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size);
func (f *File) Truncate(size int64) error {
if err := f.validate(); err != nil {
return err
}
ret := C.ceph_ftruncate(
f.mount.mount,
f.fd,
C.int64_t(size),
)
return getError(ret)
}

View File

@ -918,3 +918,54 @@ func TestFilePreadvPwritev(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
}) })
} }
func TestFileTruncate(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
fname := "TestFileTruncate.txt"
defer mount.Unlink(fname)
t.Run("invalidSize", func(t *testing.T) {
// "touch" the file
f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
assert.NoError(t, err)
defer func() {
assert.NoError(t, f1.Close())
}()
err = f1.Truncate(-1)
assert.Error(t, err)
st, err := f1.Fstatx(StatxBasicStats, 0)
if assert.NoError(t, err) {
assert.EqualValues(t, 0, st.Size)
}
})
t.Run("closedFile", func(t *testing.T) {
t.Skip("test fails because of a bug(?) in ceph")
// "touch" the file
f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
assert.NoError(t, err)
assert.NoError(t, f1.Close())
f2, err := mount.Open(fname, os.O_RDONLY, 0644)
assert.NoError(t, err)
assert.NoError(t, f2.Close())
err = f2.Truncate(1024)
assert.Error(t, err)
// I wanted to do the stat check here too but it is a pain to implement
// because we close the file.
// The original version of this test, using a read-only file, failed
// due to a bug in libcephfs (see Truncate doc comment).
})
t.Run("invalidFile", func(t *testing.T) {
f := &File{}
err := f.Truncate(0)
assert.Error(t, err)
})
}