summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbdrewery <bdrewery@FreeBSD.org>2015-06-07 06:30:25 +0000
committerbdrewery <bdrewery@FreeBSD.org>2015-06-07 06:30:25 +0000
commit4e68976c74c31df589e6df98a36af08d01812eb3 (patch)
treef14fc15dd11f8aa22eae8093c31c9482a73ff4e6
parent939189542ecd10392ffaf53f33e9ea26735a3b84 (diff)
downloadFreeBSD-src-4e68976c74c31df589e6df98a36af08d01812eb3.zip
FreeBSD-src-4e68976c74c31df589e6df98a36af08d01812eb3.tar.gz
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
-rw-r--r--bin/cp/cp.113
-rw-r--r--bin/cp/cp.c13
-rw-r--r--bin/cp/extern.h2
-rw-r--r--bin/cp/utils.c46
4 files changed, 46 insertions, 28 deletions
diff --git a/bin/cp/cp.1 b/bin/cp/cp.1
index 169f350..9bbd9d6 100644
--- a/bin/cp/cp.1
+++ b/bin/cp/cp.1
@@ -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.
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 2ad5f4a..18eb52e 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -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 {
diff --git a/bin/cp/extern.h b/bin/cp/extern.h
index 94c416b..f8c20da 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, iflag, lflag, nflag, pflag, sflag, vflag;
extern volatile sig_atomic_t info;
__BEGIN_DECLS
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index f8cf6f4..a383713 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -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);
}
OpenPOWER on IntegriCloud