Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142783974
D34063.id102003.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D34063.id102003.diff
View Options
Index: bin/cp/cp.c
===================================================================
--- bin/cp/cp.c
+++ bin/cp/cp.c
@@ -87,7 +87,7 @@
PATH_T to = { to.p_path, emptystring, "" };
int fflag, iflag, lflag, nflag, pflag, sflag, vflag;
-static int Rflag, rflag;
+static int Hflag, Lflag, Rflag, rflag;
volatile sig_atomic_t info;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -100,11 +100,10 @@
{
struct stat to_stat, tmp_stat;
enum op type;
- int Hflag, Lflag, ch, fts_options, r, have_trailing_slash;
+ int ch, fts_options, r, have_trailing_slash;
char *target;
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
- Hflag = Lflag = 0;
while ((ch = getopt(argc, argv, "HLPRafilnprsvx")) != -1)
switch (ch) {
case 'H':
@@ -271,6 +270,22 @@
&to_stat)));
}
+/* Does the right thing based on -R + -H/-L/-P */
+static int
+copy_stat(const char *path, struct stat *sb)
+{
+
+ /*
+ * For -R -H/-P, we need to lstat() instead; copy() cares about the link
+ * itself rather than the target if we're not following links during the
+ * traversal.
+ */
+ if (!Rflag || Lflag)
+ return (stat(path, sb));
+ return (lstat(path, sb));
+}
+
+
static int
copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
{
@@ -443,7 +458,7 @@
}
/* Not an error but need to remember it happened. */
- if (stat(to.p_path, &to_stat) == -1)
+ if (copy_stat(to.p_path, &to_stat) == -1)
dne = 1;
else {
if (to_stat.st_dev == curr->fts_statp->st_dev &&
Index: bin/cp/tests/cp_test.sh
===================================================================
--- bin/cp/tests/cp_test.sh
+++ bin/cp/tests/cp_test.sh
@@ -43,6 +43,21 @@
check_size baz 4
}
+atf_test_case basic_symlink
+basic_symlink_body()
+{
+ echo "foo" > bar
+ ln -s bar baz
+
+ atf_check cp baz foo
+ atf_check test '!' -L foo
+
+ atf_check -e inline:"cp: baz and baz are identical (not copied).\n" \
+ -s exit:1 cp baz baz
+ atf_check -e inline:"cp: bar and baz are identical (not copied).\n" \
+ -s exit:1 cp baz bar
+}
+
atf_test_case chrdev
chrdev_body()
{
@@ -130,12 +145,61 @@
atf_check -e not-empty -s not-exit:0 stat foo/dne/foo
}
+recursive_link_setup()
+{
+ extra_cpflag=$1
+
+ mkdir -p foo/bar
+ ln -s bar foo/baz
+
+ mkdir foo-mirror
+ eval "cp -R $extra_cpflag foo foo-mirror"
+}
+
+atf_test_case recursive_link_dflt
+recursive_link_dflt_body()
+{
+ recursive_link_setup
+
+ # -P is the default, so this should work and preserve the link.
+ atf_check cp -R foo foo-mirror
+ atf_check test -L foo-mirror/foo/baz
+}
+
+atf_test_case recursive_link_Hflag
+recursive_link_Hflag_body()
+{
+ recursive_link_setup
+
+ # -H will not follow either, so this should also work and preserve the
+ # link.
+ atf_check cp -RH foo foo-mirror
+ atf_check test -L foo-mirror/foo/baz
+}
+
+atf_test_case recursive_link_Lflag
+recursive_link_Lflag_body()
+{
+ recursive_link_setup -L
+
+ # -L will work, but foo/baz ends up expanded to a directory.
+ atf_check test -d foo-mirror/foo/baz -a \
+ '(' ! -L foo-mirror/foo/baz ')'
+ atf_check cp -RL foo foo-mirror
+ atf_check test -d foo-mirror/foo/baz -a \
+ '(' ! -L foo-mirror/foo/baz ')'
+}
+
atf_init_test_cases()
{
atf_add_test_case basic
+ atf_add_test_case basic_symlink
atf_add_test_case chrdev
atf_add_test_case matching_srctgt
atf_add_test_case matching_srctgt_contained
atf_add_test_case matching_srctgt_link
atf_add_test_case matching_srctgt_nonexistent
+ atf_add_test_case recursive_link_dflt
+ atf_add_test_case recursive_link_Hflag
+ atf_add_test_case recursive_link_Lflag
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 24, 2:15 PM (6 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27897615
Default Alt Text
D34063.id102003.diff (3 KB)
Attached To
Mode
D34063: cp: fix -R with links
Attached
Detach File
Event Timeline
Log In to Comment