From owner-svn-src-head@FreeBSD.ORG Wed Jan 28 18:37:10 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3E471A4; Wed, 28 Jan 2015 18:37:10 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2AF2AA25; Wed, 28 Jan 2015 18:37:10 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t0SIbAh3082535; Wed, 28 Jan 2015 18:37:10 GMT (envelope-from emaste@FreeBSD.org) Received: (from emaste@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t0SIbAjc082534; Wed, 28 Jan 2015 18:37:10 GMT (envelope-from emaste@FreeBSD.org) Message-Id: <201501281837.t0SIbAjc082534@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: emaste set sender to emaste@FreeBSD.org using -f From: Ed Maste Date: Wed, 28 Jan 2015 18:37:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r277843 - head/contrib/elftoolchain/elfcopy X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Jan 2015 18:37:10 -0000 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);