diff --git a/bin/cp/cp.c b/bin/cp/cp.c index b83eead..a5a6d84 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -83,8 +83,8 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; -int fflag, iflag, lflag, nflag, pflag, vflag; -static int Rflag, rflag; +int fflag, Hflag, iflag, Lflag, lflag, nflag, pflag, Rflag, vflag; +static int rflag; volatile sig_atomic_t info; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; @@ -98,7 +98,7 @@ main(int argc, char *argv[]) { struct stat to_stat, tmp_stat; enum op type; - int Hflag, Lflag, ch, fts_options, r, have_trailing_slash; + int ch, fts_options, r, have_trailing_slash; char *target; fts_options = FTS_NOCHDIR | FTS_PHYSICAL; @@ -383,10 +383,9 @@ copy(char *argv[], enum op type, int fts_options) continue; } - /* Not an error but need to remember it happened */ - if (stat(to.p_path, &to_stat) == -1) - dne = 1; - else { + dne = (stat_tofile(curr->fts_statp, &to_stat) != 0); + + if (!dne) { if (to_stat.st_dev == curr->fts_statp->st_dev && to_stat.st_ino == curr->fts_statp->st_ino) { warnx("%s and %s are identical (not copied).", diff --git a/bin/cp/extern.h b/bin/cp/extern.h index 94c416b..ef6bd67 100644 --- a/bin/cp/extern.h +++ b/bin/cp/extern.h @@ -37,7 +37,7 @@ typedef struct { } PATH_T; extern PATH_T to; -extern int fflag, iflag, lflag, nflag, pflag, vflag; +extern int fflag, Hflag, iflag, Lflag, lflag, nflag, pflag, Rflag, vflag; extern volatile sig_atomic_t info; __BEGIN_DECLS @@ -48,5 +48,6 @@ int copy_special(struct stat *, int); int setfile(struct stat *, int); int preserve_dir_acls(struct stat *, char *, char *); int preserve_fd_acls(int, int); +int stat_tofile(const struct stat *, struct stat *); void usage(void); __END_DECLS diff --git a/bin/cp/utils.c b/bin/cp/utils.c index 96ca12d..5ee37c0 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -532,6 +532,27 @@ preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir) return (0); } +int +stat_tofile(const struct stat *srcsb, struct stat *dstsb) +{ + struct stat sb; + int dangling; + + dangling = (lstat(to.p_path, &sb) == 0) && (stat(to.p_path, &sb) == -1); + + if (vflag && dangling) + printf("destination '%s' is a dangling symlink\n", to.p_path); + + /* + * If the destination file is a dangling symlink, make it possible to + * create new files by copying through that symlink. + */ + if ((dangling && S_ISREG(srcsb->st_mode)) || Hflag || Lflag) + return (stat(to.p_path, dstsb)); + else + return (lstat(to.p_path, dstsb)); +} + void usage(void) {