Index: usr.bin/diff/diffreg.c =================================================================== --- usr.bin/diff/diffreg.c +++ usr.bin/diff/diffreg.c @@ -71,6 +71,7 @@ #include #include +#include #include #include @@ -190,7 +191,7 @@ 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,8 +209,8 @@ static int skipline(FILE *); static int isqrt(int); static int stone(int *, int, int *, int *, int); -static enum readhash readhash(FILE *, int, unsigned *); -static int files_differ(FILE *, FILE *, int); +static enum readhash readhash(const uint8_t **, const uint8_t *, int, unsigned *); +static int files_differ(const uint8_t *, const uint8_t *, int); static char *match_function(const long *, int, FILE *); static char *preadline(int, size_t, off_t); @@ -258,11 +259,13 @@ diffreg(char *file1, char *file2, int flags, int capsicum) { FILE *f1, *f2; + uint8_t *filemmap1, *filemmap2; int i, rval; struct pr *pr = NULL; cap_rights_t rights_ro; f1 = f2 = NULL; + filemmap1 = filemmap2 = NULL; rval = D_SAME; anychange = 0; lastline = 0; @@ -343,7 +346,8 @@ 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,18 +366,15 @@ if (caph_enter() < 0) err(2, "unable to enter capability mode"); } - - switch (files_differ(f1, f2, flags)) { - case 0: + filemmap1 = mmap(NULL, stb1.st_size, PROT_READ, MAP_SHARED, fileno(f1), 0); + if (filemmap1 == NULL) + err(2, "unable to mmap"); + filemmap2 = mmap(NULL, stb2.st_size, PROT_READ, MAP_SHARED, fileno(f2), 0); + if (filemmap2 == NULL) + err(2, "unable to mmap"); + + if (files_differ(filemmap2, filemmap2, flags) == 0) goto closem; - case 1: - break; - default: - /* error */ - rval = D_ERROR; - status |= 2; - goto closem; - } if (diff_format == D_BRIEF && ignore_pats == NULL && (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE|D_STRIPCR)) == 0) @@ -383,11 +384,11 @@ 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, filemmap1, stb1.st_size, flags); + (void)prepare(1, filemmap2, 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, filemmap1, stb1.st_size, flags) || + !prepare(1, filemmap2, stb2.st_size, flags)) { rval = D_BINARY; status |= 1; goto closem; @@ -431,6 +432,10 @@ if (rval == D_SAME) rval = D_DIFFER; } + if (filemmap1 != NULL) + munmap(filemmap1, stb1.st_size); + if (filemmap2 != NULL) + munmap(filemmap2, stb2.st_size); if (f1 != NULL) fclose(f1); if (f2 != NULL) @@ -441,30 +446,16 @@ /* * Check to see if the given files differ. - * Returns 0 if they are the same, 1 if different, and -1 on error. - * XXX - could use code from cmp(1) [faster] + * Returns 0 if they are the same, 1 if different. */ static int -files_differ(FILE *f1, FILE *f2, int flags) +files_differ(const uint8_t *filemmap1, const uint8_t *filemmap2, int flags) { - char buf1[BUFSIZ], buf2[BUFSIZ]; - size_t i, j; - if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size || (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) return (1); - for (;;) { - i = fread(buf1, 1, sizeof(buf1), f1); - j = fread(buf2, 1, sizeof(buf2), f2); - if ((!i && ferror(f1)) || (!j && ferror(f2))) - return (-1); - if (i != j) - return (1); - if (i == 0) - return (0); - if (memcmp(buf1, buf2, i) != 0) - return (1); - } + + return (memcmp(filemmap1, filemmap2, stb1.st_size) != 0); } static FILE * @@ -516,21 +507,20 @@ } static bool -prepare(int i, FILE *fd, size_t filesize, int flags) +prepare(int i, const uint8_t *walk, size_t filesize, int flags) { struct line *p; unsigned h; size_t sz, j = 0; enum readhash r; - - rewind(fd); + 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 +1354,25 @@ * 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 (flags & D_STRIPCR && walk + 1 != end && walk[1] == '\n') { + walk += 2; + break; } /* FALLTHROUGH */ case '\t': @@ -1395,21 +1386,18 @@ /* 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); }