The branch main has been updated by des:

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

commit fe836c50120daed3e4084f43c27d8d650d36dee8
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2025-11-22 12:11:59 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2025-11-22 12:11:59 +0000

    cp: Fix copying the root directory
    
    When the source of the copy operation is the root directory, we should
    neither append it to the destination path on FTS_D nor trim it back off
    on FTS_DP.
    
    PR:             291132
    MFC after:      3 days
    Fixes:          82fc0d09e862 ("cp: Partly restore symlink folllowing.")
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D53863
---
 bin/cp/cp.c             |  7 ++++++-
 bin/cp/tests/cp_test.sh | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 38fe65399d06..7ac1e5f6a4c4 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -433,6 +433,8 @@ copy(char *argv[], enum op type, int fts_options, struct 
stat *root_stat)
                                sep = strchr(to.base, '\0');
                                sep[0] = '/';
                                sep[1] = '\0';
+                       } else if (strcmp(curr->fts_name, "/") == 0) {
+                               /* special case when source is the root 
directory */
                        } else {
                                /* entering a directory; append its name to 
to.path */
                                len = snprintf(to.end, END(to.path) - to.end, 
"%s%s",
@@ -520,6 +522,8 @@ copy(char *argv[], enum op type, int fts_options, struct 
stat *root_stat)
                                if (type == DIR_TO_DNE &&
                                    curr->fts_level == FTS_ROOTLEVEL) {
                                        /* this is actually our created root */
+                               } else if (strcmp(curr->fts_name, "/") == 0) {
+                                       /* special case when source is the root 
directory */
                                } else {
                                        while (to.end > to.path && *to.end != 
'/')
                                                to.end--;
@@ -551,7 +555,8 @@ copy(char *argv[], enum op type, int fts_options, struct 
stat *root_stat)
                /* Not an error but need to remember it happened. */
                if (to.path[0] == '\0') {
                        /*
-                        * This can happen in two cases:
+                        * This can happen in three cases:
+                        * - The source path is the root directory.
                         * - DIR_TO_DNE; we created the directory and
                         *   populated root_stat earlier.
                         * - FILE_TO_DIR if a source has a trailing slash;
diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh
index b637f862b7d3..af309ca7ea80 100755
--- a/bin/cp/tests/cp_test.sh
+++ b/bin/cp/tests/cp_test.sh
@@ -747,9 +747,23 @@ dstmode_body()
        atf_check cmp dir/file dst/file
 }
 
+atf_test_case root
+root_head()
+{
+       atf_set "descr" "Test copying the root directory"
+}
+root_body()
+{
+       atf_check mkdir dst
+       atf_check -s exit:1 \
+           -e inline:"cp: / is a directory (not copied).\n" \
+           cp / dst
+}
+
 atf_test_case to_root cleanup
 to_root_head()
 {
+       atf_set "descr" "Test copying to the root directory"
        atf_set "require.user" "unprivileged"
 }
 to_root_body()
@@ -893,6 +907,7 @@ atf_init_test_cases()
        atf_add_test_case to_deaddirlink
        atf_add_test_case to_link_outside
        atf_add_test_case dstmode
+       atf_add_test_case root
        atf_add_test_case to_root
        atf_add_test_case dirloop
        atf_add_test_case unrdir

Reply via email to