xref: /openbsd-src/usr.bin/grep/file.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: file.c,v 1.15 2019/01/31 01:30:46 tedu 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 <stdio.h>
34 #include <stdlib.h>
35 #include <zlib.h>
36 
37 #include "grep.h"
38 
39 static char	 fname[PATH_MAX];
40 static char	*lnbuf;
41 static size_t	 lnbufsize;
42 
43 #define FILE_STDIO	0
44 #define FILE_MMAP	1
45 #define FILE_GZIP	2
46 
47 struct file {
48 	int	 type;
49 	int	 noseek;
50 	FILE	*f;
51 	mmf_t	*mmf;
52 	gzFile	*gzf;
53 };
54 
55 #ifndef NOZ
56 static char *
57 gzfgetln(gzFile *f, size_t *len)
58 {
59 	size_t		n;
60 	int		c;
61 
62 	for (n = 0; ; ++n) {
63 		c = gzgetc(f);
64 		if (c == -1) {
65 			const char *gzerrstr;
66 			int gzerr;
67 
68 			if (gzeof(f))
69 				break;
70 
71 			gzerrstr = gzerror(f, &gzerr);
72 			if (gzerr == Z_ERRNO)
73 				err(2, "%s", fname);
74 			else
75 				errx(2, "%s: %s", fname, gzerrstr);
76 		}
77 		if (n >= lnbufsize) {
78 			lnbufsize *= 2;
79 			lnbuf = grep_realloc(lnbuf, ++lnbufsize);
80 		}
81 		if (c == '\n')
82 			break;
83 		lnbuf[n] = c;
84 	}
85 
86 	if (gzeof(f) && n == 0)
87 		return NULL;
88 	*len = n;
89 	return lnbuf;
90 }
91 #endif
92 
93 file_t *
94 grep_fdopen(int fd)
95 {
96 	file_t *f;
97 	struct stat sb;
98 
99 	if (fd == STDIN_FILENO)
100 		snprintf(fname, sizeof fname, "(standard input)");
101 	else if (fname[0] == '\0')
102 		snprintf(fname, sizeof fname, "(fd %d)", fd);
103 
104 	if (fstat(fd, &sb) == -1)
105 		return NULL;
106 	if (S_ISDIR(sb.st_mode)) {
107 		errno = EISDIR;
108 		return NULL;
109 	}
110 
111 	f = grep_malloc(sizeof *f);
112 
113 #ifndef NOZ
114 	if (Zflag) {
115 		f->type = FILE_GZIP;
116 		f->noseek = lseek(fd, 0L, SEEK_SET) == -1;
117 		if ((f->gzf = gzdopen(fd, "r")) != NULL)
118 			return f;
119 	}
120 #endif
121 	f->noseek = isatty(fd);
122 #ifndef SMALL
123 	/* try mmap first; if it fails, try stdio */
124 	if (!f->noseek && (f->mmf = mmopen(fd, &sb)) != NULL) {
125 		f->type = FILE_MMAP;
126 		return f;
127 	}
128 #endif
129 	f->type = FILE_STDIO;
130 	if ((f->f = fdopen(fd, "r")) != NULL)
131 		return f;
132 
133 	free(f);
134 	return NULL;
135 }
136 
137 file_t *
138 grep_open(char *path)
139 {
140 	file_t *f;
141 	int fd;
142 
143 	snprintf(fname, sizeof fname, "%s", path);
144 
145 	if ((fd = open(fname, O_RDONLY)) == -1)
146 		return NULL;
147 
148 	f = grep_fdopen(fd);
149 	if (f == NULL)
150 		close(fd);
151 	return f;
152 }
153 
154 int
155 grep_bin_file(file_t *f)
156 {
157 	if (f->noseek)
158 		return 0;
159 
160 	switch (f->type) {
161 	case FILE_STDIO:
162 		return bin_file(f->f);
163 #ifndef SMALL
164 	case FILE_MMAP:
165 		return mmbin_file(f->mmf);
166 #endif
167 #ifndef NOZ
168 	case FILE_GZIP:
169 		return gzbin_file(f->gzf);
170 #endif
171 	default:
172 		/* can't happen */
173 		errx(2, "invalid file type");
174 	}
175 }
176 
177 char *
178 grep_fgetln(file_t *f, size_t *l)
179 {
180 	switch (f->type) {
181 	case FILE_STDIO:
182 		if ((*l = getline(&lnbuf, &lnbufsize, f->f)) == -1) {
183 			if (ferror(f->f))
184 				err(2, "%s: getline", fname);
185 			else
186 				return NULL;
187 		}
188 		return lnbuf;
189 #ifndef SMALL
190 	case FILE_MMAP:
191 		return mmfgetln(f->mmf, l);
192 #endif
193 #ifndef NOZ
194 	case FILE_GZIP:
195 		return gzfgetln(f->gzf, l);
196 #endif
197 	default:
198 		/* can't happen */
199 		errx(2, "invalid file type");
200 	}
201 }
202 
203 void
204 grep_close(file_t *f)
205 {
206 	switch (f->type) {
207 	case FILE_STDIO:
208 		fclose(f->f);
209 		break;
210 #ifndef SMALL
211 	case FILE_MMAP:
212 		mmclose(f->mmf);
213 		break;
214 #endif
215 #ifndef NOZ
216 	case FILE_GZIP:
217 		gzclose(f->gzf);
218 		break;
219 #endif
220 	default:
221 		/* can't happen */
222 		errx(2, "invalid file type");
223 	}
224 	free(f);
225 }
226