summaryrefslogtreecommitdiffstats
path: root/usr.bin/tail
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2001-03-27 20:37:34 +0000
committerdwmalone <dwmalone@FreeBSD.org>2001-03-27 20:37:34 +0000
commit17ede005a9d271e69b1cd0bba9e0581657357e03 (patch)
tree1f630174f68583ca93762f83683b53ca70942147 /usr.bin/tail
parenta7847b560691a2f312ff3a6ab5003c4bdd26ef9a (diff)
downloadFreeBSD-src-17ede005a9d271e69b1cd0bba9e0581657357e03.zip
FreeBSD-src-17ede005a9d271e69b1cd0bba9e0581657357e03.tar.gz
Fix tail to work on files bigger than 2GB.
PR: 14786 Reviewed by: iedowse
Diffstat (limited to 'usr.bin/tail')
-rw-r--r--usr.bin/tail/extern.h19
-rw-r--r--usr.bin/tail/forward.c59
-rw-r--r--usr.bin/tail/misc.c55
-rw-r--r--usr.bin/tail/reverse.c78
4 files changed, 146 insertions, 65 deletions
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 <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -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();
}
OpenPOWER on IntegriCloud