mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
5.5 KiB
288 lines
5.5 KiB
/* dblow.c - lowlevel routines for database program.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#include "db.h"
|
|
#include "symref.h"
|
|
|
|
DB db[DBMAX];
|
|
|
|
|
|
/* DBCreate - create a new database
|
|
*/
|
|
BOOL DBCreate (PSZ psz)
|
|
{
|
|
DBHDR dbhdr;
|
|
HANDLE h;
|
|
int cbWritten;
|
|
|
|
dbhdr.iVersion = DB_VER;
|
|
dbhdr.oFree = 0;
|
|
dbhdr.oLast = OFIRSTALLOCOBJ;
|
|
|
|
h = CreateFile (psz, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (h == (HANDLE)-1)
|
|
return FALSE;
|
|
|
|
WriteFile (h, &dbhdr, sizeof (dbhdr), &cbWritten, NULL);
|
|
|
|
CloseHandle (h);
|
|
}
|
|
|
|
/* DBOpen - open/create a database. Uses $ENV: syntax
|
|
*
|
|
* npsz file name of database.
|
|
*
|
|
* returns NULL if error, or PDB of database
|
|
*/
|
|
PDB DBOpen (PSZ psz)
|
|
{
|
|
PDB pdb;
|
|
int cbFile, cbRead;
|
|
|
|
for (pdb = &db[0]; pdb < &db[DBMAX]; pdb++)
|
|
if (pdb->fOpen == FALSE)
|
|
break;
|
|
|
|
if (pdb == &db[DBMAX]) {
|
|
printf ("DBOpen: Too many open databases\n");
|
|
return NULL;
|
|
}
|
|
|
|
memset (pdb, '\0', sizeof (DB));
|
|
|
|
/* Try to open database file
|
|
*/
|
|
pdb->h = CreateFile (psz,
|
|
(GENERIC_READ | GENERIC_WRITE),
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (pdb->h == (HANDLE)-1) {
|
|
NOTEERROR ("DBOpen: CreateFile");
|
|
return NULL;
|
|
}
|
|
|
|
pdb->fOpen = TRUE;
|
|
|
|
pdb->pb = VirtualAlloc (NULL, DBMAXSIZE, MEM_RESERVE, PAGE_NOACCESS);
|
|
if (pdb->pb == NULL) {
|
|
NOTEERROR ("DBOpen: VirtualAlloc");
|
|
CloseHandle (pdb->h);
|
|
return NULL;
|
|
}
|
|
|
|
cbFile = GetFileSize (pdb->h, NULL);
|
|
|
|
cbFile = (cbFile + CBGROWDELTA - 1) & ~(CBGROWDELTA-1);
|
|
|
|
pdb->oAlloc = cbFile;
|
|
|
|
if (VirtualAlloc (pdb->pb, cbFile, MEM_COMMIT, PAGE_READWRITE) == NULL) {
|
|
NOTEERROR ("DBOpen: VirtualAlloc");
|
|
CloseHandle (pdb->h);
|
|
return NULL;
|
|
}
|
|
|
|
ReadFile (pdb->h, pdb->pb, cbFile, &cbRead, NULL);
|
|
|
|
if (PDBHDR (pdb)->iVersion != DB_VER) {
|
|
printf ("DBOpen: Downlevel database version\n");
|
|
DBClose (pdb, FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
return pdb;
|
|
|
|
}
|
|
|
|
/* DBClose - write out and close a database
|
|
*
|
|
* pdb pointer to openned database
|
|
* fCommit TRUE => write out DB too.
|
|
*
|
|
* returns TRUE if successful
|
|
*/
|
|
BOOL DBClose (PDB pdb, BOOL fCommit)
|
|
{
|
|
if (pdb->fOpen) {
|
|
if (fCommit)
|
|
DBFlush (pdb);
|
|
VirtualFree (pdb->pb, pdb->oAlloc, MEM_RELEASE);
|
|
CloseHandle (pdb->h);
|
|
pdb->fOpen = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* DBFlush - write out database
|
|
*
|
|
* pdb pointer to openned database
|
|
*/
|
|
void DBFlush (PDB pdb)
|
|
{
|
|
int cbWritten;
|
|
|
|
SetFilePointer (pdb->h, 0L, 0L, FILE_BEGIN);
|
|
WriteFile (pdb->h, pdb->pb, PDBHDR(pdb)->oLast, &cbWritten, FALSE);
|
|
}
|
|
|
|
/* DBMap - map an offset within the file to a pointer to real memory
|
|
*
|
|
* pdb pointer to openned database
|
|
* o offset within file
|
|
*
|
|
* returns pointer to object valid through end-of-page
|
|
* NULL if any errors
|
|
*/
|
|
PVOID DBMap (PDB pdb, OFFSET o)
|
|
{
|
|
return MAP(pdb, o);
|
|
}
|
|
|
|
/* DBAlloc - allocate an object that does not span page boundaries
|
|
*
|
|
* cch length of desired object
|
|
*
|
|
* returns offset of object
|
|
* 0L if object could not be allocated
|
|
*/
|
|
OFFSET DBAlloc (PDB pdb, LENGTH cch)
|
|
{
|
|
OFFSET oFree, oFreeLast;
|
|
|
|
//
|
|
// Round cch to long boundary
|
|
//
|
|
|
|
cch = ROUND (max (cch, sizeof (FREE)));
|
|
|
|
//
|
|
// Walk free list to find first fit
|
|
//
|
|
|
|
oFree = PDBHDR (pdb)->oFree;
|
|
oFreeLast = 0;
|
|
|
|
while (oFree != 0) {
|
|
if (FREEBLOCK (pdb, oFree)->cb >= cch) {
|
|
|
|
#if FALSE
|
|
|
|
//
|
|
// Block is big enough. See if we have to split.
|
|
//
|
|
|
|
if (FREEBLOCK (pdb, oFree)->cb >= cch + SPLITEXTRA) {
|
|
|
|
//
|
|
// We'll split from the end and save ourselves having
|
|
// to relink
|
|
//
|
|
|
|
FREEBLOCK (pdb, oFree)->cb -= cch;
|
|
|
|
oFree += FREEBLOCK (pdb, oFree)->cb;
|
|
|
|
FREEBLOCK (pdb, oFree)->cb = cch;
|
|
|
|
return oFree;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Block is too small. Unlink and return as is
|
|
//
|
|
|
|
if (oFreeLast == 0)
|
|
PDBHDR (pdb)->oFree = FREEBLOCK (pdb, oFree)->oNextFree;
|
|
else
|
|
FREEBLOCK (pdb, oFreeLast)->oNextFree = FREEBLOCK (pdb, oFree)->oNextFree;
|
|
|
|
// printf ("DBAlloc (%d) = %x\n", cch, oFree);
|
|
|
|
return oFree;
|
|
}
|
|
|
|
//
|
|
// Block is not big enough, look at next block
|
|
//
|
|
|
|
oFreeLast = oFree;
|
|
oFree = FREEBLOCK (pdb, oFree)->oNextFree;
|
|
}
|
|
|
|
//
|
|
// Free list can't satisfy the request. We'll return the object
|
|
// beginning at the current end of allocated data.
|
|
//
|
|
|
|
oFree = PDBHDR (pdb)->oLast;
|
|
|
|
PDBHDR (pdb)->oLast += cch;
|
|
|
|
//
|
|
// Check if there's room in the memory object to grow
|
|
//
|
|
|
|
if (oFree + cch > pdb->oAlloc) {
|
|
|
|
//
|
|
// Grow memory object
|
|
//
|
|
|
|
cch = (oFree + cch - pdb->oAlloc + CBGROWDELTA - 1) & ~(CBGROWDELTA - 1);
|
|
|
|
if (VirtualAlloc (MAP (pdb, pdb->oAlloc), cch, MEM_COMMIT, PAGE_READWRITE) == NULL) {
|
|
printf ("%x (%x) %x %x %x\n", pdb->oAlloc, MAP (pdb, pdb->oAlloc), cch, MEM_COMMIT, PAGE_READWRITE);
|
|
NOTEERROR ("DBAlloc: VirtualAlloc");
|
|
return 0;
|
|
}
|
|
|
|
pdb->oAlloc += cch;
|
|
}
|
|
|
|
// printf ("DBAlloc (%d) = %x\n", cch, oFree);
|
|
|
|
return oFree;
|
|
}
|
|
|
|
/* DBFree - return an object to the storage pool
|
|
*
|
|
* o offset of object
|
|
* cch size of object being freed
|
|
*/
|
|
void DBFree (PDB pdb, OFFSET o, LENGTH cch)
|
|
{
|
|
//
|
|
// Round size to long boundary
|
|
//
|
|
|
|
cch = ROUND (max (cch, sizeof (FREE)));
|
|
|
|
// printf ("DBFree (%x %d))\n", o, cch);
|
|
|
|
memset (DBMap (pdb, o), 0xFF, cch);
|
|
|
|
//
|
|
// Set up new free block
|
|
//
|
|
FREEBLOCK (pdb, o)->cb = cch;
|
|
FREEBLOCK (pdb, o)->oNextFree = PDBHDR (pdb)->oFree;
|
|
|
|
//
|
|
// Link free block onto chain
|
|
//
|
|
PDBHDR (pdb)->oFree = o;
|
|
|
|
}
|