Changeset View
Changeset View
Standalone View
Standalone View
bin/cp/cp.c
Show First 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | if (!Rflag || Lflag) | ||||
return (stat(path, sb)); | return (stat(path, sb)); | ||||
return (lstat(path, sb)); | return (lstat(path, sb)); | ||||
} | } | ||||
static int | 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]; | |||||
struct stat created_root_stat, to_stat; | struct stat created_root_stat, to_stat; | ||||
FTS *ftsp; | FTS *ftsp; | ||||
FTSENT *curr; | FTSENT *curr; | ||||
int base = 0, dne, badcp, rval; | int base = 0, dne, badcp, rval; | ||||
size_t nlen; | size_t nlen; | ||||
char *p, *recurse_path, *target_mid; | char *p, *recurse_path, *target_mid; | ||||
mode_t mask, mode; | mode_t mask, mode; | ||||
Show All 20 Lines | for (badcp = rval = 0; errno = 0, (curr = fts_read(ftsp)) != NULL; | ||||
case FTS_DC: /* Warn, continue. */ | case FTS_DC: /* Warn, continue. */ | ||||
warnx("%s: directory causes a cycle", curr->fts_path); | warnx("%s: directory causes a cycle", curr->fts_path); | ||||
badcp = rval = 1; | badcp = rval = 1; | ||||
continue; | continue; | ||||
default: | default: | ||||
; | ; | ||||
} | } | ||||
if (curr->fts_info == FTS_D && type != FILE_TO_FILE && | |||||
root_stat != NULL && | |||||
root_stat->st_dev == curr->fts_statp->st_dev && | |||||
root_stat->st_ino == curr->fts_statp->st_ino) { | |||||
assert(recurse_path == NULL); | |||||
if (curr->fts_level > FTS_ROOTLEVEL) { | |||||
/* | /* | ||||
* If the recursion isn't at the immediate | * Stash the root basename off for detecting recursion later. | ||||
* level, we can just not traverse into this | * | ||||
* directory. | * This will be essential if the root is a symlink and we're | ||||
* rolling with -L or -H. The later bits will need this bit in | |||||
* particular. | |||||
*/ | */ | ||||
fts_set(ftsp, curr, FTS_SKIP); | if (curr->fts_level == FTS_ROOTLEVEL) { | ||||
continue; | strlcpy(rootname, curr->fts_name, sizeof(rootname)); | ||||
} else { | |||||
const char *slash; | |||||
/* | |||||
* Grab the last path component and double it, | |||||
* to make life easier later and ensure that | |||||
* we work even with fts_level == 0 is a couple | |||||
* of components deep in fts_path. No path | |||||
* separators are fine and expected in the | |||||
* common case, though. | |||||
*/ | |||||
slash = strrchr(curr->fts_path, '/'); | |||||
if (slash != NULL) | |||||
slash++; | |||||
else | |||||
slash = curr->fts_path; | |||||
if (asprintf(&recurse_path, "%s/%s", | |||||
curr->fts_path, slash) == -1) | |||||
err(1, "asprintf"); | |||||
} | } | ||||
} | |||||
if (recurse_path != NULL && | |||||
strcmp(curr->fts_path, recurse_path) == 0) { | |||||
fts_set(ftsp, curr, FTS_SKIP); | |||||
continue; | |||||
} | |||||
/* | /* | ||||
* If we are in case (2) or (3) above, we need to append the | * If we are in case (2) or (3) above, we need to append the | ||||
* source name to the target name. | * source name to the target name. | ||||
*/ | */ | ||||
if (type != FILE_TO_FILE) { | if (type != FILE_TO_FILE) { | ||||
/* | /* | ||||
* Need to remember the roots of traversals to create | * Need to remember the roots of traversals to create | ||||
* correct pathnames. If there's a directory being | * correct pathnames. If there's a directory being | ||||
Show All 37 Lines | if (type != FILE_TO_FILE) { | ||||
to.p_path, p); | to.p_path, p); | ||||
badcp = rval = 1; | badcp = rval = 1; | ||||
continue; | continue; | ||||
} | } | ||||
(void)strncat(target_mid, p, nlen); | (void)strncat(target_mid, p, nlen); | ||||
to.p_end = target_mid + nlen; | to.p_end = target_mid + nlen; | ||||
*to.p_end = 0; | *to.p_end = 0; | ||||
STRIP_TRAILING_SLASH(to); | STRIP_TRAILING_SLASH(to); | ||||
/* | |||||
* We're on the verge of recursing on ourselves. Either | |||||
* we need to stop right here (we knowingly just created | |||||
* it), or we will in an immediate descendant. Record | |||||
* the path of the immediate descendant to make our | |||||
* lives a little less complicated looking. | |||||
*/ | |||||
if (curr->fts_info == FTS_D && root_stat != NULL && | |||||
root_stat->st_dev == curr->fts_statp->st_dev && | |||||
root_stat->st_ino == curr->fts_statp->st_ino) { | |||||
assert(recurse_path == NULL); | |||||
if (root_stat == &created_root_stat) { | |||||
/* | |||||
* This directory didn't exist when we | |||||
* started, we created it as part of | |||||
* traversal. Stop right here before we | |||||
* do something silly. | |||||
*/ | |||||
fts_set(ftsp, curr, FTS_SKIP); | |||||
continue; | |||||
} | |||||
if (asprintf(&recurse_path, "%s/%s", to.p_path, | |||||
rootname) == -1) | |||||
err(1, "asprintf"); | |||||
} | |||||
if (recurse_path != NULL && | |||||
strcmp(to.p_path, recurse_path) == 0) { | |||||
fts_set(ftsp, curr, FTS_SKIP); | |||||
continue; | |||||
} | |||||
} | } | ||||
if (curr->fts_info == FTS_DP) { | if (curr->fts_info == FTS_DP) { | ||||
/* | /* | ||||
* We are nearly finished with this directory. If we | * We are nearly finished with this directory. If we | ||||
* didn't actually copy it, or otherwise don't need to | * didn't actually copy it, or otherwise don't need to | ||||
* change its attributes, then we are done. | * change its attributes, then we are done. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 155 Lines • Show Last 20 Lines |