| /* |
| * readfile.c |
| * |
| * Read the entire contents of a file into malloc'd storage. This |
| * is mostly useful for things like /proc files where we can't just |
| * fstat() to get the length and then mmap(). |
| * |
| * Returns the number of bytes read, or -1 on error. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| |
| ssize_t freadfile(FILE *f, char **pp) |
| { |
| size_t bs; /* Decent starting point... */ |
| size_t bf; /* Bytes free */ |
| size_t bu = 0; /* Bytes used */ |
| char *buffer, *nb; |
| size_t rv; |
| int old_errno = errno; |
| #if 0 |
| struct stat st; |
| |
| if ( !fstat(fileno(f), &st) && S_ISREG(st.st_mode) && st.st_size ) |
| bs = st.st_size+1; |
| else |
| #endif |
| bs = BUFSIZ; /* A guess as good as any */ |
| |
| bf = bs; |
| buffer = malloc(bs); |
| |
| if ( !buffer ) |
| return -1; |
| |
| for (;;) { |
| errno = 0; |
| |
| while ( bf && (rv = _fread(buffer+bu, bf, f)) ) { |
| bu += rv; |
| bf -= rv; |
| } |
| |
| if ( errno && errno != EINTR && errno != EAGAIN ) { |
| /* error */ |
| free(buffer); |
| return -1; |
| } |
| |
| if ( bf ) { |
| /* Hit EOF, no error */ |
| |
| /* Try to free superfluous memory */ |
| if ( (nb = realloc(buffer, bu+1)) ) |
| buffer = nb; |
| |
| /* Null-terminate result for good measure */ |
| buffer[bu] = '\0'; |
| |
| *pp = buffer; |
| errno = old_errno; |
| return bu; |
| } |
| |
| /* Double the size of the buffer */ |
| bf += bs; |
| bs += bs; |
| if ( !(nb = realloc(buffer, bs)) ) { |
| /* out of memory error */ |
| free(buffer); |
| return -1; |
| } |
| buffer = nb; |
| } |
| } |
| |
| ssize_t readfile(const char *filename, char **pp) |
| { |
| FILE *f = fopen(filename, "r"); |
| ssize_t rv; |
| |
| if ( !f ) |
| return -1; |
| |
| rv = freadfile(f, pp); |
| |
| fclose(f); |
| |
| return rv; |
| } |