MFC r284105,r284106,r284163:
r284105: Cleanup some indentation issues. r284106: Implement '-s' to copy as symlink, similar to the current -l link(2) handling. r284163: Cleanup some style(9) issues. Relnotes: yes
This commit is contained in:
parent
b490558ee6
commit
1c5b4d7b40
13
bin/cp/cp.1
13
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.
|
||||
|
40
bin/cp/cp.c
40
bin/cp/cp.c
@ -75,15 +75,15 @@ __FBSDID("$FreeBSD$");
|
||||
#include "extern.h"
|
||||
|
||||
#define STRIP_TRAILING_SLASH(p) { \
|
||||
while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
|
||||
*--(p).p_end = 0; \
|
||||
while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
|
||||
*--(p).p_end = 0; \
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -183,7 +188,7 @@ main(int argc, char *argv[])
|
||||
if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
|
||||
errx(1, "%s: name too long", target);
|
||||
to.p_end = to.p_path + strlen(to.p_path);
|
||||
if (to.p_path == to.p_end) {
|
||||
if (to.p_path == to.p_end) {
|
||||
*to.p_end++ = '.';
|
||||
*to.p_end = 0;
|
||||
}
|
||||
@ -240,10 +245,10 @@ main(int argc, char *argv[])
|
||||
type = FILE_TO_FILE;
|
||||
|
||||
if (have_trailing_slash && type == FILE_TO_FILE) {
|
||||
if (r == -1)
|
||||
if (r == -1) {
|
||||
errx(1, "directory %s does not exist",
|
||||
to.p_path);
|
||||
else
|
||||
to.p_path);
|
||||
} else
|
||||
errx(1, "%s is not a directory", to.p_path);
|
||||
}
|
||||
} else
|
||||
@ -294,8 +299,8 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
|
||||
/*
|
||||
* If we are in case (2) or (3) above, we need to append the
|
||||
* source name to the target name.
|
||||
*/
|
||||
* source name to the target name.
|
||||
*/
|
||||
if (type != FILE_TO_FILE) {
|
||||
/*
|
||||
* Need to remember the roots of traversals to create
|
||||
@ -374,7 +379,8 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
mode = curr->fts_statp->st_mode;
|
||||
if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
|
||||
((mode | S_IRWXU) & mask) != (mode & mask))
|
||||
if (chmod(to.p_path, mode & mask) != 0){
|
||||
if (chmod(to.p_path, mode & mask) !=
|
||||
0) {
|
||||
warn("chmod: %s", to.p_path);
|
||||
rval = 1;
|
||||
}
|
||||
@ -382,7 +388,7 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not an error but need to remember it happened */
|
||||
/* Not an error but need to remember it happened. */
|
||||
if (stat(to.p_path, &to_stat) == -1)
|
||||
dne = 1;
|
||||
else {
|
||||
@ -408,7 +414,7 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
|
||||
switch (curr->fts_statp->st_mode & S_IFMT) {
|
||||
case S_IFLNK:
|
||||
/* Catch special case of a non-dangling symlink */
|
||||
/* Catch special case of a non-dangling symlink. */
|
||||
if ((fts_options & FTS_LOGICAL) ||
|
||||
((fts_options & FTS_COMFOLLOW) &&
|
||||
curr->fts_level == 0)) {
|
||||
@ -433,7 +439,7 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
* modified by the umask. Trade-off between being
|
||||
* able to write the directory (if from directory is
|
||||
* 555) and not causing a permissions race. If the
|
||||
* umask blocks owner writes, we fail..
|
||||
* umask blocks owner writes, we fail.
|
||||
*/
|
||||
if (dne) {
|
||||
if (mkdir(to.p_path,
|
||||
@ -452,7 +458,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 {
|
||||
@ -462,10 +468,10 @@ copy(char *argv[], enum op type, int fts_options)
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
warnx("%s is a socket (not copied).",
|
||||
curr->fts_path);
|
||||
curr->fts_path);
|
||||
break;
|
||||
case S_IFIFO:
|
||||
if (Rflag) {
|
||||
if (Rflag && !sflag) {
|
||||
if (copy_fifo(curr->fts_statp, !dne))
|
||||
badcp = rval = 1;
|
||||
} else {
|
||||
|
@ -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
|
||||
|
114
bin/cp/utils.c
114
bin/cp/utils.c
@ -57,15 +57,19 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y)))
|
||||
|
||||
/* Memory strategy threshold, in pages: if physmem is larger then this, use a
|
||||
* large buffer */
|
||||
/*
|
||||
* Memory strategy threshold, in pages: if physmem is larger then this, use a
|
||||
* large buffer.
|
||||
*/
|
||||
#define PHYSPAGES_THRESHOLD (32*1024)
|
||||
|
||||
/* Maximum buffer size in bytes - do not allow it to grow larger than this */
|
||||
/* Maximum buffer size in bytes - do not allow it to grow larger than this. */
|
||||
#define BUFSIZE_MAX (2*1024*1024)
|
||||
|
||||
/* Small (default) buffer size in bytes. It's inefficient for this to be
|
||||
* smaller than MAXPHYS */
|
||||
/*
|
||||
* Small (default) buffer size in bytes. It's inefficient for this to be
|
||||
* smaller than MAXPHYS.
|
||||
*/
|
||||
#define BUFSIZE_SMALL (MAXPHYS)
|
||||
|
||||
int
|
||||
@ -77,13 +81,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,63 +109,65 @@ 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);
|
||||
to.p_path, YESNO);
|
||||
checkch = ch = getchar();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fflag) {
|
||||
/* remove existing destination file name,
|
||||
* create a new file */
|
||||
(void)unlink(to.p_path);
|
||||
if (!lflag)
|
||||
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
|
||||
fs->st_mode & ~(S_ISUID | S_ISGID));
|
||||
} else {
|
||||
if (!lflag)
|
||||
/* overwrite existing destination file name */
|
||||
to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
|
||||
/*
|
||||
* Remove existing destination file name create a new
|
||||
* file.
|
||||
*/
|
||||
(void)unlink(to.p_path);
|
||||
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 && !sflag) {
|
||||
/* Overwrite existing destination file name. */
|
||||
to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
|
||||
}
|
||||
} else {
|
||||
if (!lflag)
|
||||
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
|
||||
fs->st_mode & ~(S_ISUID | S_ISGID));
|
||||
} 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
|
||||
* wins some CPU back.
|
||||
* 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 wins some CPU back.
|
||||
* Some filesystems, such as smbnetfs, don't support mmap,
|
||||
* so this is a best-effort attempt.
|
||||
*/
|
||||
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
|
||||
if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
|
||||
fs->st_size <= 8 * 1024 * 1024 &&
|
||||
fs->st_size <= 8 * 1024 * 1024 &&
|
||||
(p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
|
||||
MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
|
||||
wtotal = 0;
|
||||
for (bufp = p, wresid = fs->st_size; ;
|
||||
bufp += wcount, wresid -= (size_t)wcount) {
|
||||
bufp += wcount, wresid -= (size_t)wcount) {
|
||||
wcount = write(to_fd, bufp, wresid);
|
||||
if (wcount <= 0)
|
||||
break;
|
||||
@ -204,7 +212,7 @@ copy_file(const FTSENT *entp, int dne)
|
||||
wtotal = 0;
|
||||
while ((rcount = read(from_fd, buf, bufsize)) > 0) {
|
||||
for (bufp = buf, wresid = rcount; ;
|
||||
bufp += wcount, wresid -= wcount) {
|
||||
bufp += wcount, wresid -= wcount) {
|
||||
wcount = write(to_fd, bufp, wresid);
|
||||
if (wcount <= 0)
|
||||
break;
|
||||
@ -230,13 +238,18 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Don't remove the target even after an error. The target might
|
||||
* not be a regular file, or its attributes might be important,
|
||||
@ -244,7 +257,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)
|
||||
@ -255,8 +268,9 @@ copy_file(const FTSENT *entp, int dne)
|
||||
}
|
||||
}
|
||||
|
||||
(void)close(from_fd);
|
||||
|
||||
done:
|
||||
if (from_fd != -1)
|
||||
(void)close(from_fd);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
@ -338,7 +352,7 @@ setfile(struct stat *fs, int fd)
|
||||
fdval = fd != -1;
|
||||
islink = !fdval && S_ISLNK(fs->st_mode);
|
||||
fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX |
|
||||
S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim);
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim);
|
||||
@ -352,7 +366,7 @@ setfile(struct stat *fs, int fd)
|
||||
else {
|
||||
gotstat = 1;
|
||||
ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
|
||||
S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
}
|
||||
/*
|
||||
* Changing the ownership probably won't succeed, unless we're root
|
||||
@ -476,7 +490,7 @@ preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the file is a link we will not follow it
|
||||
* If the file is a link we will not follow it.
|
||||
*/
|
||||
if (S_ISLNK(fs->st_mode)) {
|
||||
aclgetf = acl_get_link_np;
|
||||
@ -535,8 +549,10 @@ 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 ... "
|
||||
"target_directory");
|
||||
"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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user