inspect: Add function to read the first line of a file, with safety checks.
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 16 Nov 2010 12:35:39 +0000 (12:35 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Thu, 18 Nov 2010 11:58:28 +0000 (11:58 +0000)
(cherry picked from commit a4448956e9a815aff59cac3d98caf80f620fc4c4)

src/inspect.c

index b350f86..a50147e 100644 (file)
@@ -217,6 +217,7 @@ static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
 static char *resolve_fstab_device (guestfs_h *g, const char *spec);
 static int download_to_tmp (guestfs_h *g, const char *filename, char *localtmp, int64_t max_size);
 static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, int (*f) (guestfs_h *, struct inspect_fs *));
+static char *first_line_of_file (guestfs_h *g, const char *filename);
 
 static int
 check_for_filesystem_on (guestfs_h *g, const char *device)
@@ -333,21 +334,9 @@ static int
 parse_release_file (guestfs_h *g, struct inspect_fs *fs,
                     const char *release_filename)
 {
-  char **product_name = guestfs_head_n (g, 1, release_filename);
-  if (product_name == NULL)
+  fs->product_name = first_line_of_file (g, release_filename);
+  if (fs->product_name == NULL)
     return -1;
-  if (product_name[0] == NULL) {
-    error (g, _("%s: file is empty"), release_filename);
-    guestfs___free_string_list (product_name);
-    return -1;
-  }
-
-  /* Note that this string becomes owned by the handle and will
-   * be freed by guestfs___free_inspect_info.
-   */
-  fs->product_name = product_name[0];
-  free (product_name);
-
   return 0;
 }
 
@@ -1254,6 +1243,45 @@ inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename,
   return r;
 }
 
+/* Get the first line of a small file, without any trailing newline
+ * character.
+ */
+static char *
+first_line_of_file (guestfs_h *g, const char *filename)
+{
+  char **lines;
+  int64_t size;
+  char *ret;
+
+  /* Don't trust guestfs_head_n not to break with very large files.
+   * Check the file size is something reasonable first.
+   */
+  size = guestfs_filesize (g, filename);
+  if (size == -1)
+    /* guestfs_filesize failed and has already set error in handle */
+    return NULL;
+  if (size > 1000000) {
+    error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
+           filename, size);
+    return NULL;
+  }
+
+  lines = guestfs_head_n (g, 1, filename);
+  if (lines == NULL)
+    return NULL;
+  if (lines[0] == NULL) {
+    error (g, _("%s: file is empty"), filename);
+    guestfs___free_string_list (lines);
+    return NULL;
+  }
+  /* lines[1] should be NULL because of '1' argument above ... */
+
+  ret = lines[0];               /* caller frees */
+  free (lines);                 /* free the array */
+
+  return ret;
+}
+
 #else /* no PCRE or hivex at compile time */
 
 /* XXX These functions should be in an optgroup. */