Index: /trunk/include/regfi.h
===================================================================
--- /trunk/include/regfi.h	(revision 79)
+++ /trunk/include/regfi.h	(revision 79)
@@ -0,0 +1,293 @@
+/*
+ * Branched from Samba project, Subversion repository version #6903:
+ *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/include/regfio.h
+ *
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ *
+ * Copyright (C) 2005-2006 Timothy D. Morgan
+ * Copyright (C) 2005 Gerald (Jerry) Carter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/************************************************************
+ * Most of this information was obtained from 
+ * http://www.wednesday.demon.co.uk/dosreg.html
+ * Thanks Nigel!
+ ***********************************************************/
+
+#ifndef _REGFI_H
+#define _REGFI_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "smb_deps.h"
+#include "void_stack.h"
+
+/******************************************************************************/
+/* Macros */
+ 
+/* Registry data types */
+#define REG_NONE                       0
+#define REG_SZ		               1
+#define REG_EXPAND_SZ                  2
+#define REG_BINARY 	               3
+#define REG_DWORD	               4
+#define REG_DWORD_LE	               4  /* DWORD, little endian */
+#define REG_DWORD_BE	               5  /* DWORD, big endian */
+#define REG_LINK                       6
+#define REG_MULTI_SZ  	               7
+#define REG_RESOURCE_LIST              8
+#define REG_FULL_RESOURCE_DESCRIPTOR   9
+#define REG_RESOURCE_REQUIREMENTS_LIST 10
+#define REG_QWORD                      11 /* 64-bit little endian */
+/* XXX: Has MS defined a REG_QWORD_BE? */
+/* Not a real type in the registry */
+#define REG_KEY                        255
+
+
+#define REGF_BLOCKSIZE		0x1000
+#define REGF_ALLOC_BLOCK	0x1000
+#define REGF_MAX_DEPTH		512
+
+/* header sizes for various records */
+
+#define REGF_HDR_SIZE		4
+#define HBIN_HDR_SIZE		4
+#define HBIN_HEADER_REC_SIZE	0x24
+#define REC_HDR_SIZE		2
+
+#define REGF_OFFSET_NONE	0xffffffff
+
+/* Flags for the vk records */
+
+#define VK_FLAG_NAME_PRESENT	0x0001
+#define VK_DATA_IN_OFFSET	0x80000000
+#define VK_MAX_DATA_LENGTH      1024*1024
+
+/* NK record macros */
+
+#define NK_TYPE_LINKKEY		0x0010
+#define NK_TYPE_NORMALKEY	0x0020
+#define NK_TYPE_ROOTKEY		0x002c
+
+#define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ };
+/* if the count == 0; we can clean up */
+#define HBIN_REMOVE_REF(x, y){ x->hbin = NULL; y->ref_count-- };
+
+
+/* HBIN block */
+struct regf_hbin;
+typedef struct regf_hbin {
+  struct regf_hbin* prev;
+  struct regf_hbin* next;
+  uint32 file_off;       /* my offset in the registry file */
+  uint32 free_off;       /* offset to free space within the hbin record */
+  uint32 free_size;      /* amount of data left in the block */
+  int    ref_count;      /* how many active records are pointing to this
+                          * block (not used currently) 
+			  */
+	
+  uint8  header[HBIN_HDR_SIZE]; /* "hbin" */
+  uint32 first_hbin_off; /* offset from first hbin block */
+  uint32 block_size;     /* block size of this block is
+                          * usually a multiple of 4096Kb 
+			  */
+  prs_struct ps;	 /* data */
+  bool dirty;            /* has this hbin block been modified? */
+} REGF_HBIN;
+
+/* ??? List -- list of key offsets and hashed names for consistency */
+typedef struct {
+  uint32 nk_off;
+  uint8 keycheck[sizeof(uint32)];
+} REGF_HASH_REC;
+
+typedef struct {
+  REGF_HBIN *hbin;       /* pointer to HBIN record (in memory) containing 
+			  * this nk record 
+			  */
+  uint32 hbin_off;	 /* offset from beginning of this hbin block */
+  uint32 rec_size;	 /* ((start_offset - end_offset) & 0xfffffff8) */
+  
+  uint8 header[REC_HDR_SIZE];
+  uint16 num_keys;
+  REGF_HASH_REC *hashes;
+} REGF_LF_REC;
+
+/* Key Value */
+
+typedef struct {
+  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
+			 * this nk record 
+			 */
+  uint32 hbin_off;	/* offset from beginning of this hbin block */
+  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
+  uint32 rec_off;	/* offset stored in the value list */
+  
+  uint8  header[REC_HDR_SIZE];
+  char*  valuename;
+  uint32 data_size;
+  uint32 data_off;
+  uint8* data;
+  uint32 type;
+  uint16 flag;
+} REGF_VK_REC;
+
+
+/* Key Security */
+struct _regf_sk_rec;
+
+typedef struct _regf_sk_rec {
+  struct _regf_sk_rec *next, *prev;
+  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
+			 * this nk record 
+			 */
+  uint32 hbin_off;	/* offset from beginning of this hbin block */
+  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
+  
+  uint32 sk_off;	/* offset parsed from NK record used as a key
+			 * to lookup reference to this SK record 
+			 */
+  
+  uint8  header[REC_HDR_SIZE];
+  uint32 prev_sk_off;
+  uint32 next_sk_off;
+  uint32 ref_count;
+  uint32 size;
+  SEC_DESC *sec_desc;
+} REGF_SK_REC;
+
+/* Key Name */ 
+
+typedef struct {
+  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
+			 * this nk record 
+			 */
+  uint32 hbin_off;	/* offset from beginning of this hbin block */
+  /*uint32 subkey_index;*/	/* index to next subkey record to return */
+  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
+  
+  /* header information */
+  uint8  header[REC_HDR_SIZE];
+  uint16 key_type;
+  NTTIME mtime;
+  uint32 parent_off;	/* back pointer in registry hive */
+  uint32 classname_off;	
+  char *classname;
+  char *keyname;
+  
+  /* max lengths */
+  uint32 max_bytes_subkeyname;	    /* max subkey name * 2 */
+  uint32 max_bytes_subkeyclassname; /* max subkey classname length (as if) */
+  uint32 max_bytes_valuename;	    /* max valuename * 2 */
+  uint32 max_bytes_value;           /* max value data size */
+  
+  /* unknowns */
+  uint32 unk_index;		    /* nigel says run time index ? */
+  
+  /* children */
+  uint32 num_subkeys;
+  uint32 subkeys_off;	/* hash records that point to NK records */	
+  uint32 num_values;
+  uint32 values_off;	/* value lists which point to VK records */
+  uint32 sk_off;	/* offset to SK record */
+  
+  /* link in the other records here */
+  REGF_LF_REC subkeys;
+  REGF_VK_REC *values;
+  REGF_SK_REC *sec_desc;
+	
+} REGF_NK_REC;
+
+/* REGF block */
+ 
+typedef struct {
+  /* run time information */
+  int fd;	  /* file descriptor */
+  int open_flags; /* flags passed to the open() call */
+  void *mem_ctx;  /* memory context for run-time file access information */
+  REGF_HBIN *block_list; /* list of open hbin blocks */
+  
+  /* file format information */
+  
+  uint8  header[REGF_HDR_SIZE];	/* "regf" */
+  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;		/* XOR of bytes 0x0000 - 0x01FB */
+  NTTIME mtime;
+  
+  REGF_SK_REC *sec_desc_list;	/* list of security descriptors referenced 
+				 * by NK records 
+				 */
+  
+  /* unknowns */
+  uint32 unknown1;
+  uint32 unknown2;
+  uint32 unknown3;
+  uint32 unknown4;
+  uint32 unknown5;
+  uint32 unknown6;
+} REGF_FILE;
+
+
+
+typedef struct {
+  REGF_FILE* f;
+  void_stack* keys;
+  uint32 cur_subkey;
+  uint32 cur_value;
+} REGFI_ITERATOR;
+
+/******************************************************************************/
+/* Function Declarations */
+
+const char*   regfi_type_val2str(unsigned int val);
+int           regfi_type_str2val(const char* str);
+
+char*         regfi_get_sacl(SEC_DESC *sec_desc);
+char*         regfi_get_dacl(SEC_DESC *sec_desc);
+char*         regfi_get_owner(SEC_DESC *sec_desc);
+char*         regfi_get_group(SEC_DESC *sec_desc);
+
+REGF_FILE*    regfi_open( const char *filename );
+int           regfi_close( REGF_FILE *r );
+
+REGF_NK_REC*  regfi_rootkey( REGF_FILE *file );
+/* REGF_NK_REC*  regfi_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk ); */
+
+REGFI_ITERATOR* regfi_iterator_create(REGF_FILE* fh);
+bool            regfi_iterator_down(REGFI_ITERATOR* i, const char* subkey_name);
+bool            regfi_iterator_up(REGFI_ITERATOR* i);
+REGF_NK_REC*    regfi_iterator_next_subkey(REGFI_ITERATOR* i);
+REGF_VK_REC*    regfi_iterator_next_value(REGFI_ITERATOR* i);
+REGF_VK_REC*    regfi_iterator_fetch_value(REGFI_ITERATOR* i, const char* value_name);
+char*           regfi_iterator_curpath(REGFI_ITERATOR* i);
+
+#endif	/* _REGFI_H */
Index: unk/include/regfio.h
===================================================================
--- /trunk/include/regfio.h	(revision 78)
+++ 	(revision )
@@ -1,293 +1,0 @@
-/*
- * Branched from Samba project, Subversion repository version #6903:
- *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/include/regfio.h
- *
- * Unix SMB/CIFS implementation.
- * Windows NT registry I/O library
- *
- * Copyright (C) 2005-2006 Timothy D. Morgan
- * Copyright (C) 2005 Gerald (Jerry) Carter
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id$
- */
-
-/************************************************************
- * Most of this information was obtained from 
- * http://www.wednesday.demon.co.uk/dosreg.html
- * Thanks Nigel!
- ***********************************************************/
-
-#ifndef _REGFI_H
-#define _REGFI_H
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <assert.h>
-
-#include "smb_deps.h"
-#include "void_stack.h"
-
-/******************************************************************************/
-/* Macros */
- 
-/* Registry data types */
-#define REG_NONE                       0
-#define REG_SZ		               1
-#define REG_EXPAND_SZ                  2
-#define REG_BINARY 	               3
-#define REG_DWORD	               4
-#define REG_DWORD_LE	               4  /* DWORD, little endian */
-#define REG_DWORD_BE	               5  /* DWORD, big endian */
-#define REG_LINK                       6
-#define REG_MULTI_SZ  	               7
-#define REG_RESOURCE_LIST              8
-#define REG_FULL_RESOURCE_DESCRIPTOR   9
-#define REG_RESOURCE_REQUIREMENTS_LIST 10
-#define REG_QWORD                      11 /* 64-bit little endian */
-/* XXX: Has MS defined a REG_QWORD_BE? */
-/* Not a real type in the registry */
-#define REG_KEY                        255
-
-
-#define REGF_BLOCKSIZE		0x1000
-#define REGF_ALLOC_BLOCK	0x1000
-#define REGF_MAX_DEPTH		512
-
-/* header sizes for various records */
-
-#define REGF_HDR_SIZE		4
-#define HBIN_HDR_SIZE		4
-#define HBIN_HEADER_REC_SIZE	0x24
-#define REC_HDR_SIZE		2
-
-#define REGF_OFFSET_NONE	0xffffffff
-
-/* Flags for the vk records */
-
-#define VK_FLAG_NAME_PRESENT	0x0001
-#define VK_DATA_IN_OFFSET	0x80000000
-#define VK_MAX_DATA_LENGTH      1024*1024
-
-/* NK record macros */
-
-#define NK_TYPE_LINKKEY		0x0010
-#define NK_TYPE_NORMALKEY	0x0020
-#define NK_TYPE_ROOTKEY		0x002c
-
-#define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ };
-/* if the count == 0; we can clean up */
-#define HBIN_REMOVE_REF(x, y){ x->hbin = NULL; y->ref_count-- };
-
-
-/* HBIN block */
-struct regf_hbin;
-typedef struct regf_hbin {
-  struct regf_hbin* prev;
-  struct regf_hbin* next;
-  uint32 file_off;       /* my offset in the registry file */
-  uint32 free_off;       /* offset to free space within the hbin record */
-  uint32 free_size;      /* amount of data left in the block */
-  int    ref_count;      /* how many active records are pointing to this
-                          * block (not used currently) 
-			  */
-	
-  uint8  header[HBIN_HDR_SIZE]; /* "hbin" */
-  uint32 first_hbin_off; /* offset from first hbin block */
-  uint32 block_size;     /* block size of this block is
-                          * usually a multiple of 4096Kb 
-			  */
-  prs_struct ps;	 /* data */
-  bool dirty;            /* has this hbin block been modified? */
-} REGF_HBIN;
-
-/* ??? List -- list of key offsets and hashed names for consistency */
-typedef struct {
-  uint32 nk_off;
-  uint8 keycheck[sizeof(uint32)];
-} REGF_HASH_REC;
-
-typedef struct {
-  REGF_HBIN *hbin;       /* pointer to HBIN record (in memory) containing 
-			  * this nk record 
-			  */
-  uint32 hbin_off;	 /* offset from beginning of this hbin block */
-  uint32 rec_size;	 /* ((start_offset - end_offset) & 0xfffffff8) */
-  
-  uint8 header[REC_HDR_SIZE];
-  uint16 num_keys;
-  REGF_HASH_REC *hashes;
-} REGF_LF_REC;
-
-/* Key Value */
-
-typedef struct {
-  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
-			 * this nk record 
-			 */
-  uint32 hbin_off;	/* offset from beginning of this hbin block */
-  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
-  uint32 rec_off;	/* offset stored in the value list */
-  
-  uint8  header[REC_HDR_SIZE];
-  char*  valuename;
-  uint32 data_size;
-  uint32 data_off;
-  uint8* data;
-  uint32 type;
-  uint16 flag;
-} REGF_VK_REC;
-
-
-/* Key Security */
-struct _regf_sk_rec;
-
-typedef struct _regf_sk_rec {
-  struct _regf_sk_rec *next, *prev;
-  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
-			 * this nk record 
-			 */
-  uint32 hbin_off;	/* offset from beginning of this hbin block */
-  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
-  
-  uint32 sk_off;	/* offset parsed from NK record used as a key
-			 * to lookup reference to this SK record 
-			 */
-  
-  uint8  header[REC_HDR_SIZE];
-  uint32 prev_sk_off;
-  uint32 next_sk_off;
-  uint32 ref_count;
-  uint32 size;
-  SEC_DESC *sec_desc;
-} REGF_SK_REC;
-
-/* Key Name */ 
-
-typedef struct {
-  REGF_HBIN *hbin;	/* pointer to HBIN record (in memory) containing 
-			 * this nk record 
-			 */
-  uint32 hbin_off;	/* offset from beginning of this hbin block */
-  /*uint32 subkey_index;*/	/* index to next subkey record to return */
-  uint32 rec_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
-  
-  /* header information */
-  uint8  header[REC_HDR_SIZE];
-  uint16 key_type;
-  NTTIME mtime;
-  uint32 parent_off;	/* back pointer in registry hive */
-  uint32 classname_off;	
-  char *classname;
-  char *keyname;
-  
-  /* max lengths */
-  uint32 max_bytes_subkeyname;	    /* max subkey name * 2 */
-  uint32 max_bytes_subkeyclassname; /* max subkey classname length (as if) */
-  uint32 max_bytes_valuename;	    /* max valuename * 2 */
-  uint32 max_bytes_value;           /* max value data size */
-  
-  /* unknowns */
-  uint32 unk_index;		    /* nigel says run time index ? */
-  
-  /* children */
-  uint32 num_subkeys;
-  uint32 subkeys_off;	/* hash records that point to NK records */	
-  uint32 num_values;
-  uint32 values_off;	/* value lists which point to VK records */
-  uint32 sk_off;	/* offset to SK record */
-  
-  /* link in the other records here */
-  REGF_LF_REC subkeys;
-  REGF_VK_REC *values;
-  REGF_SK_REC *sec_desc;
-	
-} REGF_NK_REC;
-
-/* REGF block */
- 
-typedef struct {
-  /* run time information */
-  int fd;	  /* file descriptor */
-  int open_flags; /* flags passed to the open() call */
-  void *mem_ctx;  /* memory context for run-time file access information */
-  REGF_HBIN *block_list; /* list of open hbin blocks */
-  
-  /* file format information */
-  
-  uint8  header[REGF_HDR_SIZE];	/* "regf" */
-  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;		/* XOR of bytes 0x0000 - 0x01FB */
-  NTTIME mtime;
-  
-  REGF_SK_REC *sec_desc_list;	/* list of security descriptors referenced 
-				 * by NK records 
-				 */
-  
-  /* unknowns */
-  uint32 unknown1;
-  uint32 unknown2;
-  uint32 unknown3;
-  uint32 unknown4;
-  uint32 unknown5;
-  uint32 unknown6;
-} REGF_FILE;
-
-
-
-typedef struct {
-  REGF_FILE* f;
-  void_stack* keys;
-  uint32 cur_subkey;
-  uint32 cur_value;
-} REGFI_ITERATOR;
-
-/******************************************************************************/
-/* Function Declarations */
-
-const char*   regfi_type_val2str(unsigned int val);
-int           regfi_type_str2val(const char* str);
-
-char*         regfi_get_sacl(SEC_DESC *sec_desc);
-char*         regfi_get_dacl(SEC_DESC *sec_desc);
-char*         regfi_get_owner(SEC_DESC *sec_desc);
-char*         regfi_get_group(SEC_DESC *sec_desc);
-
-REGF_FILE*    regfi_open( const char *filename );
-int           regfi_close( REGF_FILE *r );
-
-REGF_NK_REC*  regfi_rootkey( REGF_FILE *file );
-/* REGF_NK_REC*  regfi_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk ); */
-
-REGFI_ITERATOR* regfi_iterator_create(REGF_FILE* fh);
-bool            regfi_iterator_down(REGFI_ITERATOR* i, const char* subkey_name);
-bool            regfi_iterator_up(REGFI_ITERATOR* i);
-REGF_NK_REC*    regfi_iterator_next_subkey(REGFI_ITERATOR* i);
-REGF_VK_REC*    regfi_iterator_next_value(REGFI_ITERATOR* i);
-REGF_VK_REC*    regfi_iterator_fetch_value(REGFI_ITERATOR* i, const char* value_name);
-char*           regfi_iterator_curpath(REGFI_ITERATOR* i);
-
-#endif	/* _REGFI_H */
Index: /trunk/include/void_stack.h
===================================================================
--- /trunk/include/void_stack.h	(revision 78)
+++ /trunk/include/void_stack.h	(revision 79)
@@ -21,4 +21,7 @@
 #include <stdbool.h>
 #include <string.h>
+
+#define _VOID_STACK_H
+#ifndef _VOID_STACK_H
 
 typedef struct _void_stack
@@ -48,2 +51,4 @@
 void void_stack_iterator_destroy(void_stack_iterator* iter);
 const void* void_stack_iterator_next(void_stack_iterator* iter);
+
+#endif
Index: /trunk/lib/regfi.c
===================================================================
--- /trunk/lib/regfi.c	(revision 79)
+++ /trunk/lib/regfi.c	(revision 79)
@@ -0,0 +1,1545 @@
+/*
+ * Branched from Samba project Subversion repository, version #7470:
+ *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
+ *
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ *
+ * Copyright (C) 2005-2006 Timothy D. Morgan
+ * Copyright (C) 2005 Gerald (Jerry) Carter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+ *
+ * $Id$
+ */
+
+#include "../include/regfio.h"
+
+
+/* Registry types mapping */
+const unsigned int regfi_num_reg_types = 12;
+static const char* regfi_type_names[] =
+  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
+   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
+
+
+/* Returns NULL on error */
+const char* regfi_type_val2str(unsigned int val)
+{
+  if(val == REG_KEY)
+    return "KEY";
+  
+  if(val >= regfi_num_reg_types)
+    return NULL;
+  
+  return regfi_type_names[val];
+}
+
+
+/* Returns -1 on error */
+int regfi_type_str2val(const char* str)
+{
+  int i;
+
+  if(strcmp("KEY", str) == 0)
+    return REG_KEY;
+
+  for(i=0; i < regfi_num_reg_types; i++)
+    if (strcmp(regfi_type_names[i], str) == 0) 
+      return i;
+
+  if(strcmp("DWORD_LE", str) == 0)
+    return REG_DWORD_LE;
+
+  return -1;
+}
+
+
+/* Security descriptor parsing functions  */
+
+const char* regfi_ace_type2str(uint8 type)
+{
+  static const char* map[7] 
+    = {"ALLOW", "DENY", "AUDIT", "ALARM", 
+       "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
+  if(type < 7)
+    return map[type];
+  else
+    /* XXX: would be nice to return the unknown integer value.  
+     *      However, as it is a const string, it can't be free()ed later on, 
+     *      so that would need to change. 
+     */
+    return "UNKNOWN";
+}
+
+
+/* XXX: need a better reference on the meaning of each flag. */
+/* For more info, see:
+ *   http://msdn2.microsoft.com/en-us/library/aa772242.aspx
+ */
+char* regfi_ace_flags2str(uint8 flags)
+{
+  static const char* flag_map[32] = 
+    { "OI",
+      "CI",
+      "NP",
+      "IO",
+      "IA",
+      NULL,
+      NULL,
+      NULL,
+    };
+
+  char* ret_val = malloc(35*sizeof(char));
+  char* fo = ret_val;
+  uint32 i;
+  uint8 f;
+
+  if(ret_val == NULL)
+    return NULL;
+
+  fo[0] = '\0';
+  if (!flags)
+    return ret_val;
+
+  for(i=0; i < 8; i++)
+  {
+    f = (1<<i);
+    if((flags & f) && (flag_map[i] != NULL))
+    {
+      strcpy(fo, flag_map[i]);
+      fo += strlen(flag_map[i]);
+      *(fo++) = ' ';
+      flags ^= f;
+    }
+  }
+  
+  /* Any remaining unknown flags are added at the end in hex. */
+  if(flags != 0)
+    sprintf(fo, "0x%.2X ", flags);
+
+  /* Chop off the last space if we've written anything to ret_val */
+  if(fo != ret_val)
+    fo[-1] = '\0';
+
+  /* XXX: what was this old VI flag for??
+     XXX: Is this check right?  0xF == 1|2|4|8, which makes it redundant...
+  if (flags == 0xF) {
+    if (some) strcat(flg_output, " ");
+    some = 1;
+    strcat(flg_output, "VI");
+  }
+  */
+
+  return ret_val;
+}
+
+
+char* regfi_ace_perms2str(uint32 perms)
+{
+  uint32 i, p;
+  /* This is more than is needed by a fair margin. */
+  char* ret_val = malloc(350*sizeof(char));
+  char* r = ret_val;
+
+  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
+   * For more information, see:
+   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
+   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
+   */
+  static const char* perm_map[32] = 
+    {/* object-specific permissions (registry keys, in this case) */
+      "QRY_VAL",       /* KEY_QUERY_VALUE */
+      "SET_VAL",       /* KEY_SET_VALUE */
+      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
+      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
+      "NOTIFY",        /* KEY_NOTIFY */
+      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
+      NULL,
+      NULL,
+      "WOW64_64",      /* KEY_WOW64_64KEY */
+      "WOW64_32",      /* KEY_WOW64_32KEY */
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      /* standard access rights */
+      "DELETE",        /* DELETE */
+      "R_CONT",        /* READ_CONTROL */
+      "W_DAC",         /* WRITE_DAC */
+      "W_OWNER",       /* WRITE_OWNER */
+      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
+      NULL,
+      NULL,
+      NULL,
+      /* other generic */
+      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
+      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
+      NULL,
+      NULL,
+      "GEN_A",         /* GENERIC_ALL */
+      "GEN_X",         /* GENERIC_EXECUTE */
+      "GEN_W",         /* GENERIC_WRITE */
+      "GEN_R",         /* GENERIC_READ */
+    };
+
+
+  if(ret_val == NULL)
+    return NULL;
+
+  r[0] = '\0';
+  for(i=0; i < 32; i++)
+  {
+    p = (1<<i);
+    if((perms & p) && (perm_map[i] != NULL))
+    {
+      strcpy(r, perm_map[i]);
+      r += strlen(perm_map[i]);
+      *(r++) = ' ';
+      perms ^= p;
+    }
+  }
+  
+  /* Any remaining unknown permission bits are added at the end in hex. */
+  if(perms != 0)
+    sprintf(r, "0x%.8X ", perms);
+
+  /* Chop off the last space if we've written anything to ret_val */
+  if(r != ret_val)
+    r[-1] = '\0';
+
+  return ret_val;
+}
+
+
+char* regfi_sid2str(DOM_SID* sid)
+{
+  uint32 i, size = MAXSUBAUTHS*11 + 24;
+  uint32 left = size;
+  uint8 comps = sid->num_auths;
+  char* ret_val = malloc(size);
+  
+  if(ret_val == NULL)
+    return NULL;
+
+  if(comps > MAXSUBAUTHS)
+    comps = MAXSUBAUTHS;
+
+  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
+
+  for (i = 0; i < comps; i++) 
+    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
+
+  return ret_val;
+}
+
+
+char* regfi_get_acl(SEC_ACL* acl)
+{
+  uint32 i, extra, size = 0;
+  const char* type_str;
+  char* flags_str;
+  char* perms_str;
+  char* sid_str;
+  char* ace_delim = "";
+  char* ret_val = NULL;
+  char* tmp_val = NULL;
+  bool failed = false;
+  char field_delim = ':';
+
+  for (i = 0; i < acl->num_aces && !failed; i++)
+  {
+    sid_str = regfi_sid2str(&acl->ace[i].trustee);
+    type_str = regfi_ace_type2str(acl->ace[i].type);
+    perms_str = regfi_ace_perms2str(acl->ace[i].info.mask);
+    flags_str = regfi_ace_flags2str(acl->ace[i].flags);
+    
+    if(flags_str != NULL && perms_str != NULL 
+       && type_str != NULL && sid_str != NULL)
+    {
+      /* XXX: this is slow */
+      extra = strlen(sid_str) + strlen(type_str) 
+	+ strlen(perms_str) + strlen(flags_str)+5;
+      tmp_val = realloc(ret_val, size+extra);
+
+      if(tmp_val == NULL)
+      {
+	free(ret_val);
+	failed = true;
+      }
+      else
+      {
+	ret_val = tmp_val;
+	size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
+			 ace_delim,sid_str,
+			 field_delim,type_str,
+			 field_delim,perms_str,
+			 field_delim,flags_str);
+	ace_delim = "|";
+      }
+    }
+    else
+      failed = true;
+
+    if(sid_str != NULL)
+      free(sid_str);
+    if(sid_str != NULL)
+      free(perms_str);
+    if(sid_str != NULL)
+      free(flags_str);
+  }
+
+  return ret_val;
+}
+
+
+char* regfi_get_sacl(SEC_DESC *sec_desc)
+{
+  if (sec_desc->sacl)
+    return regfi_get_acl(sec_desc->sacl);
+  else
+    return NULL;
+}
+
+
+char* regfi_get_dacl(SEC_DESC *sec_desc)
+{
+  if (sec_desc->dacl)
+    return regfi_get_acl(sec_desc->dacl);
+  else
+    return NULL;
+}
+
+
+char* regfi_get_owner(SEC_DESC *sec_desc)
+{
+  return regfi_sid2str(sec_desc->owner_sid);
+}
+
+
+char* regfi_get_group(SEC_DESC *sec_desc)
+{
+  return regfi_sid2str(sec_desc->grp_sid);
+}
+
+
+
+/*******************************************************************
+ *******************************************************************/
+static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
+		       uint32 block_size )
+{
+  const int hdr_size = 0x20;
+  int bytes_read, returned;
+  char *buffer;
+  SMB_STRUCT_STAT sbuf;
+
+  /* check for end of file */
+
+  if ( fstat( file->fd, &sbuf ) ) {
+    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
+    return -1;
+  }
+
+  if ( (size_t)file_offset >= sbuf.st_size )
+    return -1;
+	
+  /* if block_size == 0, we are parsnig HBIN records and need 
+     to read some of the header to get the block_size from there */
+	   
+  if ( block_size == 0 ) {
+    uint8 hdr[0x20];
+
+    if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
+      /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
+      return -1;
+    }
+
+    bytes_read = returned = 0;
+    while (bytes_read < hdr_size)
+    {
+      returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
+      if(returned == -1 && errno != EINTR && errno != EAGAIN)
+      {
+	/*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
+	return -1;
+      }
+
+      if(returned == 0)
+	return -1;
+
+      bytes_read += returned;
+    }
+
+    /* make sure this is an hbin header */
+
+    if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
+      /*DEBUG(0,("read_block: invalid block header!\n"));*/
+      return -1;
+    }
+
+    block_size = IVAL( hdr, 0x08 );
+  }
+
+  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
+
+  /* set the offset, initialize the buffer, and read the block from disk */
+
+  if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
+    /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
+    return -1;
+  }
+	
+  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
+  buffer = ps->data_p;
+  bytes_read = returned = 0;
+
+  while ( bytes_read < block_size ) 
+  {
+    returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
+    if(returned == -1 && errno != EINTR && errno != EAGAIN)
+    {
+      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
+      return -1;
+    }
+
+    if ((returned == 0) && (bytes_read < block_size)) 
+    {
+      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
+      return -1;
+    }	
+
+    bytes_read += returned;
+  }
+	
+  return bytes_read;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool prs_regf_block(const char *desc, prs_struct *ps, 
+			   int depth, REGF_FILE *file)
+{
+  depth++;
+	
+  if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
+    return false;
+	
+  /* yes, these values are always identical so store them only once */
+	
+  if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
+    return false;
+  if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
+    return false;
+
+  /* get the modtime */
+	
+  if ( !prs_set_offset( ps, 0x0c ) )
+    return false;
+  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
+    return false;
+
+  /* constants */
+	
+  if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
+    return false;
+  if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
+    return false;
+  if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
+    return false;
+  if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
+    return false;
+
+  /* get file offsets */
+	
+  if ( !prs_set_offset( ps, 0x24 ) )
+    return false;
+  if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
+    return false;
+  if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
+    return false;
+		
+  /* one more constant */
+	
+  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
+    return false;
+		
+  /* get the checksum */
+	
+  if ( !prs_set_offset( ps, 0x01fc ) )
+    return false;
+  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
+    return false;
+	
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool prs_hbin_block(const char *desc, prs_struct *ps, 
+			   int depth, REGF_HBIN *hbin)
+{
+  uint32 block_size2;
+
+  depth++;
+	
+  if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
+    return false;
+
+  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
+    return false;
+
+  /* The dosreg.cpp comments say that the block size is at 0x1c.
+     According to a WINXP NTUSER.dat file, this is wrong.  The block_size
+     is at 0x08 */
+
+  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
+    return false;
+
+  block_size2 = hbin->block_size;
+  prs_set_offset( ps, 0x1c );
+  if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
+    return false;
+
+  if ( !ps->io )
+    hbin->dirty = true;
+	
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool prs_nk_rec( const char *desc, prs_struct *ps, 
+			int depth, REGF_NK_REC *nk )
+{
+  uint16 class_length, name_length;
+  uint32 start;
+  uint32 data_size, start_off, end_off;
+  uint32 unknown_off = REGF_OFFSET_NONE;
+
+  nk->hbin_off = ps->data_offset;
+  start = nk->hbin_off;
+	
+  depth++;
+	
+  /* back up and get the data_size */	
+  if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
+    return false;
+  start_off = ps->data_offset;
+  if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
+    return false;
+	
+  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
+    return false;
+		
+  if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
+    return false;
+  if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
+    return false;
+		
+  if ( !prs_set_offset( ps, start+0x0010 ) )
+    return false;
+  if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
+    return false;
+  if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
+    return false;
+		
+  if ( !prs_set_offset( ps, start+0x001c ) )
+    return false;
+  if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
+    return false;
+  if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
+    return false;
+		
+  if ( !prs_set_offset( ps, start+0x0024 ) )
+    return false;
+  if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
+    return false;
+  if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
+    return false;
+  if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
+    return false;
+  if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
+    return false;
+
+  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
+    return false;
+  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
+		    depth, &nk->max_bytes_subkeyclassname))
+  { return false; }
+  if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
+    return false;
+  if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
+    return false;
+  if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
+    return false;
+
+  name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
+  class_length = nk->classname ? strlen(nk->classname) : 0 ;
+  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
+    return false;
+  if ( !prs_uint16( "class_length", ps, depth, &class_length ))
+    return false;	
+		
+  if ( class_length ) 
+  {
+    ;;
+  }
+	
+  if ( name_length ) 
+  {
+    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
+	return false;
+
+    if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
+      return false;
+
+    if(ps->io)
+      nk->keyname[name_length] = '\0';
+  }
+
+  end_off = ps->data_offset;
+
+  /* data_size must be divisible by 8 and large enough to hold 
+     the original record */
+
+  data_size = ((start_off - end_off) & 0xfffffff8 );
+  /*if ( data_size > nk->rec_size )
+      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
+
+  if ( !ps->io )
+    nk->hbin->dirty = true;
+  
+  nk->subkey_index = 0;
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static uint32 regf_block_checksum( prs_struct *ps )
+{
+  char *buffer = ps->data_p;
+  uint32 checksum, x;
+  int i;
+
+  /* XOR of all bytes 0x0000 - 0x01FB */
+		
+  checksum = x = 0;
+	
+  for ( i=0; i<0x01FB; i+=4 ) {
+    x = IVAL(buffer, i );
+    checksum ^= x;
+  }
+	
+  return checksum;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool read_regf_block( REGF_FILE *file )
+{
+  prs_struct ps;
+  uint32 checksum;
+	
+  /* grab the first block from the file */
+		
+  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
+    return false;
+	
+  /* parse the block and verify the checksum */
+	
+  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
+    return false;	
+		
+  checksum = regf_block_checksum( &ps );
+	
+  if(ps.is_dynamic)
+    SAFE_FREE(ps.data_p);
+  ps.is_dynamic = false;
+  ps.buffer_size = 0;
+  ps.data_offset = 0;
+
+  if ( file->checksum !=  checksum ) {
+    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
+    return false;
+  }
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
+{
+  REGF_HBIN *hbin;
+  uint32 record_size, curr_off, block_size, header;
+	
+  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
+    return NULL;
+  hbin->file_off = offset;
+  hbin->free_off = -1;
+		
+  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
+    return NULL;
+	
+  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
+    return NULL;	
+
+  /* this should be the same thing as hbin->block_size but just in case */
+
+  block_size = hbin->ps.buffer_size;
+
+  /* Find the available free space offset.  Always at the end,
+     so walk the record list and stop when you get to the end.
+     The end is defined by a record header of 0xffffffff.  The 
+     previous 4 bytes contains the amount of free space remaining 
+     in the hbin block. */
+
+  /* remember that the record_size is in the 4 bytes preceeding the record itself */
+
+  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
+    return false;
+
+  record_size = 0;
+  curr_off = hbin->ps.data_offset;
+  while ( header != 0xffffffff ) {
+    /* not done yet so reset the current offset to the 
+       next record_size field */
+
+    curr_off = curr_off+record_size;
+
+    /* for some reason the record_size of the last record in
+       an hbin block can extend past the end of the block
+       even though the record fits within the remaining 
+       space....aaarrrgggghhhhhh */
+
+    if ( curr_off >= block_size ) {
+      record_size = -1;
+      curr_off = -1;
+      break;
+    }
+
+    if ( !prs_set_offset( &hbin->ps, curr_off) )
+      return false;
+
+    if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
+      return false;
+    if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
+      return false;
+		
+    assert( record_size != 0 );
+
+    if ( record_size & 0x80000000 ) {
+      /* absolute_value(record_size) */
+      record_size = (record_size ^ 0xffffffff) + 1;
+    }
+  }
+
+  /* save the free space offset */
+
+  if ( header == 0xffffffff ) {
+
+    /* account for the fact that the curr_off is 4 bytes behind the actual 
+       record header */
+
+    hbin->free_off = curr_off + sizeof(uint32);
+    hbin->free_size = record_size;
+  }
+
+  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
+
+  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
+    return false;
+	
+  return hbin;
+}
+
+
+/*******************************************************************
+ Input a randon offset and receive the correpsonding HBIN 
+ block for it
+*******************************************************************/
+static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
+{
+  if ( !hbin )
+    return false;
+	
+  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
+    return true;
+		
+  return false;
+}
+
+
+/*******************************************************************
+ Input a randon offset and receive the correpsonding HBIN 
+ block for it
+*******************************************************************/
+static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
+{
+  REGF_HBIN *hbin = NULL;
+  uint32 block_off;
+
+  /* start with the open list */
+
+  for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
+    /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
+    if ( hbin_contains_offset( hbin, offset ) )
+      return hbin;
+  }
+	
+  if ( !hbin ) {
+    /* start at the beginning */
+
+    block_off = REGF_BLOCKSIZE;
+    do {
+      /* cleanup before the next round */
+      if ( hbin )
+      {
+	if(hbin->ps.is_dynamic)
+	  SAFE_FREE(hbin->ps.data_p);
+	hbin->ps.is_dynamic = false;
+	hbin->ps.buffer_size = 0;
+	hbin->ps.data_offset = 0;
+      }
+
+      hbin = read_hbin_block( file, block_off );
+
+      if ( hbin ) 
+	block_off = hbin->file_off + hbin->block_size;
+
+    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
+  }
+
+  if ( hbin )
+    DLIST_ADD( file->block_list, hbin );
+
+  return hbin;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
+{
+  depth++;
+
+  if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
+    return false;
+  if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
+    return false;
+	
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
+				int depth, REGF_NK_REC *nk)
+{
+  int i;
+  REGF_LF_REC *lf = &nk->subkeys;
+  uint32 data_size, start_off, end_off;
+
+  depth++;
+
+  /* check if we have anything to do first */
+	
+  if ( nk->num_subkeys == 0 )
+    return true;
+
+  /* move to the LF record */
+
+  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
+    return false;
+
+  /* backup and get the data_size */
+	
+  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
+    return false;
+  start_off = hbin->ps.data_offset;
+  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
+    return false;
+
+  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
+		 lf->header, sizeof(lf->header)))
+    return false;
+		
+  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
+    return false;
+
+  if ( hbin->ps.io ) {
+    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
+      return false;
+  }
+
+  for ( i=0; i<lf->num_keys; i++ ) {
+    if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
+      return false;
+  }
+
+  end_off = hbin->ps.data_offset;
+
+  /* data_size must be divisible by 8 and large enough to hold the original record */
+
+  data_size = ((start_off - end_off) & 0xfffffff8 );
+  /*  if ( data_size > lf->rec_size )*/
+    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
+
+  if ( !hbin->ps.io )
+    hbin->dirty = true;
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
+{
+  prs_struct *ps = &hbin->ps;
+  uint16 tag = 0xFFFF;
+  uint32 data_size, start_off, end_off;
+
+
+  depth++;
+
+  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
+    return false;
+
+  /* backup and get the data_size */
+	
+  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
+    return false;
+  start_off = hbin->ps.data_offset;
+  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
+    return false;
+
+  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
+    return false;
+  if ( !prs_uint16( "tag", ps, depth, &tag))
+    return false;
+
+  if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
+    return false;
+  if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
+    return false;
+  if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
+    return false;
+  if ( !prs_uint32( "size", ps, depth, &sk->size))
+    return false;
+
+  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
+    return false;
+
+  end_off = hbin->ps.data_offset;
+
+  /* data_size must be divisible by 8 and large enough to hold the original record */
+
+  data_size = ((start_off - end_off) & 0xfffffff8 );
+  /*  if ( data_size > sk->rec_size )*/
+    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
+
+  if ( !hbin->ps.io )
+    hbin->dirty = true;
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
+			     REGF_VK_REC *vk, REGF_FILE *file )
+{
+  uint32 offset;
+  uint16 name_length;
+  prs_struct *ps = &hbin->ps;
+  uint32 data_size, start_off, end_off;
+
+  depth++;
+
+  /* backup and get the data_size */
+	
+  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
+    return false;
+  start_off = hbin->ps.data_offset;
+  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
+    return false;
+
+  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
+    return false;
+
+  if ( !hbin->ps.io )
+    name_length = strlen(vk->valuename);
+
+  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
+    return false;
+  if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
+    return false;
+  if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
+    return false;
+  if ( !prs_uint32( "type", ps, depth, &vk->type))
+    return false;
+  if ( !prs_uint16( "flag", ps, depth, &vk->flag))
+    return false;
+
+  offset = ps->data_offset;
+  offset += 2;	/* skip 2 bytes */
+  prs_set_offset( ps, offset );
+
+  /* get the name */
+
+  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
+
+    if ( hbin->ps.io ) {
+      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
+	return false;
+    }
+    if ( !prs_uint8s(true, "name", ps, depth, 
+		     (uint8*)vk->valuename, name_length) )
+      return false;
+  }
+
+  end_off = hbin->ps.data_offset;
+
+  /* get the data if necessary */
+
+  if ( vk->data_size != 0 ) 
+  {
+    bool charmode = false;
+
+    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
+      charmode = true;
+
+    /* the data is stored in the offset if the size <= 4 */
+    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
+    {
+      REGF_HBIN *hblock = hbin;
+      uint32 data_rec_size;
+
+      if ( hbin->ps.io ) 
+      {
+	if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
+	  return false;
+      }
+
+      /* this data can be in another hbin */
+      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
+      {
+	if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
+	  return false;
+      }
+      if (!(prs_set_offset(&hblock->ps, 
+			   (vk->data_off
+			    + HBIN_HDR_SIZE
+			    - hblock->first_hbin_off)
+			   - sizeof(uint32))))
+      {	return false; }
+
+      if ( !hblock->ps.io ) 
+      {
+	data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
+	data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
+      }
+      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
+	return false;
+      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
+		     vk->data, vk->data_size))
+	return false;
+
+      if ( !hblock->ps.io )
+	hblock->dirty = true;
+    }
+    else 
+    {
+      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
+	return false;
+      SIVAL( vk->data, 0, vk->data_off );
+    }
+		
+  }
+
+  /* data_size must be divisible by 8 and large enough to hold the original record */
+
+  data_size = ((start_off - end_off ) & 0xfffffff8 );
+  /* XXX: should probably print a warning here */
+  /*if ( data_size !=  vk->rec_size )
+    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
+
+  if ( !hbin->ps.io )
+    hbin->dirty = true;
+
+  return true;
+}
+
+
+/*******************************************************************
+ read a VK record which is contained in the HBIN block stored 
+ in the prs_struct *ps.
+*******************************************************************/
+static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
+				int depth, REGF_NK_REC *nk, REGF_FILE *file)
+{
+  int i;
+  uint32 record_size;
+
+  depth++;
+	
+  /* check if we have anything to do first */
+  if(nk->num_values == 0)
+    return true;
+		
+  if(hbin->ps.io)
+  {
+    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
+					      nk->num_values )))
+      return false;
+  }
+	
+  /* convert the offset to something relative to this HBIN block */
+  if (!prs_set_offset(&hbin->ps, 
+		      nk->values_off
+		      + HBIN_HDR_SIZE
+		      - hbin->first_hbin_off
+		      - sizeof(uint32)))
+  { return false; }
+
+  if ( !hbin->ps.io ) 
+  { 
+    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
+    record_size = (record_size - 1) ^ 0xFFFFFFFF;
+  }
+
+  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
+    return false;
+		
+  for ( i=0; i<nk->num_values; i++ ) 
+  {
+    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
+      return false;
+  }
+
+  for ( i=0; i<nk->num_values; i++ ) 
+  {
+    REGF_HBIN *sub_hbin = hbin;
+    uint32 new_offset;
+	
+    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
+    {
+      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
+      if ( !sub_hbin ) 
+      {
+	/*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n", 
+	  nk->values[i].hbin_off));*/
+	return false;
+      }
+    }
+		
+    new_offset = nk->values[i].rec_off 
+      + HBIN_HDR_SIZE 
+      - sub_hbin->first_hbin_off;
+
+    if (!prs_set_offset(&sub_hbin->ps, new_offset))
+      return false;
+    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
+      return false;
+  }
+
+  if ( !hbin->ps.io )
+    hbin->dirty = true;
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
+{
+  REGF_SK_REC *p_sk;
+	
+  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
+    if ( p_sk->sk_off == offset ) 
+      return p_sk;
+  }
+	
+  return NULL;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
+{
+  REGF_SK_REC *p;
+
+  for ( p=file->sec_desc_list; p; p=p->next ) {
+    if ( sec_desc_equal( p->sec_desc, sd ) )
+      return p;
+  }
+
+  /* failure */
+
+  return NULL;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
+{
+  int depth = 0;
+  REGF_HBIN *sub_hbin;
+	
+  depth++;
+
+  /* get the initial nk record */
+  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
+    return false;
+
+  /* fill in values */
+  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
+  {
+    sub_hbin = hbin;
+    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
+    {
+      sub_hbin = lookup_hbin_block( file, nk->values_off );
+      if ( !sub_hbin ) 
+      {
+	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", 
+	  nk->values_off));*/
+	return false;
+      }
+    }
+		
+    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
+      return false;
+  }
+		
+  /* now get subkeys */
+  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
+  {
+    sub_hbin = hbin;
+    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
+    {
+      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
+      if ( !sub_hbin ) 
+      {
+	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", 
+	  nk->subkeys_off));*/
+	return false;
+      }
+    }
+		
+    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
+      return false;
+  }
+
+  /* get the to the security descriptor.  First look if we have already parsed it */
+	
+  if ((nk->sk_off!=REGF_OFFSET_NONE) 
+      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
+  {
+    sub_hbin = hbin;
+    if (!hbin_contains_offset(hbin, nk->sk_off))
+    {
+      sub_hbin = lookup_hbin_block( file, nk->sk_off );
+      if ( !sub_hbin ) {
+	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", 
+	  nk->subkeys_off));*/
+	return false;
+      }
+    }
+		
+    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
+      return false;
+    nk->sec_desc->sk_off = nk->sk_off;
+    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
+      return false;
+			
+    /* add to the list of security descriptors (ref_count has been read from the files) */
+
+    nk->sec_desc->sk_off = nk->sk_off;
+    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
+  }
+		
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
+{
+  uint8 header[REC_HDR_SIZE] = "";
+  uint32 record_size;
+  uint32 curr_off, block_size;
+  bool found = false;
+  prs_struct *ps = &hbin->ps;
+	
+  curr_off = ps->data_offset;
+  if ( curr_off == 0 )
+    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
+
+  /* assume that the current offset is at the reacord header 
+     and we need to backup to read the record size */
+  curr_off -= sizeof(uint32);
+
+  block_size = ps->buffer_size;
+  record_size = 0;
+  while ( !found ) 
+  {
+    curr_off = curr_off+record_size;
+    if ( curr_off >= block_size ) 
+      break;
+
+    if ( !prs_set_offset( &hbin->ps, curr_off) )
+      return false;
+
+    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
+      return false;
+    if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
+      return false;
+
+    if ( record_size & 0x80000000 ) {
+      /* absolute_value(record_size) */
+      record_size = (record_size ^ 0xffffffff) + 1;
+    }
+
+    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
+      found = true;
+      curr_off += sizeof(uint32);
+    }
+  } 
+
+  /* mark prs_struct as done ( at end ) if no more SK records */
+  /* mark end-of-block as true */	
+  if ( !found )
+  {
+    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
+    *eob = true;
+    return false;
+  }
+
+  if (!prs_set_offset(ps, curr_off))
+    return false;
+
+  return true;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
+			   REGF_NK_REC *nk, bool *eob)
+{
+  if (next_record(hbin, "nk", eob) 
+      && hbin_prs_key(file, hbin, nk))
+    return true;
+	
+  return false;
+}
+
+
+/*******************************************************************
+ Open the registry file and then read in the REGF block to get the 
+ first hbin offset.
+*******************************************************************/
+REGF_FILE* regfi_open( const char *filename )
+{
+  REGF_FILE *rb;
+  int flags = O_RDONLY;
+
+  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
+    /* DEBUG(0,("ERROR allocating memory\n")); */
+    return NULL;
+  }
+  memset(rb, 0, sizeof(REGF_FILE));
+  rb->fd = -1;
+	
+  /*	if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) 
+    {
+    regfi_close( rb );
+    return NULL;
+    }
+  */
+  rb->open_flags = flags;
+	
+  /* open and existing file */
+
+  if ( (rb->fd = open(filename, flags)) == -1 ) {
+    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
+    regfi_close( rb );
+    return NULL;
+  }
+	
+  /* read in an existing file */
+	
+  if ( !read_regf_block( rb ) ) {
+    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
+    regfi_close( rb );
+    return NULL;
+  }
+	
+  /* success */
+	
+  return rb;
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+static void regfi_mem_free( REGF_FILE *file )
+{
+  /* free any zalloc()'d memory */
+	
+  /*	if ( file && file->mem_ctx )
+    free(file->mem_ctx);
+  */
+}
+
+
+/*******************************************************************
+ *******************************************************************/
+int regfi_close( REGF_FILE *file )
+{
+  int fd;
+
+  regfi_mem_free( file );
+
+  /* nothing to do if there is no open file */
+
+  if ( !file || (file->fd == -1) )
+    return 0;
+		
+  fd = file->fd;
+  file->fd = -1;
+  SAFE_FREE( file );
+
+  return close( fd );
+}
+
+
+/*******************************************************************
+ There should be only *one* root key in the registry file based 
+ on my experience.  --jerry
+*******************************************************************/
+REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
+{
+  REGF_NK_REC *nk;
+  REGF_HBIN   *hbin;
+  uint32      offset = REGF_BLOCKSIZE;
+  bool        found = false;
+  bool        eob;
+	
+  if ( !file )
+    return NULL;
+		
+  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
+    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
+    return NULL;
+  }
+	
+  /* scan through the file on 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) */
+	
+  while ( (hbin = read_hbin_block( file, offset )) ) {
+    eob = false;
+
+    while ( !eob) {
+      if ( next_nk_record( file, hbin, nk, &eob ) ) {
+	if ( nk->key_type == NK_TYPE_ROOTKEY ) {
+	  found = true;
+	  break;
+	}
+      }
+      if(hbin->ps.is_dynamic)
+	SAFE_FREE(hbin->ps.data_p);
+      hbin->ps.is_dynamic = false;
+      hbin->ps.buffer_size = 0;
+      hbin->ps.data_offset = 0;
+    }
+		
+    if ( found ) 
+      break;
+
+    offset += hbin->block_size;
+  }
+	
+  if ( !found ) {
+    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
+    return NULL;
+  }
+
+  DLIST_ADD( file->block_list, hbin );
+
+  return nk;		
+}
+
+
+/* XXX: An interator struct should be used instead, and this function
+ *   should operate on it, so the state of iteration isn't stored in the
+ * REGF_NK_REC struct itself.
+ */
+/*******************************************************************
+ This acts as an interator over the subkeys defined for a given 
+ NK record.  Remember that offsets are from the *first* HBIN block.
+*******************************************************************/
+REGF_NK_REC* regfi_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
+{
+  REGF_NK_REC *subkey;
+  REGF_HBIN   *hbin;
+  uint32      nk_offset;
+
+  /* see if there is anything left to report */
+  if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE) 
+      || (nk->subkey_index >= nk->num_subkeys))
+    return NULL;
+
+  /* find the HBIN block which should contain the nk record */
+  if(!(hbin 
+       = lookup_hbin_block(file, nk->subkeys.hashes[nk->subkey_index].nk_off )))
+  {
+    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 
+      nk->subkeys.hashes[nk->subkey_index].nk_off));*/
+    return NULL;
+  }
+  
+  nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
+  if(!prs_set_offset(&hbin->ps, 
+		     (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
+    return NULL;
+		
+  nk->subkey_index++;
+  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
+    return NULL;
+
+  if(!hbin_prs_key(file, hbin, subkey))
+    return NULL;
+
+  return subkey;
+}
Index: unk/lib/regfio.c
===================================================================
--- /trunk/lib/regfio.c	(revision 78)
+++ 	(revision )
@@ -1,1545 +1,0 @@
-/*
- * Branched from Samba project Subversion repository, version #7470:
- *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
- *
- * Unix SMB/CIFS implementation.
- * Windows NT registry I/O library
- *
- * Copyright (C) 2005-2006 Timothy D. Morgan
- * Copyright (C) 2005 Gerald (Jerry) Carter
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
- *
- * $Id$
- */
-
-#include "../include/regfio.h"
-
-
-/* Registry types mapping */
-const unsigned int regfi_num_reg_types = 12;
-static const char* regfi_type_names[] =
-  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
-   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
-
-
-/* Returns NULL on error */
-const char* regfi_type_val2str(unsigned int val)
-{
-  if(val == REG_KEY)
-    return "KEY";
-  
-  if(val >= regfi_num_reg_types)
-    return NULL;
-  
-  return regfi_type_names[val];
-}
-
-
-/* Returns -1 on error */
-int regfi_type_str2val(const char* str)
-{
-  int i;
-
-  if(strcmp("KEY", str) == 0)
-    return REG_KEY;
-
-  for(i=0; i < regfi_num_reg_types; i++)
-    if (strcmp(regfi_type_names[i], str) == 0) 
-      return i;
-
-  if(strcmp("DWORD_LE", str) == 0)
-    return REG_DWORD_LE;
-
-  return -1;
-}
-
-
-/* Security descriptor parsing functions  */
-
-const char* regfi_ace_type2str(uint8 type)
-{
-  static const char* map[7] 
-    = {"ALLOW", "DENY", "AUDIT", "ALARM", 
-       "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
-  if(type < 7)
-    return map[type];
-  else
-    /* XXX: would be nice to return the unknown integer value.  
-     *      However, as it is a const string, it can't be free()ed later on, 
-     *      so that would need to change. 
-     */
-    return "UNKNOWN";
-}
-
-
-/* XXX: need a better reference on the meaning of each flag. */
-/* For more info, see:
- *   http://msdn2.microsoft.com/en-us/library/aa772242.aspx
- */
-char* regfi_ace_flags2str(uint8 flags)
-{
-  static const char* flag_map[32] = 
-    { "OI",
-      "CI",
-      "NP",
-      "IO",
-      "IA",
-      NULL,
-      NULL,
-      NULL,
-    };
-
-  char* ret_val = malloc(35*sizeof(char));
-  char* fo = ret_val;
-  uint32 i;
-  uint8 f;
-
-  if(ret_val == NULL)
-    return NULL;
-
-  fo[0] = '\0';
-  if (!flags)
-    return ret_val;
-
-  for(i=0; i < 8; i++)
-  {
-    f = (1<<i);
-    if((flags & f) && (flag_map[i] != NULL))
-    {
-      strcpy(fo, flag_map[i]);
-      fo += strlen(flag_map[i]);
-      *(fo++) = ' ';
-      flags ^= f;
-    }
-  }
-  
-  /* Any remaining unknown flags are added at the end in hex. */
-  if(flags != 0)
-    sprintf(fo, "0x%.2X ", flags);
-
-  /* Chop off the last space if we've written anything to ret_val */
-  if(fo != ret_val)
-    fo[-1] = '\0';
-
-  /* XXX: what was this old VI flag for??
-     XXX: Is this check right?  0xF == 1|2|4|8, which makes it redundant...
-  if (flags == 0xF) {
-    if (some) strcat(flg_output, " ");
-    some = 1;
-    strcat(flg_output, "VI");
-  }
-  */
-
-  return ret_val;
-}
-
-
-char* regfi_ace_perms2str(uint32 perms)
-{
-  uint32 i, p;
-  /* This is more than is needed by a fair margin. */
-  char* ret_val = malloc(350*sizeof(char));
-  char* r = ret_val;
-
-  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
-   * For more information, see:
-   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
-   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
-   */
-  static const char* perm_map[32] = 
-    {/* object-specific permissions (registry keys, in this case) */
-      "QRY_VAL",       /* KEY_QUERY_VALUE */
-      "SET_VAL",       /* KEY_SET_VALUE */
-      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
-      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
-      "NOTIFY",        /* KEY_NOTIFY */
-      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
-      NULL,
-      NULL,
-      "WOW64_64",      /* KEY_WOW64_64KEY */
-      "WOW64_32",      /* KEY_WOW64_32KEY */
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      /* standard access rights */
-      "DELETE",        /* DELETE */
-      "R_CONT",        /* READ_CONTROL */
-      "W_DAC",         /* WRITE_DAC */
-      "W_OWNER",       /* WRITE_OWNER */
-      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
-      NULL,
-      NULL,
-      NULL,
-      /* other generic */
-      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
-      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
-      NULL,
-      NULL,
-      "GEN_A",         /* GENERIC_ALL */
-      "GEN_X",         /* GENERIC_EXECUTE */
-      "GEN_W",         /* GENERIC_WRITE */
-      "GEN_R",         /* GENERIC_READ */
-    };
-
-
-  if(ret_val == NULL)
-    return NULL;
-
-  r[0] = '\0';
-  for(i=0; i < 32; i++)
-  {
-    p = (1<<i);
-    if((perms & p) && (perm_map[i] != NULL))
-    {
-      strcpy(r, perm_map[i]);
-      r += strlen(perm_map[i]);
-      *(r++) = ' ';
-      perms ^= p;
-    }
-  }
-  
-  /* Any remaining unknown permission bits are added at the end in hex. */
-  if(perms != 0)
-    sprintf(r, "0x%.8X ", perms);
-
-  /* Chop off the last space if we've written anything to ret_val */
-  if(r != ret_val)
-    r[-1] = '\0';
-
-  return ret_val;
-}
-
-
-char* regfi_sid2str(DOM_SID* sid)
-{
-  uint32 i, size = MAXSUBAUTHS*11 + 24;
-  uint32 left = size;
-  uint8 comps = sid->num_auths;
-  char* ret_val = malloc(size);
-  
-  if(ret_val == NULL)
-    return NULL;
-
-  if(comps > MAXSUBAUTHS)
-    comps = MAXSUBAUTHS;
-
-  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
-
-  for (i = 0; i < comps; i++) 
-    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
-
-  return ret_val;
-}
-
-
-char* regfi_get_acl(SEC_ACL* acl)
-{
-  uint32 i, extra, size = 0;
-  const char* type_str;
-  char* flags_str;
-  char* perms_str;
-  char* sid_str;
-  char* ace_delim = "";
-  char* ret_val = NULL;
-  char* tmp_val = NULL;
-  bool failed = false;
-  char field_delim = ':';
-
-  for (i = 0; i < acl->num_aces && !failed; i++)
-  {
-    sid_str = regfi_sid2str(&acl->ace[i].trustee);
-    type_str = regfi_ace_type2str(acl->ace[i].type);
-    perms_str = regfi_ace_perms2str(acl->ace[i].info.mask);
-    flags_str = regfi_ace_flags2str(acl->ace[i].flags);
-    
-    if(flags_str != NULL && perms_str != NULL 
-       && type_str != NULL && sid_str != NULL)
-    {
-      /* XXX: this is slow */
-      extra = strlen(sid_str) + strlen(type_str) 
-	+ strlen(perms_str) + strlen(flags_str)+5;
-      tmp_val = realloc(ret_val, size+extra);
-
-      if(tmp_val == NULL)
-      {
-	free(ret_val);
-	failed = true;
-      }
-      else
-      {
-	ret_val = tmp_val;
-	size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
-			 ace_delim,sid_str,
-			 field_delim,type_str,
-			 field_delim,perms_str,
-			 field_delim,flags_str);
-	ace_delim = "|";
-      }
-    }
-    else
-      failed = true;
-
-    if(sid_str != NULL)
-      free(sid_str);
-    if(sid_str != NULL)
-      free(perms_str);
-    if(sid_str != NULL)
-      free(flags_str);
-  }
-
-  return ret_val;
-}
-
-
-char* regfi_get_sacl(SEC_DESC *sec_desc)
-{
-  if (sec_desc->sacl)
-    return regfi_get_acl(sec_desc->sacl);
-  else
-    return NULL;
-}
-
-
-char* regfi_get_dacl(SEC_DESC *sec_desc)
-{
-  if (sec_desc->dacl)
-    return regfi_get_acl(sec_desc->dacl);
-  else
-    return NULL;
-}
-
-
-char* regfi_get_owner(SEC_DESC *sec_desc)
-{
-  return regfi_sid2str(sec_desc->owner_sid);
-}
-
-
-char* regfi_get_group(SEC_DESC *sec_desc)
-{
-  return regfi_sid2str(sec_desc->grp_sid);
-}
-
-
-
-/*******************************************************************
- *******************************************************************/
-static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
-		       uint32 block_size )
-{
-  const int hdr_size = 0x20;
-  int bytes_read, returned;
-  char *buffer;
-  SMB_STRUCT_STAT sbuf;
-
-  /* check for end of file */
-
-  if ( fstat( file->fd, &sbuf ) ) {
-    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
-    return -1;
-  }
-
-  if ( (size_t)file_offset >= sbuf.st_size )
-    return -1;
-	
-  /* if block_size == 0, we are parsnig HBIN records and need 
-     to read some of the header to get the block_size from there */
-	   
-  if ( block_size == 0 ) {
-    uint8 hdr[0x20];
-
-    if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
-      /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
-      return -1;
-    }
-
-    bytes_read = returned = 0;
-    while (bytes_read < hdr_size)
-    {
-      returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
-      if(returned == -1 && errno != EINTR && errno != EAGAIN)
-      {
-	/*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
-	return -1;
-      }
-
-      if(returned == 0)
-	return -1;
-
-      bytes_read += returned;
-    }
-
-    /* make sure this is an hbin header */
-
-    if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
-      /*DEBUG(0,("read_block: invalid block header!\n"));*/
-      return -1;
-    }
-
-    block_size = IVAL( hdr, 0x08 );
-  }
-
-  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
-
-  /* set the offset, initialize the buffer, and read the block from disk */
-
-  if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
-    /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
-    return -1;
-  }
-	
-  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
-  buffer = ps->data_p;
-  bytes_read = returned = 0;
-
-  while ( bytes_read < block_size ) 
-  {
-    returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
-    if(returned == -1 && errno != EINTR && errno != EAGAIN)
-    {
-      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
-      return -1;
-    }
-
-    if ((returned == 0) && (bytes_read < block_size)) 
-    {
-      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
-      return -1;
-    }	
-
-    bytes_read += returned;
-  }
-	
-  return bytes_read;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool prs_regf_block(const char *desc, prs_struct *ps, 
-			   int depth, REGF_FILE *file)
-{
-  depth++;
-	
-  if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
-    return false;
-	
-  /* yes, these values are always identical so store them only once */
-	
-  if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
-    return false;
-  if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
-    return false;
-
-  /* get the modtime */
-	
-  if ( !prs_set_offset( ps, 0x0c ) )
-    return false;
-  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
-    return false;
-
-  /* constants */
-	
-  if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
-    return false;
-  if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
-    return false;
-  if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
-    return false;
-  if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
-    return false;
-
-  /* get file offsets */
-	
-  if ( !prs_set_offset( ps, 0x24 ) )
-    return false;
-  if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
-    return false;
-  if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
-    return false;
-		
-  /* one more constant */
-	
-  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
-    return false;
-		
-  /* get the checksum */
-	
-  if ( !prs_set_offset( ps, 0x01fc ) )
-    return false;
-  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
-    return false;
-	
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool prs_hbin_block(const char *desc, prs_struct *ps, 
-			   int depth, REGF_HBIN *hbin)
-{
-  uint32 block_size2;
-
-  depth++;
-	
-  if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
-    return false;
-
-  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
-    return false;
-
-  /* The dosreg.cpp comments say that the block size is at 0x1c.
-     According to a WINXP NTUSER.dat file, this is wrong.  The block_size
-     is at 0x08 */
-
-  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
-    return false;
-
-  block_size2 = hbin->block_size;
-  prs_set_offset( ps, 0x1c );
-  if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
-    return false;
-
-  if ( !ps->io )
-    hbin->dirty = true;
-	
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool prs_nk_rec( const char *desc, prs_struct *ps, 
-			int depth, REGF_NK_REC *nk )
-{
-  uint16 class_length, name_length;
-  uint32 start;
-  uint32 data_size, start_off, end_off;
-  uint32 unknown_off = REGF_OFFSET_NONE;
-
-  nk->hbin_off = ps->data_offset;
-  start = nk->hbin_off;
-	
-  depth++;
-	
-  /* back up and get the data_size */	
-  if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
-    return false;
-  start_off = ps->data_offset;
-  if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
-    return false;
-	
-  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
-    return false;
-		
-  if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
-    return false;
-  if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
-    return false;
-		
-  if ( !prs_set_offset( ps, start+0x0010 ) )
-    return false;
-  if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
-    return false;
-  if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
-    return false;
-		
-  if ( !prs_set_offset( ps, start+0x001c ) )
-    return false;
-  if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
-    return false;
-  if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
-    return false;
-		
-  if ( !prs_set_offset( ps, start+0x0024 ) )
-    return false;
-  if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
-    return false;
-  if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
-    return false;
-  if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
-    return false;
-  if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
-    return false;
-
-  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
-    return false;
-  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
-		    depth, &nk->max_bytes_subkeyclassname))
-  { return false; }
-  if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
-    return false;
-  if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
-    return false;
-  if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
-    return false;
-
-  name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
-  class_length = nk->classname ? strlen(nk->classname) : 0 ;
-  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
-    return false;
-  if ( !prs_uint16( "class_length", ps, depth, &class_length ))
-    return false;	
-		
-  if ( class_length ) 
-  {
-    ;;
-  }
-	
-  if ( name_length ) 
-  {
-    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
-	return false;
-
-    if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
-      return false;
-
-    if(ps->io)
-      nk->keyname[name_length] = '\0';
-  }
-
-  end_off = ps->data_offset;
-
-  /* data_size must be divisible by 8 and large enough to hold 
-     the original record */
-
-  data_size = ((start_off - end_off) & 0xfffffff8 );
-  /*if ( data_size > nk->rec_size )
-      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
-
-  if ( !ps->io )
-    nk->hbin->dirty = true;
-  
-  nk->subkey_index = 0;
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static uint32 regf_block_checksum( prs_struct *ps )
-{
-  char *buffer = ps->data_p;
-  uint32 checksum, x;
-  int i;
-
-  /* XOR of all bytes 0x0000 - 0x01FB */
-		
-  checksum = x = 0;
-	
-  for ( i=0; i<0x01FB; i+=4 ) {
-    x = IVAL(buffer, i );
-    checksum ^= x;
-  }
-	
-  return checksum;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool read_regf_block( REGF_FILE *file )
-{
-  prs_struct ps;
-  uint32 checksum;
-	
-  /* grab the first block from the file */
-		
-  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
-    return false;
-	
-  /* parse the block and verify the checksum */
-	
-  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
-    return false;	
-		
-  checksum = regf_block_checksum( &ps );
-	
-  if(ps.is_dynamic)
-    SAFE_FREE(ps.data_p);
-  ps.is_dynamic = false;
-  ps.buffer_size = 0;
-  ps.data_offset = 0;
-
-  if ( file->checksum !=  checksum ) {
-    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
-    return false;
-  }
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
-{
-  REGF_HBIN *hbin;
-  uint32 record_size, curr_off, block_size, header;
-	
-  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
-    return NULL;
-  hbin->file_off = offset;
-  hbin->free_off = -1;
-		
-  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
-    return NULL;
-	
-  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
-    return NULL;	
-
-  /* this should be the same thing as hbin->block_size but just in case */
-
-  block_size = hbin->ps.buffer_size;
-
-  /* Find the available free space offset.  Always at the end,
-     so walk the record list and stop when you get to the end.
-     The end is defined by a record header of 0xffffffff.  The 
-     previous 4 bytes contains the amount of free space remaining 
-     in the hbin block. */
-
-  /* remember that the record_size is in the 4 bytes preceeding the record itself */
-
-  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
-    return false;
-
-  record_size = 0;
-  curr_off = hbin->ps.data_offset;
-  while ( header != 0xffffffff ) {
-    /* not done yet so reset the current offset to the 
-       next record_size field */
-
-    curr_off = curr_off+record_size;
-
-    /* for some reason the record_size of the last record in
-       an hbin block can extend past the end of the block
-       even though the record fits within the remaining 
-       space....aaarrrgggghhhhhh */
-
-    if ( curr_off >= block_size ) {
-      record_size = -1;
-      curr_off = -1;
-      break;
-    }
-
-    if ( !prs_set_offset( &hbin->ps, curr_off) )
-      return false;
-
-    if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
-      return false;
-    if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
-      return false;
-		
-    assert( record_size != 0 );
-
-    if ( record_size & 0x80000000 ) {
-      /* absolute_value(record_size) */
-      record_size = (record_size ^ 0xffffffff) + 1;
-    }
-  }
-
-  /* save the free space offset */
-
-  if ( header == 0xffffffff ) {
-
-    /* account for the fact that the curr_off is 4 bytes behind the actual 
-       record header */
-
-    hbin->free_off = curr_off + sizeof(uint32);
-    hbin->free_size = record_size;
-  }
-
-  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
-
-  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
-    return false;
-	
-  return hbin;
-}
-
-
-/*******************************************************************
- Input a randon offset and receive the correpsonding HBIN 
- block for it
-*******************************************************************/
-static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
-{
-  if ( !hbin )
-    return false;
-	
-  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
-    return true;
-		
-  return false;
-}
-
-
-/*******************************************************************
- Input a randon offset and receive the correpsonding HBIN 
- block for it
-*******************************************************************/
-static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
-{
-  REGF_HBIN *hbin = NULL;
-  uint32 block_off;
-
-  /* start with the open list */
-
-  for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
-    /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
-    if ( hbin_contains_offset( hbin, offset ) )
-      return hbin;
-  }
-	
-  if ( !hbin ) {
-    /* start at the beginning */
-
-    block_off = REGF_BLOCKSIZE;
-    do {
-      /* cleanup before the next round */
-      if ( hbin )
-      {
-	if(hbin->ps.is_dynamic)
-	  SAFE_FREE(hbin->ps.data_p);
-	hbin->ps.is_dynamic = false;
-	hbin->ps.buffer_size = 0;
-	hbin->ps.data_offset = 0;
-      }
-
-      hbin = read_hbin_block( file, block_off );
-
-      if ( hbin ) 
-	block_off = hbin->file_off + hbin->block_size;
-
-    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
-  }
-
-  if ( hbin )
-    DLIST_ADD( file->block_list, hbin );
-
-  return hbin;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
-{
-  depth++;
-
-  if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
-    return false;
-  if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
-    return false;
-	
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
-				int depth, REGF_NK_REC *nk)
-{
-  int i;
-  REGF_LF_REC *lf = &nk->subkeys;
-  uint32 data_size, start_off, end_off;
-
-  depth++;
-
-  /* check if we have anything to do first */
-	
-  if ( nk->num_subkeys == 0 )
-    return true;
-
-  /* move to the LF record */
-
-  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
-    return false;
-
-  /* backup and get the data_size */
-	
-  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
-    return false;
-  start_off = hbin->ps.data_offset;
-  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
-    return false;
-
-  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
-		 lf->header, sizeof(lf->header)))
-    return false;
-		
-  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
-    return false;
-
-  if ( hbin->ps.io ) {
-    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
-      return false;
-  }
-
-  for ( i=0; i<lf->num_keys; i++ ) {
-    if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
-      return false;
-  }
-
-  end_off = hbin->ps.data_offset;
-
-  /* data_size must be divisible by 8 and large enough to hold the original record */
-
-  data_size = ((start_off - end_off) & 0xfffffff8 );
-  /*  if ( data_size > lf->rec_size )*/
-    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
-
-  if ( !hbin->ps.io )
-    hbin->dirty = true;
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
-{
-  prs_struct *ps = &hbin->ps;
-  uint16 tag = 0xFFFF;
-  uint32 data_size, start_off, end_off;
-
-
-  depth++;
-
-  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
-    return false;
-
-  /* backup and get the data_size */
-	
-  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
-    return false;
-  start_off = hbin->ps.data_offset;
-  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
-    return false;
-
-  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
-    return false;
-  if ( !prs_uint16( "tag", ps, depth, &tag))
-    return false;
-
-  if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
-    return false;
-  if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
-    return false;
-  if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
-    return false;
-  if ( !prs_uint32( "size", ps, depth, &sk->size))
-    return false;
-
-  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
-    return false;
-
-  end_off = hbin->ps.data_offset;
-
-  /* data_size must be divisible by 8 and large enough to hold the original record */
-
-  data_size = ((start_off - end_off) & 0xfffffff8 );
-  /*  if ( data_size > sk->rec_size )*/
-    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
-
-  if ( !hbin->ps.io )
-    hbin->dirty = true;
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
-			     REGF_VK_REC *vk, REGF_FILE *file )
-{
-  uint32 offset;
-  uint16 name_length;
-  prs_struct *ps = &hbin->ps;
-  uint32 data_size, start_off, end_off;
-
-  depth++;
-
-  /* backup and get the data_size */
-	
-  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
-    return false;
-  start_off = hbin->ps.data_offset;
-  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
-    return false;
-
-  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
-    return false;
-
-  if ( !hbin->ps.io )
-    name_length = strlen(vk->valuename);
-
-  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
-    return false;
-  if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
-    return false;
-  if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
-    return false;
-  if ( !prs_uint32( "type", ps, depth, &vk->type))
-    return false;
-  if ( !prs_uint16( "flag", ps, depth, &vk->flag))
-    return false;
-
-  offset = ps->data_offset;
-  offset += 2;	/* skip 2 bytes */
-  prs_set_offset( ps, offset );
-
-  /* get the name */
-
-  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
-
-    if ( hbin->ps.io ) {
-      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
-	return false;
-    }
-    if ( !prs_uint8s(true, "name", ps, depth, 
-		     (uint8*)vk->valuename, name_length) )
-      return false;
-  }
-
-  end_off = hbin->ps.data_offset;
-
-  /* get the data if necessary */
-
-  if ( vk->data_size != 0 ) 
-  {
-    bool charmode = false;
-
-    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
-      charmode = true;
-
-    /* the data is stored in the offset if the size <= 4 */
-    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
-    {
-      REGF_HBIN *hblock = hbin;
-      uint32 data_rec_size;
-
-      if ( hbin->ps.io ) 
-      {
-	if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
-	  return false;
-      }
-
-      /* this data can be in another hbin */
-      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
-      {
-	if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
-	  return false;
-      }
-      if (!(prs_set_offset(&hblock->ps, 
-			   (vk->data_off
-			    + HBIN_HDR_SIZE
-			    - hblock->first_hbin_off)
-			   - sizeof(uint32))))
-      {	return false; }
-
-      if ( !hblock->ps.io ) 
-      {
-	data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
-	data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
-      }
-      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
-	return false;
-      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
-		     vk->data, vk->data_size))
-	return false;
-
-      if ( !hblock->ps.io )
-	hblock->dirty = true;
-    }
-    else 
-    {
-      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
-	return false;
-      SIVAL( vk->data, 0, vk->data_off );
-    }
-		
-  }
-
-  /* data_size must be divisible by 8 and large enough to hold the original record */
-
-  data_size = ((start_off - end_off ) & 0xfffffff8 );
-  /* XXX: should probably print a warning here */
-  /*if ( data_size !=  vk->rec_size )
-    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
-
-  if ( !hbin->ps.io )
-    hbin->dirty = true;
-
-  return true;
-}
-
-
-/*******************************************************************
- read a VK record which is contained in the HBIN block stored 
- in the prs_struct *ps.
-*******************************************************************/
-static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
-				int depth, REGF_NK_REC *nk, REGF_FILE *file)
-{
-  int i;
-  uint32 record_size;
-
-  depth++;
-	
-  /* check if we have anything to do first */
-  if(nk->num_values == 0)
-    return true;
-		
-  if(hbin->ps.io)
-  {
-    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
-					      nk->num_values )))
-      return false;
-  }
-	
-  /* convert the offset to something relative to this HBIN block */
-  if (!prs_set_offset(&hbin->ps, 
-		      nk->values_off
-		      + HBIN_HDR_SIZE
-		      - hbin->first_hbin_off
-		      - sizeof(uint32)))
-  { return false; }
-
-  if ( !hbin->ps.io ) 
-  { 
-    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
-    record_size = (record_size - 1) ^ 0xFFFFFFFF;
-  }
-
-  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
-    return false;
-		
-  for ( i=0; i<nk->num_values; i++ ) 
-  {
-    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
-      return false;
-  }
-
-  for ( i=0; i<nk->num_values; i++ ) 
-  {
-    REGF_HBIN *sub_hbin = hbin;
-    uint32 new_offset;
-	
-    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
-    {
-      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
-      if ( !sub_hbin ) 
-      {
-	/*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n", 
-	  nk->values[i].hbin_off));*/
-	return false;
-      }
-    }
-		
-    new_offset = nk->values[i].rec_off 
-      + HBIN_HDR_SIZE 
-      - sub_hbin->first_hbin_off;
-
-    if (!prs_set_offset(&sub_hbin->ps, new_offset))
-      return false;
-    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
-      return false;
-  }
-
-  if ( !hbin->ps.io )
-    hbin->dirty = true;
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
-{
-  REGF_SK_REC *p_sk;
-	
-  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
-    if ( p_sk->sk_off == offset ) 
-      return p_sk;
-  }
-	
-  return NULL;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
-{
-  REGF_SK_REC *p;
-
-  for ( p=file->sec_desc_list; p; p=p->next ) {
-    if ( sec_desc_equal( p->sec_desc, sd ) )
-      return p;
-  }
-
-  /* failure */
-
-  return NULL;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
-{
-  int depth = 0;
-  REGF_HBIN *sub_hbin;
-	
-  depth++;
-
-  /* get the initial nk record */
-  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
-    return false;
-
-  /* fill in values */
-  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
-  {
-    sub_hbin = hbin;
-    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
-    {
-      sub_hbin = lookup_hbin_block( file, nk->values_off );
-      if ( !sub_hbin ) 
-      {
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", 
-	  nk->values_off));*/
-	return false;
-      }
-    }
-		
-    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
-      return false;
-  }
-		
-  /* now get subkeys */
-  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
-  {
-    sub_hbin = hbin;
-    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
-    {
-      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
-      if ( !sub_hbin ) 
-      {
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", 
-	  nk->subkeys_off));*/
-	return false;
-      }
-    }
-		
-    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
-      return false;
-  }
-
-  /* get the to the security descriptor.  First look if we have already parsed it */
-	
-  if ((nk->sk_off!=REGF_OFFSET_NONE) 
-      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
-  {
-    sub_hbin = hbin;
-    if (!hbin_contains_offset(hbin, nk->sk_off))
-    {
-      sub_hbin = lookup_hbin_block( file, nk->sk_off );
-      if ( !sub_hbin ) {
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", 
-	  nk->subkeys_off));*/
-	return false;
-      }
-    }
-		
-    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
-      return false;
-    nk->sec_desc->sk_off = nk->sk_off;
-    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
-      return false;
-			
-    /* add to the list of security descriptors (ref_count has been read from the files) */
-
-    nk->sec_desc->sk_off = nk->sk_off;
-    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
-  }
-		
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
-{
-  uint8 header[REC_HDR_SIZE] = "";
-  uint32 record_size;
-  uint32 curr_off, block_size;
-  bool found = false;
-  prs_struct *ps = &hbin->ps;
-	
-  curr_off = ps->data_offset;
-  if ( curr_off == 0 )
-    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
-
-  /* assume that the current offset is at the reacord header 
-     and we need to backup to read the record size */
-  curr_off -= sizeof(uint32);
-
-  block_size = ps->buffer_size;
-  record_size = 0;
-  while ( !found ) 
-  {
-    curr_off = curr_off+record_size;
-    if ( curr_off >= block_size ) 
-      break;
-
-    if ( !prs_set_offset( &hbin->ps, curr_off) )
-      return false;
-
-    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
-      return false;
-    if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
-      return false;
-
-    if ( record_size & 0x80000000 ) {
-      /* absolute_value(record_size) */
-      record_size = (record_size ^ 0xffffffff) + 1;
-    }
-
-    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
-      found = true;
-      curr_off += sizeof(uint32);
-    }
-  } 
-
-  /* mark prs_struct as done ( at end ) if no more SK records */
-  /* mark end-of-block as true */	
-  if ( !found )
-  {
-    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
-    *eob = true;
-    return false;
-  }
-
-  if (!prs_set_offset(ps, curr_off))
-    return false;
-
-  return true;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
-			   REGF_NK_REC *nk, bool *eob)
-{
-  if (next_record(hbin, "nk", eob) 
-      && hbin_prs_key(file, hbin, nk))
-    return true;
-	
-  return false;
-}
-
-
-/*******************************************************************
- Open the registry file and then read in the REGF block to get the 
- first hbin offset.
-*******************************************************************/
-REGF_FILE* regfi_open( const char *filename )
-{
-  REGF_FILE *rb;
-  int flags = O_RDONLY;
-
-  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
-    /* DEBUG(0,("ERROR allocating memory\n")); */
-    return NULL;
-  }
-  memset(rb, 0, sizeof(REGF_FILE));
-  rb->fd = -1;
-	
-  /*	if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) 
-    {
-    regfi_close( rb );
-    return NULL;
-    }
-  */
-  rb->open_flags = flags;
-	
-  /* open and existing file */
-
-  if ( (rb->fd = open(filename, flags)) == -1 ) {
-    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
-    regfi_close( rb );
-    return NULL;
-  }
-	
-  /* read in an existing file */
-	
-  if ( !read_regf_block( rb ) ) {
-    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
-    regfi_close( rb );
-    return NULL;
-  }
-	
-  /* success */
-	
-  return rb;
-}
-
-
-/*******************************************************************
- *******************************************************************/
-static void regfi_mem_free( REGF_FILE *file )
-{
-  /* free any zalloc()'d memory */
-	
-  /*	if ( file && file->mem_ctx )
-    free(file->mem_ctx);
-  */
-}
-
-
-/*******************************************************************
- *******************************************************************/
-int regfi_close( REGF_FILE *file )
-{
-  int fd;
-
-  regfi_mem_free( file );
-
-  /* nothing to do if there is no open file */
-
-  if ( !file || (file->fd == -1) )
-    return 0;
-		
-  fd = file->fd;
-  file->fd = -1;
-  SAFE_FREE( file );
-
-  return close( fd );
-}
-
-
-/*******************************************************************
- There should be only *one* root key in the registry file based 
- on my experience.  --jerry
-*******************************************************************/
-REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
-{
-  REGF_NK_REC *nk;
-  REGF_HBIN   *hbin;
-  uint32      offset = REGF_BLOCKSIZE;
-  bool        found = false;
-  bool        eob;
-	
-  if ( !file )
-    return NULL;
-		
-  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
-    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
-    return NULL;
-  }
-	
-  /* scan through the file on 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) */
-	
-  while ( (hbin = read_hbin_block( file, offset )) ) {
-    eob = false;
-
-    while ( !eob) {
-      if ( next_nk_record( file, hbin, nk, &eob ) ) {
-	if ( nk->key_type == NK_TYPE_ROOTKEY ) {
-	  found = true;
-	  break;
-	}
-      }
-      if(hbin->ps.is_dynamic)
-	SAFE_FREE(hbin->ps.data_p);
-      hbin->ps.is_dynamic = false;
-      hbin->ps.buffer_size = 0;
-      hbin->ps.data_offset = 0;
-    }
-		
-    if ( found ) 
-      break;
-
-    offset += hbin->block_size;
-  }
-	
-  if ( !found ) {
-    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
-    return NULL;
-  }
-
-  DLIST_ADD( file->block_list, hbin );
-
-  return nk;		
-}
-
-
-/* XXX: An interator struct should be used instead, and this function
- *   should operate on it, so the state of iteration isn't stored in the
- * REGF_NK_REC struct itself.
- */
-/*******************************************************************
- This acts as an interator over the subkeys defined for a given 
- NK record.  Remember that offsets are from the *first* HBIN block.
-*******************************************************************/
-REGF_NK_REC* regfi_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
-{
-  REGF_NK_REC *subkey;
-  REGF_HBIN   *hbin;
-  uint32      nk_offset;
-
-  /* see if there is anything left to report */
-  if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE) 
-      || (nk->subkey_index >= nk->num_subkeys))
-    return NULL;
-
-  /* find the HBIN block which should contain the nk record */
-  if(!(hbin 
-       = lookup_hbin_block(file, nk->subkeys.hashes[nk->subkey_index].nk_off )))
-  {
-    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 
-      nk->subkeys.hashes[nk->subkey_index].nk_off));*/
-    return NULL;
-  }
-  
-  nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
-  if(!prs_set_offset(&hbin->ps, 
-		     (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
-    return NULL;
-		
-  nk->subkey_index++;
-  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
-    return NULL;
-
-  if(!hbin_prs_key(file, hbin, subkey))
-    return NULL;
-
-  return subkey;
-}
Index: /trunk/src/reglookup.c
===================================================================
--- /trunk/src/reglookup.c	(revision 78)
+++ /trunk/src/reglookup.c	(revision 79)
@@ -29,5 +29,5 @@
 #include <time.h>
 #include <iconv.h>
-#include "../include/regfio.h"
+#include "../include/regfi.h"
 #include "../include/void_stack.h"
 
