source: zzuf/trunk/src/lib-stream.c @ 2559

Last change on this file since 2559 was 2559, checked in by Sam Hocevar, 12 years ago
  • Support fsetpos64 on Linux.
  • Property svn:keywords set to Id
File size: 21.1 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: lib-stream.c 2559 2008-07-16 23:17:12Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  load-stream.c: loaded stream functions
17 */
18
19#include "config.h"
20
21/* Needed for getline() and getdelim() */
22#define _GNU_SOURCE
23/* Needed for getc_unlocked() on OpenSolaris */
24#define __EXTENSIONS__
25
26#if defined HAVE___SREFILL || defined HAVE___FILBUF
27#   define HAVE_REFILL_STDIO
28#endif
29
30#if defined HAVE_STDINT_H
31#   include <stdint.h>
32#elif defined HAVE_INTTYPES_H
33#   include <inttypes.h>
34#endif
35#include <stdlib.h>
36
37#include <stdio.h>
38#include <sys/types.h>
39#if defined HAVE_REFILL_STDIO && defined HAVE_UNISTD_H
40#   include <unistd.h> /* Needed for __srefill’s lseek() call */
41#endif
42
43#include "libzzuf.h"
44#include "lib-load.h"
45#include "debug.h"
46#include "fuzz.h"
47#include "fd.h"
48
49#if defined HAVE___SREFILL
50int NEW(__srefill)(FILE *fp);
51#endif
52
53#if defined HAVE___FILBUF
54int NEW(__filbuf)(FILE *fp);
55#endif
56
57/* Library functions that we divert */
58static FILE *  (*ORIG(fopen))    (const char *path, const char *mode);
59#if defined HAVE_FOPEN64
60static FILE *  (*ORIG(fopen64))  (const char *path, const char *mode);
61#endif
62#if defined HAVE___FOPEN64
63static FILE *  (*ORIG(__fopen64))(const char *path, const char *mode);
64#endif
65static FILE *  (*ORIG(freopen))  (const char *path, const char *mode,
66                                  FILE *stream);
67#if defined HAVE_FREOPEN64
68static FILE *  (*ORIG(freopen64))(const char *path, const char *mode,
69                                  FILE *stream);
70#endif
71#if defined HAVE___FREOPEN64
72static FILE *  (*ORIG(__freopen64)) (const char *path, const char *mode,
73                                     FILE *stream);
74#endif
75static int     (*ORIG(fseek))    (FILE *stream, long offset, int whence);
76#if defined HAVE_FSEEKO
77static int     (*ORIG(fseeko))   (FILE *stream, off_t offset, int whence);
78#endif
79#if defined HAVE_FSEEKO64
80static int     (*ORIG(fseeko64)) (FILE *stream, off_t offset, int whence);
81#endif
82#if defined HAVE___FSEEKO64
83static int     (*ORIG(__fseeko64)) (FILE *stream, off_t offset, int whence);
84#endif
85#if defined HAVE_FSETPOS64
86static int     (*ORIG(fsetpos64))(FILE *stream, const fpos64_t *pos);
87#endif
88#if defined HAVE___FSETPOS64
89static int     (*ORIG(__fsetpos64)) (FILE *stream, const fpos64_t *pos);
90#endif
91static void    (*ORIG(rewind))   (FILE *stream);
92static size_t  (*ORIG(fread))    (void *ptr, size_t size, size_t nmemb,
93                                  FILE *stream);
94#if defined HAVE_FREAD_UNLOCKED
95static size_t  (*ORIG(fread_unlocked))  (void *ptr, size_t size, size_t nmemb,
96                                         FILE *stream);
97#endif
98static int     (*ORIG(getc))     (FILE *stream);
99static int     (*ORIG(getchar))  (void);
100static int     (*ORIG(fgetc))    (FILE *stream);
101#if defined HAVE__IO_GETC
102static int     (*ORIG(_IO_getc)) (FILE *stream);
103#endif
104#if defined HAVE_GETC_UNLOCKED
105static int     (*ORIG(getc_unlocked))    (FILE *stream);
106#endif
107#if defined HAVE_GETCHAR_UNLOCKED
108static int     (*ORIG(getchar_unlocked)) (void);
109#endif
110#if defined HAVE_FGETC_UNLOCKED
111static int     (*ORIG(fgetc_unlocked))   (FILE *stream);
112#endif
113static char *  (*ORIG(fgets))    (char *s, int size, FILE *stream);
114#if defined HAVE_FGETS_UNLOCKED
115static char *  (*ORIG(fgets_unlocked))   (char *s, int size, FILE *stream);
116#endif
117static int     (*ORIG(ungetc))   (int c, FILE *stream);
118static int     (*ORIG(fclose))   (FILE *fp);
119
120/* Additional GNUisms */
121#if defined HAVE_GETLINE
122static ssize_t (*ORIG(getline))    (char **lineptr, size_t *n, FILE *stream);
123#endif
124#if defined HAVE_GETDELIM
125static ssize_t (*ORIG(getdelim))   (char **lineptr, size_t *n, int delim,
126                                    FILE *stream);
127#endif
128#if defined HAVE___GETDELIM
129static ssize_t (*ORIG(__getdelim)) (char **lineptr, size_t *n, int delim,
130                                    FILE *stream);
131#endif
132
133/* Additional BSDisms */
134#if defined HAVE_FGETLN
135static char *  (*ORIG(fgetln))    (FILE *stream, size_t *len);
136#endif
137#if defined HAVE___SREFILL
138int            (*ORIG(__srefill)) (FILE *fp);
139#endif
140
141/* Additional HP-UXisms */
142#if defined HAVE___FILBUF
143int            (*ORIG(__filbuf))  (FILE *fp);
144#endif
145
146/* Our function wrappers */
147#if defined HAVE_REFILL_STDIO /* Fuzz fp if we have __srefill() */
148#   define FOPEN_FUZZ() \
149    _zz_fuzz(fd, ret->FILE_PTR, ret->FILE_CNT)
150#else
151#   define FOPEN_FUZZ()
152#endif
153
154#define FOPEN(fn) \
155    do \
156    { \
157        LOADSYM(fn); \
158        if(!_zz_ready) \
159            return ORIG(fn)(path, mode); \
160        _zz_lock(-1); \
161        ret = ORIG(fn)(path, mode); \
162        _zz_unlock(-1); \
163        if(ret && _zz_mustwatch(path)) \
164        { \
165            int fd = fileno(ret); \
166            _zz_register(fd); \
167            debug("%s(\"%s\", \"%s\") = [%i]", __func__, path, mode, fd); \
168            FOPEN_FUZZ(); \
169        } \
170    } while(0)
171
172FILE *NEW(fopen)(const char *path, const char *mode)
173{
174    FILE *ret; FOPEN(fopen); return ret;
175}
176
177#if defined HAVE_FOPEN64
178FILE *NEW(fopen64)(const char *path, const char *mode)
179{
180    FILE *ret; FOPEN(fopen64); return ret;
181}
182#endif
183
184#if defined HAVE___FOPEN64
185FILE *NEW(__fopen64)(const char *path, const char *mode)
186{
187    FILE *ret; FOPEN(__fopen64); return ret;
188}
189#endif
190
191#define FREOPEN(fn) \
192    do \
193    { \
194        int fd0 = -1, fd1 = -1, disp = 0; \
195        LOADSYM(fn); \
196        if(_zz_ready && (fd0 = fileno(stream)) >= 0 && _zz_iswatched(fd0)) \
197        { \
198            _zz_unregister(fd0); \
199            disp = 1; \
200        } \
201        _zz_lock(-1); \
202        ret = ORIG(fn)(path, mode, stream); \
203        _zz_unlock(-1); \
204        if(ret && _zz_mustwatch(path)) \
205        { \
206            fd1 = fileno(ret); \
207            _zz_register(fd1); \
208            disp = 1; \
209        } \
210        if(disp) \
211            debug("%s(\"%s\", \"%s\", [%i]) = [%i]", __func__, \
212                  path, mode, fd0, fd1); \
213    } while(0)
214
215FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream)
216{
217    FILE *ret; FREOPEN(freopen); return ret;
218}
219
220#if defined HAVE_FREOPEN64
221FILE *NEW(freopen64)(const char *path, const char *mode, FILE *stream)
222{
223    FILE *ret; FREOPEN(freopen64); return ret;
224}
225#endif
226
227#if defined HAVE___FREOPEN64
228FILE *NEW(__freopen64)(const char *path, const char *mode, FILE *stream)
229{
230    FILE *ret; FREOPEN(__freopen64); return ret;
231}
232#endif
233
234#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
235#   define FSEEK_FUZZ(fn2)
236#else
237#   define FSEEK_FUZZ(fn2) \
238        if(ret == 0) \
239        { \
240            /* FIXME: check what happens when fseek()ing a pipe */ \
241            switch(whence) \
242            { \
243                case SEEK_END: \
244                    offset = fn2(stream); \
245                    /* fall through */ \
246                case SEEK_SET: \
247                    _zz_setpos(fd, offset); \
248                    break; \
249                case SEEK_CUR: \
250                    _zz_addpos(fd, offset); \
251                    break; \
252            } \
253        }
254#endif
255
256#define FSEEK(fn, fn2) \
257    do \
258    { \
259        int fd; \
260        LOADSYM(fn); \
261        fd = fileno(stream); \
262        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
263            return ORIG(fn)(stream, offset, whence); \
264        _zz_lock(fd); \
265        ret = ORIG(fn)(stream, offset, whence); \
266        _zz_unlock(fd); \
267        debug("%s([%i], %lli, %i) = %i", __func__, \
268              fd, (long long int)offset, whence, ret); \
269        FSEEK_FUZZ(fn2) \
270    } while(0)
271
272int NEW(fseek)(FILE *stream, long offset, int whence)
273{
274    int ret; FSEEK(fseek, ftell); return ret;
275}
276
277#if defined HAVE_FSEEKO
278int NEW(fseeko)(FILE *stream, off_t offset, int whence)
279{
280    int ret; FSEEK(fseeko, ftello); return ret;
281}
282#endif
283
284#if defined HAVE_FSEEKO64
285int NEW(fseeko64)(FILE *stream, off64_t offset, int whence)
286{
287    int ret; FSEEK(fseeko64, ftello); return ret;
288}
289#endif
290
291#if defined HAVE___FSEEKO64
292int NEW(__fseeko64)(FILE *stream, off64_t offset, int whence)
293{
294    int ret; FSEEK(__fseeko64, ftello); return ret;
295}
296#endif
297
298#define FSETPOS(fn) \
299    do \
300    { \
301        int fd; \
302        LOADSYM(fn); \
303        fd = fileno(stream); \
304        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
305            return ORIG(fn)(stream, pos); \
306        _zz_lock(fd); \
307        ret = ORIG(fn)(stream, pos); \
308        _zz_unlock(fd); \
309        debug("%s([%i], %lli) = %i", __func__, \
310              fd, (long long int)FPOS_CAST(*pos), ret); \
311        _zz_setpos(fd, (int64_t)FPOS_CAST(*pos)); \
312    } \
313    while(0)
314
315#if defined HAVE_FSETPOS64
316int NEW(fsetpos64)(FILE *stream, const fpos64_t *pos)
317{
318    int ret; FSETPOS(fsetpos64); return ret;
319}
320#endif
321
322#if defined HAVE___FSETPOS64
323int NEW(__fsetpos64)(FILE *stream, const fpos64_t *pos)
324{
325    int ret; FSETPOS(__fsetpos64); return ret;
326}
327#endif
328
329void NEW(rewind)(FILE *stream)
330{
331    int fd;
332
333    LOADSYM(rewind);
334    fd = fileno(stream);
335    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
336    {
337        ORIG(rewind)(stream);
338        return;
339    }
340
341    _zz_lock(fd);
342    ORIG(rewind)(stream);
343    _zz_unlock(fd);
344    debug("%s([%i])", __func__, fd);
345
346#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
347#else
348    /* FIXME: check what happens when rewind()ing a pipe */
349    _zz_setpos(fd, 0);
350#endif
351}
352
353#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
354#   define FREAD_FUZZ() \
355    do \
356    { \
357        debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
358              (long int)size, (long int)nmemb, fd, (long int)ret); \
359    } while(0)
360#else
361#   define FREAD_FUZZ() \
362    do \
363    { \
364        int64_t newpos = ftell(stream); \
365        /* XXX: the number of bytes read is not ret * size, because \
366         * a partial read may have advanced the stream pointer. However, \
367         * when reading from a pipe ftell() will return 0, and ret * size \
368         * is then better than nothing. */ \
369        if(newpos <= 0) \
370        { \
371            pos = _zz_getpos(fd); \
372            newpos = pos + ret * size; \
373        } \
374        if(newpos != pos) \
375        { \
376            char *b = ptr; \
377            _zz_fuzz(fd, ptr, newpos - pos); \
378            _zz_setpos(fd, newpos); \
379            if(newpos >= pos + 4) \
380                debug("%s(%p, %li, %li, [%i]) = %li \"%c%c%c%c...", __func__, \
381                      ptr, (long int)size, (long int)nmemb, fd, \
382                      (long int)ret, b[0], b[1], b[2], b[3]); \
383            else \
384                debug("%s(%p, %li, %li, [%i]) = %li \"%c...", __func__, ptr, \
385                      (long int)size, (long int)nmemb, fd, \
386                      (long int)ret, b[0]); \
387        } \
388        else \
389            debug("%s(%p, %li, %li, [%i]) = %li", __func__, ptr, \
390                  (long int)size, (long int)nmemb, fd, (long int)ret); \
391    } while(0)
392#endif
393
394#define FREAD(fn) \
395    do \
396    { \
397        int64_t pos; \
398        int fd; \
399        LOADSYM(fn); \
400        fd = fileno(stream); \
401        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
402            return ORIG(fn)(ptr, size, nmemb, stream); \
403        pos = ftell(stream); \
404        _zz_lock(fd); \
405        ret = ORIG(fn)(ptr, size, nmemb, stream); \
406        _zz_unlock(fd); \
407        FREAD_FUZZ(); \
408    } while(0)
409
410size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream)
411{
412    size_t ret; FREAD(fread); return ret;
413}
414
415#if defined HAVE_FREAD_UNLOCKED
416#undef fread_unlocked /* can be a macro; we don’t want that */
417size_t NEW(fread_unlocked)(void *ptr, size_t size, size_t nmemb, FILE *stream)
418{
419    size_t ret; FREAD(fread_unlocked); return ret;
420}
421#endif
422
423#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
424#   define FGETC_FUZZ
425#else
426#   define FGETC_FUZZ \
427        if(ret != EOF) \
428        { \
429            uint8_t ch = ret; \
430            _zz_fuzz(fd, &ch, 1); \
431            _zz_addpos(fd, 1); \
432            ret = ch; \
433        }
434#endif
435
436#define FGETC(fn, s, arg) \
437    do { \
438        int fd; \
439        LOADSYM(fn); \
440        fd = fileno(s); \
441        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
442            return ORIG(fn)(arg); \
443        _zz_lock(fd); \
444        ret = ORIG(fn)(arg); \
445        _zz_unlock(fd); \
446        FGETC_FUZZ \
447        if(ret == EOF) \
448            debug("%s([%i]) = EOF", __func__, fd); \
449        else \
450            debug("%s([%i]) = '%c'", __func__, fd, ret); \
451    } while(0)
452
453#undef getc /* can be a macro; we don’t want that */
454int NEW(getc)(FILE *stream)
455{
456    int ret; FGETC(getc, stream, stream); return ret;
457}
458
459#undef getchar /* can be a macro; we don’t want that */
460int NEW(getchar)(void)
461{
462    int ret; FGETC(getchar, stdin, /* empty */); return ret;
463}
464
465int NEW(fgetc)(FILE *stream)
466{
467    int ret; FGETC(fgetc, stream, stream); return ret;
468}
469
470#if defined HAVE__IO_GETC
471int NEW(_IO_getc)(FILE *stream)
472{
473    int ret; FGETC(_IO_getc, stream, stream); return ret;
474}
475#endif
476
477#if defined HAVE_GETC_UNLOCKED
478#undef getc_unlocked /* can be a macro; we don’t want that */
479int NEW(getc_unlocked)(FILE *stream)
480{
481    int ret; FGETC(getc_unlocked, stream, stream); return ret;
482}
483#endif
484
485#if defined HAVE_GETCHAR_UNLOCKED
486#undef getchar_unlocked /* can be a macro; we don’t want that */
487int NEW(getchar_unlocked)(void)
488{
489    int ret; FGETC(getchar_unlocked, stdin, /* empty */); return ret;
490}
491#endif
492
493#if defined HAVE_FGETC_UNLOCKED
494#undef fgetc_unlocked /* can be a macro; we don’t want that */
495int NEW(fgetc_unlocked)(FILE *stream)
496{
497    int ret; FGETC(fgetc_unlocked, stream, stream); return ret;
498}
499#endif
500
501#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
502#   define FGETS_FUZZ(fn, fn2) \
503        _zz_lock(fd); \
504        ret = ORIG(fn)(s, size, stream); \
505        _zz_unlock(fd);
506#else
507#   define FGETS_FUZZ(fn, fn2) \
508        if(size <= 0) \
509            ret = NULL; \
510        else if(size == 1) \
511            s[0] = '\0'; \
512        else \
513        { \
514            int i; \
515            for(i = 0; i < size - 1; i++) \
516            { \
517                int ch; \
518                _zz_lock(fd); \
519                ch = ORIG(fn2)(stream); \
520                _zz_unlock(fd); \
521                if(ch == EOF) \
522                { \
523                    s[i] = '\0'; \
524                    if(!i) \
525                        ret = NULL; \
526                    break; \
527                } \
528                s[i] = (char)(unsigned char)ch; \
529                _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ \
530                _zz_addpos(fd, 1); \
531                if(s[i] == '\n') \
532                { \
533                    s[i + 1] = '\0'; \
534                    break; \
535                } \
536            } \
537        }
538#endif
539
540#define FGETS(fn, fn2) \
541    do \
542    { \
543        int fd; \
544        ret = s; \
545        LOADSYM(fn); \
546        LOADSYM(fn2); \
547        fd = fileno(stream); \
548        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
549            return ORIG(fn)(s, size, stream); \
550        FGETS_FUZZ(fn, fn2) \
551        debug("%s(%p, %i, [%i]) = %p", __func__, s, size, fd, ret); \
552    } while(0)
553
554char *NEW(fgets)(char *s, int size, FILE *stream)
555{
556    char *ret; FGETS(fgets, fgetc); return ret;
557}
558
559#if defined HAVE_FGETS_UNLOCKED
560char *NEW(fgets_unlocked)(char *s, int size, FILE *stream)
561{
562    char *ret; FGETS(fgets_unlocked, fgetc_unlocked); return ret;
563}
564#endif
565
566int NEW(ungetc)(int c, FILE *stream)
567{
568    int ret, fd;
569
570    LOADSYM(ungetc);
571    fd = fileno(stream);
572    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
573        return ORIG(ungetc)(c, stream);
574
575    _zz_lock(fd);
576    ret = ORIG(ungetc)(c, stream);
577    _zz_unlock(fd);
578
579    if(ret != EOF)
580    {
581        struct fuzz *fuzz = _zz_getfuzz(fd);
582        fuzz->uflag = 1;
583        fuzz->upos = _zz_getpos(fd) - 1;
584        fuzz->uchar = c;
585#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
586#else
587        _zz_addpos(fd, -1);
588#endif
589    }
590
591    if(ret == EOF)
592        debug("%s(0x%02x, [%i]) = EOF", __func__, c, fd);
593    else
594        debug("%s(0x%02x, [%i]) = '%c'", __func__, c, fd, ret);
595
596    return ret;
597}
598
599int NEW(fclose)(FILE *fp)
600{
601    int ret, fd;
602
603    LOADSYM(fclose);
604    fd = fileno(fp);
605    if(!_zz_ready || !_zz_iswatched(fd))
606        return ORIG(fclose)(fp);
607
608    _zz_lock(fd);
609    ret = ORIG(fclose)(fp);
610    _zz_unlock(fd);
611    debug("%s([%i]) = %i", __func__, fd, ret);
612    _zz_unregister(fd);
613
614    return ret;
615}
616
617#define GETDELIM(fn, delim, need_delim) \
618    do { \
619        char *line; \
620        ssize_t done, size; \
621        int fd, finished = 0; \
622        LOADSYM(fn); \
623        LOADSYM(getdelim); \
624        LOADSYM(fgetc); \
625        fd = fileno(stream); \
626        if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \
627            return ORIG(getdelim)(lineptr, n, delim, stream); \
628        line = *lineptr; \
629        size = line ? *n : 0; \
630        ret = done = finished = 0; \
631        for(;;) \
632        { \
633            int ch; \
634            if(done >= size) /* highly inefficient but I don't care */ \
635                line = realloc(line, size = done + 1); \
636            if(finished) \
637            { \
638                line[done] = '\0'; \
639                *n = size; \
640                *lineptr = line; \
641                break; \
642            } \
643            _zz_lock(fd); \
644            ch = ORIG(fgetc)(stream); \
645            _zz_unlock(fd); \
646            if(ch == EOF) \
647            { \
648                finished = 1; \
649                ret = done; \
650            } \
651            else \
652            { \
653                unsigned char c = ch; \
654                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
655                line[done++] = c; \
656                _zz_addpos(fd, 1); \
657                if(c == delim) \
658                { \
659                    finished = 1; \
660                    ret = done; \
661                } \
662            } \
663        } \
664        if(need_delim) \
665            debug("%s(%p, %p, '%c', [%i]) = %li", __func__, \
666                  lineptr, n, delim, fd, (long int)ret); \
667        else \
668            debug("%s(%p, %p, [%i]) = %li", __func__, \
669                  lineptr, n, fd, (long int)ret); \
670        return ret; \
671    } while(0)
672
673#if defined HAVE_GETLINE
674ssize_t NEW(getline)(char **lineptr, size_t *n, FILE *stream)
675{
676    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
677}
678#endif
679
680#if defined HAVE_GETDELIM
681ssize_t NEW(getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
682{
683    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
684}
685#endif
686
687#if defined HAVE___GETDELIM
688ssize_t NEW(__getdelim)(char **lineptr, size_t *n, int delim, FILE *stream)
689{
690    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
691}
692#endif
693
694#if defined HAVE_FGETLN
695char *NEW(fgetln)(FILE *stream, size_t *len)
696{
697    char *ret;
698#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
699#else
700    struct fuzz *fuzz;
701    size_t i, size;
702#endif
703    int fd;
704
705    LOADSYM(fgetln);
706    LOADSYM(fgetc);
707    fd = fileno(stream);
708    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
709        return ORIG(fgetln)(stream, len);
710
711#if defined HAVE_REFILL_STDIO /* Don't fuzz or seek if we have __srefill() */
712    _zz_lock(fd);
713    ret = ORIG(fgetln)(stream, len);
714    _zz_unlock(fd);
715#else
716    fuzz = _zz_getfuzz(fd);
717
718    for(i = size = 0; ; /* i is incremented below */)
719    {
720        int ch;
721
722        _zz_lock(fd);
723        ch = ORIG(fgetc)(stream);
724        _zz_unlock(fd);
725
726        if(ch == EOF)
727            break;
728
729        if(i >= size)
730            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
731
732        fuzz->tmp[i] = (char)(unsigned char)ch;
733        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
734        _zz_addpos(fd, 1);
735
736        if(fuzz->tmp[i++] == '\n')
737            break;
738    }
739
740    *len = i;
741    ret = fuzz->tmp;
742#endif
743
744    debug("%s([%i], &%li) = %p", __func__, fd, (long int)*len, ret);
745    return ret;
746}
747#endif
748
749#if defined HAVE___SREFILL
750int NEW(__srefill)(FILE *fp)
751{
752    off_t newpos;
753    int ret, fd;
754
755    LOADSYM(__srefill);
756    fd = fileno(fp);
757    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
758        return ORIG(__srefill)(fp);
759
760    _zz_lock(fd);
761    ret = ORIG(__srefill)(fp);
762    newpos = lseek(fd, 0, SEEK_CUR);
763    _zz_unlock(fd);
764    if(ret != EOF)
765    {
766        /* FIXME: do we have to fuzz ret, too, like in __filbuf? */
767        if(newpos != -1)
768            _zz_setpos(fd, newpos - fp->_r);
769        _zz_fuzz(fd, fp->_p, fp->_r);
770        _zz_addpos(fd, fp->_r);
771    }
772
773    if(!_zz_islocked(fd))
774        debug("%s([%i]) = %i", __func__, fd, ret);
775
776    return ret;
777}
778#endif
779
780#if defined HAVE___FILBUF
781int NEW(__filbuf)(FILE *fp)
782{
783    off_t newpos;
784    int ret, fd;
785
786    LOADSYM(__filbuf);
787    fd = fileno(fp);
788    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
789        return ORIG(__filbuf)(fp);
790
791    _zz_lock(fd);
792    ret = ORIG(__filbuf)(fp);
793    newpos = lseek(fd, 0, SEEK_CUR);
794    _zz_unlock(fd);
795    if(ret != EOF)
796    {
797        if(newpos != -1)
798            _zz_setpos(fd, newpos - fp->FILE_CNT - 1);
799        _zz_fuzz(fd, fp->FILE_PTR - 1, fp->FILE_CNT + 1);
800        ret = (uint8_t)fp->FILE_PTR[-1];
801        _zz_addpos(fd, fp->FILE_CNT + 1);
802    }
803
804    if(!_zz_islocked(fd))
805        debug("%s([%i]) = %i", __func__, fd, ret);
806
807    return ret;
808}
809#endif
810
Note: See TracBrowser for help on using the repository browser.