aboutsummaryrefslogtreecommitdiff
path: root/coreutils/cp.c
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2003-03-19 09:13:01 +0000
committerManuel Novoa III <mjn3@codepoet.org>2003-03-19 09:13:01 +0000
commitcad5364599eb5062d59e0c397ed638ddd61a8d5d (patch)
treea318d0f03aa076c74b576ea45dc543a5669e8e91 /coreutils/cp.c
parente01f9662a5bd5d91be4f6b3941b57fff73cd5af1 (diff)
downloadbusybox-w32-cad5364599eb5062d59e0c397ed638ddd61a8d5d.tar.gz
busybox-w32-cad5364599eb5062d59e0c397ed638ddd61a8d5d.tar.bz2
busybox-w32-cad5364599eb5062d59e0c397ed638ddd61a8d5d.zip
Major coreutils update.
Diffstat (limited to 'coreutils/cp.c')
-rw-r--r--coreutils/cp.c130
1 files changed, 64 insertions, 66 deletions
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 8f8fe5ed3..c5dd31ec3 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -2,7 +2,6 @@
2/* 2/*
3 * Mini cp implementation for busybox 3 * Mini cp implementation for busybox
4 * 4 *
5 *
6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 5 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -21,6 +20,15 @@
21 * 20 *
22 */ 21 */
23 22
23/* BB_AUDIT SUSv3 defects - unsupported options -H, -L, and -P. */
24/* BB_AUDIT GNU defects - only extension options supported are -a and -d. */
25/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
26
27/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
28 *
29 * Size reduction.
30 */
31
24#include <sys/types.h> 32#include <sys/types.h>
25#include <sys/stat.h> 33#include <sys/stat.h>
26#include <unistd.h> 34#include <unistd.h>
@@ -29,86 +37,76 @@
29#include <errno.h> 37#include <errno.h>
30#include <dirent.h> 38#include <dirent.h>
31#include <stdlib.h> 39#include <stdlib.h>
32 40#include <assert.h>
33#include "busybox.h" 41#include "busybox.h"
42#include "libcoreutils/coreutils.h"
43
44static const char cp_opts[] = "pdRfia"; /* WARNING!! ORDER IS IMPORTANT!! */
34 45
35extern int cp_main(int argc, char **argv) 46extern int cp_main(int argc, char **argv)
36{ 47{
48 struct stat source_stat;
49 struct stat dest_stat;
50 const char *last;
51 const char *dest;
52 int s_flags;
53 int d_flags;
54 int flags;
37 int status = 0; 55 int status = 0;
38 int opt;
39 int flags = FILEUTILS_DEREFERENCE;
40 int i;
41 56
42 while ((opt = getopt(argc, argv, "adfipR")) != -1) 57 /* Since these are enums, #if tests will not work. So use assert()s. */
43 switch (opt) { 58 assert(FILEUTILS_PRESERVE_STATUS == 1);
44 case 'a': 59 assert(FILEUTILS_DEREFERENCE == 2);
45 flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR; 60 assert(FILEUTILS_RECUR == 4);
46 /* fallthrough */ 61 assert(FILEUTILS_FORCE == 8);
47 case 'd': 62 assert(FILEUTILS_INTERACTIVE == 16);
48 flags &= ~FILEUTILS_DEREFERENCE;
49 break;
50 case 'f':
51 flags |= FILEUTILS_FORCE;
52 break;
53 case 'i':
54 flags |= FILEUTILS_INTERACTIVE;
55 break;
56 case 'p':
57 flags |= FILEUTILS_PRESERVE_STATUS;
58 break;
59 case 'R':
60 flags |= FILEUTILS_RECUR;
61 break;
62 default:
63 show_usage();
64 }
65
66 if (optind + 2 > argc)
67 show_usage();
68 63
69 /* If there are only two arguments and... */ 64 flags = bb_getopt_ulflags(argc, argv, cp_opts);
70 if (optind + 2 == argc) {
71 struct stat source_stat;
72 struct stat dest_stat;
73 int source_exists = 1;
74 int dest_exists = 1;
75 65
76 if ((!(flags & FILEUTILS_DEREFERENCE) && 66 if (flags & 32) {
77 lstat(argv[optind], &source_stat) < 0) || 67 flags |= (FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR | FILEUTILS_DEREFERENCE);
78 ((flags & FILEUTILS_DEREFERENCE) && 68 }
79 stat(argv[optind], &source_stat))) { 69
80 if (errno != ENOENT) 70 flags ^= FILEUTILS_DEREFERENCE; /* The sense of this flag was reversed. */
81 perror_msg_and_die("unable to stat `%s'", argv[optind]); 71
82 source_exists = 0; 72 if (optind + 2 > argc) {
83 } 73 bb_show_usage();
74 }
75
76 last = argv[argc - 1];
77 argv += optind;
84 78
85 if (stat(argv[optind + 1], &dest_stat) < 0) { 79 /* If there are only two arguments and... */
86 if (errno != ENOENT) 80 if (optind + 2 == argc) {
87 perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); 81 s_flags = cp_mv_stat2(*argv, &source_stat,
88 dest_exists = 0; 82 (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
83 if ((s_flags < 0) || ((d_flags = cp_mv_stat(last, &dest_stat)) < 0)) {
84 exit(EXIT_FAILURE);
89 } 85 }
90
91 /* ...if neither is a directory or... */ 86 /* ...if neither is a directory or... */
92 if (((!source_exists || !S_ISDIR(source_stat.st_mode)) && 87 if ( !((s_flags | d_flags) & 2) ||
93 (!dest_exists || !S_ISDIR(dest_stat.st_mode))) || 88 /* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */
94 /* ...recursing, the first is a directory, and the 89 /* ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) */
95 * second doesn't exist, then... */ 90 /* Simplify the above since FILEUTILS_RECUR >> 1 == 2. */
96 ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) && 91 ((((flags & FILEUTILS_RECUR) >> 1) & s_flags) && !d_flags)
97 !dest_exists)) { 92 ) {
98 /* ...do a simple copy. */ 93 /* ...do a simple copy. */
99 if (copy_file(argv[optind], argv[optind + 1], flags) < 0) 94 dest = last;
100 status = 1; 95 goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */
101 return status;
102 } 96 }
103 } 97 }
104 98
105 for (i = optind; i < argc - 1; i++) { 99 do {
106 char *dest = concat_path_file(argv[argc - 1], 100 dest = concat_path_file(last, bb_get_last_path_component(*argv));
107 get_last_path_component(argv[i])); 101 DO_COPY:
108 if (copy_file(argv[i], dest, flags) < 0) 102 if (copy_file(*argv, dest, flags) < 0) {
109 status = 1; 103 status = 1;
110 free(dest); 104 }
111 } 105 if (*++argv == last) {
106 break;
107 }
108 free((void *) dest);
109 } while (1);
112 110
113 return status; 111 exit(status);
114} 112}