Index: trunk/Makefile
===================================================================
--- trunk/Makefile	(revision 178)
+++ trunk/Makefile	(revision 180)
@@ -14,5 +14,5 @@
 #OPTS=-std=gnu99 -pedantic -Wall
 INC:=-I$(PWD)/include -I/usr/local/include 
-LIB=-L/usr/local/lib -lm
+LIB=-L/usr/local/lib -lm -lpthread
 BIN_EXT=
 EXTRA_OBJ=
Index: trunk/include/regfi.h
===================================================================
--- trunk/include/regfi.h	(revision 178)
+++ trunk/include/regfi.h	(revision 180)
@@ -69,4 +69,5 @@
 #include <unistd.h>
 #include <iconv.h>
+#include <pthread.h>
 
 #include "byteorder.h"
@@ -674,4 +675,9 @@
   REGFI_RAW_FILE* cb;
 
+  /* Mutex for all cb access.  This is done to prevent one thread from moving
+   * the file offset while another thread is in the middle of a multi-read
+   * parsing transaction */
+  pthread_mutex_t* cb_lock;
+
   /* For sanity checking (not part of the registry header) */
   uint32_t file_length;
@@ -680,6 +686,12 @@
   range_list* hbins;
 
+  /* Multiple read access allowed, write access is exclusive */
+  pthread_rwlock_t* hbins_lock;
+
   /* SK record cached since they're repeatedly reused */
   lru_cache* sk_cache;
+
+  /* Need exclusive access for LRUs, since lookups make changes */
+  pthread_mutex_t* sk_lock;
 
   /* Error/warning/info messages returned by lower layer functions */
Index: trunk/lib/regfi.c
===================================================================
--- trunk/lib/regfi.c	(revision 178)
+++ trunk/lib/regfi.c	(revision 180)
@@ -422,4 +422,74 @@
 
 
+bool regfi_read_lock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
+{
+  int lock_ret = pthread_rwlock_rdlock(lock);
+  if(lock_ret != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Error obtaining read lock in"
+		      "%s due to: %s\n", context, strerror(lock_ret));
+    return false;
+  }
+
+  return true;
+}
+
+
+bool regfi_write_lock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
+{
+  int lock_ret = pthread_rwlock_wrlock(lock);
+  if(lock_ret != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Error obtaining write lock in"
+		      "%s due to: %s\n", context, strerror(lock_ret));
+    return false;
+  }
+
+  return true;
+}
+
+
+bool regfi_rw_unlock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
+{
+  int lock_ret = pthread_rwlock_unlock(lock);
+  if(lock_ret != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Error releasing lock in"
+		      "%s due to: %s\n", context, strerror(lock_ret));
+    return false;
+  }
+
+  return true;
+}
+
+
+bool regfi_lock(REGFI_FILE* file, pthread_mutex_t* lock, const char* context)
+{
+  int lock_ret = pthread_mutex_lock(lock);
+  if(lock_ret != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Error obtaining mutex lock in"
+		      "%s due to: %s\n", context, strerror(lock_ret));
+    return false;
+  }
+
+  return true;
+}
+
+
+bool regfi_unlock(REGFI_FILE* file, pthread_mutex_t* lock, const char* context)
+{
+  int lock_ret = pthread_mutex_unlock(lock);
+  if(lock_ret != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Error releasing mutex lock in"
+		      "%s due to: %s\n", context, strerror(lock_ret));
+    return false;
+  }
+
+  return true;
+}
+
+
 off_t regfi_raw_seek(REGFI_RAW_FILE* self, off_t offset, int whence)
 {
@@ -655,4 +725,7 @@
   bool recursive_type;
 
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_subkeylist"))
+     goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN,
 		       &cell_length, &unalloc))
@@ -660,5 +733,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while "
 		      "parsing subkey-list at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -668,5 +741,5 @@
 		      " while parsing subkey-list at offset 0x%.8X.", offset);
     if(strict)
-      return NULL;
+      goto fail_locked;
     cell_length = max_size & 0xFFFFFFF8;
   }
@@ -687,10 +760,10 @@
 		      " (0x%.2X, 0x%.2X) encountered while parsing"
 		      " subkey-list at offset 0x%.8X.", buf[0], buf[1], offset);
-    return NULL;
+    goto fail_locked;
   }
 
   ret_val = talloc(NULL, REGFI_SUBKEY_LIST);
   if(ret_val == NULL)
-    return NULL;
+    goto fail_locked;
 
   ret_val->offset = offset;
@@ -711,5 +784,5 @@
 		      offset);
     if(strict)
-      goto fail;
+      goto fail_locked;
     length = cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32_t);
   }
@@ -718,13 +791,16 @@
 				   ret_val->num_children);
   if(ret_val->elements == NULL)
-    goto fail;
+    goto fail_locked;
 
   elements = (uint8_t*)malloc(length);
   if(elements == NULL)
-    goto fail;
+    goto fail_locked;
 
   read_len = length;
   if(regfi_read(file->cb, elements, &read_len) != 0 || read_len!=length)
-    goto fail;
+    goto fail_locked;
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_subkeylist"))
+     goto fail;
 
   if(elem_size == sizeof(uint32_t))
@@ -748,4 +824,6 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_subkeylist");
  fail:
   if(elements != NULL)
@@ -817,5 +895,5 @@
 			     bool strict)
 {
-  REGFI_SK_REC* ret_val;
+  REGFI_SK_REC* ret_val = NULL;
   uint8_t* sec_desc_buf = NULL;
   uint32_t cell_length, length;
@@ -823,4 +901,7 @@
   bool unalloc = false;
 
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_sk"))
+     goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, sk_header, REGFI_SK_MIN_LENGTH,
 		       &cell_length, &unalloc))
@@ -828,5 +909,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Could not parse SK record cell"
 		      " at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
    
@@ -835,10 +916,10 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
 		      " SK record at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
 
   ret_val = talloc(NULL, REGFI_SK_REC);
   if(ret_val == NULL)
-    return NULL;
+    goto fail_locked;
 
   ret_val->offset = offset;
@@ -855,5 +936,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size found while"
 		      " parsing SK record at offset 0x%.8X.", offset);
-    goto fail;
+    goto fail_locked;
   }
 
@@ -873,5 +954,5 @@
 		      " are not a multiple of 8 while parsing SK record at"
 		      " offset 0x%.8X.", offset);
-    goto fail;
+    goto fail_locked;
   }
 
@@ -881,10 +962,10 @@
 		      " cell while parsing SK record at offset 0x%.8X.", 
 		      offset);
-    goto fail;
+    goto fail_locked;
   }
 
   sec_desc_buf = (uint8_t*)malloc(ret_val->desc_size);
   if(sec_desc_buf == NULL)
-    goto fail;
+    goto fail_locked;
 
   length = ret_val->desc_size;
@@ -895,6 +976,9 @@
 		      " descriptor while parsing SK record at offset 0x%.8X.",
 		      offset);
-    goto fail;
-  }
+    goto fail_locked;
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_sk"))
+     goto fail;
 
   if(!(ret_val->sec_desc = winsec_parse_desc(ret_val, sec_desc_buf, 
@@ -910,4 +994,6 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_sk");
  fail:
   if(sec_desc_buf != NULL)
@@ -925,9 +1011,12 @@
   bool unalloc;
 
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_valuelist"))
+     goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, NULL, 0, &cell_length, &unalloc))
   {
     regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read cell header"
 		      " while parsing value list at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -937,5 +1026,5 @@
 		      " while parsing value list at offset 0x%.8X.", offset);
     if(strict)
-      return NULL;
+      goto fail_locked;
     cell_length = cell_length & 0xFFFFFFF8;
   }
@@ -946,5 +1035,5 @@
 		      " while parsing value list at offset 0x%.8X.", offset);
     if(strict)
-      return NULL;
+      goto fail_locked;
     num_values = cell_length/sizeof(uint32_t) - sizeof(uint32_t);
   }
@@ -953,12 +1042,10 @@
   ret_val = talloc(NULL, REGFI_VALUE_LIST);
   if(ret_val == NULL)
-    return NULL;
+    goto fail_locked;
 
   ret_val->elements = (REGFI_VALUE_LIST_ELEM*)talloc_size(ret_val, read_len);
   if(ret_val->elements == NULL)
-  {
-    talloc_free(ret_val);
-    return NULL;
-  }
+    goto fail_locked;
+
   ret_val->num_values = num_values;
 
@@ -969,8 +1056,10 @@
     regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read value pointers"
 		      " while parsing value list at offset 0x%.8X.", offset);
-    talloc_free(ret_val);
-    return NULL;
-  }
-  
+    goto fail_locked;
+  }
+  
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_valuelist"))
+     goto fail;
+
   for(i=0; i < num_values; i++)
   {
@@ -989,6 +1078,5 @@
 			  " (0x%.8X) found while parsing value list at offset"
 			  " 0x%.8X.", ret_val->elements[i], offset);
-	talloc_free(ret_val);
-	return NULL;
+	goto fail;
       }
     }
@@ -996,4 +1084,10 @@
 
   return ret_val;
+
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_valuelist");
+ fail:
+  talloc_free(ret_val);
+  return NULL;
 }
 
@@ -1195,5 +1289,5 @@
 	}
       }
-      talloc_steal(nk, nk->values);
+      talloc_reference(nk, nk->values);
     }
   }
@@ -1225,5 +1319,5 @@
 	nk->num_subkeys = 0;
       }
-      talloc_steal(nk, nk->subkeys);
+      talloc_reference(nk, nk->subkeys);
     }
   }
@@ -1241,4 +1335,7 @@
   void* failure_ptr = NULL;
   
+  if(!regfi_lock(file, file->sk_lock, "regfi_load_sk"))
+    return NULL;
+
   /* First look if we have already parsed it */
   ret_val = (REGFI_SK_REC*)lru_cache_find(file->sk_cache, &offset, 4);
@@ -1268,4 +1365,7 @@
   }
 
+  if(!regfi_unlock(file, file->sk_lock, "regfi_load_sk"))
+    return NULL;
+
   return ret_val;
 }
@@ -1286,4 +1386,8 @@
   while(cur_offset < hbin_end)
   {
+
+    if(!regfi_lock(file, file->cb_lock, "regfi_find_root_nk"))
+      return NULL;
+
     if(!regfi_parse_cell(file->cb, cur_offset, NULL, 0, &cell_length, &unalloc))
     {
@@ -1292,5 +1396,8 @@
       return NULL;
     }
-    
+
+    if(!regfi_unlock(file, file->cb_lock, "regfi_find_root_nk"))
+      return NULL;
+
     if(!unalloc)
     {
@@ -1335,5 +1442,5 @@
 
   /* In this case, we want file_cb to be freed when ret_val is */
-  talloc_steal(ret_val, file_cb);
+  talloc_reference(ret_val, file_cb);
   return ret_val;
 
@@ -1369,13 +1476,24 @@
   rb->file_length = file_length;  
   rb->cb = file_cb;
+  rb->cb_lock = NULL;
+  rb->hbins_lock = NULL;
+  rb->sk_lock = NULL;
+
+  rb->cb_lock = talloc(rb, pthread_mutex_t);
+  if(rb->cb_lock == NULL || pthread_mutex_init(rb->cb_lock, NULL) != 0)
+    goto fail;
+
+  rb->hbins_lock = talloc(rb, pthread_rwlock_t);
+  if(rb->hbins_lock == NULL || pthread_rwlock_init(rb->hbins_lock, NULL) != 0)
+    goto fail;
+
+  rb->sk_lock = talloc(rb, pthread_mutex_t);
+  if(rb->sk_lock == NULL || pthread_mutex_init(rb->sk_lock, NULL) != 0)
+    goto fail;
 
   rb->hbins = range_list_new();
   if(rb->hbins == NULL)
-  {
-    /* fprintf(stderr, "regfi_alloc_cb: Failed to create HBIN list.\n"); */
-    talloc_free(rb);
-    return NULL;
-  }
-  talloc_steal(rb, rb->hbins);
+    goto fail;
+  talloc_reference(rb, rb->hbins);
 
   rla = true;
@@ -1386,5 +1504,6 @@
     rla = range_list_add(rb->hbins, hbin->file_off, hbin->block_size, hbin);
     if(rla)
-      talloc_steal(rb->hbins, hbin);
+      talloc_reference(rb->hbins, hbin);
+
     hbin_off = hbin->file_off + hbin->block_size;
     hbin = regfi_parse_hbin(rb, hbin_off, true);
@@ -1405,4 +1524,18 @@
   /* success */
   return rb;
+
+ fail:
+  if(rb->cb_lock != NULL)
+    pthread_mutex_destroy(rb->cb_lock);
+  if(rb->hbins_lock != NULL)
+    pthread_rwlock_destroy(rb->hbins_lock);
+  if(rb->sk_lock != NULL)
+    pthread_mutex_destroy(rb->sk_lock);
+
+  range_list_free(rb->hbins);
+  talloc_free(rb->cb_lock);
+  talloc_free(rb->hbins_lock);
+  talloc_free(rb);
+  return NULL;
 }
 
@@ -1415,4 +1548,7 @@
     free(file->last_message);
 
+  pthread_mutex_destroy(file->cb_lock);
+  pthread_rwlock_destroy(file->hbins_lock);
+  pthread_mutex_destroy(file->sk_lock);
   talloc_free(file);
 }
@@ -1447,4 +1583,8 @@
    * block at a time looking for an NK record with a root key type.
    */
+  
+  if(!regfi_read_lock(file, file->hbins_lock, "regfi_rootkey"))
+    return NULL;
+
   num_hbins = range_list_size(file->hbins);
   for(i=0; i < num_hbins && nk == NULL; i++)
@@ -1453,4 +1593,7 @@
     nk = regfi_find_root_nk(file, hbin, output_encoding);
   }
+
+  if(!regfi_rw_unlock(file, file->hbins_lock, "regfi_rootkey"))
+    return NULL;
 
   return nk;
@@ -1519,5 +1662,5 @@
     return NULL;
   }
-  talloc_steal(ret_val, ret_val->key_positions);
+  talloc_reference(ret_val, ret_val->key_positions);
 
   ret_val->f = file;
@@ -1567,5 +1710,5 @@
     return false;
   }
-  talloc_steal(i, subkey);
+  talloc_reference(i, subkey);
 
   i->cur_key = subkey;
@@ -1852,5 +1995,5 @@
   ret_val->raw = raw;
   ret_val->size = parse_length;
-  talloc_steal(ret_val, raw);
+  talloc_reference(ret_val, raw);
 
   interpreted = talloc_array(NULL, char, parse_length);
@@ -1872,5 +2015,5 @@
     interpreted = talloc_realloc(NULL, interpreted, char, conv_size);
     ret_val->interpreted = interpreted;
-    talloc_steal(ret_val, interpreted);
+    talloc_reference(ret_val, interpreted);
   }
 
@@ -1952,5 +2095,5 @@
     return NULL;
   
-  talloc_steal(ret_val, raw_data.buf);
+  talloc_reference(ret_val, raw_data.buf);
   ret_val->raw = raw_data.buf;
   ret_val->size = raw_data.len;
@@ -2007,5 +2150,5 @@
     data->interpreted.string = tmp_str;
     data->interpreted_size = tmp_size;
-    talloc_steal(data, tmp_str);
+    talloc_reference(data, tmp_str);
     break;
 
@@ -2092,6 +2235,6 @@
     /* XXX: how meaningful is this?  should we store number of strings instead? */
     data->interpreted_size = tmp_size;
-    talloc_steal(tmp_array, tmp_str);
-    talloc_steal(data, tmp_array);
+    talloc_reference(tmp_array, tmp_str);
+    talloc_reference(data, tmp_array);
     break;
 
@@ -2281,5 +2424,8 @@
   
   if(offset >= file->file_length)
-    return NULL;
+    goto fail;
+  
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_hbin"))
+    goto fail;
 
   if(regfi_seek(file->cb, offset, SEEK_SET) == -1)
@@ -2287,5 +2433,5 @@
     regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
 		      " while parsing hbin at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -2293,16 +2439,12 @@
   if((regfi_read(file->cb, hbin_header, &length) != 0) 
      || length != REGFI_HBIN_HEADER_SIZE)
-    return NULL;
-
-  if(regfi_seek(file->cb, offset, SEEK_SET) == -1)
-  {
-    regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
-		      " while parsing hbin at offset 0x%.8X.", offset);
-    return NULL;
-  }
+    goto fail_locked;
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_hbin"))
+    goto fail;
 
   hbin = talloc(NULL, REGFI_HBIN);
   if(hbin == NULL)
-    return NULL;
+    goto fail;
   hbin->file_off = offset;
 
@@ -2314,6 +2456,5 @@
 		      " 0x%.8X.", hbin->magic[0], hbin->magic[1], 
 		      hbin->magic[2], hbin->magic[3], offset);
-    talloc_free(hbin);
-    return NULL;
+    goto fail;
   }
 
@@ -2336,9 +2477,14 @@
 		      " or runs off the end of the file"
 		      " while parsing hbin at offset 0x%.8X.", offset);
-    talloc_free(hbin);
-    return NULL;
+    goto fail;
   }
 
   return hbin;
+
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_hbin");
+ fail:
+  talloc_free(hbin);
+  return NULL;
 }
 
@@ -2354,4 +2500,15 @@
   bool unalloc = false;
 
+  ret_val = talloc(NULL, REGFI_NK_REC);
+  if(ret_val == NULL)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to allocate memory while"
+		      " parsing NK record at offset 0x%.8X.", offset);
+    goto fail;
+  }
+
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_nk"))
+    goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, nk_header, REGFI_NK_MIN_LENGTH,
 		       &cell_length, &unalloc))
@@ -2359,21 +2516,12 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
 		      " while parsing NK record at offset 0x%.8X.", offset);
-    return NULL;
-  }
-
-  /* A bit of validation before bothering to allocate memory */
+    goto fail_locked;
+  }
+
   if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
   {
     regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
 		      " NK record at offset 0x%.8X.", offset);
-    return NULL;
-  }
-
-  ret_val = talloc(NULL, REGFI_NK_REC);
-  if(ret_val == NULL)
-  {
-    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to allocate memory while"
-		      " parsing NK record at offset 0x%.8X.", offset);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -2390,6 +2538,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "A length check failed while"
 		      " parsing NK record at offset 0x%.8X.", offset);
-    talloc_free(ret_val);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -2414,8 +2561,5 @@
      && (ret_val->mtime.high < REGFI_MTIME_MIN_HIGH 
 	 || ret_val->mtime.high > REGFI_MTIME_MAX_HIGH))
-  {
-    talloc_free(ret_val);
-    return NULL;
-  }
+  { goto fail_locked; }
 
   ret_val->unknown1 = IVAL(nk_header, 0xC);
@@ -2446,6 +2590,5 @@
       regfi_add_message(file, REGFI_MSG_ERROR, "Contents too large for cell"
 			" while parsing NK record at offset 0x%.8X.", offset);
-      talloc_free(ret_val);
-      return NULL;
+      goto fail_locked;
     }
     else
@@ -2466,8 +2609,5 @@
   ret_val->keyname_raw = talloc_array(ret_val, uint8_t, ret_val->name_length);
   if(ret_val->keyname_raw == NULL)
-  {
-    talloc_free(ret_val);
-    return NULL;
-  }
+    goto fail_locked;
 
   /* Don't need to seek, should be at the right offset */
@@ -2478,9 +2618,17 @@
     regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read key name"
 		      " while parsing NK record at offset 0x%.8X.", offset);
-    talloc_free(ret_val);
-    return NULL;
-  }
+    goto fail_locked;
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_nk"))
+    goto fail;
 
   return ret_val;
+
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_nk");
+ fail:
+  talloc_free(ret_val);
+  return NULL;
 }
 
@@ -2494,57 +2642,68 @@
   bool unalloc = false;
 
-  if(*name_length > 0 && offset != REGFI_OFFSET_NONE 
-     && (offset & 0x00000007) == 0)
-  {
-    if(!regfi_parse_cell(file->cb, offset, NULL, 0, &cell_length, &unalloc))
-    {
-      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
+  if(*name_length <= 0 || offset == REGFI_OFFSET_NONE  
+     || (offset & 0x00000007) != 0)
+  { goto fail; }
+
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_classname"))
+    goto fail;
+
+  if(!regfi_parse_cell(file->cb, offset, NULL, 0, &cell_length, &unalloc))
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
+		      " while parsing class name at offset 0x%.8X.", offset);
+    goto fail_locked;
+  }
+  
+  if((cell_length & 0x0000007) != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_ERROR, "Cell length not a multiple of 8"
+		      " while parsing class name at offset 0x%.8X.", offset);
+    goto fail_locked;
+  }
+  
+  if(cell_length > max_size)
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Cell stretches past hbin "
+		      "boundary while parsing class name at offset 0x%.8X.",
+		      offset);
+    if(strict)
+      goto fail_locked;
+    cell_length = max_size;
+  }
+  
+  if((cell_length - 4) < *name_length)
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Class name is larger than"
+		      " cell_length while parsing class name at offset"
+		      " 0x%.8X.", offset);
+    if(strict)
+      goto fail_locked;
+    *name_length = cell_length - 4;
+  }
+  
+  ret_val = talloc_array(NULL, uint8_t, *name_length);
+  if(ret_val != NULL)
+  {
+    length = *name_length;
+    if((regfi_read(file->cb, ret_val, &length) != 0)
+       || length != *name_length)
+    {
+      regfi_add_message(file, REGFI_MSG_ERROR, "Could not read class name"
 			" while parsing class name at offset 0x%.8X.", offset);
-	return NULL;
-    }
-
-    if((cell_length & 0x0000007) != 0)
-    {
-      regfi_add_message(file, REGFI_MSG_ERROR, "Cell length not a multiple of 8"
-			" while parsing class name at offset 0x%.8X.", offset);
-      return NULL;
-    }
-
-    if(cell_length > max_size)
-    {
-      regfi_add_message(file, REGFI_MSG_WARN, "Cell stretches past hbin "
-			"boundary while parsing class name at offset 0x%.8X.",
-			offset);
-      if(strict)
-	return NULL;
-      cell_length = max_size;
-    }
-
-    if((cell_length - 4) < *name_length)
-    {
-      regfi_add_message(file, REGFI_MSG_WARN, "Class name is larger than"
-			" cell_length while parsing class name at offset"
-			" 0x%.8X.", offset);
-      if(strict)
-	return NULL;
-      *name_length = cell_length - 4;
-    }
-    
-    ret_val = talloc_array(NULL, uint8_t, *name_length);
-    if(ret_val != NULL)
-    {
-      length = *name_length;
-      if((regfi_read(file->cb, ret_val, &length) != 0)
-	 || length != *name_length)
-      {
-	regfi_add_message(file, REGFI_MSG_ERROR, "Could not read class name"
-			  " while parsing class name at offset 0x%.8X.", offset);
-	talloc_free(ret_val);
-	return NULL;
-      }
-    }
-  }
+      goto fail_locked;
+    }
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_classname"))
+    goto fail;
 
   return ret_val;
+
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_classname");
+ fail:
+  talloc_free(ret_val);
+  return NULL;
 }
 
@@ -2560,4 +2719,11 @@
   bool unalloc = false;
 
+  ret_val = talloc(NULL, REGFI_VK_REC);
+  if(ret_val == NULL)
+    goto fail;
+
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_nk"))
+    goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, vk_header, REGFI_VK_MIN_LENGTH,
 		       &cell_length, &unalloc))
@@ -2565,10 +2731,6 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
 		      " while parsing VK record at offset 0x%.8X.", offset);
-    return NULL;
-  }
-
-  ret_val = talloc(NULL, REGFI_VK_REC);
-  if(ret_val == NULL)
-    return NULL;
+    goto fail_locked;
+  }
 
   ret_val->offset = offset;
@@ -2584,6 +2746,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size encountered"
 		      " while parsing VK record at offset 0x%.8X.", offset);
-    talloc_free(ret_val);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -2598,6 +2759,5 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch"
 		      " while parsing VK record at offset 0x%.8X.", offset);
-    talloc_free(ret_val);
-    return NULL;
+    goto fail_locked;
   }
 
@@ -2622,8 +2782,5 @@
 			offset);
       if(strict)
-      {
-	talloc_free(ret_val);
-	return NULL;
-      }
+	goto fail_locked;
       else
 	ret_val->name_length = ret_val->cell_size - REGFI_VK_MIN_LENGTH - 4;
@@ -2637,8 +2794,5 @@
     ret_val->valuename_raw = talloc_array(ret_val, uint8_t, ret_val->name_length);
     if(ret_val->valuename_raw == NULL)
-    {
-      talloc_free(ret_val);
-      return NULL;
-    }
+      goto fail_locked;
 
     length = ret_val->name_length;
@@ -2648,10 +2802,12 @@
       regfi_add_message(file, REGFI_MSG_ERROR, "Could not read value name"
 			" while parsing VK record at offset 0x%.8X.", offset);
-      talloc_free(ret_val);
-      return NULL;
+      goto fail_locked;
     }
   }
   else
     cell_length = REGFI_VK_MIN_LENGTH + 4;
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_nk"))
+    goto fail;
 
   if(unalloc)
@@ -2663,4 +2819,10 @@
 
   return ret_val;
+  
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_vk");
+ fail:
+  talloc_free(ret_val);
+  return NULL;
 }
 
@@ -2711,4 +2873,7 @@
     }
     
+    if(!regfi_lock(file, file->cb_lock, "regfi_load_data"))
+      goto fail;
+
     if(!regfi_parse_cell(file->cb, offset, NULL, 0,
 			 &cell_length, &unalloc))
@@ -2716,6 +2881,9 @@
       regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
 			" parsing data record at offset 0x%.8X.", offset);
+      goto fail_locked;
+    }
+
+    if(!regfi_unlock(file, file->cb_lock, "regfi_load_data"))
       goto fail;
-    }
 
     if((cell_length & 0x00000007) != 0)
@@ -2765,4 +2933,6 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_load_data");
  fail:
   ret_val.buf = NULL;
@@ -2784,14 +2954,17 @@
   ret_val.len = 0;
   
+  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
+    goto fail;
+  ret_val.len = length;
+
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_data"))
+    goto fail;
+
   if(regfi_seek(file->cb, offset+4, SEEK_SET) == -1)
   {
     regfi_add_message(file, REGFI_MSG_WARN, "Could not seek while "
 		      "reading data at offset 0x%.8X.", offset);
-    return ret_val;
-  }
-
-  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
-    return ret_val;
-  ret_val.len = length;
+    goto fail_locked;
+  }
   
   read_length = length;
@@ -2801,9 +2974,18 @@
     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.buf);
-    ret_val.buf = NULL;
-    ret_val.buf = 0;
-  }
-
+    goto fail_locked;
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_data"))
+    goto fail;
+
+  return ret_val;
+
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_data");
+ fail:
+  talloc_free(ret_val.buf);
+  ret_val.buf = NULL;
+  ret_val.buf = 0;
   return ret_val;
 }
@@ -2862,4 +3044,8 @@
   }
 
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_big_data_header"))
+    goto fail;
+
+
   if(!regfi_parse_cell(file->cb, offset, ret_val.buf, REGFI_BIG_DATA_MIN_LENGTH,
 		       &cell_length, &unalloc))
@@ -2867,6 +3053,9 @@
     regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
 		      " parsing big data header at offset 0x%.8X.", offset);
-    goto fail;
-  }
+    goto fail_locked;
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_header"))
+    goto fail;
 
   if((ret_val.buf[0] != 'd') || (ret_val.buf[1] != 'b'))
@@ -2882,10 +3071,9 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_header");
  fail:
-  if(ret_val.buf != NULL)
-  {
-    talloc_free(ret_val.buf);
-    ret_val.buf = NULL;
-  }
+  talloc_free(ret_val.buf);
+  ret_val.buf = NULL;
   ret_val.len = 0;
   return ret_val;
@@ -2916,4 +3104,7 @@
     goto fail;
 
+  if(!regfi_lock(file, file->cb_lock, "regfi_parse_big_data_indirect"))
+    goto fail;
+
   if(!regfi_parse_cell(file->cb, offset, (uint8_t*)ret_val,
 		       num_chunks*sizeof(uint32_t),
@@ -2923,6 +3114,9 @@
 		      " parsing big data indirect record at offset 0x%.8X.", 
 		      offset);
-    goto fail;
-  }
+    goto fail_locked;
+  }
+
+  if(!regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_indirect"))
+    goto fail;
 
   /* Convert pointers to proper endianess, verify they are aligned. */
@@ -2936,7 +3130,8 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_indirect");
  fail:
-  if(ret_val != NULL)
-    talloc_free(ret_val);
+  talloc_free(ret_val);
   return NULL;
 }
@@ -2970,4 +3165,7 @@
   for(i=0; i<num_chunks; i++)
   {
+    if(!regfi_lock(file, file->cb_lock, "regfi_parse_big_data_cells"))
+      goto fail;
+
     chunk_offset = offsets[i]+REGFI_REGF_SIZE;
     if(!regfi_parse_cell(file->cb, chunk_offset, NULL, 0,
@@ -2977,6 +3175,9 @@
 			" parsing big data chunk at offset 0x%.8X.", 
 			chunk_offset);
+      goto fail_locked;
+    }
+
+    if(!regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_cells"))
       goto fail;
-    }
 
     if(!range_list_add(ret_val, chunk_offset, cell_length, NULL))
@@ -2986,4 +3187,6 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_parse_big_data_cells");
  fail:
   if(ret_val != NULL)
@@ -3079,4 +3282,7 @@
     }
 
+    if(!regfi_lock(file, file->cb_lock, "regfi_load_big_data"))
+      goto fail;
+
     if(regfi_seek(file->cb, cell_info->offset+sizeof(uint32_t), SEEK_SET) == -1)
     {
@@ -3084,5 +3290,5 @@
 			"constructing big data at offset 0x%.8X "
 			"(chunk offset 0x%.8X).", offset, cell_info->offset);
-      goto fail;
+      goto fail_locked;
     }
 
@@ -3094,6 +3300,9 @@
 			" constructing big data at offset 0x%.8X"
 			" (chunk offset 0x%.8X).", offset, cell_info->offset);
+      goto fail_locked;
+    }
+
+    if(!regfi_unlock(file, file->cb_lock, "regfi_load_big_data"))
       goto fail;
-    }
 
     if(used_ranges != NULL)
@@ -3108,9 +3317,9 @@
   return ret_val;
 
+ fail_locked:
+  regfi_unlock(file, file->cb_lock, "regfi_load_big_data");
  fail:
-  if(ret_val.buf != NULL)
-    talloc_free(ret_val.buf);
-  if(indirect_ptrs != NULL)
-    talloc_free(indirect_ptrs);
+  talloc_free(ret_val.buf);
+  talloc_free(indirect_ptrs);
   if(bd_cells != NULL)
     range_list_free(bd_cells);
@@ -3133,4 +3342,10 @@
     return NULL;
 
+  if(!regfi_read_lock(file, file->hbins_lock, "regfi_parse_unalloc_cells"))
+  {
+    range_list_free(ret_val);
+    return NULL;
+  }
+
   num_hbins = range_list_size(file->hbins);
   for(i=0; i<num_hbins; i++)
@@ -3144,8 +3359,17 @@
     while(curr_off < hbin->block_size)
     {
+      if(!regfi_lock(file, file->cb_lock, "regfi_parse_unalloc_cells"))
+	break;
+
       if(!regfi_parse_cell(file->cb, hbin->file_off+curr_off, NULL, 0,
 			   &cell_len, &is_unalloc))
+      {
+	regfi_unlock(file, file->cb_lock, "regfi_parse_unalloc_cells");
 	break;
-      
+      }
+
+      if(!regfi_unlock(file, file->cb_lock, "regfi_parse_unalloc_cells"))
+	break;
+
       if((cell_len == 0) || ((cell_len & 0x00000007) != 0))
       {
@@ -3171,4 +3395,10 @@
   }
 
+  if(!regfi_rw_unlock(file, file->hbins_lock, "regfi_parse_unalloc_cells"))
+  {
+    range_list_free(ret_val);
+    return NULL;
+  }
+
   return ret_val;
 }
