Date: Tue, 27 Mar 2001 10:22:23 +0100 From: David Malone <dwmalone@maths.tcd.ie> To: "Andrey A. Chernov" <ache@nagual.pp.ru> Cc: Andrew Gallatin <gallatin@cs.duke.edu>, cvs-committers@FreeBSD.org, cvs-all@FreeBSD.org Subject: Re: cvs commit: src/usr.bin/tail forward.c Message-ID: <20010327102223.A46353@walton.maths.tcd.ie> In-Reply-To: <20010327050155.A12287@nagual.pp.ru>; from ache@nagual.pp.ru on Tue, Mar 27, 2001 at 05:01:57AM %2B0400 References: <200103261929.f2QJToC44593@freefall.freebsd.org> <20010326193031.A54642@grasshopper.cs.duke.edu> <20010327050155.A12287@nagual.pp.ru>
next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Mar 27, 2001 at 05:01:57AM +0400, Andrey A. Chernov wrote: > Yes, I'll change that. Kernel actually use ssize_t for check. Actually - if someone could review this patch which myself and Ian Dowse produced we can just fix the problem. I've done quite a bit of testing of the patch and read through it several times and it seems to work fine. David. Index: extern.h =================================================================== RCS file: /FreeBSD/FreeBSD-CVS/src/usr.bin/tail/extern.h,v retrieving revision 1.4 diff -u -r1.4 extern.h --- extern.h 1998/04/06 16:13:48 1.4 +++ extern.h 2001/02/23 22:30:11 @@ -33,10 +33,21 @@ * @(#)extern.h 8.1 (Berkeley) 6/6/93 */ -#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 }; void forward __P((FILE *, enum STYLE, long, struct stat *)); @@ -47,6 +58,8 @@ 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; Index: forward.c =================================================================== RCS file: /FreeBSD/FreeBSD-CVS/src/usr.bin/tail/forward.c,v retrieving revision 1.17 diff -u -r1.17 forward.c --- forward.c 2000/12/03 17:05:44 1.17 +++ forward.c 2001/02/23 23:25:59 @@ -269,40 +269,46 @@ 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; - if (size > SIZE_T_MAX) { - errno = EFBIG; - ierr(); - return; + /* + * 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; + 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(); return; } - /* 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, (long)sbp->st_size, SEEK_SET) == -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; } Index: misc.c =================================================================== RCS file: /FreeBSD/FreeBSD-CVS/src/usr.bin/tail/misc.c,v retrieving revision 1.5 diff -u -r1.5 misc.c --- misc.c 2000/12/02 19:10:12 1.5 +++ misc.c 2001/02/23 22:38:52 @@ -44,6 +44,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include <sys/mman.h> #include <errno.h> #include <unistd.h> #include <stdio.h> @@ -63,4 +64,58 @@ 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); } Index: reverse.c =================================================================== RCS file: /FreeBSD/FreeBSD-CVS/src/usr.bin/tail/reverse.c,v retrieving revision 1.10 diff -u -r1.10 reverse.c --- reverse.c 2000/12/03 17:05:45 1.10 +++ reverse.c 2001/02/23 23:24:34 @@ -114,43 +114,60 @@ 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; - } - - if ((start = mmap(NULL, (size_t)size, - PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) { - ierr(); - return; - } - p = start + size - 1; - if (style == RBYTES && off < size) size = off; - /* 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; + map.start = NULL; + map.mapoff = map.maxoff = size; + map.fd = fileno(fp); + + /* + * 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; } } - if (llen) - WR(p, llen); - if (munmap(start, (size_t)sbp->st_size)) + for (i = curoff - map.mapoff; i >= 0; i--) + 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; + + /* Print the line and update offsets. */ + if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) { + ierr(); + return; + } + lineend = curoff + 1; + curoff--; + + if (--off == 0) { + /* Avoid printing anything below. */ + curoff = 0; + break; + } + } + if (curoff < 0 && mapprint(&map, 0, lineend) != 0) { + ierr(); + return; + } + if (map.start != NULL && munmap(map.start, map.maplen)) ierr(); } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe cvs-all" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010327102223.A46353>