From owner-svn-src-all@freebsd.org Thu Jan 31 05:20:12 2019 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 949D01342058; Thu, 31 Jan 2019 05:20:12 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 1C5916E4A7; Thu, 31 Jan 2019 05:20:12 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 0A55E2892; Thu, 31 Jan 2019 05:20:12 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x0V5KB2J033767; Thu, 31 Jan 2019 05:20:11 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x0V5KBXj033765; Thu, 31 Jan 2019 05:20:11 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201901310520.x0V5KBXj033765@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Thu, 31 Jan 2019 05:20:11 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r343601 - in head/usr.bin/xinstall: . tests X-SVN-Group: head X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in head/usr.bin/xinstall: . tests X-SVN-Commit-Revision: 343601 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 1C5916E4A7 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.998,0]; NEURAL_HAM_SHORT(-0.96)[-0.961,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-0.999,0] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 31 Jan 2019 05:20:12 -0000 Author: kevans Date: Thu Jan 31 05:20:11 2019 New Revision: 343601 URL: https://svnweb.freebsd.org/changeset/base/343601 Log: install(1): Fix relative path calculation with partial common dest/src For example, from the referenced PR [1]: $ mkdir /tmp/lib/ /tmp/libexec $ touch /tmp/lib/foo.so $ install -lrs /tmp/lib/foo.so /tmp/libexec/ The common path identification bits terminate src at /tmp/lib/ and the destination at /tmp/libe. The subsequent backtracking is then incorrect, as it traverses the destination and backtraces exactly one level while eating the 'libexec' because it was previously (falsely) identified as common with 'lib'. The obvious fix would be to make sure we've actually terminated just after directory separators and rewind a character if we haven't. In the above example, we would end up rewinding to /tmp/ and subsequently doing the right thing. Test case added. PR: 235330 [1] MFC after: 1 week Modified: head/usr.bin/xinstall/tests/install_test.sh head/usr.bin/xinstall/xinstall.c Modified: head/usr.bin/xinstall/tests/install_test.sh ============================================================================== --- head/usr.bin/xinstall/tests/install_test.sh Thu Jan 31 04:16:52 2019 (r343600) +++ head/usr.bin/xinstall/tests/install_test.sh Thu Jan 31 05:20:11 2019 (r343601) @@ -377,6 +377,29 @@ mkdir_simple_body() { atf_check install -d dir1/dir2/dir3 } +atf_test_case symbolic_link_relative_absolute_common +symbolic_link_relative_absolute_common_head() { + atf_set "descr" "Verify -l rs with absolute paths having common components" +} +symbolic_link_relative_absolute_common_body() { + filename=foo.so + src_path=lib + src_path_prefixed=$PWD/$src_path + dest_path=$PWD/libexec/ + src_file=$src_path_prefixed/$filename + dest_file=$dest_path/$filename + + atf_check mkdir $src_path_prefixed $dest_path + atf_check touch $src_file + atf_check install -l sr $src_file $dest_path + + dest_path_relative=$(readlink $dest_file) + src_path_relative="../lib/$filename" + if [ "$src_path_relative" != "$dest_path_relative" ]; then + atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')" + fi +} + atf_init_test_cases() { atf_add_test_case copy_to_nonexistent atf_add_test_case copy_to_nonexistent_safe @@ -415,5 +438,6 @@ atf_init_test_cases() { atf_add_test_case symbolic_link_relative_absolute_source_and_dest1 atf_add_test_case symbolic_link_relative_absolute_source_and_dest1_double_slash atf_add_test_case symbolic_link_relative_absolute_source_and_dest2 + atf_add_test_case symbolic_link_relative_absolute_common atf_add_test_case mkdir_simple } Modified: head/usr.bin/xinstall/xinstall.c ============================================================================== --- head/usr.bin/xinstall/xinstall.c Thu Jan 31 04:16:52 2019 (r343600) +++ head/usr.bin/xinstall/xinstall.c Thu Jan 31 05:20:11 2019 (r343601) @@ -673,7 +673,7 @@ makelink(const char *from_name, const char *to_name, } if (dolink & LN_RELATIVE) { - char *to_name_copy, *cp, *d, *s; + char *to_name_copy, *cp, *d, *ld, *ls, *s; if (*from_name != '/') { /* this is already a relative link */ @@ -709,8 +709,19 @@ makelink(const char *from_name, const char *to_name, free(to_name_copy); /* Trim common path components. */ - for (s = src, d = dst; *s == *d; s++, d++) + ls = ld = NULL; + for (s = src, d = dst; *s == *d; ls = s, ld = d, s++, d++) continue; + /* + * If we didn't end after a directory separator, then we've + * falsely matched the last component. For example, if one + * invoked install -lrs /lib/foo.so /libexec/ then the source + * would terminate just after the separator while the + * destination would terminate in the middle of 'libexec', + * leading to a full directory getting falsely eaten. + */ + if ((ls != NULL && *ls != '/') || (ld != NULL && *ld != '/')) + s--, d--; while (*s != '/') s--, d--;