1*9e94795aSAndroid Build Coastguard Worker /*
2*9e94795aSAndroid Build Coastguard Worker * Copyright 2005 The Android Open Source Project
3*9e94795aSAndroid Build Coastguard Worker *
4*9e94795aSAndroid Build Coastguard Worker * Android "cp" replacement.
5*9e94795aSAndroid Build Coastguard Worker *
6*9e94795aSAndroid Build Coastguard Worker * The GNU/Linux "cp" uses O_LARGEFILE in its open() calls, utimes() instead
7*9e94795aSAndroid Build Coastguard Worker * of utime(), and getxattr()/setxattr() instead of chmod(). These are
8*9e94795aSAndroid Build Coastguard Worker * probably "better", but are non-portable, and not necessary for our
9*9e94795aSAndroid Build Coastguard Worker * purposes.
10*9e94795aSAndroid Build Coastguard Worker */
11*9e94795aSAndroid Build Coastguard Worker #include <stdlib.h>
12*9e94795aSAndroid Build Coastguard Worker #include <stdio.h>
13*9e94795aSAndroid Build Coastguard Worker #include <string.h>
14*9e94795aSAndroid Build Coastguard Worker #include <unistd.h>
15*9e94795aSAndroid Build Coastguard Worker #include <sys/types.h>
16*9e94795aSAndroid Build Coastguard Worker #include <sys/stat.h>
17*9e94795aSAndroid Build Coastguard Worker #include <getopt.h>
18*9e94795aSAndroid Build Coastguard Worker #include <dirent.h>
19*9e94795aSAndroid Build Coastguard Worker #include <fcntl.h>
20*9e94795aSAndroid Build Coastguard Worker #include <utime.h>
21*9e94795aSAndroid Build Coastguard Worker #include <limits.h>
22*9e94795aSAndroid Build Coastguard Worker #include <errno.h>
23*9e94795aSAndroid Build Coastguard Worker #include <assert.h>
24*9e94795aSAndroid Build Coastguard Worker #include <host/CopyFile.h>
25*9e94795aSAndroid Build Coastguard Worker
26*9e94795aSAndroid Build Coastguard Worker /*#define DEBUG_MSGS*/
27*9e94795aSAndroid Build Coastguard Worker #ifdef DEBUG_MSGS
28*9e94795aSAndroid Build Coastguard Worker # define DBUG(x) printf x
29*9e94795aSAndroid Build Coastguard Worker #else
30*9e94795aSAndroid Build Coastguard Worker # define DBUG(x) ((void)0)
31*9e94795aSAndroid Build Coastguard Worker #endif
32*9e94795aSAndroid Build Coastguard Worker
33*9e94795aSAndroid Build Coastguard Worker #define FSSEP '/' /* filename separator char */
34*9e94795aSAndroid Build Coastguard Worker
35*9e94795aSAndroid Build Coastguard Worker
36*9e94795aSAndroid Build Coastguard Worker /*
37*9e94795aSAndroid Build Coastguard Worker * Process the command-line file arguments.
38*9e94795aSAndroid Build Coastguard Worker *
39*9e94795aSAndroid Build Coastguard Worker * Returns 0 on success.
40*9e94795aSAndroid Build Coastguard Worker */
process(int argc,char * const argv[],unsigned int options)41*9e94795aSAndroid Build Coastguard Worker int process(int argc, char* const argv[], unsigned int options)
42*9e94795aSAndroid Build Coastguard Worker {
43*9e94795aSAndroid Build Coastguard Worker int retVal = 0;
44*9e94795aSAndroid Build Coastguard Worker int i;
45*9e94795aSAndroid Build Coastguard Worker char* stripDest = NULL;
46*9e94795aSAndroid Build Coastguard Worker int stripDestLen;
47*9e94795aSAndroid Build Coastguard Worker bool destMustBeDir = false;
48*9e94795aSAndroid Build Coastguard Worker struct stat sb;
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Worker assert(argc >= 2);
51*9e94795aSAndroid Build Coastguard Worker
52*9e94795aSAndroid Build Coastguard Worker /*
53*9e94795aSAndroid Build Coastguard Worker * Check for and trim a trailing slash on the last arg.
54*9e94795aSAndroid Build Coastguard Worker *
55*9e94795aSAndroid Build Coastguard Worker * It's useful to be able to say "cp foo bar/" when you want to copy
56*9e94795aSAndroid Build Coastguard Worker * a single file into a directory. If you say "cp foo bar", and "bar"
57*9e94795aSAndroid Build Coastguard Worker * does not exist, it will create "bar", when what you really wanted
58*9e94795aSAndroid Build Coastguard Worker * was for the cp command to fail with "directory does not exist".
59*9e94795aSAndroid Build Coastguard Worker */
60*9e94795aSAndroid Build Coastguard Worker stripDestLen = strlen(argv[argc-1]);
61*9e94795aSAndroid Build Coastguard Worker stripDest = malloc(stripDestLen+1);
62*9e94795aSAndroid Build Coastguard Worker memcpy(stripDest, argv[argc-1], stripDestLen+1);
63*9e94795aSAndroid Build Coastguard Worker if (stripDest[stripDestLen-1] == FSSEP) {
64*9e94795aSAndroid Build Coastguard Worker stripDest[--stripDestLen] = '\0';
65*9e94795aSAndroid Build Coastguard Worker destMustBeDir = true;
66*9e94795aSAndroid Build Coastguard Worker }
67*9e94795aSAndroid Build Coastguard Worker
68*9e94795aSAndroid Build Coastguard Worker if (argc > 2)
69*9e94795aSAndroid Build Coastguard Worker destMustBeDir = true;
70*9e94795aSAndroid Build Coastguard Worker
71*9e94795aSAndroid Build Coastguard Worker /*
72*9e94795aSAndroid Build Coastguard Worker * Start with a quick check to ensure that, if we're expecting to copy
73*9e94795aSAndroid Build Coastguard Worker * to a directory, the target already exists and is actually a directory.
74*9e94795aSAndroid Build Coastguard Worker * It's okay if it's a symlink to a directory.
75*9e94795aSAndroid Build Coastguard Worker *
76*9e94795aSAndroid Build Coastguard Worker * If it turns out to be a directory, go ahead and raise the
77*9e94795aSAndroid Build Coastguard Worker * destMustBeDir flag so we do some path concatenation below.
78*9e94795aSAndroid Build Coastguard Worker */
79*9e94795aSAndroid Build Coastguard Worker if (stat(stripDest, &sb) < 0) {
80*9e94795aSAndroid Build Coastguard Worker if (destMustBeDir) {
81*9e94795aSAndroid Build Coastguard Worker if (errno == ENOENT)
82*9e94795aSAndroid Build Coastguard Worker fprintf(stderr,
83*9e94795aSAndroid Build Coastguard Worker "acp: destination directory '%s' does not exist\n",
84*9e94795aSAndroid Build Coastguard Worker stripDest);
85*9e94795aSAndroid Build Coastguard Worker else
86*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "acp: unable to stat dest dir\n");
87*9e94795aSAndroid Build Coastguard Worker retVal = 1;
88*9e94795aSAndroid Build Coastguard Worker goto bail;
89*9e94795aSAndroid Build Coastguard Worker }
90*9e94795aSAndroid Build Coastguard Worker } else {
91*9e94795aSAndroid Build Coastguard Worker if (S_ISDIR(sb.st_mode)) {
92*9e94795aSAndroid Build Coastguard Worker DBUG(("--- dest exists and is a dir, setting flag\n"));
93*9e94795aSAndroid Build Coastguard Worker destMustBeDir = true;
94*9e94795aSAndroid Build Coastguard Worker } else if (destMustBeDir) {
95*9e94795aSAndroid Build Coastguard Worker fprintf(stderr,
96*9e94795aSAndroid Build Coastguard Worker "acp: destination '%s' is not a directory\n",
97*9e94795aSAndroid Build Coastguard Worker stripDest);
98*9e94795aSAndroid Build Coastguard Worker retVal = 1;
99*9e94795aSAndroid Build Coastguard Worker goto bail;
100*9e94795aSAndroid Build Coastguard Worker }
101*9e94795aSAndroid Build Coastguard Worker }
102*9e94795aSAndroid Build Coastguard Worker
103*9e94795aSAndroid Build Coastguard Worker /*
104*9e94795aSAndroid Build Coastguard Worker * Copying files.
105*9e94795aSAndroid Build Coastguard Worker *
106*9e94795aSAndroid Build Coastguard Worker * Strip trailing slashes off. They shouldn't be there, but
107*9e94795aSAndroid Build Coastguard Worker * sometimes file completion will put them in for directories.
108*9e94795aSAndroid Build Coastguard Worker *
109*9e94795aSAndroid Build Coastguard Worker * The observed behavior of GNU and BSD cp is that they print warnings
110*9e94795aSAndroid Build Coastguard Worker * if something fails, but continue on. If any part fails, the command
111*9e94795aSAndroid Build Coastguard Worker * exits with an error status.
112*9e94795aSAndroid Build Coastguard Worker */
113*9e94795aSAndroid Build Coastguard Worker for (i = 0; i < argc-1; i++) {
114*9e94795aSAndroid Build Coastguard Worker const char* srcName;
115*9e94795aSAndroid Build Coastguard Worker char* src;
116*9e94795aSAndroid Build Coastguard Worker char* dst;
117*9e94795aSAndroid Build Coastguard Worker int copyResult;
118*9e94795aSAndroid Build Coastguard Worker int srcLen;
119*9e94795aSAndroid Build Coastguard Worker
120*9e94795aSAndroid Build Coastguard Worker /* make a copy of the source name, and strip trailing '/' */
121*9e94795aSAndroid Build Coastguard Worker srcLen = strlen(argv[i]);
122*9e94795aSAndroid Build Coastguard Worker src = malloc(srcLen+1);
123*9e94795aSAndroid Build Coastguard Worker memcpy(src, argv[i], srcLen+1);
124*9e94795aSAndroid Build Coastguard Worker
125*9e94795aSAndroid Build Coastguard Worker if (src[srcLen-1] == FSSEP)
126*9e94795aSAndroid Build Coastguard Worker src[--srcLen] = '\0';
127*9e94795aSAndroid Build Coastguard Worker
128*9e94795aSAndroid Build Coastguard Worker /* find just the name part */
129*9e94795aSAndroid Build Coastguard Worker srcName = strrchr(src, FSSEP);
130*9e94795aSAndroid Build Coastguard Worker if (srcName == NULL) {
131*9e94795aSAndroid Build Coastguard Worker srcName = src;
132*9e94795aSAndroid Build Coastguard Worker } else {
133*9e94795aSAndroid Build Coastguard Worker srcName++;
134*9e94795aSAndroid Build Coastguard Worker assert(*srcName != '\0');
135*9e94795aSAndroid Build Coastguard Worker }
136*9e94795aSAndroid Build Coastguard Worker
137*9e94795aSAndroid Build Coastguard Worker if (destMustBeDir) {
138*9e94795aSAndroid Build Coastguard Worker /* concatenate dest dir and src name */
139*9e94795aSAndroid Build Coastguard Worker int srcNameLen = strlen(srcName);
140*9e94795aSAndroid Build Coastguard Worker
141*9e94795aSAndroid Build Coastguard Worker dst = malloc(stripDestLen +1 + srcNameLen +1);
142*9e94795aSAndroid Build Coastguard Worker memcpy(dst, stripDest, stripDestLen);
143*9e94795aSAndroid Build Coastguard Worker dst[stripDestLen] = FSSEP;
144*9e94795aSAndroid Build Coastguard Worker memcpy(dst + stripDestLen+1, srcName, srcNameLen+1);
145*9e94795aSAndroid Build Coastguard Worker } else {
146*9e94795aSAndroid Build Coastguard Worker /* simple */
147*9e94795aSAndroid Build Coastguard Worker dst = stripDest;
148*9e94795aSAndroid Build Coastguard Worker }
149*9e94795aSAndroid Build Coastguard Worker
150*9e94795aSAndroid Build Coastguard Worker /*
151*9e94795aSAndroid Build Coastguard Worker * Copy the source to the destination.
152*9e94795aSAndroid Build Coastguard Worker */
153*9e94795aSAndroid Build Coastguard Worker copyResult = copyFile(src, dst, options);
154*9e94795aSAndroid Build Coastguard Worker
155*9e94795aSAndroid Build Coastguard Worker if (copyResult != 0)
156*9e94795aSAndroid Build Coastguard Worker retVal = 1;
157*9e94795aSAndroid Build Coastguard Worker
158*9e94795aSAndroid Build Coastguard Worker free(src);
159*9e94795aSAndroid Build Coastguard Worker if (dst != stripDest)
160*9e94795aSAndroid Build Coastguard Worker free(dst);
161*9e94795aSAndroid Build Coastguard Worker }
162*9e94795aSAndroid Build Coastguard Worker
163*9e94795aSAndroid Build Coastguard Worker bail:
164*9e94795aSAndroid Build Coastguard Worker free(stripDest);
165*9e94795aSAndroid Build Coastguard Worker return retVal;
166*9e94795aSAndroid Build Coastguard Worker }
167*9e94795aSAndroid Build Coastguard Worker
168*9e94795aSAndroid Build Coastguard Worker /*
169*9e94795aSAndroid Build Coastguard Worker * Set up the options.
170*9e94795aSAndroid Build Coastguard Worker */
main(int argc,char * const argv[])171*9e94795aSAndroid Build Coastguard Worker int main(int argc, char* const argv[])
172*9e94795aSAndroid Build Coastguard Worker {
173*9e94795aSAndroid Build Coastguard Worker bool wantUsage;
174*9e94795aSAndroid Build Coastguard Worker int ic, retVal;
175*9e94795aSAndroid Build Coastguard Worker int verboseLevel;
176*9e94795aSAndroid Build Coastguard Worker unsigned int options;
177*9e94795aSAndroid Build Coastguard Worker
178*9e94795aSAndroid Build Coastguard Worker verboseLevel = 0;
179*9e94795aSAndroid Build Coastguard Worker options = 0;
180*9e94795aSAndroid Build Coastguard Worker wantUsage = false;
181*9e94795aSAndroid Build Coastguard Worker
182*9e94795aSAndroid Build Coastguard Worker while (1) {
183*9e94795aSAndroid Build Coastguard Worker ic = getopt(argc, argv, "defprtuv");
184*9e94795aSAndroid Build Coastguard Worker if (ic < 0)
185*9e94795aSAndroid Build Coastguard Worker break;
186*9e94795aSAndroid Build Coastguard Worker
187*9e94795aSAndroid Build Coastguard Worker switch (ic) {
188*9e94795aSAndroid Build Coastguard Worker case 'd':
189*9e94795aSAndroid Build Coastguard Worker options |= COPY_NO_DEREFERENCE;
190*9e94795aSAndroid Build Coastguard Worker break;
191*9e94795aSAndroid Build Coastguard Worker case 'e':
192*9e94795aSAndroid Build Coastguard Worker options |= COPY_TRY_EXE;
193*9e94795aSAndroid Build Coastguard Worker break;
194*9e94795aSAndroid Build Coastguard Worker case 'f':
195*9e94795aSAndroid Build Coastguard Worker options |= COPY_FORCE;
196*9e94795aSAndroid Build Coastguard Worker break;
197*9e94795aSAndroid Build Coastguard Worker case 'p':
198*9e94795aSAndroid Build Coastguard Worker options |= COPY_PERMISSIONS;
199*9e94795aSAndroid Build Coastguard Worker break;
200*9e94795aSAndroid Build Coastguard Worker case 't':
201*9e94795aSAndroid Build Coastguard Worker options |= COPY_TIMESTAMPS;
202*9e94795aSAndroid Build Coastguard Worker break;
203*9e94795aSAndroid Build Coastguard Worker case 'r':
204*9e94795aSAndroid Build Coastguard Worker options |= COPY_RECURSIVE;
205*9e94795aSAndroid Build Coastguard Worker break;
206*9e94795aSAndroid Build Coastguard Worker case 'u':
207*9e94795aSAndroid Build Coastguard Worker options |= COPY_UPDATE_ONLY;
208*9e94795aSAndroid Build Coastguard Worker break;
209*9e94795aSAndroid Build Coastguard Worker case 'v':
210*9e94795aSAndroid Build Coastguard Worker verboseLevel++;
211*9e94795aSAndroid Build Coastguard Worker break;
212*9e94795aSAndroid Build Coastguard Worker default:
213*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "Unexpected arg -%c\n", ic);
214*9e94795aSAndroid Build Coastguard Worker wantUsage = true;
215*9e94795aSAndroid Build Coastguard Worker break;
216*9e94795aSAndroid Build Coastguard Worker }
217*9e94795aSAndroid Build Coastguard Worker
218*9e94795aSAndroid Build Coastguard Worker if (wantUsage)
219*9e94795aSAndroid Build Coastguard Worker break;
220*9e94795aSAndroid Build Coastguard Worker }
221*9e94795aSAndroid Build Coastguard Worker
222*9e94795aSAndroid Build Coastguard Worker options |= verboseLevel & COPY_VERBOSE_MASK;
223*9e94795aSAndroid Build Coastguard Worker
224*9e94795aSAndroid Build Coastguard Worker if (optind == argc-1) {
225*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "acp: missing destination file\n");
226*9e94795aSAndroid Build Coastguard Worker return 2;
227*9e94795aSAndroid Build Coastguard Worker } else if (optind+2 > argc)
228*9e94795aSAndroid Build Coastguard Worker wantUsage = true;
229*9e94795aSAndroid Build Coastguard Worker
230*9e94795aSAndroid Build Coastguard Worker if (wantUsage) {
231*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "Usage: acp [OPTION]... SOURCE DEST\n");
232*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " or: acp [OPTION]... SOURCE... DIRECTORY\n");
233*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "\nOptions:\n");
234*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -d never follow (dereference) symbolic links\n");
235*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -e if source file doesn't exist, try adding "
236*9e94795aSAndroid Build Coastguard Worker "'.exe' [Win32 only]\n");
237*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -f use force, removing existing file if it's "
238*9e94795aSAndroid Build Coastguard Worker "not writeable\n");
239*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -p preserve mode, ownership\n");
240*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -r recursive copy\n");
241*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -t preserve timestamps\n");
242*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -u update only: don't copy if dest is newer\n");
243*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, " -v verbose output (-vv is more verbose)\n");
244*9e94795aSAndroid Build Coastguard Worker return 2;
245*9e94795aSAndroid Build Coastguard Worker }
246*9e94795aSAndroid Build Coastguard Worker
247*9e94795aSAndroid Build Coastguard Worker retVal = process(argc-optind, argv+optind, options);
248*9e94795aSAndroid Build Coastguard Worker DBUG(("EXIT: %d\n", retVal));
249*9e94795aSAndroid Build Coastguard Worker return retVal;
250*9e94795aSAndroid Build Coastguard Worker }
251*9e94795aSAndroid Build Coastguard Worker
252