Commit 4138d39f authored by Iustin Pop's avatar Iustin Pop
Browse files

Add a "safe" file wrapper over WriteFile

Signed-off-by: default avatarIustin Pop <>
Reviewed-by: default avatarMichael Hanselmann <>
parent 9e100285
......@@ -1912,6 +1912,31 @@ def VerifyFileID(fi_disk, fi_ours):
return (d1, i1) == (d2, i2) and m1 <= m2
def SafeWriteFile(file_name, file_id, **kwargs):
"""Wraper over L{WriteFile} that locks the target file.
By keeping the target file locked during WriteFile, we ensure that
cooperating writers will safely serialise access to the file.
@type file_name: str
@param file_name: the target filename
@type file_id: tuple
@param file_id: a result from L{GetFileID}
fd =, os.O_RDONLY | os.O_CREAT)
if file_id is not None:
disk_id = GetFileID(fd=fd)
if not VerifyFileID(disk_id, file_id):
raise errors.LockError("Cannot overwrite file %s, it has been modified"
" since last written" % file_name)
return WriteFile(file_name, **kwargs)
def ReadOneLineFile(file_name, strict=False):
"""Return the first non-empty line from a file.
......@@ -2374,6 +2374,21 @@ class TestFileID(testutils.GanetiTestCase):
def testWriteFile(self):
name = self._CreateTempFile()
oldi = utils.GetFileID(path=name)
mtime = oldi[2]
os.utime(name, (mtime + 10, mtime + 10))
self.assertRaises(errors.LockError, utils.SafeWriteFile, name,
oldi, data="")
os.utime(name, (mtime - 10, mtime - 10))
utils.SafeWriteFile(name, oldi, data="")
oldi = utils.GetFileID(path=name)
mtime = oldi[2]
os.utime(name, (mtime + 10, mtime + 10))
# this doesn't raise, since we passed None
utils.SafeWriteFile(name, None, data="")
if __name__ == '__main__':
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment