diff --git a/src/load-stream.c b/src/load-stream.c index 3690dc3..f837af3 100644 --- a/src/load-stream.c +++ b/src/load-stream.c @@ -18,8 +18,7 @@ #include "config.h" -/* Can't remember what that's for */ -#define _GNU_SOURCE +#define _GNU_SOURCE /* for getline() and getdelim() */ #if defined HAVE_STDINT_H # include @@ -43,15 +42,34 @@ static FILE * (*fopen64_orig) (const char *path, const char *mode); static int (*fseek_orig) (FILE *stream, long offset, int whence); static size_t (*fread_orig) (void *ptr, size_t size, size_t nmemb, FILE *stream); +static int (*getc_orig) (FILE *stream); +static int (*fgetc_orig) (FILE *stream); +static char * (*fgets_orig) (char *s, int size, FILE *stream); +static int (*ungetc_orig) (int c, FILE *stream); static int (*fclose_orig) (FILE *fp); +/* Additional GNUisms */ +static ssize_t (*getline_orig) (char **lineptr, size_t *n, FILE *stream); +static ssize_t (*getdelim_orig) (char **lineptr, size_t *n, int delim, + FILE *stream); +static ssize_t (*__getdelim_orig) (char **lineptr, size_t *n, int delim, + FILE *stream); + void zzuf_load_stream(void) { LOADSYM(fopen); LOADSYM(fopen64); LOADSYM(fseek); LOADSYM(fread); + LOADSYM(getc); + LOADSYM(fgetc); + LOADSYM(fgets); + LOADSYM(ungetc); LOADSYM(fclose); + + LOADSYM(getline); + LOADSYM(getdelim); + LOADSYM(__getdelim); } /* Our function wrappers */ @@ -59,10 +77,11 @@ void zzuf_load_stream(void) do \ { \ if(!_zzuf_ready) \ + { \ LOADSYM(fn); \ + return ORIG(fn)(path, mode); \ + } \ ret = ORIG(fn)(path, mode); \ - if(!_zzuf_ready) \ - return ret; \ if(ret) \ { \ if(_zzuf_include && \ @@ -97,14 +116,11 @@ int fseek(FILE *stream, long offset, int whence) if(!_zzuf_ready) LOADSYM(fseek); - ret = fseek_orig(stream, offset, whence); - if(!_zzuf_ready) - return ret; - fd = fileno(stream); - if(!files[fd].managed) - return ret; + if(!_zzuf_ready || !files[fd].managed) + return fseek_orig(stream, offset, whence); + ret = fseek_orig(stream, offset, whence); debug("fseek(%p, %li, %i) = %i", stream, offset, whence, ret); if(ret == 0) { @@ -125,14 +141,11 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) if(!_zzuf_ready) LOADSYM(fread); - ret = fread_orig(ptr, size, nmemb, stream); - if(!_zzuf_ready) - return ret; - fd = fileno(stream); - if(!files[fd].managed) - return ret; + if(!_zzuf_ready || !files[fd].managed) + return fread_orig(ptr, size, nmemb, stream); + ret = fread_orig(ptr, size, nmemb, stream); debug("fread(%p, %li, %li, %p) = %li", ptr, (long int)size, (long int)nmemb, stream, (long int)ret); if(ret > 0) @@ -143,6 +156,102 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) return ret; } +#define FGETC(fn) \ + do { \ + int fd; \ + if(!_zzuf_ready) \ + LOADSYM(fn); \ + fd = fileno(stream); \ + if(!_zzuf_ready || !files[fd].managed) \ + return ORIG(fn)(stream); \ + ret = ORIG(fn)(stream); \ + if(ret != EOF) \ + { \ + uint8_t ch = ret; \ + zzuf_fuzz(fd, &ch, 1); \ + files[fd].pos += 1; \ + ret = ch; \ + } \ + debug(STR(fn)"(%p) = 0x%02x", stream, ret); \ + } while(0) + +int getc(FILE *stream) +{ + int ret; FGETC(getc); return ret; +} + +int fgetc(FILE *stream) +{ + int ret; FGETC(fgetc); return ret; +} + +char *fgets(char *s, int size, FILE *stream) +{ + char *ret = s; + int i, fd; + + if(!_zzuf_ready) + LOADSYM(fgets); + fd = fileno(stream); + if(!_zzuf_ready || !files[fd].managed) + return fgets_orig(s, size, stream); + + if(size <= 0) + ret = NULL; + else if(size == 1) + s[0] = '\0'; + else + { + for(i = 0; i < size - 1; i++) + { + int ch = fgetc_orig(stream); + + if(ch == EOF) + { + s[i] = '\0'; + if(!i) + ret = NULL; + break; + } + s[i] = (char)(unsigned char)ch; + zzuf_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */ + files[fd].pos++; + if(s[i] == '\n') + { + s[i + 1] = '\0'; + break; + } + } + } + + debug("fgets(%p, %i, %p) = %p", s, size, stream, ret); + if(ret >= 0) + files[fd].pos += 1; + return ret; +} + +int ungetc(int c, FILE *stream) +{ + unsigned char ch = c; + int ret, fd; + + if(!_zzuf_ready) + LOADSYM(ungetc); + fd = fileno(stream); + if(!_zzuf_ready || !files[fd].managed) + return ungetc_orig(c, stream); + + files[fd].pos -= 1; + zzuf_fuzz(fd, &ch, 1); + ret = ungetc_orig((int)ch, stream); + if(ret >= 0) + ret = c; + else + files[fd].pos += 1; /* revert what we did */ + debug("ungetc(0x%02x, %p) = 0x%02x", c, stream, ret); + return ret; +} + int fclose(FILE *fp) { int ret, fd; @@ -150,16 +259,81 @@ int fclose(FILE *fp) if(!_zzuf_ready) LOADSYM(fclose); fd = fileno(fp); + if(!_zzuf_ready || !files[fd].managed) + return fclose_orig(fp); + ret = fclose_orig(fp); - if(!_zzuf_ready) - return ret; - - if(!files[fd].managed) - return ret; - debug("fclose(%p) = %i", fp, ret); files[fd].managed = 0; return ret; } +#define GETDELIM(fn, delim, need_delim) \ + do { \ + char *line; \ + ssize_t done, size; \ + int fd, finished = 0; \ + if(!_zzuf_ready) \ + LOADSYM(fn); \ + fd = fileno(stream); \ + if(!_zzuf_ready || !files[fd].managed) \ + return getdelim_orig(lineptr, n, delim, stream); \ + line = *lineptr; \ + size = line ? *n : 0; \ + ret = done = finished = 0; \ + for(;;) \ + { \ + int ch; \ + if(done >= size) /* highly inefficient but I don't care */ \ + line = realloc(line, size = done + 1); \ + if(finished) \ + { \ + line[done] = '\0'; \ + *n = size; \ + *lineptr = line; \ + break; \ + } \ + ch = fgetc_orig(stream); \ + if(ch == EOF) \ + { \ + finished = 1; \ + ret = done; \ + } \ + else \ + { \ + unsigned char c = ch; \ + zzuf_fuzz(fd, &c, 1); /* even more inefficient */ \ + line[done++] = c; \ + files[fd].pos++; \ + if(c == delim) \ + { \ + finished = 1; \ + ret = done; \ + } \ + } \ + } \ + if(need_delim) \ + debug(STR(fn) "(%p, %p, 0x%02x, %p) = %li", \ + lineptr, n, delim, stream, (long int)ret); \ + else \ + debug(STR(fn) "(%p, %p, %p) = %li", \ + lineptr, n, stream, (long int)ret); \ + return ret; \ + } while(0) + +ssize_t getline(char **lineptr, size_t *n, FILE *stream) +{ + ssize_t ret; GETDELIM(getline, '\n', 0); return ret; +} + +ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream) +{ + ssize_t ret; GETDELIM(getdelim, delim, 1); return ret; +} + +ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream) +{ + ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret; +} +