github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/make/tools/acp/acp.c (about)

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