Fix tail to work on files bigger than 2GB.
PR: 14786 Reviewed by: iedowse
This commit is contained in:
parent
5c620e2dad
commit
726098d35e
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
if ((start = mmap(NULL, (size_t)size,
|
||||
PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) {
|
||||
ierr();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Last char is special, ignore whether newline or not. */
|
||||
for (p = start + size - 1; --size;)
|
||||
if (*--p == '\n' && !--off) {
|
||||
++p;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
curoff++;
|
||||
if (mapprint(&map, curoff, size - curoff) != 0) {
|
||||
ierr();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
/*
|
||||
* 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 (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;
|
||||
|
||||
/* Print the line and update offsets. */
|
||||
if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) {
|
||||
ierr();
|
||||
return;
|
||||
}
|
||||
lineend = curoff + 1;
|
||||
curoff--;
|
||||
|
||||
if (style == RLINES)
|
||||
off--;
|
||||
|
||||
if (off == 0 && style != REVERSE) {
|
||||
/* 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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user