OSDN Git Service

Updating security string to 2016-09-05 to platform and CTS in preparation
[android-x86/build.git] / libs / host / CopyFile.c
1 /*
2  * Copyright 2005 The Android Open Source Project
3  *
4  * Android "cp" replacement.
5  *
6  * The GNU/Linux "cp" uses O_LARGEFILE in its open() calls, utimes() instead
7  * of utime(), and getxattr()/setxattr() instead of chmod().  These are
8  * probably "better", but are non-portable, and not necessary for our
9  * purposes.
10  */
11 #include <host/CopyFile.h>
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <getopt.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <utime.h>
23 #include <limits.h>
24 #include <errno.h>
25 #include <assert.h>
26
27 #ifdef HAVE_MS_C_RUNTIME
28 #  define  mkdir(path,mode)   _mkdir(path)
29 #endif
30
31 #if defined(_WIN32)
32 #  define S_ISLNK(s) 0
33 #  define lstat stat
34 #  ifndef EACCESS   /* seems to be missing from the Mingw headers */
35 #    define  EACCESS            13
36 #  endif
37 #endif
38
39 #ifndef O_BINARY
40 #  define  O_BINARY  0
41 #endif
42
43 /*#define DEBUG_MSGS*/
44 #ifdef DEBUG_MSGS
45 # define DBUG(x) printf x
46 #else
47 # define DBUG(x) ((void)0)
48 #endif
49
50 #define FSSEP '/'       /* filename separator char */
51
52 static int copyFileRecursive(const char* src, const char* dst, bool isCmdLine, unsigned int options);
53
54 /*
55  * Returns true if the source file is newer than the destination file.
56  *
57  * The check is based on the modification date, whole seconds only.  This
58  * also returns true if the file sizes don't match.
59  */
60 static bool isSourceNewer(const struct stat* pSrcStat, const struct stat* pDstStat)
61 {
62     return (pSrcStat->st_mtime > pDstStat->st_mtime) ||
63            (pSrcStat->st_size != pDstStat->st_size);
64 }
65
66 /*
67  * Returns true if the source file has high resolution modification
68  * date. Cygwin/Mingw doesn't support st_mtim and always returns false.
69  */
70 static bool isHiresMtime(const struct stat* pSrcStat)
71 {
72 #if defined(__CYGWIN__) || defined(__MINGW32__)
73   return 0;
74 #elif defined(MACOSX_RSRC)
75     return pSrcStat->st_mtimespec.tv_nsec > 0;
76 #else
77     return pSrcStat->st_mtim.tv_nsec > 0;
78 #endif
79 }
80
81 /*
82  * Returns true if the source and destination files are actually the
83  * same thing.  We detect this by checking the inode numbers, which seems
84  * to work on Cygwin.
85  */
86 static bool isSameFile(const struct stat* pSrcStat, const struct stat* pDstStat)
87 {
88 #ifndef HAVE_VALID_STAT_ST_INO
89     /* with MSVCRT.DLL, stat always sets st_ino to 0, and there is no simple way to */
90         /* get the equivalent information with Win32 (Cygwin does some weird stuff in   */
91         /* its winsup/cygwin/fhandler_disk_file.cc to emulate this, too complex for us) */
92         return 0;
93 #else
94     return (pSrcStat->st_ino == pDstStat->st_ino);
95 #endif
96 }
97
98 static void printCopyMsg(const char* src, const char* dst, unsigned int options)
99 {
100     if ((options & COPY_VERBOSE_MASK) > 0)
101         printf("    '%s' --> '%s'\n", src, dst);
102 }
103
104 static void printNotNewerMsg(const char* src, const char* dst, unsigned int options)
105 {
106     if ((options & COPY_VERBOSE_MASK) > 1)
107         printf("    '%s' is up-to-date\n", dst);
108 }
109
110 /*
111  * Copy the contents of one file to another.
112  *
113  * The files are assumed to be seeked to the start.
114  */
115 static int copyFileContents(const char* dst, int dstFd, const char* src, int srcFd)
116 {
117     unsigned char buf[8192];
118     ssize_t readCount, writeCount;
119
120     /*
121      * Read a chunk, write it, and repeat.
122      */
123     while (1) {
124         readCount = read(srcFd, buf, sizeof(buf));
125         if (readCount < 0) {
126             fprintf(stderr,
127                 "acp: failed reading '%s': %s\n", src, strerror(errno));
128             return -1;
129         }
130
131         if (readCount > 0) {
132             writeCount = write(dstFd, buf, readCount);
133             if (writeCount < 0) {
134                 fprintf(stderr,
135                     "acp: failed writing '%s': %s\n", dst, strerror(errno));
136                 return -1;
137             }
138             if (writeCount != readCount) {
139                 fprintf(stderr, "acp: partial write to '%s' (%zd of %zd)\n",
140                     dst, writeCount, readCount);
141                 return -1;
142             }
143         }
144
145         if (readCount < (ssize_t) sizeof(buf))
146             break;
147     }
148
149     return 0;
150 }
151
152 /*
153  * Set the permissions, owner, and timestamps on the destination file
154  * equal to those of the source file.
155  *
156  * Failures here are "soft"; they don't produce warning messages and don't
157  * cause the cp command to report a failure.
158  */
159 static int setPermissions(const char* dst, const struct stat* pSrcStat, unsigned int options)
160 {
161     struct utimbuf ut;
162
163     if (options & COPY_TIMESTAMPS) {
164         /*
165          * Start with timestamps.  The access and mod dates are not affected
166          * by the next operations.
167          */
168         ut.actime = pSrcStat->st_atime;
169         ut.modtime = pSrcStat->st_mtime;
170         if (isHiresMtime(pSrcStat))
171             ut.modtime += 1;
172         if (utime(dst, &ut) != 0) {
173             DBUG(("---   unable to set timestamps on '%s': %s\n",
174                 dst, strerror(errno)));
175         }
176     }
177
178     if (options & COPY_PERMISSIONS) {
179         /*
180          * Set the permissions.
181          */
182         if (chmod(dst, pSrcStat->st_mode & ~(S_IFMT)) != 0) {
183             DBUG(("---   unable to set perms on '%s' to 0%o: %s\n",
184                 dst, pSrcStat->st_mode & ~(S_IFMT), strerror(errno)));
185         }
186 #ifndef HAVE_MS_C_RUNTIME
187         /*
188          * Set the owner.
189          */
190         if (chown(dst, pSrcStat->st_uid, pSrcStat->st_gid) != 0) {
191             DBUG(("---   unable to set owner of '%s' to %d/%d: %s\n",
192                 dst, pSrcStat->st_uid, pSrcStat->st_gid, strerror(errno)));
193         }
194 #endif
195     }
196
197     return 0;
198 }
199
200 /*
201  * Copy a regular file.  If the destination file exists and is not a
202  * regular file, we fail.  However, we use stat() rather than lstat(),
203  * because it's okay to write through a symlink (the noDereference stuff
204  * only applies to the source file).
205  *
206  * If the file doesn't exist, create it.  If it does exist, truncate it.
207  */
208 static int copyRegular(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
209 {
210     struct stat dstStat;
211     int srcFd, dstFd, statResult, copyResult;
212
213     DBUG(("--- copying regular '%s' to '%s'\n", src, dst));
214
215     statResult = stat(dst, &dstStat);
216     if (statResult == 0 && !S_ISREG(dstStat.st_mode)) {
217         fprintf(stderr,
218             "acp: destination '%s' exists and is not regular file\n",
219             dst);
220         return -1;
221     } else if (statResult != 0 && errno != ENOENT) {
222         fprintf(stderr, "acp: unable to stat destination '%s'\n", dst);
223         return -1;
224     }
225
226     if (statResult == 0) {
227         if (isSameFile(pSrcStat, &dstStat)) {
228             fprintf(stderr, "acp: '%s' and '%s' are the same file\n",
229                 src, dst);
230             return -1;
231         }
232         if (options & COPY_UPDATE_ONLY) {
233             if (!isSourceNewer(pSrcStat, &dstStat)) {
234                 DBUG(("---  source is not newer: '%s'\n", src));
235                 printNotNewerMsg(src, dst, options);
236                 return 0;
237             }
238         }
239     }
240
241     /* open src */
242     srcFd = open(src, O_RDONLY | O_BINARY, 0);
243     if (srcFd < 0) {
244         fprintf(stderr, "acp: unable to open '%s': %s\n", src, strerror(errno));
245         return -1;
246     }
247
248     /* open dest with O_CREAT | O_TRUNC */
249     DBUG(("---  opening '%s'\n", dst));
250     dstFd = open(dst, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
251
252     if (dstFd < 0) {
253         if (errno == ENOENT) {
254             /* this happens if the target directory doesn't exist */
255             fprintf(stderr,
256                 "acp: cannot create '%s': %s\n", dst, strerror(errno));
257             (void) close(srcFd);
258             return -1;
259         }
260
261         /* if "force" is set, try removing the destination file and retry */
262         if (options & COPY_FORCE) {
263             if (unlink(dst) != 0) {
264 #ifdef HAVE_MS_C_RUNTIME
265                                 /* MSVCRT.DLL unlink will fail with EACCESS if the file is set read-only */
266                                 /* so try to change its mode, and unlink again                           */
267                                 if (errno == EACCESS) {
268                                         if (chmod(dst, S_IWRITE|S_IREAD) == 0 && unlink(dst) == 0)
269                                                 goto Open_File;
270                                 }
271 #endif          
272                 fprintf(stderr, "acp: unable to remove '%s': %s\n",
273                     dst, strerror(errno));
274                 (void) close(srcFd);
275                 return -1;
276             }
277 #ifdef HAVE_MS_C_RUNTIME
278         Open_File:
279 #endif                  
280             dstFd = open(dst, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
281         }
282     }
283     if (dstFd < 0) {
284         fprintf(stderr, "acp: unable to open '%s': %s\n",
285             dst, strerror(errno));
286         (void) close(srcFd);
287         return -1;
288     }
289
290     copyResult = copyFileContents(dst, dstFd, src, srcFd);
291
292     (void) close(srcFd);
293     (void) close(dstFd);
294     if (copyResult != 0)
295         return -1;
296
297 #ifdef MACOSX_RSRC
298     {
299         char* srcRsrcName = NULL;
300         char* dstRsrcName = NULL;
301         struct stat rsrcStat;
302
303         srcRsrcName = malloc(strlen(src) + 5 + 1);
304         strcpy(srcRsrcName, src);
305         strcat(srcRsrcName, "/rsrc");
306
307         dstRsrcName = malloc(strlen(dst) + 5 + 1);
308         strcpy(dstRsrcName, dst);
309         strcat(dstRsrcName, "/rsrc");
310
311         if (stat(srcRsrcName, &rsrcStat) == 0 && rsrcStat.st_size > 0) {
312             DBUG(("---  RSRC: %s --> %s\n", srcRsrcName, dstRsrcName));
313
314             srcFd = open(srcRsrcName, O_RDONLY);
315             dstFd = open(dstRsrcName, O_TRUNC | O_WRONLY, 0);
316             copyResult = -1;
317             if (srcFd >= 0 && dstFd >= 0) {
318                 copyResult = copyFileContents(dstRsrcName, dstFd,
319                     srcRsrcName, srcFd);
320                 (void) close(srcFd);
321                 (void) close(dstFd);
322             }
323
324             if (copyResult != 0)
325                 return -1;
326         }
327
328         free(srcRsrcName);
329         free(dstRsrcName);
330     }
331 #endif
332
333     setPermissions(dst, pSrcStat, options);
334
335     printCopyMsg(src, dst, options);
336
337     return 0;
338 }
339
340
341 /*
342  * Copy a symlink.  This only happens if we're in "no derefence" mode,
343  * in which we copy the links rather than the files that are pointed at.
344  *
345  * We always discard the destination file.  If it's a symlink already,
346  * we want to throw it out and replace it.  If it's not a symlink, we
347  * need to trash it so we can create one.
348  */
349 #if defined(_WIN32)
350 extern int copySymlink(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options) __attribute__((error("no symlinks on Windows")));
351 #else
352 static int copySymlink(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
353 {
354     struct stat dstStat;
355     char linkBuf[PATH_MAX+1];
356     int statResult, nameLen;
357
358     assert(options & COPY_NO_DEREFERENCE);
359     DBUG(("--- copying symlink '%s' to '%s'\n", src, dst));
360
361     /* NOTE: we use lstat() here */
362     statResult = lstat(dst, &dstStat);
363     if (statResult == 0 && !S_ISREG(dstStat.st_mode)
364                          && !S_ISLNK(dstStat.st_mode)
365                                                  )
366     {
367         fprintf(stderr,
368             "acp: destination '%s' exists and is not regular or symlink\n",
369             dst);
370         return -1;
371     }
372
373     if (statResult == 0) {
374         if (isSameFile(pSrcStat, &dstStat)) {
375             fprintf(stderr, "acp: '%s' and '%s' are the same file\n",
376                 src, dst);
377             return -1;
378         }
379         if (options & COPY_UPDATE_ONLY) {
380             if (!isSourceNewer(pSrcStat, &dstStat)) {
381                 DBUG(("---  source is not newer: '%s'\n", src));
382                 printNotNewerMsg(src, dst, options);
383                 return 0;
384             }
385         }
386     }
387
388     /* extract the symlink contents */
389     nameLen = readlink(src, linkBuf, sizeof(linkBuf)-1);
390     if (nameLen <= 0) {
391         fprintf(stderr, "acp: unable to read symlink '%s': %s\n",
392             src, strerror(errno));
393         return -1;
394     }
395     linkBuf[nameLen] = '\0';
396     DBUG(("--- creating symlink file '%s' (--> %s)\n", dst, linkBuf));
397
398     if (statResult == 0) {
399         DBUG(("---  removing '%s'\n", dst));
400         if (unlink(dst) != 0) {
401             fprintf(stderr, "acp: unable to remove '%s': %s\n",
402                 dst, strerror(errno));
403             return -1;
404         }
405     }
406
407     if (symlink(linkBuf, dst) != 0) {
408         fprintf(stderr, "acp: unable to create symlink '%s' [%s]: %s\n",
409             dst, linkBuf, strerror(errno));
410         return -1;
411     }
412
413     /*
414      * There's no way to set the file date or access permissions, but
415      * it is possible to set the owner.
416      */
417     if (options & COPY_PERMISSIONS) {
418         if (lchown(dst, pSrcStat->st_uid, pSrcStat->st_gid) != 0)
419             DBUG(("---  lchown failed: %s\n", strerror(errno)));
420     }
421
422     printCopyMsg(src, dst, options);
423
424     return 0;
425 }
426 #endif
427
428 /*
429  * Copy the contents of one directory to another.  Both "src" and "dst"
430  * must be directories.  We will create "dst" if it does not exist.
431  */
432 int copyDirectory(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
433 {
434     int retVal = 0;
435     struct stat dstStat;
436     DIR* dir;
437     int cc, statResult;
438
439     DBUG(("--- copy dir '%s' to '%s'\n", src, dst));
440
441     statResult = stat(dst, &dstStat);
442     if (statResult == 0 && !S_ISDIR(dstStat.st_mode)) {
443         fprintf(stderr,
444             "acp: destination '%s' exists and is not a directory\n", dst);
445         return -1;
446     } else if (statResult != 0 && errno != ENOENT) {
447         fprintf(stderr, "acp: unable to stat destination '%s'\n", dst);
448         return -1;
449     }
450
451     if (statResult == 0) {
452         if (isSameFile(pSrcStat, &dstStat)) {
453             fprintf(stderr,
454                 "acp: cannot copy directory into itself ('%s' and '%s')\n",
455                 src, dst);
456             return -1;
457         }
458     } else {
459         DBUG(("---  creating dir '%s'\n", dst));
460         cc = mkdir(dst, 0755);
461         if (cc != 0) {
462             fprintf(stderr, "acp: unable to create directory '%s': %s\n",
463                 dst, strerror(errno));
464             return -1;
465         }
466
467         /* only print on mkdir */
468         printCopyMsg(src, dst, options);
469     }
470
471     /*
472      * Open the directory, and plow through its contents.
473      */
474     dir = opendir(src);
475     if (dir == NULL) {
476         fprintf(stderr, "acp: unable to open directory '%s': %s\n",
477             src, strerror(errno));
478         return -1;
479     }
480
481     while (1) {
482         struct dirent* ent;
483         char* srcFile;
484         char* dstFile;
485         int srcLen, dstLen, nameLen;
486
487         ent = readdir(dir);
488         if (ent == NULL)
489             break;
490
491         if (strcmp(ent->d_name, ".") == 0 ||
492             strcmp(ent->d_name, "..") == 0)
493         {
494             continue;
495         }
496
497         nameLen = strlen(ent->d_name);
498         srcLen = strlen(src);
499         dstLen = strlen(dst);
500
501         srcFile = malloc(srcLen +1 + nameLen +1);
502         memcpy(srcFile, src, srcLen);
503         srcFile[srcLen] = FSSEP;
504         memcpy(srcFile + srcLen+1, ent->d_name, nameLen +1);
505
506         dstFile = malloc(dstLen +1 + nameLen +1);
507         memcpy(dstFile, dst, dstLen);
508         dstFile[dstLen] = FSSEP;
509         memcpy(dstFile + dstLen+1, ent->d_name, nameLen +1);
510
511         if (copyFileRecursive(srcFile, dstFile, false, options) != 0)
512             retVal = -1;        /* note failure and keep going */
513
514         free(srcFile);
515         free(dstFile);
516     }
517     closedir(dir);
518
519     setPermissions(dst, pSrcStat, options);
520
521     return retVal;
522 }
523
524 /*
525  * Do the actual copy.  This is called recursively from copyDirectory().
526  *
527  * "dst" should only be a directory if "src" is also a directory.
528  *
529  * Returns 0 on success.
530  */
531 static int copyFileRecursive(const char* src, const char* dst, bool isCmdLine, unsigned int options)
532 {
533     char* srcExe = NULL;
534     char* dstExe = NULL;
535     char* dstDir = NULL;
536     struct stat srcStat;
537     int retVal = 0;
538     int statResult, statErrno;
539
540     /*
541      * Stat the source file.  If it doesn't exist, fail.
542      */
543     if (options & COPY_NO_DEREFERENCE)
544         statResult = lstat(src, &srcStat);
545     else
546         statResult = stat(src, &srcStat);
547     statErrno = errno;        /* preserve across .exe attempt */
548
549 #ifdef WIN32_EXE
550     /*
551      * Here's the interesting part.  Under Cygwin, if you have a file
552      * called "foo.exe", stat("foo", ...) will succeed, but open("foo", ...)
553      * will fail.  We need to figure out what its name is supposed to be
554      * so we can create the correct destination file.
555      *
556      * If we don't have the "-e" flag set, we want "acp foo bar" to fail,
557      * not automatically find "foo.exe".  That way, if we really were
558      * trying to copy "foo", it doesn't grab something we don't want.
559      */
560     if (isCmdLine && statResult == 0) {
561         int tmpFd;
562         tmpFd = open(src, O_RDONLY | O_BINARY, 0);
563         if (tmpFd < 0) {
564             statResult = -1;
565             statErrno = ENOENT;
566         } else {
567             (void) close(tmpFd);
568         }
569     }
570
571     /*
572      * If we didn't find the file, try it again with ".exe".
573      */
574     if (isCmdLine && statResult < 0 && statErrno == ENOENT && (options & COPY_TRY_EXE)) {
575         srcExe = malloc(strlen(src) + 4 +1);
576         strcpy(srcExe, src);
577         strcat(srcExe, ".exe");
578
579         if (options & COPY_NO_DEREFERENCE)
580             statResult = lstat(srcExe, &srcStat);
581         else
582             statResult = stat(srcExe, &srcStat);
583
584         if (statResult == 0 && !S_ISREG(srcStat.st_mode))
585             statResult = -1;        /* fail, use original statErrno below */
586
587         if (statResult == 0) {
588             /* found a .exe, copy that instead */
589             dstExe = malloc(strlen(dst) + 4 +1);
590             strcpy(dstExe, dst);
591             strcat(dstExe, ".exe");
592
593             src = srcExe;
594             dst = dstExe;
595         } else {
596             DBUG(("---  couldn't find '%s' either\n", srcExe));
597         }
598     }
599 #endif
600     if (statResult < 0) {
601         if (statErrno == ENOENT)
602             fprintf(stderr, "acp: file '%s' does not exist\n", src);
603         else
604             fprintf(stderr, "acp: unable to stat '%s': %s\n",
605                 src, strerror(statErrno));
606         retVal = -1;
607         goto bail;
608     }
609
610     /*
611      * If "src" is a directory, ignore it if "recursive" isn't set.
612      *
613      * We want to create "dst" as a directory (or verify that it already
614      * exists as a directory), and then copy its contents.
615      */
616     if (S_ISDIR(srcStat.st_mode)) {
617         if (!(options & COPY_RECURSIVE)) {
618             fprintf(stderr, "acp: omitting directory '%s'\n", src);
619         } else {
620             retVal = copyDirectory(src, dst, &srcStat, options);
621         }
622     } else if (S_ISLNK(srcStat.st_mode)) {
623         retVal = copySymlink(src, dst, &srcStat, options);
624     } else if (S_ISREG(srcStat.st_mode)) {
625         retVal = copyRegular(src, dst, &srcStat, options);
626     } else {
627         fprintf(stderr, "acp: skipping unusual file '%s' (mode=0%o)\n",
628             src, srcStat.st_mode);
629         retVal = -1;
630     }
631
632 bail:
633     free(srcExe);
634     free(dstExe);
635     free(dstDir);
636     return retVal;
637 }
638
639 int copyFile(const char* src, const char* dst, unsigned int options)
640 {
641     return copyFileRecursive(src, dst, true, options);
642 }
643
644