diff --git a/lib/utils.py b/lib/utils.py index fda1f6b3c6ab108615829d0ee97f9e1b1840b161..28c2be828a4f8d7c71c39b7f30691790934f3a94 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -959,8 +959,9 @@ def NewUUID(): def WriteFile(file_name, fn=None, data=None, mode=None, uid=-1, gid=-1, - atime=None, mtime=None, - check_abspath=True, dry_run=False, backup=False): + atime=None, mtime=None, close=True, + check_abspath=True, dry_run=False, backup=False, + prewrite=None, postwrite=None): """(Over)write a file atomically. The file_name and either fn (a function taking one argument, the @@ -974,6 +975,22 @@ def WriteFile(file_name, fn=None, data=None, exception, an existing target file should be unmodified and the temporary file should be removed. + Args: + file_name: New filename + fn: Content writing function, called with file descriptor as parameter + data: Content as string + mode: File mode + uid: Owner + gid: Group + atime: Access time + mtime: Modification time + close: Whether to close file after writing it + prewrite: Function object called before writing content + postwrite: Function object called after writing content + + Returns: + None if "close" parameter evaluates to True, otherwise file descriptor. + """ if check_abspath and not os.path.isabs(file_name): raise errors.ProgrammerError("Path passed to WriteFile is not" @@ -998,19 +1015,29 @@ def WriteFile(file_name, fn=None, data=None, os.chown(new_name, uid, gid) if mode: os.chmod(new_name, mode) + if callable(prewrite): + prewrite(fd) if data is not None: os.write(fd, data) else: fn(fd) + if callable(postwrite): + postwrite(fd) os.fsync(fd) if atime is not None and mtime is not None: os.utime(new_name, (atime, mtime)) if not dry_run: os.rename(new_name, file_name) finally: - os.close(fd) + if close: + os.close(fd) + result = None + else: + result = fd RemoveFile(new_name) + return result + def all(seq, pred=bool): "Returns True if pred(x) is True for every element in the iterable"