[git commit master] cp: add support for --parents and long option synonyms of short opts

Denys Vlasenko vda.linux at googlemail.com
Sat Sep 26 12:31:04 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=48f116198d53697d59d03f4e0ff6cd8c04e79660
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

By Ian Wienand (ianw AT vmware.com)

function                                             old     new   delta
cp_main                                              257     369    +112
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 112/0)             Total: 112 bytes
   text    data     bss     dec     hex filename
 823000     458    6948  830406   cabc6 busybox_old
 823283     458    6948  830689   cace1 busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/Config.in     |   10 ++++++-
 coreutils/cp.c          |   66 +++++++++++++++++++++++++++++++++++++----------
 testsuite/cp/cp-parents |    5 +++
 3 files changed, 66 insertions(+), 15 deletions(-)
 create mode 100644 testsuite/cp/cp-parents

diff --git a/coreutils/Config.in b/coreutils/Config.in
index cacfb96..64a9421 100644
--- a/coreutils/Config.in
+++ b/coreutils/Config.in
@@ -78,6 +78,14 @@ config CP
 	help
 	  cp is used to copy files and directories.
 
+config FEATURE_CP_LONG_OPTIONS
+	bool "Enable long options for cp"
+	default n
+	depends on CP
+	help
+	  Enable long options for cp.
+	  Also add support for --parents option.
+
 config CUT
 	bool "cut"
 	default n
@@ -113,7 +121,7 @@ config FEATURE_DD_SIGNAL_HANDLING
 	default y
 	depends on DD
 	help
-	  sending a SIGUSR1 signal to a running `dd' process makes it
+	  Sending a SIGUSR1 signal to a running `dd' process makes it
 	  print to standard error the number of records read and written
 	  so far, then to resume copying.
 
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 71a2939..2c0b90b 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -20,7 +20,6 @@
 
 /* This is a NOEXEC applet. Be very careful! */
 
-
 int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int cp_main(int argc, char **argv)
 {
@@ -31,12 +30,16 @@ int cp_main(int argc, char **argv)
 	int s_flags;
 	int d_flags;
 	int flags;
-	int status = 0;
+	int status;
 	enum {
 		OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
 		OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
 		OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
 		OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
+		OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+		OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+4),
+#endif
 	};
 
 	// Need at least two arguments
@@ -46,6 +49,20 @@ int cp_main(int argc, char **argv)
 	// -R (and therefore -r) turns on -d (coreutils does this)
 	// -a = -pdR
 	opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL";
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+	applet_long_options =
+		"archive\0"        No_argument "a"
+		"force\0"          No_argument "f"
+		"interactive\0"    No_argument "i"
+		"link\0"           No_argument "l"
+		"dereference\0"    No_argument "L"
+		"no-dereference\0" No_argument "P"
+		"recursive\0"      No_argument "R"
+		"symbolic-link\0"  No_argument "s"
+		"verbose\0"        No_argument "v"
+		"parents\0"        No_argument "\xff"
+		;
+#endif
 	// -v (--verbose) is ignored
 	flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv");
 	/* Options of cp from GNU coreutils 6.10:
@@ -62,8 +79,9 @@ int cp_main(int argc, char **argv)
 	 * -d	same as --no-dereference --preserve=links
 	 * -p	same as --preserve=mode,ownership,timestamps
 	 * -c	same as --preserve=context
+	 * --parents
+	 *	use full source file name under DIRECTORY
 	 * NOT SUPPORTED IN BBOX:
-	 * long options are not supported (even those above).
 	 * --backup[=CONTROL]
 	 *	make a backup of each existing destination file
 	 * -b	like --backup but does not accept an argument
@@ -73,8 +91,6 @@ int cp_main(int argc, char **argv)
 	 *	preserve attributes (default: mode,ownership,timestamps),
 	 *	if possible additional attributes: security context,links,all
 	 * --no-preserve=ATTR_LIST
-	 * --parents
-	 *	use full source file name under DIRECTORY
 	 * --remove-destination
 	 *	remove  each existing destination file before attempting to open
 	 * --sparse=WHEN
@@ -115,39 +131,61 @@ int cp_main(int argc, char **argv)
 	}
 #endif
 
+	status = EXIT_SUCCESS;
 	last = argv[argc - 1];
 	/* If there are only two arguments and...  */
 	if (argc == 2) {
 		s_flags = cp_mv_stat2(*argv, &source_stat,
-				      (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
+				(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
 		if (s_flags < 0)
 			return EXIT_FAILURE;
 		d_flags = cp_mv_stat(last, &dest_stat);
 		if (d_flags < 0)
 			return EXIT_FAILURE;
 
-		/* ...if neither is a directory or...  */
-		if ( !((s_flags | d_flags) & 2) ||
-			/* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */
-			((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+		if (flags & OPT_parents) {
+			if (!(d_flags & 2)) {
+				bb_error_msg_and_die("with --parents, the destination must be a directory");
+			}
+		}
+#endif
+
+		/* ...if neither is a directory...  */
+		if (!((s_flags | d_flags) & 2)
+		    /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */
+		 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
 		) {
-			/* ...do a simple copy.  */
+			/* Do a simple copy */
 			dest = last;
 			goto DO_COPY; /* NB: argc==2 -> *++argv==last */
 		}
 	}
 
 	while (1) {
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+		if (flags & OPT_parents) {
+			char *dest_dup;
+			char *dest_dir;
+			dest = concat_path_file(last, *argv);
+			dest_dup = xstrdup(dest);
+			dest_dir = dirname(dest_dup);
+			if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) {
+				return EXIT_FAILURE;
+			}
+			free(dest_dup);
+			goto DO_COPY;
+		}
+#endif
 		dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
  DO_COPY:
 		if (copy_file(*argv, dest, flags) < 0) {
-			status = 1;
+			status = EXIT_FAILURE;
 		}
+		free((void*)dest);
 		if (*++argv == last) {
-			/* possibly leaking dest... */
 			break;
 		}
-		free((void*)dest);
 	}
 
 	/* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */
diff --git a/testsuite/cp/cp-parents b/testsuite/cp/cp-parents
new file mode 100644
index 0000000..a721cea
--- /dev/null
+++ b/testsuite/cp/cp-parents
@@ -0,0 +1,5 @@
+mkdir -p foo/bar/baz
+touch foo/bar/baz/file
+mkdir dir
+busybox cp --parents foo/bar/baz/file dir
+test -f dir/foo/bar/baz/file
-- 
1.6.3.3



More information about the busybox-cvs mailing list