Branch: master

b9ad6f1e 2015-01-09 01:26:41 Timothy Pearson
Alter safe_rename behaviour to more closely match that of rename()
This resolves bus errors on tdelibs build when using cross-device /tmp due to truncating libraries that tdelfeditor relies on when updating their metadata
M src/libr-bfd.c
diff --git a/src/libr-bfd.c b/src/libr-bfd.c
index 338cd81..9d6d263 100644
--- a/src/libr-bfd.c
+++ b/src/libr-bfd.c
@@ -43,6 +43,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <limits.h>
 
 /*
  * Build the libr_file handle for processing with libbfd
@@ -324,12 +325,28 @@
 	size_t read;
 	int status_in;
 	int status_out;
-	
+	char linkdest[PATH_MAX];
+	char linkdest_test[PATH_MAX];
+	int ret;
+	int is_symlink = 0;
+	ret = readlink(new, linkdest_test, PATH_MAX);
+	while (ret >= 0) {
+		// Symlink encountered
+		is_symlink = 1;
+		linkdest_test[ret] = 0;
+		char* cwd = getcwd(NULL, 0);
+		snprintf(linkdest, PATH_MAX, "%s/%s", cwd, linkdest_test);
+		free(cwd);
+		ret = readlink(linkdest, linkdest_test, PATH_MAX);
+	}
+
 	in = fopen(old, "r");
 	if(!in) {
 		return -1;
 	}
-	out = fopen(new, "w");
+	// Avoid bus error if modifying a library we are currently using
+	unlink((is_symlink)?linkdest:new);
+	out = fopen((is_symlink)?linkdest:new, "w");
 	if(!out) {
 		fclose(in);
 		return -1;
@@ -342,7 +359,7 @@
 		if (ferror(in) || ferror(out)) {
 			fclose(in);
 			fclose(out);
-			remove(new);
+			remove((is_symlink)?linkdest:new);
 			return -1;
 		}
 	}
@@ -351,7 +368,7 @@
 	fclose(in);
 	fclose(out);
 	if(status_in || status_out) {
-		remove(new);
+		remove((is_symlink)?linkdest:new);
 		return -1;
 	}
 	return remove(old);