From: Rusty Russell Date: Thu, 11 Feb 2010 01:09:08 +0000 (+1030) Subject: Fix Joey's report of rename failing across moint points. X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=354c772e913d137034d5bcd00efdcb880697532e Fix Joey's report of rename failing across moint points. --- diff --git a/tools/ccanlint/compulsory_tests/build.c b/tools/ccanlint/compulsory_tests/build.c index e3f96d7d..d2b22ac5 100644 --- a/tools/ccanlint/compulsory_tests/build.c +++ b/tools/ccanlint/compulsory_tests/build.c @@ -46,7 +46,7 @@ static void *do_build(struct manifest *m) if (filename) { char *realname = talloc_asprintf(m, "%s.o", m->dir); /* We leave this object file around, all built. */ - if (rename(filename, realname) != 0) + if (!move_file(filename, realname)) return talloc_asprintf(m, "Failed to rename %s to %s", filename, realname); return NULL; diff --git a/tools/ccanlint/tests/has_info_documentation.c b/tools/ccanlint/tests/has_info_documentation.c index 9233e288..17e4207e 100644 --- a/tools/ccanlint/tests/has_info_documentation.c +++ b/tools/ccanlint/tests/has_info_documentation.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -81,7 +82,7 @@ static void create_info_template_doc(struct manifest *m, void *check_result) unlink_noerr("_info.new"); err(1, "Closing _info.new"); } - if (rename("_info.new", "_info") != 0) { + if (!move_file("_info.new", "_info")) { unlink_noerr("_info.new"); err(1, "Renaming _info.new to _info"); } diff --git a/tools/namespacize.c b/tools/namespacize.c index 77269aac..545b28bb 100644 --- a/tools/namespacize.c +++ b/tools/namespacize.c @@ -406,7 +406,7 @@ static void setup_adjust_files(const char *dir, static void rename_files(const struct adjusted *adj) { while (adj) { - if (rename(adj->tmpfile, adj->file) != 0) + if (!move_file(adj->tmpfile, adj->file)) warn("Could not rename over '%s', we're in trouble", adj->file); adj = adj->next; diff --git a/tools/tools.c b/tools/tools.c index 87ff4a3b..18cc1b84 100644 --- a/tools/tools.c +++ b/tools/tools.c @@ -1,7 +1,10 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -107,3 +110,39 @@ char *temp_file(const void *ctx, const char *extension) return talloc_asprintf(ctx, "%s/%u%s", tmpdir, count++, extension); } + +bool move_file(const char *oldname, const char *newname) +{ + char *contents; + size_t size; + int fd; + bool ret; + + /* Simple case: rename works. */ + if (rename(oldname, newname) == 0) + return true; + + /* Try copy and delete: not atomic! */ + contents = grab_file(NULL, oldname, &size); + if (!contents) + return false; + + fd = open(newname, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) { + ret = false; + goto free; + } + + ret = write_all(fd, contents, size); + if (close(fd) != 0) + ret = false; + + if (ret) + unlink(oldname); + else + unlink(newname); + +free: + talloc_free(contents); + return ret; +} diff --git a/tools/tools.h b/tools/tools.h index 2092042f..34c2f99f 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -29,6 +29,7 @@ char *talloc_dirname(const void *ctx, const char *dir); char *talloc_getcwd(const void *ctx); char *run_command(const void *ctx, const char *fmt, ...); char *temp_file(const void *ctx, const char *extension); +bool move_file(const char *oldname, const char *newname); /* From compile.c. *