diff --git a/bin/cp/cp.c b/bin/cp/cp.c --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -433,6 +433,8 @@ 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 @@ 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 @@ /* 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 --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -747,9 +747,23 @@ 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_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