mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 21:34:54 +03:00
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.
This commit is contained in:
parent
9b76b08ae4
commit
559644ddd2
@ -1181,6 +1181,7 @@ virFileDirectFdFree;
|
||||
virFileDirectFdNew;
|
||||
virFileFclose;
|
||||
virFileFdopen;
|
||||
virFileRewrite;
|
||||
|
||||
|
||||
# virnetmessage.h
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user