diff --git a/cephfs/file_ops.go b/cephfs/file_ops.go index 8a799c6..c54c267 100644 --- a/cephfs/file_ops.go +++ b/cephfs/file_ops.go @@ -6,12 +6,14 @@ package cephfs /* #cgo LDFLAGS: -lcephfs #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 +#include #include #include */ import "C" import ( + ts "github.com/ceph/go-ceph/internal/timespec" "unsafe" ) @@ -60,3 +62,34 @@ func (mount *MountInfo) Futime(fd int, times *Utime) error { ret := C.ceph_futime(mount.mount, cFd, uTimeBuf) return getError(ret) } + +// Futimens changes file/directory last access and modification times, here times param +// is an array of Timespec struct having length 2, where times[0] represents the access time +// and times[1] represents the modification time. +// +// Implements: +// +// int ceph_futimens(struct ceph_mount_info *cmount, int fd, struct timespec times[2]); +func (mount *MountInfo) Futimens(fd int, times []Timespec) error { + if err := mount.validate(); err != nil { + return err + } + + if len(times) != 2 { + return getError(-C.EINVAL) + } + + cFd := C.int(fd) + cTimes := []C.struct_timespec{} + for _, val := range times { + cTs := &C.struct_timespec{} + ts.CopyToCStruct( + ts.Timespec(val), + ts.CTimespecPtr(cTs), + ) + cTimes = append(cTimes, *cTs) + } + + ret := C.ceph_futimens(mount.mount, cFd, &cTimes[0]) + return getError(ret) +} diff --git a/cephfs/file_ops_test.go b/cephfs/file_ops_test.go index 3ab4fa1..f0a4b14 100644 --- a/cephfs/file_ops_test.go +++ b/cephfs/file_ops_test.go @@ -91,3 +91,47 @@ func TestFutime(t *testing.T) { err = mount1.Futime(int(f1.fd), newTime) assert.Error(t, err) } + +func TestFutimens(t *testing.T) { + mount := fsConnect(t) + defer fsDisconnect(t, mount) + + fname := "futimens_file.txt" + f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + assert.NoError(t, err) + assert.NotNil(t, f1) + defer func() { + assert.NoError(t, f1.Close()) + assert.NoError(t, mount.Unlink(fname)) + }() + + times := []Timespec{ + {int64(time.Now().Second()), 0}, + {int64(time.Now().Second()), 0}, + } + err = mount.Futimens(int(f1.fd), times) + assert.NoError(t, err) + + sx, err := mount.Statx(fname, StatxBasicStats, 0) + assert.NoError(t, err) + assert.Equal(t, times[0], sx.Atime) + assert.Equal(t, times[1], sx.Mtime) + + // Test invalid mount value + mount1 := &MountInfo{} + times = []Timespec{ + {int64(time.Now().Second()), 0}, + {int64(time.Now().Second()), 0}, + } + err = mount1.Futimens(int(f1.fd), times) + assert.Error(t, err) + + // Test times array length more than 2 + times = []Timespec{ + {int64(time.Now().Second()), 0}, + {int64(time.Now().Second()), 0}, + {int64(time.Now().Second()), 0}, + } + err = mount.Futimens(int(f1.fd), times) + assert.Error(t, err) +} diff --git a/docs/api-status.json b/docs/api-status.json index a9d187a..0fd0399 100644 --- a/docs/api-status.json +++ b/docs/api-status.json @@ -337,6 +337,12 @@ "comment": "Futime changes file/directory last access and modification times.\n\nImplements:\n\n\tint ceph_futime(struct ceph_mount_info *cmount, int fd, struct utimbuf *buf);\n", "added_in_version": "$NEXT_RELEASE", "expected_stable_version": "$NEXT_RELEASE_STABLE" + }, + { + "name": "MountInfo.Futimens", + "comment": "Futimens changes file/directory last access and modification times, here times param\nis an array of Timespec struct having length 2, where times[0] represents the access time\nand times[1] represents the modification time.\n\nImplements:\n\n\tint ceph_futimens(struct ceph_mount_info *cmount, int fd, struct timespec times[2]);\n", + "added_in_version": "$NEXT_RELEASE", + "expected_stable_version": "$NEXT_RELEASE_STABLE" } ] }, diff --git a/docs/api-status.md b/docs/api-status.md index 67abef7..186b814 100644 --- a/docs/api-status.md +++ b/docs/api-status.md @@ -12,6 +12,7 @@ MountInfo.SelectFilesystem | v0.20.0 | v0.22.0 | MountInfo.MakeDirs | v0.21.0 | v0.23.0 | MountInfo.Mknod | $NEXT_RELEASE | $NEXT_RELEASE_STABLE | MountInfo.Futime | $NEXT_RELEASE | $NEXT_RELEASE_STABLE | +MountInfo.Futimens | $NEXT_RELEASE | $NEXT_RELEASE_STABLE | ## Package: cephfs/admin