Index: /trunk/include/regfi.h
===================================================================
--- /trunk/include/regfi.h	(revision 150)
+++ /trunk/include/regfi.h	(revision 151)
@@ -95,4 +95,9 @@
 #define REGFI_REGF_SIZE            0x1000 /* "regf" header block size */
 #define REGFI_REGF_MAGIC_SIZE      4
+#define REGFI_REGF_NAME_SIZE       64
+
+#define REGFI_REGF_RESERVED1_SIZE  340
+#define REGFI_REGF_RESERVED2_SIZE  3528
+
 #define REGFI_HBIN_MAGIC_SIZE      4
 #define REGFI_CELL_MAGIC_SIZE      2
@@ -337,26 +342,52 @@
   /********************************/
   uint8  magic[REGFI_REGF_MAGIC_SIZE];/* "regf" */
+
+ /* These sequence numbers should match if
+  * the hive was properly synced to disk.
+  */
+  uint32 sequence1;            
+  uint32 sequence2;
+
   NTTIME mtime;
-  uint32 data_offset;		/* offset to record in the first (or any?) 
-				 * hbin block 
-				 */
-  uint32 last_block;		/* offset to last hbin block in file */
-
-  uint32 checksum;		/* Stored checksum. */
-  uint32 computed_checksum;     /* Our own calculation of the checksum.
-				 * (XOR of bytes 0x0000 - 0x01FB) 
-				 */
-  
-  /* XXX: Some of these we have some clues about (major/minor version, etc). 
-   *      Should verify and update names accordingly. 
-   */
-  /* unknown data structure values */
-  uint32 unknown1;
-  uint32 unknown2;
-  uint32 unknown3;
-  uint32 unknown4;
-  uint32 unknown5;
-  uint32 unknown6;
-  uint32 unknown7;
+  uint32 major_version;  /* XXX: Unverified. Set to 1 in all known hives */
+  uint32 minor_version;  /* XXX: Unverified. Set to 3 or 5 in all known hives */
+  uint32 type;           /* XXX: Unverified.  Set to 0 in all known hives */
+  uint32 format;         /* XXX: Unverified.  Set to 1 in all known hives */
+
+  uint32 root_cell;  /* Offset to root cell in the first (or any?) hbin block */
+  uint32 last_block; /* Offset to last hbin block in file
+		      * (or length of file minus header?) */
+
+  uint32 cluster;    /* XXX: Unverified. Set to 1 in all known hives */
+
+  /* Matches hive's base file name. Stored in UTF-16LE */
+  uint8 file_name[REGFI_REGF_NAME_SIZE];
+
+  WINSEC_UUID* rm_id;       /* XXX: Unverified. */
+  WINSEC_UUID* log_id;      /* XXX: Unverified. */
+  WINSEC_UUID* tm_id;       /* XXX: Unverified. */
+  uint32 flags;             /* XXX: Unverified. */
+  uint32 guid_signature;    /* XXX: Unverified. */
+
+  uint32 checksum;          /* Stored checksum from file */
+  uint32 computed_checksum; /* Our own calculation of the checksum. 
+			     * (XOR of bytes 0x0000 - 0x01FB) */
+
+  WINSEC_UUID* thaw_tm_id;  /* XXX: Unverified. */
+  WINSEC_UUID* thaw_rm_id;  /* XXX: Unverified. */
+  WINSEC_UUID* thaw_log_id; /* XXX: Unverified. */
+  uint32 boot_type;         /* XXX: Unverified. */
+  uint32 boot_recover;      /* XXX: Unverified. */
+
+  /* This seems to include random junk.  Possibly unsanitized memory left over
+   * from when header block was written.  For instance, chunks of nk records 
+   * can be found, though often it's all 0s. */
+  uint8 reserved1[REGFI_REGF_RESERVED1_SIZE];
+
+  /* This is likely reserved and unusued currently.  (Should be all 0s.)
+   * Included here for easier access in looking for hidden data 
+   * or doing research. */
+  uint8 reserved2[REGFI_REGF_RESERVED2_SIZE];
+
 } REGFI_FILE;
 
@@ -367,5 +398,5 @@
  *      whole keys.
  */
-typedef struct 
+typedef struct _regfi_iterator
 {
   REGFI_FILE* f;
@@ -377,5 +408,5 @@
 
 
-typedef struct 
+typedef struct _regfi_iter_position
 {
   REGFI_NK_REC* nk;
@@ -385,4 +416,11 @@
    */
 } REGFI_ITER_POSITION;
+
+
+typedef struct _regfi_buffer
+{
+  uint8* buf;
+  uint32_t len;
+} REGFI_BUFFER;
 
 
@@ -478,5 +516,5 @@
 				     uint32 max_size, bool strict);
 
-uint8*                regfi_parse_data(REGFI_FILE* file, 
+REGFI_BUFFER          regfi_parse_data(REGFI_FILE* file, 
 				       uint32 data_type, uint32 offset, 
 				       uint32 length, uint32 max_size, 
Index: /trunk/lib/regfi.c
===================================================================
--- /trunk/lib/regfi.c	(revision 150)
+++ /trunk/lib/regfi.c	(revision 151)
@@ -948,4 +948,5 @@
   const REGFI_HBIN* hbin;
   uint32 data_offset, data_maxsize;
+  REGFI_BUFFER data;
 
   hbin = regfi_lookup_hbin(file, offset - REGFI_REGF_SIZE);
@@ -965,7 +966,9 @@
     if(ret_val->data_in_offset)
     {
-      ret_val->data = regfi_parse_data(file, ret_val->type, ret_val->data_off,
-				       ret_val->data_size, 4,
-				       ret_val->data_in_offset, strict);
+      data = regfi_parse_data(file, ret_val->type, ret_val->data_off,
+			      ret_val->data_size, 4,
+			      ret_val->data_in_offset, strict);
+      ret_val->data = data.buf;
+      ret_val->data_size = data.len;
     }
     else
@@ -976,7 +979,10 @@
 	data_offset = ret_val->data_off+REGFI_REGF_SIZE;
 	data_maxsize = hbin->block_size + hbin->file_off - data_offset;
-	ret_val->data = regfi_parse_data(file, ret_val->type, data_offset, 
-					 ret_val->data_size, data_maxsize, 
-					 ret_val->data_in_offset, strict);
+	data = regfi_parse_data(file, ret_val->type, data_offset, 
+				ret_val->data_size, data_maxsize, 
+				ret_val->data_in_offset, strict);
+	ret_val->data = data.buf;
+	ret_val->data_size = data.len;
+
       }
       else
@@ -992,5 +998,5 @@
     {
       regfi_add_message(file, REGFI_MSG_WARN, "Could not parse data record"
-			" while parsing VK record at offset 0x%.8X.", 
+			" while parsing VK record at offset 0x%.8X.",
 			ret_val->offset);
     }
@@ -1740,23 +1746,37 @@
     regfi_add_message(ret_val, REGFI_MSG_WARN, "Magic number mismatch "
 		      "(%.2X %.2X %.2X %.2X) while parsing hive header",
-		      ret_val->magic[0],ret_val->magic[1], 
+		      ret_val->magic[0], ret_val->magic[1], 
 		      ret_val->magic[2], ret_val->magic[3]);
   }
-  
-  ret_val->unknown1 = IVAL(file_header, 0x4);
-  ret_val->unknown2 = IVAL(file_header, 0x8);
-
+  ret_val->sequence1 = IVAL(file_header, 0x4);
+  ret_val->sequence2 = IVAL(file_header, 0x8);
   ret_val->mtime.low = IVAL(file_header, 0xC);
   ret_val->mtime.high = IVAL(file_header, 0x10);
-
-  ret_val->unknown3 = IVAL(file_header, 0x14);
-  ret_val->unknown4 = IVAL(file_header, 0x18);
-  ret_val->unknown5 = IVAL(file_header, 0x1C);
-  ret_val->unknown6 = IVAL(file_header, 0x20);
-  
-  ret_val->data_offset = IVAL(file_header, 0x24);
+  ret_val->major_version = IVAL(file_header, 0x14);
+  ret_val->minor_version = IVAL(file_header, 0x18);
+  ret_val->type = IVAL(file_header, 0x1C);
+  ret_val->format = IVAL(file_header, 0x20);
+  ret_val->root_cell = IVAL(file_header, 0x24);
   ret_val->last_block = IVAL(file_header, 0x28);
 
-  ret_val->unknown7 = IVAL(file_header, 0x2C);
+  ret_val->cluster = IVAL(file_header, 0x2C);
+
+  memcpy(ret_val->file_name, file_header+0x30,  REGFI_REGF_NAME_SIZE);
+
+  /* XXX: Should we add a warning if these uuid parsers fail?  Can they? */
+  ret_val->rm_id = winsec_parse_uuid(ret_val, file_header+0x70, 16);
+  ret_val->log_id = winsec_parse_uuid(ret_val, file_header+0x80, 16);
+  ret_val->flags = IVAL(file_header, 0x90);
+  ret_val->tm_id = winsec_parse_uuid(ret_val, file_header+0x94, 16);
+  ret_val->guid_signature = IVAL(file_header, 0xa4);
+
+  memcpy(ret_val->reserved1, file_header+0xa8, REGFI_REGF_RESERVED1_SIZE);
+  memcpy(ret_val->reserved2, file_header+0x200, REGFI_REGF_RESERVED2_SIZE);
+
+  ret_val->thaw_tm_id = winsec_parse_uuid(ret_val, file_header+0xFC8, 16);
+  ret_val->thaw_rm_id = winsec_parse_uuid(ret_val, file_header+0xFD8, 16);
+  ret_val->thaw_log_id = winsec_parse_uuid(ret_val, file_header+0xFE8, 16);
+  ret_val->boot_type = IVAL(file_header, 0x90);
+  ret_val->boot_recover = IVAL(file_header, 0x90);
 
   return ret_val;
@@ -2201,14 +2221,14 @@
 
 
-uint8* regfi_parse_data(REGFI_FILE* file, 
-			uint32 data_type, uint32 offset,
-			uint32 length, uint32 max_size, 
-			bool data_in_offset, bool strict)
-{
-  uint8* ret_val;
+REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, 
+			      uint32 data_type, uint32 offset,
+			      uint32 length, uint32 max_size, 
+			      bool data_in_offset, bool strict)
+{
+  REGFI_BUFFER ret_val;
   uint32 read_length, cell_length;
   uint8 i;
   bool unalloc;
-
+  
   /* The data is typically stored in the offset if the size <= 4 */
   if(data_in_offset)
@@ -2219,12 +2239,13 @@
 			" while parsing data record at offset 0x%.8X.", 
 			offset);
-      return NULL;
-    }
-
-    if((ret_val = talloc_array(NULL, uint8_t, length)) == NULL)
-      return NULL;
+      goto fail;
+    }
+
+    if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
+      goto fail;
+    ret_val.len = length;
 
     for(i = 0; i < length; i++)
-      ret_val[i] = (uint8)((offset >> i*8) & 0xFF);
+      ret_val.buf[i] = (uint8)((offset >> i*8) & 0xFF);
   }
   else
@@ -2235,5 +2256,5 @@
       regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
 			" parsing data record at offset 0x%.8X.", offset);
-      return NULL;
+      goto fail;
     }
 
@@ -2243,5 +2264,5 @@
 			" while parsing data record at offset 0x%.8X.",
 			offset);
-      return NULL;
+      goto fail;
     }
 
@@ -2252,5 +2273,5 @@
 			offset);
       if(strict)
-	return NULL;
+	goto fail;
       else
 	cell_length = max_size;
@@ -2261,5 +2282,6 @@
       /* XXX: This strict condition has been triggered in multiple registries.
        *      Not sure the cause, but the data length values are very large,
-       *      such as 53392.
+       *      such as 53392.  For now, we're truncating the size and returning 
+       *      what we can, since this issue is so common.
        */
       regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
@@ -2267,24 +2289,32 @@
 			" while parsing data record at offset 0x%.8X.", 
 			length, cell_length - 4, offset);
+      /*
       if(strict)
-	return NULL;
+        goto fail;
       else
-	length = cell_length - 4;
-    }
-
-    if((ret_val = talloc_array(NULL, uint8_t, length)) == NULL)
-      return NULL;
+      */
+      length = cell_length - 4;
+    }
+
+    if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
+      goto fail;
+    ret_val.len = length;
 
     read_length = length;
-    if((regfi_read(file->fd, ret_val, &read_length) != 0) 
+    if((regfi_read(file->fd, ret_val.buf, &read_length) != 0)
        || read_length != length)
     {
       regfi_add_message(file, REGFI_MSG_ERROR, "Could not read data block while"
 			" parsing data record at offset 0x%.8X.", offset);
-      talloc_free(ret_val);
-      return NULL;
-    }
-  }
-
+      talloc_free(ret_val.buf);
+      goto fail;
+    }
+  }
+
+  return ret_val;
+
+ fail:
+  ret_val.buf = NULL;
+  ret_val.len = 0;
   return ret_val;
 }
Index: /trunk/src/reglookup-recover.c
===================================================================
--- /trunk/src/reglookup-recover.c	(revision 150)
+++ /trunk/src/reglookup-recover.c	(revision 151)
@@ -263,12 +263,5 @@
   uint32 virt_offset, i, stack_size, ret_val_size, ret_val_used;
   uint32 max_length;
-  /* A little hack so we don't have to walk a quoted string twice. */
-  struct name_holder
-  {
-    char* quoted_name;
-    uint32_t length;
-  };
-  struct name_holder* path_element;
-
+  REGFI_BUFFER* path_element;
   
   /* The path_stack size limit should guarantee that we don't recurse forever. */
@@ -298,10 +291,10 @@
 	  virt_offset = cur_ancestor->parent_off;
 	
-	path_element = talloc(path_stack, struct name_holder);
+	path_element = talloc(path_stack, REGFI_BUFFER);
 	if(path_element != NULL)
-	  path_element->quoted_name = quote_string(cur_ancestor->keyname, 
+	  path_element->buf = (uint8*)quote_string(cur_ancestor->keyname, 
 						   key_special_chars);
 	  
-	if(path_element == NULL || path_element->quoted_name == NULL 
+	if(path_element == NULL || path_element->buf == NULL 
 	   || !void_stack_push(path_stack, path_element))
 	{
@@ -316,6 +309,6 @@
 	 * 16 bits and the max depth is 512.
 	 */
-	path_element->length = strlen(path_element->quoted_name);
-	ret_val_size += path_element->length + 1;
+	path_element->len = strlen((char*)path_element->buf);
+	ret_val_size += path_element->len + 1;
 
 	regfi_free_key(cur_ancestor);
@@ -338,7 +331,7 @@
     path_element = void_stack_pop(path_stack);
     snprintf(ret_val+ret_val_used, ret_val_size-ret_val_used, 
-	     "/%s", path_element->quoted_name);
-    ret_val_used += path_element->length + 1;
-    free(path_element->quoted_name);
+	     "/%s", path_element->buf);
+    ret_val_used += path_element->len + 1;
+    free(path_element->buf);
     talloc_free(path_element);
   }
@@ -471,4 +464,5 @@
   REGFI_VK_REC* vk;
   const REGFI_HBIN* hbin;
+  REGFI_BUFFER data;
   uint32 i, off, data_offset, data_maxsize;
 
@@ -488,7 +482,9 @@
       if(vk->data_in_offset)
       {
-	vk->data = regfi_parse_data(f, vk->type, vk->data_off,
-				    vk->data_size, 4,
-				    vk->data_in_offset, false);
+	data = regfi_parse_data(f, vk->type, vk->data_off,
+				vk->data_size, 4,
+				vk->data_in_offset, false);
+	vk->data = data.buf;
+	vk->data_size = data.len;
       }
       else if(range_list_has_range(unalloc_cells, off, vk->data_size))
@@ -499,7 +495,10 @@
 	  data_offset = vk->data_off+REGFI_REGF_SIZE;
 	  data_maxsize = hbin->block_size + hbin->file_off - data_offset;
-	  vk->data = regfi_parse_data(f, vk->type, data_offset, 
-				      vk->data_size, data_maxsize, 
-				      vk->data_in_offset, false);
+	  data = regfi_parse_data(f, vk->type, data_offset, 
+				  vk->data_size, data_maxsize, 
+				  vk->data_in_offset, false);
+	  vk->data = data.buf;
+	  vk->data_size = data.len;
+
 	  if(vk->data != NULL)
 	  {
@@ -509,4 +508,8 @@
 	     *      wrong.  Need a feedback mechanism to be more fuzzy with 
 	     *      data cell lengths and the ranges removed. 
+	     *
+	     *      The introduction of REGFI_BUFFER in regfi_parse_data has 
+	     *      fixed some of this.  Should review again with respect to 
+	     *      the other issues mentioned above though.
 	     */
 	    /* A data record was recovered. Remove from unalloc_cells. */
