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>
