Changeset View
Changeset View
Standalone View
Standalone View
bin/cp/cp.c
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||
| #include <assert.h> | #include <assert.h> | ||||
| #include <err.h> | #include <err.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #include <fts.h> | #include <fts.h> | ||||
| #include <getopt.h> | |||||
| #include <limits.h> | #include <limits.h> | ||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <stdbool.h> | #include <stdbool.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include "extern.h" | #include "extern.h" | ||||
| static char dot[] = "."; | static char dot[] = "."; | ||||
| #define END(buf) (buf + sizeof(buf)) | #define END(buf) (buf + sizeof(buf)) | ||||
| PATH_T to = { .dir = -1, .end = to.path }; | PATH_T to = { .dir = -1, .end = to.path }; | ||||
| int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; | bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag; | ||||
| static int Hflag, Lflag, Pflag, Rflag, rflag; | static bool Hflag, Lflag, Pflag, Rflag, rflag, Sflag; | ||||
| volatile sig_atomic_t info; | volatile sig_atomic_t info; | ||||
| enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; | enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; | ||||
| static int copy(char *[], enum op, int, struct stat *); | static int copy(char *[], enum op, int, struct stat *); | ||||
| static void siginfo(int __unused); | static void siginfo(int __unused); | ||||
| enum { | |||||
| SORT_OPT = CHAR_MAX, | |||||
| }; | |||||
| static const struct option long_opts[] = | |||||
| { | |||||
| { "archive", no_argument, NULL, 'a' }, | |||||
| { "force", no_argument, NULL, 'f' }, | |||||
| { "interactive", no_argument, NULL, 'i' }, | |||||
| { "dereference", no_argument, NULL, 'L' }, | |||||
| { "link", no_argument, NULL, 'l' }, | |||||
| { "no-clobber", no_argument, NULL, 'n' }, | |||||
| { "no-dereference", no_argument, NULL, 'P' }, | |||||
| { "recursive", no_argument, NULL, 'R' }, | |||||
| { "symbolic-link", no_argument, NULL, 's' }, | |||||
| { "verbose", no_argument, NULL, 'v' }, | |||||
| { "one-file-system", no_argument, NULL, 'x' }, | |||||
| { "sort", no_argument, NULL, SORT_OPT }, | |||||
| { 0 } | |||||
| }; | |||||
| int | int | ||||
| main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
| { | { | ||||
| struct stat to_stat, tmp_stat; | struct stat to_stat, tmp_stat; | ||||
| enum op type; | enum op type; | ||||
| int ch, fts_options, r; | int ch, fts_options, r; | ||||
| char *sep, *target; | char *sep, *target; | ||||
| bool have_trailing_slash = false; | bool have_trailing_slash = false; | ||||
| fts_options = FTS_NOCHDIR | FTS_PHYSICAL; | fts_options = FTS_NOCHDIR | FTS_PHYSICAL; | ||||
| while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1) | while ((ch = getopt_long(argc, argv, "HLPRafilNnprsvx", long_opts, | ||||
kevans: Want to avoid the default behavior of permuting non-option args to the end | |||||
| NULL)) != -1) | |||||
| switch (ch) { | switch (ch) { | ||||
| case 'H': | case 'H': | ||||
| Hflag = 1; | Hflag = true; | ||||
| Lflag = Pflag = 0; | Lflag = Pflag = false; | ||||
| break; | break; | ||||
| case 'L': | case 'L': | ||||
| Lflag = 1; | Lflag = true; | ||||
| Hflag = Pflag = 0; | Hflag = Pflag = false; | ||||
| break; | break; | ||||
| case 'P': | case 'P': | ||||
| Pflag = 1; | Pflag = true; | ||||
| Hflag = Lflag = 0; | Hflag = Lflag = false; | ||||
| break; | break; | ||||
| case 'R': | case 'R': | ||||
| Rflag = 1; | Rflag = true; | ||||
| break; | break; | ||||
| case 'a': | case 'a': | ||||
| pflag = 1; | pflag = true; | ||||
| Rflag = 1; | Rflag = true; | ||||
| Pflag = 1; | Pflag = true; | ||||
| Hflag = Lflag = 0; | Hflag = Lflag = false; | ||||
| break; | break; | ||||
| case 'f': | case 'f': | ||||
| fflag = 1; | fflag = true; | ||||
| iflag = nflag = 0; | iflag = nflag = false; | ||||
| break; | break; | ||||
| case 'i': | case 'i': | ||||
| iflag = 1; | iflag = true; | ||||
| fflag = nflag = 0; | fflag = nflag = false; | ||||
| break; | break; | ||||
| case 'l': | case 'l': | ||||
| lflag = 1; | lflag = true; | ||||
| break; | break; | ||||
| case 'N': | case 'N': | ||||
| Nflag = 1; | Nflag = true; | ||||
| break; | break; | ||||
| case 'n': | case 'n': | ||||
| nflag = 1; | nflag = true; | ||||
| fflag = iflag = 0; | fflag = iflag = false; | ||||
| break; | break; | ||||
| case 'p': | case 'p': | ||||
| pflag = 1; | pflag = true; | ||||
| break; | break; | ||||
| case 'r': | case 'r': | ||||
| rflag = Lflag = 1; | rflag = Lflag = true; | ||||
| Hflag = Pflag = 0; | Hflag = Pflag = false; | ||||
| break; | break; | ||||
| case 's': | case 's': | ||||
| sflag = 1; | sflag = true; | ||||
| break; | break; | ||||
| case 'v': | case 'v': | ||||
| vflag = 1; | vflag = true; | ||||
| break; | break; | ||||
| case 'x': | case 'x': | ||||
| fts_options |= FTS_XDEV; | fts_options |= FTS_XDEV; | ||||
| break; | break; | ||||
| case SORT_OPT: | |||||
| Sflag = true; | |||||
| break; | |||||
| default: | default: | ||||
| usage(); | usage(); | ||||
| } | } | ||||
| argc -= optind; | argc -= optind; | ||||
| argv += optind; | argv += optind; | ||||
| if (argc < 2) | if (argc < 2) | ||||
| usage(); | usage(); | ||||
| if (Rflag && rflag) | if (Rflag && rflag) | ||||
| errx(1, "the -R and -r options may not be specified together"); | errx(1, "the -R and -r options may not be specified together"); | ||||
| if (lflag && sflag) | if (lflag && sflag) | ||||
| errx(1, "the -l and -s options may not be specified together"); | errx(1, "the -l and -s options may not be specified together"); | ||||
| if (rflag) | if (rflag) | ||||
| Rflag = 1; | Rflag = true; | ||||
| if (Rflag) { | if (Rflag) { | ||||
| if (Hflag) | if (Hflag) | ||||
| fts_options |= FTS_COMFOLLOW; | fts_options |= FTS_COMFOLLOW; | ||||
| if (Lflag) { | if (Lflag) { | ||||
| fts_options &= ~FTS_PHYSICAL; | fts_options &= ~FTS_PHYSICAL; | ||||
| fts_options |= FTS_LOGICAL; | fts_options |= FTS_LOGICAL; | ||||
| } | } | ||||
| } else if (!Pflag) { | } else if (!Pflag) { | ||||
| ▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | main(int argc, char *argv[]) | ||||
| * as we need to skip checking root_stat on the first iteration and | * as we need to skip checking root_stat on the first iteration and | ||||
| * ensure that we set it with the first mkdir(). | * ensure that we set it with the first mkdir(). | ||||
| */ | */ | ||||
| exit (copy(argv, type, fts_options, (type == DIR_TO_DNE ? NULL : | exit (copy(argv, type, fts_options, (type == DIR_TO_DNE ? NULL : | ||||
| &to_stat))); | &to_stat))); | ||||
| } | } | ||||
| static int | static int | ||||
| ftscmp(const FTSENT * const *a, const FTSENT * const *b) | |||||
| { | |||||
| return (strcmp((*a)->fts_name, (*b)->fts_name)); | |||||
| } | |||||
| static int | |||||
| copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) | copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) | ||||
| { | { | ||||
| char rootname[NAME_MAX]; | char rootname[NAME_MAX]; | ||||
| struct stat created_root_stat, to_stat, *curr_stat; | struct stat created_root_stat, to_stat, *curr_stat; | ||||
| FTS *ftsp; | FTS *ftsp; | ||||
| FTSENT *curr; | FTSENT *curr; | ||||
| char *recpath = NULL, *sep; | char *recpath = NULL, *sep; | ||||
| int atflags, dne, badcp, len, level, rval; | int atflags, dne, badcp, len, level, rval; | ||||
| Show All 26 Lines | copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) | ||||
| } else { | } else { | ||||
| /* | /* | ||||
| * We will create the destination directory imminently. | * We will create the destination directory imminently. | ||||
| */ | */ | ||||
| to.dir = -1; | to.dir = -1; | ||||
| } | } | ||||
| level = FTS_ROOTLEVEL; | level = FTS_ROOTLEVEL; | ||||
| if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) | if ((ftsp = fts_open(argv, fts_options, Sflag ? ftscmp : NULL)) == NULL) | ||||
| err(1, "fts_open"); | err(1, "fts_open"); | ||||
| for (badcp = rval = 0; | for (badcp = rval = 0; | ||||
| (curr = fts_read(ftsp)) != NULL; | (curr = fts_read(ftsp)) != NULL; | ||||
| badcp = 0, *to.end = '\0') { | badcp = 0, *to.end = '\0') { | ||||
| curr_stat = curr->fts_statp; | curr_stat = curr->fts_statp; | ||||
| switch (curr->fts_info) { | switch (curr->fts_info) { | ||||
| case FTS_NS: | case FTS_NS: | ||||
| case FTS_DNR: | case FTS_DNR: | ||||
| ▲ Show 20 Lines • Show All 347 Lines • Show Last 20 Lines | |||||
Want to avoid the default behavior of permuting non-option args to the end