Changeset View
Changeset View
Standalone View
Standalone View
head/usr.bin/xinstall/xinstall.c
Show First 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
static void do_symlink(const char *, const char *, const struct stat *); | static void do_symlink(const char *, const char *, const struct stat *); | ||||
static void makelink(const char *, const char *, const struct stat *); | static void makelink(const char *, const char *, const struct stat *); | ||||
static void install(const char *, const char *, u_long, u_int); | static void install(const char *, const char *, u_long, u_int); | ||||
static void install_dir(char *); | static void install_dir(char *); | ||||
static void metadata_log(const char *, const char *, struct timespec *, | static void metadata_log(const char *, const char *, struct timespec *, | ||||
const char *, const char *, off_t); | const char *, const char *, off_t); | ||||
static int parseid(const char *, id_t *); | static int parseid(const char *, id_t *); | ||||
static int strip(const char *, int, const char *, char **); | static int strip(const char *, int, const char *, char **); | ||||
static int trymmap(int); | static int trymmap(size_t); | ||||
static void usage(void); | static void usage(void); | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
struct stat from_sb, to_sb; | struct stat from_sb, to_sb; | ||||
mode_t *set; | mode_t *set; | ||||
u_long fset; | u_long fset; | ||||
▲ Show 20 Lines • Show All 922 Lines • ▼ Show 20 Lines | if (from_len != to_len) | ||||
return 1; | return 1; | ||||
do_digest = (digesttype != DIGEST_NONE && dresp != NULL && | do_digest = (digesttype != DIGEST_NONE && dresp != NULL && | ||||
*dresp == NULL); | *dresp == NULL); | ||||
if (from_len <= MAX_CMP_SIZE) { | if (from_len <= MAX_CMP_SIZE) { | ||||
if (do_digest) | if (do_digest) | ||||
digest_init(&ctx); | digest_init(&ctx); | ||||
done_compare = 0; | done_compare = 0; | ||||
if (trymmap(from_fd) && trymmap(to_fd)) { | if (trymmap(from_len) && trymmap(to_len)) { | ||||
p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, | p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, | ||||
from_fd, (off_t)0); | from_fd, (off_t)0); | ||||
if (p == MAP_FAILED) | if (p == MAP_FAILED) | ||||
goto out; | goto out; | ||||
q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, | q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, | ||||
to_fd, (off_t)0); | to_fd, (off_t)0); | ||||
if (q == MAP_FAILED) { | if (q == MAP_FAILED) { | ||||
munmap(p, from_len); | munmap(p, from_len); | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | copy(int from_fd, const char *from_name, int to_fd, const char *to_name, | ||||
/* Rewind file descriptors. */ | /* Rewind file descriptors. */ | ||||
if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) | if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) | ||||
err(EX_OSERR, "lseek: %s", from_name); | err(EX_OSERR, "lseek: %s", from_name); | ||||
if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) | if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) | ||||
err(EX_OSERR, "lseek: %s", to_name); | err(EX_OSERR, "lseek: %s", to_name); | ||||
digest_init(&ctx); | digest_init(&ctx); | ||||
/* | |||||
* 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. | |||||
*/ | |||||
done_copy = 0; | done_copy = 0; | ||||
if (size <= 8 * 1048576 && trymmap(from_fd) && | if (trymmap((size_t)size) && | ||||
(p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, | (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, | ||||
from_fd, (off_t)0)) != MAP_FAILED) { | from_fd, (off_t)0)) != MAP_FAILED) { | ||||
nw = write(to_fd, p, size); | nw = write(to_fd, p, size); | ||||
if (nw != size) { | if (nw != size) { | ||||
serrno = errno; | serrno = errno; | ||||
(void)unlink(to_name); | (void)unlink(to_name); | ||||
if (nw >= 0) { | if (nw >= 0) { | ||||
errx(EX_OSERR, | errx(EX_OSERR, | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | " directory ...\n"); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | } | ||||
/* | /* | ||||
* trymmap -- | * trymmap -- | ||||
* return true (1) if mmap should be tried, false (0) if not. | * return true (1) if mmap should be tried, false (0) if not. | ||||
*/ | */ | ||||
static int | static int | ||||
trymmap(int fd) | trymmap(size_t filesize) | ||||
{ | { | ||||
/* | /* | ||||
* The ifdef is for bootstrapping - f_fstypename doesn't exist in | * This function existed to skip mmap() for NFS file systems whereas | ||||
* pre-Lite2-merge systems. | * nowadays mmap() should be perfectly safe. Nevertheless, using mmap() | ||||
* only reduces the number of system calls if we need multiple read() | |||||
* syscalls, i.e. if the file size is > MAXBSIZE. However, mmap() is | |||||
* more expensive than read() so set the threshold at 4 fewer syscalls. | |||||
* Additionally, for larger file size mmap() can significantly increase | |||||
* the number of page faults, so avoid it in that case. | |||||
* | |||||
* Note: the 8MB limit is not based on any meaningful benchmarking | |||||
* results, it is simply reusing the same value that was used before | |||||
* and also matches bin/cp. | |||||
* | |||||
* XXX: Maybe we shouldn't bother with mmap() at all, since we use | |||||
* MAXBSIZE the syscall overhead of read() shouldn't be too high? | |||||
*/ | */ | ||||
#ifdef MFSNAMELEN | return (filesize > 4 * MAXBSIZE && filesize < 8 * 1024 * 1024); | ||||
struct statfs stfs; | |||||
if (fstatfs(fd, &stfs) != 0) | |||||
return (0); | |||||
if (strcmp(stfs.f_fstypename, "ufs") == 0 || | |||||
strcmp(stfs.f_fstypename, "cd9660") == 0) | |||||
return (1); | |||||
#endif | |||||
return (0); | |||||
} | } |