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