diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c index e728441c2cb..ca8f7491995 100644 --- a/usr.bin/diff/diffreg.c +++ b/usr.bin/diff/diffreg.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -190,7 +191,7 @@ static void range(int, int, const char *); static void uni_range(int, int); static void dump_context_vec(FILE *, FILE *, int); static void dump_unified_vec(FILE *, FILE *, int); -static bool prepare(int, FILE *, size_t, int); +static bool prepare(int, const uint8_t *, size_t, int); static void prune(void); static void equiv(struct line *, int, struct line *, int, int *); static void unravel(int); @@ -208,7 +209,7 @@ static int search(int *, int, int); static int skipline(FILE *); static int isqrt(int); static int stone(int *, int, int *, int *, int); -static enum readhash readhash(FILE *, int, unsigned *); +static enum readhash readhash(const uint8_t **, const uint8_t *, int, unsigned *); static int files_differ(FILE *, FILE *, int); static char *match_function(const long *, int, FILE *); static char *preadline(int, size_t, off_t); @@ -258,11 +259,13 @@ int diffreg(char *file1, char *file2, int flags, int capsicum) { FILE *f1, *f2; + uint8_t *buf1, *buf2; int i, rval; struct pr *pr = NULL; cap_rights_t rights_ro; f1 = f2 = NULL; + buf1 = buf2 = NULL; rval = D_SAME; anychange = 0; lastline = 0; @@ -343,7 +346,8 @@ diffreg(char *file1, char *file2, int flags, int capsicum) pr = start_pr(file1, file2); if (capsicum) { - cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); + cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK, + CAP_MMAP); if (caph_rights_limit(fileno(f1), &rights_ro) < 0) err(2, "unable to limit rights on: %s", file1); if (caph_rights_limit(fileno(f2), &rights_ro) < 0) @@ -362,6 +366,12 @@ diffreg(char *file1, char *file2, int flags, int capsicum) if (caph_enter() < 0) err(2, "unable to enter capability mode"); } + buf1 = mmap(NULL, stb1.st_size, PROT_READ, MAP_SHARED, fileno(f1), 0); + if (buf1 == NULL) + err(2, "unable to mmap"); + buf2 = mmap(NULL, stb2.st_size, PROT_READ, MAP_SHARED, fileno(f2), 0); + if (buf2 == NULL) + err(2, "unable to mmap"); switch (files_differ(f1, f2, flags)) { case 0: @@ -383,11 +393,11 @@ diffreg(char *file1, char *file2, int flags, int capsicum) goto closem; } if ((flags & D_FORCEASCII) != 0) { - (void)prepare(0, f1, stb1.st_size, flags); - (void)prepare(1, f2, stb2.st_size, flags); + (void)prepare(0, buf1, stb1.st_size, flags); + (void)prepare(1, buf2, stb2.st_size, flags); } else if (!asciifile(f1) || !asciifile(f2) || - !prepare(0, f1, stb1.st_size, flags) || - !prepare(1, f2, stb2.st_size, flags)) { + !prepare(0, buf1, stb1.st_size, flags) || + !prepare(1, buf2, stb2.st_size, flags)) { rval = D_BINARY; status |= 1; goto closem; @@ -431,6 +441,10 @@ diffreg(char *file1, char *file2, int flags, int capsicum) if (rval == D_SAME) rval = D_DIFFER; } + if (buf1 != NULL) + munmap(buf1, stb1.st_size); + if (buf2 != NULL) + munmap(buf2, stb2.st_size); if (f1 != NULL) fclose(f1); if (f2 != NULL) @@ -516,21 +530,22 @@ splice(char *dir, char *path) } static bool -prepare(int i, FILE *fd, size_t filesize, int flags) +prepare(int i, const uint8_t *buf, size_t filesize, int flags) { struct line *p; unsigned h; size_t sz, j = 0; enum readhash r; - rewind(fd); + const uint8_t *walk = buf; + const uint8_t *end = buf + filesize; sz = MIN(filesize, SIZE_MAX) / 25; if (sz < 100) sz = 100; p = xcalloc(sz + 3, sizeof(*p)); - while ((r = readhash(fd, flags, &h)) != RH_EOF) + while ((r = readhash(&walk, end, flags, &h)) != RH_EOF) switch (r) { case RH_EOF: /* otherwise clang complains */ case RH_BINARY: @@ -1364,24 +1379,25 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. */ static enum readhash -readhash(FILE *f, int flags, unsigned *hash) +readhash(const uint8_t **buf, const uint8_t *end, int flags, unsigned *hash) { - int i, t, space; + int t, space; unsigned sum; + const uint8_t *walk = *buf; sum = 1; space = 0; - for (i = 0;;) { - switch (t = getc(f)) { + if (walk == end) + return (RH_EOF); + for (; walk < end; walk++) { + switch (t = *walk) { case '\0': if ((flags & D_FORCEASCII) == 0) return (RH_BINARY); case '\r': - if (flags & D_STRIPCR) { - t = getc(f); - if (t == '\n') - break; - ungetc(t, f); + if (walk + 1 != end && walk[1] == '\n') { + walk += 2; + break; } /* FALLTHROUGH */ case '\t': @@ -1395,21 +1411,18 @@ readhash(FILE *f, int flags, unsigned *hash) /* FALLTHROUGH */ default: if (space && (flags & D_IGNOREBLANKS) == 0) { - i++; space = 0; } sum = sum * 127 + chrtran(t); - i++; continue; - case EOF: - if (i == 0) - return (RH_EOF); /* FALLTHROUGH */ case '\n': + walk++; break; } break; } + *buf = walk; *hash = sum; return (RH_OK); }