diff --git a/ChangeLog b/ChangeLog
index fbdf485521b49b7f45dbfb289b4e184be8089d65..b21088840d6d9596a59ef131023eb465de7cb3ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Tue Sep  2 12:28:54 CEST 2008 Jim Meyering <meyering@redhat.com>
+
+	util.c: add a file-descriptor-based wrapper for fread_file_lim
+	* src/util.c (virFileReadLimFP): New function.
+	(__virFileReadLimFD): New function.
+	* src/util.h (__virFileReadLimFD): Declare.
+	(virFileReadLimFD): Define.
+	(virFileReadAll): Rewrite to use virFileReadLimFP.
+
 Fri Aug 29 08:04:15 BST 2008 Daniel P. Berrange <berrange@redhat.com>
 
 	* src/bridge.c, src/proxy_internal.c, src/qemu_conf.c,
diff --git a/src/util.c b/src/util.c
index cb03e7bbb86549400933ed818cb17c5aed15300d..c7242686f4c120c16a8cecb4aa65e363f7cf3840 100644
--- a/src/util.c
+++ b/src/util.c
@@ -510,40 +510,63 @@ fread_file_lim (FILE *stream, size_t max_len, size_t *length)
     return NULL;
 }
 
-int __virFileReadAll(const char *path, int maxlen, char **buf)
+/* A wrapper around fread_file_lim that maps a failure due to
+   exceeding the maximum size limitation to EOVERFLOW.  */
+static int virFileReadLimFP(FILE *fp, int maxlen, char **buf)
 {
-    FILE *fh;
-    int ret = -1;
     size_t len;
-    char *s;
+    char *s = fread_file_lim (fp, maxlen+1, &len);
+    if (s == NULL)
+        return -1;
+    if (len > maxlen || (int)len != len) {
+        VIR_FREE(s);
+        /* There was at least one byte more than MAXLEN.
+           Set errno accordingly. */
+        errno = EOVERFLOW;
+        return -1;
+    }
+    *buf = s;
+    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;
+}
 
-    if (!(fh = fopen(path, "r"))) {
+int __virFileReadAll(const char *path, int maxlen, char **buf)
+{
+    FILE *fh = fopen(path, "r");
+    if (fh == NULL) {
         virLog("Failed to open file '%s': %s\n",
                path, strerror(errno));
-        goto error;
+        return -1;
     }
 
-    s = fread_file_lim(fh, maxlen+1, &len);
-    if (s == NULL) {
+    int len = virFileReadLimFP (fh, maxlen, buf);
+    fclose(fh);
+    if (len < 0) {
         virLog("Failed to read '%s': %s\n", path, strerror (errno));
-        goto error;
-    }
-
-    if (len > maxlen || (int)len != len) {
-        VIR_FREE(s);
-        virLog("File '%s' is too large %d, max %d\n",
-               path, (int)len, maxlen);
-        goto error;
+        return -1;
     }
 
-    *buf = s;
-    ret = len;
-
- error:
-    if (fh)
-        fclose(fh);
-
-    return ret;
+    return len;
 }
 
 int virFileMatchesNameSuffix(const char *file,
diff --git a/src/util.h b/src/util.h
index 51515821f94ea89697195c714dd5797bb55e0990..f2da006772d60b5d167db5e1f8478ba34b815f0a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -45,9 +45,10 @@ int virExec(virConnectPtr conn,
             int flags);
 int virRun(virConnectPtr conn, const char *const*argv, int *status);
 
-int __virFileReadAll(const char *path,
-                     int maxlen,
-                     char **buf);
+int __virFileReadLimFD(int fd, int maxlen, char **buf);
+#define virFileReadLimFD(fd,m,b) __virFileReadLimFD((fd),(m),(b))
+
+int __virFileReadAll(const char *path, int maxlen, char **buf);
 #define virFileReadAll(p,m,b) __virFileReadAll((p),(m),(b))
 
 int virFileMatchesNameSuffix(const char *file,