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