diff options
Diffstat (limited to 'usr.bin/tail/forward.c')
-rw-r--r-- | usr.bin/tail/forward.c | 59 |
1 files changed, 25 insertions, 34 deletions
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; } |