diff --git a/cephfs/file_ops.go b/cephfs/file_ops.go index b450d7b..8a799c6 100644 --- a/cephfs/file_ops.go +++ b/cephfs/file_ops.go @@ -32,3 +32,31 @@ func (mount *MountInfo) Mknod(path string, mode uint16, dev uint16) error { ret := C.ceph_mknod(mount.mount, cPath, C.mode_t(mode), C.dev_t(dev)) return getError(ret) } + +// Utime struct is the equivalent of C.struct_utimbuf +type Utime struct { + // AcTime represents the file's access time in seconds since the Unix epoch. + AcTime int64 + // ModTime represents the file's modification time in seconds since the Unix epoch. + ModTime int64 +} + +// Futime changes file/directory last access and modification times. +// +// Implements: +// +// int ceph_futime(struct ceph_mount_info *cmount, int fd, struct utimbuf *buf); +func (mount *MountInfo) Futime(fd int, times *Utime) error { + if err := mount.validate(); err != nil { + return err + } + + cFd := C.int(fd) + uTimeBuf := &C.struct_utimbuf{ + actime: C.time_t(times.AcTime), + modtime: C.time_t(times.ModTime), + } + + ret := C.ceph_futime(mount.mount, cFd, uTimeBuf) + return getError(ret) +} diff --git a/cephfs/file_ops_test.go b/cephfs/file_ops_test.go index 4ae5e5a..3ab4fa1 100644 --- a/cephfs/file_ops_test.go +++ b/cephfs/file_ops_test.go @@ -4,8 +4,10 @@ package cephfs import ( + "os" "syscall" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -52,3 +54,40 @@ func TestMknod(t *testing.T) { err = mount1.Mknod(file4, uint16(syscall.S_IFCHR), 64) assert.Error(t, err) } + +func TestFutime(t *testing.T) { + mount := fsConnect(t) + defer fsDisconnect(t, mount) + + fname := "futime_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)) + }() + + currentTime := Timespec{int64(time.Now().Second()), 0} + newTime := &Utime{ + AcTime: currentTime.Sec, + ModTime: currentTime.Sec, + } + err = mount.Futime(int(f1.fd), newTime) + assert.NoError(t, err) + + sx, err := mount.Statx(fname, StatxBasicStats, 0) + assert.NoError(t, err) + assert.Equal(t, currentTime, sx.Atime) + assert.Equal(t, currentTime, sx.Mtime) + + // Test invalid mount value + mount1 := &MountInfo{} + currentTime = Timespec{int64(time.Now().Second()), 0} + newTime = &Utime{ + AcTime: currentTime.Sec, + ModTime: currentTime.Sec, + } + err = mount1.Futime(int(f1.fd), newTime) + assert.Error(t, err) +} diff --git a/docs/api-status.json b/docs/api-status.json index e4aa422..a9d187a 100644 --- a/docs/api-status.json +++ b/docs/api-status.json @@ -331,6 +331,12 @@ "comment": "Mknod creates a regular, block or character special file.\n\nImplements:\n\n\tint ceph_mknod(struct ceph_mount_info *cmount, const char *path, mode_t mode,\n\t\t\t\t dev_t rdev);\n", "added_in_version": "$NEXT_RELEASE", "expected_stable_version": "$NEXT_RELEASE_STABLE" + }, + { + "name": "MountInfo.Futime", + "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" } ] }, diff --git a/docs/api-status.md b/docs/api-status.md index 1693cf5..67abef7 100644 --- a/docs/api-status.md +++ b/docs/api-status.md @@ -11,6 +11,7 @@ Name | Added in Version | Expected Stable Version | 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 | ## Package: cephfs/admin