[libvirt] [PATCH 2/4] Introduce virFileRewrite for safe file rewrite

Daniel P. Berrange berrange at redhat.com
Thu Oct 20 09:21:25 UTC 2011


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 :|




More information about the libvir-list mailing list