From 17ede005a9d271e69b1cd0bba9e0581657357e03 Mon Sep 17 00:00:00 2001 From: dwmalone Date: Tue, 27 Mar 2001 20:37:34 +0000 Subject: Fix tail to work on files bigger than 2GB. PR: 14786 Reviewed by: iedowse --- usr.bin/tail/extern.h | 19 ++++++++++-- usr.bin/tail/forward.c | 59 ++++++++++++++++---------------------- usr.bin/tail/misc.c | 55 +++++++++++++++++++++++++++++++++++ usr.bin/tail/reverse.c | 78 +++++++++++++++++++++++++++++++------------------- 4 files changed, 146 insertions(+), 65 deletions(-) (limited to 'usr.bin/tail') diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h index 0ec272d..cdf6929 100644 --- a/usr.bin/tail/extern.h +++ b/usr.bin/tail/extern.h @@ -31,11 +31,24 @@ * SUCH DAMAGE. * * @(#)extern.h 8.1 (Berkeley) 6/6/93 + * + * $FreeBSD$ */ -#define WR(p, size) \ +#define WR(p, size) do { \ if (write(STDOUT_FILENO, p, size) != size) \ - oerr(); + oerr(); \ + } while(0) + +#define TAILMAPLEN (4<<20) + +struct mapinfo { + off_t mapoff; + off_t maxoff; + size_t maplen; + char *start; + int fd; +}; enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE }; @@ -47,6 +60,8 @@ int lines __P((FILE *, off_t)); void ierr __P((void)); void oerr __P((void)); +int mapprint __P((struct mapinfo *, off_t, off_t)); +int maparound __P((struct mapinfo *, off_t)); extern int Fflag, fflag, rflag, rval; extern char *fname; diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c index ef046cc..ffca06a 100644 --- a/usr.bin/tail/forward.c +++ b/usr.bin/tail/forward.c @@ -267,55 +267,46 @@ rlines(fp, off, sbp) long off; struct stat *sbp; { - off_t size; - char *p; - char *start; + struct mapinfo map; + off_t curoff, size; + int i; if (!(size = sbp->st_size)) return; + map.start = NULL; + map.fd = fileno(fp); + map.mapoff = map.maxoff = size; /* - * size not passed directly to mmap() below because unclear error - * diagnostic "Invalid argument". + * Last char is special, ignore whether newline or not. Note that + * size == 0 is dealt with above, and size == 1 sets curoff to -1. */ - if (size > SIZE_T_MAX || size < 0) { - errno = EFBIG; - ierr(); - exit(1); - } - - /* - * XXX: FIXME - mmap() not support files over 2GB - * Large file processing require alternative implementation, - * for now print nice error diagnostic at least. - */ - if (size > SSIZE_MAX) { - errno = EFBIG; - ierr(); - exit(1); + curoff = size - 2; + while (curoff >= 0) { + if (curoff < map.mapoff && maparound(&map, curoff) != 0) { + ierr(); + return; + } + for (i = curoff - map.mapoff; i >= 0; i--) + if (map.start[i] == '\n' && --off == 0) + break; + /* `i' is either the map offset of a '\n', or -1. */ + curoff = map.mapoff + i; + if (i >= 0) + break; } - - if ((start = mmap(NULL, (size_t)size, - PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) { + curoff++; + if (mapprint(&map, curoff, size - curoff) != 0) { ierr(); exit(1); } - /* Last char is special, ignore whether newline or not. */ - for (p = start + size - 1; --size;) - if (*--p == '\n' && !--off) { - ++p; - break; - } - /* Set the file pointer to reflect the length displayed. */ - size = sbp->st_size - size; - WR(p, size); - if (fseek(fp, 0L, SEEK_END) == -1) { + if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) { ierr(); return; } - if (munmap(start, (size_t)sbp->st_size)) { + if (map.start != NULL && munmap(map.start, map.maplen)) { ierr(); return; } diff --git a/usr.bin/tail/misc.c b/usr.bin/tail/misc.c index c4edfc3..275acb9 100644 --- a/usr.bin/tail/misc.c +++ b/usr.bin/tail/misc.c @@ -44,6 +44,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -64,3 +65,57 @@ oerr() { err(1, "stdout"); } + +/* + * Print `len' bytes from the file associated with `mip', starting at + * absolute file offset `startoff'. May move map window. + */ +int +mapprint(mip, startoff, len) + struct mapinfo *mip; + off_t startoff, len; +{ + int n; + + while (len > 0) { + if (startoff < mip->mapoff || startoff >= mip->mapoff + + mip->maplen) { + if (maparound(mip, startoff) != 0) + return (1); + } + n = (mip->mapoff + mip->maplen) - startoff; + if (n > len) + n = len; + WR(mip->start + (startoff - mip->mapoff), n); + startoff += n; + len -= n; + } + return (0); +} + +/* + * Move the map window so that it contains the byte at absolute file + * offset `offset'. The start of the map window will be TAILMAPLEN + * aligned. + */ +int +maparound(mip, offset) + struct mapinfo *mip; + off_t offset; +{ + + if (mip->start != NULL && munmap(mip->start, mip->maplen) != 0) + return (1); + + mip->mapoff = offset & ~((off_t)TAILMAPLEN - 1); + mip->maplen = TAILMAPLEN; + if (mip->maplen > mip->maxoff - mip->mapoff) + mip->maplen = mip->maxoff - mip->mapoff; + if (mip->maplen <= 0) + abort(); + if ((mip->start = mmap(NULL, mip->maplen, PROT_READ, MAP_SHARED, + mip->fd, mip->mapoff)) == MAP_FAILED) + return (1); + + return (0); +} diff --git a/usr.bin/tail/reverse.c b/usr.bin/tail/reverse.c index bd2d3ee..24468dd 100644 --- a/usr.bin/tail/reverse.c +++ b/usr.bin/tail/reverse.c @@ -114,43 +114,63 @@ r_reg(fp, style, off, sbp) long off; struct stat *sbp; { - off_t size; - int llen; - char *p; - char *start; + struct mapinfo map; + off_t curoff, size, lineend; + int i; if (!(size = sbp->st_size)) return; - if (size > SIZE_T_MAX) { - errno = EFBIG; - ierr(); - return; - } + map.start = NULL; + map.mapoff = map.maxoff = size; + map.fd = fileno(fp); - if ((start = mmap(NULL, (size_t)size, - PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) { - ierr(); - return; - } - p = start + size - 1; + /* + * Last char is special, ignore whether newline or not. Note that + * size == 0 is dealt with above, and size == 1 sets curoff to -1. + */ + curoff = size - 2; + lineend = size; + while (curoff >= 0) { + if (curoff < map.mapoff || curoff >= map.mapoff + map.maplen) { + if (maparound(&map, curoff) != 0) { + ierr(); + return; + } + } + for (i = curoff - map.mapoff; i >= 0; i--) { + if (style == RBYTES && --off == 0) + break; + if (map.start[i] == '\n') + break; + } + /* `i' is either the map offset of a '\n', or -1. */ + curoff = map.mapoff + i; + if (i < 0) + continue; - if (style == RBYTES && off < size) - size = off; + /* Print the line and update offsets. */ + if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) { + ierr(); + return; + } + lineend = curoff + 1; + curoff--; - /* Last char is special, ignore whether newline or not. */ - for (llen = 1; --size; ++llen) - if (*--p == '\n') { - WR(p + 1, llen); - llen = 0; - if (style == RLINES && !--off) { - ++p; - break; - } + if (style == RLINES) + off--; + + if (off == 0 && style != REVERSE) { + /* Avoid printing anything below. */ + curoff = 0; + break; } - if (llen) - WR(p, llen); - if (munmap(start, (size_t)sbp->st_size)) + } + if (curoff < 0 && mapprint(&map, 0, lineend) != 0) { + ierr(); + return; + } + if (map.start != NULL && munmap(map.start, map.maplen)) ierr(); } -- cgit v1.1