From nobody Tue Feb 22 22:06:25 2022 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id AF30619DA131; Tue, 22 Feb 2022 22:06:25 +0000 (UTC) (envelope-from git@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) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4K3CtT4b8sz3D5m; Tue, 22 Feb 2022 22:06:25 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1645567585; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hGxFS7ablLscOsfqBKU3l0cFVN/nUC+7hEpLtM4qY94=; b=dO3pT/bNcpG9ALK9gTy3oKeX5maU4vETmT+jtpSTn375WR9vdjw1h/jSt09uggckghjlRH wJWCBmcnF6vTk+TVHfCqEJn2korADsUzD1sbkjRvu4ThkOIimLPC5rqBsIpbdTTnMCGj87 UYOTPDjDCOInOE+VmQXdiwU+CHNVwIwwcd3FqkomWqk8gWNpccFJwgFUgheRm1/anVj2p2 BRoj/42lfKD91NAqT9k8PBRv+Ugl4K2bmNhmGpNF4Jnj/B05Oq8uF3p1X+D+7Gm6/mrYTv wh3iKDZoHWHEtxQqtk0FklAJb//0LIIRe+9HRk2KC9dTB1f9+B8fqaksIppT9Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7971A41FC; Tue, 22 Feb 2022 22:06:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 21MM6PiU001221; Tue, 22 Feb 2022 22:06:25 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 21MM6PoA001220; Tue, 22 Feb 2022 22:06:25 GMT (envelope-from git) Date: Tue, 22 Feb 2022 22:06:25 GMT Message-Id: <202202222206.21MM6PoA001220@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 33ad990ce974 - main - cp: fix -R with links List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 33ad990ce974be50abdc25427b0f365699d83a34 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1645567585; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hGxFS7ablLscOsfqBKU3l0cFVN/nUC+7hEpLtM4qY94=; b=uwbDa/ukdndnN4x7EqNUkPpF0ynObccFto5z74ykrcXjNt7WBx/6tujNWApK+Thg6gHeXu UHECzYixtRKK2E0XiZzM7XFjlTs19106Szq7uLTnWeA5JNrO7c2mBbFft2w8yQQhyM0AEL 47/LfCX2e/WYFbYfH5ffX0LQiuLs5wIQ+pWruBjz0yP63Fd0BGDypq0n68drmriwc17nuP tpT7XTZa+FS64Z8hXmiC0D8NuPm2uiFtimwn/o5doC3Q7ExE1doSy67CJGJx8xInAxqb0A kSxM30R0JIed/M8v6SE3F2euH+GZwzLsy4ORKoJXPdxpHCYg6so15exRHonNTw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1645567585; a=rsa-sha256; cv=none; b=po2UlHj4q1btrkdDRE8EIqvuFBDdAd7WfrLKMuQ74doiJYrn8Xtugtb+dueOL3KFL+8jYB +vJzWvU7m0H6rL9WLDQlznr0g89s1pu/ZswWARFPCAK/9wiBnIVcwJbi4k5AKCU3MhdGNv MRmr9rium5PCbA0ZI67V4g0NeSnLz971CmQoHZsrVUMZLA1VQxIEknNuruGTuYFzDl9MR4 HDYvwINkBQFePpZwYGok7Eqo3e/Bc5hkGWpNVrS2rex3IPLWTbCskMljMDx0WGJzP7QL9x 5LpxTpJ1Xoz8F0zc9xxQDrCu3mtwZPLACMxVKyUzkTV7eucza1a+Rs8wdpAGfA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=33ad990ce974be50abdc25427b0f365699d83a34 commit 33ad990ce974be50abdc25427b0f365699d83a34 Author: Kyle Evans AuthorDate: 2022-01-27 18:02:17 +0000 Commit: Kyle Evans CommitDate: 2022-02-22 22:06:02 +0000 cp: fix -R with links The traversal was previously not properly honoring -H/-L/-P. Notably, we should not have been resolving symlinks encountered during traversal when either -H or -P are specified. Sponsored by: Klara, Inc. Reviewed by: bapt Differential Revision: https://reviews.freebsd.org/D34063 --- bin/cp/cp.c | 23 ++++++++++++++---- bin/cp/tests/cp_test.sh | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 4328b89cfd7a..7156c7f10742 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -87,7 +87,7 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; int fflag, iflag, lflag, nflag, pflag, sflag, vflag; -static int Rflag, rflag; +static int Hflag, Lflag, Rflag, rflag; volatile sig_atomic_t info; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; @@ -100,11 +100,10 @@ main(int argc, char *argv[]) { struct stat to_stat, tmp_stat; enum op type; - int Hflag, Lflag, ch, fts_options, r, have_trailing_slash; + int ch, fts_options, r, have_trailing_slash; char *target; fts_options = FTS_NOCHDIR | FTS_PHYSICAL; - Hflag = Lflag = 0; while ((ch = getopt(argc, argv, "HLPRafilnprsvx")) != -1) switch (ch) { case 'H': @@ -271,6 +270,22 @@ main(int argc, char *argv[]) &to_stat))); } +/* Does the right thing based on -R + -H/-L/-P */ +static int +copy_stat(const char *path, struct stat *sb) +{ + + /* + * For -R -H/-P, we need to lstat() instead; copy() cares about the link + * itself rather than the target if we're not following links during the + * traversal. + */ + if (!Rflag || Lflag) + return (stat(path, sb)); + return (lstat(path, sb)); +} + + static int copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) { @@ -443,7 +458,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) } /* Not an error but need to remember it happened. */ - if (stat(to.p_path, &to_stat) == -1) + if (copy_stat(to.p_path, &to_stat) == -1) dne = 1; else { if (to_stat.st_dev == curr->fts_statp->st_dev && diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh index 3220b45b4438..36d64900f4bb 100755 --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -43,6 +43,21 @@ basic_body() check_size baz 4 } +atf_test_case basic_symlink +basic_symlink_body() +{ + echo "foo" > bar + ln -s bar baz + + atf_check cp baz foo + atf_check test '!' -L foo + + atf_check -e inline:"cp: baz and baz are identical (not copied).\n" \ + -s exit:1 cp baz baz + atf_check -e inline:"cp: bar and baz are identical (not copied).\n" \ + -s exit:1 cp baz bar +} + atf_test_case chrdev chrdev_body() { @@ -130,12 +145,61 @@ matching_srctgt_nonexistent_body() atf_check -e not-empty -s not-exit:0 stat foo/dne/foo } +recursive_link_setup() +{ + extra_cpflag=$1 + + mkdir -p foo/bar + ln -s bar foo/baz + + mkdir foo-mirror + eval "cp -R $extra_cpflag foo foo-mirror" +} + +atf_test_case recursive_link_dflt +recursive_link_dflt_body() +{ + recursive_link_setup + + # -P is the default, so this should work and preserve the link. + atf_check cp -R foo foo-mirror + atf_check test -L foo-mirror/foo/baz +} + +atf_test_case recursive_link_Hflag +recursive_link_Hflag_body() +{ + recursive_link_setup + + # -H will not follow either, so this should also work and preserve the + # link. + atf_check cp -RH foo foo-mirror + atf_check test -L foo-mirror/foo/baz +} + +atf_test_case recursive_link_Lflag +recursive_link_Lflag_body() +{ + recursive_link_setup -L + + # -L will work, but foo/baz ends up expanded to a directory. + atf_check test -d foo-mirror/foo/baz -a \ + '(' ! -L foo-mirror/foo/baz ')' + atf_check cp -RL foo foo-mirror + atf_check test -d foo-mirror/foo/baz -a \ + '(' ! -L foo-mirror/foo/baz ')' +} + atf_init_test_cases() { atf_add_test_case basic + atf_add_test_case basic_symlink atf_add_test_case chrdev atf_add_test_case matching_srctgt atf_add_test_case matching_srctgt_contained atf_add_test_case matching_srctgt_link atf_add_test_case matching_srctgt_nonexistent + atf_add_test_case recursive_link_dflt + atf_add_test_case recursive_link_Hflag + atf_add_test_case recursive_link_Lflag }