enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
static int copy(char *[], enum op, int);
-static int mastercmp(const FTSENT * const *, const FTSENT * const *);
static void siginfo(int __unused);
int
char *target;
Hflag = Lflag = Pflag = 0;
- while ((ch = getopt(argc, argv, "HLPRXfinprv")) != -1)
+ while ((ch = getopt(argc, argv, "HLPRXafinprv")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
case 'v':
vflag = 1;
break;
+ case 'a':
+ pflag = 1;
+ Pflag = 1;
+ Rflag = 1;
+ break;
default:
usage();
break;
case FTS_ERR:
warnx("%s: %s",
curr->fts_path, strerror(curr->fts_errno));
- badcp = rval = 1;
+ rval = 1;
continue;
case FTS_DC: /* Warn, continue. */
warnx("%s: directory causes a cycle", curr->fts_path);
- badcp = rval = 1;
+ rval = 1;
continue;
default:
;
}
+#ifdef __APPLE__
+#ifdef __clang__
+#pragma clang diagnostic push
+/* clang doesn't like fts_name[1], but we know better... */
+#pragma clang diagnostic ignored "-Warray-bounds"
+#endif
+ /* Skip ._<file> when using copyfile and <file> exists */
+ if ((pflag || !Xflag) && (curr->fts_level != FTS_ROOTLEVEL) &&
+ (curr->fts_namelen > 2) && /* ._\0 is not AppleDouble */
+ (curr->fts_name[0] == '.') && (curr->fts_name[1] == '_')) {
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ struct stat statbuf;
+ char path[PATH_MAX];
+ char *p = strrchr(curr->fts_path, '/');
+ if (p) {
+ size_t s = p + 2 - curr->fts_path;
+ if (s > sizeof(path)) s = sizeof(path);
+ strlcpy(path, curr->fts_path, s);
+ strlcat(path, curr->fts_name+2, sizeof(path));
+ } else {
+ strlcpy(path, curr->fts_name+2, sizeof(path));
+ }
+ if (!lstat(path, &statbuf)) {
+ continue;
+ }
+ }
+#endif /* __APPLE__ */
/*
* If we are in case (2) or (3) above, we need to append the
* source name to the target name.
if (target_mid - to.p_path + nlen >= PATH_MAX) {
warnx("%s%s: name too long (not copied)",
to.p_path, p);
- badcp = rval = 1;
+ rval = 1;
continue;
}
(void)strncat(target_mid, p, nlen);
to_stat.st_ino == curr->fts_statp->st_ino) {
warnx("%s and %s are identical (not copied).",
to.p_path, curr->fts_path);
- badcp = rval = 1;
+ rval = 1;
if (S_ISDIR(curr->fts_statp->st_mode))
(void)fts_set(ftsp, curr, FTS_SKIP);
continue;
warnx("cannot overwrite directory %s with "
"non-directory %s",
to.p_path, curr->fts_path);
- badcp = rval = 1;
+ rval = 1;
continue;
}
dne = 0;
*/
if (dne) {
if (mkdir(to.p_path,
- curr->fts_statp->st_mode | S_IRWXU) < 0)
+ curr->fts_statp->st_mode | S_IRWXU) < 0) {
if (COMPAT_MODE("bin/cp", "unix2003")) {
warn("%s", to.p_path);
} else {
err(1, "%s", to.p_path);
}
+ }
} else if (!S_ISDIR(to_stat.st_mode)) {
errno = ENOTDIR;
if (COMPAT_MODE("bin/cp", "unix2003")) {
return (rval);
}
-/*
- * mastercmp --
- * The comparison function for the copy order. The order is to copy
- * non-directory files before directory files. The reason for this
- * is because files tend to be in the same cylinder group as their
- * parent directory, whereas directories tend not to be. Copying the
- * files first reduces seeking.
- */
-static int
-mastercmp(const FTSENT * const *a, const FTSENT * const *b)
-{
- int a_info, b_info;
-
- a_info = (*a)->fts_info;
- if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
- return (0);
- b_info = (*b)->fts_info;
- if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
- return (0);
- if (a_info == FTS_D)
- return (-1);
- if (b_info == FTS_D)
- return (1);
- return (0);
-}
-
static void
siginfo(int sig __unused)
{