New implementation of the win95 registry loader.

This commit is contained in:
Juergen Schmied 2000-01-15 23:42:50 +00:00 committed by Alexandre Julliard
parent 927525a9b3
commit 271ba29e39
1 changed files with 359 additions and 429 deletions

View File

@ -670,18 +670,16 @@ static void _wine_loadreg( HKEY hkey, char *fn )
#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 @@ typedef struct
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 @@ LPSTR _strdupnA( LPCSTR str, int len )
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 @@ int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
* - 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 @@ error:
* 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 @@ int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
}
}
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 @@ error: ERR_(reg)("error reading lf block\n");
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 @@ int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
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 @@ error: ERR_(reg)("error reading nk block\n");
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 @@ void _w31_loadreg(void) {
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 @@ void SHELL_LoadRegistry( void )
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 @@ void SHELL_LoadRegistry( void )
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 @@ void SHELL_LoadRegistry( void )
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 @@ void SHELL_LoadRegistry( void )
_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