s3-registry: update to use new DLIST macros
[ira/wip.git] / source3 / registry / regfio.c
index aebb1ebaed614f6e13a1ab6160331ba7871e04b9..c3873a894bba41960bcbd8634d1789cd2d1c6c97 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * 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.  
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.  
  */
 
 #include "includes.h"
 #include "regfio.h"
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
 /*******************************************************************
  *
  * TODO : Right now this code basically ignores classnames.
@@ -43,7 +45,7 @@ static int write_block( REGF_FILE *file, prs_struct *ps, uint32 offset )
 
        /* check for end of file */
 
-       if ( sys_fstat( file->fd, &sbuf ) ) {
+       if (sys_fstat(file->fd, &sbuf, false)) {
                DEBUG(0,("write_block: stat() failed! (%s)\n", strerror(errno)));
                return -1;
        }
@@ -77,15 +79,15 @@ static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint
 
        /* check for end of file */
 
-       if ( sys_fstat( file->fd, &sbuf ) ) {
+       if (sys_fstat(file->fd, &sbuf, false)) {
                DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));
                return -1;
        }
 
-       if ( (size_t)file_offset >= sbuf.st_size )
+       if ( (size_t)file_offset >= sbuf.st_ex_size )
                return -1;
        
-       /* if block_size == 0, we are parsnig HBIN records and need 
+       /* if block_size == 0, we are parsing HBIN records and need 
           to read some of the header to get the block_size from there */
           
        if ( block_size == 0 ) {
@@ -121,7 +123,10 @@ static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint
                return -1;
        }
        
-       prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
+       if (!prs_init( ps, block_size, file->mem_ctx, UNMARSHALL )) {
+               DEBUG(0,("read_block: prs_init() failed! (%s)\n", strerror(errno) ));
+               return -1;
+       }
        buffer = prs_data_p( ps );
        bytes_read = returned = 0;
 
@@ -144,7 +149,7 @@ static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint
 /*******************************************************************
 *******************************************************************/
 
-static BOOL write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin )
+static bool write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin )
 {
        if ( !hbin->dirty )
                return True;
@@ -170,7 +175,7 @@ static BOOL write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin )
+static bool hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin )
 {
        REGF_HBIN *p;
 
@@ -194,7 +199,7 @@ static BOOL hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file )
+static bool prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file )
 {
        prs_debug(ps, depth, desc, "prs_regf_block");
        depth++;
@@ -254,7 +259,7 @@ static BOOL prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FI
 /*******************************************************************
 *******************************************************************/
 
-static BOOL prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin )
+static bool prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin )
 {
        uint32 block_size2;
 
@@ -289,7 +294,7 @@ static BOOL prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HB
 /*******************************************************************
 *******************************************************************/
 
-static BOOL prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk )
+static bool prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk )
 {
        uint16 class_length, name_length;
        uint32 start;
@@ -416,7 +421,7 @@ static uint32 regf_block_checksum( prs_struct *ps )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL read_regf_block( REGF_FILE *file )
+static bool read_regf_block( REGF_FILE *file )
 {
        prs_struct ps;
        uint32 checksum;
@@ -533,11 +538,11 @@ static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
 }
 
 /*******************************************************************
- Input a randon offset and receive the correpsonding HBIN 
+ Input a random offset and receive the corresponding HBIN 
  block for it
 *******************************************************************/
 
-static BOOL hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
+static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
 {
        if ( !hbin )
                return False;
@@ -549,7 +554,7 @@ static BOOL hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
 }
 
 /*******************************************************************
- Input a randon offset and receive the correpsonding HBIN 
+ Input a random offset and receive the corresponding HBIN 
  block for it
 *******************************************************************/
 
@@ -561,7 +566,7 @@ static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
        /* 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 ));
+               DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%lx]\n", hbin->file_off, (unsigned long)hbin ));
                if ( hbin_contains_offset( hbin, offset ) )
                        return hbin;
        }
@@ -592,7 +597,7 @@ static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
+static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
 {
        prs_debug(ps, depth, desc, "prs_hash_rec");
        depth++;
@@ -608,7 +613,7 @@ static BOOL prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH
 /*******************************************************************
 *******************************************************************/
 
-static BOOL hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk )
+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;
@@ -642,8 +647,12 @@ static BOOL hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, R
                return False;
 
        if ( UNMARSHALLING(&hbin->ps) ) {
-               if ( !(lf->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) )
-                       return False;
+               if (lf->num_keys) {
+                       if ( !(lf->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) )
+                               return False;
+               } else {
+                       lf->hashes = NULL;
+               }
        }
 
        for ( i=0; i<lf->num_keys; i++ ) {
@@ -668,7 +677,7 @@ static BOOL hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, R
 /*******************************************************************
 *******************************************************************/
 
-static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
+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;
@@ -703,8 +712,30 @@ static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_
        if ( !prs_uint32( "size", ps, depth, &sk->size))
                return False;
 
-       if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
-               return False;
+       {
+               NTSTATUS status;
+               TALLOC_CTX *mem_ctx = prs_get_mem_context(&hbin->ps);
+               DATA_BLOB blob;
+
+               if (MARSHALLING(&hbin->ps)) {
+                       status = marshall_sec_desc(mem_ctx,
+                                                  sk->sec_desc,
+                                                  &blob.data, &blob.length);
+                       if (!NT_STATUS_IS_OK(status))
+                               return False;
+                       if (!prs_copy_data_in(&hbin->ps, (const char *)blob.data, blob.length))
+                               return False;
+               } else {
+                       blob = data_blob_const(prs_data_p(&hbin->ps),
+                                              prs_data_size(&hbin->ps));
+                       status = unmarshall_sec_desc(mem_ctx,
+                                                    blob.data, blob.length,
+                                                    &sk->sec_desc);
+                       if (!NT_STATUS_IS_OK(status))
+                               return False;
+                       prs_set_offset(&hbin->ps, blob.length);
+               }
+       }
 
        end_off = prs_offset( &hbin->ps );
 
@@ -723,7 +754,7 @@ static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_
 /*******************************************************************
 *******************************************************************/
 
-static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_VK_REC *vk, REGF_FILE *file )
+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;
@@ -779,7 +810,7 @@ static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_
        /* get the data if necessary */
 
        if ( vk->data_size != 0 ) {
-               BOOL charmode = False;
+               bool charmode = False;
 
                if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
                        charmode = True;
@@ -840,7 +871,7 @@ static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_
  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 )
+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;
@@ -927,7 +958,7 @@ 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 ) )
+               if ( security_descriptor_equal( p->sec_desc, sd ) )
                        return p;
        }
 
@@ -939,7 +970,7 @@ static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
+static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
 {
        int depth = 0;
        REGF_HBIN *sub_hbin;
@@ -1018,19 +1049,19 @@ static BOOL hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL next_record( REGF_HBIN *hbin, const char *hdr, BOOL *eob )
+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;
+       bool found = False;
        prs_struct *ps = &hbin->ps;
        
        curr_off = prs_offset( ps );
        if ( curr_off == 0 )
                prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
 
-       /* assume that the current offset is at the reacord header 
+       /* assume that the current offset is at the record header 
           and we need to backup to read the record size */
 
        curr_off -= sizeof(uint32);
@@ -1081,7 +1112,7 @@ static BOOL next_record( REGF_HBIN *hbin, const char *hdr, BOOL *eob )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, BOOL *eob )
+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;
@@ -1094,10 +1125,10 @@ static BOOL next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, B
  block header to disk 
 *******************************************************************/
 
-static BOOL init_regf_block( REGF_FILE *file )
+static bool init_regf_block( REGF_FILE *file )
 {      
        prs_struct ps;
-       BOOL result = True;
+       bool result = True;
        
        if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) )
                return False;
@@ -1224,7 +1255,7 @@ static void regfio_mem_free( REGF_FILE *file )
 
        /* cleanup for a file opened for write */
 
-       if ( file->open_flags & (O_WRONLY|O_RDWR) ) {
+       if ((file->fd != -1) && (file->open_flags & (O_WRONLY|O_RDWR))) {
                prs_struct ps;
                REGF_SK_REC *sk;
 
@@ -1268,7 +1299,7 @@ static void regfio_mem_free( REGF_FILE *file )
 
        /* nothing tdo do if there is no open file */
 
-       if ( !file || (file->fd == -1) )
+       if (file->fd == -1)
                return 0;
                
        fd = file->fd;
@@ -1300,8 +1331,8 @@ REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
        REGF_NK_REC *nk;
        REGF_HBIN   *hbin;
        uint32      offset = REGF_BLOCKSIZE;
-       BOOL        found = False;
-       BOOL        eob;
+       bool        found = False;
+       bool        eob;
        
        if ( !file )
                return NULL;
@@ -1398,12 +1429,12 @@ static REGF_HBIN* regf_hbin_allocate( REGF_FILE *file, uint32 block_size )
        memcpy( hbin->header, "hbin", sizeof(HBIN_HDR_SIZE) );
 
 
-       if ( sys_fstat( file->fd, &sbuf ) ) {
+       if (sys_fstat(file->fd, &sbuf, false)) {
                DEBUG(0,("regf_hbin_allocate: stat() failed! (%s)\n", strerror(errno)));
                return NULL;
        }
 
-       hbin->file_off       = sbuf.st_size;
+       hbin->file_off       = sbuf.st_ex_size;
 
        hbin->free_off       = HBIN_HEADER_REC_SIZE;
        hbin->free_size      = block_size - hbin->free_off + sizeof(uint32);;
@@ -1447,7 +1478,7 @@ static REGF_HBIN* find_free_space( REGF_FILE *file, uint32 size )
 {
        REGF_HBIN *hbin, *p_hbin;
        uint32 block_off;
-       BOOL cached;
+       bool cached;
 
        /* check open block list */
 
@@ -1544,7 +1575,7 @@ static uint32 sk_record_data_size( SEC_DESC * sd )
 
        /* the record size is sizeof(hdr) + name + static members + data_size_field */
 
-       size = sizeof(uint32)*5 + sec_desc_size( sd ) + sizeof(uint32);
+       size = sizeof(uint32)*5 + ndr_size_security_descriptor(sd, NULL, 0) + sizeof(uint32);
 
        /* multiple of 8 */
        size_mod8 = size & 0xfffffff8;
@@ -1626,7 +1657,8 @@ static uint32 nk_record_data_size( REGF_NK_REC *nk )
 /*******************************************************************
 *******************************************************************/
 
-static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *value )
+static bool create_vk_record(REGF_FILE *file, REGF_VK_REC *vk,
+                            struct regval_blob *value)
 {
        char *name = regval_name(value);
        REGF_HBIN *data_hbin;
@@ -1646,12 +1678,19 @@ static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *
        if ( vk->data_size > sizeof(uint32) ) {
                uint32 data_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
 
-               vk->data = TALLOC_MEMDUP( file->mem_ctx, regval_data_p(value), vk->data_size );
+               vk->data = (uint8 *)TALLOC_MEMDUP( file->mem_ctx,
+                                                  regval_data_p(value),
+                                                  vk->data_size );
+               if (vk->data == NULL) {
+                       return False;
+               }
 
                /* go ahead and store the offset....we'll pick this hbin block back up when 
                   we stream the data */
 
-               data_hbin = find_free_space(file, data_size );
+               if ((data_hbin = find_free_space(file, data_size )) == NULL) {
+                       return False;
+               }
                vk->data_off = prs_offset( &data_hbin->ps ) + data_hbin->first_hbin_off - HBIN_HDR_SIZE;
        }
        else {
@@ -1670,14 +1709,14 @@ static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *
 
 static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
 {
-       return strcmp( h1->fullname, h2->fullname );
+       return StrCaseCmp( h1->fullname, h2->fullname );
 }
 
 /*******************************************************************
 *******************************************************************/
 
- REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name, 
-                               REGVAL_CTR *values, REGSUBKEY_CTR *subkeys, 
+ REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name,
+                               struct regval_ctr *values, struct regsubkey_ctr *subkeys,
                                SEC_DESC *sec_desc, REGF_NK_REC *parent )
 {
        REGF_NK_REC *nk;
@@ -1712,7 +1751,9 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
 
        size = nk_record_data_size( nk );
        nk->rec_size = ( size - 1 ) ^ 0XFFFFFFFF;
-       nk->hbin = find_free_space( file, size );
+       if ((nk->hbin = find_free_space( file, size )) == NULL) {
+               return NULL;
+       }
        nk->hbin_off = prs_offset( &nk->hbin->ps );
 
        /* Update the hash record in the parent */
@@ -1739,14 +1780,15 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
        if ( sec_desc ) {
                uint32 sk_size = sk_record_data_size( sec_desc );
                REGF_HBIN *sk_hbin;
-               REGF_SK_REC *tmp = NULL;
 
                /* search for it in the existing list of sd's */
 
                if ( (nk->sec_desc = find_sk_record_by_sec_desc( file, sec_desc )) == NULL ) {
                        /* not found so add it to the list */
 
-                       sk_hbin = find_free_space( file, sk_size );
+                       if (!(sk_hbin = find_free_space( file, sk_size ))) {
+                               return NULL;
+                       }
 
                        if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) )
                                return NULL;
@@ -1764,26 +1806,33 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
                        nk->sec_desc->ref_count = 0;
                        
                        /* size value must be self-inclusive */
-                       nk->sec_desc->size      = sec_desc_size(sec_desc) + sizeof(uint32);
+                       nk->sec_desc->size      = ndr_size_security_descriptor(sec_desc, NULL, 0)
+                               + sizeof(uint32);
 
-                       DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, tmp );
+                       DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, REGF_SK_REC *);
 
-                       /* initialize offsets */
+                       /* update the offsets for us and the previous sd in the list.
+                          if this is the first record, then just set the next and prev
+                          offsets to ourself. */
 
-                       nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off;
-                       nk->sec_desc->next_sk_off = nk->sec_desc->sk_off;
+                       if ( DLIST_PREV(nk->sec_desc) ) {
+                               REGF_SK_REC *prev = DLIST_PREV(nk->sec_desc);
 
-                       /* now update the offsets for us and the previous sd in the list */
+                               nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE;
+                               prev->next_sk_off = nk->sec_desc->sk_off;
 
-                       if ( nk->sec_desc->prev ) {
-                               REGF_SK_REC *prev = nk->sec_desc->prev;
+                               /* the end must loop around to the front */
+                               nk->sec_desc->next_sk_off = file->sec_desc_list->sk_off;
 
-                               nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE;
-                               prev->next_sk_off = nk->sk_off;
+                               /* and first must loop around to the tail */
+                               file->sec_desc_list->prev_sk_off = nk->sec_desc->sk_off;
+                       } else {
+                               nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off;
+                               nk->sec_desc->next_sk_off = nk->sec_desc->sk_off;
                        }
                }
 
-               /* dump the reference count */
+               /* bump the reference count +1 */
 
                nk->sk_off = nk->sec_desc->sk_off;
                nk->sec_desc->ref_count++;
@@ -1797,7 +1846,9 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
                uint32 namelen;
                int i;
                
-               nk->subkeys.hbin = find_free_space( file, lf_size );
+               if (!(nk->subkeys.hbin = find_free_space( file, lf_size ))) {
+                       return NULL;
+               }
                nk->subkeys.hbin_off = prs_offset( &nk->subkeys.hbin->ps );
                nk->subkeys.rec_size = (lf_size-1) ^ 0xFFFFFFFF;
                nk->subkeys_off = prs_offset( &nk->subkeys.hbin->ps ) + nk->subkeys.hbin->first_hbin_off - HBIN_HDR_SIZE;
@@ -1805,8 +1856,12 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
                memcpy( nk->subkeys.header, "lf", REC_HDR_SIZE );
                
                nk->subkeys.num_keys = nk->num_subkeys;
-               if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) )
-                       return NULL;
+               if (nk->subkeys.num_keys) {
+                       if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) )
+                               return NULL;
+               } else {
+                       nk->subkeys.hashes = NULL;
+               }
                nk->subkey_index = 0;
 
                /* update the max_bytes_subkey{name,classname} fields */
@@ -1824,17 +1879,23 @@ static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
                uint32 vlist_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
                int i;
                
-               vlist_hbin = find_free_space( file, vlist_size );
+               if (!(vlist_hbin = find_free_space( file, vlist_size ))) {
+                       return NULL;
+               }
                nk->values_off = prs_offset( &vlist_hbin->ps ) + vlist_hbin->first_hbin_off - HBIN_HDR_SIZE;
        
-               if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) )
-                       return NULL;
+               if (nk->num_values) {
+                       if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) )
+                               return NULL;
+               } else {
+                       nk->values = NULL;
+               }
 
                /* create the vk records */
 
                for ( i=0; i<nk->num_values; i++ ) {
                        uint32 vk_size, namelen, datalen;
-                       REGISTRY_VALUE *r;
+                       struct regval_blob *r;
 
                        r = regval_ctr_specific_value( values, i );
                        create_vk_record( file, &nk->values[i], r );