summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-01-09 01:26:41 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-01-09 01:26:41 -0600
commitb9ad6f1e954a68640d01176e597af03ec9281e35 (patch)
tree2428dd8869a2754e3ade86aff5d64f462b6f67c6
parentff4002f7a42db78228975b1c492cd8afa22df886 (diff)
downloadlibr-b9ad6f1e.tar.gz
libr-b9ad6f1e.zip
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
-rw-r--r--src/libr-bfd.c25
1 files changed, 21 insertions, 4 deletions
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 @@ int safe_rename(const char *old, const char *new)
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 @@ int safe_rename(const char *old, const char *new)
if (ferror(in) || ferror(out)) {
fclose(in);
fclose(out);
- remove(new);
+ remove((is_symlink)?linkdest:new);
return -1;
}
}
@@ -351,7 +368,7 @@ int safe_rename(const char *old, const char *new)
fclose(in);
fclose(out);
if(status_in || status_out) {
- remove(new);
+ remove((is_symlink)?linkdest:new);
return -1;
}
return remove(old);