summaryrefslogtreecommitdiffstats
path: root/contrib/elftoolchain/elfcopy/main.c
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2015-01-28 18:37:09 +0000
committeremaste <emaste@FreeBSD.org>2015-01-28 18:37:09 +0000
commitb4f4496909b7cb04bac577eb178e95f3595d4197 (patch)
tree3eef552cafd54c1077c64b2acd82e6d8e2330b18 /contrib/elftoolchain/elfcopy/main.c
parent110aa2a0d09a6283b549938eabee76423a2e96f5 (diff)
downloadFreeBSD-src-b4f4496909b7cb04bac577eb178e95f3595d4197.zip
FreeBSD-src-b4f4496909b7cb04bac577eb178e95f3595d4197.tar.gz
Preserve hard & symbolic links when modifying source file
Strip is often used to modify existing files, rather than creating new files. If the existing file has hard links or is a symbolic link, act as if editing the file in place and preserve the links. Reported by: luigi Reviewed by: imp, rpaulo Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D1682
Diffstat (limited to 'contrib/elftoolchain/elfcopy/main.c')
-rw-r--r--contrib/elftoolchain/elfcopy/main.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/contrib/elftoolchain/elfcopy/main.c b/contrib/elftoolchain/elfcopy/main.c
index 0ba4e68..4a693ca 100644
--- a/contrib/elftoolchain/elfcopy/main.c
+++ b/contrib/elftoolchain/elfcopy/main.c
@@ -210,7 +210,7 @@ static struct {
};
static int copy_from_tempfile(const char *src, const char *dst,
- int infd, int *outfd);
+ int infd, int *outfd, int in_place);
static void create_file(struct elfcopy *ecp, const char *src,
const char *dst);
static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv);
@@ -523,33 +523,39 @@ create_tempfile(char **fn, int *fd)
#undef _TEMPFILEPATH
}
+/*
+ * Copy temporary file with path src and file descriptor infd to path dst.
+ * If in_place is set act as if editing the file in place, avoiding rename()
+ * to preserve hard and symbolic links. Output file remains open, with file
+ * descriptor returned in outfd.
+ */
static int
-copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd)
+copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd,
+ int in_place)
{
int tmpfd;
/*
* First, check if we can use rename().
*/
- if (rename(src, dst) >= 0) {
- *outfd = infd;
- return (0);
- } else if (errno != EXDEV)
- return (-1);
-
- /*
- * If the rename() failed due to 'src' and 'dst' residing in
- * two different file systems, invoke a helper function in
- * libelftc to do the copy.
- */
-
- if (unlink(dst) < 0)
- return (-1);
+ if (in_place == 0) {
+ if (rename(src, dst) >= 0) {
+ *outfd = infd;
+ return (0);
+ } else if (errno != EXDEV)
+ return (-1);
+
+ /*
+ * If the rename() failed due to 'src' and 'dst' residing in
+ * two different file systems, invoke a helper function in
+ * libelftc to do the copy.
+ */
- if ((tmpfd = open(dst, O_CREAT | O_WRONLY, 0755)) < 0)
- return (-1);
+ if (unlink(dst) < 0)
+ return (-1);
+ }
- if (lseek(infd, 0, SEEK_SET) < 0)
+ if ((tmpfd = open(dst, O_CREAT | O_TRUNC | O_WRONLY, 0755)) < 0)
return (-1);
if (elftc_copyfile(infd, tmpfd) < 0)
@@ -578,6 +584,7 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
struct stat sb;
char *tempfile, *elftemp;
int efd, ifd, ofd, ofd0, tfd;
+ int in_place;
tempfile = NULL;
@@ -718,10 +725,15 @@ copy_done:
#endif
if (tempfile != NULL) {
- if (dst == NULL)
+ in_place = 0;
+ if (dst == NULL) {
dst = src;
+ if (lstat(dst, &sb) != -1 &&
+ (sb.st_nlink > 1 || S_ISLNK(sb.st_mode)))
+ in_place = 1;
+ }
- if (copy_from_tempfile(tempfile, dst, ofd, &tfd) < 0)
+ if (copy_from_tempfile(tempfile, dst, ofd, &tfd, in_place) < 0)
err(EXIT_FAILURE, "creation of %s failed", dst);
free(tempfile);
OpenPOWER on IntegriCloud