1291 lines
31 KiB
C
1291 lines
31 KiB
C
/*++
|
|
|
|
Copyright (C) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mmfile.c
|
|
|
|
Abstract;
|
|
|
|
This file contains code to read/write MM data structures
|
|
from/to internal file format.. code is nearly ripped off of
|
|
server\dbconfig.c
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
|
|
typedef struct _DB_CREATE_CONTEXT {
|
|
IN ULONG Index;
|
|
IN PM_SERVER Server;
|
|
|
|
IN PM_CLASSDEF UserClass, VendorClass;
|
|
IN PM_SUBNET Subnet;
|
|
IN PM_RESERVATION Reservation;
|
|
|
|
} DB_CREATE_CONTEXT, *PDB_CREATE_CONTEXT;
|
|
|
|
|
|
//
|
|
// types of records
|
|
//
|
|
|
|
enum {
|
|
DBCFG_CLASS,
|
|
DBCFG_OPT,
|
|
DBCFG_OPTDEF,
|
|
DBCFG_SCOPE,
|
|
DBCFG_MSCOPE,
|
|
DBCFG_RANGE,
|
|
DBCFG_EXCL,
|
|
DBCFG_RESERVATION,
|
|
DBCFG_END
|
|
};
|
|
|
|
//
|
|
// attributes/fields
|
|
//
|
|
|
|
enum {
|
|
DBCFG_INDEX,
|
|
DBCFG_TYPE,
|
|
DBCFG_SUBTYPE,
|
|
DBCFG_FLAGS,
|
|
DBCFG_NAME,
|
|
DBCFG_COMMENT,
|
|
DBCFG_INFO,
|
|
DBCFG_OPTION_ID,
|
|
DBCFG_OPTION_USER,
|
|
DBCFG_OPTION_VENDOR,
|
|
DBCFG_IPADDRESS,
|
|
DBCFG_MASK,
|
|
DBCFG_SUPERSCOPE,
|
|
DBCFG_MSCOPEID,
|
|
DBCFG_MSCOPELANG,
|
|
DBCFG_MSCOPETTL,
|
|
DBCFG_MSCOPE_EXPIRY,
|
|
DBCFG_RANGE_START,
|
|
DBCFG_RANGE_END,
|
|
DBCFG_RANGE_MASK,
|
|
DBCFG_BOOTP_ALLOCATED,
|
|
DBCFG_BOOTP_MAX,
|
|
DBCFG_LAST_COLUMN
|
|
};
|
|
|
|
typedef struct _DBCFG_ENTRY {
|
|
ULONG Bitmasks; // indicates which of the fields below is present
|
|
ULONG Index;
|
|
ULONG Type, SubType, Flags;
|
|
LPWSTR Name, Comment;
|
|
PUCHAR Info;
|
|
ULONG OptionId;
|
|
LPWSTR UserClass, VendorClass;
|
|
ULONG IpAddress, Mask;
|
|
LPWSTR SuperScope;
|
|
ULONG MscopeId;
|
|
LPWSTR MscopeLang;
|
|
ULONG Ttl;
|
|
FILETIME ExpiryTime;
|
|
ULONG RangeStart, RangeEnd, RangeMask;
|
|
ULONG BootpAllocated, BootpMax;
|
|
|
|
ULONG InfoSize;
|
|
PVOID Buf;
|
|
} DBCFG_ENTRY, *PDBCFG_ENTRY;
|
|
|
|
typedef struct _DBCFG_MAP {
|
|
DWORD Offset, Size;
|
|
} DBCFG_MAP;
|
|
|
|
DBCFG_MAP EntryMap[] = {
|
|
FIELD_OFFSET(DBCFG_ENTRY,Index), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,Type), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,SubType), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,Flags), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,Name), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,Comment), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,Info), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,OptionId), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,UserClass), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,VendorClass), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,IpAddress), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,Mask), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,SuperScope), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,MscopeId), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,MscopeLang), 0,
|
|
FIELD_OFFSET(DBCFG_ENTRY,Ttl), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,ExpiryTime), sizeof(FILETIME),
|
|
FIELD_OFFSET(DBCFG_ENTRY,RangeStart), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,RangeEnd), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,RangeMask), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,BootpAllocated), sizeof(DWORD),
|
|
FIELD_OFFSET(DBCFG_ENTRY,BootpMax), sizeof(DWORD)
|
|
};
|
|
|
|
DWORD Bitmasks[] = {
|
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
|
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
|
|
0x010000, 0x020000, 0x040000, 0x080000, 0x100000, 0x200000,
|
|
0x400000, 0x80000,
|
|
};
|
|
|
|
DWORD
|
|
CreateDbEntry(
|
|
IN PDBCFG_ENTRY Entry
|
|
)
|
|
{
|
|
DWORD Error, Size, i, Offset;
|
|
PVOID Data;
|
|
WORD Buffer[4096];
|
|
|
|
Offset = 0;
|
|
|
|
for( i = 0; i < DBCFG_LAST_COLUMN; i ++ ) {
|
|
if( (Entry->Bitmasks & Bitmasks[i]) == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
Size = EntryMap[i].Size;
|
|
Data = EntryMap[i].Offset + (LPBYTE)Entry;
|
|
|
|
if( i == DBCFG_INFO ) {
|
|
//
|
|
// Skip info -- it is added at end
|
|
//
|
|
continue;
|
|
} else if( 0 == Size ) {
|
|
//
|
|
// Calculate the size of the string
|
|
//
|
|
Data = *(LPWSTR *)Data;
|
|
|
|
if( NULL != Data ) Size = sizeof(WCHAR)*(
|
|
1 + wcslen(Data));
|
|
}
|
|
|
|
if( 0 == Size ) continue;
|
|
|
|
Buffer[Offset++] = (WORD)i;
|
|
Buffer[Offset++] = (WORD)Size;
|
|
memcpy(&Buffer[Offset], Data, Size);
|
|
Offset += (Size + sizeof(WORD) - 1 )/sizeof(WORD);
|
|
|
|
}
|
|
|
|
//
|
|
// add info at the end.
|
|
//
|
|
|
|
i = DBCFG_INFO;
|
|
if( Entry->Bitmasks & Bitmasks[i]) {
|
|
Size = EntryMap[i].Size;
|
|
Data = EntryMap[i].Offset + (LPBYTE)Entry;
|
|
Data = *(PUCHAR *)Data;
|
|
|
|
if( NULL != Data ) Size = Entry->InfoSize;
|
|
if( 0 != Size ) {
|
|
|
|
Buffer[Offset++] = (WORD)i;
|
|
Buffer[Offset++] = (WORD)Size;
|
|
memcpy(&Buffer[Offset], Data, Size);
|
|
Offset += (Size + sizeof(WORD) - 1 )/sizeof(WORD);
|
|
}
|
|
}
|
|
|
|
|
|
Buffer[Offset++] = DBCFG_LAST_COLUMN+1;
|
|
Buffer[Offset++] = 0;
|
|
|
|
//
|
|
// Write the record onto file
|
|
//
|
|
|
|
return AddRecordNoSize( (LPBYTE)Buffer, Offset*sizeof(WORD));
|
|
}
|
|
|
|
DWORD
|
|
CreateClassEntry(
|
|
IN ULONG Index,
|
|
IN PM_CLASSDEF Class
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// IsVendor, Type, Name, Comment, nBytes, ActualBytes
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_SUBTYPE] |
|
|
Bitmasks[DBCFG_FLAGS] | Bitmasks[DBCFG_SUBTYPE] |
|
|
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] |
|
|
Bitmasks[DBCFG_INFO] );
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_CLASS;
|
|
|
|
Entry.Flags = Class->IsVendor;
|
|
Entry.SubType = Class->Type;
|
|
Entry.Name = Class->Name;
|
|
Entry.Comment = Class->Comment;
|
|
Entry.Info = Class->ActualBytes;
|
|
Entry.InfoSize = Class->nBytes;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateOptDefEntry(
|
|
IN ULONG Index,
|
|
IN PM_OPTDEF OptDef,
|
|
IN PM_CLASSDEF UserClass,
|
|
IN PM_CLASSDEF VendorClass
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// OptId, Type, OptName, OptComment, OptVal, OptValLen,
|
|
// User, Vendor
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_SUBTYPE] | Bitmasks[DBCFG_OPTION_ID] |
|
|
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] |
|
|
Bitmasks[DBCFG_INFO] | Bitmasks[DBCFG_OPTION_USER] |
|
|
Bitmasks[DBCFG_OPTION_VENDOR] );
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_OPTDEF;
|
|
|
|
Entry.OptionId = OptDef->OptId;
|
|
Entry.SubType = OptDef->Type;
|
|
Entry.Name = OptDef->OptName;
|
|
Entry.Comment = OptDef->OptComment;
|
|
Entry.Info = OptDef->OptVal;
|
|
Entry.InfoSize = OptDef->OptValLen;
|
|
if( UserClass) Entry.UserClass = UserClass->Name;
|
|
if( VendorClass) Entry.VendorClass = VendorClass->Name;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateOptionEntry(
|
|
IN ULONG Index,
|
|
IN PM_OPTION Option,
|
|
IN PM_CLASSDEF UserClass,
|
|
IN PM_CLASSDEF VendorClass,
|
|
IN PM_SUBNET Subnet,
|
|
IN PM_RESERVATION Reservation
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// OptId, Len, Val, User, Vendor
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_OPTION_ID] | Bitmasks[DBCFG_INFO] |
|
|
Bitmasks[DBCFG_OPTION_USER] |
|
|
Bitmasks[DBCFG_OPTION_VENDOR] );
|
|
|
|
if( Reservation ) {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
|
|
Entry.IpAddress = Reservation->Address;
|
|
} else if( Subnet && Subnet->fSubnet ) {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
|
|
Entry.IpAddress = Subnet->Address;
|
|
} else if( Subnet && !Subnet->fSubnet ) {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
|
|
Entry.MscopeId = Subnet->MScopeId;
|
|
}
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_OPT;
|
|
|
|
Entry.OptionId = Option->OptId;
|
|
Entry.Info = Option->Val;
|
|
Entry.InfoSize = Option->Len;
|
|
if( UserClass) Entry.UserClass = UserClass->Name;
|
|
if( VendorClass) Entry.VendorClass = VendorClass->Name;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateScopeEntry(
|
|
IN ULONG Index,
|
|
IN PM_SUBNET Subnet,
|
|
IN PM_SSCOPE SScope
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// State, Policy, ExpiryTime, Name, Description
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_SUBTYPE] | Bitmasks[DBCFG_FLAGS] |
|
|
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] );
|
|
|
|
if( Subnet->fSubnet ) {
|
|
Entry.Bitmasks |= (
|
|
Bitmasks[DBCFG_IPADDRESS] | Bitmasks[DBCFG_MASK] |
|
|
Bitmasks[DBCFG_SUPERSCOPE] );
|
|
Entry.IpAddress = Subnet->Address;
|
|
Entry.Mask = Subnet->Mask;
|
|
if( SScope ) Entry.SuperScope = SScope->Name;
|
|
} else {
|
|
Entry.Bitmasks |= (
|
|
Bitmasks[DBCFG_MSCOPEID] | Bitmasks[DBCFG_MSCOPETTL] |
|
|
Bitmasks[DBCFG_MSCOPELANG] |
|
|
Bitmasks[DBCFG_MSCOPE_EXPIRY] );
|
|
|
|
Entry.MscopeId = Subnet->MScopeId;
|
|
Entry.Ttl = Subnet->TTL;
|
|
Entry.MscopeLang = Subnet->LangTag;
|
|
Entry.ExpiryTime = *(FILETIME *)&Subnet->ExpiryTime;
|
|
}
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = Subnet->fSubnet ? DBCFG_SCOPE : DBCFG_MSCOPE ;
|
|
|
|
Entry.SubType = Subnet->State;
|
|
Entry.Flags = Subnet->Policy;
|
|
Entry.Name = Subnet->Name;
|
|
Entry.Comment = Subnet->Description;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateRangeEntry(
|
|
IN ULONG Index,
|
|
IN PM_RANGE Range,
|
|
IN PM_SUBNET Subnet
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// Start, End, Mask, State, BootpAllocated, MaxBootpAllowed
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_RANGE_START] | Bitmasks[DBCFG_RANGE_END] |
|
|
Bitmasks[DBCFG_RANGE_MASK] | Bitmasks[DBCFG_FLAGS] |
|
|
Bitmasks[DBCFG_BOOTP_ALLOCATED] | Bitmasks[DBCFG_BOOTP_MAX] );
|
|
|
|
if( Subnet->fSubnet ) {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
|
|
Entry.IpAddress = Subnet->Address;
|
|
} else {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
|
|
Entry.MscopeId = Subnet->MScopeId;
|
|
}
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_RANGE;
|
|
|
|
Entry.RangeStart = Range->Start;
|
|
Entry.RangeEnd = Range->End;
|
|
Entry.RangeMask = Range->Mask;
|
|
Entry.Flags = Range->State;
|
|
Entry.BootpAllocated = Range->BootpAllocated;
|
|
Entry.BootpMax = Range->MaxBootpAllowed;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateExclEntry(
|
|
IN ULONG Index,
|
|
IN PM_EXCL Excl,
|
|
IN PM_SUBNET Subnet
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// Start, End
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_RANGE_START] | Bitmasks[DBCFG_RANGE_END] );
|
|
|
|
if( Subnet->fSubnet ) {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
|
|
Entry.IpAddress = Subnet->Address;
|
|
} else {
|
|
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
|
|
Entry.MscopeId = Subnet->MScopeId;
|
|
}
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_EXCL;
|
|
|
|
Entry.RangeStart = Excl->Start;
|
|
Entry.RangeEnd = Excl->End;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
CreateReservationEntry(
|
|
IN ULONG Index,
|
|
IN PM_RESERVATION Reservation
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
|
|
//
|
|
// Address, Flags, nBytes, ClientUID
|
|
//
|
|
|
|
ZeroMemory(&Entry, sizeof(Entry));
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
|
|
Bitmasks[DBCFG_IPADDRESS] | Bitmasks[DBCFG_INFO] |
|
|
Bitmasks[DBCFG_FLAGS] );
|
|
|
|
Entry.Index = Index;
|
|
Entry.Type = DBCFG_RESERVATION;
|
|
|
|
Entry.IpAddress = Reservation->Address;
|
|
Entry.Flags = Reservation->Flags;
|
|
Entry.Info = Reservation->ClientUID;
|
|
Entry.InfoSize = Reservation->nBytes;
|
|
|
|
return CreateDbEntry( &Entry );
|
|
}
|
|
|
|
DWORD
|
|
IterateArrayWithDbCreateRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PARRAY Array,
|
|
IN DWORD (*Routine)(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PVOID ArrayElement
|
|
)
|
|
)
|
|
{
|
|
ARRAY_LOCATION Loc;
|
|
DWORD Error;
|
|
PVOID Element;
|
|
|
|
Error = MemArrayInitLoc( Array, &Loc );
|
|
while( NO_ERROR == Error ) {
|
|
|
|
Error = MemArrayGetElement(
|
|
Array, &Loc, &Element );
|
|
ASSERT( NO_ERROR == Error && NULL != Element );
|
|
|
|
Ctxt->Index ++;
|
|
|
|
Error = Routine( Ctxt, Element );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = MemArrayNextLoc( Array, &Loc );
|
|
}
|
|
|
|
if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
DbCreateClassRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_CLASSDEF Class
|
|
)
|
|
{
|
|
return CreateClassEntry( Ctxt->Index, Class );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateOptDefRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_OPTDEF OptDef
|
|
)
|
|
{
|
|
return CreateOptDefEntry(
|
|
Ctxt->Index, OptDef, Ctxt->UserClass,
|
|
Ctxt->VendorClass );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateOptClassDefRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_OPTCLASSDEFL_ONE OptClassDef
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
if( 0 == MemArraySize(&OptClassDef->OptDefList.OptDefArray) ) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if( 0 == OptClassDef->ClassId ) {
|
|
Ctxt->UserClass = NULL;
|
|
} else {
|
|
Error = MemServerGetClassDef(
|
|
Ctxt->Server, OptClassDef->ClassId, NULL, 0, NULL,
|
|
&Ctxt->UserClass );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
}
|
|
|
|
if( 0 == OptClassDef->VendorId ) {
|
|
Ctxt->VendorClass = NULL;
|
|
} else {
|
|
Error = MemServerGetClassDef(
|
|
Ctxt->Server, OptClassDef->VendorId, NULL, 0, NULL,
|
|
&Ctxt->VendorClass );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
}
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &OptClassDef->OptDefList.OptDefArray,
|
|
DbCreateOptDefRoutine );
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
DbCreateOptionRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_OPTION Option
|
|
)
|
|
{
|
|
return CreateOptionEntry(
|
|
Ctxt->Index, Option, Ctxt->UserClass,
|
|
Ctxt->VendorClass, Ctxt->Subnet, Ctxt->Reservation );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateOptListRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_ONECLASS_OPTLIST OptList
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
if( 0 == MemArraySize(&OptList->OptList) ) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if( 0 == OptList->ClassId ) {
|
|
Ctxt->UserClass = NULL;
|
|
} else {
|
|
Error = MemServerGetClassDef(
|
|
Ctxt->Server, OptList->ClassId, NULL, 0, NULL,
|
|
&Ctxt->UserClass );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
}
|
|
|
|
if( 0 == OptList->VendorId ) {
|
|
Ctxt->VendorClass = NULL;
|
|
} else {
|
|
Error = MemServerGetClassDef(
|
|
Ctxt->Server, OptList->VendorId, NULL, 0, NULL,
|
|
&Ctxt->VendorClass );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
}
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &OptList->OptList, DbCreateOptionRoutine );
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
DbCreateRangeRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_RANGE Range
|
|
)
|
|
{
|
|
return CreateRangeEntry(
|
|
Ctxt->Index, Range, Ctxt->Subnet );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateExclRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_EXCL Excl
|
|
)
|
|
{
|
|
return CreateExclEntry(
|
|
Ctxt->Index, Excl, Ctxt->Subnet );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateReservationRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_RESERVATION Reservation
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = CreateReservationEntry(
|
|
Ctxt->Index, Reservation );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Ctxt->Reservation = Reservation;
|
|
|
|
//
|
|
// Now add the options for this reservation
|
|
//
|
|
|
|
return IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Reservation->Options.Array,
|
|
DbCreateOptListRoutine );
|
|
}
|
|
|
|
DWORD
|
|
DbCreateScopeRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_SUBNET Subnet
|
|
)
|
|
{
|
|
PM_SSCOPE SScope = NULL;
|
|
DWORD Error;
|
|
|
|
if( Subnet->fSubnet && Subnet->SuperScopeId ) {
|
|
DWORD Error;
|
|
|
|
Error = MemServerFindSScope(
|
|
Ctxt->Server, Subnet->SuperScopeId, NULL, &SScope );
|
|
if( NO_ERROR != Error ) {
|
|
SScope = NULL;
|
|
}
|
|
}
|
|
|
|
Error = CreateScopeEntry(
|
|
Ctxt->Index, Subnet, SScope );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Initialize the two fields that will get used later
|
|
//
|
|
|
|
Ctxt->Subnet = Subnet;
|
|
Ctxt->Reservation = NULL;
|
|
|
|
//
|
|
// Now add the options for this scope
|
|
//
|
|
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Subnet->Options.Array,
|
|
DbCreateOptListRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Now add the ranges and exclusions
|
|
//
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Subnet->Ranges, DbCreateRangeRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Subnet->Exclusions, DbCreateExclRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Finally, add the reservations
|
|
//
|
|
|
|
return IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Subnet->Reservations,
|
|
DbCreateReservationRoutine );
|
|
}
|
|
|
|
|
|
DWORD
|
|
DbCreateServerRoutine(
|
|
IN PDB_CREATE_CONTEXT Ctxt,
|
|
IN PM_SERVER Server
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
Ctxt->Server = Server;
|
|
|
|
//
|
|
// First look through the classes
|
|
//
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Server->ClassDefs.ClassDefArray,
|
|
DbCreateClassRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Next save the option defs
|
|
//
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Server->OptDefs.Array,
|
|
DbCreateOptClassDefRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Next save the options
|
|
//
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Server->Options.Array,
|
|
DbCreateOptListRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
//
|
|
// Next save the scopes and mcast scopes
|
|
//
|
|
|
|
Error = IterateArrayWithDbCreateRoutine(
|
|
Ctxt, &Server->Subnets, DbCreateScopeRoutine );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
SaveConfigurationToFile(
|
|
IN PM_SERVER Server
|
|
)
|
|
{
|
|
DB_CREATE_CONTEXT Ctxt;
|
|
DWORD Error;
|
|
|
|
ZeroMemory( &Ctxt, sizeof(Ctxt) );
|
|
|
|
Error = DbCreateServerRoutine(
|
|
&Ctxt, Server );
|
|
|
|
if( NO_ERROR != Error ) {
|
|
Tr("DbCreateServerRoutine: %ld\n", Error);
|
|
} else {
|
|
//
|
|
// Sentinel
|
|
//
|
|
DBCFG_ENTRY Entry;
|
|
ZeroMemory( &Entry, sizeof(Entry) );
|
|
Entry.Bitmasks = (
|
|
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] );
|
|
Entry.Type = DBCFG_END;
|
|
|
|
Error = CreateDbEntry( &Entry );
|
|
if( NO_ERROR != Error ) {
|
|
Tr("Create last entry: %ld\n", Error );
|
|
}
|
|
}
|
|
|
|
Tr("SaveConfigurationToFile: %ld\n", Error);
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
GetColumnFromMemory(
|
|
IN OUT LPBYTE *Mem,
|
|
IN OUT ULONG *MemSize,
|
|
IN ULONG Col,
|
|
IN OUT PVOID Buffer,
|
|
IN ULONG BufSize,
|
|
IN OUT ULONG *CopiedSize
|
|
)
|
|
{
|
|
WORD *WordMem = (WORD *)*Mem;
|
|
DWORD Size;
|
|
|
|
if( *MemSize < sizeof(WORD)*2 ) return ERROR_INVALID_DATA;
|
|
if( Col != WordMem[0] ) return JET_wrnColumnNull;
|
|
|
|
Size = sizeof(WORD)*(
|
|
2 + (WordMem[1]+sizeof(WORD)-1)/sizeof(WORD) );
|
|
if( Size > *MemSize ) return ERROR_INVALID_DATA;
|
|
|
|
if( WordMem[1] >= BufSize ) *CopiedSize = BufSize;
|
|
else *CopiedSize = WordMem[1];
|
|
|
|
memcpy(Buffer, &WordMem[2], *CopiedSize );
|
|
|
|
(*Mem) += Size;
|
|
(*MemSize) -= Size;
|
|
|
|
if( WordMem[1] > BufSize ) return JET_wrnBufferTruncated;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
ReadDbEntry(
|
|
IN OUT LPBYTE *Mem,
|
|
IN OUT ULONG *MemSize,
|
|
IN PDBCFG_ENTRY Entry,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufSize
|
|
)
|
|
{
|
|
DWORD Size, CopiedSize, i, OldMemSize, DummySize;
|
|
JET_ERR JetError;
|
|
LPVOID Data, Ptr;
|
|
LPBYTE OldMem;
|
|
|
|
OldMemSize = *MemSize;
|
|
OldMem = *Mem;
|
|
|
|
ZeroMemory( Entry, sizeof(*Entry) );
|
|
ZeroMemory( Buffer, BufSize );
|
|
|
|
for( i = 0; i < DBCFG_LAST_COLUMN; i ++ ) {
|
|
|
|
//
|
|
// Info should be read at the very end to avoid screwing
|
|
// up alignment as info is binary while the rest of the
|
|
// variable size columns are all WCHAR strings
|
|
//
|
|
|
|
if( i == DBCFG_INFO ) continue;
|
|
|
|
Size = EntryMap[i].Size;
|
|
Data = EntryMap[i].Offset + (LPBYTE)Entry;
|
|
Ptr = Data;
|
|
|
|
if( 0 == Size ) {
|
|
//
|
|
// Calculate the size of the string
|
|
//
|
|
Data = Buffer;
|
|
Size = BufSize;
|
|
}
|
|
|
|
JetError = GetColumnFromMemory(
|
|
Mem, MemSize, i, Data, Size, &CopiedSize );
|
|
|
|
//
|
|
// If the column doesn't exist, continue
|
|
//
|
|
|
|
if( JET_wrnColumnNull == JetError ) continue;
|
|
|
|
if( JET_wrnBufferTruncated == JetError &&
|
|
Data == Buffer ) {
|
|
|
|
(*Mem) = OldMem;
|
|
(*MemSize) = OldMemSize;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
if( NO_ERROR != JetError ) {
|
|
Tr( "GetColumnFromMemory: %ld\n", JetError );
|
|
return JetError;
|
|
}
|
|
|
|
//
|
|
// If it is any of the variable sized params, then
|
|
// set the ptr to point to the buffer where the data is
|
|
// copied, and also update the buffer.
|
|
//
|
|
|
|
if( Data == Buffer ) {
|
|
(*(LPVOID *)Ptr) = Buffer;
|
|
BufSize -= CopiedSize;
|
|
Buffer = (PVOID)(((PUCHAR)Buffer) + CopiedSize);
|
|
} else {
|
|
ASSERT( CopiedSize == Size );
|
|
}
|
|
|
|
//
|
|
// Indicate that the column was retrieved successfully
|
|
//
|
|
|
|
Entry->Bitmasks |= Bitmasks[i];
|
|
}
|
|
|
|
//
|
|
// Read the info field
|
|
//
|
|
|
|
Size = BufSize;
|
|
JetError = GetColumnFromMemory(
|
|
Mem, MemSize, DBCFG_INFO, Buffer, Size, &CopiedSize );
|
|
|
|
GetColumnFromMemory(
|
|
Mem, MemSize, DBCFG_LAST_COLUMN+1,NULL, 0, &DummySize);
|
|
|
|
if( JET_wrnColumnNull == JetError ) return NO_ERROR;
|
|
|
|
if( JET_wrnBufferTruncated == JetError ) {
|
|
(*Mem) = OldMem;
|
|
(*MemSize) = OldMemSize;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
if( NO_ERROR != JetError ) {
|
|
Tr("GetColumnFromMemory: %ld\n", JetError );
|
|
return JetError;
|
|
}
|
|
|
|
Entry->Info = Buffer;
|
|
Entry->InfoSize = CopiedSize;
|
|
Entry->Bitmasks |= Bitmasks[DBCFG_INFO];
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
ReadDbEntryEx(
|
|
IN OUT LPBYTE *Mem,
|
|
IN OUT ULONG *MemSize,
|
|
IN PDBCFG_ENTRY Entry
|
|
)
|
|
{
|
|
PVOID Buffer;
|
|
ULONG BufSize;
|
|
DWORD Error;
|
|
|
|
Buffer = NULL;
|
|
BufSize = 512;
|
|
|
|
do {
|
|
if( NULL != Buffer ) LocalFree(Buffer);
|
|
|
|
BufSize *= 2;
|
|
Buffer = LocalAlloc( LPTR, BufSize );
|
|
if( NULL == Buffer ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
Error = ReadDbEntry(Mem, MemSize, Entry, Buffer, BufSize);
|
|
|
|
} while( ERROR_INSUFFICIENT_BUFFER == Error );
|
|
|
|
if( !(Entry->Bitmasks & Bitmasks[DBCFG_INDEX]) ||
|
|
!(Entry->Bitmasks & Bitmasks[DBCFG_TYPE]) ) {
|
|
if( NO_ERROR == Error ) {
|
|
ASSERT( FALSE );
|
|
Error = ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if( NO_ERROR != Error ) {
|
|
LocalFree( Buffer );
|
|
return Error;
|
|
}
|
|
|
|
Entry->Buf = Buffer;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
AddDbEntry(
|
|
IN PM_SERVER Server,
|
|
IN PDBCFG_ENTRY Entry
|
|
)
|
|
{
|
|
DWORD UserId, VendorId, SScopeId, Error;
|
|
PM_SUBNET Subnet;
|
|
PM_OPTCLASS OptClass;
|
|
PM_OPTION Option, DelOpt;
|
|
PM_RANGE DelRange;
|
|
PM_EXCL DelExcl;
|
|
PM_RESERVATION Reservation;
|
|
PM_CLASSDEF ClassDef;
|
|
PM_SSCOPE SScope;
|
|
|
|
Subnet = NULL;
|
|
OptClass = NULL;
|
|
Option = DelOpt = NULL;
|
|
Reservation = NULL;
|
|
DelRange = NULL;
|
|
DelExcl = NULL;
|
|
UserId = 0;
|
|
VendorId = 0;
|
|
SScopeId = 0;
|
|
|
|
if( Entry->UserClass ) {
|
|
Error = MemServerGetClassDef(
|
|
Server, 0, Entry->UserClass, 0, NULL, &ClassDef );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
ASSERT( ClassDef->IsVendor == FALSE );
|
|
UserId = ClassDef->ClassId;
|
|
}
|
|
|
|
if( Entry->VendorClass ) {
|
|
Error = MemServerGetClassDef(
|
|
Server, 0, Entry->VendorClass, 0, NULL, &ClassDef );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
ASSERT( ClassDef->IsVendor == TRUE);
|
|
VendorId = ClassDef->ClassId;
|
|
}
|
|
|
|
if( Entry->SuperScope ) {
|
|
Error = MemServerFindSScope(
|
|
Server, INVALID_SSCOPE_ID, Entry->SuperScope, &SScope );
|
|
if( NO_ERROR == Error ) {
|
|
SScopeId = SScope->SScopeId;
|
|
} else if( ERROR_FILE_NOT_FOUND != Error ) {
|
|
return Error;
|
|
} else {
|
|
Error = MemSScopeInit( &SScope, 0, Entry->SuperScope );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = MemServerAddSScope( Server, SScope );
|
|
if( NO_ERROR != Error ) {
|
|
MemSScopeCleanup( SScope );
|
|
return Error;
|
|
}
|
|
SScopeId = SScope->SScopeId;
|
|
}
|
|
}
|
|
|
|
switch( Entry->Type ) {
|
|
case DBCFG_CLASS :
|
|
//
|
|
// Flags = IsVendor, SubType =Type, Info = ActualBytes
|
|
//
|
|
|
|
return MemServerAddClassDef(
|
|
Server, MemNewClassId(), Entry->Flags, Entry->Name,
|
|
Entry->Comment, Entry->InfoSize, Entry->Info );
|
|
|
|
case DBCFG_OPTDEF :
|
|
//
|
|
// OptionId = OptId, SubType = Type, Info = OptVal
|
|
//
|
|
|
|
return MemServerAddOptDef(
|
|
Server, UserId, VendorId, Entry->OptionId,
|
|
Entry->Name, Entry->Comment, Entry->SubType,
|
|
Entry->Info, Entry->InfoSize );
|
|
|
|
case DBCFG_OPT:
|
|
//
|
|
// OptionId = OptId, Info = Val
|
|
// If this is a reservation option, address is set to
|
|
// reserved client address. If this is a subnet option,
|
|
// address is set to subnet address. If this is a mscope
|
|
// option, scopeid is set to mscope scopeid. If it is a
|
|
// global option, neither address not scopeid is set.
|
|
//
|
|
|
|
if( Entry->Bitmasks & Bitmasks[DBCFG_MSCOPEID] ) {
|
|
Error = MemServerFindMScope(
|
|
Server, Entry->MscopeId, NULL, &Subnet );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
OptClass = &Subnet->Options;
|
|
} else if( 0 == (Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] )) {
|
|
OptClass = &Server->Options;
|
|
} else {
|
|
Error = MemServerGetUAddressInfo(
|
|
Server, Entry->IpAddress, &Subnet, NULL, NULL,
|
|
&Reservation );
|
|
ASSERT( NO_ERROR == Error );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
if( NULL != Reservation ) {
|
|
OptClass = &Reservation->Options;
|
|
} else OptClass = &Subnet->Options;
|
|
}
|
|
|
|
Error = MemOptInit(
|
|
&Option, Entry->OptionId, Entry->InfoSize,
|
|
Entry->Info );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = MemOptClassAddOption(
|
|
OptClass, Option, UserId, VendorId, &DelOpt );
|
|
|
|
ASSERT( NULL == DelOpt );
|
|
if( NO_ERROR != Error ) MemFree( Option );
|
|
|
|
return Error;
|
|
|
|
case DBCFG_SCOPE:
|
|
//
|
|
// IpAddress = Address, Mask = Mask, SubType = State,
|
|
// Flags = Policy
|
|
//
|
|
|
|
Error = MemSubnetInit(
|
|
&Subnet, Entry->IpAddress, Entry->Mask,
|
|
Entry->SubType, SScopeId, Entry->Name, Entry->Comment );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = MemServerAddSubnet( Server, Subnet );
|
|
if( NO_ERROR != Error ) MemSubnetCleanup( Subnet );
|
|
|
|
return Error;
|
|
|
|
case DBCFG_MSCOPE :
|
|
//
|
|
// MscopeId = MScopeId, Ttl = TTL, MscopeLang = LangTag,
|
|
// ExpiryTime = ExpiryTime, SubType = State, Flags =
|
|
// Policy..
|
|
//
|
|
|
|
Error = MemMScopeInit(
|
|
&Subnet, Entry->MscopeId, Entry->SubType,
|
|
Entry->Flags, (BYTE)Entry->Ttl, Entry->Name,
|
|
Entry->Comment, Entry->MscopeLang,
|
|
*(DATE_TIME *)&Entry->ExpiryTime );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
Error = MemServerAddMScope( Server, Subnet );
|
|
if( NO_ERROR != Error ) MemSubnetCleanup( Subnet );
|
|
|
|
Subnet->ServerPtr = Server;
|
|
return Error;
|
|
|
|
case DBCFG_RANGE :
|
|
|
|
//
|
|
// RangeStart = Start, RangeEnd = End, RangeMask = Mask,
|
|
// Flags = State, BootpAllocated, BootpMax =
|
|
// MaxBootpAllowed... Also, IpAddress or MscopeId
|
|
//
|
|
|
|
if( Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] ) {
|
|
Error = MemServerGetUAddressInfo(
|
|
Server, Entry->IpAddress, &Subnet, NULL, NULL,
|
|
NULL );
|
|
} else {
|
|
Error = MemServerFindMScope(
|
|
Server, Entry->MscopeId, NULL, &Subnet );
|
|
}
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
return MemSubnetAddRange(
|
|
Subnet, Entry->RangeStart, Entry->RangeEnd,
|
|
Entry->Flags, Entry->BootpAllocated, Entry->BootpMax,
|
|
&DelRange );
|
|
|
|
case DBCFG_EXCL:
|
|
//
|
|
// RangeStart = Start, RangeEnd = End
|
|
//
|
|
|
|
if( Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] ) {
|
|
Error = MemServerGetUAddressInfo(
|
|
Server, Entry->IpAddress, &Subnet, NULL, NULL,
|
|
NULL );
|
|
} else {
|
|
Error = MemServerFindMScope(
|
|
Server, Entry->MscopeId, NULL, &Subnet );
|
|
}
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
return MemSubnetAddExcl(
|
|
Subnet, Entry->RangeStart, Entry->RangeEnd, &DelExcl
|
|
);
|
|
|
|
case DBCFG_RESERVATION :
|
|
//
|
|
// IpAddress = Address, Flags = Flags, Info = ClientUID
|
|
//
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
Server, Entry->IpAddress, &Subnet, NULL, NULL, NULL );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
return MemReserveAdd(
|
|
&Subnet->Reservations, Entry->IpAddress,
|
|
Entry->Flags, Entry->Info, Entry->InfoSize );
|
|
default:
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
AddDbEntryEx(
|
|
IN PM_SERVER Server,
|
|
IN PDBCFG_ENTRY Entry
|
|
)
|
|
{
|
|
DWORD Error;
|
|
LPSTR EntryTypes[] = {
|
|
"Class", "Opt", "OptDef", "Scope", "Mscope", "Range",
|
|
"Excl", "Reservation", "Unknown1", "Unknown2", "Unknown3"
|
|
};
|
|
|
|
Error = AddDbEntry( Server, Entry );
|
|
if( NO_ERROR != Error ) {
|
|
Tr("Error adding entry[%ld] %s: 0x%lx\n",
|
|
Entry->Index, EntryTypes[Entry->Type], Error );
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
ReadDbEntries(
|
|
IN OUT LPBYTE *Mem,
|
|
IN OUT ULONG *MemSize,
|
|
IN OUT PM_SERVER *Server
|
|
)
|
|
{
|
|
DBCFG_ENTRY Entry;
|
|
DWORD Error = NO_ERROR;
|
|
|
|
Error = MemServerInit(
|
|
Server, -1, 0, 0, NULL, NULL );
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
while( Error == NO_ERROR ) {
|
|
|
|
Error = ReadDbEntryEx( Mem, MemSize, &Entry );
|
|
if( NO_ERROR != Error ) {
|
|
Tr( "ReadDbEntryEx: %ld\n", Error );
|
|
break;
|
|
}
|
|
|
|
if( Entry.Type == DBCFG_END ) {
|
|
Error = NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
Error = AddDbEntryEx( *Server, &Entry );
|
|
if( NULL != Entry.Buf ) LocalFree( Entry.Buf );
|
|
if( NO_ERROR != Error ) {
|
|
Tr( "AddDbEntryEx: %ld\n", Error );
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
Tr("ReadDbEntries: %ld\n", Error);
|
|
|
|
if( NO_ERROR != Error ) {
|
|
MemServerFree( *Server );
|
|
(*Server) = NULL;
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|