aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-01-15 22:05:07 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-01-15 22:05:07 +0100
commita40f0624db4c9490d46f116c4c4635dfa68e070c (patch)
tree6495c54fab2be22802c6befc9d5c8ea01807a60c
parent662078f9fd41efe422d7abc0aea1395c27c61ddd (diff)
downloadbusybox-w32-a40f0624db4c9490d46f116c4c4635dfa68e070c.tar.gz
busybox-w32-a40f0624db4c9490d46f116c4c4635dfa68e070c.tar.bz2
busybox-w32-a40f0624db4c9490d46f116c4c4635dfa68e070c.zip
cp: fix -H handling
function old new delta copy_file 1495 1518 +23 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--coreutils/cp.c16
-rw-r--r--coreutils/install.c2
-rw-r--r--include/libbb.h23
-rw-r--r--libbb/copy_file.c4
-rwxr-xr-xtestsuite/cp.tests206
5 files changed, 227 insertions, 24 deletions
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 9f6c12367..d7c8d91cc 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -35,10 +35,9 @@ int cp_main(int argc, char **argv)
35 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1), 35 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
36 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)), 36 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
37 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1), 37 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
38 OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2), 38 OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
39 OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
40#if ENABLE_FEATURE_CP_LONG_OPTIONS 39#if ENABLE_FEATURE_CP_LONG_OPTIONS
41 OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+4), 40 OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
42#endif 41#endif
43 }; 42 };
44 43
@@ -48,7 +47,7 @@ int cp_main(int argc, char **argv)
48 // -r and -R are the same 47 // -r and -R are the same
49 // -R (and therefore -r) turns on -d (coreutils does this) 48 // -R (and therefore -r) turns on -d (coreutils does this)
50 // -a = -pdR 49 // -a = -pdR
51 opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL"; 50 opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR";
52#if ENABLE_FEATURE_CP_LONG_OPTIONS 51#if ENABLE_FEATURE_CP_LONG_OPTIONS
53 applet_long_options = 52 applet_long_options =
54 "archive\0" No_argument "a" 53 "archive\0" No_argument "a"
@@ -64,7 +63,7 @@ int cp_main(int argc, char **argv)
64 ; 63 ;
65#endif 64#endif
66 // -v (--verbose) is ignored 65 // -v (--verbose) is ignored
67 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv"); 66 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPv");
68 /* Options of cp from GNU coreutils 6.10: 67 /* Options of cp from GNU coreutils 6.10:
69 * -a, --archive 68 * -a, --archive
70 * -f, --force 69 * -f, --force
@@ -113,17 +112,14 @@ int cp_main(int argc, char **argv)
113 */ 112 */
114 argc -= optind; 113 argc -= optind;
115 argv += optind; 114 argv += optind;
116 flags ^= FILEUTILS_DEREFERENCE; /* the sense of this flag was reversed */ 115 /* Reverse this bit. If there is -d, bit is not set: */
116 flags ^= FILEUTILS_DEREFERENCE;
117 /* coreutils 6.9 compat: 117 /* coreutils 6.9 compat:
118 * by default, "cp" derefs symlinks (creates regular dest files), 118 * by default, "cp" derefs symlinks (creates regular dest files),
119 * but "cp -R" does not. We switch off deref if -r or -R (see above). 119 * but "cp -R" does not. We switch off deref if -r or -R (see above).
120 * However, "cp -RL" must still deref symlinks: */ 120 * However, "cp -RL" must still deref symlinks: */
121 if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */ 121 if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */
122 flags |= FILEUTILS_DEREFERENCE; 122 flags |= FILEUTILS_DEREFERENCE;
123 /* The behavior of -H is *almost* like -L, but not quite, so let's
124 * just ignore it too for fun. TODO.
125 if (flags & OPT_H) ... // deref command-line params only
126 */
127 123
128#if ENABLE_SELINUX 124#if ENABLE_SELINUX
129 if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) { 125 if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
diff --git a/coreutils/install.c b/coreutils/install.c
index 2e604bec7..e9682990d 100644
--- a/coreutils/install.c
+++ b/coreutils/install.c
@@ -101,7 +101,7 @@ int install_main(int argc, char **argv)
101#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS 101#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
102 applet_long_options = install_longopts; 102 applet_long_options = install_longopts;
103#endif 103#endif
104 opt_complementary = "s--d:d--s" IF_SELINUX(":Z--\xff:\xff--Z"); 104 opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
105 /* -c exists for backwards compatibility, it's needed */ 105 /* -c exists for backwards compatibility, it's needed */
106 /* -v is ignored ("print name of each created directory") */ 106 /* -v is ignored ("print name of each created directory") */
107 /* -b is ignored ("make a backup of each existing destination file") */ 107 /* -b is ignored ("make a backup of each existing destination file") */
diff --git a/include/libbb.h b/include/libbb.h
index 11596346d..9e6ee8434 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -262,20 +262,21 @@ extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC;
262extern const char *bb_mode_string(mode_t mode) FAST_FUNC; 262extern const char *bb_mode_string(mode_t mode) FAST_FUNC;
263extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; 263extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC;
264enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ 264enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */
265 FILEUTILS_PRESERVE_STATUS = 1, 265 FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */
266 FILEUTILS_DEREFERENCE = 2, 266 FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */
267 FILEUTILS_RECUR = 4, 267 FILEUTILS_RECUR = 1 << 2, /* -R */
268 FILEUTILS_FORCE = 8, 268 FILEUTILS_FORCE = 1 << 3, /* -f */
269 FILEUTILS_INTERACTIVE = 0x10, 269 FILEUTILS_INTERACTIVE = 1 << 4, /* -i */
270 FILEUTILS_MAKE_HARDLINK = 0x20, 270 FILEUTILS_MAKE_HARDLINK = 1 << 5, /* -l */
271 FILEUTILS_MAKE_SOFTLINK = 0x40, 271 FILEUTILS_MAKE_SOFTLINK = 1 << 6, /* -s */
272 FILEUTILS_DEREF_SOFTLINK = 0x80, 272 FILEUTILS_DEREF_SOFTLINK = 1 << 7, /* -L */
273 FILEUTILS_DEREFERENCE_L0 = 1 << 8, /* -H */
273#if ENABLE_SELINUX 274#if ENABLE_SELINUX
274 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 0x100, 275 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 9, /* -c */
275 FILEUTILS_SET_SECURITY_CONTEXT = 0x200 276 FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10,
276#endif 277#endif
277}; 278};
278#define FILEUTILS_CP_OPTSTR "pdRfilsL" IF_SELINUX("c") 279#define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c")
279extern int remove_file(const char *path, int flags) FAST_FUNC; 280extern int remove_file(const char *path, int flags) FAST_FUNC;
280/* NB: without FILEUTILS_RECUR in flags, it will basically "cat" 281/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
281 * the source, not copy (unless "source" is a directory). 282 * the source, not copy (unless "source" is a directory).
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 893b52ed5..6c64fab16 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -83,7 +83,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
83 signed char ovr; 83 signed char ovr;
84 84
85/* Inverse of cp -d ("cp without -d") */ 85/* Inverse of cp -d ("cp without -d") */
86#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE) 86#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
87 87
88 if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { 88 if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
89 /* This may be a dangling symlink. 89 /* This may be a dangling symlink.
@@ -194,7 +194,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
194 if (new_source == NULL) 194 if (new_source == NULL)
195 continue; 195 continue;
196 new_dest = concat_path_file(dest, d->d_name); 196 new_dest = concat_path_file(dest, d->d_name);
197 if (copy_file(new_source, new_dest, flags) < 0) 197 if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
198 retval = -1; 198 retval = -1;
199 free(new_source); 199 free(new_source);
200 free(new_dest); 200 free(new_dest);
diff --git a/testsuite/cp.tests b/testsuite/cp.tests
new file mode 100755
index 000000000..75a7dcb48
--- /dev/null
+++ b/testsuite/cp.tests
@@ -0,0 +1,206 @@
1#!/bin/sh
2# Copyright 2010 by Denys Vlasenko
3# Licensed under GPL v2, see file LICENSE for details.
4
5. ./testing.sh
6
7# Opening quote in "omitting directory 'dir'" message:
8sq='`' # GNU cp: `
9sq="'" # bbox cp: '
10
11rm -rf cp.testdir >/dev/null
12
13mkdir cp.testdir
14mkdir cp.testdir/dir
15> cp.testdir/dir/file
16ln -s file cp.testdir/dir/file_symlink
17
18> cp.testdir/file
19ln -s file cp.testdir/file_symlink
20ln -s dir cp.testdir/dir_symlink
21
22
23# testing "test name" "command" "expected result" "file input" "stdin"
24
25rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
26testing "cp" '\
27cd cp.testdir || exit 1; cp * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
28test ! -L cp.testdir2/file || echo BAD: file
29test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
30test ! -e cp.testdir2/dir || echo BAD: dir
31test ! -e cp.testdir2/dir_symlink || echo BAD: dir_symlink
32' "\
33cp: omitting directory ${sq}dir'
34cp: omitting directory ${sq}dir_symlink'
351
36" "" ""
37
38rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
39testing "cp -d" '\
40cd cp.testdir || exit 1; cp -d * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
41test ! -L cp.testdir2/file || echo BAD: file
42test -L cp.testdir2/file_symlink || echo BAD: file_symlink
43test ! -e cp.testdir2/dir || echo BAD: dir
44test -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
45' "\
46cp: omitting directory ${sq}dir'
471
48" "" ""
49
50rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
51testing "cp -P" '\
52cd cp.testdir || exit 1; cp -P * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
53test ! -L cp.testdir2/file || echo BAD: file
54test -L cp.testdir2/file_symlink || echo BAD: file_symlink
55test ! -e cp.testdir2/dir || echo BAD: dir
56test -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
57' "\
58cp: omitting directory ${sq}dir'
591
60" "" ""
61
62rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
63testing "cp -L" '\
64cd cp.testdir || exit 1; cp -L * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
65test ! -L cp.testdir2/file || echo BAD: file
66test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
67test ! -e cp.testdir2/dir || echo BAD: dir
68test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
69' "\
70cp: omitting directory ${sq}dir'
71cp: omitting directory ${sq}dir_symlink'
721
73" "" ""
74
75rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
76testing "cp -H" '\
77cd cp.testdir || exit 1; cp -H * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
78test ! -L cp.testdir2/file || echo BAD: file
79test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
80test ! -e cp.testdir2/dir || echo BAD: dir
81test ! -e cp.testdir2/dir_symlink || echo BAD: dir_symlink
82' "\
83cp: omitting directory ${sq}dir'
84cp: omitting directory ${sq}dir_symlink'
851
86" "" ""
87
88rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
89testing "cp -R" '\
90cd cp.testdir || exit 1; cp -R * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
91test ! -L cp.testdir2/file || echo BAD: file
92test -L cp.testdir2/file_symlink || echo BAD: file_symlink
93test ! -L cp.testdir2/dir || echo BAD: dir
94test -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
95test ! -L cp.testdir2/dir/file || echo BAD: dir/file
96test -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
97' "\
980
99" "" ""
100
101rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
102testing "cp -Rd" '\
103cd cp.testdir || exit 1; cp -Rd * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
104test ! -L cp.testdir2/file || echo BAD: file
105test -L cp.testdir2/file_symlink || echo BAD: file_symlink
106test ! -L cp.testdir2/dir || echo BAD: dir
107test -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
108test ! -L cp.testdir2/dir/file || echo BAD: dir/file
109test -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
110' "\
1110
112" "" ""
113
114rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
115testing "cp -RP" '\
116cd cp.testdir || exit 1; cp -RP * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
117test ! -L cp.testdir2/file || echo BAD: file
118test -L cp.testdir2/file_symlink || echo BAD: file_symlink
119test ! -L cp.testdir2/dir || echo BAD: dir
120test -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
121test ! -L cp.testdir2/dir/file || echo BAD: dir/file
122test -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
123' "\
1240
125" "" ""
126
127rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
128testing "cp -RL" '\
129cd cp.testdir || exit 1; cp -RL * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
130test ! -L cp.testdir2/file || echo BAD: file
131test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
132test ! -L cp.testdir2/dir || echo BAD: dir
133test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
134test ! -L cp.testdir2/dir/file || echo BAD: dir/file
135test ! -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
136' "\
1370
138" "" ""
139
140rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
141# GNU coreutils 7.2 says:
142# cp: will not create hard link `../cp.testdir2/dir_symlink' to directory `../cp.testdir2/dir'
143test x"$SKIP_KNOWN_BUGS" = x"" && \
144testing "cp -RH" '\
145cd cp.testdir || exit 1; cp -RH * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
146test ! -L cp.testdir2/file || echo BAD: file
147test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
148test ! -L cp.testdir2/dir || echo BAD: dir
149test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
150test ! -L cp.testdir2/dir/file || echo BAD: dir/file
151test -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
152' "\
1530
154" "" ""
155
156rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
157# GNU coreutils 7.2 says:
158# cp: will not create hard link `../cp.testdir2/dir_symlink' to directory `../cp.testdir2/dir'
159test x"$SKIP_KNOWN_BUGS" = x"" && \
160testing "cp -RHP" '\
161cd cp.testdir || exit 1; cp -RHP * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
162test ! -L cp.testdir2/file || echo BAD: file
163test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
164test ! -L cp.testdir2/dir || echo BAD: dir
165test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
166test ! -L cp.testdir2/dir/file || echo BAD: dir/file
167test -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
168' "\
1690
170" "" ""
171
172rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
173testing "cp -RHL" '\
174cd cp.testdir || exit 1; cp -RHL * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
175test ! -L cp.testdir2/file || echo BAD: file
176test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
177test ! -L cp.testdir2/dir || echo BAD: dir
178test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
179test ! -L cp.testdir2/dir/file || echo BAD: dir/file
180test ! -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
181' "\
1820
183" "" ""
184
185rm -rf cp.testdir2 >/dev/null && mkdir cp.testdir2 || exit 1
186# Wow! "cp -RLH" is not the same as "cp -RHL" (prev test)!
187# GNU coreutils 7.2 says:
188# cp: will not create hard link `../cp.testdir2/dir_symlink' to directory `../cp.testdir2/dir'
189test x"$SKIP_KNOWN_BUGS" = x"" && \
190testing "cp -RLH" '\
191cd cp.testdir || exit 1; cp -RLH * ../cp.testdir2 2>&1; echo $?; cd .. || exit 1
192test ! -L cp.testdir2/file || echo BAD: file
193test ! -L cp.testdir2/file_symlink || echo BAD: file_symlink
194test ! -L cp.testdir2/dir || echo BAD: dir
195test ! -L cp.testdir2/dir_symlink || echo BAD: dir_symlink
196test ! -L cp.testdir2/dir/file || echo BAD: dir/file
197test ! -L cp.testdir2/dir/file_symlink || echo BAD: dir/file_symlink
198' "\
1990
200" "" ""
201
202
203# Clean up
204rm -rf cp.testdir cp.testdir2 2>/dev/null
205
206exit $FAILCOUNT