xref: /openbsd/usr.bin/grep/file.c (revision 75891f45)
1 /*	$OpenBSD: file.c,v 1.17 2021/12/15 19:22:44 tb Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 James Howard and Dag-Erling Co�dan Sm�rgrav
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/stat.h>
30 #include <err.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <zlib.h>
38 
39 #include "grep.h"
40 
41 static char	 fname[PATH_MAX];
42 static char	*lnbuf;
43 static size_t	 lnbufsize;
44 
45 #define FILE_STDIO	0
46 #define FILE_MMAP	1
47 #define FILE_GZIP	2
48 
49 struct file {
50 	int	 type;
51 	int	 noseek;
52 	FILE	*f;
53 	mmf_t	*mmf;
54 	gzFile	 gzf;
55 };
56 
57 #ifndef NOZ
58 static char *
gzfgetln(gzFile f,size_t * len)59 gzfgetln(gzFile f, size_t *len)
60 {
61 	size_t		n;
62 	int		c;
63 
64 	for (n = 0; ; ++n) {
65 		c = gzgetc(f);
66 		if (c == -1) {
67 			const char *gzerrstr;
68 			int gzerr;
69 
70 			if (gzeof(f))
71 				break;
72 
73 			gzerrstr = gzerror(f, &gzerr);
74 			if (gzerr == Z_ERRNO)
75 				err(2, "%s", fname);
76 			else
77 				errx(2, "%s: %s", fname, gzerrstr);
78 		}
79 		if (n >= lnbufsize) {
80 			lnbufsize *= 2;
81 			lnbuf = grep_realloc(lnbuf, ++lnbufsize);
82 		}
83 		if (c == '\n')
84 			break;
85 		lnbuf[n] = c;
86 	}
87 
88 	if (gzeof(f) && n == 0)
89 		return NULL;
90 	*len = n;
91 	return lnbuf;
92 }
93 #endif
94 
95 file_t *
grep_fdopen(int fd)96 grep_fdopen(int fd)
97 {
98 	file_t *f;
99 	struct stat sb;
100 
101 	if (fd == STDIN_FILENO)
102 		snprintf(fname, sizeof fname, "(standard input)");
103 	else if (fname[0] == '\0')
104 		snprintf(fname, sizeof fname, "(fd %d)", fd);
105 
106 	if (fstat(fd, &sb) == -1)
107 		return NULL;
108 	if (S_ISDIR(sb.st_mode)) {
109 		errno = EISDIR;
110 		return NULL;
111 	}
112 
113 	f = grep_malloc(sizeof *f);
114 
115 #ifndef NOZ
116 	if (Zflag) {
117 		f->type = FILE_GZIP;
118 		f->noseek = lseek(fd, 0L, SEEK_SET) == -1;
119 		if ((f->gzf = gzdopen(fd, "r")) != NULL)
120 			return f;
121 	}
122 #endif
123 	f->noseek = isatty(fd);
124 #ifndef SMALL
125 	/* try mmap first; if it fails, try stdio */
126 	if (!f->noseek && (f->mmf = mmopen(fd, &sb)) != NULL) {
127 		f->type = FILE_MMAP;
128 		return f;
129 	}
130 #endif
131 	f->type = FILE_STDIO;
132 	if ((f->f = fdopen(fd, "r")) != NULL)
133 		return f;
134 
135 	free(f);
136 	return NULL;
137 }
138 
139 file_t *
grep_open(char * path)140 grep_open(char *path)
141 {
142 	file_t *f;
143 	int fd;
144 
145 	snprintf(fname, sizeof fname, "%s", path);
146 
147 	if ((fd = open(fname, O_RDONLY)) == -1)
148 		return NULL;
149 
150 	f = grep_fdopen(fd);
151 	if (f == NULL)
152 		close(fd);
153 	return f;
154 }
155 
156 int
grep_bin_file(file_t * f)157 grep_bin_file(file_t *f)
158 {
159 	if (f->noseek)
160 		return 0;
161 
162 	switch (f->type) {
163 	case FILE_STDIO:
164 		return bin_file(f->f);
165 #ifndef SMALL
166 	case FILE_MMAP:
167 		return mmbin_file(f->mmf);
168 #endif
169 #ifndef NOZ
170 	case FILE_GZIP:
171 		return gzbin_file(f->gzf);
172 #endif
173 	default:
174 		/* can't happen */
175 		errx(2, "invalid file type");
176 	}
177 }
178 
179 char *
grep_fgetln(file_t * f,size_t * l)180 grep_fgetln(file_t *f, size_t *l)
181 {
182 	switch (f->type) {
183 	case FILE_STDIO:
184 		if ((*l = getline(&lnbuf, &lnbufsize, f->f)) == -1) {
185 			if (ferror(f->f))
186 				err(2, "%s: getline", fname);
187 			else
188 				return NULL;
189 		}
190 		return lnbuf;
191 #ifndef SMALL
192 	case FILE_MMAP:
193 		return mmfgetln(f->mmf, l);
194 #endif
195 #ifndef NOZ
196 	case FILE_GZIP:
197 		return gzfgetln(f->gzf, l);
198 #endif
199 	default:
200 		/* can't happen */
201 		errx(2, "invalid file type");
202 	}
203 }
204 
205 void
grep_close(file_t * f)206 grep_close(file_t *f)
207 {
208 	switch (f->type) {
209 	case FILE_STDIO:
210 		fclose(f->f);
211 		break;
212 #ifndef SMALL
213 	case FILE_MMAP:
214 		mmclose(f->mmf);
215 		break;
216 #endif
217 #ifndef NOZ
218 	case FILE_GZIP:
219 		gzclose(f->gzf);
220 		break;
221 #endif
222 	default:
223 		/* can't happen */
224 		errx(2, "invalid file type");
225 	}
226 	free(f);
227 }
228