xref: /aosp_15_r20/build/make/tools/acp/acp.c (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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