Skip to content

cp: name both paths when a directory cannot overwrite a non-directory - #15170

Merged
RenjiSann merged 3 commits into
uutils:mainfrom
NdekoCode:cp-overwrite-non-directory
Oct 10, 2026
Merged

RenjiSann merged 3 commits into
uutils:mainfrom
NdekoCode:cp-overwrite-non-directory

Conversation

@NdekoCode

Copy link
Copy Markdown
Contributor

cannot overwrite non-directory with directory named neither path, where GNU says cannot overwrite non-directory 'dst' with directory 'src'. A subdirectory whose destination already existed as a regular file was not caught at all: cp went on into it and failed on the first file inside with cannot create regular file 'd/sub/x': Not a directory, then stopped. A dangling symlink given as the target of cp -r was followed, and its target created as a directory.

The message now names the destination and the directory. A target that is not a directory (a file, or a symlink that does not lead to one) is refused before the tree is walked. A subdirectory that would land on a file or a symlink is reported, its subtree is left alone, and the copy goes on with the next entry, as GNU does; the exit status is 1. The target_is_file field of Entry and Context only served the first case and is gone.

Checked against GNU 9.12 for cp -r src dst, cp -rT src dst, cp -r src/. d, a subdirectory landing on a file, on a symlink to a directory, and a dangling symlink target. The cp test suite passes on macOS and Linux.

Closes #15000.

Comment thread src/uu/cp/src/copydir.rs Outdated
"cannot overwrite non-directory with directory" named neither path. A
subdirectory whose destination already existed as a regular file was
not caught at all: cp went on into it and failed later on the first
file inside, with "cannot create regular file 'd/sub/x': Not a
directory", and stopped there. A dangling symlink as the target of
`cp -r` was followed, and its target created as a directory.

Say which destination and which directory, as GNU does. Refuse a
target that is not a directory before walking the tree, and for a
subdirectory that would land on a file or a symlink, report it, leave
the subtree alone and go on with the next entry, as GNU does.
Go through print_verbose_output like the file lines do, so that a
closed or full stdout gives "write error" instead of a panic in
println!.
The walk joins paths with a backslash on Windows.
@NdekoCode
NdekoCode force-pushed the cp-overwrite-non-directory branch from 8abc8d7 to 0901725 Compare October 9, 2026 21:47
@NdekoCode

Copy link
Copy Markdown
Contributor Author

Rebased on main (the --parents closure in copydir.rs), moved the directory -v line to print_verbose_output, and the new test builds the expected paths with path_concat! so it passes on Windows too.

@NdekoCode
NdekoCode requested a review from RenjiSann October 9, 2026 21:51
@RenjiSann
RenjiSann merged commit 391d025 into uutils:main Oct 10, 2026
100 of 102 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cp: "cannot overwrite non-directory" errors differ from GNU

2 participants