diff --git a/cephfs/file.go b/cephfs/file.go index 07ba2e0..7ae2145 100644 --- a/cephfs/file.go +++ b/cephfs/file.go @@ -173,3 +173,29 @@ func (f *File) Seek(offset int64, whence int) (int64, error) { } return int64(ret), nil } + +// Fchmod changes the mode bits (permissions) of a file. +// +// Implements: +// int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode); +func (f *File) Fchmod(mode uint32) error { + if err := f.validate(); err != nil { + return err + } + + ret := C.ceph_fchmod(f.mount.mount, f.fd, C.mode_t(mode)) + return getError(ret) +} + +// Fchown changes the ownership of a file. +// +// Implements: +// int ceph_fchown(struct ceph_mount_info *cmount, int fd, int uid, int gid); +func (f *File) Fchown(user uint32, group uint32) error { + if err := f.validate(); err != nil { + return err + } + + ret := C.ceph_fchown(f.mount.mount, f.fd, C.int(user), C.int(group)) + return getError(ret) +} diff --git a/cephfs/file_test.go b/cephfs/file_test.go index 2dc9e46..7d7125f 100644 --- a/cephfs/file_test.go +++ b/cephfs/file_test.go @@ -4,6 +4,7 @@ import ( "io" "os" "path" + "syscall" "testing" "github.com/stretchr/testify/assert" @@ -337,3 +338,70 @@ func TestMixedReadReadAt(t *testing.T) { assert.NoError(t, f1.Close()) } + +func TestFchmod(t *testing.T) { + useMount(t) + mount := fsConnect(t) + defer fsDisconnect(t, mount) + + fname := "file.txt" + var statsBefore uint32 = 0755 + var statsAfter uint32 = 0700 + + f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE, statsBefore) + assert.NoError(t, err) + assert.NotNil(t, f1) + defer func() { + assert.NoError(t, f1.Close()) + assert.NoError(t, mount.Unlink(fname)) + }() + + err = mount.SyncFs() + assert.NoError(t, err) + + stats, err := os.Stat(path.Join(CephMountDir, fname)) + assert.NoError(t, err) + assert.Equal(t, uint32(stats.Mode().Perm()), statsBefore) + + err = f1.Fchmod(statsAfter) + assert.NoError(t, err) + + stats, err = os.Stat(path.Join(CephMountDir, fname)) + assert.Equal(t, uint32(stats.Mode().Perm()), statsAfter) +} + +func TestFchown(t *testing.T) { + useMount(t) + + fname := "file.txt" + // dockerfile creates bob user account + var bob uint32 = 1010 + var root uint32 + + mount := fsConnect(t) + defer fsDisconnect(t, mount) + + f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE, 0666) + assert.NoError(t, err) + assert.NotNil(t, f1) + defer func() { + assert.NoError(t, f1.Close()) + assert.NoError(t, mount.Unlink(fname)) + }() + + err = mount.SyncFs() + assert.NoError(t, err) + + stats, err := os.Stat(path.Join(CephMountDir, fname)) + assert.NoError(t, err) + assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), root) + assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), root) + + err = f1.Fchown(bob, bob) + assert.NoError(t, err) + + stats, err = os.Stat(path.Join(CephMountDir, fname)) + assert.NoError(t, err) + assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), bob) + assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), bob) +}