]> xenbits.xensource.com Git - libvirt.git/commitdiff
Introduce virFileRewrite for safe file rewrite
authorJiri Denemark <jdenemar@redhat.com>
Thu, 13 Oct 2011 10:17:12 +0000 (12:17 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Thu, 27 Oct 2011 18:11:24 +0000 (20:11 +0200)
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
src/util/virfile.c
src/util/virfile.h

index a81966d8f7ee30dc3b6900c3f2744fe8f7ac9248..3366ac971a15b6e1dfdef8186ba55c1178dec784 100644 (file)
@@ -1181,6 +1181,7 @@ virFileDirectFdFree;
 virFileDirectFdNew;
 virFileFclose;
 virFileFdopen;
+virFileRewrite;
 
 
 # virnetmessage.h
index 11589988c021d1a9663a6a184ee86acf5dfa9d15..cbc3fccccc413b23e6fa8a7d1fc858e59d07976c 100644 (file)
@@ -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;
+}
index e02561456ba5b8c40e0f1f7ad637ce7465d29d08..a6e659712b102ccc0200ba2a8aef20bf63d6daee 100644 (file)
@@ -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 */