diff --git a/bin/cp/cp.c b/bin/cp/cp.c --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -183,7 +183,12 @@ sep--; *sep = '\0'; } - if (strlcpy(to.base, target, sizeof(to.base)) >= sizeof(to.base)) + /* + * Copy target into to.base, leaving room for a possible separator + * which will be appended later in the non-FILE_TO_FILE cases. + */ + if (strlcpy(to.base, target, sizeof(to.base) - 1) >= + sizeof(to.base) - 1) errc(1, ENAMETOOLONG, "%s", target); /* Set end of argument list for fts(3). */ @@ -264,7 +269,7 @@ struct stat created_root_stat, to_stat, *curr_stat; FTS *ftsp; FTSENT *curr; - char *recpath = NULL; + char *recpath = NULL, *sep; int atflags, dne, badcp, len, rval; mode_t mask, mode; bool beneath = Rflag && type != FILE_TO_FILE; @@ -280,11 +285,17 @@ if (type == FILE_TO_FILE) { to.dir = AT_FDCWD; to.end = to.path + strlcpy(to.path, to.base, sizeof(to.path)); - strlcpy(to.base, dot, sizeof(to.base)); + to.base[0] = '\0'; } else if (type == FILE_TO_DIR) { to.dir = open(to.base, O_DIRECTORY | O_SEARCH); if (to.dir < 0) err(1, "%s", to.base); + /* + * We have previously made sure there is room for this. + */ + sep = strchr(to.base, '\0'); + sep[0] = '/'; + sep[1] = '\0'; } if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) @@ -370,13 +381,20 @@ umask(~mask); root_stat = &created_root_stat; curr->fts_number = 1; + /* + * We have previously made sure there is + * room for this. + */ + sep = strchr(to.base, '\0'); + sep[0] = '/'; + sep[1] = '\0'; } else { /* entering a directory; append its name to to.path */ len = snprintf(to.end, END(to.path) - to.end, "%s%s", to.end > to.path ? "/" : "", curr->fts_name); if (to.end + len >= END(to.path)) { *to.end = '\0'; - warnc(ENAMETOOLONG, "%s/%s%s%s", to.base, + warnc(ENAMETOOLONG, "%s%s%s%s", to.base, to.path, to.end > to.path ? "/" : "", curr->fts_name); fts_set(ftsp, curr, FTS_SKIP); @@ -448,7 +466,7 @@ const char *path = *to.path ? to.path : dot; mode = curr_stat->st_mode; if (fchmodat(to.dir, path, mode & mask, 0) != 0) { - warn("chmod: %s/%s", to.base, to.path); + warn("chmod: %s%s", to.base, to.path); rval = 1; } } @@ -474,7 +492,7 @@ to.end > to.path ? "/" : "", curr->fts_name); if (to.end + len >= END(to.path)) { *to.end = '\0'; - warnc(ENAMETOOLONG, "%s/%s%s%s", to.base, + warnc(ENAMETOOLONG, "%s%s%s%s", to.base, to.path, to.end > to.path ? "/" : "", curr->fts_name); badcp = rval = 1; @@ -506,7 +524,7 @@ if (!dne && to_stat.st_dev == curr_stat->st_dev && to_stat.st_ino == curr_stat->st_ino) { - warnx("%s/%s and %s are identical (not copied).", + warnx("%s%s and %s are identical (not copied).", to.base, to.path, curr->fts_path); badcp = rval = 1; if (S_ISDIR(curr_stat->st_mode)) @@ -558,7 +576,7 @@ if (~mask & S_IRWXU) umask(~mask & ~S_IRWXU); if (mkdirat(to.dir, to.path, mode) != 0) { - warn("%s/%s", to.base, to.path); + warn("%s%s", to.base, to.path); fts_set(ftsp, curr, FTS_SKIP); badcp = rval = 1; if (~mask & S_IRWXU) @@ -568,7 +586,7 @@ if (~mask & S_IRWXU) umask(~mask); } else if (!S_ISDIR(to_stat.st_mode)) { - warnc(ENOTDIR, "%s/%s", to.base, to.path); + warnc(ENOTDIR, "%s%s", to.base, to.path); fts_set(ftsp, curr, FTS_SKIP); badcp = rval = 1; break; @@ -611,7 +629,7 @@ break; } if (vflag && !badcp) - (void)printf("%s -> %s/%s\n", curr->fts_path, to.base, to.path); + (void)printf("%s -> %s%s\n", curr->fts_path, to.base, to.path); } if (errno) err(1, "fts_read"); diff --git a/bin/cp/extern.h b/bin/cp/extern.h --- a/bin/cp/extern.h +++ b/bin/cp/extern.h @@ -31,8 +31,8 @@ typedef struct { int dir; /* base directory handle */ + char base[PATH_MAX + 1]; /* base directory path */ char *end; /* pointer to NUL at end of path */ - char base[PATH_MAX]; /* base directory path */ char path[PATH_MAX]; /* target path */ } PATH_T; diff --git a/bin/cp/utils.c b/bin/cp/utils.c --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -143,12 +143,12 @@ if (!dne) { if (nflag) { if (vflag) - printf("%s/%s not overwritten\n", + printf("%s%s not overwritten\n", to.base, to.path); rval = 1; goto done; } else if (iflag) { - (void)fprintf(stderr, "overwrite %s/%s? %s", + (void)fprintf(stderr, "overwrite %s%s? %s", to.base, to.path, YESNO); checkch = ch = getchar(); while (ch != '\n' && ch != EOF) @@ -172,7 +172,7 @@ if (lflag) { if (linkat(AT_FDCWD, entp->fts_path, to.dir, to.path, 0) != 0) { - warn("%s/%s", to.base, to.path); + warn("%s%s", to.base, to.path); rval = 1; } goto done; @@ -180,7 +180,7 @@ if (sflag) { if (symlinkat(entp->fts_path, to.dir, to.path) != 0) { - warn("%s/%s", to.base, to.path); + warn("%s%s", to.base, to.path); rval = 1; } goto done; @@ -198,7 +198,7 @@ fs->st_mode & ~(S_ISUID | S_ISGID)); } if (to_fd == -1) { - warn("%s/%s", to.base, to.path); + warn("%s%s", to.base, to.path); rval = 1; goto done; } @@ -220,7 +220,7 @@ if (info) { info = 0; (void)fprintf(stderr, - "%s -> %s/%s %3d%%\n", + "%s -> %s%s %3d%%\n", entp->fts_path, to.base, to.path, cp_pct(wtotal, fs->st_size)); } @@ -241,7 +241,7 @@ if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) rval = 1; if (close(to_fd)) { - warn("%s/%s", to.base, to.path); + warn("%s%s", to.base, to.path); rval = 1; } @@ -260,7 +260,7 @@ if (!dne && nflag) { if (vflag) - printf("%s/%s not overwritten\n", to.base, to.path); + printf("%s%s not overwritten\n", to.base, to.path); return (1); } if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) { @@ -269,7 +269,7 @@ } llink[len] = '\0'; if (!dne && unlinkat(to.dir, to.path, atflags) != 0) { - warn("unlink: %s/%s", to.base, to.path); + warn("unlink: %s%s", to.base, to.path); return (1); } if (symlinkat(llink, to.dir, to.path) != 0) { @@ -286,15 +286,15 @@ if (!dne && nflag) { if (vflag) - printf("%s/%s not overwritten\n", to.base, to.path); + printf("%s%s not overwritten\n", to.base, to.path); return (1); } if (!dne && unlinkat(to.dir, to.path, atflags) != 0) { - warn("unlink: %s/%s", to.base, to.path); + warn("unlink: %s%s", to.base, to.path); return (1); } if (mkfifoat(to.dir, to.path, from_stat->st_mode) != 0) { - warn("mkfifo: %s/%s", to.base, to.path); + warn("mkfifo: %s%s", to.base, to.path); return (1); } return (pflag ? setfile(from_stat, -1, beneath) : 0); @@ -307,15 +307,15 @@ if (!dne && nflag) { if (vflag) - printf("%s/%s not overwritten\n", to.base, to.path); + printf("%s%s not overwritten\n", to.base, to.path); return (1); } if (!dne && unlinkat(to.dir, to.path, atflags) != 0) { - warn("unlink: %s/%s", to.base, to.path); + warn("unlink: %s%s", to.base, to.path); return (1); } if (mknodat(to.dir, to.path, from_stat->st_mode, from_stat->st_rdev) != 0) { - warn("mknod: %s/%s", to.base, to.path); + warn("mknod: %s%s", to.base, to.path); return (1); } return (pflag ? setfile(from_stat, -1, beneath) : 0); @@ -341,7 +341,7 @@ tspec[1] = fs->st_mtim; if (fdval ? futimens(fd, tspec) : utimensat(to.dir, to.path, tspec, atflags)) { - warn("utimensat: %s/%s", to.base, to.path); + warn("utimensat: %s%s", to.base, to.path); rval = 1; } if (fdval ? fstat(fd, &ts) : @@ -362,7 +362,7 @@ if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : fchownat(to.dir, to.path, fs->st_uid, fs->st_gid, atflags)) { if (errno != EPERM) { - warn("chown: %s/%s", to.base, to.path); + warn("chown: %s%s", to.base, to.path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); @@ -372,7 +372,7 @@ if (!gotstat || fs->st_mode != ts.st_mode) { if (fdval ? fchmod(fd, fs->st_mode) : fchmodat(to.dir, to.path, fs->st_mode, atflags)) { - warn("chmod: %s/%s", to.base, to.path); + warn("chmod: %s%s", to.base, to.path); rval = 1; } } @@ -388,7 +388,7 @@ * that we copied, i.e., that we didn't create.) */ if (errno != EOPNOTSUPP || fs->st_flags != 0) { - warn("chflags: %s/%s", to.base, to.path); + warn("chflags: %s%s", to.base, to.path); rval = 1; } } @@ -409,7 +409,7 @@ acl_supported = 1; acl_type = ACL_TYPE_NFS4; } else if (ret < 0 && errno != EINVAL) { - warn("fpathconf(..., _PC_ACL_NFS4) failed for %s/%s", + warn("fpathconf(..., _PC_ACL_NFS4) failed for %s%s", to.base, to.path); return (-1); } @@ -419,7 +419,7 @@ acl_supported = 1; acl_type = ACL_TYPE_ACCESS; } else if (ret < 0 && errno != EINVAL) { - warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s/%s", + warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s%s", to.base, to.path); return (-1); } @@ -429,12 +429,12 @@ acl = acl_get_fd_np(source_fd, acl_type); if (acl == NULL) { - warn("failed to get acl entries while setting %s/%s", + warn("failed to get acl entries while setting %s%s", to.base, to.path); return (-1); } if (acl_is_trivial_np(acl, &trivial)) { - warn("acl_is_trivial() failed for %s/%s", + warn("acl_is_trivial() failed for %s%s", to.base, to.path); acl_free(acl); return (-1); @@ -444,7 +444,7 @@ return (0); } if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) { - warn("failed to set acl entries for %s/%s", + warn("failed to set acl entries for %s%s", to.base, to.path); acl_free(acl); return (-1); @@ -465,7 +465,7 @@ dest_fd = (*dest_dir == '\0') ? to.dir : openat(to.dir, dest_dir, O_DIRECTORY, AT_RESOLVE_BENEATH); if (dest_fd < 0) { - warn("%s: failed to copy ACLs to %s/%s", source_dir, + warn("%s: failed to copy ACLs to %s%s", source_dir, to.base, dest_dir); close(source_fd); return (-1);