summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xglusterfs/api.py149
-rwxr-xr-xglusterfs/gfapi.py35
-rw-r--r--test/unit/gluster/test_gfapi.py42
3 files changed, 222 insertions, 4 deletions
diff --git a/glusterfs/api.py b/glusterfs/api.py
index 1ecc34a..803a778 100755
--- a/glusterfs/api.py
+++ b/glusterfs/api.py
@@ -86,6 +86,149 @@ class Dirent (ctypes.Structure):
("d_name", ctypes.c_char * 256),
]
+
+# Here is the reference card of libgfapi library exported
+# apis with its different versions.
+#
+# GFAPI_3.4.0 {
+# glfs_new;
+# glfs_set_volfile;
+# glfs_set_volfile_server;
+# glfs_set_logging;
+# glfs_init;
+# glfs_fini;
+# glfs_open;
+# glfs_creat;
+# glfs_close;
+# glfs_from_glfd;
+# glfs_set_xlator_option;
+# glfs_read;
+# glfs_write;
+# glfs_read_async;
+# glfs_write_async;
+# glfs_readv;
+# glfs_writev;
+# glfs_readv_async;
+# glfs_writev_async;
+# glfs_pread;
+# glfs_pwrite;
+# glfs_pread_async;
+# glfs_pwrite_async;
+# glfs_preadv;
+# glfs_pwritev;
+# glfs_preadv_async;
+# glfs_pwritev_async;
+# glfs_lseek;
+# glfs_truncate;
+# glfs_ftruncate;
+# glfs_ftruncate_async;
+# glfs_lstat;
+# glfs_stat;
+# glfs_fstat;
+# glfs_fsync;
+# glfs_fsync_async;
+# glfs_fdatasync;
+# glfs_fdatasync_async;
+# glfs_access;
+# glfs_symlink;
+# glfs_readlink;
+# glfs_mknod;
+# glfs_mkdir;
+# glfs_unlink;
+# glfs_rmdir;
+# glfs_rename;
+# glfs_link;
+# glfs_opendir;
+# glfs_readdir_r;
+# glfs_readdirplus_r;
+# glfs_telldir;
+# glfs_seekdir;
+# glfs_closedir;
+# glfs_statvfs;
+# glfs_chmod;
+# glfs_fchmod;
+# glfs_chown;
+# glfs_lchown;
+# glfs_fchown;
+# glfs_utimens;
+# glfs_lutimens;
+# glfs_futimens;
+# glfs_getxattr;
+# glfs_lgetxattr;
+# glfs_fgetxattr;
+# glfs_listxattr;
+# glfs_llistxattr;
+# glfs_flistxattr;
+# glfs_setxattr;
+# glfs_lsetxattr;
+# glfs_fsetxattr;
+# glfs_removexattr;
+# glfs_lremovexattr;
+# glfs_fremovexattr;
+# glfs_getcwd;
+# glfs_chdir;
+# glfs_fchdir;
+# glfs_realpath;
+# glfs_posix_lock;
+# glfs_dup;
+#
+# }
+#
+# GFAPI_3.4.2 {
+# glfs_setfsuid;
+# glfs_setfsgid;
+# glfs_setfsgroups;
+# glfs_h_lookupat;
+# glfs_h_creat;
+# glfs_h_mkdir;
+# glfs_h_mknod;
+# glfs_h_symlink;
+# glfs_h_unlink;
+# glfs_h_close;
+# glfs_h_truncate;
+# glfs_h_stat;
+# glfs_h_getattrs;
+# glfs_h_setattrs;
+# glfs_h_readlink;
+# glfs_h_link;
+# glfs_h_rename;
+# glfs_h_extract_handle;
+# glfs_h_create_from_handle;
+# glfs_h_opendir;
+# glfs_h_open;
+# }
+#
+# GFAPI_3.5.0 {
+#
+# glfs_get_volumeid;
+# glfs_readdir;
+# glfs_readdirplus;
+# glfs_fallocate;
+# glfs_discard;
+# glfs_discard_async;
+# glfs_zerofill;
+# glfs_zerofill_async;
+# glfs_caller_specific_init;
+# glfs_h_setxattrs;
+#
+# }
+#
+# GFAPI_3.5.1 {
+#
+# glfs_unset_volfile_server;
+# glfs_h_getxattrs;
+# glfs_h_removexattrs;
+#
+# }
+#
+# GFAPI_3.6.0 {
+#
+# glfs_get_volfile;
+# glfs_h_access;
+#
+# }
+#
+
# Define function prototypes for the wrapper functions.
glfs_init = ctypes.CFUNCTYPE(
@@ -232,6 +375,12 @@ glfs_rmdir = ctypes.CFUNCTYPE(ctypes.c_int,
ctypes.c_void_p,
ctypes.c_char_p)(('glfs_rmdir', client))
+glfs_setfsuid = ctypes.CFUNCTYPE(ctypes.c_int,
+ ctypes.c_uint)(('glfs_setfsuid', client))
+
+glfs_setfsgid = ctypes.CFUNCTYPE(ctypes.c_int,
+ ctypes.c_uint)(('glfs_setfsgid', client))
+
# TODO: creat and open fails on test_create_file_already_exists & test_open_file_not_exist functional testing, # noqa
# when defined via function prototype.. Need to find RCA. For time being, using it from 'api.glfs_' # noqa
diff --git a/glusterfs/gfapi.py b/glusterfs/gfapi.py
index 2d51a96..42c4aef 100755
--- a/glusterfs/gfapi.py
+++ b/glusterfs/gfapi.py
@@ -104,6 +104,12 @@ class File(object):
raise OSError(err, os.strerror(err))
return ret
+ def fgetsize(self):
+ """
+ Return the size of a file, reported by fstat()
+ """
+ return self.fstat().st_size
+
def fstat(self):
"""
Returns Stat object for this file.
@@ -137,9 +143,18 @@ class File(object):
"""
return api.glfs_lseek(self.fd, pos, how)
- def read(self, buflen, flags=0):
+ def read(self, buflen=-1):
+ """
+ read file
+
+ :param buflen: length of read buffer. If less than 0, then whole
+ file is read. Default is -1.
+ :returns: buffer of size buflen
+ """
+ if buflen < 0:
+ buflen = self.fgetsize()
rbuf = ctypes.create_string_buffer(buflen)
- ret = api.glfs_read(self.fd, rbuf, buflen, flags)
+ ret = api.glfs_read(self.fd, rbuf, buflen, 0)
if ret > 0:
return rbuf
elif ret < 0:
@@ -190,8 +205,6 @@ class Dir(object):
class Volume(object):
- # Housekeeping functions.
-
def __init__(self, host, volid, proto="tcp", port=24007):
# Add a reference so the module-level variable "api" doesn't
# get yanked out from under us (see comment above File def'n).
@@ -468,6 +481,20 @@ class Volume(object):
except OSError as e:
onerror(self.rmdir, path, e)
+ def setfsuid(self, uid):
+ ret = api.glfs_setfsuid(uid)
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return ret
+
+ def setfsgid(self, gid):
+ ret = api.glfs_setfsgid(gid)
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return ret
+
def setxattr(self, path, key, value, vlen):
ret = api.glfs_setxattr(self.fs, path, key, value, vlen, 0)
if ret < 0:
diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py
index 1608332..8451b51 100644
--- a/test/unit/gluster/test_gfapi.py
+++ b/test/unit/gluster/test_gfapi.py
@@ -180,6 +180,18 @@ class TestFile(unittest.TestCase):
b = self.fd.read(5)
self.assertEqual(b, 0)
+ def test_read_buflen_negative(self):
+ _mock_fgetsize = Mock(return_value=12345)
+
+ def _mock_glfs_read(fd, rbuf, buflen, flags):
+ self.assertEqual(buflen, 12345)
+ return buflen
+
+ for buflen in (-1,-2,-999):
+ with patch("glusterfs.gfapi.api.glfs_read", _mock_glfs_read):
+ with patch("glusterfs.gfapi.File.fgetsize", _mock_fgetsize):
+ b = self.fd.read(buflen)
+
def test_write_success(self):
mock_glfs_write = Mock()
mock_glfs_write.return_value = 5
@@ -791,6 +803,36 @@ class TestVolume(unittest.TestCase):
mock_unlink.assert_called_once_with("dir1/file")
mock_rmdir.assert_called_with("dir1")
+ def test_setfsuid_success(self):
+ mock_glfs_setfsuid = Mock()
+ mock_glfs_setfsuid.return_value = 0
+
+ with patch("glusterfs.gfapi.api.glfs_setfsuid", mock_glfs_setfsuid):
+ ret = self.vol.setfsuid(1000)
+ self.assertEquals(ret, 0)
+
+ def test_setfsuid_fail(self):
+ mock_glfs_setfsuid = Mock()
+ mock_glfs_setfsuid.return_value = -1
+
+ with patch("glusterfs.gfapi.api.glfs_setfsuid", mock_glfs_setfsuid):
+ self.assertRaises(OSError, self.vol.setfsuid, 1001)
+
+ def test_setfsgid_success(self):
+ mock_glfs_setfsgid = Mock()
+ mock_glfs_setfsgid.return_value = 0
+
+ with patch("glusterfs.gfapi.api.glfs_setfsgid", mock_glfs_setfsgid):
+ ret = self.vol.setfsgid(1000)
+ self.assertEquals(ret, 0)
+
+ def test_setfsgid_fail(self):
+ mock_glfs_setfsgid = Mock()
+ mock_glfs_setfsgid.return_value = -1
+
+ with patch("glusterfs.gfapi.api.glfs_setfsgid", mock_glfs_setfsgid):
+ self.assertRaises(OSError, self.vol.setfsgid, 1001)
+
def test_setxattr_success(self):
mock_glfs_setxattr = Mock()
mock_glfs_setxattr.return_value = 0