git: 39d543db53a4 - stable/13 - cp: Improved conformance when copying directories.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Mon, 08 Apr 2024 10:11:41 UTC
The branch stable/13 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=39d543db53a456d97e3dec12b22ac191360b8866

commit 39d543db53a456d97e3dec12b22ac191360b8866
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2024-04-01 17:28:58 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-04-08 10:10:14 +0000

    cp: Improved conformance when copying directories.
    
    * When copying a directory, if the destination exists and is not a
      directory, we would previously emit an error message and exit.  The
      correct behavior according to POSIX is to emit an error message and
      continue without descending further into the source directory.
    
    * When copying a directory, if the destination does not exist and we
      fail to create it, we would previously emit an error message and
      exit.  The correct behavior according to POSIX is to emit an error
      message and continue.  Whether to descend further into the source
      directory is explicitly left unspecified; GNU cp does not, which
      seems to me to be the safer and less surprising option, so let's not
      either.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D44577
    
    (cherry picked from commit dd286b0dc187c351a9537a363840245d5505b15b)
    
    cp: Correct the list of non-portable flags.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D44576
    
    (cherry picked from commit aaa1806f68ef3102a9b888a03360f166b88618c8)
---
 bin/cp/cp.1 |  8 +++++---
 bin/cp/cp.c | 27 ++++++++++++++++++---------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/bin/cp/cp.1 b/bin/cp/cp.1
index d8d62ef076a1..90b1a158a131 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 14, 2023
+.Dd March 28, 2024
 .Dt CP 1
 .Os
 .Sh NAME
@@ -311,12 +311,14 @@ differ as they copy special files as normal
 files while recreating a hierarchy.
 .Pp
 The
+.Fl a ,
 .Fl l ,
+.Fl N ,
+.Fl n ,
 .Fl s ,
 .Fl v ,
-.Fl x
 and
-.Fl n
+.Fl x
 options are non-standard and their use in scripts is not recommended.
 .Sh SEE ALSO
 .Xr mv 1 ,
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 852868e65dcb..af7d5ffac398 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -519,9 +519,13 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
 			 * umask blocks owner writes, we fail.
 			 */
 			if (dne) {
-				if (mkdir(to.p_path,
-				    curr->fts_statp->st_mode | S_IRWXU) < 0)
-					err(1, "%s", to.p_path);
+				mode = curr->fts_statp->st_mode | S_IRWXU;
+				if (mkdir(to.p_path, mode) != 0) {
+					warn("%s", to.p_path);
+					(void)fts_set(ftsp, curr, FTS_SKIP);
+					badcp = rval = 1;
+					break;
+				}
 				/*
 				 * First DNE with a NULL root_stat is the root
 				 * path, so set root_stat.  We can't really
@@ -530,14 +534,19 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
 				 * first directory we created and use that.
 				 */
 				if (root_stat == NULL &&
-				    stat(to.p_path, &created_root_stat) == -1) {
-					err(1, "stat");
-				} else if (root_stat == NULL) {
-					root_stat = &created_root_stat;
+				    stat(to.p_path, &created_root_stat) != 0) {
+					warn("%s", to.p_path);
+					(void)fts_set(ftsp, curr, FTS_SKIP);
+					badcp = rval = 1;
+					break;
 				}
+				if (root_stat == NULL)
+					root_stat = &created_root_stat;
 			} else if (!S_ISDIR(to_stat.st_mode)) {
-				errno = ENOTDIR;
-				err(1, "%s", to.p_path);
+				warnc(ENOTDIR, "%s", to.p_path);
+				(void)fts_set(ftsp, curr, FTS_SKIP);
+				badcp = rval = 1;
+				break;
 			}
 			/*
 			 * Arrange to correct directory attributes later