From 559644ddd2fd7065220331d11197bf54f6484231 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Thu, 13 Oct 2011 12:17:12 +0200 Subject: [PATCH] Introduce virFileRewrite for safe file rewrite When saving config files we just overwrite old content of the file. In case something fails during that process (e.g. disk gets full) we lose both old and new content. This patch makes the process more robust by writing the new content into a separate file and only if that succeeds the original file is atomically replaced with the new one. --- src/libvirt_private.syms | 1 + src/util/virfile.c | 56 ++++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 6 +++++ 3 files changed, 63 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a81966d8f7..3366ac971a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1181,6 +1181,7 @@ virFileDirectFdFree; virFileDirectFdNew; virFileFclose; virFileFdopen; +virFileRewrite; # virnetmessage.h diff --git a/src/util/virfile.c b/src/util/virfile.c index 11589988c0..cbc3fccccc 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -334,3 +334,59 @@ int virFileUnlock(int fd ATTRIBUTE_UNUSED, return -ENOSYS; } #endif + +int +virFileRewrite(const char *path, + mode_t mode, + virFileRewriteFunc rewrite, + void *opaque) +{ + char *newfile = NULL; + int fd = -1; + int ret = -1; + + if (virAsprintf(&newfile, "%s.new", path) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((fd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) { + virReportSystemError(errno, _("cannot create file '%s'"), + newfile); + goto cleanup; + } + + if (rewrite(fd, opaque) < 0) { + virReportSystemError(errno, _("cannot write data to file '%s'"), + newfile); + goto cleanup; + } + + if (fsync(fd) < 0) { + virReportSystemError(errno, _("cannot sync file '%s'"), + newfile); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + virReportSystemError(errno, _("cannot save file '%s'"), + newfile); + goto cleanup; + } + + if (rename(newfile, path) < 0) { + virReportSystemError(errno, _("cannot rename file '%s' as '%s'"), + newfile, path); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FORCE_CLOSE(fd); + if (newfile) { + unlink(newfile); + VIR_FREE(newfile); + } + return ret; +} diff --git a/src/util/virfile.h b/src/util/virfile.h index e02561456b..a6e659712b 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -68,4 +68,10 @@ void virFileDirectFdFree(virFileDirectFdPtr dfd); int virFileLock(int fd, bool shared, off_t start, off_t len); int virFileUnlock(int fd, off_t start, off_t len); +typedef int (*virFileRewriteFunc)(int fd, void *opaque); +int virFileRewrite(const char *path, + mode_t mode, + virFileRewriteFunc rewrite, + void *opaque); + #endif /* __VIR_FILES_H */