[BusyBox] new cp and mv

Matt Kraai kraai at alumni.carnegiemellon.edu
Mon Apr 23 15:40:03 UTC 2001


Howdy,

Attached is a patch which contains my rewrite of cp and mv.  They
are, unfortunately, 25% larger.  If anyone has ideas on how to
shrink them further, I'd love to hear them.  If people could test
this out and let me know what they think is broken, I'd appreciate
that as well.

Matt
-------------- next part --------------
Index: Config.h
===================================================================
RCS file: /var/cvs/busybox/Config.h,v
retrieving revision 1.74
diff -u -r1.74 Config.h
--- Config.h	2001/04/20 17:40:33	1.74
+++ Config.h	2001/04/23 15:38:12
@@ -16,7 +16,7 @@
 #define BB_CHVT
 #define BB_CLEAR
 //#define BB_CMP
-#define BB_CP_MV
+#define BB_CP
 #define BB_CUT
 #define BB_DATE
 //#define BB_DC
@@ -76,6 +76,7 @@
 #define BB_MORE
 #define BB_MOUNT
 //#define BB_MT
+#define BB_MV
 //#define BB_NSLOOKUP
 //#define BB_PING
 //#define BB_PIVOT_ROOT
Index: applets.h
===================================================================
RCS file: /var/cvs/busybox/applets.h,v
retrieving revision 1.27
diff -u -r1.27 applets.h
--- applets.h	2001/04/04 17:31:15	1.27
+++ applets.h	2001/04/23 15:38:12
@@ -80,8 +80,8 @@
 #ifdef BB_CMP
 	APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
 #endif
-#ifdef BB_CP_MV
-	APPLET(cp, cp_mv_main, _BB_DIR_BIN)
+#ifdef BB_CP
+	APPLET(cp, cp_main, _BB_DIR_BIN)
 #endif
 #ifdef BB_CUT
 	APPLET(cut, cut_main, _BB_DIR_USR_BIN)
@@ -269,8 +269,8 @@
 #ifdef BB_MT
 	APPLET(mt, mt_main, _BB_DIR_BIN)
 #endif
-#ifdef BB_CP_MV
-	APPLET(mv, cp_mv_main, _BB_DIR_BIN)
+#ifdef BB_MV
+	APPLET(mv, mv_main, _BB_DIR_BIN)
 #endif
 #ifdef BB_NC
 	APPLET(nc, nc_main, _BB_DIR_USR_BIN)
Index: cp.c
===================================================================
RCS file: cp.c
diff -N cp.c
--- /dev/null	Mon Nov 13 12:19:20 2000
+++ cp.c	Mon Apr 23 09:38:12 2001
@@ -0,0 +1,114 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cp implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai at alumni.carnegiemellon.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+extern int cp_main(int argc, char **argv)
+{
+	int status = 0;
+	int opt;
+	int flags = 0;
+	int i;
+
+	while ((opt = getopt(argc, argv, "adfipR")) != -1)
+		switch (opt) {
+		case 'a':
+			flags |= CP_PRESERVE_STATUS | CP_RECUR;
+			/* fallthrough */
+		case 'd':
+			flags |= CP_PRESERVE_SYMLINKS;
+			break;
+		case 'f':
+			flags |= CP_FORCE;
+			break;
+		case 'i':
+			flags |= CP_INTERACTIVE;
+			break;
+		case 'p':
+			flags |= CP_PRESERVE_STATUS;
+			break;
+		case 'R':
+			flags |= CP_RECUR;
+			break;
+		default:
+			show_usage();
+		}
+	
+	if (optind + 2 > argc)
+		show_usage();
+
+	/* If there are only two arguments and...  */
+	if (optind + 2 == argc) {
+		struct stat source_stat;
+		struct stat dest_stat;
+		int source_exists = 1;
+		int dest_exists = 1;
+
+		if (((flags & CP_PRESERVE_SYMLINKS) &&
+				lstat(argv[optind], &source_stat) < 0) ||
+				(!(flags & CP_PRESERVE_SYMLINKS) &&
+				 stat(argv[optind], &source_stat))) {
+			if (errno != ENOENT)
+				perror_msg_and_die("unable to stat `%s'", argv[optind]);
+			source_exists = 0;
+		}
+
+		if (stat(argv[optind + 1], &dest_stat) < 0) {
+			if (errno != ENOENT)
+				perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
+			dest_exists = 0;
+		}
+		
+		/* ...if neither is a directory or...  */
+		if (((!source_exists || !S_ISDIR(source_stat.st_mode)) &&
+				(!dest_exists || !S_ISDIR(dest_stat.st_mode))) ||
+				/* ...recursing, the first is a directory, and the
+				 * second doesn't exist, then... */
+				((flags & CP_RECUR) && S_ISDIR(source_stat.st_mode) &&
+				 !dest_exists)) {
+			/* ...do a simple copy.  */
+			if (copy_file(argv[optind], argv[optind + 1], flags) < 0)
+				status = 1;
+			return status;
+		}
+	}
+
+	for (i = optind; i < argc - 1; i++) {
+		char *dest = concat_path_file(argv[argc - 1],
+				get_last_path_component(argv[i]));
+		if (copy_file(argv[i], dest, flags) < 0)
+			status = 1;
+		free(dest);
+	}
+
+	return status;
+}
Index: mv.c
===================================================================
RCS file: mv.c
diff -N mv.c
--- /dev/null	Mon Nov 13 12:19:20 2000
+++ mv.c	Mon Apr 23 09:38:12 2001
@@ -0,0 +1,168 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mv implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai at alumni.carnegiemellon.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+static int flags = CP_RECUR | CP_PRESERVE_STATUS | CP_PRESERVE_SYMLINKS;
+
+static int remove_file(const char *path, struct stat *statbuf, void *junk)
+{
+	if (unlink(path) < 0)
+		return FALSE;
+	return TRUE;
+}
+
+static int remove_directory(const char *path, struct stat *statbuf, void *junk)
+{
+	if (rmdir(path) < 0)
+		return FALSE;
+	return TRUE;
+}
+
+static int move_file(const char *source, const char *dest)
+{
+	struct stat source_stat;
+	struct stat dest_stat;
+	int source_exists = 1;
+	int dest_exists = 1;
+
+	if (stat(dest, &dest_stat) < 0) {
+		if (errno != ENOENT) {
+			perror_msg("unable to stat `%s'", dest);
+			return -1;
+		}
+		dest_exists = 0;
+	}
+
+	if (dest_exists && !(flags & CP_FORCE) &&
+			((access(dest, W_OK) < 0 && isatty(0)) ||
+			 (flags & CP_INTERACTIVE))) {
+		fprintf(stderr, "mv: overwrite `%s'? ", dest);
+		if (!ask_confirmation())
+			return 0;
+	}
+
+	if (rename(source, dest) == 0) {
+		return 0;
+	}
+
+	if (errno != EXDEV) {
+		perror_msg("%s", source);
+		return -1;
+	}
+
+	if (stat(source, &source_stat) < 0) {
+		if (errno != ENOENT) {
+			perror_msg("unable to stat `%s'", source);
+			return -1;
+		}
+		source_exists = 0;
+	}
+
+	if (dest_exists) {
+		if (S_ISDIR(dest_stat.st_mode) &&
+			  (!source_exists || !S_ISDIR(source_stat.st_mode))) {
+			error_msg("cannot overwrite directory with non-directory");
+			return -1;
+		}
+
+		if (!S_ISDIR(dest_stat.st_mode) && source_exists &&
+				S_ISDIR(source_stat.st_mode)) {
+			error_msg("cannot overwrite non-directory with directory");
+			return -1;
+		}
+
+		if (unlink(dest) < 0) {
+			perror_msg("cannot remove `%s'", dest);
+			return -1;
+		}
+	}
+
+	if (copy_file(source, dest,
+				CP_RECUR | CP_PRESERVE_STATUS | CP_PRESERVE_SYMLINKS) < 0)
+		return -1;
+
+	if (!recursive_action(source, TRUE, FALSE, TRUE, remove_file,
+				remove_directory, NULL))
+		return -1;
+
+	return 0;
+}
+
+extern int mv_main(int argc, char **argv)
+{
+	int status = 0;
+	int opt;
+	int i;
+
+	while ((opt = getopt(argc, argv, "fi")) != -1)
+		switch (opt) {
+		case 'f':
+			flags &= ~CP_INTERACTIVE;
+			flags |= CP_FORCE;
+			break;
+		case 'i':
+			flags &= ~CP_FORCE;
+			flags |= CP_INTERACTIVE;
+			break;
+		default:
+			show_usage();
+		}
+
+	if (optind + 2 > argc)
+		show_usage();
+
+	if (optind + 2 == argc) {
+		struct stat dest_stat;
+		int dest_exists = 1;
+
+		if (stat(argv[optind + 1], &dest_stat) < 0) {
+			if (errno != ENOENT)
+				perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
+			dest_exists = 0;
+		}
+
+		if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) {
+			if (move_file(argv[optind], argv[optind + 1]) < 0)
+				status = 1;
+			return status;
+		}
+	}
+
+	for (i = optind; i < argc - 1; i++) {
+		char *dest = concat_path_file(argv[argc - 1],
+				get_last_path_component(argv[i]));
+		if (move_file(argv[i], dest) < 0)
+			status = 1;
+		free(dest);
+	}
+
+	return status;
+}
Index: libbb/copy_file.c
===================================================================
RCS file: /var/cvs/busybox/libbb/copy_file.c,v
retrieving revision 1.3
diff -u -r1.3 copy_file.c
--- libbb/copy_file.c	2001/04/20 05:16:38	1.3
+++ libbb/copy_file.c	2001/04/23 15:38:12
@@ -1,11 +1,10 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Utility routines.
+ * Mini copy_file implementation for busybox
  *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
  *
+ * Copyright (C) 2000 by Matt Kraai <kraai at alumni.carnegiemellon.edu>
+ *
  * 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
  * the Free Software Foundation; either version 2 of the License, or
@@ -20,179 +19,226 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
  */
 
-#include <stdio.h>
-#include <errno.h>
-#include <utime.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <sys/stat.h>
-#include "libbb.h"
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
 
+#include "libbb.h"
 
-/*
- * Copy one file to another, while possibly preserving its modes, times, and
- * modes.  Returns TRUE if successful, or FALSE on a failure with an error
- * message output.  (Failure is not indicated if attributes cannot be set.)
- * -Erik Andersen
- */
-int
-copy_file(const char *src_name, const char *dst_name,
-		 int set_modes, int follow_links, int force_flag, int quiet_flag)
+int copy_file(const char *source, const char *dest, int flags)
 {
-	FILE *src_file = NULL;
-	FILE *dst_file = NULL;
-	struct stat srcStatBuf;
-	struct stat dstStatBuf;
-	struct utimbuf times;
-	int src_status;
-	int dst_status;
-
-	if (follow_links == TRUE) {
-		src_status = stat(src_name, &srcStatBuf);
-		dst_status = stat(dst_name, &dstStatBuf);
-	} else {
-		src_status = lstat(src_name, &srcStatBuf);
-		dst_status = lstat(dst_name, &dstStatBuf);
+	struct stat source_stat;
+	struct stat dest_stat;
+	int dest_exists = 1;
+	int status = 0;
+
+	if (((flags & CP_PRESERVE_SYMLINKS) && lstat(source, &source_stat) < 0) ||
+			(!(flags & CP_PRESERVE_SYMLINKS) &&
+			 stat(source, &source_stat) < 0)) {
+		perror_msg("%s", source);
+		return -1;
 	}
 
-	if (src_status < 0) {
-		if (!quiet_flag) {
-			perror_msg("%s", src_name);
+	if (stat(dest, &dest_stat) < 0) {
+		if (errno != ENOENT) {
+			perror_msg("unable to stat `%s'", dest);
+			return -1;
 		}
-		return FALSE;
+		dest_exists = 0;
 	}
 
-	if ((dst_status < 0) || force_flag) {
-		unlink(dst_name);
-		dstStatBuf.st_ino = -1;
-		dstStatBuf.st_dev = -1;
+	if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev &&
+			source_stat.st_ino == dest_stat.st_ino) {
+		error_msg("`%s' and `%s' are the same file", source, dest);
+		return -1;
 	}
+
+	if (S_ISDIR(source_stat.st_mode)) {
+		DIR *dp;
+		struct dirent *d;
 
-	if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
-		(srcStatBuf.st_ino == dstStatBuf.st_ino)) {
-		if (!quiet_flag) {
-			error_msg("Copying file \"%s\" to itself", src_name);
+		if (!(flags & CP_RECUR)) {
+			error_msg("%s: omitting directory", source);
+			return -1;
 		}
-		return FALSE;
-	}
 
-	if (S_ISDIR(srcStatBuf.st_mode)) {
-		//fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
-		/* Make sure the directory is writable */
-		dst_status = create_path(dst_name, 0777777 ^ umask(0));
-		if ((dst_status < 0) && (errno != EEXIST)) {
-			if (!quiet_flag) {
-				perror_msg("%s", dst_name);
+		/* Create DEST.  */
+		if (dest_exists) {
+			if (!S_ISDIR(dest_stat.st_mode)) {
+				error_msg("`%s' is not a directory", dest);
+				return -1;
 			}
-			return FALSE;
-		}
-	} else if (S_ISLNK(srcStatBuf.st_mode)) {
-		char link_val[BUFSIZ + 1];
-		int link_size;
-
-		//fprintf(stderr, "copying link %s to %s\n", srcName, destName);
-		/* Warning: This could possibly truncate silently, to BUFSIZ chars */
-		link_size = readlink(src_name, &link_val[0], BUFSIZ);
-		if (link_size < 0) {
-			if (quiet_flag) {
-				perror_msg("%s", src_name);
+		} else {
+			mode_t mode, saved_umask;
+			saved_umask = umask(0);
+
+			mode = source_stat.st_mode;
+			if (!(flags & CP_PRESERVE_STATUS))
+				mode = source_stat.st_mode & ~saved_umask;
+			mode |= S_IRWXU;
+
+			if (mkdir(dest, mode) < 0) {
+				umask(saved_umask);
+				perror_msg("cannot create directory `%s'", dest);
+				return -1;
 			}
-			return FALSE;
+
+			umask(saved_umask);
 		}
-		link_val[link_size] = '\0';
-		src_status = symlink(link_val, dst_name);
-		if (src_status < 0) {
-			if (!quiet_flag) {
-				perror_msg("%s", dst_name);
-			}
-			return FALSE;
+		
+		/* Recursively copy files in SOURCE.  */
+		if ((dp = opendir(source)) == NULL) {
+			perror_msg("unable to open directory `%s'", source);
+			status = -1;
+			goto end;
 		}
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-		if (set_modes == TRUE) {
-			/* Try to set owner, but fail silently like GNU cp */
-			lchown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid);
+
+		while ((d = readdir(dp)) != NULL) {
+			char *new_source, *new_dest;
+
+			if (strcmp(d->d_name, ".") == 0 ||
+					strcmp(d->d_name, "..") == 0)
+				continue;
+
+			new_source = concat_path_file(source, d->d_name);
+			new_dest = concat_path_file(dest, d->d_name);
+			if (copy_file(new_source, new_dest, flags) < 0)
+				status = -1;
+			free(new_source);
+			free(new_dest);
 		}
-#endif
-		return TRUE;
-	} else if (S_ISFIFO(srcStatBuf.st_mode)) {
-		//fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
-		if (mkfifo(dst_name, 0644) < 0) {
-			if (!quiet_flag) {
-				perror_msg("%s", dst_name);
-			}
-			return FALSE;
+		
+		/* ??? What if an error occurs in readdir?  */
+
+		if (closedir(dp) < 0) {
+			perror_msg("unable to close directory `%s'", source);
+			status = -1;
 		}
-	} else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
-			   || S_ISSOCK(srcStatBuf.st_mode)) {
-		//fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
-		if (mknod(dst_name, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
-			if (!quiet_flag) {
-				perror_msg("%s", dst_name);
+	} else if (S_ISREG(source_stat.st_mode)) {
+		FILE *sfp, *dfp;
+
+		if (dest_exists) {
+			if (flags & CP_INTERACTIVE) {
+				fprintf(stderr, "cp: overwrite `%s'? ", dest);
+				if (!ask_confirmation())
+					return 0;
 			}
-			return FALSE;
-		}
-	} else if (S_ISREG(srcStatBuf.st_mode)) {
-		//fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
-		src_file = fopen(src_name, "r");
-		if (src_file == NULL) {
-			if (!quiet_flag) {
-				perror_msg("%s", src_name);
+
+			if ((dfp = fopen(dest, "w")) == NULL) {
+				if (!(flags & CP_FORCE)) {
+					perror_msg("unable to open `%s'", dest);
+					return -1;
+				}
+
+				if (unlink(dest) < 0) {
+					perror_msg("unable to remove `%s'", dest);
+					return -1;
+				}
+
+				dest_exists = 0;
 			}
-			return FALSE;
 		}
+
+		if (!dest_exists) {
+			int fd;
 
-	 	dst_file = fopen(dst_name, "w");
-		chmod(dst_name, srcStatBuf.st_mode);
-		if (dst_file == NULL) {
-			if (!quiet_flag) {
-				perror_msg("%s", dst_name);
+			if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
+					(dfp = fdopen(fd, "w")) == NULL) {
+				if (fd >= 0)
+					close(fd);
+				perror_msg("unable to open `%s'", dest);
+				return -1;
 			}
-			fclose(src_file);
-			return FALSE;
 		}
 
-		if (copy_file_chunk(src_file, dst_file, srcStatBuf.st_size)==FALSE) {
-			goto error_exit;
+		if ((sfp = fopen(source, "r")) == NULL) {
+			fclose(dfp);
+			perror_msg("unable to open `%s'", source);
+			status = -1;
+			goto end;
 		}
+
+		copy_file_chunk(sfp, dfp, source_stat.st_size);
 
-		fclose(src_file);
-		if (fclose(dst_file) < 0) {
-			return FALSE;
+		if (fclose(dfp) < 0) {
+			perror_msg("unable to close `%s'", dest);
+			status = -1;
 		}
-	}
+
+		if (fclose(sfp) < 0) {
+			perror_msg("unable to close `%s'", source);
+			status = -1;
+		}
+	} else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+			S_ISSOCK(source_stat.st_mode)) {
+		if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+			perror_msg("unable to create `%s'", dest);
+			return -1;
+		}
+	} else if (S_ISFIFO(source_stat.st_mode)) {
+		mode_t mode, saved_umask;
+		saved_umask = umask(0);
+
+		mode = source_stat.st_mode;
+		if (!(flags & CP_PRESERVE_STATUS))
+			mode = source_stat.st_mode & ~saved_umask;
+		mode |= S_IRWXU;
+
+		if (mkfifo(dest, mode) < 0) {
+			umask(saved_umask);
+			perror_msg("cannot create fifo `%s'", dest);
+			return -1;
+		}
+
+		umask(saved_umask);
+	} else if (S_ISLNK(source_stat.st_mode)) {
+		char buf[BUFSIZ + 1];
+
+		if (readlink(source, buf, BUFSIZ) < 0) {
+			perror_msg("cannot read `%s'", source);
+			return -1;
+		}
+		buf[BUFSIZ] = '\0';
 
-	if (set_modes == TRUE) {
-		/* This is fine, since symlinks never get here */
-		if (chown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0)
-			perror_msg("%s", dst_name);
-		if (chmod(dst_name, srcStatBuf.st_mode) < 0)
-			perror_msg("%s", dst_name);
-		times.actime = srcStatBuf.st_atime;
-		times.modtime = srcStatBuf.st_mtime;
-		if (utime(dst_name, &times) < 0)
-			perror_msg("%s", dst_name);
+		if (symlink(buf, dest) < 0) {
+			perror_msg("cannot create symlink `%s'", dest);
+			return -1;
+		}
+
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+		if (flags & CP_PRESERVE_STATUS)
+			if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+				perror_msg("unable to preserve ownership of `%s'", dest);
+#endif
+		return 0;
+	} else {
+		error_msg("internal error: unrecognized file type");
+		return -1;
 	}
 
-	return TRUE;
+end:
 
-error_exit:
-	perror_msg("%s", dst_name);
-	fclose(src_file);
-	fclose(dst_file);
+	if (flags & CP_PRESERVE_STATUS) {
+		struct utimbuf times;
 
-	return FALSE;
-}
+		times.actime = source_stat.st_atime;
+		times.modtime = source_stat.st_mtime;
+		if (utime(dest, &times) < 0)
+			perror_msg("unable to preserve times of `%s'", dest);
+		if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+			source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+			perror_msg("unable to preserve ownership of `%s'", dest);
+		}
+		if (chmod(dest, source_stat.st_mode) < 0)
+			perror_msg("unable to preserve permissions of `%s'", dest);
+	}
 
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+	return 0;
+}
Index: libbb/libbb.h
===================================================================
RCS file: /var/cvs/busybox/libbb/libbb.h,v
retrieving revision 1.20
diff -u -r1.20 libbb.h
--- libbb/libbb.h	2001/04/18 20:17:05	1.20
+++ libbb/libbb.h	2001/04/23 15:38:12
@@ -93,8 +93,7 @@
 void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name);
 void reset_ino_dev_hashtable(void);
 
-int copy_file(const char *src_name, const char *dst_name,
-		 int set_modes, int follow_links, int force_flag, int quiet_flag);
+int copy_file(const char *source, const char *dest, int flags);
 int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
 char *buildName(const char *dirName, const char *fileName);
 int makeString(int argc, const char **argv, char *buf, int bufLen);
@@ -254,5 +253,13 @@
 #define CT_UNIX2DOS	1
 #define CT_DOS2UNIX	2
 /* extern int convert(char *fn, int ConvType); */
+
+enum {
+	CP_PRESERVE_STATUS = 1,
+	CP_PRESERVE_SYMLINKS = 2,
+	CP_RECUR = 4,
+	CP_FORCE = 8,
+	CP_INTERACTIVE = 16
+};
 
 #endif /* __LIBBB_H__ */


More information about the busybox mailing list