From nobody Wed Jan 17 18:28:34 2024 X-Original-To: dev-commits-src-branches@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 4TFZBp5984z56P96; Wed, 17 Jan 2024 18:28:34 +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 4TFZBp4Qxsz4c4w; Wed, 17 Jan 2024 18:28:34 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705516114; 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=e03MNRVww2t5pHlzg6CxjEZ2zrIfR3nOs/+0HfVij4k=; b=mIiDdoEGdAXGIDAVU4P595hbxRNAgL6ZxIXnYKz0OdryosTdTJB18ev3uxejPbv+C0zUFC 2treBq78Ml6ftsdso+0L9dZX9XJeZ0o113a3gpnEbOQf0bFjhOVN8N0Pb+m9jditKsHPvB Po+1vCGG3uPey4p8JZNk62/Ec+utU/tgdTA6mBtZP1VZqevSJPJkHILRIqSd50bOLyWlPW 8grqUjTRqjkmE++fk7qRcCg1T17ORbQi83RMm1YpDhCHvN1NRe/9d3OMYCiASVYes6eAC9 I8SH05SNH9D2pQHg2kgwUMeIBc01pqRhWjVhCbtjwm01cbPw3J4MN2njfM+L9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705516114; 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=e03MNRVww2t5pHlzg6CxjEZ2zrIfR3nOs/+0HfVij4k=; b=I/lTOhqjunkXz4ABGgYtZCN0dwfguuMxcHhEMGj9aSSx5egBlchN0Xp1+u3UXgdrbJvOlJ o80OPNVkUwIrDr8fA4A6akXeNnUqW+FUuF1+LvS3HF1GYDbBKxBQUDG6QdS7MpvxDsq8N9 siKPyAJCjQYl1HEOhVnzGzxn0i6v/bZpXIecjr+12E8fTskAJhjPKD7/0jAjgKN5r0xgLD 6R527kMHRPc+B4Ew7PDxNRuhUo3gAlLecVjPkTSSHQ1PaNtH70jYbeLjyCeiz6rr9k7515 5nJqppP7E/sXwqZdD4S4+B8kIsaJjA0hydv73j+aeFfMMbEdcU/MOArHPGsHSw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1705516114; a=rsa-sha256; cv=none; b=a5jY0lJMhMQPpsY3U4zL+oWWA85nMHO5hcQ90Ip1iAsU3dHqoviqK1z9qSdyrTXD7mdRDm jcRlZg2t+DJRpg8Uu2F5XdZXftZgKmr9/lGiKs/3tecWjISd0eVZjy1J1guAs2graYEAlg tzCTjeDF13uUucGEvaP5fYjKXHmYhiGYfEsO0iO5DQ0uZoPtBjKlNpvtVbE1CZHP4eQpaE vhqCW0H04kksJFRJRKQn+sSVTNtkUqJQrDydtom35SbFCR/xwCusw5PNlgL0YattFGSekB vO7ILMNjfqkJq54S1/dDmRCPeloiOw2MJjYWex92SnkTepJSz3z7gH/p9Zzikg== 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 4TFZBp3PkbzZk1; Wed, 17 Jan 2024 18:28:34 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 40HISY6l063293; Wed, 17 Jan 2024 18:28:34 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 40HISYEe063290; Wed, 17 Jan 2024 18:28:34 GMT (envelope-from git) Date: Wed, 17 Jan 2024 18:28:34 GMT Message-Id: <202401171828.40HISYEe063290@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: d514cadacc50 - stable/14 - cp: Add tests for hard link case. List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: d514cadacc50bfcdef76214b2499bcef464b324e Auto-Submitted: auto-generated The branch stable/14 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=d514cadacc50bfcdef76214b2499bcef464b324e commit d514cadacc50bfcdef76214b2499bcef464b324e Author: Dag-Erling Smørgrav AuthorDate: 2023-12-13 21:31:05 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2024-01-17 18:28:22 +0000 cp: Add tests for hard link case. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D43052 (cherry picked from commit 1fead66b64822f3f8106ad09bef0b9656836fa1a) cp: Add tests for symbolic link case. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans, allanjude Differential Revision: https://reviews.freebsd.org/D43054 (cherry picked from commit d3a8e9b43b4cef5b80e3845dfa8fd1fec6e568f9) cp: Refactor the core logic. Rewrite `copy_file()` so the lflag and sflag are handled as early as possible instead of constantly checking that they're not set and then handling them at the end. This also opens the door to changing the failure logic at some future point (for instance, we might decide to fall back to copying if `errno` indicates that the file system does not support links). MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans, allanjude Differential Revision: https://reviews.freebsd.org/D43055 (cherry picked from commit d002316fd7bf0b359ea2f5518f3c10f6ad89a9ac) cp: Split the basic_symlink test case in two. This test case tests two different things: first, that copying a symlink results in a file with the same contents as the target of the symlink, rather than a second symlink, and second, that cp will refuse to copy a file to itself, or to a link to itself, or a link to its target. Leave the first part in basic_symlink, move the second part to a new test case named samefile, and slightly expand both cases. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D43062 (cherry picked from commit ac56b9d83c75f548667912ffe422be6bd4f5c27e) cp: Move the flags around a bit. - The HLPR flags are grouped together at the beginning because they are the standard flags for programs using FTS. Move the N flag out from among them to its correct place in the sequence. - The Pflag variable isn't used outside main(), but moving it out lets us skip initialization and keeps it with its friends H, L and R. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D43063 (cherry picked from commit 0f4467ce444b201468d2268958130f495951ca3c) cp: Further simplify the core logic. If the destination file exists but we decide unlink it, set the dne flag. This means we don't need to re-check the conditions that would have caused us to delete the file when we later need to decide whether to create or replace it. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D43064 (cherry picked from commit 38509270663f336103273878cc8ddc88a225b9d8) cp: Move the -N flag in the manual page. This accidentally got left out of 0f4467ce444b. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans, allanjude Differential Revision: https://reviews.freebsd.org/D43067 (cherry picked from commit 53fc8e190241233d94e183f8a39ec39f2154dfa8) --- bin/cp/cp.1 | 10 ++-- bin/cp/cp.c | 13 +++--- bin/cp/tests/cp_test.sh | 87 ++++++++++++++++++++++++++++++++-- bin/cp/utils.c | 122 ++++++++++++++++++++++++------------------------ 4 files changed, 154 insertions(+), 78 deletions(-) diff --git a/bin/cp/cp.1 b/bin/cp/cp.1 index 3862babafe7f..d8d62ef076a1 100644 --- a/bin/cp/cp.1 +++ b/bin/cp/cp.1 @@ -31,7 +31,7 @@ .\" .\" @(#)cp.1 8.3 (Berkeley) 4/18/94 .\" -.Dd December 7, 2023 +.Dd December 14, 2023 .Dt CP 1 .Os .Sh NAME @@ -90,10 +90,6 @@ option is specified, symbolic links on the command line are followed. If the .Fl R option is specified, all symbolic links are followed. -.It Fl N -When used with -.Fl p , -suppress copying file flags. .It Fl P No symbolic links are followed. This is the default if the @@ -161,6 +157,10 @@ or options.) .It Fl l Create hard links to regular files in a hierarchy instead of copying. +.It Fl N +When used with +.Fl p , +suppress copying file flags. .It Fl n Do not overwrite an existing file. (The diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 8217a1e5d3c9..852868e65dcb 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -85,7 +85,7 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; -static int Hflag, Lflag, Rflag, rflag; +static int Hflag, Lflag, Pflag, Rflag, rflag; volatile sig_atomic_t info; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; @@ -98,12 +98,11 @@ main(int argc, char *argv[]) { struct stat to_stat, tmp_stat; enum op type; - int Pflag, ch, fts_options, r, have_trailing_slash; + int ch, fts_options, r, have_trailing_slash; char *target; fts_options = FTS_NOCHDIR | FTS_PHYSICAL; - Pflag = 0; - while ((ch = getopt(argc, argv, "HLNPRafilnprsvx")) != -1) + while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1) switch (ch) { case 'H': Hflag = 1; @@ -113,9 +112,6 @@ main(int argc, char *argv[]) Lflag = 1; Hflag = Pflag = 0; break; - case 'N': - Nflag = 1; - break; case 'P': Pflag = 1; Hflag = Lflag = 0; @@ -140,6 +136,9 @@ main(int argc, char *argv[]) case 'l': lflag = 1; break; + case 'N': + Nflag = 1; + break; case 'n': nflag = 1; fflag = iflag = 0; diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh index f995d709cc3c..397c06d75bbb 100755 --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -51,10 +51,7 @@ basic_symlink_body() 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_check cmp foo bar } atf_test_case chrdev @@ -71,6 +68,35 @@ chrdev_body() check_size trunc 0 } +atf_test_case hardlink +hardlink_body() +{ + echo "foo" >foo + atf_check cp -l foo bar + atf_check -o inline:"foo\n" cat bar + atf_check_equal "$(stat -f%d,%i foo)" "$(stat -f%d,%i bar)" +} + +atf_test_case hardlink_exists +hardlink_exists_body() +{ + echo "foo" >foo + echo "bar" >bar + atf_check -s not-exit:0 -e match:exists cp -l foo bar + atf_check -o inline:"bar\n" cat bar + atf_check_not_equal "$(stat -f%d,%i foo)" "$(stat -f%d,%i bar)" +} + +atf_test_case hardlink_exists_force +hardlink_exists_force_body() +{ + echo "foo" >foo + echo "bar" >bar + atf_check cp -fl foo bar + atf_check -o inline:"foo\n" cat bar + atf_check_equal "$(stat -f%d,%i foo)" "$(stat -f%d,%i bar)" +} + atf_test_case matching_srctgt matching_srctgt_body() { @@ -198,6 +224,22 @@ recursive_link_Lflag_body() '(' ! -L foo-mirror/foo/baz ')' } +atf_test_case samefile +samefile_body() +{ + echo "foo" >foo + ln foo bar + ln -s bar baz + atf_check -e match:"baz and baz are identical" \ + -s exit:1 cp baz baz + atf_check -e match:"bar and baz are identical" \ + -s exit:1 cp baz bar + atf_check -e match:"foo and baz are identical" \ + -s exit:1 cp baz foo + atf_check -e match:"bar and foo are identical" \ + -s exit:1 cp foo bar +} + file_is_sparse() { atf_check ${0%/*}/sparse "$1" @@ -205,7 +247,7 @@ file_is_sparse() files_are_equal() { - atf_check test "$(stat -f "%d %i" "$1")" != "$(stat -f "%d %i" "$2")" + atf_check_not_equal "$(stat -f%d,%i "$1")" "$(stat -f%d,%i "$2")" atf_check cmp "$1" "$2" } @@ -293,11 +335,42 @@ standalone_Pflag_body() atf_check -o inline:'Symbolic Link\n' stat -f %SHT baz } +atf_test_case symlink +symlink_body() +{ + echo "foo" >foo + atf_check cp -s foo bar + atf_check -o inline:"foo\n" cat bar + atf_check -o inline:"foo\n" readlink bar +} + +atf_test_case symlink_exists +symlink_exists_body() +{ + echo "foo" >foo + echo "bar" >bar + atf_check -s not-exit:0 -e match:exists cp -s foo bar + atf_check -o inline:"bar\n" cat bar +} + +atf_test_case symlink_exists_force +symlink_exists_force_body() +{ + echo "foo" >foo + echo "bar" >bar + atf_check cp -fs foo bar + atf_check -o inline:"foo\n" cat bar + atf_check -o inline:"foo\n" readlink bar +} + atf_init_test_cases() { atf_add_test_case basic atf_add_test_case basic_symlink atf_add_test_case chrdev + atf_add_test_case hardlink + atf_add_test_case hardlink_exists + atf_add_test_case hardlink_exists_force atf_add_test_case matching_srctgt atf_add_test_case matching_srctgt_contained atf_add_test_case matching_srctgt_link @@ -305,10 +378,14 @@ atf_init_test_cases() atf_add_test_case recursive_link_dflt atf_add_test_case recursive_link_Hflag atf_add_test_case recursive_link_Lflag + atf_add_test_case samefile atf_add_test_case sparse_leading_hole atf_add_test_case sparse_multiple_holes atf_add_test_case sparse_only_hole atf_add_test_case sparse_to_dev atf_add_test_case sparse_trailing_hole atf_add_test_case standalone_Pflag + atf_add_test_case symlink + atf_add_test_case symlink_exists + atf_add_test_case symlink_exists_force } diff --git a/bin/cp/utils.c b/bin/cp/utils.c index f43902eab3e6..0bb5157e3f57 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -68,6 +68,11 @@ static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; */ #define BUFSIZE_SMALL (MAXPHYS) +/* + * Prompt used in -i case. + */ +#define YESNO "(y/n [n]) " + static ssize_t copy_fallback(int from_fd, int to_fd) { @@ -125,7 +130,6 @@ copy_file(const FTSENT *entp, int dne) * modified by the umask.) */ if (!dne) { -#define YESNO "(y/n [n]) " if (nflag) { if (vflag) printf("%s not overwritten\n", to.p_path); @@ -145,70 +149,69 @@ copy_file(const FTSENT *entp, int dne) } if (fflag) { - /* - * Remove existing destination file name create a new - * file. - */ + /* remove existing destination file */ (void)unlink(to.p_path); - if (!lflag && !sflag) { - to_fd = open(to.p_path, - O_WRONLY | O_TRUNC | O_CREAT, - fs->st_mode & ~(S_ISUID | S_ISGID)); - } - } else if (!lflag && !sflag) { - /* Overwrite existing destination file name. */ - to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + dne = 1; + } + } + + rval = 0; + + if (lflag) { + if (link(entp->fts_path, to.p_path) != 0) { + warn("%s", to.p_path); + rval = 1; + } + goto done; + } + + if (sflag) { + if (symlink(entp->fts_path, to.p_path) != 0) { + warn("%s", to.p_path); + rval = 1; } - } else if (!lflag && !sflag) { + goto done; + } + + if (!dne) { + /* overwrite existing destination file */ + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + } else { + /* create new destination file */ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); } - - if (!lflag && !sflag && to_fd == -1) { + if (to_fd == -1) { warn("%s", to.p_path); rval = 1; goto done; } - rval = 0; - - if (!lflag && !sflag) { - wtotal = 0; - do { - if (use_copy_file_range) { - wcount = copy_file_range(from_fd, NULL, - to_fd, NULL, SSIZE_MAX, 0); - if (wcount < 0 && errno == EINVAL) { - /* Prob a non-seekable FD */ - use_copy_file_range = 0; - } - } - if (!use_copy_file_range) { - wcount = copy_fallback(from_fd, to_fd); + wtotal = 0; + do { + if (use_copy_file_range) { + wcount = copy_file_range(from_fd, NULL, + to_fd, NULL, SSIZE_MAX, 0); + if (wcount < 0 && errno == EINVAL) { + /* probably a non-seekable descriptor */ + use_copy_file_range = 0; } - wtotal += wcount; - if (info) { - info = 0; - (void)fprintf(stderr, - "%s -> %s %3d%%\n", - entp->fts_path, to.p_path, - cp_pct(wtotal, fs->st_size)); - } - } while (wcount > 0); - if (wcount < 0) { - warn("%s", entp->fts_path); - rval = 1; } - } else if (lflag) { - if (link(entp->fts_path, to.p_path)) { - warn("%s", to.p_path); - rval = 1; + if (!use_copy_file_range) { + wcount = copy_fallback(from_fd, to_fd); } - } else if (sflag) { - if (symlink(entp->fts_path, to.p_path)) { - warn("%s", to.p_path); - rval = 1; + wtotal += wcount; + if (info) { + info = 0; + (void)fprintf(stderr, + "%s -> %s %3d%%\n", + entp->fts_path, to.p_path, + cp_pct(wtotal, fs->st_size)); } + } while (wcount > 0); + if (wcount < 0) { + warn("%s", entp->fts_path); + rval = 1; } /* @@ -217,16 +220,13 @@ copy_file(const FTSENT *entp, int dne) * or its contents might be irreplaceable. It would only be safe * to remove it if we created it and its length is 0. */ - - if (!lflag && !sflag) { - if (pflag && setfile(fs, to_fd)) - rval = 1; - if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) - rval = 1; - if (close(to_fd)) { - warn("%s", to.p_path); - rval = 1; - } + if (pflag && setfile(fs, to_fd)) + rval = 1; + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; + if (close(to_fd)) { + warn("%s", to.p_path); + rval = 1; } done: