home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
- /* ====================================================================
- * reg.c
- * XP Registry functions
- * ====================================================================
- */
-
- /* Preprocessor Defines
- * STANDALONE_REGISTRY - define if not linking with Navigator
- * NOCACHE_HDR - define if multi-threaded access to registry
- * SELF_REPAIR - define to skip header update on open
- * VERIFY_READ - define TRUE to double-check short reads
- */
- #define NOCACHE_HDR 1
- #define SELF_REPAIR 1
- #ifdef DEBUG
- #define VERIFY_READ 1
- #endif
-
- #ifndef STANDALONE_REGISTRY
- #include "xp_mcom.h"
- #include "xp_error.h"
- #include "prmon.h"
- #include "prefapi.h"
- #else
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
-
- #ifdef SUNOS4
- #include <unistd.h> /* for SEEK_SET */
- #endif /* SUNOS4 */
- #endif /* STANDALONE_REGISTRY */
-
- #include "reg.h"
- #include "NSReg.h"
-
-
- /* NOTE! It is EXREMELY important that node names be in UTF-8; otherwise
- * backwards path search for delim char will fail for multi-byte/Unicode names.
- * SmartUpdate will also break, as it relies on Java's UTF-8 -> Unicode
- * conversion, which will fail if the text is not actually valid UTF-8
- */
-
- /* ====================================================================
- * Overview
- * --------------------------------------------------------------------
- *
- * Layers:
- * Interface
- * Path Parsing
- * Key/Entry Management
- * Block I/O
- * Virtual I/O
- *
- * The functions in this file search and add to a binary Registry file
- * quite efficiently. So efficiently, squeezing out space left by
- * deleted and updated objects requires a separate "pack" operation.
- *
- * Terms:
- * As used here, a 'key' is a node in the tree. The root of the tree
- * exists in an otherwise empty Registry as is itself a key. Every key
- * has 0 or more sub-keys. Every key also has 0 or more 'entry's. Both
- * entries and keys have names. Entries also have values associated.
- * Names and values are simply strings of characters. These strings
- * may be quoted so that they can include path delimiter and equals
- * sign characters which are otherwise reserved.
- * ====================================================================
- */
-
- /* --------------------------------------------------------------------
- * Module Global Data
- * --------------------------------------------------------------------
- */
-
- static REGFILE *RegList = NULL;
- static XP_Bool bRegStarted = FALSE;
- #if !defined(STANDALONE_REGISTRY)
- static PRMonitor *reglist_monitor;
- #endif
-
-
-
- /* --------------------------------------------------------------------
- * Registry List management
- * --------------------------------------------------------------------
- */
- static void nr_AddNode(REGFILE* pReg);
- static void nr_DeleteNode(REGFILE *pReg);
- static REGFILE* vr_findRegFile(char *filename);
- /* -------------------------------------------------------------------- */
-
- static void nr_AddNode(REGFILE* pReg)
- {
- /* add node to head of list */
- pReg->next = RegList;
- pReg->prev = NULL;
-
- RegList = pReg;
-
- if ( pReg->next != NULL ) {
- pReg->next->prev = pReg;
- }
- }
-
- static void nr_DeleteNode(REGFILE* pReg)
- {
- /* if at head of list... */
- if ( pReg->prev == NULL ) {
- RegList = pReg->next;
- }
- else {
- pReg->prev->next = pReg->next;
- }
-
- if ( pReg->next != NULL ) {
- pReg->next->prev = pReg->prev;
- }
-
- /* free memory */
- #ifndef STANDALONE_REGISTRY
- if ( pReg->monitor != NULL )
- PR_DestroyMonitor( pReg->monitor );
- #endif
- XP_FREEIF( pReg->filename );
- XP_FREE( pReg );
- }
-
- static REGFILE* vr_findRegFile(char *filename)
- {
- REGFILE *pReg;
-
- pReg = RegList;
- while( pReg != NULL ) {
- #ifdef XP_UNIX
- if ( 0 == XP_STRCMP( filename, pReg->filename ) ) {
- #else
- if ( 0 == XP_STRCASECMP( filename, pReg->filename ) ) {
- #endif
- break;
- }
- pReg = pReg->next;
- }
-
- return pReg;
- }
-
-
- /* --------------------------------------------------------------------
- * Virtual I/O
- * Platform-specifics go in this section
- * --------------------------------------------------------------------
- */
- static REGERR nr_OpenFile(char *path, FILEHANDLE *fh);
- static REGERR nr_CloseFile(FILEHANDLE *fh); /* Note: fh is a pointer */
- static REGERR nr_ReadFile(FILEHANDLE fh, REGOFF offset, int32 len, void *buffer);
- static REGERR nr_WriteFile(FILEHANDLE fh, REGOFF offset, int32 len, void *buffer);
- static REGERR nr_LockRange(FILEHANDLE fh, REGOFF offset, int32 len);
- static REGERR nr_UnlockRange(FILEHANDLE fh, REGOFF offset, int32 len);
- static int32 nr_GetFileLength(FILEHANDLE fh);
- /* -------------------------------------------------------------------- */
-
-
-
- static REGERR nr_OpenFile(char *path, FILEHANDLE *fh)
- {
- XP_ASSERT( path != NULL );
- XP_ASSERT( fh != NULL );
-
- /* Open the file for exclusive random read/write */
- (*fh) = XP_FileOpen(path, xpRegistry, XP_FILE_UPDATE_BIN);
- if ( !VALID_FILEHANDLE(*fh) )
- {
- switch (errno)
- {
- case ENOENT: /* file not found */
- return REGERR_NOFILE;
-
- case EACCES: /* file in use */
- /* DVNOTE: should we try read only? */
- (*fh) = XP_FileOpen(path, xpRegistry, XP_FILE_READ_BIN);
- if ( VALID_FILEHANDLE(*fh) )
- return REGERR_READONLY;
- else
- return REGERR_FAIL;
-
- case EMFILE: /* too many files open */
- default:
- return REGERR_FAIL;
- }
- }
-
- return REGERR_OK;
-
- } /* OpenFile */
-
-
-
- static REGERR nr_CloseFile(FILEHANDLE *fh)
- {
- /* NOTE: 'fh' is a pointer, unlike other Close functions
- * This is necessary so that nr_CloseFile can set it to NULL
- */
-
- XP_ASSERT( fh != NULL );
- if ( VALID_FILEHANDLE(*fh) )
- XP_FileClose(*fh);
- (*fh) = NULL;
- return REGERR_OK;
-
- } /* CloseFile */
-
-
-
- static REGERR nr_ReadFile(FILEHANDLE fh, REGOFF offset, int32 len, void *buffer)
- {
- #if VERIFY_READ
- #define FILLCHAR 0xCC
- unsigned char* p;
- unsigned char* dbgend = (unsigned char*)buffer+len;
- #endif
-
- int32 readlen;
- REGERR err = REGERR_OK;
-
- XP_ASSERT(len > 0);
- XP_ASSERT(buffer != NULL);
- XP_ASSERT(fh != NULL);
-
- #if VERIFY_READ
- memset(buffer, FILLCHAR, len);
- #endif
-
- if (XP_FileSeek(fh, offset, SEEK_SET) != 0 ) {
- err = REGERR_FAIL;
- }
- else {
- readlen = XP_FileRead(buffer, len, fh );
- /* PR_READ() returns an unreliable length, check EOF separately */
- if (readlen < 0) {
- if (errno == EBADF) /* bad file handle, not open for read, etc. */
- err = REGERR_FAIL;
- else
- err = REGERR_BADREAD;
- }
- else if (readlen < len) {
- #if VERIFY_READ
- /* PR_READ() says we hit EOF but return length is unreliable. */
- /* If buffer has new data beyond what PR_READ() says it got */
- /* we'll assume the read was OK--this is a gamble but */
- /* missing errors will cause fewer problems than too many. */
- p = (unsigned char*)buffer+readlen;
- while ( (*p == (unsigned char)FILLCHAR) && (p < dbgend) ) {
- p++;
- }
-
- /* really was EOF if it's all FILLCHAR's */
- if ( p == dbgend ) {
- err = REGERR_BADREAD;
- }
- #else
- err = REGERR_BADREAD;
- #endif
- }
- }
-
- return err;
-
- } /* ReadFile */
-
-
-
- static REGERR nr_WriteFile(FILEHANDLE fh, REGOFF offset, int32 len, void *buffer)
- {
-
- /* Note: 'offset' will commonly be the end of the file, in which
- * case this function extends the file to 'offset'+'len'. This may
- * be a two-step operation on some platforms.
- */
- XP_ASSERT(len > 0);
- XP_ASSERT(buffer);
- XP_ASSERT(fh != NULL);
-
- if (XP_FileSeek(fh, offset, SEEK_SET) != 0)
- return REGERR_FAIL;
-
- if ((int32)XP_FileWrite(buffer, len, fh) != len)
- {
- /* disk full or some other catastrophic error */
- return REGERR_FAIL;
- }
-
- return REGERR_OK;
-
- } /* WriteFile */
-
-
-
- static REGERR nr_LockRange(FILEHANDLE fh, REGOFF offset, int32 len)
- {
- /* TODO: Implement XP lock function with built-in retry. */
-
- return REGERR_OK;
-
- } /* LockRange */
-
-
-
- static REGERR nr_UnlockRange(FILEHANDLE fh, REGOFF offset, int32 len)
- {
- /* TODO: Implement XP unlock function with built-in retry. */
-
- XP_FileFlush( fh );
- return REGERR_OK;
-
- } /* UnlockRange */
-
-
-
- #if SELF_REPAIR
- static int32 nr_GetFileLength(FILEHANDLE fh)
- {
- int32 length;
- int32 curpos;
-
- curpos = XP_FileTell(fh);
- XP_FileSeek(fh, 0, SEEK_END);
- length = XP_FileTell(fh);
- XP_FileSeek(fh, curpos, SEEK_SET);
- return length;
-
- } /* GetFileLength */
- #endif
-
-
-
- /* --------------------------------------------------------------------
- * Numeric converters
- * --------------------------------------------------------------------
- * The converters read and write integers in a common format so we
- * can transport registries without worrying about endian problems.
- *
- * The buffers *MUST* be the appropriate size!
- * --------------------------------------------------------------------
- */
- static uint32 nr_ReadLong(char *buffer);
- static uint16 nr_ReadShort(char *buffer);
- static void nr_WriteLong(uint32 num, char *buffer);
- static void nr_WriteShort(uint16 num, char *buffer);
- /* -------------------------------------------------------------------- */
-
-
-
- static uint16 nr_ReadShort(char *buffer)
- {
- uint16 val;
- uint8 *p = (uint8*)buffer;
-
- val = *p + (uint16)( *(p+1) * 0x100 );
-
- return val;
- }
-
-
-
- static uint32 nr_ReadLong(char *buffer)
- {
- uint32 val;
- uint8 *p = (uint8*)buffer;
-
- val = *p
- + (uint32)(*(p+1) * 0x100L)
- + (uint32)(*(p+2) * 0x10000L )
- + (uint32)(*(p+3) * 0x1000000L );
-
- return val;
- }
-
-
-
- static void nr_WriteLong(uint32 num, char *buffer)
- {
- uint8 *p = (uint8*)buffer;
- *p++ = (uint8)(num & 0x000000FF);
- num /= 0x100;
- *p++ = (uint8)(num & 0x000000FF);
- num /= 0x100;
- *p++ = (uint8)(num & 0x000000FF);
- num /= 0x100;
- *p = (uint8)(num & 0x000000FF);
- }
-
-
-
- static void nr_WriteShort(uint16 num, char *buffer)
- {
- uint8 *p = (uint8*)buffer;
-
- *p = (uint8)(num & 0x00FF);
- *(p+1) = (uint8)(num / 0x100);
- }
-
-
-
- /* --------------------------------------------------------------------
- * Block I/O
- * --------------------------------------------------------------------
- */
- static REGERR nr_ReadHdr(REGFILE *reg); /* Reads the file header, creates file if empty */
- static REGERR nr_WriteHdr(REGFILE *reg); /* Writes the file header */
- static REGERR nr_CreateRoot(REGFILE *reg);
-
- static REGERR nr_Lock(REGFILE *reg);
- static REGERR nr_Unlock(REGFILE *reg);
-
- static REGERR nr_ReadDesc(REGFILE *reg, REGOFF offset, REGDESC *desc); /* reads a desc */
- static REGERR nr_ReadName(REGFILE *reg, REGDESC *desc, uint32 buflen, char *buf);
- static REGERR nr_ReadData(REGFILE *reg, REGDESC *desc, uint32 buflen, char *buf);
-
- static REGERR nr_WriteDesc(REGFILE *reg, REGDESC *desc); /* writes a desc */
- static REGERR nr_WriteString(REGFILE *reg, char *string, REGDESC *desc); /* writes a string */
- static REGERR nr_WriteData(REGFILE *reg, char *string, uint32 len, REGDESC *desc); /* writes a string */
-
- static REGERR nr_AppendDesc(REGFILE *reg, REGDESC *desc, REGOFF *result); /* adds a desc */
- static REGERR nr_AppendName(REGFILE *reg, char *name, REGDESC *desc); /* adds a name */
- static REGERR nr_AppendString(REGFILE *reg, char *string, REGDESC *desc); /* adds a string */
- static REGERR nr_AppendData(REGFILE *reg, char *string, uint32 len, REGDESC *desc); /* adds a string */
- /* -------------------------------------------------------------------- */
-
-
-
- static REGERR nr_ReadHdr(REGFILE *reg)
- {
-
- int err;
- long filelength;
- char hdrBuf[sizeof(REGHDR)];
-
- XP_ASSERT(reg);
- reg->hdrDirty = 0;
-
- err = nr_ReadFile(reg->fh, 0, sizeof(REGHDR), &hdrBuf);
-
- switch (err)
- {
- case REGERR_BADREAD:
- /* header doesn't exist, so create one */
- err = nr_CreateRoot(reg);
- break;
-
- case REGERR_OK:
- /* header read successfully -- convert */
- reg->hdr.magic = nr_ReadLong ( hdrBuf + HDR_MAGIC );
- reg->hdr.verMajor = nr_ReadShort( hdrBuf + HDR_VERMAJOR );
- reg->hdr.verMinor = nr_ReadShort( hdrBuf + HDR_VERMINOR );
- reg->hdr.avail = nr_ReadLong ( hdrBuf + HDR_AVAIL );
- reg->hdr.root = nr_ReadLong ( hdrBuf + HDR_ROOT );
-
- /* check to see if it's the right file type */
- if (reg->hdr.magic != MAGIC_NUMBER) {
- err = REGERR_BADMAGIC;
- break;
- }
-
- /* Check registry version
- * If the major version is bumped we're incompatible
- * (minor version just means some new features were added)
- *
- * Upgrade code will go here in the future...
- */
- if ( reg->hdr.verMajor > MAJOR_VERSION ) {
- err = REGERR_REGVERSION;
- break;
- }
-
- #if SELF_REPAIR
- if ( reg->inInit && !(reg->readOnly) ) {
- filelength = nr_GetFileLength(reg->fh);
- if (reg->hdr.avail != filelength)
- {
- reg->hdr.avail = filelength;
- reg->hdrDirty = 1;
- #if NOCACHE_HDR
- err = nr_WriteHdr(reg);
- #endif
- }
- }
- #endif /* SELF_REPAIR */
- break;
-
- default:
- /* unexpected error from nr_ReadFile()*/
- XP_ASSERT(FALSE);
- err = REGERR_FAIL;
- break;
- } /* switch */
-
- return err;
-
- } /* ReadHdr */
-
-
-
- static REGERR nr_WriteHdr(REGFILE *reg)
- {
- REGERR err;
- char hdrBuf[sizeof(REGHDR)];
-
- XP_ASSERT(reg);
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- /* convert to XP int format */
- nr_WriteLong ( reg->hdr.magic, hdrBuf + HDR_MAGIC );
- nr_WriteShort( reg->hdr.verMajor, hdrBuf + HDR_VERMAJOR );
- nr_WriteShort( reg->hdr.verMinor, hdrBuf + HDR_VERMINOR );
- nr_WriteLong ( reg->hdr.avail, hdrBuf + HDR_AVAIL );
- nr_WriteLong ( reg->hdr.root, hdrBuf + HDR_ROOT );
-
- /* err = nr_WriteFile(reg->fh, 0, sizeof(REGHDR), ®->hdr); */
- err = nr_WriteFile(reg->fh, 0, sizeof(REGHDR), &hdrBuf);
-
- if (err == REGERR_OK)
- reg->hdrDirty = 0;
-
- return err;
-
- } /* WriteHdr */
-
-
-
- static REGERR nr_CreateRoot(REGFILE *reg)
- {
- /* Called when an empty file is detected by ReadHdr */
- REGERR err;
- REGDESC root;
-
- XP_ASSERT(reg);
-
- /* Create 'hdr' */
- reg->hdr.magic = MAGIC_NUMBER;
- reg->hdr.verMajor = MAJOR_VERSION;
- reg->hdr.verMinor = MINOR_VERSION;
- reg->hdr.root = 0;
- reg->hdr.avail = HDRRESERVE;
-
- /* Create root descriptor */
- root.location = 0;
- root.left = 0;
- root.value = 0;
- root.down = 0;
- root.type = REGTYPE_KEY;
- root.valuelen = 0;
- root.valuebuf = 0;
- root.parent = 0;
-
- err = nr_AppendName(reg, ROOTKEY_STR, &root);
- if (err != REGERR_OK)
- return err;
-
- err = nr_AppendDesc(reg, &root, ®->hdr.root);
- if (err != REGERR_OK)
- return err;
-
- return nr_WriteHdr(reg); /* actually commit to disk */
-
- /* Create standard top-level nodes */
-
- } /* CreateRoot */
-
-
-
- static REGERR nr_Lock(REGFILE *reg)
- {
-
- REGERR err;
-
- /* lock header */
- err = nr_LockRange(reg->fh, 0, sizeof(REGHDR));
- if (err != REGERR_OK)
- return err;
-
- #ifndef STANDALONE_REGISTRY
- PR_EnterMonitor( reg->monitor );
- #endif
-
- return nr_ReadHdr(reg);
-
- } /* Lock */
-
-
-
- static REGERR nr_Unlock(REGFILE *reg)
- {
- #ifndef STANDALONE_REGISTRY
- PR_ExitMonitor( reg->monitor );
- #endif
-
- return nr_UnlockRange(reg->fh, 0, sizeof(REGHDR));
- } /* Unlock */
-
-
-
- static REGERR nr_ReadDesc(REGFILE *reg, REGOFF offset, REGDESC *desc)
- {
-
- REGERR err;
- char descBuf[ DESC_SIZE ];
-
- XP_ASSERT(reg);
- XP_ASSERT(offset >= HDRRESERVE);
- XP_ASSERT(offset < reg->hdr.avail);
- XP_ASSERT(desc);
-
- err = nr_ReadFile(reg->fh, offset, DESC_SIZE, &descBuf);
- if (err == REGERR_OK)
- {
- desc->location = nr_ReadLong ( descBuf + DESC_LOCATION );
- desc->name = nr_ReadLong ( descBuf + DESC_NAME );
- desc->namelen = nr_ReadShort( descBuf + DESC_NAMELEN );
- desc->type = nr_ReadShort( descBuf + DESC_TYPE );
- desc->left = nr_ReadLong ( descBuf + DESC_LEFT );
- desc->value = nr_ReadLong ( descBuf + DESC_VALUE );
- desc->valuelen = nr_ReadLong ( descBuf + DESC_VALUELEN );
- desc->parent = nr_ReadLong ( descBuf + DESC_PARENT );
-
- if ( TYPE_IS_ENTRY(desc->type) ) {
- desc->down = 0;
- desc->valuebuf = nr_ReadShort( descBuf + DESC_VALUEBUF );
- }
- else { /* TYPE is KEY */
- desc->down = nr_ReadLong( descBuf + DESC_DOWN );
- desc->valuebuf = 0;
- }
-
- if (desc->location != offset)
- err = REGERR_BADLOCN;
- else if ( desc->type & REGTYPE_DELETED )
- err = REGERR_DELETED;
- }
-
- return err;
-
- } /* ReadDesc */
-
-
-
- static REGERR nr_ReadName(REGFILE *reg, REGDESC *desc, uint32 buflen, char *buf)
- {
-
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(desc->name > 0);
- XP_ASSERT(desc->name < reg->hdr.avail);
- XP_ASSERT(buflen > 0);
- XP_ASSERT(buf);
-
- if ( desc->namelen > buflen )
- return REGERR_BUFTOOSMALL;
-
- err = nr_ReadFile(reg->fh, desc->name, desc->namelen, buf);
-
- buf[buflen-1] = '\0'; /* avoid runaways */
-
- return err;
-
- } /* ReadName */
-
-
-
- static REGERR nr_ReadData(REGFILE *reg, REGDESC *desc, uint32 buflen, char *buf)
- {
-
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(desc->value > 0);
- XP_ASSERT(desc->value < reg->hdr.avail);
- XP_ASSERT(buflen > 0);
- XP_ASSERT(buf);
-
- if ( desc->valuelen > buflen )
- return REGERR_BUFTOOSMALL;
-
- err = nr_ReadFile(reg->fh, desc->value, desc->valuelen, buf);
-
- return err;
-
- } /* nr_ReadData */
-
-
-
- static REGERR nr_WriteDesc(REGFILE *reg, REGDESC *desc)
- {
- char descBuf[ DESC_SIZE ];
-
- XP_ASSERT(reg);
- XP_ASSERT(desc);
- XP_ASSERT( desc->location >= HDRRESERVE );
- XP_ASSERT( desc->location < reg->hdr.avail );
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- /* convert to XP int format */
- nr_WriteLong ( desc->location, descBuf + DESC_LOCATION );
- nr_WriteLong ( desc->name, descBuf + DESC_NAME );
- nr_WriteShort( desc->namelen, descBuf + DESC_NAMELEN );
- nr_WriteShort( desc->type, descBuf + DESC_TYPE );
- nr_WriteLong ( desc->left, descBuf + DESC_LEFT );
- nr_WriteLong ( desc->value, descBuf + DESC_VALUE );
- nr_WriteLong ( desc->valuelen, descBuf + DESC_VALUELEN );
- nr_WriteLong ( desc->parent, descBuf + DESC_PARENT );
-
- if ( TYPE_IS_ENTRY(desc->type) ) {
- XP_ASSERT( 0 == desc->down );
- nr_WriteLong( desc->valuebuf, descBuf + DESC_VALUEBUF );
- }
- else { /* TYPE is KEY */
- XP_ASSERT( 0 == desc->valuebuf );
- nr_WriteLong( desc->down, descBuf + DESC_DOWN );
- }
-
- return nr_WriteFile(reg->fh, desc->location, DESC_SIZE, descBuf);
- } /* nr_WriteDesc */
-
-
-
- static REGERR nr_AppendDesc(REGFILE *reg, REGDESC *desc, REGOFF *result)
- {
-
- REGERR err;
- char descBuf[ DESC_SIZE ];
-
- XP_ASSERT(reg);
- XP_ASSERT(desc);
- XP_ASSERT(result);
-
- *result = 0;
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- desc->location = reg->hdr.avail;
-
- /* convert to XP int format */
- nr_WriteLong ( desc->location, descBuf + DESC_LOCATION );
- nr_WriteLong ( desc->name, descBuf + DESC_NAME );
- nr_WriteShort( desc->namelen, descBuf + DESC_NAMELEN );
- nr_WriteShort( desc->type, descBuf + DESC_TYPE );
- nr_WriteLong ( desc->left, descBuf + DESC_LEFT );
- nr_WriteLong ( desc->value, descBuf + DESC_VALUE );
- nr_WriteLong ( desc->valuelen, descBuf + DESC_VALUELEN );
- nr_WriteLong ( desc->parent, descBuf + DESC_PARENT );
-
- if ( TYPE_IS_ENTRY(desc->type) ) {
- XP_ASSERT( 0 == desc->down );
- nr_WriteLong( desc->valuebuf, descBuf + DESC_VALUEBUF );
- }
- else { /* TYPE is KEY */
- XP_ASSERT( 0 == desc->valuebuf );
- nr_WriteLong( desc->down, descBuf + DESC_DOWN );
- }
-
- err = nr_WriteFile(reg->fh, reg->hdr.avail, DESC_SIZE, descBuf);
-
- if (err == REGERR_OK)
- {
- *result = reg->hdr.avail;
- reg->hdr.avail += DESC_SIZE;
- reg->hdrDirty = 1;
- #if NOCACHE_HDR
- err = nr_WriteHdr(reg);
- #endif
- }
-
- return err;
-
- } /* AppendDesc */
-
-
-
- static REGERR nr_AppendName(REGFILE *reg, char *name, REGDESC *desc)
- {
- REGERR err;
- int len;
- char *p;
-
- XP_ASSERT(reg);
- XP_ASSERT(name);
- XP_ASSERT(desc);
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- len = XP_STRLEN(name) + 1;
-
- /* check for valid name parameter */
- if ( len == 1 )
- return REGERR_PARAM;
-
- if ( len > MAXREGNAMELEN )
- return REGERR_NAMETOOLONG;
-
- for ( p = name; (*p != 0); p++ ) {
- if ( INVALID_NAME_CHAR(*p) )
- return REGERR_BADNAME;
- }
-
- /* save the name */
- err = nr_WriteFile(reg->fh, reg->hdr.avail, len, name);
-
- /* if write successful update the desc and hdr */
- if (err == REGERR_OK)
- {
- desc->namelen = (uint16)len;
- desc->name = reg->hdr.avail;
- reg->hdr.avail += len;
- reg->hdrDirty = 1;
- #if NOCACHE_HDR
- err = nr_WriteHdr(reg);
- #endif
- }
-
- return err;
-
- } /* nr_AppendName */
-
-
-
- static REGERR nr_WriteString(REGFILE *reg, char *string, REGDESC *desc)
- {
- uint32 len;
-
- XP_ASSERT(string);
- if (reg->readOnly)
- return REGERR_READONLY;
- len = XP_STRLEN(string) + 1;
-
- return nr_WriteData( reg, string, len, desc );
-
- } /* nr_WriteString */
-
-
-
- static REGERR nr_WriteData(REGFILE *reg, char *string, uint32 len, REGDESC *desc)
- {
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(string);
- XP_ASSERT(desc);
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- if ( len == 0 )
- return REGERR_PARAM;
-
- if ( len > MAXREGVALUELEN )
- return REGERR_NAMETOOLONG;
-
- /* save the data in the same place if it fits */
- if ( len <= desc->valuebuf ) {
- err = nr_WriteFile( reg->fh, desc->value, len, string );
- if ( err == REGERR_OK ) {
- desc->valuelen = len;
- }
- }
- else {
- /* otherwise append new data */
- err = nr_AppendData( reg, string, len, desc );
- }
-
- return err;
-
- } /* nr_WriteData */
-
-
-
- static REGERR nr_AppendString(REGFILE *reg, char *string, REGDESC *desc)
- {
- uint32 len;
-
- XP_ASSERT(string);
- if (reg->readOnly)
- return REGERR_READONLY;
- len = XP_STRLEN(string) + 1;
-
- return nr_AppendData( reg, string, len, desc );
-
- } /* nr_AppendString */
-
-
-
- static REGERR nr_AppendData(REGFILE *reg, char *string, uint32 len, REGDESC *desc)
- {
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(string);
- XP_ASSERT(desc);
-
- if (reg->readOnly)
- return REGERR_READONLY;
-
- if ( len == 0 )
- return REGERR_PARAM;
-
- if ( len > MAXREGVALUELEN )
- return REGERR_NAMETOOLONG;
-
- /* save the string */
- err = nr_WriteFile(reg->fh, reg->hdr.avail, len, string);
- if (err == REGERR_OK)
- {
- desc->value = reg->hdr.avail;
- desc->valuelen = len;
- desc->valuebuf = len;
-
- reg->hdr.avail += len;
- reg->hdrDirty = 1;
- #if NOCACHE_HDR
- err = nr_WriteHdr(reg);
- #endif
- }
-
- return err;
-
- } /* nr_AppendData */
-
-
-
- /* --------------------------------------------------------------------
- * Path Parsing
- * --------------------------------------------------------------------
- */
- static REGERR nr_NextName(char *pPath, char *buf, uint32 bufsize, char **newPath);
- static REGERR nr_RemoveName(char *path);
- static REGERR nr_CatName(REGFILE *reg, REGOFF node, char *path, uint32 bufsize,
- REGDESC *desc);
- static REGERR nr_ReplaceName(REGFILE *reg, REGOFF node, char *path,
- uint32 bufsize, REGDESC *desc);
-
- #if 0 /* old interface */
- static char * nr_LastDelim(char *pPath);
- static Bool nr_IsQualifiedEntry(char *pPath);
- static REGERR nr_SplitEntry(char *pPath, char **name, char **value);
- static REGERR nr_CatNameValue(char *path, int bufsize, REGDESC *desc);
- static REGERR nr_ReplaceNameValue(char *path, int bufsize, REGDESC *desc);
- #endif
- /* -------------------------------------------------------------------- */
-
-
- /* Scans path at 'pPath' and copies next name segment into 'buf'.
- * Also sets 'newPath' to point at the next segment of pPath.
- */
- static REGERR nr_NextName(char *pPath, char *buf, uint32 bufsize, char **newPath)
- {
- uint32 len = 0;
- REGERR err = REGERR_OK;
-
- /* initialization and validation */
- XP_ASSERT(buf);
-
- *newPath = NULL;
- *buf = '\0';
-
- if ( pPath==NULL || *pPath=='\0' )
- return REGERR_NOMORE;
-
- /* ... skip an initial path delimiter */
- if ( *pPath == PATHDEL ) {
- pPath++;
-
- if ( *pPath == '\0' )
- return REGERR_NOMORE;
- }
-
- /* ... missing name segment or initial blank are errors*/
- if ( *pPath == PATHDEL || *pPath == ' ' )
- return REGERR_BADNAME;
-
- /* copy first path segment into return buf */
- while ( *pPath != '\0' && *pPath != PATHDEL )
- {
- if ( len == bufsize ) {
- err = REGERR_NAMETOOLONG;
- break;
- }
- if ( *pPath < ' ' && *pPath > 0 )
- return REGERR_BADNAME;
-
- *buf++ = *pPath++;
- len++;
- }
- *buf = '\0';
-
- /* ... name segment can't end with blanks, either */
- if ( ' ' == *(buf-1) )
- return REGERR_BADNAME;
-
- /* return a pointer to the start of the next segment */
- *newPath = pPath;
-
- return err;
-
- } /* nr_NextName */
-
-
-
- static REGERR nr_CatName(REGFILE *reg, REGOFF node, char *path, uint32 bufsize, REGDESC *desc)
- {
- REGERR err = REGERR_OK;
-
- char *p;
- uint32 len = XP_STRLEN(path);
-
- if (len > 0)
- {
- p = &path[len-1];
- if (*p != PATHDEL)
- {
- if ( len < bufsize ) {
- p++;
- *p = PATHDEL;
- len++;
- }
- else
- err = REGERR_BUFTOOSMALL;
- }
- p++; /* point one past PATHDEL */
- }
- else
- p = path;
-
- if ( err == REGERR_OK ) {
- err = nr_ReadDesc( reg, node, desc );
- if ( err == REGERR_OK ) {
- err = nr_ReadName( reg, desc, bufsize-len, p );
- }
- }
-
- return err;
-
- } /* CatName */
-
-
-
- static REGERR nr_ReplaceName(REGFILE *reg, REGOFF node, char *path, uint32 bufsize, REGDESC *desc)
- {
- /* NOTE! It is EXREMELY important that names be in UTF-8; otherwise
- * the backwards path search will fail for multi-byte/Unicode names
- */
-
- char *p;
- uint32 len;
- REGERR err;
-
- XP_ASSERT(path);
-
- len = XP_STRLEN(path);
- if ( len > bufsize )
- return REGERR_PARAM;
-
- if ( len > 0 ) {
- p = &path[len-1];
-
- while ((p > path) && (*p != PATHDEL)) {
- --p;
- --len;
- }
- if ( *p == PATHDEL ) {
- p++;
- len++;
- }
- }
- else
- p = path;
-
-
- err = nr_ReadDesc( reg, node, desc );
- if ( err == REGERR_OK ) {
- err = nr_ReadName( reg, desc, bufsize-len, p );
- }
-
- return err;
-
- } /* ReplaceName */
-
-
- static REGERR nr_RemoveName(char *path)
- {
- /* Typical inputs:
- * path = "/Machine/4.0/" output = "/Machine"
- * path = "/Machine" output = ""
- * path = "" output = REGERR_NOMORE
- *
- * NOTE! It is EXREMELY important that names be in UTF-8; otherwise
- * the backwards path search will fail for multi-byte/Unicode names
- */
-
- int len = XP_STRLEN(path);
- char *p;
- if (len < 1)
- return REGERR_NOMORE;
-
- p = &path[len-1];
- /* if last char is '/', ignore it */
- if (*p == PATHDEL)
- p--;
-
- while ((p > path) && (*p != PATHDEL))
- p--;
-
- /* if (*p != PATHDEL)
- return REGERR_NOMORE;
- */
-
- *p = '\0';
- return REGERR_OK;
-
- } /* RemoveName */
-
-
-
- /* --------------------------------------------------------------------
- * Key/Entry Management
- * --------------------------------------------------------------------
- */
- static REGERR nr_Find(REGFILE *reg, REGOFF offParent, char *pPath,
- REGDESC *pDesc, REGOFF *pPrev, REGOFF *pParent);
-
- static REGERR nr_FindAtLevel(REGFILE *reg, REGOFF offFirst, char *pName,
- REGDESC *pDesc, REGOFF *pOffPrev);
-
- static REGERR nr_CreateSubKey(REGFILE *reg, REGDESC *pParent, char *name);
- static REGERR nr_CreateEntryString(REGFILE *reg, REGDESC *pParent,
- char *name, char *value);
- static REGERR nr_CreateEntry(REGFILE *reg, REGDESC *pParent, char *name,
- uint16 type, char *buffer, uint32 length);
- /* -------------------------------------------------------------------- */
-
-
-
- static REGERR nr_Find(REGFILE *reg,
- REGOFF offParent,
- char *pPath,
- REGDESC *pDesc,
- REGOFF *pPrev,
- REGOFF *pParent)
- {
-
- REGERR err;
- REGDESC desc;
- REGOFF offPrev = 0;
- char namebuf[MAXREGNAMELEN];
- char *p;
-
- XP_ASSERT( pPath != NULL );
- XP_ASSERT( offParent >= HDRRESERVE );
- XP_ASSERT( VALID_FILEHANDLE( reg->fh ) );
-
- if (pPrev)
- *pPrev = 0;
- if (pParent)
- *pParent = 0;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, offParent, &desc);
-
- /* Walk 'path', reading keys into 'desc' */
- p = pPath;
- while ( err == REGERR_OK ) {
-
- err = nr_NextName(p, namebuf, sizeof(namebuf), &p);
-
- if ( err == REGERR_OK ) {
- /* save current location as parent of next segment */
- offParent = desc.location;
- /* look for name at next level down */
- err = nr_FindAtLevel(reg, desc.down, namebuf, &desc, &offPrev);
- }
- }
-
- if ( err == REGERR_NOMORE ) {
- /* we found all the segments of the path--success! */
- err = REGERR_OK;
-
- if (pDesc) {
- COPYDESC(pDesc, &desc);
- }
- if (pPrev) {
- *pPrev = offPrev;
- }
- if (pParent) {
- *pParent = offParent;
- }
- }
-
- return err;
-
- } /* nr_Find */
-
-
- /* nr_FindAtLevel -- looks for a node matching "pName" on the level starting
- * with "offset". Returns REGERR_OK if found, REGERR_NOFIND
- * if not (plus other error conditions).
- *
- * If pDesc and pOffPrev are valid pointers *AND* the name is
- * found then pDesc will point at the REGDESC of the node and
- * pOffPrev will be the offset of the desc for the previous
- * node at the same level. These values aren't touched
- * if the node is not found.
- */
- static REGERR nr_FindAtLevel(REGFILE *reg,
- REGOFF offset,
- char *pName,
- REGDESC *pDesc,
- REGOFF *pOffPrev)
- {
- char namebuf[MAXREGNAMELEN];
- REGDESC desc;
- REGERR err;
- REGOFF prev = 0;
-
- /* Note: offset=0 when there's no 'down' or 'left' */
- XP_ASSERT(reg);
- XP_ASSERT(offset < reg->hdr.avail);
- XP_ASSERT(pName);
- XP_ASSERT(*pName);
-
- while ( offset != 0 )
- {
- /* get name of next node */
- err = nr_ReadDesc(reg, offset, &desc);
- if (err != REGERR_OK)
- return err;
-
- err = nr_ReadName(reg, &desc, sizeof(namebuf), namebuf);
- if (err != REGERR_OK)
- return err;
-
- /* check to see if it's the one we want */
- if (XP_STRCASECMP(namebuf, pName) == 0) {
- /* Found it! */
- if ( pDesc != NULL ) {
- COPYDESC( pDesc, &desc );
- }
- if ( pOffPrev != NULL ) {
- *pOffPrev = prev;
- }
- return REGERR_OK;
- }
-
- /* advance to the next node */
- prev = offset;
- offset = desc.left;
- }
-
- return REGERR_NOFIND;
- } /* FindAtLevel */
-
-
-
- static REGERR nr_CreateSubKey(REGFILE *reg, REGDESC *pParent, char *name)
- {
- /* nr_CreateSubKey does NO error checking--callers *MUST*
- * ensure that there are no duplicates
- */
- REGDESC desc;
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(pParent);
- XP_ASSERT(name);
-
- err = nr_AppendName(reg, name, &desc);
- if (err != REGERR_OK)
- return err;
-
- desc.type = REGTYPE_KEY;
- desc.left = pParent->down;
- desc.down = 0;
- desc.value = 0;
- desc.valuelen = 0;
- desc.valuebuf = 0;
- desc.parent = pParent->location;
-
- err = nr_AppendDesc(reg, &desc, &pParent->down);
- if (err != REGERR_OK)
- return err;
-
- /* printf("nr_CreateSubKey: %s @0x%lx\n", name, pParent->down); */
-
- err = nr_WriteDesc(reg, pParent);
- COPYDESC(pParent, &desc);
-
- return err;
-
- } /* nr_CreateSubKey */
-
-
-
- static REGERR nr_CreateEntryString(REGFILE *reg, REGDESC *pParent, char *name, char *value)
- {
- REGDESC desc;
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(pParent);
- XP_ASSERT(name);
- XP_ASSERT(value);
-
- memset( &desc, 0, sizeof(REGDESC) );
-
- err = nr_AppendName(reg, name, &desc);
- if (err != REGERR_OK)
- return err;
-
- err = nr_AppendString(reg, value, &desc);
- if (err != REGERR_OK)
- return err;
-
- desc.type = REGTYPE_ENTRY_STRING_UTF;
- desc.left = pParent->value;
- desc.down = 0;
- desc.parent = pParent->location;
-
- err = nr_AppendDesc(reg, &desc, &pParent->value);
- if (err != REGERR_OK)
- return err;
-
- /* printf("nr_AddEntry: %s=%s @0x%lx\n", name, value, pParent->value); */
-
- return nr_WriteDesc(reg, pParent);
-
- } /* nr_CreateEntryString */
-
-
-
- static REGERR nr_CreateEntry(REGFILE *reg, REGDESC *pParent, char *name,
- uint16 type, char *value, uint32 length)
- {
- REGDESC desc;
- REGERR err;
-
- XP_ASSERT(reg);
- XP_ASSERT(pParent);
- XP_ASSERT(name);
- XP_ASSERT(value);
-
- memset( &desc, 0, sizeof(REGDESC) );
-
- err = nr_AppendName(reg, name, &desc);
- if (err != REGERR_OK)
- return err;
-
- err = nr_AppendData(reg, value, length, &desc);
- if (err != REGERR_OK)
- return err;
-
- desc.type = type;
- desc.left = pParent->value;
- desc.down = 0;
- desc.parent = pParent->location;
-
- err = nr_AppendDesc(reg, &desc, &pParent->value);
- if (err != REGERR_OK)
- return err;
-
- /* printf("nr_AddEntry: %s=%s @0x%lx\n", name, value, pParent->value); */
-
- return nr_WriteDesc(reg, pParent);
-
- } /* nr_CreateEntry */
-
-
-
- #if 0 /* old interface */
- VR_INTERFACE(REGERR) NR_RegRename(RKEY key, char *path, char *newname)
- {
-
- REGDESC desc;
- REGERR err;
-
- if ( !VALID_FILEHANDLE(gReg.fh) )
- return REGERR_FAIL;
-
- /* Okay to Update to "", but names must not be null */
- if (!newname || !*newname)
- return REGERR_PARAM;
-
- err = nr_Lock(&gReg);
- if (err != REGERR_OK)
- return err;
-
- /* Find the key or entry to rename (and validate the
- incoming parameters) */
- err = nr_Find((REGOFF)key, path, &desc, 0, 0);
- if (err != REGERR_OK)
- goto cleanup;
-
- /* Write the new name string to the file and update
- the key or entry's pointer */
- err = nr_AppendName(&gReg, newname, &desc);
- if (err != REGERR_OK)
- goto cleanup;
-
- /* Write the key or entry back to the disk and return */
- err = nr_WriteDesc(&gReg, &desc);
-
- cleanup:
- nr_Unlock(&gReg);
- return err;
-
- } /* RegRename */
-
-
-
- VR_INTERFACE(REGERR) NR_RegPack(char *newfilename)
- {
-
- REGFILE dstReg;
- char *path = NULL;
- int err = REGERR_OK;
-
- dstReg.fh = NULL;
-
- if (!newfilename || !*newfilename)
- return REGERR_PARAM;
- if ( !VALID_FILEHANDLE(gReg.fh) )
- return REGERR_FAIL;
-
- /* open it & create a header by trying to read */
- err = nr_OpenFile(newfilename, &dstReg.fh);
- if (err != REGERR_OK)
- goto cleanup;
- err = nr_ReadHdr(&dstReg);
- if (err != REGERR_OK)
- goto cleanup;
-
- /* read records from the current registry file and
- add them to 'dstReg' */
- path = XP_ALLOC(PACKBUFFERSIZE);
- if (path == NULL)
- {
- err = REGERR_FAIL;
- goto cleanup;
- }
-
- XP_STRCPY(path, "/");
-
- err = nr_Lock(&gReg);
- if (err != REGERR_OK)
- goto cleanup;
-
- while (NR_RegNext( 0, PACKBUFFERSIZE, path ) == REGERR_OK)
- {
- err = nr_RegGenericAdd(&dstReg, 0, path);
- if (err != REGERR_OK)
- break;
- }
-
- nr_Unlock(&gReg);
-
- cleanup:
- XP_FREEIF(path);
- if ( VALID_FILEHANDLE(dstReg.fh) )
- {
- /* even if not caching headers it could be dirty due to an error */
- if (dstReg.hdrDirty) {
- nr_WriteHdr(&dstReg);
- }
- nr_CloseFile(&dstReg.fh);
- }
-
- return err;
-
- } /* RegPack */
-
- #endif /* old interface */
-
-
-
- /* ---------------------------------------------------------------------
- * Intermediate API
- * ---------------------------------------------------------------------
- */
- static REGOFF nr_TranslateKey( REGFILE *reg, RKEY key );
- static void nr_InitStdRkeys( REGFILE *reg );
- static Bool nr_ProtectedNode( REGFILE *reg, REGOFF key );
- static REGERR nr_RegAddKey( REGFILE *reg, RKEY key, char *path, RKEY *newKey );
- static void nr_Upgrade_1_1( REGFILE *reg );
- /* --------------------------------------------------------------------- */
-
-
- static REGOFF nr_TranslateKey( REGFILE *reg, RKEY key )
- {
- REGOFF retKey = 0;
-
- /* if it's a special key */
- if ( key < HDRRESERVE ) {
- /* ...translate it */
- switch (key)
- {
- case ROOTKEY:
- retKey = reg->hdr.root;
- break;
-
- case ROOTKEY_VERSIONS:
- retKey = reg->rkeys.versions;
- break;
-
- case ROOTKEY_USERS:
- retKey = reg->rkeys.users;
- break;
-
- case ROOTKEY_COMMON:
- retKey = reg->rkeys.common;
- break;
-
- #ifndef STANDALONE_REGISTRY
- case ROOTKEY_CURRENT_USER:
- if ( reg->rkeys.current_user == 0 ) {
- /* not initialized--find the current user key */
- RKEY userkey = 0;
- REGERR err;
- char* profName;
-
- err = PREF_CopyDefaultCharPref( "profile.name", &profName );
-
- if (err == PREF_NOERROR ) {
- /* Don't assign a slot for missing or magic profile */
- if ( '\0' == *profName ||
- 0 == XP_STRCMP(ASW_MAGIC_PROFILE_NAME, profName))
- {
- err = REGERR_FAIL;
- } else {
- err = nr_RegAddKey( reg, reg->rkeys.users, profName, &userkey );
- }
- XP_FREE(profName);
- }
- else {
- err = nr_RegAddKey( reg, reg->rkeys.users, "default", &userkey );
- }
-
- if ( err == REGERR_OK ) {
- reg->rkeys.current_user = userkey;
- }
- }
- retKey = reg->rkeys.current_user;
- break;
- #endif /* !STANDALONE_REGISTRY */
-
- case ROOTKEY_PRIVATE:
- retKey = reg->rkeys.privarea;
- break;
-
- default:
- /* not a valid key */
- retKey = 0;
- break;
- }
- }
- else {
- /* ...otherwise it's fine as-is */
- retKey = (REGOFF)key;
- }
- return ( retKey );
- } /* nr_TranslateKey */
-
-
-
- static void nr_InitStdRkeys( REGFILE *reg )
- {
- REGERR err;
- RKEY key;
- char *profName;
-
- XP_ASSERT( reg != NULL );
-
- /* initialize to invalid key values */
- memset( ®->rkeys, 0, sizeof(STDNODES) );
-
- /* Add each key before looking it up. Adding an already
- * existing key is harmless, and these MUST exist.
- */
-
- /* ROOTKEY_USERS */
- err = nr_RegAddKey( reg, reg->hdr.root, ROOTKEY_USERS_STR, &key );
- if ( err == REGERR_OK ) {
- reg->rkeys.users = key;
- }
-
- /* ROOTKEY_COMMON */
- err = nr_RegAddKey( reg, reg->hdr.root, ROOTKEY_COMMON_STR, &key );
- if ( err == REGERR_OK ) {
- reg->rkeys.common = key;
- }
-
- /* ROOTKEY_VERSIONS */
- err = nr_RegAddKey( reg, reg->hdr.root, ROOTKEY_VERSIONS_STR, &key );
- if ( err == REGERR_OK ) {
- reg->rkeys.versions = key;
- }
-
- /* ROOTKEY_CURRENT_USER */
- #if 0 /* delay until first use */ /*#ifndef STANDALONE_REGISTRY */
- err = PREF_CopyDefaultCharPref( "profile.name", &profName );
-
- if (err == PREF_NOERROR ) {
- err = nr_RegAddKey( reg, reg->rkeys.users, profName, &key );
- XP_FREE(profName);
- }
- else {
- err = nr_RegAddKey( reg, reg->rkeys.users, "default", &key );
- }
- if ( err == REGERR_OK ) {
- reg->rkeys.current_user = key;
- }
- #endif
-
- /* ROOTKEY_PRIVATE */
- err = nr_RegAddKey( reg, reg->hdr.root, ROOTKEY_PRIVATE_STR, &key );
- if ( err == REGERR_OK ) {
- reg->rkeys.privarea = key;
- }
- } /* nr_InitStdRkeys */
-
-
-
- static Bool nr_ProtectedNode( REGFILE *reg, REGOFF key )
- {
- if ( (key == reg->hdr.root) ||
- (key == reg->rkeys.users) ||
- (key == reg->rkeys.versions) ||
- (key == reg->rkeys.common) ||
- (key == reg->rkeys.current_user) )
- {
- return TRUE;
- }
- else
- return FALSE;
- }
-
-
-
- static REGERR nr_RegAddKey( REGFILE *reg, RKEY key, char *path, RKEY *newKey )
- {
- REGERR err;
- REGDESC desc;
- char namebuf[MAXREGNAMELEN];
- char *p;
-
- XP_ASSERT( path != NULL );
- XP_ASSERT( *path != '\0' );
- XP_ASSERT( key >= HDRRESERVE );
- XP_ASSERT( VALID_FILEHANDLE( reg->fh ) );
-
- /* lock registry */
- err = nr_Lock( reg );
- if ( err != REGERR_OK ) {
- return err;
- }
-
- /* Get starting desc */
- err = nr_ReadDesc( reg, key, &desc );
-
- /* Walk 'path', reading keys into 'desc' */
- p = path;
- while ( err == REGERR_OK ) {
-
- /* get next name on the path */
- err = nr_NextName(p, namebuf, sizeof(namebuf), &p);
- if ( err == REGERR_OK ) {
-
- /* look for name at next level down */
- err = nr_FindAtLevel(reg, desc.down, namebuf, &desc, 0);
-
- /* if key is not found */
- if ( err == REGERR_NOFIND ) {
- /* add it as a sub-key to the last found key */
- err = nr_CreateSubKey(reg, &desc, namebuf);
- }
- }
- }
-
- XP_ASSERT( err != REGERR_OK );
- /* it's good to have processed the whole path */
- if ( err == REGERR_NOMORE ) {
- err = REGERR_OK;
-
- /* return new key if the caller wants it */
- if ( newKey != NULL ) {
- *newKey = desc.location;
- }
- }
-
- /* unlock registry */
- nr_Unlock(reg);
-
- return err;
-
- } /* nr_RegAddKey */
-
-
-
- static void nr_Upgrade_1_1(REGFILE *reg)
- {
- REGDESC desc;
- REGOFF level;
- REGERR err;
-
- XP_ASSERT(reg);
-
- /* find offset for start of the top-level nodes */
- err = nr_ReadDesc( reg, reg->hdr.root, &desc);
- if ( err != REGERR_OK ) {
- return;
- }
- level = desc.down;
-
- /* ROOTKEY_VERSIONS */
- err = nr_FindAtLevel( reg, level, OLD_VERSIONS_STR, &desc, NULL );
- if ( err == REGERR_NOFIND ) {
- err = REGERR_OK;
- }
- else if ( REGERR_OK == err ) {
- err = nr_AppendName( reg, ROOTKEY_VERSIONS_STR, &desc );
- if ( REGERR_OK == err ) {
- err = nr_WriteDesc( reg, &desc );
- }
- }
- if ( err != REGERR_OK )
- return;
-
- /* ROOTKEY_USERS */
- err = nr_FindAtLevel( reg, level, OLD_USERS_STR, &desc, NULL );
- if ( err == REGERR_NOFIND ) {
- err = REGERR_OK;
- }
- else if ( REGERR_OK == err ) {
- err = nr_AppendName( reg, ROOTKEY_USERS_STR, &desc );
- if ( REGERR_OK == err ) {
- err = nr_WriteDesc( reg, &desc );
- }
- }
- if ( err != REGERR_OK )
- return;
-
- /* ROOTKEY_COMMON */
- err = nr_FindAtLevel( reg, level, OLD_COMMON_STR, &desc, NULL );
- if ( err == REGERR_NOFIND ) {
- err = REGERR_OK;
- }
- else if ( REGERR_OK == err ) {
- err = nr_AppendName( reg, ROOTKEY_COMMON_STR, &desc );
- if ( REGERR_OK == err ) {
- err = nr_WriteDesc( reg, &desc );
- }
- }
- if ( err != REGERR_OK )
- return;
-
- /* Mark registry with new version */
- reg->hdr.verMinor = MINOR_VERSION;
- nr_WriteHdr(reg);
-
- }
-
-
-
- /* ---------------------------------------------------------------------
- * Public API
- * --------------------------------------------------------------------- */
-
- /* ---------------------------------------------------------------------
- * NReg_Open - Open a netscape XP registry
- *
- * Parameters:
- * filename - registry file to open. NULL or "" opens standard
- * local registry. (This parameter currently ignored)
- * hReg - OUT: handle to opened registry
- *
- * Output:
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegOpen( char *filename, HREG *hReg )
- {
- REGERR status = REGERR_OK;
- REGFILE *pReg;
- REGHANDLE *pHandle;
-
- XP_ASSERT(bRegStarted);
-
- /* initialize output handle in case of error */
- *hReg = NULL;
-
- #if !defined(STANDALONE_REGISTRY)
- PR_EnterMonitor(reglist_monitor);
- #endif
-
- /* Look for named file in list of open registries */
- if (filename == NULL) {
- filename = "";
- }
- pReg = vr_findRegFile( filename );
-
- /* if registry not already open */
- if (pReg == NULL) {
-
- /* ...then open it */
- pReg = (REGFILE*)XP_ALLOC( sizeof(REGFILE) );
- if ( pReg == NULL ) {
- status = REGERR_MEMORY;
- goto bail;
- }
- XP_MEMSET(pReg, 0, sizeof(REGFILE));
-
- pReg->inInit = TRUE;
- pReg->filename = XP_STRDUP(filename);
- if (pReg->filename == NULL) {
- XP_FREE( pReg );
- status = REGERR_MEMORY;
- goto bail;
- }
-
- status = nr_OpenFile( filename, &(pReg->fh) );
- if (status == REGERR_READONLY) {
- /* Open, but read only */
- pReg->readOnly = TRUE;
- status = REGERR_OK;
- }
- if ( status != REGERR_OK ) {
- XP_FREE( pReg );
- goto bail;
- }
-
- /* ...read and validate the header */
- status = nr_ReadHdr( pReg );
- if ( status != REGERR_OK ) {
- nr_CloseFile( &(pReg->fh) );
- XP_FREE( pReg );
- goto bail;
- }
-
- /* ...other misc initialization */
- pReg->refCount = 0;
-
- #ifndef STANDALONE_REGISTRY
- pReg->monitor = PR_NewMonitor();
- #endif
- /* now done with everything that needs to protect the header */
- pReg->inInit = FALSE;
-
- if ( pReg->hdr.verMajor == 1 && pReg->hdr.verMinor <= 1 )
- nr_Upgrade_1_1(pReg);
-
- nr_InitStdRkeys( pReg );
-
- /* ...and add it to the list */
- nr_AddNode( pReg );
- }
-
- /* create a new handle to the regfile */
- pHandle = (REGHANDLE*)XP_ALLOC( sizeof(REGHANDLE) );
- if ( pHandle == NULL ) {
- /* we can't create the handle */
- if ( pReg->refCount == 0 ) {
- /* we've just opened it so close it and remove node */
- nr_CloseFile( &(pReg->fh) );
- nr_DeleteNode( pReg );
- }
-
- status = REGERR_MEMORY;
- goto bail;
- }
-
- pHandle->magic = MAGIC_NUMBER;
- pHandle->pReg = pReg;
-
- /* success: bump the reference count and return the handle */
- pReg->refCount++;
- *hReg = (void*)pHandle;
-
- bail:
- #if !defined(STANDALONE_REGISTRY)
- PR_ExitMonitor(reglist_monitor);
- #endif
-
- return status;
-
- } /* NR_RegOpen */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegClose - Close a netscape XP registry
- *
- * Parameters:
- * hReg - handle of open registry to be closed.
- *
- * After calling this routine the handle is no longer valid
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegClose( HREG hReg )
- {
- REGERR err;
- REGHANDLE* reghnd = (REGHANDLE*)hReg;
-
- XP_ASSERT(bRegStarted);
-
- /* verify handle */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- XP_ASSERT( VALID_FILEHANDLE(reghnd->pReg->fh) );
-
- #if !defined(STANDALONE_REGISTRY)
- PR_EnterMonitor(reglist_monitor);
- #endif
- /* lower REGFILE user count */
- reghnd->pReg->refCount--;
-
- /* if registry is no longer in use */
- if ( reghnd->pReg->refCount < 1 ) {
- /* ...then close the file */
- if ( reghnd->pReg->hdrDirty ) {
- nr_WriteHdr( reghnd->pReg );
- }
- nr_CloseFile( &(reghnd->pReg->fh) );
- /* ...and delete REGFILE node from list */
- nr_DeleteNode( reghnd->pReg );
- }
- #if !defined(STANDALONE_REGISTRY)
- PR_ExitMonitor(reglist_monitor);
- #endif
-
- reghnd->magic = 0; /* prevent accidental re-use */
- XP_FREE( reghnd );
-
- return REGERR_OK;
-
- } /* NR_RegClose */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegPack - Pack an open registry.
- * Registry is locked the entire time.
- *
- * Parameters:
- * hReg - handle of open registry to pack
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegPack( HREG hReg )
- {
- XP_ASSERT(bRegStarted);
-
- return REGERR_FAIL;
- }
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegAddKey - Add a key node to the registry
- *
- * This routine is simply a wrapper to perform user input
- * validation and translation from HREG and standard key
- * values into the internal format
- *
- * Parameters:
- * hReg - handle of open registry
- * key - registry key obtained from NR_RegGetKey(),
- * or one of the standard top-level keys
- * path - relative path of key to be added. Intermediate
- * nodes will also be added if necessary.
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegAddKey( HREG hReg, RKEY key, char *path, RKEY *newKey )
- {
- REGERR err;
- REGOFF start;
- REGFILE* reg;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- start = nr_TranslateKey( reg, key );
-
- /* ... don't allow additional children of ROOTKEY */
- if ( start == reg->hdr.root )
- return REGERR_PARAM;
-
- if ( path == NULL || *path == '\0' || start == 0 || reg == NULL )
- return REGERR_PARAM;
-
- /* call the real routine */
- return nr_RegAddKey( reg, start, path, newKey );
- } /* NR_RegAddKey */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegDeleteKey - Delete the specified key and all of its children
- *
- * Note that delete simply orphans blocks and makes no attempt
- * to reclaim space in the file. Use NR_RegPack()
- *
- * Parameters:
- * hReg - handle of open registry
- * key - starting node RKEY, typically one of the standard ones.
- * path - relative path of key to delete
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegDeleteKey( HREG hReg, RKEY key, char *path )
- {
- REGERR err;
- REGOFF start;
- REGFILE* reg;
- REGDESC desc;
- REGDESC predecessor;
- REGOFF offPrev;
- REGOFF offParent;
- REGOFF* link;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- start = nr_TranslateKey( reg, key );
- if ( path == NULL || *path == '\0' || start == 0 )
- return REGERR_PARAM;
-
- /* lock registry */
- err = nr_Lock( reg );
- if ( err != REGERR_OK )
- return err;
-
- /* find the specified key */
- err = nr_Find( reg, start, path, &desc, &offPrev, &offParent );
- if ( err == REGERR_OK ) {
-
- XP_ASSERT( !TYPE_IS_ENTRY( desc.type ) );
-
- /* make sure it's childless and not a top-level key */
- if ( (desc.down == 0) && !nr_ProtectedNode( reg, desc.location ) ) {
-
- /* Are we the first on our level? */
- if ( offPrev == 0 ) {
- /* Yes: link to parent's "down" pointer */
- err = nr_ReadDesc( reg, offParent, &predecessor );
- link = &(predecessor.down);
- }
- else {
- /* No: link using predecessor's "left" pointer */
- err = nr_ReadDesc( reg, offPrev, &predecessor );
- link = &(predecessor.left);
- }
-
- /* If we read the predecessor desc OK */
- if (err == REGERR_OK) {
- XP_ASSERT( *link == desc.location );
-
- /* link predecessor to next, removing current node from chain */
- *link = desc.left;
-
- /* Write the updated predecessor */
- err = nr_WriteDesc( reg, &predecessor );
- if ( err == REGERR_OK ) {
- /* Mark key deleted to prevent bogus use by anyone
- * who is holding an RKEY for that node
- */
- desc.type |= REGTYPE_DELETED;
- err = nr_WriteDesc( reg, &desc );
- }
- }
- }
- else {
- /* specified node is protected from deletion */
- err = REGERR_FAIL;
- }
- }
-
- /* unlock registry */
- nr_Unlock(reg);
-
- return err;
-
- } /* NR_RegDeleteKey */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegGetKey - Get the RKEY value of a node from its path
- *
- * Parameters:
- * hReg - handle of open registry
- * key - starting node RKEY, typically one of the standard ones.
- * path - relative path of key to find. (a blank path just gives you
- * the starting key--useful for verification, VersionRegistry)
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegGetKey( HREG hReg, RKEY key, char *path, RKEY *result )
- {
- REGERR err;
- REGOFF start;
- REGFILE* reg;
- REGDESC desc;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- reg = ((REGHANDLE*)hReg)->pReg;
- start = nr_TranslateKey( reg, key );
-
- if ( path == NULL || start == 0 || result == NULL )
- return REGERR_PARAM;
-
- /* find the specified key */
- err = nr_Find( reg, start, path, &desc, 0, 0 );
- if ( err == REGERR_OK ) {
- *result = (RKEY)desc.location;
- }
-
- return err;
-
- } /* NR_RegGetKey */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegGetEntryInfo - Get some basic info about the entry data
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * info - return: Entry info object
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegGetEntryInfo( HREG hReg, RKEY key, char *name,
- REGINFO *info )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' || info == NULL )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &desc);
- if ( err == REGERR_OK ) {
-
- /* if the named entry exists */
- err = nr_FindAtLevel( reg, desc.value, name, &desc, NULL );
- if ( err == REGERR_OK ) {
-
- /* ... return the values */
- if ( info->size != sizeof(REGINFO) )
- err = REGERR_PARAM;
- else {
- info->entryType = desc.type;
- info->entryLength = desc.valuelen;
- }
- }
- }
-
- return err;
-
- } /* NR_RegGetEntryInfo */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegGetEntryString - Get the UTF string value associated with the
- * named entry of the specified key.
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * buffer - destination for string
- * bufsize - size of buffer
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegGetEntryString( HREG hReg, RKEY key, char *name,
- char *buffer, uint32 bufsize)
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' || buffer == NULL || bufsize == 0 )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &desc);
- if ( err == REGERR_OK )
- {
- /* if the named entry exists */
- err = nr_FindAtLevel( reg, desc.value, name, &desc, NULL );
- if ( err == REGERR_OK )
- {
- /* read the string */
- if ( desc.type == REGTYPE_ENTRY_STRING_UTF )
- {
- err = nr_ReadData( reg, &desc, bufsize, buffer );
- /* prevent run-away strings */
- buffer[bufsize-1] = '\0';
- }
- else {
- err = REGERR_BADTYPE;
- }
- }
- }
-
- return err;
-
- } /* NR_RegGetEntryString */
-
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegGetEntry - Get the value data associated with the
- * named entry of the specified key.
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * buffer - destination for data
- * size - in: size of buffer
- * out: size of actual data (incl. \0 term. for strings)
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegGetEntry( HREG hReg, RKEY key, char *name,
- void *buffer, uint32 *size )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
- char *tmpbuf = NULL; /* malloc a tmp buffer to convert XP int arrays */
- uint32 nInt;
- uint32 *pISrc;
- uint32 *pIDest;
- XP_Bool needFree = FALSE;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' || buffer == NULL || size == NULL )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &desc);
- if ( err == REGERR_OK )
- {
- /* if the named entry exists */
- err = nr_FindAtLevel( reg, desc.value, name, &desc, NULL );
- if ( err == REGERR_OK )
- {
- if ( desc.valuelen > *size ) {
- err = REGERR_BUFTOOSMALL;
- }
- else if ( desc.valuelen == 0 ) {
- err = REGERR_FAIL;
- }
- else switch (desc.type)
- {
- /* platform independent array of 32-bit integers */
- case REGTYPE_ENTRY_INT32_ARRAY:
- tmpbuf = (char*)XP_ALLOC( desc.valuelen );
- if ( tmpbuf != NULL )
- {
- needFree = TRUE;
- err = nr_ReadData( reg, &desc, desc.valuelen, tmpbuf );
- if ( REGERR_OK == err )
- {
- /* convert int array */
- nInt = (desc.valuelen / INTSIZE);
- pISrc = (uint32*)tmpbuf;
- pIDest = (uint32*)buffer;
- for(; nInt > 0; nInt--, pISrc++, pIDest++) {
- *pIDest = nr_ReadLong((char*)pISrc);
- }
- }
- }
- else
- err = REGERR_MEMORY;
-
- break;
-
-
- case REGTYPE_ENTRY_STRING_UTF:
- tmpbuf = (char*)buffer;
- err = nr_ReadData( reg, &desc, *size, tmpbuf );
- /* prevent run-away strings */
- tmpbuf[(*size)-1] = '\0';
- break;
-
-
- case REGTYPE_ENTRY_BYTES:
- default: /* return raw data for unknown types */
- err = nr_ReadData( reg, &desc, *size, (char*)buffer );
- break;
- }
-
- /* return the actual data size */
- *size = desc.valuelen;
- }
- }
-
- if (needFree)
- XP_FREE(tmpbuf);
-
- return err;
-
- } /* NR_RegGetEntry */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegSetEntryString - Store a UTF string value associated with the
- * named entry of the specified key. Used for
- * both creation and update.
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * buffer - UTF String to store
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegSetEntryString( HREG hReg, RKEY key, char *name,
- char *buffer )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
- REGDESC parent;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' || buffer == NULL )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* lock registry */
- err = nr_Lock( reg );
- if ( err != REGERR_OK )
- return err;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &parent);
- if ( err == REGERR_OK ) {
-
- /* if the named entry already exists */
- err = nr_FindAtLevel( reg, parent.value, name, &desc, NULL );
- if ( err == REGERR_OK ) {
- /* then update the existing one */
- err = nr_WriteString( reg, buffer, &desc );
- if ( err == REGERR_OK ) {
- desc.type = REGTYPE_ENTRY_STRING_UTF;
- err = nr_WriteDesc( reg, &desc );
- }
- }
- else if ( err == REGERR_NOFIND ) {
- /* otherwise create a new entry */
- err = nr_CreateEntryString( reg, &parent, name, buffer );
- }
- /* other errors fall through */
- }
-
- /* unlock registry */
- nr_Unlock( reg );
-
- return err;
-
- } /* NR_RegSetEntryString */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegSetEntry - Store value data associated with the named entry
- * of the specified key. Used for both creation and update.
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * type - type of data to be stored
- * buffer - data to store
- * size - length of data to store in bytes
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegSetEntry( HREG hReg, RKEY key, char *name, uint16 type,
- void *buffer, uint32 size )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
- REGDESC parent;
- char *data;
- uint32 nInt;
- uint32 *pIDest;
- uint32 *pISrc;
- XP_Bool needFree = FALSE;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' || buffer == NULL || size == 0 )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* validate type and convert numerics to XP format */
- switch (type)
- {
- case REGTYPE_ENTRY_BYTES:
- data = (char*)buffer;
- break;
-
-
- case REGTYPE_ENTRY_STRING_UTF:
- data = (char*)buffer;
- /* string must be null terminated */
- if ( data[size-1] != '\0' )
- return REGERR_PARAM;
- break;
-
-
- case REGTYPE_ENTRY_INT32_ARRAY:
- /* verify no partial integers */
- if ( (size % INTSIZE) != 0 )
- return REGERR_PARAM;
-
- /* get a conversion buffer */
- data = (char*)XP_ALLOC(size);
- if ( data == NULL )
- return REGERR_MEMORY;
- else
- needFree = TRUE;
-
- /* convert array to XP format */
- nInt = ( size / INTSIZE );
- pIDest = (uint32*)data;
- pISrc = (uint32*)buffer;
-
- for( ; nInt > 0; nInt--, pIDest++, pISrc++) {
- nr_WriteLong( *pISrc, (char*)pIDest );
- }
- break;
-
-
- default:
- return REGERR_BADTYPE;
- }
-
- /* lock registry */
- err = nr_Lock( reg );
- if ( REGERR_OK == err )
- {
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &parent);
- if ( err == REGERR_OK )
- {
- /* if the named entry already exists */
- err = nr_FindAtLevel( reg, parent.value, name, &desc, NULL );
- if ( err == REGERR_OK )
- {
- /* then update the existing one */
- err = nr_WriteData( reg, data, size, &desc );
- if ( err == REGERR_OK )
- {
- desc.type = type;
- err = nr_WriteDesc( reg, &desc );
- }
- }
- else if ( err == REGERR_NOFIND )
- {
- /* otherwise create a new entry */
- err = nr_CreateEntry( reg, &parent, name, type, data, size );
- }
- else {
- /* other errors fall through */
- }
- }
- }
-
- /* unlock registry */
- nr_Unlock( reg );
-
- if (needFree)
- XP_FREE(data);
-
- return err;
-
- } /* NR_RegSetEntry */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegDeleteEntry - Delete the named entry
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * name - name of entry
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegDeleteEntry( HREG hReg, RKEY key, char *name )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
- REGDESC parent;
- REGOFF offPrev;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- if ( name == NULL || *name == '\0' )
- return REGERR_PARAM;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* lock registry */
- err = nr_Lock( reg );
- if ( err != REGERR_OK )
- return err;
-
- /* read starting desc */
- err = nr_ReadDesc( reg, key, &parent);
- if ( err == REGERR_OK ) {
-
- /* look up the named entry */
- err = nr_FindAtLevel( reg, parent.value, name, &desc, &offPrev );
- if ( err == REGERR_OK ) {
-
- XP_ASSERT( TYPE_IS_ENTRY( desc.type ) );
-
- /* if entry is the head of a chain */
- if ( offPrev == 0 ) {
- /* hook parent key to next entry */
- XP_ASSERT( parent.value == desc.location );
- parent.value = desc.left;
- }
- else {
- /* otherwise hook previous entry to next */
- err = nr_ReadDesc( reg, offPrev, &parent );
- parent.left = desc.left;
- }
- /* write out changed desc for previous node */
- if ( err == REGERR_OK ) {
- err = nr_WriteDesc( reg, &parent );
- /* zap the deleted desc because an enum state may contain a
- * reference to a specific entry node
- */
- if ( err == REGERR_OK ) {
- desc.type |= REGTYPE_DELETED;
- err = nr_WriteDesc( reg, &desc );
- }
- }
- }
- }
-
- /* unlock registry */
- nr_Unlock( reg );
-
- return err;
-
- } /* NR_RegDeleteEntry */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegEnumSubkeys - Enumerate the subkey names for the specified key
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key to enumerate--obtain with NR_RegGetKey()
- * eState - enumerations state, must contain NULL to start
- * buffer - location to store subkey names. Once an enumeration
- * is started user must not modify contents since values
- * are built using the previous contents.
- * bufsize - size of buffer for names
- * style - 0 returns direct child keys only, REGENUM_DESCEND
- * returns entire sub-tree
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegEnumSubkeys( HREG hReg, RKEY key, REGENUM *state,
- char *buffer, uint32 bufsize, uint32 style)
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- key = nr_TranslateKey( reg, key );
-
- /* verify starting key */
- err = nr_ReadDesc( reg, key, &desc);
- if ( err != REGERR_OK )
- return err;
-
- /* if in initial state */
- if ( *state == 0 ) {
-
- /* get first subkey */
- if ( desc.down != 0 ) {
- *buffer = '\0';
- err = nr_ReplaceName( reg, desc.down, buffer, bufsize, &desc );
- }
- else {
- /* there *are* no child keys */
- err = REGERR_NOMORE;
- }
- }
- /* else already enumerating so get current 'state' node */
- else if ( REGERR_OK == (err = nr_ReadDesc( reg, *state, &desc )) ) {
-
- /* if traversing the tree */
- if ( style & REGENUM_DESCEND ) {
- if ( desc.down != 0 ) {
- /* append name of first child key */
- err = nr_CatName( reg, desc.down, buffer, bufsize, &desc );
- }
- else if ( desc.left != 0 ) {
- /* replace last segment with next sibling */
- err = nr_ReplaceName( reg, desc.left, buffer, bufsize, &desc );
- }
- else {
- /* done with level, pop up as many times as necessary */
- while ( err == REGERR_OK ) {
- if ( desc.parent != key && desc.parent != 0 ) {
- err = nr_RemoveName( buffer );
- if ( err == REGERR_OK ) {
- err = nr_ReadDesc( reg, desc.parent, &desc );
- if ( err == REGERR_OK && desc.left != 0 ) {
- err = nr_ReplaceName( reg, desc.left, buffer,
- bufsize, &desc );
- break; /* found a node */
- }
- }
- }
- else {
- err = REGERR_NOMORE;
- }
- }
- }
- }
- /* else immediate child keys only */
- else {
- /* get next key in chain */
- if ( desc.left != 0 ) {
- *buffer = '\0';
- err = nr_ReplaceName( reg, desc.left, buffer, bufsize, &desc );
- }
- else {
- err = REGERR_NOMORE;
- }
- }
- }
-
- /* set enum state to current key */
- if ( err == REGERR_OK ) {
- *state = desc.location;
- }
-
- return err;
-
- } /* NR_RegEnumSubkeys */
-
-
-
- /* ---------------------------------------------------------------------
- * NR_RegEnumEntries - Enumerate the entry names for the specified key
- *
- * Parameters:
- * hReg - handle of open registry
- * key - RKEY of key that contains entry--obtain with NR_RegGetKey()
- * eState - enumerations state, must contain NULL to start
- * buffer - location to store entry names
- * bufsize - size of buffer for names
- * ---------------------------------------------------------------------
- */
- VR_INTERFACE(REGERR) NR_RegEnumEntries( HREG hReg, RKEY key, REGENUM *state,
- char *buffer, uint32 bufsize, REGINFO *info )
- {
- REGERR err;
- REGFILE* reg;
- REGDESC desc;
-
- XP_ASSERT(bRegStarted);
-
- /* verify parameters */
- err = VERIFY_HREG( hReg );
- if ( err != REGERR_OK )
- return err;
-
- reg = ((REGHANDLE*)hReg)->pReg;
-
- /* verify starting key */
- err = nr_ReadDesc( reg, key, &desc);
- if ( err != REGERR_OK )
- return err;
-
- if ( *state == 0 ) {
- /* initial state--get first entry */
-
- if ( desc.value != 0 ) {
- *buffer = '\0';
- err = nr_ReplaceName( reg, desc.value, buffer, bufsize, &desc );
- }
- else {
- /* there *are* no entries */
- err = REGERR_NOMORE;
- }
- }
- else {
- /* 'state' stores previous entry */
- err = nr_ReadDesc( reg, *state, &desc );
- if ( err == REGERR_OK ) {
-
- /* get next entry in chain */
- if ( desc.left != 0 ) {
- *buffer = '\0';
- err = nr_ReplaceName( reg, desc.left, buffer, bufsize, &desc );
- }
- else {
- /* at end of chain */
- err = REGERR_NOMORE;
- }
- }
- }
-
- /* if we found an entry */
- if ( err == REGERR_OK ) {
-
- /* set enum state to current entry */
- *state = desc.location;
-
- /* return REGINFO if requested */
- if ( info != NULL && info->size >= sizeof(REGINFO) ) {
- info->entryType = desc.type;
- info->entryLength = desc.valuelen;
- }
- }
-
- return err;
-
- } /* NR_RegEnumEntries */
-
-
-
-
- #ifndef STANDALONE_REGISTRY
- #include "VerReg.h"
-
- #ifdef WIN32
- extern BOOL WFE_IsMoveFileExBroken();
- #endif
- /* ---------------------------------------------------------------------
- * ---------------------------------------------------------------------
- * Registry initialization and shut-down
- * ---------------------------------------------------------------------
- * ---------------------------------------------------------------------
- */
- #ifdef BROKEN
- extern void SU_InitMonitor(void);
- extern void SU_DestroyMonitor(void);
- #endif
- extern PRMonitor *vr_monitor;
- #ifdef XP_UNIX
- extern XP_Bool bGlobalRegistry;
- #endif
-
- #ifdef XP_MAC
- #pragma export on
- #endif
-
- void NR_StartupRegistry(void)
- {
- HREG reg;
- RKEY key;
- REGERR err;
- REGENUM state;
- XP_Bool removeFromList;
- XP_StatStruct stat;
-
- vr_monitor = PR_NewMonitor();
- XP_ASSERT( vr_monitor != NULL );
- reglist_monitor = PR_NewMonitor();
- XP_ASSERT( reglist_monitor != NULL );
- #ifdef XP_UNIX
- bGlobalRegistry = ( getenv(UNIX_GLOBAL_FLAG) != NULL );
- #endif
-
- #ifdef BROKEN
- SU_InitMonitor();
- #endif
- bRegStarted = TRUE;
- /* need to register a PREF callback for "profile.name" */
-
- /* check to see that we have a valid registry */
- if (REGERR_OK == NR_RegOpen("", ®))
- {
- #ifdef XP_PC
- /* perform scheduled file deletions and replacements (PC only) */
- if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE,
- REG_DELETE_LIST_KEY,&key))
- {
- char *urlFile;
- char *pFile;
- char buf[MAXREGNAMELEN];
-
- state = 0;
- while (REGERR_OK == NR_RegEnumEntries(reg, key, &state,
- buf, sizeof(buf), NULL ))
- {
- urlFile = XP_PlatformFileToURL(buf);
- if ( urlFile == NULL)
- continue;
- pFile = urlFile+7;
-
- removeFromList = FALSE;
- if (0 == XP_FileRemove(pFile, xpURL)) {
- /* file was successfully deleted */
- removeFromList = TRUE;
- }
- else if (XP_Stat(pFile, &stat, xpURL) != 0) {
- /* file doesn't appear to exist */
- removeFromList = TRUE;
- }
-
- if (removeFromList) {
- err = NR_RegDeleteEntry( reg, key, buf );
- /* must reset state or enum will stop on deleted entry */
- if ( err == REGERR_OK )
- state = 0;
- }
-
- XP_FREEIF(urlFile);
- }
- /* delete list node if empty */
- state = 0;
- if (REGERR_NOMORE == NR_RegEnumEntries( reg, key, &state, buf,
- sizeof(buf), NULL ))
- {
- NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY);
- }
- }
-
- /* replace files if any listed */
- if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE,
- REG_REPLACE_LIST_KEY, &key))
- {
- char tmpfile[MAXREGNAMELEN];
- char target[MAXREGNAMELEN];
-
- state = 0;
- while (REGERR_OK == NR_RegEnumEntries(reg, key, &state,
- tmpfile, sizeof(tmpfile), NULL ))
- {
- removeFromList = FALSE;
- if (XP_Stat(tmpfile, &stat, xpURL) != 0)
- {
- /* new file is gone! */
- removeFromList = TRUE;
- }
- else if ( REGERR_OK != NR_RegGetEntryString( reg, key,
- tmpfile, target, sizeof(target) ) )
- {
- /* can't read target filename, corruption? */
- removeFromList = TRUE;
- }
- else {
- if (XP_Stat(target, &stat, xpURL) == 0) {
- /* need to delete old file first */
- XP_FileRemove( target, xpURL );
- }
- if (0 == XP_FileRename(tmpfile, xpURL, target, xpURL)) {
- removeFromList = TRUE;
- }
- }
-
- if (removeFromList) {
- err = NR_RegDeleteEntry( reg, key, tmpfile );
- /* must reset state or enum will stop on deleted entry */
- if ( err == REGERR_OK )
- state = 0;
- }
- }
- /* delete list node if empty */
- state = 0;
- if (REGERR_NOMORE == NR_RegEnumEntries(reg, key, &state, tmpfile,
- sizeof(tmpfile), NULL ))
- {
- NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY);
- }
- }
- #endif /* XP_PC */
- NR_RegClose(reg);
- }
- else {
- /* Couldn't open -- make a VersionRegistry call to force creation */
- /* Didn't worry about this before because Netcaster was doing it */
- VR_InRegistry("/Netscape");
- VR_Close();
- }
- }
-
- void NR_ShutdownRegistry(void)
- {
- REGFILE* pReg;
-
- if ( vr_monitor != NULL ) {
- VR_Close();
- PR_DestroyMonitor(vr_monitor);
- vr_monitor = NULL;
- }
-
- /* close any forgotten open registries */
- while ( RegList != NULL ) {
- pReg = RegList;
- if ( pReg->hdrDirty ) {
- nr_WriteHdr( pReg );
- }
- nr_CloseFile( &(pReg->fh) );
- nr_DeleteNode( pReg );
- }
-
- if ( reglist_monitor != NULL ) {
- PR_DestroyMonitor( reglist_monitor );
- reglist_monitor = NULL;
- }
- #ifdef BROKEN
- SU_DestroyMonitor();
- #endif
- }
-
- #ifdef XP_MAC
- #pragma export reset
- #endif
-
- #endif /* STANDALONE_REGISTRY */
-
- /* EOF: reg.c */
-