Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Jan 2015 18:37:10 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r277843 - head/contrib/elftoolchain/elfcopy
Message-ID:  <201501281837.t0SIbAjc082534@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Wed Jan 28 18:37:09 2015
New Revision: 277843
URL: https://svnweb.freebsd.org/changeset/base/277843

Log:
  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

Modified:
  head/contrib/elftoolchain/elfcopy/main.c

Modified: head/contrib/elftoolchain/elfcopy/main.c
==============================================================================
--- head/contrib/elftoolchain/elfcopy/main.c	Wed Jan 28 18:36:33 2015	(r277842)
+++ head/contrib/elftoolchain/elfcopy/main.c	Wed Jan 28 18:37:09 2015	(r277843)
@@ -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 c
 	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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501281837.t0SIbAjc082534>