xref: /openbsd-src/usr.bin/grep/file.c (revision 75891f45ba202082e573a03f58a61c230bb10e38)
1*75891f45Stb /*	$OpenBSD: file.c,v 1.17 2021/12/15 19:22:44 tb Exp $	*/
2fd6e2b5bSderaadt 
3fe07e37bSderaadt /*-
4fe07e37bSderaadt  * Copyright (c) 1999 James Howard and Dag-Erling Co�dan Sm�rgrav
5fe07e37bSderaadt  * All rights reserved.
6fe07e37bSderaadt  *
7fe07e37bSderaadt  * Redistribution and use in source and binary forms, with or without
8fe07e37bSderaadt  * modification, are permitted provided that the following conditions
9fe07e37bSderaadt  * are met:
10fe07e37bSderaadt  * 1. Redistributions of source code must retain the above copyright
11fe07e37bSderaadt  *    notice, this list of conditions and the following disclaimer.
12fe07e37bSderaadt  * 2. Redistributions in binary form must reproduce the above copyright
13fe07e37bSderaadt  *    notice, this list of conditions and the following disclaimer in the
14fe07e37bSderaadt  *    documentation and/or other materials provided with the distribution.
15fe07e37bSderaadt  *
16fe07e37bSderaadt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17fe07e37bSderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fe07e37bSderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fe07e37bSderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20fe07e37bSderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21fe07e37bSderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22fe07e37bSderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fe07e37bSderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24fe07e37bSderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fe07e37bSderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fe07e37bSderaadt  * SUCH DAMAGE.
27fe07e37bSderaadt  */
28fe07e37bSderaadt 
293a21e479Stedu #include <sys/stat.h>
30fe07e37bSderaadt #include <err.h>
313a21e479Stedu #include <errno.h>
323a21e479Stedu #include <fcntl.h>
33*75891f45Stb #include <limits.h>
34fe07e37bSderaadt #include <stdio.h>
35fe07e37bSderaadt #include <stdlib.h>
36*75891f45Stb #include <unistd.h>
37fe07e37bSderaadt #include <zlib.h>
38fe07e37bSderaadt 
39fe07e37bSderaadt #include "grep.h"
40fe07e37bSderaadt 
41b9fc9a72Sderaadt static char	 fname[PATH_MAX];
42fe07e37bSderaadt static char	*lnbuf;
436ec3986fStedu static size_t	 lnbufsize;
44fe07e37bSderaadt 
45fe07e37bSderaadt #define FILE_STDIO	0
46fe07e37bSderaadt #define FILE_MMAP	1
47fe07e37bSderaadt #define FILE_GZIP	2
48fe07e37bSderaadt 
49fe07e37bSderaadt struct file {
50fe07e37bSderaadt 	int	 type;
5171d182b2Sotto 	int	 noseek;
52fe07e37bSderaadt 	FILE	*f;
53fe07e37bSderaadt 	mmf_t	*mmf;
5419739ec8Smillert 	gzFile	 gzf;
55fe07e37bSderaadt };
56fe07e37bSderaadt 
5738d402d2Sderaadt #ifndef NOZ
58fe07e37bSderaadt static char *
gzfgetln(gzFile f,size_t * len)5919739ec8Smillert gzfgetln(gzFile f, size_t *len)
60fe07e37bSderaadt {
61fe07e37bSderaadt 	size_t		n;
62fe07e37bSderaadt 	int		c;
63fe07e37bSderaadt 
64fe07e37bSderaadt 	for (n = 0; ; ++n) {
65fe07e37bSderaadt 		c = gzgetc(f);
66fe07e37bSderaadt 		if (c == -1) {
67fe07e37bSderaadt 			const char *gzerrstr;
68fe07e37bSderaadt 			int gzerr;
69fe07e37bSderaadt 
70fe07e37bSderaadt 			if (gzeof(f))
71fe07e37bSderaadt 				break;
72fe07e37bSderaadt 
73fe07e37bSderaadt 			gzerrstr = gzerror(f, &gzerr);
74fe07e37bSderaadt 			if (gzerr == Z_ERRNO)
75f91b5226Smillert 				err(2, "%s", fname);
76fe07e37bSderaadt 			else
77f91b5226Smillert 				errx(2, "%s: %s", fname, gzerrstr);
78fe07e37bSderaadt 		}
796ec3986fStedu 		if (n >= lnbufsize) {
806ec3986fStedu 			lnbufsize *= 2;
816ec3986fStedu 			lnbuf = grep_realloc(lnbuf, ++lnbufsize);
82fe07e37bSderaadt 		}
8325ef2405Scanacar 		if (c == '\n')
8425ef2405Scanacar 			break;
85fe07e37bSderaadt 		lnbuf[n] = c;
86fe07e37bSderaadt 	}
87fe07e37bSderaadt 
88fe07e37bSderaadt 	if (gzeof(f) && n == 0)
89fe07e37bSderaadt 		return NULL;
90fe07e37bSderaadt 	*len = n;
91fe07e37bSderaadt 	return lnbuf;
92fe07e37bSderaadt }
9338d402d2Sderaadt #endif
94fe07e37bSderaadt 
95fe07e37bSderaadt file_t *
grep_fdopen(int fd)963a21e479Stedu grep_fdopen(int fd)
97fe07e37bSderaadt {
98fe07e37bSderaadt 	file_t *f;
993a21e479Stedu 	struct stat sb;
100fe07e37bSderaadt 
101c4dcc50fStedu 	if (fd == STDIN_FILENO)
10238d402d2Sderaadt 		snprintf(fname, sizeof fname, "(standard input)");
1033a21e479Stedu 	else if (fname[0] == '\0')
10438d402d2Sderaadt 		snprintf(fname, sizeof fname, "(fd %d)", fd);
105fe07e37bSderaadt 
1063a21e479Stedu 	if (fstat(fd, &sb) == -1)
1073a21e479Stedu 		return NULL;
1083a21e479Stedu 	if (S_ISDIR(sb.st_mode)) {
1093a21e479Stedu 		errno = EISDIR;
1103a21e479Stedu 		return NULL;
1113a21e479Stedu 	}
1123a21e479Stedu 
113fe07e37bSderaadt 	f = grep_malloc(sizeof *f);
114fe07e37bSderaadt 
11538d402d2Sderaadt #ifndef NOZ
116fe07e37bSderaadt 	if (Zflag) {
117fe07e37bSderaadt 		f->type = FILE_GZIP;
11871d182b2Sotto 		f->noseek = lseek(fd, 0L, SEEK_SET) == -1;
1193a21e479Stedu 		if ((f->gzf = gzdopen(fd, "r")) != NULL)
120fe07e37bSderaadt 			return f;
121fe07e37bSderaadt 	}
1223a21e479Stedu #endif
1233a21e479Stedu 	f->noseek = isatty(fd);
1243a21e479Stedu #ifndef SMALL
1253a21e479Stedu 	/* try mmap first; if it fails, try stdio */
1263a21e479Stedu 	if (!f->noseek && (f->mmf = mmopen(fd, &sb)) != NULL) {
1273a21e479Stedu 		f->type = FILE_MMAP;
1283a21e479Stedu 		return f;
1293a21e479Stedu 	}
1303a21e479Stedu #endif
1313a21e479Stedu 	f->type = FILE_STDIO;
1323a21e479Stedu 	if ((f->f = fdopen(fd, "r")) != NULL)
1333a21e479Stedu 		return f;
134fe07e37bSderaadt 
135fe07e37bSderaadt 	free(f);
136fe07e37bSderaadt 	return NULL;
137fe07e37bSderaadt }
138fe07e37bSderaadt 
139fe07e37bSderaadt file_t *
grep_open(char * path)1403a21e479Stedu grep_open(char *path)
141fe07e37bSderaadt {
142fe07e37bSderaadt 	file_t *f;
1433a21e479Stedu 	int fd;
144fe07e37bSderaadt 
14538d402d2Sderaadt 	snprintf(fname, sizeof fname, "%s", path);
146fe07e37bSderaadt 
1473a21e479Stedu 	if ((fd = open(fname, O_RDONLY)) == -1)
148fe07e37bSderaadt 		return NULL;
1493a21e479Stedu 
1503a21e479Stedu 	f = grep_fdopen(fd);
1513a21e479Stedu 	if (f == NULL)
1523a21e479Stedu 		close(fd);
1533a21e479Stedu 	return f;
154fe07e37bSderaadt }
155fe07e37bSderaadt 
156fe07e37bSderaadt int
grep_bin_file(file_t * f)157fe07e37bSderaadt grep_bin_file(file_t *f)
158fe07e37bSderaadt {
15971d182b2Sotto 	if (f->noseek)
16071d182b2Sotto 		return 0;
16171d182b2Sotto 
162fe07e37bSderaadt 	switch (f->type) {
163fe07e37bSderaadt 	case FILE_STDIO:
164fe07e37bSderaadt 		return bin_file(f->f);
1657fec5d18Snicm #ifndef SMALL
166fe07e37bSderaadt 	case FILE_MMAP:
167fe07e37bSderaadt 		return mmbin_file(f->mmf);
1687fec5d18Snicm #endif
16938d402d2Sderaadt #ifndef NOZ
170fe07e37bSderaadt 	case FILE_GZIP:
171fe07e37bSderaadt 		return gzbin_file(f->gzf);
17238d402d2Sderaadt #endif
173fe07e37bSderaadt 	default:
174fe07e37bSderaadt 		/* can't happen */
175f91b5226Smillert 		errx(2, "invalid file type");
176fe07e37bSderaadt 	}
177fe07e37bSderaadt }
178fe07e37bSderaadt 
179fe07e37bSderaadt char *
grep_fgetln(file_t * f,size_t * l)180fe07e37bSderaadt grep_fgetln(file_t *f, size_t *l)
181fe07e37bSderaadt {
182fe07e37bSderaadt 	switch (f->type) {
183fe07e37bSderaadt 	case FILE_STDIO:
1846ec3986fStedu 		if ((*l = getline(&lnbuf, &lnbufsize, f->f)) == -1) {
1856ec3986fStedu 			if (ferror(f->f))
1866ec3986fStedu 				err(2, "%s: getline", fname);
1876ec3986fStedu 			else
1886ec3986fStedu 				return NULL;
1896ec3986fStedu 		}
1906ec3986fStedu 		return lnbuf;
1917fec5d18Snicm #ifndef SMALL
192fe07e37bSderaadt 	case FILE_MMAP:
193fe07e37bSderaadt 		return mmfgetln(f->mmf, l);
1947fec5d18Snicm #endif
19538d402d2Sderaadt #ifndef NOZ
196fe07e37bSderaadt 	case FILE_GZIP:
197fe07e37bSderaadt 		return gzfgetln(f->gzf, l);
19838d402d2Sderaadt #endif
199fe07e37bSderaadt 	default:
200fe07e37bSderaadt 		/* can't happen */
201f91b5226Smillert 		errx(2, "invalid file type");
202fe07e37bSderaadt 	}
203fe07e37bSderaadt }
204fe07e37bSderaadt 
205fe07e37bSderaadt void
grep_close(file_t * f)206fe07e37bSderaadt grep_close(file_t *f)
207fe07e37bSderaadt {
208fe07e37bSderaadt 	switch (f->type) {
209fe07e37bSderaadt 	case FILE_STDIO:
210fe07e37bSderaadt 		fclose(f->f);
211fe07e37bSderaadt 		break;
2127fec5d18Snicm #ifndef SMALL
213fe07e37bSderaadt 	case FILE_MMAP:
214fe07e37bSderaadt 		mmclose(f->mmf);
215fe07e37bSderaadt 		break;
2167fec5d18Snicm #endif
21738d402d2Sderaadt #ifndef NOZ
218fe07e37bSderaadt 	case FILE_GZIP:
219fe07e37bSderaadt 		gzclose(f->gzf);
220fe07e37bSderaadt 		break;
22138d402d2Sderaadt #endif
222fe07e37bSderaadt 	default:
223fe07e37bSderaadt 		/* can't happen */
224f91b5226Smillert 		errx(2, "invalid file type");
225fe07e37bSderaadt 	}
2263faa8aa0Sotto 	free(f);
227fe07e37bSderaadt }
228