blob: 98bb80041e9ef15a5fd38df386a3b1c91e5f201c [file] [log] [blame]
/*
* 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;
}