Fix virFileReadLimFD/virFileReadAll to handle EINTR

The fread_file_lim() function uses fread() but never handles
EINTR results, causing unexpected failures when reading QEMU
help arg info. It was unneccessarily using FILE * instead
of plain UNIX file handles, which prevented use of saferead()

* src/util/util.c: Switch fread_file_lim over to use saferead
  instead of fread, remove FILE * use, and rename
This commit is contained in:
Daniel P. Berrange 2009-10-12 20:32:33 +01:00
parent 826cbac459
commit 11a36d956c

View File

@ -898,7 +898,7 @@ virExec(virConnectPtr conn,
number of bytes. If the length of the input is <= max_len, and number of bytes. If the length of the input is <= max_len, and
upon error while reading that data, it works just like fread_file. */ upon error while reading that data, it works just like fread_file. */
static char * static char *
fread_file_lim (FILE *stream, size_t max_len, size_t *length) saferead_lim (int fd, size_t max_len, size_t *length)
{ {
char *buf = NULL; char *buf = NULL;
size_t alloc = 0; size_t alloc = 0;
@ -906,8 +906,8 @@ fread_file_lim (FILE *stream, size_t max_len, size_t *length)
int save_errno; int save_errno;
for (;;) { for (;;) {
size_t count; int count;
size_t requested; int requested;
if (size + BUFSIZ + 1 > alloc) { if (size + BUFSIZ + 1 > alloc) {
alloc += alloc / 2; alloc += alloc / 2;
@ -923,12 +923,12 @@ fread_file_lim (FILE *stream, size_t max_len, size_t *length)
/* Ensure that (size + requested <= max_len); */ /* Ensure that (size + requested <= max_len); */
requested = MIN (size < max_len ? max_len - size : 0, requested = MIN (size < max_len ? max_len - size : 0,
alloc - size - 1); alloc - size - 1);
count = fread (buf + size, 1, requested, stream); count = saferead (fd, buf + size, requested);
size += count; size += count;
if (count != requested || requested == 0) { if (count != requested || requested == 0) {
save_errno = errno; save_errno = errno;
if (ferror (stream)) if (count < 0)
break; break;
buf[size] = '\0'; buf[size] = '\0';
*length = size; *length = size;
@ -941,12 +941,12 @@ fread_file_lim (FILE *stream, size_t max_len, size_t *length)
return NULL; return NULL;
} }
/* A wrapper around fread_file_lim that maps a failure due to /* A wrapper around saferead_lim that maps a failure due to
exceeding the maximum size limitation to EOVERFLOW. */ exceeding the maximum size limitation to EOVERFLOW. */
static int virFileReadLimFP(FILE *fp, int maxlen, char **buf) int virFileReadLimFD(int fd, int maxlen, char **buf)
{ {
size_t len; size_t len;
char *s = fread_file_lim (fp, maxlen+1, &len); char *s = saferead_lim (fd, maxlen+1, &len);
if (s == NULL) if (s == NULL)
return -1; return -1;
if (len > maxlen || (int)len != len) { if (len > maxlen || (int)len != len) {
@ -960,37 +960,16 @@ static int virFileReadLimFP(FILE *fp, int maxlen, char **buf)
return len; return len;
} }
/* Like virFileReadLimFP, but use a file descriptor rather than a FILE*. */
int virFileReadLimFD(int fd_arg, int maxlen, char **buf)
{
int fd = dup (fd_arg);
if (fd >= 0) {
FILE *fp = fdopen (fd, "r");
if (fp) {
int len = virFileReadLimFP (fp, maxlen, buf);
int saved_errno = errno;
fclose (fp);
errno = saved_errno;
return len;
} else {
int saved_errno = errno;
close (fd);
errno = saved_errno;
}
}
return -1;
}
int virFileReadAll(const char *path, int maxlen, char **buf) int virFileReadAll(const char *path, int maxlen, char **buf)
{ {
FILE *fh = fopen(path, "r"); int fd = open(path, O_RDONLY);
if (fh == NULL) { if (fd < 0) {
virReportSystemError(NULL, errno, _("Failed to open file '%s'"), path); virReportSystemError(NULL, errno, _("Failed to open file '%s'"), path);
return -1; return -1;
} }
int len = virFileReadLimFP (fh, maxlen, buf); int len = virFileReadLimFD(fd, maxlen, buf);
fclose(fh); close(fd);
if (len < 0) { if (len < 0) {
virReportSystemError(NULL, errno, _("Failed to read file '%s'"), path); virReportSystemError(NULL, errno, _("Failed to read file '%s'"), path);
return -1; return -1;