X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cp_mv.c;h=b15235a2573cda3375f2dd1f5833bd457411884a;hb=8fbaeece53a3cad58ca2e135fc6b6d540fa1e3c4;hp=2ba8662b914fc23afef5522a1cf92fcb7bd51544;hpb=fac10d7c59f7db0facd5fb94de273310b9ec86e6;p=oweals%2Fbusybox.git diff --git a/cp_mv.c b/cp_mv.c index 2ba8662b9..b15235a25 100644 --- a/cp_mv.c +++ b/cp_mv.c @@ -1,3 +1,4 @@ +/* vi: set sw=4 ts=4: */ /* * Mini `cp' and `mv' implementation for BusyBox. * @@ -36,223 +37,311 @@ #include #include #include +#include +#include +#include +#include #define is_cp 0 #define is_mv 1 -static const char *dz; /* dollar zero, .bss */ -static int dz_i; /* index, .bss */ -static const char *cp_mv_usage[] = /* .rodata */ +static int dz_i; /* index into cp_mv_usage */ +static const char *dz; /* dollar zero, .bss */ +static const char *cp_mv_usage[] = /* .rodata */ { - "cp [OPTION]... SOURCE DEST\n" - " or: cp [OPTION]... SOURCE... DIRECTORY\n\n" - "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" - "\n" - "\t-a\tsame as -dpR\n" - "\t-d\tpreserve links\n" - "\t-p\tpreserve file attributes if possible\n" - "\t-R\tcopy directories recursively\n" - , - "mv SOURCE DEST\n" - " or: mv SOURCE... DIRECTORY\n\n" - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n" - "Warning!! This is not GNU `mv'. It does not preserve hard links.\n" + "cp [OPTION]... SOURCE DEST\n" + " or: cp [OPTION]... SOURCE... DIRECTORY\n" +#ifndef BB_FEATURE_TRIVIAL_HELP + "\nCopies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" + "\n" + "\t-a\tSame as -dpR\n" + "\t-d\tPreserves links\n" + "\t-p\tPreserves file attributes if possible\n" + "\t-f\tforce (implied; ignored) - always set\n" + "\t-R\tCopies directories recursively\n" +#endif + , + "mv SOURCE DEST\n" + " or: mv SOURCE... DIRECTORY\n" +#ifndef BB_FEATURE_TRIVIAL_HELP + "\nRename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n" +#endif }; -extern int cp_mv_main(int argc, char **argv) -{ - __label__ name_too_long__exit; - __label__ exit_false; +static int recursiveFlag; +static int followLinks; +static int preserveFlag; +static int forceFlag; + +static const char *baseSrcName; +static int srcDirFlag; +static struct stat srcStatBuf; - int recursiveFlag; - int followLinks; - int preserveFlag; +static char baseDestName[BUFSIZ + 1]; +static size_t baseDestLen; +static int destDirFlag; +static struct stat destStatBuf; - const char *baseSrcName; - int srcDirFlag; +static jmp_buf catch; +static volatile int mv_Action_first_time; - char baseDestName[PATH_MAX + 1]; - size_t baseDestLen; - int destDirFlag; +static void name_too_long__exit (void) __attribute__((noreturn)); - void fill_baseDest_buf(char *_buf, size_t *_buflen) - { - const char *srcBasename; - if ((srcBasename = strrchr(baseSrcName, '/')) == NULL) - { +static +void name_too_long__exit (void) +{ + fprintf(stderr, name_too_long, dz); + exit(FALSE); +} + +static void +fill_baseDest_buf(char *_buf, size_t * _buflen) { + const char *srcBasename; + if ((srcBasename = strrchr(baseSrcName, '/')) == NULL) { srcBasename = baseSrcName; - if (_buf[*_buflen - 1] != '/') - { - if (++(*_buflen) > PATH_MAX) - goto name_too_long__exit; - strcat(_buf, "/"); + if (_buf[*_buflen - 1] != '/') { + if (++(*_buflen) > BUFSIZ) + name_too_long__exit(); + strcat(_buf, "/"); } - } - if (*_buflen + strlen(srcBasename) > PATH_MAX) - goto name_too_long__exit; - strcat(_buf, srcBasename); - return; } + if (*_buflen + strlen(srcBasename) > BUFSIZ) + name_too_long__exit(); + strcat(_buf, srcBasename); + return; + +} + +static int +cp_mv_Action(const char *fileName, struct stat *statbuf, void* junk) +{ + char destName[BUFSIZ + 1]; + size_t destLen; + const char *srcBasename; + char *name; - int fileAction(const char *fileName, struct stat *statbuf) - { - __label__ return_false; - char destName[PATH_MAX + 1]; - size_t destLen; - const char *srcBasename; - - strcpy(destName, baseDestName); - destLen = strlen(destName); - - if (srcDirFlag == TRUE) - { - if (recursiveFlag == FALSE) - { - fprintf(stderr, omitting_directory, "cp", baseSrcName); - return TRUE; + strcpy(destName, baseDestName); + destLen = strlen(destName); + + if (srcDirFlag == TRUE) { + if (recursiveFlag == FALSE) { + fprintf(stderr, omitting_directory, dz, baseSrcName); + return TRUE; } srcBasename = (strstr(fileName, baseSrcName) - + strlen(baseSrcName)); - if (destLen + strlen(srcBasename) > PATH_MAX) - { - fprintf(stderr, name_too_long, "cp"); - goto return_false; + + strlen(baseSrcName)); + + if (destLen + strlen(srcBasename) > BUFSIZ) { + fprintf(stderr, name_too_long, dz); + return FALSE; } strcat(destName, srcBasename); - } - else if (destDirFlag == TRUE) - { + } + else if (destDirFlag == TRUE) { fill_baseDest_buf(&destName[0], &destLen); - } - else - { + } + else { srcBasename = baseSrcName; - } - return copyFile(fileName, destName, preserveFlag, followLinks); - - return_false: - return FALSE; } + if (mv_Action_first_time && (dz_i == is_mv)) { + mv_Action_first_time = errno = 0; + if (rename(fileName, destName) < 0 && errno != EXDEV) { + fprintf(stderr, "%s: rename(%s, %s): %s\n", + dz, fileName, destName, strerror(errno)); + goto do_copyFile; /* Try anyway... */ + } + else if (errno == EXDEV) + goto do_copyFile; + else + longjmp(catch, 1); /* succeeded with rename() */ + } + do_copyFile: + if (preserveFlag == TRUE && statbuf->st_nlink > 1) { + if (is_in_ino_dev_hashtable(statbuf, &name)) { + if (link(name, destName) < 0) { + fprintf(stderr, "%s: link(%s, %s): %s\n", + dz, name, destName, strerror(errno)); + return FALSE; + } + return TRUE; + } + else { + add_to_ino_dev_hashtable(statbuf, destName); + } + } + return copyFile(fileName, destName, preserveFlag, followLinks, forceFlag); +} - int rmfileAction(const char *fileName, struct stat* statbuf) - { - if (unlink(fileName) < 0 ) { - perror(fileName); - return FALSE; - } - return TRUE; - } - - int rmdirAction(const char *fileName, struct stat* statbuf) - { - if (rmdir(fileName) < 0 ) { - perror(fileName); - return FALSE; - } - return TRUE; - } - - if ((dz = strrchr(*argv, '/')) == NULL) dz = *argv; else dz++; - if (*dz == 'c' && *(dz + 1) == 'p') dz_i = is_cp; else dz_i = is_mv; - if (argc < 3) usage(cp_mv_usage[dz_i]); - argc--; - argv++; +static int +rm_Action(const char *fileName, struct stat *statbuf, void* junk) +{ + int status = TRUE; - if (dz_i == is_cp) - { - recursiveFlag = preserveFlag = FALSE; - followLinks = TRUE; - while (**argv == '-') - { - while (*++(*argv)) - { - switch (**argv) - { - case 'a': - followLinks = FALSE; - preserveFlag = TRUE; - recursiveFlag = TRUE; - break; - case 'd': - followLinks = FALSE; - break; - case 'p': - preserveFlag = TRUE; - break; - case 'R': - recursiveFlag = TRUE; - break; - default: - usage(cp_mv_usage[is_cp]); + if (S_ISDIR(statbuf->st_mode)) { + if (rmdir(fileName) < 0) { + fprintf(stderr, "%s: rmdir(%s): %s\n", dz, fileName, strerror(errno)); + status = FALSE; } - } - argc--; - argv++; + } else if (unlink(fileName) < 0) { + fprintf(stderr, "%s: unlink(%s): %s\n", dz, fileName, strerror(errno)); + status = FALSE; } - } - else /* (dz_i == is_mv) */ - { - recursiveFlag = preserveFlag = TRUE; - followLinks = FALSE; - } + return status; +} - if (strlen(argv[argc - 1]) > PATH_MAX) - { - fprintf(stderr, name_too_long, "cp"); - goto exit_false; - } - strcpy(baseDestName, argv[argc - 1]); - baseDestLen = strlen(baseDestName); - if (baseDestLen == 0) goto exit_false; +extern int cp_mv_main(int argc, char **argv) +{ + dz = *argv; /* already basename'd by busybox.c:main */ + if (*dz == 'c' && *(dz + 1) == 'p') + dz_i = is_cp; + else + dz_i = is_mv; + if (argc < 3) + usage(cp_mv_usage[dz_i]); + argc--; + argv++; - destDirFlag = isDirectory(baseDestName, TRUE); - if ((argc > 3) && destDirFlag == FALSE) - { - fprintf(stderr, not_a_directory, "cp", baseDestName); - goto exit_false; - } + if (dz_i == is_cp) { + recursiveFlag = preserveFlag = forceFlag = FALSE; + followLinks = TRUE; + while (*argv && **argv == '-') { + while (*++(*argv)) { + switch (**argv) { + case 'a': + followLinks = FALSE; + preserveFlag = TRUE; + recursiveFlag = TRUE; + break; + case 'd': + followLinks = FALSE; + break; + case 'p': + preserveFlag = TRUE; + break; + case 'R': + recursiveFlag = TRUE; + break; + case 'f': + forceFlag = TRUE; + break; + default: + usage(cp_mv_usage[is_cp]); + } + } + argc--; + argv++; + } + if (argc < 2) { + usage(cp_mv_usage[dz_i]); + } + } else { /* (dz_i == is_mv) */ + recursiveFlag = preserveFlag = TRUE; + followLinks = FALSE; + } + - while (argc-- > 1) - { - size_t srcLen; - int flags_memo; + if (strlen(argv[argc - 1]) > BUFSIZ) { + fprintf(stderr, name_too_long, "cp"); + goto exit_false; + } + strcpy(baseDestName, argv[argc - 1]); + baseDestLen = strlen(baseDestName); + if (baseDestLen == 0) + goto exit_false; - baseSrcName = *(argv++); + destDirFlag = isDirectory(baseDestName, TRUE, &destStatBuf); + if ((argc > 3) && destDirFlag == FALSE) { + fprintf(stderr, not_a_directory, "cp", baseDestName); + goto exit_false; + } - if ((srcLen = strlen(baseSrcName)) > PATH_MAX) - goto name_too_long__exit; + while (argc-- > 1) { + size_t srcLen; + volatile int flags_memo; + int status; - if (srcLen == 0) continue; + baseSrcName = *(argv++); - srcDirFlag = isDirectory(baseSrcName, followLinks); + if ((srcLen = strlen(baseSrcName)) > BUFSIZ) + name_too_long__exit(); - if ((flags_memo = (recursiveFlag == TRUE && - srcDirFlag == TRUE && destDirFlag == TRUE))) - { - fill_baseDest_buf(&baseDestName[0], &baseDestLen); - } - if (recursiveAction(baseSrcName, - recursiveFlag, followLinks, FALSE, - fileAction, fileAction) - == FALSE) goto exit_false; + if (srcLen == 0) continue; /* "" */ - if (dz_i == is_mv && - recursiveAction(baseSrcName, - recursiveFlag, followLinks, TRUE, - rmfileAction, rmdirAction) - == FALSE) goto exit_false; + srcDirFlag = isDirectory(baseSrcName, followLinks, &srcStatBuf); - if (flags_memo) *(baseDestName + baseDestLen) = '\0'; - } + if ((flags_memo = (recursiveFlag == TRUE && + srcDirFlag == TRUE && destDirFlag == TRUE))) { - exit TRUE; + struct stat sb; + int state = 0; + char *pushd, *d, *p; - name_too_long__exit: - fprintf(stderr, name_too_long, "cp"); + if ((pushd = getcwd(NULL, BUFSIZ + 1)) == NULL) { + fprintf(stderr, "%s: getcwd(): %s\n", dz, strerror(errno)); + continue; + } + if (chdir(baseDestName) < 0) { + fprintf(stderr, "%s: chdir(%s): %s\n", dz, baseSrcName, strerror(errno)); + continue; + } + if ((d = getcwd(NULL, BUFSIZ + 1)) == NULL) { + fprintf(stderr, "%s: getcwd(): %s\n", dz, strerror(errno)); + continue; + } + while (!state && *d != '\0') { + if (stat(d, &sb) < 0) { /* stat not lstat - always dereference targets */ + fprintf(stderr, "%s: stat(%s) :%s\n", dz, d, strerror(errno)); + state = -1; + continue; + } + if ((sb.st_ino == srcStatBuf.st_ino) && + (sb.st_dev == srcStatBuf.st_dev)) { + fprintf(stderr, + "%s: Cannot %s `%s' " + "into a subdirectory of itself, `%s/%s'\n", + dz, dz, baseSrcName, baseDestName, baseSrcName); + state = -1; + continue; + } + if ((p = strrchr(d, '/')) != NULL) { + *p = '\0'; + } + } + if (chdir(pushd) < 0) { + fprintf(stderr, "%s: chdir(%s): %s\n", dz, pushd, strerror(errno)); + free(pushd); + free(d); + continue; + } + free(pushd); + free(d); + if (state < 0) + continue; + else + fill_baseDest_buf(baseDestName, &baseDestLen); + } + status = setjmp(catch); + if (status == 0) { + mv_Action_first_time = 1; + if (recursiveAction(baseSrcName, + recursiveFlag, followLinks, FALSE, + cp_mv_Action, cp_mv_Action, NULL) == FALSE) goto exit_false; + if (dz_i == is_mv && + recursiveAction(baseSrcName, + recursiveFlag, followLinks, TRUE, + rm_Action, rm_Action, NULL) == FALSE) goto exit_false; + } + if (flags_memo) + *(baseDestName + baseDestLen) = '\0'; + } + return( TRUE); exit_false: - exit FALSE; + return( FALSE); } -// Local Variables: -// c-file-style: "k&r" -// c-basic-offset: 4 -// End: +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/