diff options
Diffstat (limited to 'usr.bin/grep/file.c')
-rw-r--r-- | usr.bin/grep/file.c | 125 |
1 files changed, 93 insertions, 32 deletions
diff --git a/usr.bin/grep/file.c b/usr.bin/grep/file.c index a6216e5..644c788 100644 --- a/usr.bin/grep/file.c +++ b/usr.bin/grep/file.c @@ -34,13 +34,15 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/types.h> +#include <sys/mman.h> #include <sys/stat.h> +#include <sys/types.h> #include <bzlib.h> #include <err.h> #include <errno.h> #include <fcntl.h> +#include <lzma.h> #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -56,10 +58,12 @@ __FBSDID("$FreeBSD$"); static gzFile gzbufdesc; static BZFILE* bzbufdesc; +static lzma_stream lstrm = LZMA_STREAM_INIT; -static unsigned char buffer[MAXBUFSIZ]; +static unsigned char *buffer; static unsigned char *bufpos; static size_t bufrem; +static size_t fsiz; static unsigned char *lnbuf; static size_t lnbuflen; @@ -70,6 +74,9 @@ grep_refill(struct file *f) ssize_t nr; int bzerr; + if (filebehave == FILE_MMAP) + return (0); + bufpos = buffer; bufrem = 0; @@ -101,6 +108,36 @@ grep_refill(struct file *f) /* Make sure we exit with an error */ nr = -1; } + } else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) { + lzma_action action = LZMA_RUN; + uint8_t in_buf[MAXBUFSIZ]; + lzma_ret ret; + + ret = (filebehave == FILE_XZ) ? + lzma_stream_decoder(&lstrm, UINT64_MAX, + LZMA_CONCATENATED) : + lzma_alone_decoder(&lstrm, UINT64_MAX); + + if (ret != LZMA_OK) + return (-1); + + lstrm.next_out = buffer; + lstrm.avail_out = MAXBUFSIZ; + lstrm.next_in = in_buf; + nr = read(f->fd, in_buf, MAXBUFSIZ); + + if (nr < 0) + return (-1); + else if (nr == 0) + action = LZMA_FINISH; + + lstrm.avail_in = nr; + ret = lzma_code(&lstrm, action); + + if (ret != LZMA_OK && ret != LZMA_STREAM_END) + return (-1); + bufrem = MAXBUFSIZ - lstrm.avail_out; + return (0); } else nr = read(f->fd, buffer, MAXBUFSIZ); @@ -186,56 +223,76 @@ error: return (NULL); } -static inline struct file * -grep_file_init(struct file *f) +/* + * Opens a file for processing. + */ +struct file * +grep_open(const char *path) { + struct file *f; + + f = grep_malloc(sizeof *f); + memset(f, 0, sizeof *f); + if (path == NULL) { + /* Processing stdin implies --line-buffered. */ + lbflag = true; + f->fd = STDIN_FILENO; + } else if ((f->fd = open(path, O_RDONLY)) == -1) + goto error1; + + if (filebehave == FILE_MMAP) { + struct stat st; + + if ((fstat(f->fd, &st) == -1) || (st.st_size > OFF_MAX) || + (!S_ISREG(st.st_mode))) + filebehave = FILE_STDIO; + else { + int flags = MAP_PRIVATE | MAP_NOCORE | MAP_NOSYNC; +#ifdef MAP_PREFAULT_READ + flags |= MAP_PREFAULT_READ; +#endif + fsiz = st.st_size; + buffer = mmap(NULL, fsiz, PROT_READ, flags, + f->fd, (off_t)0); + if (buffer == MAP_FAILED) + filebehave = FILE_STDIO; + else { + bufrem = st.st_size; + bufpos = buffer; + madvise(buffer, st.st_size, MADV_SEQUENTIAL); + } + } + } + + if ((buffer == NULL) || (buffer == MAP_FAILED)) + buffer = grep_malloc(MAXBUFSIZ); if (filebehave == FILE_GZIP && (gzbufdesc = gzdopen(f->fd, "r")) == NULL) - goto error; + goto error2; if (filebehave == FILE_BZIP && (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL) - goto error; + goto error2; /* Fill read buffer, also catches errors early */ - if (grep_refill(f) != 0) - goto error; + if (bufrem == 0 && grep_refill(f) != 0) + goto error2; /* Check for binary stuff, if necessary */ if (binbehave != BINFILE_TEXT && memchr(bufpos, '\0', bufrem) != NULL) - f->binary = true; + f->binary = true; return (f); -error: + +error2: close(f->fd); +error1: free(f); return (NULL); } /* - * Opens a file for processing. - */ -struct file * -grep_open(const char *path) -{ - struct file *f; - - f = grep_malloc(sizeof *f); - memset(f, 0, sizeof *f); - if (path == NULL) { - /* Processing stdin implies --line-buffered. */ - lbflag = true; - f->fd = STDIN_FILENO; - } else if ((f->fd = open(path, O_RDONLY)) == -1) { - free(f); - return (NULL); - } - - return (grep_file_init(f)); -} - -/* * Closes a file. */ void @@ -245,6 +302,10 @@ grep_close(struct file *f) close(f->fd); /* Reset read buffer and line buffer */ + if (filebehave == FILE_MMAP) { + munmap(buffer, fsiz); + buffer = NULL; + } bufpos = buffer; bufrem = 0; |