Skip site navigation (1)Skip section navigation (2)
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>