1217 lines
31 KiB
C
1217 lines
31 KiB
C
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (C) 1992, Microsoft Corporation
|
||
|
//
|
||
|
// File: lvolinfo.c
|
||
|
//
|
||
|
// Contents: Functions to store and retrieve local volume info in the
|
||
|
// registry.
|
||
|
//
|
||
|
// Classes: None
|
||
|
//
|
||
|
// Functions: DfsStoreLvolInfo
|
||
|
// DfsGetLvolInfo
|
||
|
// DfsDeleteLvolInfo
|
||
|
// DfsChangeLvolInfoServiceType
|
||
|
// DfsChangeLvolInfoEntryPath
|
||
|
// DfsCreateExitPointInfo
|
||
|
// DfsDeleteExitPointInfo
|
||
|
//
|
||
|
// DfspAddSubordinateId
|
||
|
// GuidToString
|
||
|
// StringToGuid
|
||
|
//
|
||
|
//
|
||
|
// History: August 16, 1994 Milans created
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include "dfsprocs.h"
|
||
|
#include "regkeys.h"
|
||
|
#include "registry.h"
|
||
|
|
||
|
#define Dbg DEBUG_TRACE_LOCALVOL
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspAddSubordinateId(
|
||
|
IN PWSTR wszLvolKey,
|
||
|
IN PDFS_PKT_ENTRY_ID pId);
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspReadPrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
OUT PUNICODE_STRING pustrPrefix);
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspSavePrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
IN PUNICODE_STRING pustrPrefix);
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspUpgradePrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
IN USHORT cbComputerName,
|
||
|
IN PULONG pcbPrefix,
|
||
|
IN OUT PWSTR *pwszPrefix);
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsStoreLvolInfo
|
||
|
//
|
||
|
// Synopsis: Stores the local volume info in the registry.
|
||
|
//
|
||
|
// Arguments: [pRelationInfo] -- Contains the entry id and exit point info
|
||
|
// for the local volume.
|
||
|
//
|
||
|
// Returns: STATUS_SUCCESS
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsStoreLvolInfo(
|
||
|
IN PDFS_LOCAL_VOLUME_CONFIG pConfigInfo,
|
||
|
IN PUNICODE_STRING pustrStorageId)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
WCHAR wszLvolKey[ 2 * sizeof(GUID) + 1 ];
|
||
|
ULONG i;
|
||
|
|
||
|
DebugTrace(+1, Dbg, "DfsStoreLvolInfo: Entered\n", 0);
|
||
|
|
||
|
//
|
||
|
// Open the local volume section
|
||
|
//
|
||
|
|
||
|
Status = KRegSetRoot(wszLocalVolumesSection);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "Unable to open Local volumes section!\n", 0);
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, create a key for the local volume. We use the ascii form of the
|
||
|
// volume guid as the key.
|
||
|
//
|
||
|
|
||
|
GuidToString( &pConfigInfo->RelationInfo.EntryId.Uid, wszLvolKey );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Volume Guid (Key) is [%ws]\n", wszLvolKey);
|
||
|
|
||
|
Status = KRegCreateKey( NULL, wszLvolKey );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, put the rest of the stuff in the registry for this local volume.
|
||
|
// Entry Path
|
||
|
// 8.3 Entry Path
|
||
|
// Entry Type
|
||
|
// Storage ID
|
||
|
// Share Name
|
||
|
// A separate key for each exit point.
|
||
|
//
|
||
|
|
||
|
DebugTrace(0, Dbg, "Entry path is %wZ\n", &pConfigInfo->RelationInfo.EntryId.Prefix);
|
||
|
|
||
|
Status = DfspSavePrefix(
|
||
|
wszLvolKey,
|
||
|
wszEntryPath,
|
||
|
&pConfigInfo->RelationInfo.EntryId.Prefix);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting entry path in registry %08lx!\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(
|
||
|
0, Dbg, "Short Entry path is %wZ\n",
|
||
|
&pConfigInfo->RelationInfo.EntryId.ShortPrefix);
|
||
|
|
||
|
Status = DfspSavePrefix(
|
||
|
wszLvolKey,
|
||
|
wszShortEntryPath,
|
||
|
&pConfigInfo->RelationInfo.EntryId.ShortPrefix);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting short entry path in registry %08lx!\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Entry type is %08lx\n", ULongToPtr( pConfigInfo->EntryType ));
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszLvolKey,
|
||
|
wszEntryType,
|
||
|
REG_DWORD,
|
||
|
sizeof(ULONG),
|
||
|
(PBYTE) &pConfigInfo->EntryType);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting entry type in registry %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszLvolKey,
|
||
|
wszServiceType,
|
||
|
REG_DWORD,
|
||
|
sizeof(ULONG),
|
||
|
(PBYTE) &pConfigInfo->ServiceType);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting service type in registry %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Storage ID is %wZ\n", pustrStorageId);
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszLvolKey,
|
||
|
wszStorageId,
|
||
|
REG_SZ,
|
||
|
pustrStorageId->Length,
|
||
|
(PBYTE) pustrStorageId->Buffer);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting storage id in registry %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Share name is %wZ\n", &pConfigInfo->Share);
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszLvolKey,
|
||
|
wszShareName,
|
||
|
REG_SZ,
|
||
|
pConfigInfo->Share.Length,
|
||
|
(PVOID) pConfigInfo->Share.Buffer);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error setting share name in registry %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
for (i = pConfigInfo->RelationInfo.SubordinateIdCount;
|
||
|
i != 0;
|
||
|
i--) {
|
||
|
|
||
|
|
||
|
Status = DfspAddSubordinateId(
|
||
|
wszLvolKey,
|
||
|
&pConfigInfo->RelationInfo.SubordinateIdList[i-1]);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx adding subordinate info!\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Successfully added subordinate info\n", 0);
|
||
|
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
//
|
||
|
// We have to cleanup all the stuff we did if we failed somewhere.
|
||
|
// This is easy - just delete the key we added for the local volume
|
||
|
//
|
||
|
|
||
|
NTSTATUS CleanupStatus;
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error occured, cleaning up...\n", 0);
|
||
|
|
||
|
CleanupStatus = KRegDeleteKey( wszLvolKey );
|
||
|
|
||
|
if (!NT_SUCCESS(CleanupStatus)) {
|
||
|
|
||
|
//
|
||
|
// We are hosed!
|
||
|
//
|
||
|
|
||
|
DebugTrace(0, Dbg, "Unable to cleanup %08lx!\n", ULongToPtr( CleanupStatus ));
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsStoreLvolInfo exited %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsGetLvolInfo
|
||
|
//
|
||
|
// Synopsis: Retrieves local volume info from the registry given the key
|
||
|
// identifying the local volume.
|
||
|
//
|
||
|
// Arguments: [pwszGuid] -- the string representation of the guid of the
|
||
|
// volume.
|
||
|
// [pRelationInfo] -- Pointer to relation info which will be
|
||
|
// filled in. Note that the SubordinateIdList will
|
||
|
// be allocated here, and must be freed by the
|
||
|
// caller. Additionally, the buffers in the
|
||
|
// individual prefixes are also allocated and must
|
||
|
// be freed.
|
||
|
//
|
||
|
// Returns: NTSTATUS from reading the registry.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsGetLvolInfo(
|
||
|
IN PWSTR pwszGuid,
|
||
|
OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo,
|
||
|
OUT PUNICODE_STRING pustrStorageId)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PDFS_PKT_ENTRY_ID pid;
|
||
|
PULONG pulEntryType = NULL;
|
||
|
PULONG pulServiceType = NULL;
|
||
|
ULONG i, cbSize;
|
||
|
APWSTR awstrSubs = NULL;
|
||
|
|
||
|
DebugTrace(+1, Dbg, "DfsGetLvolInfo: Entered for %ws\n", pwszGuid);
|
||
|
|
||
|
//
|
||
|
// First, initialize the pConfigInfo and pustrStorageId to NULL to
|
||
|
// facilitate cleanup.
|
||
|
//
|
||
|
|
||
|
RtlZeroMemory((PVOID) pConfigInfo, sizeof(DFS_LOCAL_VOLUME_CONFIG));
|
||
|
|
||
|
RtlZeroMemory((PVOID) pustrStorageId, sizeof(UNICODE_STRING));
|
||
|
|
||
|
Status = KRegSetRoot(wszLocalVolumesSection);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsGetLvolInfo: Error setting registry root %08lx!\n", ULongToPtr( Status ));
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the Entry ID - convert the wchar GUID to an actual GUID, and get
|
||
|
// the entry path from the registry.
|
||
|
//
|
||
|
|
||
|
pid = &pConfigInfo->RelationInfo.EntryId;
|
||
|
|
||
|
Status = DfspReadPrefix( pwszGuid, wszEntryPath, &pid->Prefix );
|
||
|
|
||
|
DebugTrace(0, Dbg, "EntryPath is %wZ\n", &pid->Prefix);
|
||
|
|
||
|
Status = DfspReadPrefix( pwszGuid, wszShortEntryPath, &pid->ShortPrefix );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsGetLvolInfo: Error reading entry path %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "8.3 EntryPath is %wZ\n", &pid->Prefix);
|
||
|
|
||
|
StringToGuid( pwszGuid, &pid->Uid );
|
||
|
|
||
|
//
|
||
|
// Now get the Entry and Service Type
|
||
|
//
|
||
|
|
||
|
Status = KRegGetValue( pwszGuid, wszEntryType, (PBYTE *) &pulEntryType );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx getting entry type\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
pConfigInfo->EntryType = *pulEntryType;
|
||
|
|
||
|
Status = KRegGetValue( pwszGuid, wszServiceType, (PBYTE *) &pulServiceType );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
|
||
|
pConfigInfo->ServiceType = 0;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx getting service type\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
pConfigInfo->ServiceType = *pulServiceType;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next, get the Storage ID
|
||
|
//
|
||
|
|
||
|
Status = KRegGetValue( pwszGuid, wszStorageId, (PBYTE *) &pustrStorageId->Buffer);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx getting storage id from registry\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
pustrStorageId->Length = wcslen(pustrStorageId->Buffer) * sizeof(WCHAR);
|
||
|
|
||
|
pustrStorageId->MaximumLength = pustrStorageId->Length + sizeof(WCHAR);
|
||
|
|
||
|
DebugTrace(0, Dbg, "Storage id is %wZ\n", pustrStorageId);
|
||
|
|
||
|
//
|
||
|
// Next, get the share name
|
||
|
//
|
||
|
|
||
|
Status = KRegGetValue( pwszGuid, wszShareName, (PBYTE *) &pConfigInfo->Share.Buffer);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx getting share name from registry\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
pConfigInfo->Share.Length = wcslen(pConfigInfo->Share.Buffer) * sizeof(WCHAR);
|
||
|
|
||
|
pustrStorageId->MaximumLength = pConfigInfo->Share.Length + sizeof(WCHAR);
|
||
|
|
||
|
DebugTrace(0, Dbg, "Share Nameis %wZ\n", &pConfigInfo->Share);
|
||
|
|
||
|
//
|
||
|
// We have the volumes PKT_ENTRY_ID. Now, figure out how many
|
||
|
// subordinates there are, and get them.
|
||
|
//
|
||
|
|
||
|
Status = KRegEnumSubKeySet(
|
||
|
pwszGuid,
|
||
|
&pConfigInfo->RelationInfo.SubordinateIdCount,
|
||
|
&awstrSubs);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "DfsGetLvolInfo: Error getting subkeys %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Volume has %d subordinates\n", ULongToPtr( pConfigInfo->RelationInfo.SubordinateIdCount ));
|
||
|
|
||
|
if (pConfigInfo->RelationInfo.SubordinateIdCount == 0) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsGetLvolInfo: No subordinates! Returning success\n", 0);
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
cbSize = pConfigInfo->RelationInfo.SubordinateIdCount * sizeof(DFS_PKT_ENTRY_ID);
|
||
|
|
||
|
pConfigInfo->RelationInfo.SubordinateIdList = ExAllocatePoolWithTag(
|
||
|
PagedPool,
|
||
|
cbSize,
|
||
|
' sfD' );
|
||
|
|
||
|
if (pConfigInfo->RelationInfo.SubordinateIdList == NULL) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "DfsGetLvolInfo: Unable to allocate %d bytes!\n", ULongToPtr( cbSize ));
|
||
|
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory(pConfigInfo->RelationInfo.SubordinateIdList, cbSize);
|
||
|
|
||
|
//
|
||
|
// Get all the Subordinate information
|
||
|
//
|
||
|
|
||
|
for (i = pConfigInfo->RelationInfo.SubordinateIdCount; i != 0; i--) {
|
||
|
|
||
|
PWSTR pwszSubordinateGuid;
|
||
|
|
||
|
pid = &pConfigInfo->RelationInfo.SubordinateIdList[i-1];
|
||
|
|
||
|
//
|
||
|
// awstrSubs[?] is of the form lvolguid\subordinateguid.
|
||
|
//
|
||
|
|
||
|
pwszSubordinateGuid = &awstrSubs[i-1][2 * sizeof(GUID) + 1];
|
||
|
|
||
|
DebugTrace(0, Dbg, "Subordinate Guid is %ws\n", pwszSubordinateGuid);
|
||
|
|
||
|
StringToGuid( pwszSubordinateGuid, &pid->Uid );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Subkey is %ws\n", awstrSubs[i-1]);
|
||
|
|
||
|
Status = DfspReadPrefix(
|
||
|
awstrSubs[i-1],
|
||
|
wszEntryPath,
|
||
|
&pid->Prefix);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error %08lx reading subordinate prefix\n", ULongToPtr( Status ));
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(0, Dbg, "Retrieved Subordinate Entry %ws\n", awstrSubs[i-1]);
|
||
|
|
||
|
DebugTrace(0, Dbg, "Prefix is %wZ\n", &pid->Prefix);
|
||
|
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
if (pulEntryType) {
|
||
|
|
||
|
ExFreePool( pulEntryType );
|
||
|
|
||
|
}
|
||
|
|
||
|
if (pulServiceType) {
|
||
|
|
||
|
ExFreePool( pulServiceType );
|
||
|
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
//
|
||
|
// Cleanup whatever relation info we might have built up so far.
|
||
|
//
|
||
|
|
||
|
KRegFreeArray(
|
||
|
pConfigInfo->RelationInfo.SubordinateIdCount,
|
||
|
(APBYTE) awstrSubs);
|
||
|
|
||
|
if (pConfigInfo->RelationInfo.EntryId.Prefix.Buffer != NULL) {
|
||
|
|
||
|
ExFreePool(pConfigInfo->RelationInfo.EntryId.Prefix.Buffer);
|
||
|
|
||
|
}
|
||
|
|
||
|
if (pustrStorageId->Buffer != NULL) {
|
||
|
|
||
|
ExFreePool(pustrStorageId->Buffer);
|
||
|
|
||
|
}
|
||
|
|
||
|
for (i = pConfigInfo->RelationInfo.SubordinateIdCount; i != 0; i--) {
|
||
|
|
||
|
pid = &pConfigInfo->RelationInfo.SubordinateIdList[i-1];
|
||
|
|
||
|
if (pid->Prefix.Buffer != NULL) {
|
||
|
|
||
|
ExFreePool( pid->Prefix.Buffer );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (pConfigInfo->RelationInfo.SubordinateIdList != NULL) {
|
||
|
|
||
|
ExFreePool(pConfigInfo->RelationInfo.SubordinateIdList);
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
KRegFreeArray(
|
||
|
pConfigInfo->RelationInfo.SubordinateIdCount,
|
||
|
(APBYTE) awstrSubs);
|
||
|
|
||
|
}
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsGetLvolInfo: Exited - %08lx\n", ULongToPtr( Status ) );
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsDeleteLvolInfo
|
||
|
//
|
||
|
// Synopsis: Deletes local volume information from the registry.
|
||
|
//
|
||
|
// Arguments: [pguidLvol] -- pointer to guid of local volume to delete.
|
||
|
//
|
||
|
// Returns: NTSTATUS from registry API
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsDeleteLvolInfo(
|
||
|
IN GUID *pguidLvol)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
WCHAR wszLvolKey[ 2 * sizeof(GUID) + 1 ];
|
||
|
|
||
|
DebugTrace(+1, Dbg, "DfsDeleteLvolInfo - Entered\n", 0);
|
||
|
|
||
|
GuidToString(pguidLvol, wszLvolKey);
|
||
|
|
||
|
Status = KRegSetRoot( wszLocalVolumesSection );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsDeleteLvolInfo - Error %08lx opening local volumes section\n", ULongToPtr( Status ));
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
Status = KRegDeleteKey( wszLvolKey );
|
||
|
|
||
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsDeleteLvolInfo - Exiting %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsChangeLvolInfoServiceType
|
||
|
//
|
||
|
// Synopsis: Changes the service type associated with the local volume in
|
||
|
// the registry.
|
||
|
//
|
||
|
// Arguments: [pguidLvol] -- pointer to guid of local volume.
|
||
|
// [ulServiceType] -- new service type.
|
||
|
//
|
||
|
// Returns: NTSTATUS from registry api.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsChangeLvolInfoServiceType(
|
||
|
IN GUID *pguidLvol,
|
||
|
IN ULONG ulServiceType)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
WCHAR wszLvolKey[ 2 * sizeof(GUID) + 1 ];
|
||
|
|
||
|
Status = KRegSetRoot( wszLocalVolumesSection );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
GuidToString(pguidLvol, wszLvolKey);
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszLvolKey,
|
||
|
wszServiceType,
|
||
|
REG_DWORD,
|
||
|
sizeof(ULONG),
|
||
|
(PBYTE) &ulServiceType);
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsChangeLvolInfoEntryPath
|
||
|
//
|
||
|
// Synopsis: Changes the entry path associated with the local volume in the
|
||
|
// registry.
|
||
|
//
|
||
|
// Arguments: [pguidLvol] -- pointer to guid of local volume.
|
||
|
// [pustrEntryPath] -- new entry path.
|
||
|
//
|
||
|
// Returns: NTSTATUS from registry api.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsChangeLvolInfoEntryPath(
|
||
|
IN GUID *pguidLvol,
|
||
|
IN PUNICODE_STRING pustrEntryPath)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
WCHAR wszLvolKey[ 2 * sizeof(GUID) + 1 ];
|
||
|
|
||
|
Status = KRegSetRoot( wszLocalVolumesSection );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
GuidToString(pguidLvol, wszLvolKey);
|
||
|
|
||
|
Status = DfspSavePrefix(
|
||
|
wszLvolKey,
|
||
|
wszEntryPath,
|
||
|
pustrEntryPath);
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsCreateExitPointInfo
|
||
|
//
|
||
|
// Synopsis: Adds a single exit point to the local volume information in
|
||
|
// the registry.
|
||
|
//
|
||
|
// Arguments: [pguidLvol] -- pointer to guid of local volume.
|
||
|
// [pidExitPoint] -- pointer to PKT_ENTRY_ID of exit point.
|
||
|
//
|
||
|
// Returns: NTSTATUS from registry manipulation.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsCreateExitPointInfo(
|
||
|
IN GUID *pguidLvol,
|
||
|
IN PDFS_PKT_ENTRY_ID pidExitPoint)
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
WCHAR wszLvolKey[ 2 * sizeof(GUID) + 1 ];
|
||
|
|
||
|
DebugTrace(+1, Dbg, "DfsCreateExitPointInfo - Entered\n", 0);
|
||
|
|
||
|
//
|
||
|
// Stop storing exit point information in the SYSTEM part of
|
||
|
// the registry. (380845).
|
||
|
//
|
||
|
|
||
|
#if 0
|
||
|
Status = KRegSetRoot( wszLocalVolumesSection );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsCreateExitPointInfo - exiting %08lx\n", Status);
|
||
|
|
||
|
return(Status);
|
||
|
|
||
|
}
|
||
|
|
||
|
GuidToString( pguidLvol, wszLvolKey );
|
||
|
|
||
|
Status = DfspAddSubordinateId( wszLvolKey, pidExitPoint );
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
#endif
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsCreateExitPointInfo - Exited %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsDeleteExitPointInfo
|
||
|
//
|
||
|
// Synopsis: Deletes an exit point info from the registry.
|
||
|
//
|
||
|
// Arguments: [pguidLvol] -- pointer to guid of local volume.
|
||
|
// [pguidExitPoint] -- pointer to guid of exit point.
|
||
|
//
|
||
|
// Returns: NTSTATUS from registry api.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsDeleteExitPointInfo(
|
||
|
IN GUID *pguidLvol,
|
||
|
IN GUID *pguidExitPoint)
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
WCHAR wszExitPointKey[ 2 * sizeof(GUID) + // for Local volume guid
|
||
|
1 + // for UNICODE_PATH_SEP
|
||
|
2 * sizeof(GUID) + // for exit point guid
|
||
|
1 ]; // for UNICODE_NULL
|
||
|
|
||
|
DebugTrace(+1, Dbg, "DfsDeleteExitPointInfo: Entered\n", 0);
|
||
|
|
||
|
//
|
||
|
// Stop storing exit point information in the SYSTEM part of
|
||
|
// the registry. (380845).
|
||
|
//
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
Status = KRegSetRoot( wszLocalVolumesSection );
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsDeleteExitPointInfo: Exiting %08lx\n", Status);
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
GuidToString( pguidLvol, wszExitPointKey );
|
||
|
|
||
|
wszExitPointKey[ 2 * sizeof(GUID) ] = UNICODE_PATH_SEP;
|
||
|
|
||
|
GuidToString( pguidExitPoint, &wszExitPointKey[2*sizeof(GUID) + 1] );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Attempting to delete subkey %ws\n", wszExitPointKey);
|
||
|
|
||
|
Status = KRegDeleteKey( wszExitPointKey );
|
||
|
|
||
|
KRegCloseRoot();
|
||
|
|
||
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
DebugTrace(-1, Dbg, "DfsDeleteExitPointInfo: Exiting %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfspAddSubordinateId
|
||
|
//
|
||
|
// Synopsis: Adds a single exit point info to a local volume entry in the
|
||
|
// registry.
|
||
|
//
|
||
|
// Arguments: [wszLvolKey] -- The local volume key under which to add info.
|
||
|
// [pId] -- The info to add.
|
||
|
//
|
||
|
// Returns: NT Status from adding the info.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspAddSubordinateId(
|
||
|
IN PWSTR wszLvolKey,
|
||
|
IN PDFS_PKT_ENTRY_ID pId)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
WCHAR wszExitPoint[ 2 * sizeof(GUID) + 1 ];
|
||
|
WCHAR wszExitPointKey[ 2 * sizeof(GUID) +
|
||
|
sizeof(UNICODE_PATH_SEP_STR) +
|
||
|
2 * sizeof(GUID) +
|
||
|
sizeof(UNICODE_NULL) ];
|
||
|
|
||
|
GuidToString( &pId->Uid, wszExitPoint );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Adding exit point key %ws\n", wszExitPoint);
|
||
|
|
||
|
Status = KRegCreateKey(wszLvolKey, wszExitPoint);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
DebugTrace(0, Dbg, "Error adding exit pt key %08lx\n", ULongToPtr( Status ));
|
||
|
|
||
|
return(Status);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, add the entry path for the exit point as a value to the
|
||
|
// new key.
|
||
|
//
|
||
|
|
||
|
wcscpy(wszExitPointKey, wszLvolKey);
|
||
|
wcscat(wszExitPointKey, UNICODE_PATH_SEP_STR);
|
||
|
wcscat(wszExitPointKey, wszExitPoint);
|
||
|
|
||
|
DebugTrace(0, Dbg, "Subkey name is %ws\n", wszExitPointKey);
|
||
|
|
||
|
DebugTrace(0, Dbg, "Prefix is %wZ\n", &pId->Prefix);
|
||
|
|
||
|
Status = DfspSavePrefix(
|
||
|
wszExitPointKey,
|
||
|
wszEntryPath,
|
||
|
&pId->Prefix);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
|
||
|
KRegDeleteKey(wszExitPointKey);
|
||
|
|
||
|
}
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfspReadPrefix
|
||
|
//
|
||
|
// Synopsis: Reads a prefix from the registry, given the registry key and
|
||
|
// value name. To handle machine renames, the first component
|
||
|
// of the prefix is matched against the current computer name.
|
||
|
// If the two are different, indicating a computer name change,
|
||
|
// the prefix is updated.
|
||
|
//
|
||
|
// Arguments: [wszKey] -- Name of key (relative to current root)
|
||
|
// [wszValue] -- Name of value to read prefix from
|
||
|
// [pustrPrefix] -- On successful return, the prefix is returned
|
||
|
// here.
|
||
|
//
|
||
|
// Returns: [STATUS_SUCCESS] -- If successfully retrieved prefix.
|
||
|
//
|
||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate memory
|
||
|
//
|
||
|
// [STATUS_INTERNAL_DB_CORRUPTION] -- The retrieved value did
|
||
|
// not look like a prefix.
|
||
|
//
|
||
|
// Status from reading the registry value
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspReadPrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
OUT PUNICODE_STRING pustrPrefix)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PWSTR wszCurrentPrefix = NULL;
|
||
|
ULONG cbPrefix, cwCurrentPrefix, i;
|
||
|
UNICODE_STRING ustrComputerName;
|
||
|
|
||
|
Status = KRegGetValue(
|
||
|
wszKey,
|
||
|
wszValue,
|
||
|
(LPBYTE *)&wszCurrentPrefix );
|
||
|
|
||
|
//
|
||
|
// If successfully read in the prefix, do some elementary syntax checking
|
||
|
//
|
||
|
|
||
|
if (NT_SUCCESS(Status)) {
|
||
|
|
||
|
cwCurrentPrefix = wcslen(wszCurrentPrefix);
|
||
|
|
||
|
cbPrefix = cwCurrentPrefix * sizeof(WCHAR);
|
||
|
|
||
|
//
|
||
|
// Must be atleast \a\b
|
||
|
//
|
||
|
|
||
|
if ((cwCurrentPrefix < 4) ||
|
||
|
(wszCurrentPrefix[0] != UNICODE_PATH_SEP)) {
|
||
|
|
||
|
Status = STATUS_INTERNAL_DB_CORRUPTION;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Compute the first component of the prefix
|
||
|
//
|
||
|
|
||
|
if (NT_SUCCESS(Status)) {
|
||
|
|
||
|
ustrComputerName.Buffer = &wszCurrentPrefix[1];
|
||
|
|
||
|
for (i = 1;
|
||
|
(i < cwCurrentPrefix) &&
|
||
|
(wszCurrentPrefix[i] != UNICODE_PATH_SEP);
|
||
|
i++) {
|
||
|
|
||
|
NOTHING;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (i != cwCurrentPrefix) {
|
||
|
|
||
|
ustrComputerName.Length = (USHORT) ((i-1) * sizeof(WCHAR));
|
||
|
|
||
|
ustrComputerName.MaximumLength = ustrComputerName.Length;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Status = STATUS_INTERNAL_DB_CORRUPTION;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (NT_SUCCESS(Status)) {
|
||
|
|
||
|
pustrPrefix->Buffer = wszCurrentPrefix;
|
||
|
pustrPrefix->Length = (USHORT) cbPrefix;
|
||
|
pustrPrefix->MaximumLength = (USHORT)cbPrefix + sizeof(UNICODE_NULL);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (wszCurrentPrefix != NULL)
|
||
|
kreg_free( wszCurrentPrefix );
|
||
|
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfspSavePrefix
|
||
|
//
|
||
|
// Synopsis: Saves a prefix to the registry.
|
||
|
//
|
||
|
// Arguments: [wszKey] -- Name of key (relative to current root)
|
||
|
// [wszValue] -- Name of value to save prefix to.
|
||
|
// [pustrPrefix] -- The prefix to store.
|
||
|
//
|
||
|
// Returns: Status from registry operation
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspSavePrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
IN PUNICODE_STRING pustrPrefix)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
Status = KRegSetValue(
|
||
|
wszKey,
|
||
|
wszValue,
|
||
|
REG_SZ,
|
||
|
pustrPrefix->Length,
|
||
|
(LPBYTE) pustrPrefix->Buffer);
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfspUpgradePrefix
|
||
|
//
|
||
|
// Synopsis: If a machine rename has occured since the last time a prefix
|
||
|
// was updated, this routine will upgrade the first component
|
||
|
// of the prefix to match the computer name.
|
||
|
//
|
||
|
// Arguments: [wszKey] -- Name of key (relative to current root)
|
||
|
// [wszValue] -- Name of value to save updated prefix to.
|
||
|
// [cbComputerName] -- size, in bytes, of the first component of
|
||
|
// the input prefix.
|
||
|
// [pcbPrefix] -- On entry, size in bytes of the input prefix.
|
||
|
// On return, size in bytes of the new prefix. Neither
|
||
|
// sizes includes the terminating NULL.
|
||
|
// [pwszPrefix] -- On entry, the prefix as it currently exists in
|
||
|
// the registry. On return, points to a new block of
|
||
|
// memory that has the new prefix.
|
||
|
//
|
||
|
// Returns: [STATUS_SUCCESS] -- Successfully updated prefix.
|
||
|
//
|
||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfspUpgradePrefix(
|
||
|
IN PWSTR wszKey,
|
||
|
IN PWSTR wszValue,
|
||
|
IN USHORT cbComputerName,
|
||
|
IN PULONG pcbPrefix,
|
||
|
IN OUT PWSTR *pwszPrefix)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG cbPrefix;
|
||
|
PWSTR wszCurrentPrefix, wszNewPrefix;
|
||
|
|
||
|
wszCurrentPrefix = *pwszPrefix;
|
||
|
|
||
|
cbPrefix = (*pcbPrefix) -
|
||
|
cbComputerName +
|
||
|
DfsData.NetBIOSName.Length;
|
||
|
|
||
|
wszNewPrefix = (PWSTR) kreg_alloc( cbPrefix + sizeof(UNICODE_NULL) );
|
||
|
|
||
|
if (wszNewPrefix != NULL) {
|
||
|
|
||
|
wszNewPrefix[0] = UNICODE_PATH_SEP;
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
&wszNewPrefix[1],
|
||
|
DfsData.NetBIOSName.Buffer,
|
||
|
DfsData.NetBIOSName.Length);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
&wszNewPrefix[ DfsData.NetBIOSName.Length/sizeof(WCHAR) + 1],
|
||
|
&wszCurrentPrefix[ cbComputerName/sizeof(WCHAR) + 1 ],
|
||
|
(*pcbPrefix) - cbComputerName);
|
||
|
|
||
|
*pcbPrefix = cbPrefix;
|
||
|
|
||
|
*pwszPrefix = wszNewPrefix;
|
||
|
|
||
|
kreg_free( wszCurrentPrefix );
|
||
|
|
||
|
//
|
||
|
// We try to update the prefix in the registry. Failure to do so is
|
||
|
// ok, we'll just try again next time we try to read it.
|
||
|
//
|
||
|
|
||
|
(VOID) KRegSetValue(
|
||
|
wszKey,
|
||
|
wszValue,
|
||
|
REG_SZ,
|
||
|
cbPrefix,
|
||
|
(LPBYTE) wszNewPrefix);
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GuidToString
|
||
|
//
|
||
|
// Synopsis: Converts a GUID to a 32 char wchar null terminated string.
|
||
|
//
|
||
|
// Arguments: [pGuid] -- Pointer to Guid structure.
|
||
|
// [pwszGuid] -- wchar buffer into which to put the string
|
||
|
// representation of the GUID. Must be atleast
|
||
|
// 2 * sizeof(GUID) + 1 long.
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
const WCHAR rgwchHexDigits[] = L"0123456789ABCDEF";
|
||
|
|
||
|
VOID GuidToString(
|
||
|
IN GUID *pGuid,
|
||
|
OUT PWSTR pwszGuid)
|
||
|
{
|
||
|
PBYTE pbBuffer = (PBYTE) pGuid;
|
||
|
USHORT i;
|
||
|
|
||
|
for(i = 0; i < sizeof(GUID); i++) {
|
||
|
pwszGuid[2 * i] = rgwchHexDigits[(pbBuffer[i] >> 4) & 0xF];
|
||
|
pwszGuid[2 * i + 1] = rgwchHexDigits[pbBuffer[i] & 0xF];
|
||
|
}
|
||
|
pwszGuid[2 * i] = UNICODE_NULL;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: StringToGuid
|
||
|
//
|
||
|
// Synopsis: Converts a 32 wchar null terminated string to a GUID.
|
||
|
//
|
||
|
// Arguments: [pwszGuid] -- the string to convert
|
||
|
// [pGuid] -- Pointer to destination GUID.
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#define HEX_DIGIT_TO_INT(d, i) \
|
||
|
ASSERT(((d) >= L'0' && (d) <= L'9') || \
|
||
|
((d) >= L'A' && (d) <= L'F')); \
|
||
|
if ((d) <= L'9') { \
|
||
|
i = (d) - L'0'; \
|
||
|
} else { \
|
||
|
i = (d) - L'A' + 10; \
|
||
|
}
|
||
|
|
||
|
VOID StringToGuid(
|
||
|
IN PWSTR pwszGuid,
|
||
|
OUT GUID *pGuid)
|
||
|
{
|
||
|
PBYTE pbBuffer = (PBYTE) pGuid;
|
||
|
USHORT i, n;
|
||
|
|
||
|
for (i = 0; i < sizeof(GUID); i++) {
|
||
|
HEX_DIGIT_TO_INT(pwszGuid[2 * i], n);
|
||
|
pbBuffer[i] = n << 4;
|
||
|
HEX_DIGIT_TO_INT(pwszGuid[2 * i + 1], n);
|
||
|
pbBuffer[i] |= n;
|
||
|
}
|
||
|
}
|