Implement '-s' to copy as symlink, similar to the current -l link(2) handling.

This is also implemented in at least GNU coreutils cp.

While here also improve the '-l' handling to not open(2) the source file as
it does not actually need the descriptor.

Sponsored by:	EMC / Isilon Storage Division
This commit is contained in:
Bryan Drewery 2015-06-07 06:30:25 +00:00
parent 14376e1f21
commit 7ea2450f42
4 changed files with 46 additions and 28 deletions

View File

@ -32,7 +32,7 @@
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd March 15, 2013
.Dd June 6, 2015
.Dt CP 1
.Os
.Sh NAME
@ -45,7 +45,7 @@
.Op Fl H | Fl L | Fl P
.Oc
.Op Fl f | i | n
.Op Fl alpvx
.Op Fl alpsvx
.Ar source_file target_file
.Nm
.Oo
@ -53,7 +53,7 @@
.Op Fl H | Fl L | Fl P
.Oc
.Op Fl f | i | n
.Op Fl alpvx
.Op Fl alpsvx
.Ar source_file ... target_directory
.Sh DESCRIPTION
In the first synopsis form, the
@ -179,6 +179,8 @@ If the source file has both its set-user-ID and set-group-ID bits on,
and either the user ID or group ID cannot be preserved, neither
the set-user-ID nor set-group-ID bits are preserved in the copy's
permissions.
.It Fl s
Create symbolic links to regular files in a hierarchy instead of copying.
.It Fl v
Cause
.Nm
@ -298,7 +300,10 @@ differ as they copy special files as normal
files while recreating a hierarchy.
.Pp
The
.Fl v
.Fl l,
.Fl s,
.Fl v,
.Fl x
and
.Fl n
options are non-standard and their use in scripts is not recommended.

View File

@ -83,7 +83,7 @@ static char emptystring[] = "";
PATH_T to = { to.p_path, emptystring, "" };
int fflag, iflag, lflag, nflag, pflag, vflag;
int fflag, iflag, lflag, nflag, pflag, sflag, vflag;
static int Rflag, rflag;
volatile sig_atomic_t info;
@ -102,7 +102,7 @@ main(int argc, char *argv[])
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
Hflag = Lflag = 0;
while ((ch = getopt(argc, argv, "HLPRafilnprvx")) != -1)
while ((ch = getopt(argc, argv, "HLPRafilnprsvx")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@ -145,6 +145,9 @@ main(int argc, char *argv[])
rflag = Lflag = 1;
Hflag = 0;
break;
case 's':
sflag = 1;
break;
case 'v':
vflag = 1;
break;
@ -163,6 +166,8 @@ main(int argc, char *argv[])
if (Rflag && rflag)
errx(1, "the -R and -r options may not be specified together");
if (lflag && sflag)
errx(1, "the -l and -s options may not be specified together");
if (rflag)
Rflag = 1;
if (Rflag) {
@ -452,7 +457,7 @@ copy(char *argv[], enum op type, int fts_options)
break;
case S_IFBLK:
case S_IFCHR:
if (Rflag) {
if (Rflag && !sflag) {
if (copy_special(curr->fts_statp, !dne))
badcp = rval = 1;
} else {
@ -465,7 +470,7 @@ copy(char *argv[], enum op type, int fts_options)
curr->fts_path);
break;
case S_IFIFO:
if (Rflag) {
if (Rflag && !sflag) {
if (copy_fifo(curr->fts_statp, !dne))
badcp = rval = 1;
} else {

View File

@ -37,7 +37,7 @@ typedef struct {
} PATH_T;
extern PATH_T to;
extern int fflag, iflag, lflag, nflag, pflag, vflag;
extern int fflag, iflag, lflag, nflag, pflag, sflag, vflag;
extern volatile sig_atomic_t info;
__BEGIN_DECLS

View File

@ -77,13 +77,15 @@ copy_file(const FTSENT *entp, int dne)
ssize_t wcount;
size_t wresid;
off_t wtotal;
int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
int ch, checkch, from_fd, rcount, rval, to_fd;
char *bufp;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
char *p;
#endif
if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
from_fd = to_fd = -1;
if (!lflag && !sflag &&
(from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
warn("%s", entp->fts_path);
return (1);
}
@ -103,8 +105,8 @@ copy_file(const FTSENT *entp, int dne)
if (nflag) {
if (vflag)
printf("%s not overwritten\n", to.p_path);
(void)close(from_fd);
return (1);
rval = 1;
goto done;
} else if (iflag) {
(void)fprintf(stderr, "overwrite %s? %s",
to.p_path, YESNO);
@ -112,9 +114,9 @@ copy_file(const FTSENT *entp, int dne)
while (ch != '\n' && ch != EOF)
ch = getchar();
if (checkch != 'y' && checkch != 'Y') {
(void)close(from_fd);
(void)fprintf(stderr, "not overwritten\n");
return (1);
rval = 1;
goto done;
}
}
@ -122,28 +124,28 @@ copy_file(const FTSENT *entp, int dne)
/* remove existing destination file name,
* create a new file */
(void)unlink(to.p_path);
if (!lflag) {
if (!lflag && !sflag) {
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
fs->st_mode & ~(S_ISUID | S_ISGID));
}
} else if (!lflag) {
} else if (!lflag && !sflag) {
/* overwrite existing destination file name */
to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
}
} else if (!lflag) {
} else if (!lflag && !sflag) {
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
fs->st_mode & ~(S_ISUID | S_ISGID));
}
if (to_fd == -1) {
if (!lflag && !sflag && to_fd == -1) {
warn("%s", to.p_path);
(void)close(from_fd);
return (1);
rval = 1;
goto done;
}
rval = 0;
if (!lflag) {
if (!lflag && !sflag) {
/*
* Mmap and write if less than 8M (the limit is so we don't totally
* trash memory on big files. This is really a minor hack, but it
@ -229,11 +231,16 @@ copy_file(const FTSENT *entp, int dne)
rval = 1;
}
}
} else {
} else if (lflag) {
if (link(entp->fts_path, to.p_path)) {
warn("%s", to.p_path);
rval = 1;
}
} else if (sflag) {
if (symlink(entp->fts_path, to.p_path)) {
warn("%s", to.p_path);
rval = 1;
}
}
/*
@ -243,7 +250,7 @@ copy_file(const FTSENT *entp, int dne)
* to remove it if we created it and its length is 0.
*/
if (!lflag) {
if (!lflag && !sflag) {
if (pflag && setfile(fs, to_fd))
rval = 1;
if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
@ -254,8 +261,9 @@ copy_file(const FTSENT *entp, int dne)
}
}
(void)close(from_fd);
done:
if (from_fd != -1)
(void)close(from_fd);
return (rval);
}
@ -535,8 +543,8 @@ usage(void)
{
(void)fprintf(stderr, "%s\n%s\n",
"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file target_file",
" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file ... "
"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file target_file",
" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file ... "
"target_directory");
exit(EX_USAGE);
}