/*
* Copyright 2005 The Android Open Source Project
*
* Android " cp " replacement .
*
* The GNU / Linux " cp " uses O_LARGEFILE in its open ( ) calls , utimes ( ) instead
* of utime ( ) , and getxattr ( ) / setxattr ( ) instead of chmod ( ) . These are
* probably " better " , but are non - portable , and not necessary for our
* purposes .
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <dirent.h>
#include <fcntl.h>
#include <utime.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include <host/CopyFile.h>
/*#define DEBUG_MSGS*/
#ifdef DEBUG_MSGS
# define DBUG(x) printf x
#else
# define DBUG(x) ((void )0 )
#endif
#define FSSEP '/' /* filename separator char */
/*
* Process the command - line file arguments .
*
* Returns 0 on success .
*/
int process(int argc, char * const argv[], unsigned int options)
{
int retVal = 0 ;
int i;
char * stripDest = NULL;
int stripDestLen;
bool destMustBeDir = false ;
struct stat sb;
assert(argc >= 2 );
/*
* Check for and trim a trailing slash on the last arg .
*
* It ' s useful to be able to say " cp foo bar / " when you want to copy
* a single file into a directory . If you say " cp foo bar " , and " bar "
* does not exist , it will create " bar " , when what you really wanted
* was for the cp command to fail with " directory does not exist " .
*/
stripDestLen = strlen(argv[argc-1 ]);
stripDest = malloc(stripDestLen+1 );
memcpy(stripDest, argv[argc-1 ], stripDestLen+1 );
if (stripDest[stripDestLen-1 ] == FSSEP) {
stripDest[--stripDestLen] = '\0' ;
destMustBeDir = true ;
}
if (argc > 2 )
destMustBeDir = true ;
/*
* Start with a quick check to ensure that , if we ' re expecting to copy
* to a directory , the target already exists and is actually a directory .
* It ' s okay if it ' s a symlink to a directory .
*
* If it turns out to be a directory , go ahead and raise the
* destMustBeDir flag so we do some path concatenation below .
*/
if (stat(stripDest, &sb) < 0 ) {
if (destMustBeDir) {
if (errno == ENOENT)
fprintf(stderr,
"acp: destination directory '%s' does not exist\n" ,
stripDest);
else
fprintf(stderr, "acp: unable to stat dest dir\n" );
retVal = 1 ;
goto bail;
}
} else {
if (S_ISDIR(sb.st_mode)) {
DBUG(("--- dest exists and is a dir, setting flag\n" ));
destMustBeDir = true ;
} else if (destMustBeDir) {
fprintf(stderr,
"acp: destination '%s' is not a directory\n" ,
stripDest);
retVal = 1 ;
goto bail;
}
}
/*
* Copying files .
*
* Strip trailing slashes off . They shouldn ' t be there , but
* sometimes file completion will put them in for directories .
*
* The observed behavior of GNU and BSD cp is that they print warnings
* if something fails , but continue on . If any part fails , the command
* exits with an error status .
*/
for (i = 0 ; i < argc-1 ; i++) {
const char * srcName;
char * src;
char * dst;
int copyResult;
int srcLen;
/* make a copy of the source name, and strip trailing '/' */
srcLen = strlen(argv[i]);
src = malloc(srcLen+1 );
memcpy(src, argv[i], srcLen+1 );
if (src[srcLen-1 ] == FSSEP)
src[--srcLen] = '\0' ;
/* find just the name part */
srcName = strrchr(src, FSSEP);
if (srcName == NULL) {
srcName = src;
} else {
srcName++;
assert(*srcName != '\0' );
}
if (destMustBeDir) {
/* concatenate dest dir and src name */
int srcNameLen = strlen(srcName);
dst = malloc(stripDestLen +1 + srcNameLen +1 );
memcpy(dst, stripDest, stripDestLen);
dst[stripDestLen] = FSSEP;
memcpy(dst + stripDestLen+1 , srcName, srcNameLen+1 );
} else {
/* simple */
dst = stripDest;
}
/*
* Copy the source to the destination .
*/
copyResult = copyFile(src, dst, options);
if (copyResult != 0 )
retVal = 1 ;
free(src);
if (dst != stripDest)
free(dst);
}
bail:
free(stripDest);
return retVal;
}
/*
* Set up the options .
*/
int main(int argc, char * const argv[])
{
bool wantUsage;
int ic, retVal;
int verboseLevel;
unsigned int options;
verboseLevel = 0 ;
options = 0 ;
wantUsage = false ;
while (1 ) {
ic = getopt(argc, argv, "defprtuv" );
if (ic < 0 )
break ;
switch (ic) {
case 'd' :
options |= COPY_NO_DEREFERENCE;
break ;
case 'e' :
options |= COPY_TRY_EXE;
break ;
case 'f' :
options |= COPY_FORCE;
break ;
case 'p' :
options |= COPY_PERMISSIONS;
break ;
case 't' :
options |= COPY_TIMESTAMPS;
break ;
case 'r' :
options |= COPY_RECURSIVE;
break ;
case 'u' :
options |= COPY_UPDATE_ONLY;
break ;
case 'v' :
verboseLevel++;
break ;
default :
fprintf(stderr, "Unexpected arg -%c\n" , ic);
wantUsage = true ;
break ;
}
if (wantUsage)
break ;
}
options |= verboseLevel & COPY_VERBOSE_MASK;
if (optind == argc-1 ) {
fprintf(stderr, "acp: missing destination file\n" );
return 2 ;
} else if (optind+2 > argc)
wantUsage = true ;
if (wantUsage) {
fprintf(stderr, "Usage: acp [OPTION]... SOURCE DEST\n" );
fprintf(stderr, " or: acp [OPTION]... SOURCE... DIRECTORY\n" );
fprintf(stderr, "\nOptions:\n" );
fprintf(stderr, " -d never follow (dereference) symbolic links\n" );
fprintf(stderr, " -e if source file doesn't exist, try adding "
"'.exe' [Win32 only]\n" );
fprintf(stderr, " -f use force, removing existing file if it's "
"not writeable\n" );
fprintf(stderr, " -p preserve mode, ownership\n" );
fprintf(stderr, " -r recursive copy\n" );
fprintf(stderr, " -t preserve timestamps\n" );
fprintf(stderr, " -u update only: don't copy if dest is newer\n" );
fprintf(stderr, " -v verbose output (-vv is more verbose)\n" );
return 2 ;
}
retVal = process(argc-optind, argv+optind, options);
DBUG(("EXIT: %d\n" , retVal));
return retVal;
}
Messung V0.5 in Prozent C=92 H=87 G=89
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-28)
¤
*© Formatika GbR, Deutschland