Repository: ceph/go-ceph
Pull request #243 (2020-05-05 13:11:06)

cephfs: implement wrappers for fchmod and fchown
Fchmod() implemenets ceph_fchmod()
Fchown() implements ceph_fchown()
To fix: https://github.com/ceph/go-ceph/issues/240

Signed-off-by: Mudit Agarwal muagarwa@redhat.com

## Checklist
- [ ] Added tests for features and functional changes
- [ ] Public functions and types are documented
- [ ] Standard formatting is applied to Go code



Patch:
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)
+}


Test patch:
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)
+}