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 dd286b0dc1)

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 aaa1806f68)
This commit is contained in:
Dag-Erling Smørgrav 2024-04-01 19:28:58 +02:00
parent 928ea8066d
commit 2ad8333c65
2 changed files with 23 additions and 12 deletions

View file

@ -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 ,

View file

@ -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