On Wed, Oct 19, 2011 at 07:26:25PM +0200, Jiri Denemark wrote: > 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 */ ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list