From 9e100285c6862e28da18ed2094197acc17a140b9 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Fri, 22 Oct 2010 14:00:35 +0200 Subject: [PATCH] Add functions to read and compare file 'ID's Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Michael Hanselmann <hansmi@google.com> --- lib/utils.py | 40 +++++++++++++++++++++++++++++++++++ test/ganeti.utils_unittest.py | 19 +++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/lib/utils.py b/lib/utils.py index 919eab11c..aa84cb1f8 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1872,6 +1872,46 @@ def WriteFile(file_name, fn=None, data=None, return result +def GetFileID(path=None, fd=None): + """Returns the file 'id', i.e. the dev/inode and mtime information. + + Either the path to the file or the fd must be given. + + @param path: the file path + @param fd: a file descriptor + @return: a tuple of (device number, inode number, mtime) + + """ + if [path, fd].count(None) != 1: + raise errors.ProgrammerError("One and only one of fd/path must be given") + + if fd is None: + st = os.stat(path) + else: + st = os.fstat(fd) + + return (st.st_dev, st.st_ino, st.st_mtime) + + +def VerifyFileID(fi_disk, fi_ours): + """Verifies that two file IDs are matching. + + Differences in the inode/device are not accepted, but and older + timestamp for fi_disk is accepted. + + @param fi_disk: tuple (dev, inode, mtime) representing the actual + file data + @param fi_ours: tuple (dev, inode, mtime) representing the last + written file data + @rtype: boolean + + """ + (d1, i1, m1) = fi_disk + (d2, i2, m2) = fi_ours + + return (d1, i1) == (d2, i2) and m1 <= m2 + + def ReadOneLineFile(file_name, strict=False): """Return the first non-empty line from a file. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 08c753e3b..7fc93db1f 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -2356,5 +2356,24 @@ class TestFindMatch(unittest.TestCase): self.assert_(utils.FindMatch(data, "Hello World") is None) +class TestFileID(testutils.GanetiTestCase): + def testEquality(self): + name = self._CreateTempFile() + oldi = utils.GetFileID(path=name) + self.failUnless(utils.VerifyFileID(oldi, oldi)) + + def testUpdate(self): + name = self._CreateTempFile() + oldi = utils.GetFileID(path=name) + os.utime(name, None) + fd = os.open(name, os.O_RDWR) + try: + newi = utils.GetFileID(fd=fd) + self.failUnless(utils.VerifyFileID(oldi, newi)) + self.failUnless(utils.VerifyFileID(newi, oldi)) + finally: + os.close(fd) + + if __name__ == '__main__': testutils.GanetiTestProgram() -- GitLab