New implementation of the win95 registry loader.
diff --git a/misc/registry.c b/misc/registry.c
index cc929b0..cc21f39 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -670,18 +670,16 @@
#define MAP_FAILED ((LPVOID)-1)
#endif
-#define LONG_DUMP 1
+#define NT_REG_BLOCK_SIZE 0x1000
-#define REG_BLOCK_SIZE 0x1000
-
-#define REG_HEADER_BLOCK_ID 0x66676572 /* regf */
-#define REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
-#define REG_KEY_BLOCK_ID 0x6b6e
-#define REG_VALUE_BLOCK_ID 0x6b76
-#define REG_HASH_BLOCK_ID 0x666c
-#define REG_NOHASH_BLOCK_ID 0x696c
-#define REG_KEY_BLOCK_TYPE 0x20
-#define REG_ROOT_KEY_BLOCK_TYPE 0x2c
+#define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
+#define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
+#define NT_REG_KEY_BLOCK_ID 0x6b6e
+#define NT_REG_VALUE_BLOCK_ID 0x6b76
+#define NT_REG_HASH_BLOCK_ID 0x666c
+#define NT_REG_NOHASH_BLOCK_ID 0x696c
+#define NT_REG_KEY_BLOCK_TYPE 0x20
+#define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
typedef struct
{
@@ -778,14 +776,6 @@
char name[1];
} nt_vk;
-#define vk_sz 0x0001
-#define vk_expsz 0x0002
-#define vk_bin 0x0003
-#define vk_dword 0x0004
-#define vk_multisz 0x0007
-#define vk_u2 0x0008
-#define vk_u1 0x000a
-
LPSTR _strdupnA( LPCSTR str, int len )
{
LPSTR ret;
@@ -797,9 +787,9 @@
return ret;
}
-int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
-int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level);
-int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
+static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
+static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
+static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
/*
@@ -816,13 +806,13 @@
* - reg_dword, reg_binary:
* if highest bit of data_len is set data_off contains the value
*/
-int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk, int level)
+static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
{
WCHAR name [256];
DWORD ret;
BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
- if(vk->id != REG_VALUE_BLOCK_ID) goto error;
+ if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
lstrcpynAtoW(name, vk->name, vk->nam_len+1);
@@ -845,11 +835,11 @@
* exception: if the id is 'il' there are no hash values and every
* dword is a offset
*/
-int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
+static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
{
int i;
- if (lf->id == REG_HASH_BLOCK_ID)
+ if (lf->id == NT_REG_HASH_BLOCK_ID)
{
for (i=0; i<lf->nr_keys; i++)
{
@@ -857,7 +847,7 @@
}
}
- else if (lf->id == REG_NOHASH_BLOCK_ID)
+ else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
{
for (i=0; i<lf->nr_keys; i++)
{
@@ -870,28 +860,31 @@
return FALSE;
}
-int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
+static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
{
char * name;
int i;
DWORD * vl;
- HKEY subkey;
+ HKEY subkey = hkey;
- if(nk->SubBlockId != REG_KEY_BLOCK_ID) goto error;
- if((nk->Type!=REG_ROOT_KEY_BLOCK_TYPE) &&
- (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != REG_KEY_BLOCK_ID)) goto error;
+ if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID) goto error;
+ if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
+ (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) goto error;
/* create the new key */
- name = _strdupnA( nk->name, nk->name_len+1);
- if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
- free(name);
+ if(level <= 0)
+ {
+ name = _strdupnA( nk->name, nk->name_len+1);
+ if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
+ free(name);
+ }
/* loop through the subkeys */
if (nk->nr_subkeys)
{
nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
if (nk->nr_subkeys != lf->nr_keys) goto error1;
- if (!_nt_parse_lf(subkey, base, lf, level+1)) goto error1;
+ if (!_nt_parse_lf(subkey, base, lf, level-1)) goto error1;
}
/* loop trough the value list */
@@ -899,7 +892,7 @@
for (i=0; i<nk->nr_values; i++)
{
nt_vk * vk = (nt_vk*)(base+vl[i]+4);
- if (!_nt_parse_vk(subkey, base, vk, level+1 )) goto error1;
+ if (!_nt_parse_vk(subkey, base, vk)) goto error1;
}
RegCloseKey(subkey);
@@ -910,421 +903,353 @@
return FALSE;
}
-/*
- * this function intentionally uses unix file functions to make it possible
- * to move it to a seperate registry helper programm
- */
-static int _nt_loadreg( HKEY hkey, char* fn )
-{
- void * base;
- int len, fd;
- struct stat st;
- nt_regf * regf;
- nt_hbin * hbin;
- nt_hbin_sub * hbin_sub;
- nt_nk* nk;
- DOS_FULL_NAME full_name;
-
- if (!DOSFS_GetFullName( fn, 0, &full_name ));
-
- TRACE_(reg)("Loading NT registry database '%s' '%s'\n",fn, full_name.long_name);
-
- if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
- if (fstat(fd, &st ) == -1) goto error1;
- len = st.st_size;
- if ((base=mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error1;
-
- /* start block */
- regf = base;
- if(regf->id != REG_HEADER_BLOCK_ID) /* 'regf' */
- {
- ERR( "%s is not a nt-registry\n", fn);
- goto error;
- }
- TRACE_(reg)( "%p [regf] offset=%lx size=%lx\n", regf, regf->RootKeyBlock, regf->BlockSize);
-
- /* hbin block */
- hbin = base + 0x1000;
- if (hbin->id != REG_POOL_BLOCK_ID)
- {
- ERR_(reg)( "%s hbin block invalid\n", fn);
- goto error;
- }
- TRACE_(reg)( "%p [hbin] prev=%lx next=%lx size=%lx\n", hbin, hbin->off_prev, hbin->off_next, hbin->size);
-
- /* hbin_sub block */
- hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
- if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
- {
- ERR_(reg)( "%s hbin_sub block invalid\n", fn);
- goto error;
- }
- TRACE_(reg)( "%p [hbin sub] size=%lx\n", hbin_sub, hbin_sub->blocksize);
-
- /* nk block */
- nk = (nt_nk*)&(hbin_sub->data[0]);
- if (nk->Type != REG_ROOT_KEY_BLOCK_TYPE)
- {
- ERR_(reg)( "%s special nk block not found\n", fn);
- goto error;
- }
-
- _nt_parse_nk (hkey, base+0x1000, nk, 0);
-
- munmap(base, len);
- close(fd);
- return 1;
-
-error: munmap(base, len);
-error1: close(fd);
- ERR_(reg)("error reading registry file\n");
- return 0;
-}
/* end nt loader */
-/* WINDOWS 95 REGISTRY LOADER */
-/*
- * Structure of a win95 registry database.
- * main header:
- * 0 : "CREG" - magic
- * 4 : DWORD version
- * 8 : DWORD offset_of_RGDB_part
- * 0C..0F: ? (someone fill in please)
- * 10: WORD number of RGDB blocks
- * 12: WORD ?
- * 14: WORD always 0000?
- * 16: WORD always 0001?
- * 18..1F: ? (someone fill in please)
+/* windows 95 registry loader */
+
+/* SECTION 1: main header
*
- * 20: RGKN_section:
- * header:
- * 0 : "RGKN" - magic
- * 4 : DWORD offset to first RGDB section
- * 8 : DWORD offset to the root record
- * C..0x1B: ? (fill in)
- * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
+ * once at offset 0
+ */
+#define W95_REG_CREG_ID 0x47455243
+
+typedef struct
+{
+ DWORD id; /* "CREG" = W95_REG_CREG_ID */
+ DWORD version; /* ???? 0x00010000 */
+ DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
+ DWORD uk2; /* 0x0c */
+ WORD rgdb_num; /* 0x10 # of RGDB-blocks */
+ WORD uk3;
+ DWORD uk[3];
+ /* rgkn */
+} _w95creg;
+
+/* SECTION 2: Directory information (tree structure)
*
- * Disk Key Entry Structure:
- * 00: DWORD - Free entry indicator(?)
- * 04: DWORD - Hash = sum of bytes of keyname
- * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
- * 0C: DWORD - disk address of PreviousLevel Key.
- * 10: DWORD - disk address of Next Sublevel Key.
- * 14: DWORD - disk address of Next Key (on same level).
- * DKEP>18: WORD - Nr, Low Significant part.
- * 1A: WORD - Nr, High Significant part.
+ * once on offset 0x20
*
- * The disk address always points to the nr part of the previous key entry
- * of the referenced key. Don't ask me why, or even if I got this correct
- * from staring at 1kg of hexdumps. (DKEP)
+ * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
+ */
+#define W95_REG_RGKN_ID 0x4e4b4752
+
+typedef struct
+{
+ DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
+ DWORD size; /* Size of the RGKN-block */
+ DWORD root_off; /* Rel. Offset of the root-record */
+ DWORD uk[5];
+} _w95rgkn;
+
+/* Disk Key Entry Structure
*
- * The High significant part of the structure seems to equal the number
- * of the RGDB section. The low significant part is a unique ID within
- * that RGDB section
+ * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
+ * hive itself. It looks the same like other keys. Even the ID-number can
+ * be any value.
*
- * There are two minor corrections to the position of that structure.
- * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
- * the DKE reread from there.
- * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
- * CPS - I have not experienced the above phenomenon in my registry files
+ * The "hash"-value is a value representing the key's name. Windows will not
+ * search for the name, but for a matching hash-value. if it finds one, it
+ * will compare the actual string info, otherwise continue with the next key.
+ * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
+ * of the string which are smaller than 0x80 (128) to this D-Word.
*
- * RGDB_section:
- * 00: "RGDB" - magic
- * 04: DWORD offset to next RGDB section
- * 08: DWORD ?
- * 0C: WORD always 000d?
- * 0E: WORD RGDB block number
- * 10: DWORD ? (equals value at offset 4 - value at offset 8)
- * 14..1F: ?
- * 20.....: disk keys
- *
- * disk key:
- * 00: DWORD nextkeyoffset - offset to the next disk key structure
- * 08: WORD nrLS - low significant part of NR
- * 0A: WORD nrHS - high significant part of NR
- * 0C: DWORD bytesused - bytes used in this structure.
- * 10: WORD name_len - length of name in bytes. without \0
- * 12: WORD nr_of_values - number of values.
- * 14: char name[name_len] - name string. No \0.
- * 14+name_len: disk values
- * nextkeyoffset: ... next disk key
- *
- * disk value:
- * 00: DWORD type - value type (hmm, could be WORD too)
- * 04: DWORD - unknown, usually 0
- * 08: WORD namelen - length of Name. 0 means name=NULL
- * 0C: WORD datalen - length of Data.
- * 10: char name[namelen] - name, no \0
- * 10+namelen: BYTE data[datalen] - data, without \0 if string
- * 10+namelen+datalen: next values or disk key
+ * If you want to modify key names, also modify the hash-values, since they
+ * cannot be found again (although they would be displayed in REGEDIT)
+ * End of list-pointers are filled with 0xFFFFFFFF
*
* Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
* 0xFFFF, which means skipping over nextkeyoffset bytes (including this
* structure) and reading another RGDB_section.
- * repeat until end of file.
+ *
+ * there is a one to one relationship between dke and dkh
+ */
+ /* key struct, once per key */
+typedef struct
+{
+ DWORD x1; /* Free entry indicator(?) */
+ DWORD hash; /* sum of bytes of keyname */
+ DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
+ DWORD prevlvl; /* offset of previous key */
+ DWORD nextsub; /* offset of child key */
+ DWORD next; /* offset of sibling key */
+ WORD nrLS; /* id inside the rgdb block */
+ WORD nrMS; /* number of the rgdb block */
+} _w95dke;
+
+/* SECTION 3: key information, values and data
+ *
+ * structure:
+ * section: [blocks]* (repeat creg->rgdb_num times)
+ * blocks: [rgdb] [subblocks]* (repeat till block size reached )
+ * subblocks: [dkh] [dkv]* (repeat dkh->values times )
*
* An interesting relationship exists in RGDB_section. The value at offset
* 10 equals the value at offset 4 minus the value at offset 8. I have no
* idea at the moment what this means. (Kevin Cozens)
+ */
+
+/* block header, once per block */
+#define W95_REG_RGDB_ID 0x42444752
+
+typedef struct
+{
+ DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
+ DWORD size; /* 0x04 */
+ DWORD uk1; /* 0x08 */
+ DWORD uk2; /* 0x0c */
+ DWORD uk3; /* 0x10 */
+ DWORD uk4; /* 0x14 */
+ DWORD uk5; /* 0x18 */
+ DWORD uk6; /* 0x1c */
+ /* dkh */
+} _w95rgdb;
+
+/* Disk Key Header structure (RGDB part), once per key */
+typedef struct
+{
+ DWORD nextkeyoff; /* 0x00 offset to next dkh*/
+ WORD nrLS; /* 0x04 id inside the rgdb block */
+ WORD nrMS; /* 0x06 number of the rgdb block */
+ DWORD bytesused; /* 0x08 */
+ WORD keynamelen; /* 0x0c len of name */
+ WORD values; /* 0x0e number of values */
+ DWORD xx1; /* 0x10 */
+ char name[1]; /* 0x14 */
+ /* dkv */ /* 0x14 + keynamelen */
+} _w95dkh;
+
+/* Disk Key Value structure, once per value */
+typedef struct
+{
+ DWORD type; /* 0x00 */
+ DWORD x1; /* 0x04 */
+ WORD valnamelen; /* 0x08 length of name, 0 is default key */
+ WORD valdatalen; /* 0x0A length of data */
+ char name[1]; /* 0x0c */
+ /* raw data */ /* 0x0c + valnamelen */
+} _w95dkv;
+
+/******************************************************************************
+ * _w95_lookup_dkh [Internal]
*
- * FIXME: this description needs some serious help, yes.
+ * seeks the dkh belonging to a dke
*/
-
-struct _w95keyvalue {
- unsigned long type;
- unsigned short datalen;
- char *name;
- unsigned char *data;
- unsigned long x1;
- int lastmodified;
-};
-
-struct _w95key {
- char *name;
- int nrofvals;
- struct _w95keyvalue *values;
- struct _w95key *prevlvl;
- struct _w95key *nextsub;
- struct _w95key *next;
-};
-
-
-struct _w95_info {
- char *rgknbuffer;
- int rgknsize;
- char *rgdbbuffer;
- int rgdbsize;
- int depth;
- int lastmodified;
-};
-
-
-/******************************************************************************
- * _w95_processKey [Internal]
- */
-static HKEY _w95_processKey ( HKEY hkey, int nrLS, int nrMS, struct _w95_info *info )
-
+static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
{
- /* Disk Key Header structure (RGDB part) */
- struct dkh {
- unsigned long nextkeyoff;
- unsigned short nrLS;
- unsigned short nrMS;
- unsigned long bytesused;
- unsigned short keynamelen;
- unsigned short values;
- unsigned long xx1;
- /* keyname */
- /* disk key values or nothing */
- };
- /* Disk Key Value structure */
- struct dkv {
- unsigned long type;
- unsigned long x1;
- unsigned short valnamelen;
- unsigned short valdatalen;
- /* valname, valdata */
- };
-
+ _w95rgdb * rgdb;
+ _w95dkh * dkh;
+ int i;
- struct dkh dkh;
- int bytesread = 0;
- char *rgdbdata = info->rgdbbuffer;
- int nbytes = info->rgdbsize;
- char *curdata = rgdbdata;
- char *end = rgdbdata + nbytes;
- int off_next_rgdb;
- char *next = rgdbdata;
- int nrgdb, i;
- HKEY subkey;
+ rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
+ assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
- do {
- curdata = next;
- if (strncmp(curdata, "RGDB", 4)) return 0;
-
- memcpy(&off_next_rgdb,curdata+4,4);
- next = curdata + off_next_rgdb;
- nrgdb = (int) *((short *)curdata + 7);
-
- } while (nrgdb != nrMS && (next < end));
-
- /* curdata now points to the start of the right RGDB section */
- curdata += 0x20;
-
-#define XREAD(whereto,len) \
- if ((curdata + len) <= end) {\
- memcpy(whereto,curdata,len);\
- curdata+=len;\
- bytesread+=len;\
+ /* find the right block */
+ for(i=0; i<nrMS ;i++)
+ {
+ assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
+ rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
}
- while (curdata < next) {
- struct dkh *xdkh = (struct dkh*)curdata;
+ dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
- bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
- if (xdkh->nrLS == nrLS) {
- memcpy(&dkh,xdkh,sizeof(dkh));
- curdata += sizeof(dkh);
- break;
- }
- curdata += xdkh->nextkeyoff;
- };
+ do
+ {
+ if(nrLS==dkh->nrLS ) return dkh;
+ dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
+ } while ((char *)dkh < ((char*)rgdb+rgdb->size));
- if (dkh.nrLS != nrLS) return 0;
+ return NULL;
+}
+
+/******************************************************************************
+ * _w95_parse_dkv [Internal]
+ */
+static int _w95_parse_dkv (
+ HKEY hkey,
+ _w95dkh * dkh,
+ int nrLS,
+ int nrMS )
+{
+ _w95dkv * dkv;
+ int i;
+ DWORD ret;
+ char * name;
+
+ /* first value block */
+ dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
- if (nrgdb != dkh.nrMS)
- return 0;
+ /* loop trought the values */
+ for (i=0; i< dkh->values; i++)
+ {
+ name = _strdupnA(dkv->name, dkv->valnamelen+1);
+ ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
+ if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
+ free (name);
- assert((dkh.keynamelen<2) || curdata[0]);
- subkey=_find_or_add_key(hkey,strcvtA2W(curdata, dkh.keynamelen));
- curdata += dkh.keynamelen;
-
- for (i=0;i< dkh.values; i++) {
- struct dkv dkv;
- LPBYTE data;
- int len;
- LPWSTR name;
-
- XREAD(&dkv,sizeof(dkv));
-
- name = strcvtA2W(curdata, dkv.valnamelen);
- curdata += dkv.valnamelen;
-
- if ((1 << dkv.type) & UNICONVMASK) {
- data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
- len = 2*(dkv.valdatalen + 1);
- } else {
- /* I don't think we want to NULL terminate all data */
- data = xmalloc(dkv.valdatalen);
- memcpy (data, curdata, dkv.valdatalen);
- len = dkv.valdatalen;
- }
-
- curdata += dkv.valdatalen;
-
- _find_or_add_value( subkey, name, dkv.type, data, len );
+ /* next value */
+ dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
}
- return subkey;
+ return TRUE;
}
/******************************************************************************
- * _w95_walkrgkn [Internal]
+ * _w95_parse_dke [Internal]
*/
-static void _w95_walkrgkn( HKEY prevkey, char *off,
- struct _w95_info *info )
-
+static int _w95_parse_dke(
+ HKEY hkey,
+ _w95creg * creg,
+ _w95rgkn *rgkn,
+ _w95dke * dke,
+ int level )
{
- /* Disk Key Entry structure (RGKN part) */
- struct dke {
- unsigned long x1;
- unsigned long x2;
- unsigned long x3;/*usually 0xFFFFFFFF */
- unsigned long prevlvl;
- unsigned long nextsub;
- unsigned long next;
- unsigned short nrLS;
- unsigned short nrMS;
- } *dke = (struct dke *)off;
- HKEY subkey;
+ _w95dkh * dkh;
+ HKEY hsubkey = hkey;
+ char * name;
+ int ret = FALSE;
- if (dke == NULL) {
- dke = (struct dke *) ((char *)info->rgknbuffer);
- }
+ /* get start address of root key block */
+ if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
+
+ /* create key */
+ if (dke->nrLS != 0xffff && dke->nrMS!=0xffff) /* eg. the root key has no name */
+ {
+ if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
+ {
+ fprintf(stderr, "dke pointing to missing dkh !\n");
+ goto error;
+ }
+ /* subblock found */
+ if ( level <= 0 )
+ {
+ name = _strdupnA( dkh->name, dkh->keynamelen+1);
+ if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
+ free(name);
+ }
+ _w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS);
+ }
+ else
+ {
+ level++; /* we have to skip the root-block anyway */
+ }
+
+ /* walk sibling keys */
+ if (dke->next != 0xffffffff )
+ {
+ _w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level);
+ }
- subkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
-
- if (dke->nextsub != -1 &&
- ((dke->nextsub - 0x20) < info->rgknsize)
- && (dke->nextsub > 0x20)) {
-
- _w95_walkrgkn(subkey ? subkey : prevkey, /* XXX <-- This is a hack*/
- info->rgknbuffer + dke->nextsub - 0x20,
- info);
- }
- if (subkey) RegCloseKey( subkey );
-
- if (dke->next != -1 &&
- ((dke->next - 0x20) < info->rgknsize) &&
- (dke->next > 0x20)) {
- _w95_walkrgkn(prevkey,
- info->rgknbuffer + dke->next - 0x20,
- info);
- }
+ /* next sub key */
+ if (dke->nextsub != 0xffffffff)
+ {
+ _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1);
+ }
+
+ ret = TRUE;
+ if (hsubkey != hkey) RegCloseKey(hsubkey);
+error: return ret;
}
-
+/* end windows 95 loader */
/******************************************************************************
- * _w95_loadreg [Internal]
+ * NativeRegLoadKey [Internal]
+ *
+ * Loads a native registry file (win95/nt)
+ * hkey root key
+ * fn filename
+ * level number of levels to cut away (eg. ".Default" in user.dat)
+ *
+ * this function intentionally uses unix file functions to make it possible
+ * to move it to a seperate registry helper programm
*/
-static void _w95_loadreg( char* fn, HKEY hkey )
+static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
{
- HFILE hfd;
- char magic[5];
- unsigned long where,version,rgdbsection,end;
- struct _w95_info info;
- OFSTRUCT ofs;
- BY_HANDLE_FILE_INFORMATION hfdinfo;
+ int fd = 0;
+ struct stat st;
+ DOS_FULL_NAME full_name;
+ int ret = FALSE;
+ void * base;
+
+ if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
+
+ /* map the registry into the memory */
+ if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
+ if ((fstat(fd, &st) == -1)) goto error;
+ if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
- TRACE("Loading Win95 registry database '%s'\n",fn);
- hfd=OpenFile(fn,&ofs,OF_READ);
- if (hfd==HFILE_ERROR)
- return;
- magic[4]=0;
- if (4!=_lread(hfd,magic,4))
- return;
- if (strcmp(magic,"CREG")) {
- WARN("%s is not a w95 registry.\n",fn);
- return;
- }
- if (4!=_lread(hfd,&version,4))
- return;
- if (4!=_lread(hfd,&rgdbsection,4))
- return;
- if (-1==_llseek(hfd,0x20,SEEK_SET))
- return;
- if (4!=_lread(hfd,magic,4))
- return;
- if (strcmp(magic,"RGKN")) {
- WARN("second IFF header not RGKN, but %s\n", magic);
- return;
+ switch (*(LPDWORD)base)
+ {
+ /* windows 95 'creg' */
+ case W95_REG_CREG_ID:
+ {
+ _w95creg * creg;
+ _w95rgkn * rgkn;
+ creg = base;
+ TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
+
+ /* load the header (rgkn) */
+ rgkn = (_w95rgkn*)(creg + 1);
+ if (rgkn->id != W95_REG_RGKN_ID)
+ {
+ ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
+ goto error1;
+ }
+
+ ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
+ }
+ break;
+ /* nt 'regf'*/
+ case NT_REG_HEADER_BLOCK_ID:
+ {
+ nt_regf * regf;
+ nt_hbin * hbin;
+ nt_hbin_sub * hbin_sub;
+ nt_nk* nk;
+
+ TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
+
+ /* start block */
+ regf = base;
+
+ /* hbin block */
+ hbin = base + 0x1000;
+ if (hbin->id != NT_REG_POOL_BLOCK_ID)
+ {
+ ERR_(reg)( "%s hbin block invalid\n", fn);
+ goto error1;
+ }
+
+ /* hbin_sub block */
+ hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
+ if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
+ {
+ ERR_(reg)( "%s hbin_sub block invalid\n", fn);
+ goto error1;
+ }
+
+ /* nk block */
+ nk = (nt_nk*)&(hbin_sub->data[0]);
+ if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
+ {
+ ERR_(reg)( "%s special nk block not found\n", fn);
+ goto error1;
+ }
+
+ ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
+ }
+ break;
+ default:
+ {
+ ERR("unknown signature in registry file %s.\n",fn);
+ goto error1;
+ }
}
- /* STEP 1: Keylink structures */
- if (-1==_llseek(hfd,0x40,SEEK_SET))
- return;
- where = 0x40;
- end = rgdbsection;
-
- info.rgknsize = end - where;
- info.rgknbuffer = (char*)xmalloc(info.rgknsize);
- if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
- return;
-
- if (!GetFileInformationByHandle(hfd,&hfdinfo))
- return;
-
- end = hfdinfo.nFileSizeLow;
- info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
-
- if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
- return;
-
- info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
- info.rgdbsize = end - rgdbsection;
-
- if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
- return;
- _lclose(hfd);
-
- _w95_walkrgkn(hkey, NULL, &info);
-
- free (info.rgdbbuffer);
- free (info.rgknbuffer);
+error1: munmap(base, st.st_size);
+error: close(fd);
+ return ret;
}
-
/* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
-
/*
reghack - windows 3.11 registry data format demo program.
@@ -1529,26 +1454,35 @@
return;
}
+/**********************************************************************************
+ * SetLoadLevel [Internal]
+ *
+ * set level to 0 for loading system files
+ * set level to 1 for loading user files
+ */
+static void SetLoadLevel(int level)
+{
+ struct set_registry_levels_request *req = get_req_buffer();
+
+ req->current = level;
+ req->saving = 0;
+ req->version = 1;
+ server_call( REQ_SET_REGISTRY_LEVELS );
+}
/**********************************************************************************
* SHELL_LoadRegistry [Internal]
*/
void SHELL_LoadRegistry( void )
{
- struct set_registry_levels_request *req = get_req_buffer();
- int save_timeout;
- char *fn, *home;
- HKEY hkey;
+ int save_timeout;
+ char *fn, *home;
+ HKEY hkey;
TRACE("(void)\n");
REGISTRY_Init();
-
- /* set level to 0 for loading system files */
- req->current = 0;
- req->saving = 0;
- req->version = 1;
- server_call( REQ_SET_REGISTRY_LEVELS );
+ SetLoadLevel(0);
if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1))
{
@@ -1558,9 +1492,9 @@
if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1))
{
/* Load windows 95 entries */
- _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE);
- _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE);
- _w95_loadreg("user.dat", HKEY_USERS);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, "system.dat", 0);
+ NativeRegLoadKey(HKEY_CURRENT_USER, "user.dat", 1);
}
if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1))
{
@@ -1572,7 +1506,7 @@
strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
- _nt_loadreg( HKEY_USERS, fn );
+ NativeRegLoadKey( HKEY_CURRENT_USER, fn, 1 );
}
/*
* FIXME
@@ -1582,19 +1516,19 @@
strcpy(home, fn);
strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
- _nt_loadreg(HKEY_LOCAL_MACHINE, home);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
strcpy(home, fn);
strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
- _nt_loadreg(HKEY_LOCAL_MACHINE, home);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
strcpy(home, fn);
strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
- _nt_loadreg(HKEY_LOCAL_MACHINE, home);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
strcpy(home, fn);
strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
- _nt_loadreg(HKEY_LOCAL_MACHINE, home);
+ NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
free (home);
free (fn);
@@ -1616,11 +1550,7 @@
_wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
}
- /* set level to 1 for loading user files */
- req->current = 1;
- req->saving = 0;
- req->version = 1;
- server_call( REQ_SET_REGISTRY_LEVELS );
+ SetLoadLevel(1);
/*
* Load the user saved registries