1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
diff -urNp coreutils-7.1-orig/src/copy.c coreutils-7.1/src/copy.c
--- coreutils-7.1-orig/src/copy.c 2009-02-27 12:07:29.000000000 +0100
+++ coreutils-7.1/src/copy.c 2009-02-27 12:14:29.000000000 +0100
@@ -104,6 +104,7 @@ static bool copy_internal (char const *s
struct dir_list *ancestors,
const struct cp_options *x,
bool command_line_arg,
+ bool *first_dir_created_per_command_line_arg,
bool *copy_into_self,
bool *rename_succeeded);
static bool owner_failure_ok (struct cp_options const *x);
@@ -201,13 +202,16 @@ copy_attr_by_name (char const *src_path,
DST_NAME_IN is a directory that was created previously in the
recursion. SRC_SB and ANCESTORS describe SRC_NAME_IN.
Set *COPY_INTO_SELF if SRC_NAME_IN is a parent of
+ FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG FIXME
(or the same as) DST_NAME_IN; otherwise, clear it.
Return true if successful. */
static bool
copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst,
const struct stat *src_sb, struct dir_list *ancestors,
- const struct cp_options *x, bool *copy_into_self)
+ const struct cp_options *x,
+ bool *first_dir_created_per_command_line_arg,
+ bool *copy_into_self)
{
char *name_space;
char *namep;
@@ -237,12 +241,20 @@ copy_dir (char const *src_name_in, char
ok &= copy_internal (src_name, dst_name, new_dst, src_sb->st_dev,
ancestors, &non_command_line_options, false,
+ first_dir_created_per_command_line_arg,
&local_copy_into_self, NULL);
*copy_into_self |= local_copy_into_self;
free (dst_name);
free (src_name);
+ /* If we're copying into self, there's no point in continuing,
+ and in fact, that would even infloop, now that we record only
+ the first created directory per command line argument. */
+ if (local_copy_into_self)
+ break;
+
+
namep += strlen (namep) + 1;
}
free (name_space);
@@ -1125,6 +1137,7 @@ restore_default_fscreatecon_or_die (void
not known. ANCESTORS points to a linked, null terminated list of
devices and inodes of parent directories of SRC_NAME. COMMAND_LINE_ARG
is true iff SRC_NAME was specified on the command line.
+ FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG is both input and output.
Set *COPY_INTO_SELF if SRC_NAME is a parent of (or the
same as) DST_NAME; otherwise, clear it.
Return true if successful. */
@@ -1135,6 +1148,7 @@ copy_internal (char const *src_name, cha
struct dir_list *ancestors,
const struct cp_options *x,
bool command_line_arg,
+ bool *first_dir_created_per_command_line_arg,
bool *copy_into_self,
bool *rename_succeeded)
{
@@ -1815,11 +1829,15 @@ copy_internal (char const *src_name, cha
}
}
- /* Insert the created directory's inode and device
- numbers into the search structure, so that we can
- avoid copying it again. */
- if (!x->hard_link)
- remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev);
+ /* Record the created directory's inode and device numbers into
+ the search structure, so that we can avoid copying it again.
+ Do this only for the first directory that is created for each
+ source command line argument. */
+ if (!*first_dir_created_per_command_line_arg)
+ {
+ remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev);
+ *first_dir_created_per_command_line_arg = true;
+ }
if (x->verbose)
emit_verbose (src_name, dst_name, NULL);
@@ -1840,6 +1858,7 @@ copy_internal (char const *src_name, cha
in a source directory would cause the containing destination
directory not to have owner/perms set properly. */
delayed_ok = copy_dir (src_name, dst_name, new_dst, &src_sb, dir, x,
+ first_dir_created_per_command_line_arg,
copy_into_self);
}
}
@@ -2187,8 +2206,11 @@ copy (char const *src_name, char const *
top_level_src_name = src_name;
top_level_dst_name = dst_name;
+ bool first_dir_created_per_command_line_arg = false;
return copy_internal (src_name, dst_name, nonexistent_dst, 0, NULL,
- options, true, copy_into_self, rename_succeeded);
+ options, true,
+ &first_dir_created_per_command_line_arg,
+ copy_into_self, rename_succeeded);
}
/* Set *X to the default options for a value of type struct cp_options. */
diff -urNp coreutils-7.1-orig/tests/cp/into-self coreutils-7.1/tests/cp/into-self
--- coreutils-7.1-orig/tests/cp/into-self 2008-09-18 09:06:57.000000000 +0200
+++ coreutils-7.1/tests/cp/into-self 2009-02-27 12:16:21.000000000 +0100
@@ -1,7 +1,7 @@
#!/bin/sh
# Confirm that copying a directory into itself gets a proper diagnostic.
-# Copyright (C) 2001, 2002, 2004, 2006-2008 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2004, 2006-2009 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -28,15 +28,32 @@ fi
. $srcdir/test-lib.sh
-mkdir dir || framework_failure
+mkdir a dir || framework_failure
fail=0
# This command should exit nonzero.
cp -R dir dir 2> out && fail=1
+echo 1 >> out
+
+# This should, too. However, with coreutils-7.1 it would infloop.
+cp -rl dir dir 2>> out && fail=1
+echo 2 >> out
+
+cp -rl a dir dir 2>> out && fail=1
+echo 3 >> out
+cp -rl a dir dir 2>> out && fail=1
+echo 4 >> out
cat > exp <<\EOF
cp: cannot copy a directory, `dir', into itself, `dir/dir'
+1
+cp: cannot copy a directory, `dir', into itself, `dir/dir'
+2
+cp: cannot copy a directory, `dir', into itself, `dir/dir'
+3
+cp: cannot copy a directory, `dir', into itself, `dir/dir'
+4
EOF
#'
|