Changeset View
Changeset View
Standalone View
Standalone View
bin/cp/utils.c
Show All 35 Lines | |||||
#endif /* not lint */ | #endif /* not lint */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/acl.h> | #include <sys/acl.h> | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED | |||||
#include <sys/mman.h> | |||||
#endif | |||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <fts.h> | #include <fts.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
Show All 15 Lines | |||||
/* | /* | ||||
* Small (default) buffer size in bytes. It's inefficient for this to be | * Small (default) buffer size in bytes. It's inefficient for this to be | ||||
* smaller than MAXPHYS. | * smaller than MAXPHYS. | ||||
*/ | */ | ||||
#define BUFSIZE_SMALL (MAXPHYS) | #define BUFSIZE_SMALL (MAXPHYS) | ||||
static ssize_t | static ssize_t | ||||
copy_fallback(int from_fd, int to_fd, char *buf, size_t bufsize) | copy_fallback(int from_fd, int to_fd) | ||||
{ | { | ||||
static char *buf = NULL; | |||||
static size_t bufsize; | |||||
ssize_t rcount, wresid, wcount = 0; | ssize_t rcount, wresid, wcount = 0; | ||||
char *bufp; | char *bufp; | ||||
if (buf == NULL) { | |||||
if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) | |||||
bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); | |||||
else | |||||
bufsize = BUFSIZE_SMALL; | |||||
buf = malloc(bufsize); | |||||
if (buf == NULL) | |||||
err(1, "Not enough memory"); | |||||
} | |||||
rcount = read(from_fd, buf, bufsize); | rcount = read(from_fd, buf, bufsize); | ||||
if (rcount <= 0) | if (rcount <= 0) | ||||
return (rcount); | return (rcount); | ||||
for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { | for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { | ||||
wcount = write(to_fd, bufp, wresid); | wcount = write(to_fd, bufp, wresid); | ||||
if (wcount <= 0) | if (wcount <= 0) | ||||
break; | break; | ||||
if (wcount >= (ssize_t)wresid) | if (wcount >= (ssize_t)wresid) | ||||
break; | break; | ||||
} | } | ||||
return (wcount < 0 ? wcount : rcount); | return (wcount < 0 ? wcount : rcount); | ||||
} | } | ||||
int | int | ||||
copy_file(const FTSENT *entp, int dne) | copy_file(const FTSENT *entp, int dne) | ||||
{ | { | ||||
static char *buf = NULL; | |||||
static size_t bufsize; | |||||
struct stat *fs; | struct stat *fs; | ||||
ssize_t wcount; | ssize_t wcount; | ||||
off_t wtotal; | off_t wtotal; | ||||
int ch, checkch, from_fd, rval, to_fd; | int ch, checkch, from_fd, rval, to_fd; | ||||
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED | |||||
size_t wresid; | |||||
char *bufp, *p; | |||||
#endif | |||||
int use_copy_file_range = 1; | int use_copy_file_range = 1; | ||||
from_fd = to_fd = -1; | from_fd = to_fd = -1; | ||||
if (!lflag && !sflag && | if (!lflag && !sflag && | ||||
(from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { | (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { | ||||
warn("%s", entp->fts_path); | warn("%s", entp->fts_path); | ||||
return (1); | return (1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if (!lflag && !sflag && to_fd == -1) { | ||||
warn("%s", to.p_path); | warn("%s", to.p_path); | ||||
rval = 1; | rval = 1; | ||||
goto done; | goto done; | ||||
} | } | ||||
rval = 0; | rval = 0; | ||||
if (!lflag && !sflag) { | 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. | |||||
* 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 && | |||||
(p = mmap(NULL, (size_t)fs->st_size, PROT_READ, | |||||
MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) { | |||||
wtotal = 0; | wtotal = 0; | ||||
for (bufp = p, wresid = fs->st_size; ; | |||||
bufp += wcount, wresid -= (size_t)wcount) { | |||||
wcount = write(to_fd, bufp, wresid); | |||||
if (wcount <= 0) | |||||
break; | |||||
wtotal += wcount; | |||||
if (info) { | |||||
info = 0; | |||||
(void)fprintf(stderr, | |||||
"%s -> %s %3d%%\n", | |||||
entp->fts_path, to.p_path, | |||||
cp_pct(wtotal, fs->st_size)); | |||||
} | |||||
if (wcount >= (ssize_t)wresid) | |||||
break; | |||||
} | |||||
if (wcount != (ssize_t)wresid) { | |||||
warn("%s", to.p_path); | |||||
rval = 1; | |||||
} | |||||
/* Some systems don't unmap on close(2). */ | |||||
if (munmap(p, fs->st_size) < 0) { | |||||
warn("%s", entp->fts_path); | |||||
rval = 1; | |||||
} | |||||
} else | |||||
#endif | |||||
{ | |||||
if (buf == NULL) { | |||||
/* | |||||
* Note that buf and bufsize are static. If | |||||
* malloc() fails, it will fail at the start | |||||
* and not copy only some files. | |||||
*/ | |||||
if (sysconf(_SC_PHYS_PAGES) > | |||||
PHYSPAGES_THRESHOLD) | |||||
bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); | |||||
else | |||||
bufsize = BUFSIZE_SMALL; | |||||
buf = malloc(bufsize); | |||||
if (buf == NULL) | |||||
err(1, "Not enough memory"); | |||||
} | |||||
wtotal = 0; | |||||
do { | do { | ||||
if (use_copy_file_range) { | if (use_copy_file_range) { | ||||
wcount = copy_file_range(from_fd, NULL, | wcount = copy_file_range(from_fd, NULL, | ||||
to_fd, NULL, SSIZE_MAX, 0); | to_fd, NULL, SSIZE_MAX, 0); | ||||
if (wcount < 0 && errno == EINVAL) { | if (wcount < 0 && errno == EINVAL) { | ||||
/* Prob a non-seekable FD */ | /* Prob a non-seekable FD */ | ||||
use_copy_file_range = 0; | use_copy_file_range = 0; | ||||
} | } | ||||
} | } | ||||
if (!use_copy_file_range) { | if (!use_copy_file_range) { | ||||
wcount = copy_fallback(from_fd, to_fd, | wcount = copy_fallback(from_fd, to_fd); | ||||
buf, bufsize); | |||||
} | } | ||||
wtotal += wcount; | wtotal += wcount; | ||||
if (info) { | if (info) { | ||||
info = 0; | info = 0; | ||||
(void)fprintf(stderr, | (void)fprintf(stderr, | ||||
"%s -> %s %3d%%\n", | "%s -> %s %3d%%\n", | ||||
entp->fts_path, to.p_path, | entp->fts_path, to.p_path, | ||||
cp_pct(wtotal, fs->st_size)); | cp_pct(wtotal, fs->st_size)); | ||||
} | } | ||||
} while (wcount > 0); | } while (wcount > 0); | ||||
if (wcount < 0) { | if (wcount < 0) { | ||||
warn("%s", entp->fts_path); | warn("%s", entp->fts_path); | ||||
rval = 1; | rval = 1; | ||||
} | |||||
} | } | ||||
} else if (lflag) { | } else if (lflag) { | ||||
if (link(entp->fts_path, to.p_path)) { | if (link(entp->fts_path, to.p_path)) { | ||||
warn("%s", to.p_path); | warn("%s", to.p_path); | ||||
rval = 1; | rval = 1; | ||||
} | } | ||||
} else if (sflag) { | } else if (sflag) { | ||||
if (symlink(entp->fts_path, to.p_path)) { | if (symlink(entp->fts_path, to.p_path)) { | ||||
▲ Show 20 Lines • Show All 312 Lines • Show Last 20 Lines |