Index: /trunk/include/regfi.h
===================================================================
--- /trunk/include/regfi.h	(revision 145)
+++ /trunk/include/regfi.h	(revision 146)
@@ -158,5 +158,4 @@
 
 
-
 /* HBIN block */
 typedef struct _regfi_hbin 
@@ -258,8 +257,4 @@
   WINSEC_DESC* sec_desc;
   uint32 hbin_off;	/* offset from beginning of this hbin block */
-  
-  uint32 sk_off;	/* offset parsed from NK record used as a key
-			 * to lookup reference to this SK record 
-			 */
   
   uint32 prev_sk_off;
@@ -330,4 +325,7 @@
   /* Metadata about hbins */
   range_list* hbins;
+
+  /* SK record cached since they're repeatedly reused */
+  lru_cache* sk_cache;
 
   /* Error/warning/info messages returned by lower layer functions */
@@ -375,5 +373,4 @@
   REGFI_FILE* f;
   void_stack* key_positions;
-  lru_cache* sk_recs;
   REGFI_NK_REC* cur_key;
   uint32 cur_subkey;
@@ -384,7 +381,4 @@
 typedef struct 
 {
-  /* XXX: Should probably eliminate the storage of keys here 
-   *      once key caching is implemented. 
-   */
   REGFI_NK_REC* nk;
   uint32 cur_subkey;
@@ -437,17 +431,23 @@
 
 /********************************************************/
-/* Middle-layer structure caching, loading, and linking */
+/* Middle-layer structure loading, linking, and caching */
 /********************************************************/
-REGFI_HBIN*           regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset);
 REGFI_NK_REC*         regfi_load_key(REGFI_FILE* file, uint32 offset, 
 				     bool strict);
-REGFI_SUBKEY_LIST*    regfi_load_subkeylist(REGFI_FILE* file, uint32 offset, 
-					    uint32 num_keys, uint32 max_size, 
-					    bool strict);
 REGFI_VK_REC*         regfi_load_value(REGFI_FILE* file, uint32 offset, 
 				       bool strict);
+REGFI_SUBKEY_LIST*    regfi_load_subkeylist(REGFI_FILE* file, uint32 offset,
+					    uint32 num_keys, uint32 max_size,
+					    bool strict);
 REGFI_VALUE_LIST*     regfi_load_valuelist(REGFI_FILE* file, uint32 offset, 
-					   uint32 num_values, uint32 max_size, 
+					   uint32 num_values, uint32 max_size,
 					   bool strict);
+
+/* These are cached so return values don't need to be freed. */
+const REGFI_SK_REC*   regfi_load_sk(REGFI_FILE* file, uint32 offset,
+				    bool strict);
+const REGFI_HBIN*     regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset);
+
+
 
 /************************************/
@@ -522,3 +522,6 @@
 void                  regfi_add_message(REGFI_FILE* file, uint16 msg_type, 
 					const char* fmt, ...);
+REGFI_NK_REC*         regfi_copy_nk(const REGFI_NK_REC* nk);
+REGFI_VK_REC*         regfi_copy_vk(const REGFI_VK_REC* vk);
+
 #endif	/* _REGFI_H */
Index: /trunk/lib/lru_cache.c
===================================================================
--- /trunk/lib/lru_cache.c	(revision 145)
+++ /trunk/lib/lru_cache.c	(revision 146)
@@ -106,5 +106,5 @@
 
   if(max_keys == 0)
-    ret_val->num_buckets = 2048;
+    ret_val->num_buckets = 1024;
   else
   {
Index: /trunk/lib/regfi.c
===================================================================
--- /trunk/lib/regfi.c	(revision 145)
+++ /trunk/lib/regfi.c	(revision 146)
@@ -475,5 +475,5 @@
  * The offset is a virtual file offset.
  *******************************************************************/
-static bool regfi_offset_in_hbin(REGFI_HBIN* hbin, uint32 voffset)
+static bool regfi_offset_in_hbin(const REGFI_HBIN* hbin, uint32 voffset)
 {
   if(!hbin)
@@ -493,7 +493,8 @@
  * block for it.  NULL if one doesn't exist.
  *******************************************************************/
-REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset)
-{
-  return (REGFI_HBIN*)range_list_find_data(file->hbins, voffset+REGFI_REGF_SIZE);
+const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset)
+{
+  return (const REGFI_HBIN*)range_list_find_data(file->hbins, 
+						 voffset+REGFI_REGF_SIZE);
 }
 
@@ -541,5 +542,5 @@
   REGFI_SUBKEY_LIST* ret_val;
   REGFI_SUBKEY_LIST** sublists;
-  REGFI_HBIN* sublist_hbin;
+  const REGFI_HBIN* sublist_hbin;
   uint32 i, num_sublists, off, max_length;
 
@@ -956,8 +957,9 @@
 /******************************************************************************
  ******************************************************************************/
-REGFI_VK_REC* regfi_load_value(REGFI_FILE* file, uint32 offset, bool strict)
+REGFI_VK_REC* regfi_load_value(REGFI_FILE* file, uint32 offset, 
+			       bool strict)
 {
   REGFI_VK_REC* ret_val = NULL;
-  REGFI_HBIN* hbin;
+  const REGFI_HBIN* hbin;
   uint32 data_offset, data_maxsize;
 
@@ -1018,5 +1020,5 @@
  ******************************************************************************/
 REGFI_VALUE_LIST* regfi_load_valuelist(REGFI_FILE* file, uint32 offset, 
-				       uint32 num_values, uint32 max_size, 
+				       uint32 num_values, uint32 max_size,
 				       bool strict)
 {
@@ -1041,12 +1043,11 @@
 
 
-/*******************************************************************
- * XXX: Need to add full key caching using a 
- *      custom cache structure.
- *******************************************************************/
+/******************************************************************************
+ *
+ ******************************************************************************/
 REGFI_NK_REC* regfi_load_key(REGFI_FILE* file, uint32 offset, bool strict)
 {
-  REGFI_HBIN* hbin;
-  REGFI_HBIN* sub_hbin;
+  const REGFI_HBIN* hbin;
+  const REGFI_HBIN* sub_hbin;
   REGFI_NK_REC* nk;
   uint32 max_length, off;
@@ -1058,5 +1059,5 @@
   /* get the initial nk record */
   max_length = hbin->block_size + hbin->file_off - offset;
-  if ((nk = regfi_parse_nk(file, offset, max_length, true)) == NULL)
+  if((nk = regfi_parse_nk(file, offset, max_length, true)) == NULL)
   {
     regfi_add_message(file, REGFI_MSG_ERROR, "Could not load NK record at"
@@ -1065,5 +1066,5 @@
   }
 
-  /* fill in values */
+  /* get value list */
   if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 
   {
@@ -1102,5 +1103,5 @@
   }
 
-  /* now get subkeys */
+  /* now get subkey list */
   if(nk->num_subkeys && (nk->subkeys_off != REGFI_OFFSET_NONE)) 
   {
@@ -1141,5 +1142,42 @@
 /******************************************************************************
  ******************************************************************************/
-static bool regfi_find_root_nk(REGFI_FILE* file, uint32 offset, uint32 hbin_size,
+const REGFI_SK_REC* regfi_load_sk(REGFI_FILE* file, uint32 offset, bool strict)
+{
+  REGFI_SK_REC* ret_val = NULL;
+  const REGFI_HBIN* hbin;
+  uint32 max_length;
+
+  /* First look if we have already parsed it */
+  ret_val = (REGFI_SK_REC*)lru_cache_find(file->sk_cache, &offset, 4);
+
+  /* Bail out if we have previously cached a parse failure at this offset. */
+  if(ret_val == (void*)REGFI_OFFSET_NONE)
+    return NULL;
+
+  if(ret_val == NULL)
+  {
+    hbin = regfi_lookup_hbin(file, offset - REGFI_REGF_SIZE);
+    if(hbin == NULL)
+      return NULL;
+
+    max_length = hbin->block_size + hbin->file_off - offset;
+    ret_val = regfi_parse_sk(file, offset, max_length, strict);
+    if(ret_val == NULL)
+    { /* Cache the parse failure and bail out. */
+      lru_cache_update(file->sk_cache, &offset, 4, (void*)REGFI_OFFSET_NONE);
+      return NULL;
+    }
+
+    lru_cache_update(file->sk_cache, &offset, 4, ret_val);
+  }
+
+  return ret_val;
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************/
+static bool regfi_find_root_nk(REGFI_FILE* file, uint32 offset,uint32 hbin_size,
 			       uint32* root_offset)
 {
@@ -1192,5 +1230,5 @@
   REGFI_FILE* rb;
   REGFI_HBIN* hbin = NULL;
-  uint32 hbin_off, file_length;
+  uint32 hbin_off, file_length, cache_secret;
   int fd;
   bool rla;
@@ -1241,4 +1279,14 @@
   }
 
+
+  /* This secret isn't very secret, but we don't need a good one.  This 
+   * secret is just designed to prevent someone from trying to blow our
+   * caching and make things slow.
+   */
+  cache_secret = 0x15DEAD05^time(NULL)^(getpid()<<16);
+
+  /* Cache an unlimited number of SK records.  Typically there are very few. */
+  rb->sk_cache = lru_cache_create(0, cache_secret, true);
+
   /* Default message mask */
   rb->msg_mask = REGFI_MSG_ERROR|REGFI_MSG_WARN;
@@ -1251,5 +1299,5 @@
 /*******************************************************************
  *******************************************************************/
-int regfi_close( REGFI_FILE *file )
+int regfi_close(REGFI_FILE *file)
 {
   int fd;
@@ -1266,4 +1314,6 @@
   range_list_free(file->hbins);
 
+  if(file->sk_cache != NULL)
+    lru_cache_destroy(file->sk_cache);
   free(file);
 
@@ -1279,6 +1329,6 @@
 {
   REGFI_NK_REC* nk = NULL;
-  REGFI_HBIN*   hbin;
-  uint32       root_offset, i, num_hbins;
+  REGFI_HBIN* hbin;
+  uint32 root_offset, i, num_hbins;
   
   if(!file)
@@ -1286,8 +1336,8 @@
 
   /* Scan through the file one HBIN block at a time looking 
-     for an NK record with a type == 0x002c.
-     Normally this is the first nk record in the first hbin 
-     block (but I'm not assuming that for now) */
-
+   * for an NK record with a root key type.
+   * This is typically the first NK record in the first HBIN
+   * block (but we're not assuming that generally).
+   */
   num_hbins = range_list_size(file->hbins);
   for(i=0; i < num_hbins; i++)
@@ -1361,14 +1411,6 @@
   {
     free(ret_val);
-    free(root);
-    return NULL;
-  }
-
-  /* This secret isn't very secret, but we don't need a good one.  This 
-   * secret is just designed to prevent someone from trying to blow our
-   * caching and make things slow.
-   */
-  ret_val->sk_recs = lru_cache_create(127, 0x15DEAD05^time(NULL)^(getpid()<<16),
-				      true);
+    return NULL;
+  }
 
   ret_val->f = fh;
@@ -1396,6 +1438,5 @@
   }
   
-  lru_cache_destroy(i->sk_recs);
-
+  void_stack_free(i->key_positions);
   free(i);
 }
@@ -1543,34 +1584,9 @@
 const REGFI_SK_REC* regfi_iterator_cur_sk(REGFI_ITERATOR* i)
 {
-  REGFI_SK_REC* ret_val = NULL;
-  REGFI_HBIN* hbin;
-  uint32 max_length, off;
-
-  if(i->cur_key == NULL)
-    return NULL;
-  
-  /* First look if we have already parsed it */
-  if((i->cur_key->sk_off!=REGFI_OFFSET_NONE)
-     && !(ret_val =(REGFI_SK_REC*)lru_cache_find(i->sk_recs, 
-						&i->cur_key->sk_off, 4)))
-  {
-    hbin = regfi_lookup_hbin(i->f, i->cur_key->sk_off);
-
-    if(hbin == NULL)
-      return NULL;
-
-    off = i->cur_key->sk_off + REGFI_REGF_SIZE;
-    max_length = hbin->block_size + hbin->file_off - off;
-    ret_val = regfi_parse_sk(i->f, off, max_length, true);
-    if(ret_val == NULL)
-      return NULL;
-
-    ret_val->sk_off = i->cur_key->sk_off;
-    lru_cache_update(i->sk_recs, &i->cur_key->sk_off, 4, ret_val);
-  }
-
-  return ret_val;
-}
-
+  if(i->cur_key == NULL || i->cur_key->sk_off == REGFI_OFFSET_NONE)
+    return NULL;
+
+  return regfi_load_sk(i->f, i->cur_key->sk_off + REGFI_REGF_SIZE, true);
+}
 
 
@@ -1658,5 +1674,5 @@
 const REGFI_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
 {
-  REGFI_VK_REC* ret_val = NULL;
+  const REGFI_VK_REC* ret_val = NULL;
   uint32 voffset;
 
@@ -1687,5 +1703,4 @@
   return ret_val;
 }
-
 
 
@@ -1852,5 +1867,5 @@
 {
   uint8 nk_header[REGFI_NK_MIN_LENGTH];
-  REGFI_HBIN *hbin;
+  const REGFI_HBIN *hbin;
   REGFI_NK_REC* ret_val;
   uint32 length,cell_length;
Index: /trunk/src/reglookup-recover.c
===================================================================
--- /trunk/src/reglookup-recover.c	(revision 145)
+++ /trunk/src/reglookup-recover.c	(revision 146)
@@ -257,5 +257,5 @@
 {
   void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
-  REGFI_HBIN* hbin;
+  const REGFI_HBIN* hbin;
   REGFI_NK_REC* cur_ancestor;
   char* ret_val;
@@ -465,5 +465,5 @@
   const range_list_element* cur_elem;
   REGFI_VK_REC* vk;
-  REGFI_HBIN* hbin;
+  const REGFI_HBIN* hbin;
   uint32 i, off, data_offset, data_maxsize;
 
@@ -570,5 +570,5 @@
   REGFI_NK_REC* nk;
   REGFI_VK_REC* vk;
-  REGFI_HBIN* hbin;
+  const REGFI_HBIN* hbin;
   const range_list_element* cur_elem;
   uint32 i, j, num_keys, off, values_length, max_length;
