Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153422505
D51096.id157762.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D51096.id157762.diff
View Options
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -270,10 +270,9 @@
FTS *ftsp;
FTSENT *curr;
char *recpath = NULL, *sep;
- int atflags, dne, badcp, len, rval;
+ int atflags, dne, badcp, len, level, rval;
mode_t mask, mode;
bool beneath = Rflag && type != FILE_TO_FILE;
- bool skipdp = false;
/*
* Keep an inverted copy of the umask, for use in correcting
@@ -305,6 +304,7 @@
to.dir = -1;
}
+ level = FTS_ROOTLEVEL;
if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
err(1, "fts_open");
for (badcp = rval = 0;
@@ -315,6 +315,20 @@
case FTS_NS:
case FTS_DNR:
case FTS_ERR:
+ if (level > curr->fts_level) {
+ /* leaving a directory; remove its name from to.path */
+ if (type == DIR_TO_DNE &&
+ curr->fts_level == FTS_ROOTLEVEL) {
+ /* this is actually our created root */
+ } else {
+ while (to.end > to.path && *to.end != '/')
+ to.end--;
+ assert(strcmp(to.end + (*to.end == '/'),
+ curr->fts_name) == 0);
+ *to.end = '\0';
+ }
+ level--;
+ }
warnc(curr->fts_errno, "%s", curr->fts_path);
badcp = rval = 1;
continue;
@@ -335,14 +349,6 @@
strlcpy(rootname, curr->fts_name,
sizeof(rootname));
}
- /*
- * If we FTS_SKIP while handling FTS_D, we will
- * immediately get FTS_DP for the same directory.
- * If this happens before we've appended the name
- * to to.path, we need to remember not to perform
- * the reverse operation.
- */
- skipdp = true;
/* we must have a destination! */
if (type == DIR_TO_DNE &&
curr->fts_level == FTS_ROOTLEVEL) {
@@ -410,7 +416,7 @@
}
to.end += len;
}
- skipdp = false;
+ level++;
/*
* We're on the verge of recursing on ourselves.
* Either we need to stop right here (we knowingly
@@ -477,18 +483,19 @@
rval = 1;
}
}
- /* are we leaving a directory we failed to enter? */
- if (skipdp)
- continue;
- /* leaving a directory; remove its name from to.path */
- if (type == DIR_TO_DNE &&
- curr->fts_level == FTS_ROOTLEVEL) {
- /* this is actually our created root */
- } else {
- while (to.end > to.path && *to.end != '/')
- to.end--;
- assert(strcmp(to.end + (*to.end == '/'), curr->fts_name) == 0);
- *to.end = '\0';
+ if (level > curr->fts_level) {
+ /* leaving a directory; remove its name from to.path */
+ if (type == DIR_TO_DNE &&
+ curr->fts_level == FTS_ROOTLEVEL) {
+ /* this is actually our created root */
+ } else {
+ while (to.end > to.path && *to.end != '/')
+ to.end--;
+ assert(strcmp(to.end + (*to.end == '/'),
+ curr->fts_name) == 0);
+ *to.end = '\0';
+ }
+ level--;
}
continue;
default:
@@ -638,6 +645,7 @@
if (vflag && !badcp)
(void)printf("%s -> %s%s\n", curr->fts_path, to.base, to.path);
}
+ assert(level == FTS_ROOTLEVEL);
if (errno)
err(1, "fts_read");
(void)fts_close(ftsp);
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
@@ -618,6 +618,54 @@
(dst=$(cat dst) && rm "/$dst") 2>/dev/null || true
}
+atf_test_case dirloop
+dirloop_body()
+{
+ mkdir -p src/a src/b
+ ln -s ../b src/a
+ ln -s ../a src/b
+ atf_check \
+ -s exit:1 \
+ -e match:"src/a/b/a: directory causes a cycle" \
+ -e match:"src/b/a/b: directory causes a cycle" \
+ cp -r src dst
+ atf_check test -d dst
+ atf_check test -d dst/a
+ atf_check test -d dst/b
+ atf_check test -d dst/a/b
+ atf_check -s exit:1 test -d dst/a/b/a
+ atf_check test -d dst/b/a
+ atf_check -s exit:1 test -d dst/b/a/b
+}
+
+atf_test_case unrdir
+unrdir_body()
+{
+ mkdir -p src/foo
+ echo "bar" >src/bar
+ chmod 0 src/foo
+ atf_check \
+ -s not-exit:0 \
+ -e match:"^cp: src/foo: Permission denied" \
+ cp -R src dst
+ atf_check test -d dst/foo
+ atf_check -o inline:"bar\n" cat dst/bar
+}
+
+atf_test_case unrfile
+unrfile_body()
+{
+ mkdir -p src/foo
+ echo "bar" >src/bar
+ chmod 0 src/bar
+ atf_check \
+ -s not-exit:0 \
+ -e match:"^cp: src/bar: Permission denied" \
+ cp -R src dst
+ atf_check test -d dst/foo
+ atf_check -s not-exit:0 -e ignore cat dst/bar
+}
+
atf_init_test_cases()
{
atf_add_test_case basic
@@ -656,4 +704,7 @@
atf_add_test_case to_link_outside
atf_add_test_case dstmode
atf_add_test_case to_root
+ atf_add_test_case dirloop
+ atf_add_test_case unrdir
+ atf_add_test_case unrfile
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 22, 2:15 AM (6 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31946700
Default Alt Text
D51096.id157762.diff (4 KB)
Attached To
Mode
D51096: cp: Don't rely on FTS_DP to keep track of depth.
Attached
Detach File
Event Timeline
Log In to Comment