diff options
| author | Thiago da Silva <thiago@redhat.com> | 2014-03-26 16:31:28 -0400 | 
|---|---|---|
| committer | Thiago da Silva <thiago@redhat.com> | 2014-03-27 15:21:50 -0400 | 
| commit | bd683d93cb8d967f761d53f7a6b4243eb8eaedea (patch) | |
| tree | 5f73d7390690a9de7e3bf2371fb6590d5ecce95b | |
| parent | f50cec44586e851c3d9e29dd59574696ae6f0c3a (diff) | |
adding new apis requested from gluster-swift proj
This patch adds new functions that are used in gluster-swift.
These functions are: dup, lseek, getatime, getctime, getmtime
Change-Id: I09036f7e393a89e09913f7f6de173e1eca8dca95
Signed-off-by: Thiago da Silva <thiago@redhat.com>
| -rw-r--r-- | glusterfs/gfapi.py | 48 | ||||
| -rw-r--r-- | test/functional/libgfapi-python-tests.py | 24 | ||||
| -rw-r--r-- | test/unit/gluster/test_gfapi.py | 20 | 
3 files changed, 89 insertions, 3 deletions
diff --git a/glusterfs/gfapi.py b/glusterfs/gfapi.py index 6ca2ad7..80418a1 100644 --- a/glusterfs/gfapi.py +++ b/glusterfs/gfapi.py @@ -87,8 +87,9 @@ api.glfs_fstat.argtypes = [ctypes.c_void_p, ctypes.POINTER(Stat)]  class File(object): -    def __init__(self, fd): +    def __init__(self, fd, path=None):          self.fd = fd +        self.originalpath = path      def __enter__(self):          if self.fd is None: @@ -115,6 +116,13 @@ class File(object):              raise OSError(err, os.strerror(err))          return ret +    def dup(self): +        dupfd = api.glfs_dup(self.fd) +        if not dupfd: +            err = ctypes.get_errno() +            raise OSError(err, os.strerror(err)) +        return File(dupfd, self.originalpath) +      def fallocate(self, mode, offset, len):          ret = api.glfs_fallocate(self.fd, mode, offset, len)          if ret < 0: @@ -166,6 +174,21 @@ class File(object):              raise OSError(err, os.strerror(err))          return ret +    def lseek(self, pos, how): +        """ +        Set the read/write offset position of this file. +        The new position is defined by 'pos' relative to 'how' + +        :param pos: sets new offset position according to 'how' +        :param how: SEEK_SET, sets offset position 'pos' bytes relative to +                    beginning of file, SEEK_CUR, the position is set relative +                    to the current position and SEEK_END sets the position +                    relative to the end of the file. +        :returns: the new offset position + +        """ +        return api.glfs_lseek(self.fd, pos, how) +      def read(self, buflen, flags=0):          rbuf = ctypes.create_string_buffer(buflen)          ret = api.glfs_read(self.fd, rbuf, buflen, flags) @@ -263,6 +286,27 @@ class Volume(object):              return False          return True +    def getatime(self, path): +        """ +        Returns the last access time as reported by stat +        """ +        return self.stat(path).st_atime + +    def getctime(self, path): +        """ +        Returns the time when changes were made to the path as reported by stat +        This time is updated when changes are made to the file or dir's inode +        or the contents of the file +        """ +        return self.stat(path).st_ctime + +    def getmtime(self, path): +        """ +        Returns the time when changes were made to the content of the path +        as reported by stat +        """ +        return self.stat(path).st_mtime +      def getsize(self, filename):          """          Return the size of a file, reported by stat() @@ -388,7 +432,7 @@ class Volume(object):              err = ctypes.get_errno()              raise OSError(err, os.strerror(err)) -        return File(fd) +        return File(fd, path)      def opendir(self, path):          fd = api.glfs_opendir(self.fs, path) diff --git a/test/functional/libgfapi-python-tests.py b/test/functional/libgfapi-python-tests.py index ac5c38f..baad035 100644 --- a/test/functional/libgfapi-python-tests.py +++ b/test/functional/libgfapi-python-tests.py @@ -78,6 +78,7 @@ class FileOpsTest(unittest.TestCase):              self.assertEqual(rc, len(self.data))              ret = fd.fsync()              self.assertEqual(ret, 0) +            self.assertEqual(fd.originalpath, self.path)      def tearDown(self):          self.path = None @@ -110,6 +111,29 @@ class FileOpsTest(unittest.TestCase):              g.close()              self.fail("Expected a OSError with errno.EEXIST") +    def test_write_file_dup_lseek_read(self): +        try: +            f = self.vol.open("dune", os.O_CREAT | os.O_EXCL | os.O_RDWR) +            f.write("I must not fear. Fear is the mind-killer.") +            fdup = f.dup() +            self.assertTrue(isinstance(fdup, gfapi.File)) +            f.close() +            ret = fdup.lseek(0, os.SEEK_SET) +            self.assertEqual(ret, 0) + +            buf = fdup.read(15) +            self.assertEqual(buf.value, "I must not fear") + +            ret = fdup.lseek(29, os.SEEK_SET) +            self.assertEqual(ret, 29) + +            buf = fdup.read(11) +            self.assertEqual(buf.value, "mind-killer") + +            fdup.close() +        except OSError as e: +            self.fail(e.message) +      def test_exists(self):          e = self.vol.exists(self.path)          self.assertTrue(e) diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py index ed7ed45..e0308f7 100644 --- a/test/unit/gluster/test_gfapi.py +++ b/test/unit/gluster/test_gfapi.py @@ -49,7 +49,7 @@ class TestFile(unittest.TestCase):      @classmethod      def setUpClass(cls): -        cls.fd = gfapi.File(2) +        cls.fd = gfapi.File(2, 'fakefile')      @classmethod      def tearDownClass(cls): @@ -77,6 +77,16 @@ class TestFile(unittest.TestCase):          with patch("glusterfs.gfapi.api.glfs_fchown", mock_glfs_fchown):              self.assertRaises(OSError, self.fd.fchown, 9, 11) +    def test_dup(self): +        mock_glfs_dup = Mock() +        mock_glfs_dup.return_value = 2 + +        with patch("glusterfs.gfapi.api.glfs_dup", mock_glfs_dup): +            f = self.fd.dup() +            self.assertTrue(isinstance(f, gfapi.File)) +            self.assertEqual(f.originalpath, "fakefile") +            self.assertEqual(f.fd, 2) +      def test_fdatasync_success(self):          mock_glfs_fdatasync = Mock()          mock_glfs_fdatasync.return_value = 4 @@ -122,6 +132,14 @@ class TestFile(unittest.TestCase):          with patch("glusterfs.gfapi.api.glfs_fsync", mock_glfs_fsync):              self.assertRaises(OSError, self.fd.fsync) +    def test_lseek_success(self): +        mock_glfs_lseek = Mock() +        mock_glfs_lseek.return_value = 20 + +        with patch("glusterfs.gfapi.api.glfs_lseek", mock_glfs_lseek): +            o = self.fd.lseek(20, os.SEEK_SET) +            self.assertEqual(o, 20) +      def test_read_success(self):          def _mock_glfs_read(fd, rbuf, buflen, flags):              rbuf.value = "hello"  | 
