[PATCH] support for cp --parents

Ian Wienand ianw at vmware.com
Fri Sep 25 23:56:37 UTC 2009


Hi,

A little patch to enable --parents in cp, if the new cp long options
config is turned on.

Should you choose it, it seems to add ~150 bytes

function                                             old     new   delta
cp_main                                              273     407    +134
cp_longopts                                            -      11     +11
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 145/0)             Total: 145 bytes
   text	   data	    bss	    dec	    hex	filename
 849561	   4358	   9736	 863655	  d2da7	busybox_old
 849766	   4366	   9728	 863860	  d2e74	busybox_unstripped

Thanks,

-i

diff --git a/coreutils/Config.in b/coreutils/Config.in
index cacfb96..3cfcdeb 100644
--- a/coreutils/Config.in
+++ b/coreutils/Config.in
@@ -78,6 +78,15 @@ config CP
 	help
 	  cp is used to copy files and directories.
 
+config FEATURE_CP_LONG_OPTIONS
+       bool "Enable selected long options for cp"
+       default n
+       depends on CP
+       help
+         Enable selected long options for cp.  Currently
+	 supports:
+		--parents
+
 config CUT
 	bool "cut"
 	default n
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 71a2939..510dc0f 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -20,6 +20,12 @@
 
 /* This is a NOEXEC applet. Be very careful! */
 
+#ifdef CONFIG_FEATURE_CP_LONG_OPTIONS
+static const char cp_longopts[] ALIGN1 =
+  "parents\0" No_argument "\xff";
+
+const char *applet_long_options = cp_longopts;
+#endif
 
 int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int cp_main(int argc, char **argv)
@@ -37,6 +43,10 @@ int cp_main(int argc, char **argv)
 		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),
+#ifdef CONFIG_FEATURE_CP_LONG_OPTIONS
+		OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+4),
+#endif
 	};
 
 	// Need at least two arguments
@@ -62,8 +72,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 +84,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
@@ -108,7 +117,6 @@ int cp_main(int argc, char **argv)
 	 * just ignore it too for fun. TODO.
 	if (flags & OPT_H) ... // deref command-line params only
 	*/
-
 #if ENABLE_SELINUX
 	if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
 		selinux_or_die();
@@ -126,6 +134,14 @@ int cp_main(int argc, char **argv)
 		if (d_flags < 0)
 			return EXIT_FAILURE;
 
+#ifdef CONFIG_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 or...  */
 		if ( !((s_flags | d_flags) & 2) ||
 			/* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */
@@ -138,6 +154,20 @@ int cp_main(int argc, char **argv)
 	}
 
 	while (1) {
+#ifdef CONFIG_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, (mode_t)(-1), FILEUTILS_RECUR)) {
+				exit(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) {
diff --git a/testsuite/cp/cp-parents b/testsuite/cp/cp-parents
new file mode 100644
index 0000000..b25f1e8
--- /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
\ No newline at end of file


More information about the busybox mailing list