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(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9666a0a..1c7910b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1172,6 +1172,7 @@ virFileDirectFdFree; virFileDirectFdNew; virFileFclose; virFileFdopen; +virFileRewrite; virFileSync; diff --git a/src/util/virfile.c b/src/util/virfile.c index 50b8aab..8c00e86 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -350,3 +350,59 @@ virFileSync(int fd, bool metadata) return ret; } + +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 (virFileSync(fd, true) < 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 0b14e1d..c26ff5a 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -70,4 +70,10 @@ int virFileUnlock(int fd, off_t start, off_t len); int virFileSync(int fd, bool metadata); +typedef int (*virFileRewriteFunc)(int fd, void *opaque); +int virFileRewrite(const char *path, + mode_t mode, + virFileRewriteFunc rewrite, + void *opaque); + #endif /* __VIR_FILES_H */ -- 1.7.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list