Revision 087b34fe lib/utils.py
b/lib/utils.py | ||
---|---|---|
855 | 855 |
return f.read(128).rstrip("\n") |
856 | 856 |
finally: |
857 | 857 |
f.close() |
858 |
|
|
859 |
|
|
860 |
def WriteFile(file_name, fn=None, data=None, |
|
861 |
mode=None, uid=-1, gid=-1, |
|
862 |
atime=None, mtime=None): |
|
863 |
"""(Over)write a file atomically. |
|
864 |
|
|
865 |
The file_name and either fn (a function taking one argument, the |
|
866 |
file descriptor, and which should write the data to it) or data (the |
|
867 |
contents of the file) must be passed. The other arguments are |
|
868 |
optional and allow setting the file mode, owner and group, and the |
|
869 |
mtime/atime of the file. |
|
870 |
|
|
871 |
If the function doesn't raise an exception, it has succeeded and the |
|
872 |
target file has the new contents. If the file has raised an |
|
873 |
exception, an existing target file should be unmodified and the |
|
874 |
temporary file should be removed. |
|
875 |
|
|
876 |
""" |
|
877 |
if not os.path.isabs(file_name): |
|
878 |
raise errors.ProgrammerError("Path passed to WriteFile is not" |
|
879 |
" absolute: '%s'" % file_name) |
|
880 |
|
|
881 |
if [fn, data].count(None) != 1: |
|
882 |
raise errors.ProgrammerError("fn or data required") |
|
883 |
|
|
884 |
if [atime, mtime].count(None) == 1: |
|
885 |
raise errors.ProgrammerError("Both atime and mtime must be either" |
|
886 |
" set or None") |
|
887 |
|
|
888 |
|
|
889 |
dir_name, base_name = os.path.split(file_name) |
|
890 |
fd, new_name = tempfile.mkstemp('.new', base_name, dir_name) |
|
891 |
# here we need to make sure we remove the temp file, if any error |
|
892 |
# leaves it in place |
|
893 |
try: |
|
894 |
if uid != -1 or gid != -1: |
|
895 |
os.chown(new_name, uid, gid) |
|
896 |
if mode: |
|
897 |
os.chmod(new_name, mode) |
|
898 |
if data is not None: |
|
899 |
os.write(fd, data) |
|
900 |
else: |
|
901 |
fn(fd) |
|
902 |
os.fsync(fd) |
|
903 |
if atime is not None and mtime is not None: |
|
904 |
os.utime(new_name, (atime, mtime)) |
|
905 |
os.rename(new_name, file_name) |
|
906 |
finally: |
|
907 |
os.close(fd) |
|
908 |
RemoveFile(new_name) |
Also available in: Unified diff