Browse Source

Fix Joey's report of rename failing across moint points.

Rusty Russell 16 years ago
parent
commit
354c772e91

+ 1 - 1
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;

+ 2 - 1
tools/ccanlint/tests/has_info_documentation.c

@@ -1,5 +1,6 @@
 #include <tools/ccanlint/ccanlint.h>
 #include <tools/doc_extract.h>
+#include <tools/tools.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -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");
 	}

+ 1 - 1
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;

+ 39 - 0
tools/tools.c

@@ -1,7 +1,10 @@
 #include <ccan/talloc/talloc.h>
 #include <ccan/grab_file/grab_file.h>
+#include <ccan/noerr/noerr.h>
+#include <ccan/read_write_all/read_write_all.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
@@ -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;
+}

+ 1 - 0
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.
  *