git: 760720469681 - stable/14 - cp: Clarify an obscure comment.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 24 Apr 2024 22:12:38 UTC
The branch stable/14 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=760720469681a2119b4537a6603337834317383b

commit 760720469681a2119b4537a6603337834317383b
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2024-04-17 01:36:22 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-04-24 22:11:56 +0000

    cp: Clarify an obscure comment.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    allanjude
    Differential Revision:  https://reviews.freebsd.org/D44805
    
    (cherry picked from commit 64d6925d1901637125f9f739282e72c992657dc8)
    
    cp: Additional sanity check.
    
    Once we've successfully opened the file we've been asked to copy, check
    that it's of the same type as FTS told us it was.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D44806
    
    (cherry picked from commit 9075d4cfad5b339aabdf8033623a2164898c2786)
    
    cp: Use warnc().
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    
    (cherry picked from commit f070188c3ad6b87ee9ce220b21718333d1bd9d52)
---
 bin/cp/cp.c    | 13 +++++++++----
 bin/cp/utils.c | 27 ++++++++++++++++++++-------
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index af7d5ffac398..a8c57308ae96 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -316,8 +316,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
 		case FTS_NS:
 		case FTS_DNR:
 		case FTS_ERR:
-			warnx("%s: %s",
-			    curr->fts_path, strerror(curr->fts_errno));
+			warnc(curr->fts_errno, "%s", curr->fts_path);
 			badcp = rval = 1;
 			continue;
 		case FTS_DC:			/* Warn, continue. */
@@ -491,13 +490,19 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
 
 		switch (curr->fts_statp->st_mode & S_IFMT) {
 		case S_IFLNK:
-			/* Catch special case of a non-dangling symlink. */
 			if ((fts_options & FTS_LOGICAL) ||
 			    ((fts_options & FTS_COMFOLLOW) &&
 			    curr->fts_level == 0)) {
+				/*
+				 * We asked FTS to follow links but got
+				 * here anyway, which means the target is
+				 * nonexistent or inaccessible.  Let
+				 * copy_file() deal with the error.
+				 */
 				if (copy_file(curr, dne))
 					badcp = rval = 1;
-			} else {	
+			} else {
+				/* Copy the link. */
 				if (copy_link(curr, !dne))
 					badcp = rval = 1;
 			}
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index 353d35214844..a2cb2f536843 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -106,21 +106,34 @@ copy_fallback(int from_fd, int to_fd)
 int
 copy_file(const FTSENT *entp, int dne)
 {
-	struct stat *fs;
+	struct stat sb, *fs;
 	ssize_t wcount;
 	off_t wtotal;
 	int ch, checkch, from_fd, rval, to_fd;
 	int use_copy_file_range = 1;
 
+	fs = entp->fts_statp;
 	from_fd = to_fd = -1;
-	if (!lflag && !sflag &&
-	    (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
-		warn("%s", entp->fts_path);
-		return (1);
+	if (!lflag && !sflag) {
+		if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) < 0 ||
+		    fstat(from_fd, &sb) != 0) {
+			warn("%s", entp->fts_path);
+			return (1);
+		}
+		/*
+		 * Check that the file hasn't been replaced with one of a
+		 * different type.  This can happen if we've been asked to
+		 * copy something which is actively being modified and
+		 * lost the race, or if we've been asked to copy something
+		 * like /proc/X/fd/Y which stat(2) reports as S_IFREG but
+		 * is actually something else once you open it.
+		 */
+		if ((sb.st_mode & S_IFMT) != (fs->st_mode & S_IFMT)) {
+			warnx("%s: File changed", entp->fts_path);
+			return (1);
+		}
 	}
 
-	fs = entp->fts_statp;
-
 	/*
 	 * If the file exists and we're interactive, verify with the user.
 	 * If the file DNE, set the mode to be the from file, minus setuid