[augeas-devel] [PATCH] Fix saving of files where backup/new and target are on different devices
David Lutterkort
lutter at redhat.com
Wed Nov 19 11:59:50 UTC 2008
* transform.c (clone_file): new function
* transform.c (transform_save): if rename fails because new/backup file
and target file are on different devices, copy the files
---
src/transform.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 77 insertions(+), 9 deletions(-)
diff --git a/src/transform.c b/src/transform.c
index e216a6b..93bf485 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -448,6 +448,68 @@ static int transfer_file_attrs(const char *from, const char *to,
return 0;
}
+static int clone_file(const char *from, const char *to,
+ const char **err_status) {
+ FILE *from_fp = NULL, *to_fp = NULL;
+ char buf[BUFSIZ];
+ size_t len;
+ int result = -1;
+
+ unlink(to); /* Return value ignored intentionally */
+ if (link(from, to) == 0)
+ return 0;
+ if (errno != EXDEV) {
+ *err_status = "link";
+ return -1;
+ }
+
+ /* link not possible, copy file contents */
+ from_fp = fopen(from, "r");
+ if (!(from_fp = fopen(from, "r"))) {
+ *err_status = "clone_open_src";
+ goto done;
+ }
+
+ if (!(to_fp = fopen(to, "w"))) {
+ *err_status = "clone_open_dst";
+ goto done;
+ }
+
+ if (transfer_file_attrs(from, to, err_status) < 0)
+ goto done;
+
+ while ((len = fread(buf, 1, BUFSIZ, from_fp)) > 0) {
+ if (fwrite(buf, 1, len, to_fp) != len) {
+ *err_status = "clone_write";
+ goto done;
+ }
+ }
+ if (ferror(from_fp)) {
+ *err_status = "clone_read";
+ goto done;
+ }
+
+ result = 0;
+ done:
+ fclose(from_fp);
+ fclose(to_fp);
+ if (result != 0)
+ unlink(to);
+ return result;
+}
+
+static char *strappend(const char *s1, const char *s2) {
+ size_t len = strlen(s1) + strlen(s2);
+ char *result = NULL, *p;
+
+ if (ALLOC_N(result, len + 1) < 0)
+ return NULL;
+
+ p = stpcpy(result, s1);
+ stpcpy(p, s2);
+ return result;
+}
+
int transform_save(struct augeas *aug, struct transform *xform,
const char *path, struct tree *tree) {
FILE *fp = NULL;
@@ -457,6 +519,7 @@ int transform_save(struct augeas *aug, struct transform *xform,
char *text = NULL;
const char *filename = path + strlen(AUGEAS_FILES_TREE) + 1;
const char *err_status = NULL;
+ char *dyn_err_status = NULL;
struct lns_error *err = NULL;
int result = -1;
@@ -545,24 +608,29 @@ int transform_save(struct augeas *aug, struct transform *xform,
goto done;
}
- /* We do an unlink + link on AUGSAVE rather than a rename so that
- we never have any point in time where augorig_canon does
- not exist. */
- unlink(augsave); /* Return value ignored intentionally */
- if (link(augorig_canon, augsave) != 0) {
- err_status = "rename_augsave";
+ if (clone_file(augorig_canon, augsave, &err_status) != 0) {
+ dyn_err_status = strappend(err_status, "_augsave");
goto done;
}
}
- if (rename(augnew, augorig_canon) != 0) {
- err_status = "rename_augnew";
+ if (clone_file(augnew, augorig_canon, &err_status) != 0) {
+ dyn_err_status = strappend(err_status, "_augnew");
+ goto done;
+ }
+ if (unlink(augnew) != 0) {
+ err_status = "unlink_augnew";
goto done;
}
}
result = 1;
done:
- store_error(aug, filename, path, err_status, errno, err);
+ {
+ const char *emsg =
+ dyn_err_status == NULL ? err_status : dyn_err_status;
+ store_error(aug, filename, path, emsg, errno, err);
+ }
+ free(dyn_err_status);
lens_release(xform->lens);
free(text);
free(augnew);
--
1.5.6.5
More information about the augeas-devel
mailing list