1 #include "burp.h"
2 #include "alloc.h"
3 #include "cmd.h"
4 #include "fsops.h"
5 #include "fzp.h"
6 #include "log.h"
7 #include "prepend.h"
8 #ifndef HAVE_WIN32
9 #include "server/compress.h"
10 #include "server/protocol1/zlibio.h"
11 #endif
12
fzp_alloc(void)13 static struct fzp *fzp_alloc(void)
14 {
15 return (struct fzp *)calloc_w(1, sizeof(struct fzp), __func__);
16 }
17
fzp_free(struct fzp ** fzp)18 static void fzp_free(struct fzp **fzp)
19 {
20 if(!fzp || !*fzp) return;
21 free_w(&(*fzp)->buf);
22 free_v((void **)fzp);
23 }
24
open_fp(const char * fname,const char * mode)25 static FILE *open_fp(const char *fname, const char *mode)
26 {
27 FILE *fp=NULL;
28 if(!(fp=fopen(fname, mode)))
29 logp("could not open %s: %s\n", fname, strerror(errno));
30 return fp;
31 }
32
open_zp(const char * fname,const char * mode)33 static gzFile open_zp(const char *fname, const char *mode)
34 {
35 gzFile zp=NULL;
36
37 if(!(zp=gzopen(fname, mode)))
38 logp("could not open %s: %s\n", fname, strerror(errno));
39 return zp;
40 }
41
close_fp(FILE ** fp)42 static int close_fp(FILE **fp)
43 {
44 int ret=0;
45 if(!*fp) return ret;
46 if(fclose(*fp))
47 {
48 logp("fclose failed: %s\n", strerror(errno));
49 ret=-1;
50 }
51 *fp=NULL;
52 return ret;
53 }
54
close_zp(gzFile * zp)55 static int close_zp(gzFile *zp)
56 {
57 int e;
58 int ret=0;
59 if(!*zp) return ret;
60 if((e=gzclose(*zp))
61 // Can return Z_BUF_ERROR if the last read ended in the middle
62 // of a gzip stream. I saw this happening in utests on OpenBSD.
63 && e!=Z_BUF_ERROR)
64 {
65 const char *str=NULL;
66 if(e==Z_ERRNO)
67 str=strerror(errno);
68 logp("gzclose failed: %d (%s)\n", e, str?:"");
69 ret=-1;
70 }
71 return ret;
72 }
73
unknown_type(enum fzp_type type,const char * func)74 static void unknown_type(enum fzp_type type, const char *func)
75 {
76 logp("unknown type in %s: %d\n", func, type);
77 }
78
not_open(const char * func)79 static void not_open(const char *func)
80 {
81 logp("File pointer not open in %s\n", func);
82 }
83
fzp_do_open(const char * path,const char * mode,enum fzp_type type)84 static struct fzp *fzp_do_open(const char *path, const char *mode,
85 enum fzp_type type)
86 {
87 struct fzp *fzp=NULL;
88
89 if(!(fzp=fzp_alloc())) goto error;
90 fzp->type=type;
91 switch(type)
92 {
93 case FZP_FILE:
94 if(!(fzp->fp=open_fp(path, mode)))
95 goto error;
96 return fzp;
97 case FZP_COMPRESSED:
98 if(!(fzp->zp=open_zp(path, mode)))
99 goto error;
100 return fzp;
101 default:
102 unknown_type(fzp->type, __func__);
103 goto error;
104 }
105 error:
106 fzp_close(&fzp);
107 return NULL;
108 }
109
fzp_open(const char * path,const char * mode)110 struct fzp *fzp_open(const char *path, const char *mode)
111 {
112 return fzp_do_open(path, mode, FZP_FILE);
113 }
114
fzp_gzopen(const char * path,const char * mode)115 struct fzp *fzp_gzopen(const char *path, const char *mode)
116 {
117 return fzp_do_open(path, mode, FZP_COMPRESSED);
118 }
119
fzp_close(struct fzp ** fzp)120 int fzp_close(struct fzp **fzp)
121 {
122 int ret=-1;
123 if(!fzp || !*fzp) return 0;
124 switch((*fzp)->type)
125 {
126 case FZP_FILE:
127 ret=close_fp(&((*fzp)->fp));
128 break;
129 case FZP_COMPRESSED:
130 ret=close_zp(&((*fzp)->zp));
131 break;
132 default:
133 unknown_type((*fzp)->type, __func__);
134 break;
135 }
136 fzp_free(fzp);
137 return ret;
138 }
139
fzp_read(struct fzp * fzp,void * ptr,size_t nmemb)140 int fzp_read(struct fzp *fzp, void *ptr, size_t nmemb)
141 {
142 if(fzp) switch(fzp->type)
143 {
144 case FZP_FILE:
145 return (int)fread(ptr, 1, nmemb, fzp->fp);
146 case FZP_COMPRESSED:
147 return gzread(fzp->zp, ptr, (unsigned)nmemb);
148 default:
149 unknown_type(fzp->type, __func__);
150 goto error;
151 }
152 not_open(__func__);
153 error:
154 return 0;
155 }
156
fzp_write(struct fzp * fzp,const void * ptr,size_t nmemb)157 size_t fzp_write(struct fzp *fzp, const void *ptr, size_t nmemb)
158 {
159 if(fzp) switch(fzp->type)
160 {
161 case FZP_FILE:
162 return fwrite(ptr, 1, nmemb, fzp->fp);
163 case FZP_COMPRESSED:
164 return gzwrite(fzp->zp, ptr, (unsigned)nmemb);
165 default:
166 unknown_type(fzp->type, __func__);
167 goto error;
168 }
169 not_open(__func__);
170 error:
171 return 0;
172 }
173
fzp_eof(struct fzp * fzp)174 int fzp_eof(struct fzp *fzp)
175 {
176 if(fzp) switch(fzp->type)
177 {
178 case FZP_FILE:
179 return feof(fzp->fp);
180 case FZP_COMPRESSED:
181 return gzeof(fzp->zp);
182 default:
183 unknown_type(fzp->type, __func__);
184 goto error;
185 }
186 not_open(__func__);
187 error:
188 // Non-zero means end of file. Should be OK to use -1 here.
189 return -1;
190 }
191
fzp_flush(struct fzp * fzp)192 int fzp_flush(struct fzp *fzp)
193 {
194 if(fzp) switch(fzp->type)
195 {
196 case FZP_FILE:
197 return fflush(fzp->fp);
198 case FZP_COMPRESSED:
199 return gzflush(fzp->zp, Z_FINISH);
200 default:
201 unknown_type(fzp->type, __func__);
202 goto error;
203 }
204 not_open(__func__);
205 error:
206 return EOF;
207 }
208
fzp_seek(struct fzp * fzp,off_t offset,int whence)209 int fzp_seek(struct fzp *fzp, off_t offset, int whence)
210 {
211 if(fzp) switch(fzp->type)
212 {
213 case FZP_FILE:
214 return fseeko(fzp->fp, offset, whence);
215 case FZP_COMPRESSED:
216 // Notice that gzseek returns the new offset.
217 if(gzseek(fzp->zp, offset, whence)==offset)
218 return 0;
219 goto error;
220 default:
221 unknown_type(fzp->type, __func__);
222 goto error;
223 }
224 not_open(__func__);
225 error:
226 return -1;
227 }
228
fzp_tell(struct fzp * fzp)229 off_t fzp_tell(struct fzp *fzp)
230 {
231 if(fzp) switch(fzp->type)
232 {
233 case FZP_FILE:
234 return ftello(fzp->fp);
235 case FZP_COMPRESSED:
236 return gztell(fzp->zp);
237 default:
238 unknown_type(fzp->type, __func__);
239 goto error;
240 }
241 not_open(__func__);
242 error:
243 return -1;
244 }
245
246 #ifndef HAVE_WIN32
247 // There is no zlib gztruncate. Inflate it, truncate it, recompress it.
gztruncate(const char * path,off_t length,int compression)248 static int gztruncate(const char *path, off_t length, int compression)
249 {
250 int ret=1;
251 char tmp[16];
252 char *dest=NULL;
253 char *dest2=NULL;
254 snprintf(tmp, sizeof(tmp), ".%d", getpid());
255 if(!(dest=prepend(path, tmp))
256 || !(dest2=prepend(dest, "-2"))
257 || zlib_inflate(NULL, path, dest, NULL))
258 goto end;
259 if(truncate(dest, length))
260 {
261 logp("truncate of %s failed in %s\n", dest, __func__);
262 goto end;
263 }
264 if(compress_file(dest, dest2, compression))
265 goto end;
266 unlink(dest);
267 ret=do_rename(dest2, path);
268 end:
269 if(dest) unlink(dest);
270 if(dest2) unlink(dest2);
271 free_w(&dest);
272 free_w(&dest2);
273 return ret;
274 }
275
fzp_truncate(const char * path,enum fzp_type type,off_t length,int compression)276 int fzp_truncate(const char *path, enum fzp_type type, off_t length,
277 int compression)
278 {
279 if(!path)
280 {
281 // Avoids a valgrind complaint in one of the tests.
282 errno=ENOENT;
283 goto error;
284 }
285 switch(type)
286 {
287 case FZP_FILE:
288 return truncate(path, length);
289 case FZP_COMPRESSED:
290 return gztruncate(path, length, compression);
291 default:
292 unknown_type(type, __func__);
293 goto error;
294 }
295 error:
296 return -1;
297 }
298 #endif
299
fzp_printf(struct fzp * fzp,const char * format,...)300 int fzp_printf(struct fzp *fzp, const char *format, ...)
301 {
302 int ret=-1;
303 int n;
304
305 if(!fzp)
306 {
307 not_open(__func__);
308 return ret;
309 }
310
311 if(!fzp->buf)
312 {
313 fzp->s=128;
314 if(!(fzp->buf=(char *)malloc_w(fzp->s, __func__)))
315 return ret;
316 }
317
318 // Avoid fixed size buffer.
319 while(1)
320 {
321 va_list ap;
322 va_start(ap, format);
323 n=vsnprintf(fzp->buf, fzp->s, format, ap);
324 va_end(ap);
325 if(n<0)
326 {
327 logp("Failed to vsnprintf in %s: %s\n",
328 __func__, strerror(errno));
329 return ret;
330 }
331 if(fzp->s<(size_t)n)
332 {
333 fzp->s*=2;
334 if(!(fzp->buf=(char *)
335 realloc_w(fzp->buf, fzp->s, __func__)))
336 return ret;
337 continue;
338 }
339
340 break;
341 }
342
343 switch(fzp->type)
344 {
345 case FZP_FILE:
346 ret=fprintf(fzp->fp, "%s", fzp->buf);
347 break;
348 case FZP_COMPRESSED:
349 ret=gzprintf(fzp->zp, "%s", fzp->buf);
350 break;
351 default:
352 unknown_type(fzp->type, __func__);
353 break;
354 }
355
356 return ret;
357 }
358
fzp_setlinebuf(struct fzp * fzp)359 void fzp_setlinebuf(struct fzp *fzp)
360 {
361 #ifndef HAVE_WIN32
362 if(fzp) switch(fzp->type)
363 {
364 case FZP_FILE:
365 setlinebuf(fzp->fp);
366 return;
367 case FZP_COMPRESSED:
368 logp("gzsetlinebuf() does not exist in %s\n", __func__);
369 return;
370 default:
371 unknown_type(fzp->type, __func__);
372 return;
373 }
374 not_open(__func__);
375 #endif
376 }
377
fzp_gets(struct fzp * fzp,char * s,int size)378 char *fzp_gets(struct fzp *fzp, char *s, int size)
379 {
380 if(fzp) switch(fzp->type)
381 {
382 case FZP_FILE:
383 return fgets(s, size, fzp->fp);
384 case FZP_COMPRESSED:
385 return gzgets(fzp->zp, s, size);
386 default:
387 unknown_type(fzp->type, __func__);
388 goto error;
389 }
390 not_open(__func__);
391 error:
392 return NULL;
393 }
394
fzp_fileno(struct fzp * fzp)395 extern int fzp_fileno(struct fzp *fzp)
396 {
397 if(fzp) switch(fzp->type)
398 {
399 case FZP_FILE:
400 return fileno(fzp->fp);
401 case FZP_COMPRESSED:
402 logp("gzfileno() does not exist in %s\n", __func__);
403 goto error;
404 default:
405 unknown_type(fzp->type, __func__);
406 goto error;
407 }
408 not_open(__func__);
409 error:
410 return -1;
411 }
412
fzp_do_dopen(int fd,const char * mode,enum fzp_type type)413 static struct fzp *fzp_do_dopen(int fd, const char *mode,
414 enum fzp_type type)
415 {
416 struct fzp *fzp=NULL;
417
418 if(!(fzp=fzp_alloc())) goto error;
419 fzp->type=type;
420 switch(type)
421 {
422 case FZP_FILE:
423 if(!(fzp->fp=fdopen(fd, mode)))
424 goto error;
425 return fzp;
426 case FZP_COMPRESSED:
427 if(!(fzp->zp=gzdopen(fd, mode)))
428 goto error;
429 return fzp;
430 default:
431 unknown_type(fzp->type, __func__);
432 goto error;
433 }
434 error:
435 fzp_close(&fzp);
436 return NULL;
437 }
438
fzp_dopen(int fd,const char * mode)439 struct fzp *fzp_dopen(int fd, const char *mode)
440 {
441 return fzp_do_dopen(fd, mode, FZP_FILE);
442 }
443
fzp_gzdopen(int fd,const char * mode)444 struct fzp *fzp_gzdopen(int fd, const char *mode)
445 {
446 return fzp_do_dopen(fd, mode, FZP_COMPRESSED);
447 }
448
fzp_ERR_print_errors_fp(struct fzp * fzp)449 void fzp_ERR_print_errors_fp(struct fzp *fzp)
450 {
451 if(fzp) switch(fzp->type)
452 {
453 case FZP_FILE:
454 ERR_print_errors_fp(fzp->fp);
455 break;
456 case FZP_COMPRESSED:
457 logp("ERR_print_errors_zp() does not exist in %s\n",
458 __func__);
459 break;
460 default:
461 unknown_type(fzp->type, __func__);
462 break;
463 }
464 }
465
fzp_PEM_read_X509(struct fzp * fzp)466 X509 *fzp_PEM_read_X509(struct fzp *fzp)
467 {
468 if(fzp) switch(fzp->type)
469 {
470 case FZP_FILE:
471 return PEM_read_X509(fzp->fp, NULL, NULL, NULL);
472 case FZP_COMPRESSED:
473 logp("PEM_read_X509() does not exist in %s\n",
474 __func__);
475 goto error;
476 default:
477 unknown_type(fzp->type, __func__);
478 goto error;
479 }
480 not_open(__func__);
481 error:
482 return NULL;
483 }
484
pass_msg(size_t nmemb,size_t got,int pass)485 static void pass_msg(size_t nmemb, size_t got, int pass)
486 {
487 logp("Tried to read %lu bytes, got %lu by pass %d\n",
488 (unsigned long)nmemb, (unsigned long)got, pass);
489 }
490
fzp_read_ensure(struct fzp * fzp,void * ptr,size_t nmemb,const char * func)491 int fzp_read_ensure(struct fzp *fzp, void *ptr, size_t nmemb, const char *func)
492 {
493 static int f;
494 static int r;
495 static size_t got;
496 static int pass;
497 for(r=0, got=0, pass=0; got!=nmemb; pass++)
498 {
499 r=fzp_read(fzp, ((char *)ptr)+got, nmemb-got);
500 if(r>0)
501 {
502 got+=r;
503 continue;
504 }
505 if(r<0)
506 {
507 pass_msg(nmemb, got, pass);
508 logp("Error in %s, called from %s: %s\n",
509 __func__, func, strerror(errno));
510 return -1;
511 }
512 f=fzp_eof(fzp);
513 if(!f) continue; // Not yet end of file, keep trying.
514 if(f>0)
515 {
516 // End of file.
517 if(!got) return 1;
518 pass_msg(nmemb, got, pass);
519 logp("Error in %s, called from %s: %lu bytes, eof\n",
520 __func__, func, (unsigned long)got);
521 return -1;
522 }
523 else
524 {
525 pass_msg(nmemb, got, pass);
526 logp("Error in %s by fzp_feof, called from %s: %s\n",
527 __func__, func, strerror(errno));
528 return -1;
529 }
530 }
531 return 0;
532 }
533