From nobody Wed Jan 17 18:28:36 2024 X-Original-To: dev-commits-src-all@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 4TFZBr3xwcz56P2G; Wed, 17 Jan 2024 18:28:36 +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 4TFZBr2Rxcz4cP7; Wed, 17 Jan 2024 18:28:36 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705516116; 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=IFVtzZxdamw8efRd5pKNjt/7CTLIre0MaemqGKcsKMU=; b=iIHsKoWfDEvMhVT5ZuQeUG85BnPnjkSASUAtgqsLm7Fv9URRTDZc+SEp5HTQqMdJCaufX1 azgsu+MFX7gqmrxXty4OtaSyvC3unBDYwFqNnsvb09cy5aX9lSivYlsUiwh4qCOfOlM6UE RAigSUKeHK8NuiIWYqAqUz4k1DZUVR98tmcDSl4tyEgDrJPfeF0JmuthjRt4OERT2mNlrz O2FTL29Lw3auKHGEciTDVvf45njLTVWZXDULMSNdLyu9Nu+ovlOxJ9gQgizCwQQUM8rSll RR8yIQhEYrvRjzwLTbU5kHb2lmUzpxxV2XEjhZ1vLjUs1W1YbmgrugH5/Bdm7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705516116; 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=IFVtzZxdamw8efRd5pKNjt/7CTLIre0MaemqGKcsKMU=; b=DKljFGr5YiJxaHIC4QzIaijeoB413rz9nSsPP/AQH5PoQJUsoTKrUUK208DaxFfeC0pSzl bBNqd87ZmuXmClJjKBDzokjjGftPHUJf9DM12t7Zym4lLkl6qZvIVcxKeAAtnYxl07I/oz 4VE91Cz3+LyYPnUZUxKw299viZEAto86ST6rViueaGjroMer84eS4KKXQn0D7a0fVZNvzA sfPd3628Sc/nXawga9hFqvTs7Y/JHW4VMUviT46wdbVcLIfi+IqL+4h6CrSTQ12g/cOMIQ uvnzu3HpnqcmZ5PqTTt+wq/O7o2OvvZ4Uy/7D+ZcgIHltDd0ZXlG9xsSPgWqkw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1705516116; a=rsa-sha256; cv=none; b=spHZgB4A/f5liIsW0kZVSPSkh9g3/tYyhyDzsBwAwROIU0RrftRFo7RWDR2b4CHRBwQDfW DE4tFi9XHQ3YrsAc6xZvjLV9o0Ri/LqZy00SzyvGi7tWG4z5Genr674o16ndNB4kSCPqHz IHlxdzgi0tCF5fOODj2MC7T1RtB4P/yVFUxq3QmzkXEzezzWU+MQmqi84hetn9dJGbmY7a 5xoUaau1JH1+f+0wFSzHJ9Ii9KCKdRxwT0K36Vi5E7uzTnuDJtRnILIVLjpl9aMq/DSO+x hD3A6MpU/8yoaqigzDePcvL5VT0lziVWy3RiDW6GjwkzeFGFIzCxTess0kgBIg== 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 4TFZBr1FV8zZnC; Wed, 17 Jan 2024 18:28:36 +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 40HISaut063534; Wed, 17 Jan 2024 18:28:36 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 40HISa8b063531; Wed, 17 Jan 2024 18:28:36 GMT (envelope-from git) Date: Wed, 17 Jan 2024 18:28:36 GMT Message-Id: <202401171828.40HISa8b063531@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: 006017419bea - stable/13 - cp: Add tests for hard link case. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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/13 X-Git-Reftype: branch X-Git-Commit: 006017419beab30f45131ca3953c7e4273e9aa65 Auto-Submitted: auto-generated The branch stable/13 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=006017419beab30f45131ca3953c7e4273e9aa65 commit 006017419beab30f45131ca3953c7e4273e9aa65 Author: Dag-Erling Smørgrav AuthorDate: 2023-12-13 21:31:05 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2024-01-17 16:15:59 +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: