windows-nt/Source/XPSP1/NT/base/fs/dfs/driver/pkt.c
2020-09-26 16:20:57 +08:00

2150 lines
65 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: PKT.C
//
// Contents: This module implements the Partition Knowledge Table routines
// for the Dfs driver.
//
// Functions: PktInitialize -
// PktInitializeLocalPartition -
// RemoveLastComponent -
// PktCreateEntry -
// PktCreateSubordinateEntry -
// PktLookupEntryById -
// PktEntryModifyPrefix -
// PktLookupEntryByPrefix -
// PktLookupEntryByUid -
// PktLookupReferralEntry -
// PktSetRelationInfo -
// PktTrimSubordinates -
// PktpAddEntry -
//
// History: 5 May 1992 PeterCo Created.
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include <netevent.h>
#include <smbtypes.h>
#include <smbtrans.h>
#include "attach.h"
#include "log.h"
#include "know.h"
#define Dbg (DEBUG_TRACE_PKT)
//
// Local procedure prototypes
//
NTSTATUS
PktInitializeLocalPartition(
IN PDFS_PKT Pkt,
IN PUNICODE_STRING LocalVolumeName,
IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo);
NTSTATUS
PktpAddEntry (
IN PDFS_PKT Pkt,
IN PUNICODE_STRING Prefix,
IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
IN ULONG CreateDisposition,
OUT PDFS_PKT_ENTRY *ppPktEntry);
VOID
PktShuffleServiceList(
PDFS_PKT_ENTRY_INFO pInfo);
VOID
PktShuffleGroup(
PDFS_PKT_ENTRY_INFO pInfo,
ULONG nStart,
ULONG nEnd);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, PktInitialize )
#pragma alloc_text( PAGE, PktUninitialize )
#pragma alloc_text( PAGE, PktInitializeLocalPartition )
#pragma alloc_text( PAGE, RemoveLastComponent )
#pragma alloc_text( PAGE, PktCreateEntry )
#pragma alloc_text( PAGE, PktCreateSubordinateEntry )
#pragma alloc_text( PAGE, PktLookupEntryById )
#pragma alloc_text( PAGE, PktEntryModifyPrefix )
#pragma alloc_text( PAGE, PktLookupEntryByPrefix )
#pragma alloc_text( PAGE, PktLookupEntryByUid )
#pragma alloc_text( PAGE, PktSetRelationInfo )
#pragma alloc_text( PAGE, PktTrimSubordinates )
#pragma alloc_text( PAGE, PktpAddEntry )
#endif // ALLOC_PRAGMA
//
// declare the global null guid
//
GUID _TheNullGuid;
//+-------------------------------------------------------------------------
//
// Function: PktInitialize, public
//
// Synopsis: PktInitialize initializes the partition knowledge table.
//
// Arguments: [Pkt] - pointer to an uninitialized PKT
//
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
//
// Notes: This routine is called only at driver init time.
//
//--------------------------------------------------------------------------
NTSTATUS
PktInitialize(
IN PDFS_PKT Pkt
) {
DebugTrace(+1, Dbg, "PktInitialize: Entered\n", 0);
//
// initialize the NULL GUID.
//
RtlZeroMemory(&_TheNullGuid, sizeof(GUID));
//
// Always zero the pkt first
//
RtlZeroMemory(Pkt, sizeof(DFS_PKT));
//
// do basic initialization
//
Pkt->NodeTypeCode = DFS_NTC_PKT;
Pkt->NodeByteSize = sizeof(DFS_PKT);
ExInitializeResourceLite(&Pkt->Resource);
InitializeListHead(&Pkt->EntryList);
DfsInitializeUnicodePrefix(&Pkt->LocalVolTable);
DfsInitializeUnicodePrefix(&Pkt->PrefixTable);
DfsInitializeUnicodePrefix(&Pkt->ShortPrefixTable);
RtlInitializeUnicodePrefix(&Pkt->DSMachineTable);
//
// We don't know anything about our domain yet, so we leave
// it NULL. This will get initialized later to the right value!
//
Pkt->DomainPktEntry = NULL;
DebugTrace(-1, Dbg, "PktInitialize: Exit -> VOID\n", 0 );
return STATUS_SUCCESS;
}
VOID
PktUninitialize(
IN PDFS_PKT Pkt)
{
DfsFreePrefixTable(&Pkt->LocalVolTable);
DfsFreePrefixTable(&Pkt->PrefixTable);
DfsFreePrefixTable(&Pkt->ShortPrefixTable);
ExDeleteResourceLite(&Pkt->Resource);
}
//+-------------------------------------------------------------------------
//
// Function: PktInitializeLocalPartition, public
//
// Synopsis: PktInitializeLocalPartition initializes the Pkt entry
// and its subordinates specified by the ConfigInfo structure
// passed in.
//
// Arguments: [Pkt] - a pointer to an (exclusively) acquired Pkt.
// [LocalVolumeName] - the name of the local volume.
// [ConfigInfo] - the parameters specifying the local
// entry and all its exit points.
//
// Returns: [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory conditions
//
// [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would
// require the invalidation of a local entry or exit point.
//
// [STATUS_INVALID_PARAMETER] - the Id specified for the
// new entry is invalid.
//
// Note: The ConfigInfo argument is stripped of all its Ids as a
// by-product of this operation.
//
// The Pkt needs to be acquired exclusively before calling this.
//
//--------------------------------------------------------------------------
NTSTATUS
PktInitializeLocalPartition(
IN PDFS_PKT Pkt,
IN PUNICODE_STRING LocalVolumeName,
IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo
)
{
NTSTATUS status;
PDFS_PKT_ENTRY entry;
DFS_PKT_ENTRY_ID entryId;
PDFS_SERVICE localService;
PDFS_PKT_RELATION_INFO relationInfo;
PDFS_LOCAL_VOL_ENTRY localVolEntry;
UNICODE_STRING LocalVolumeRelativeName;
DebugTrace(+1, Dbg, "PktInitializeLocalPartition: Entered\n", 0);
ASSERT(ARGUMENT_PRESENT(Pkt) &&
ARGUMENT_PRESENT(LocalVolumeName) &&
ARGUMENT_PRESENT(ConfigInfo));
//
// Now we attempt to create a local service
// structure for this Entry...so allocate some memory.
//
localService = (PDFS_SERVICE) ExAllocatePoolWithTag(PagedPool, sizeof(DFS_SERVICE), ' sfD');
if (localService == NULL) {
DebugTrace(0, Dbg,
"PktInitializeLocalPartition: Cannot allocate local service!\n",0);
DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
return STATUS_INSUFFICIENT_RESOURCES;
}
localVolEntry = (PDFS_LOCAL_VOL_ENTRY) ExAllocatePoolWithTag(
PagedPool,
sizeof(DFS_LOCAL_VOL_ENTRY),
' sfD');
if (localVolEntry == NULL) {
DebugTrace(0, Dbg,
"PktInitializeLocalPartition: Cannot allocate local vol entry!\n",0);
DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
ExFreePool(localService);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Construct the local service. We need to first compute the
// break point between the volume device object name, and the
// local entry point within the volume, which will become the
// service's "address".
//
if (!(ConfigInfo->EntryType & PKT_ENTRY_TYPE_LEAFONLY)) {
status = DfsGetAttachName(
LocalVolumeName,
&LocalVolumeRelativeName);
} else {
LocalVolumeRelativeName = *LocalVolumeName;
status = STATUS_SUCCESS;
}
if (NT_SUCCESS(status)) {
status = PktServiceConstruct(
localService,
ConfigInfo->ServiceType | DFS_SERVICE_TYPE_LOCAL,
PROV_STRIP_PREFIX,
DFS_SERVICE_STATUS_VERIFIED,
PROV_ID_LOCAL_FS,
NULL,
&LocalVolumeRelativeName
);
}
if (!NT_SUCCESS(status)) {
DebugTrace(0, Dbg,
"PktInitializeLocalPartition: Cannot construct local service!\n",0);
DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
ULongToPtr( status ) );
ExFreePool(localService);
ExFreePool(localVolEntry);
return status;
}
//
// Now we attempt to create/update the entry point entry.
//
//
// Remember! the create strips the entry Id off! so we need to
// duplicate the entry id info off the relation info structure
// so that we can pass it into PktCreateEntry...
//
relationInfo = &ConfigInfo->RelationInfo;
status = PktEntryIdConstruct(&entryId,
&relationInfo->EntryId.Uid,
&relationInfo->EntryId.Prefix,
&relationInfo->EntryId.ShortPrefix);
DebugTrace(0, Dbg, "PktEntryIdConstruct returned 0x%x\n", ULongToPtr( status ));
if (NT_SUCCESS(status)) {
status = PktCreateEntry(
Pkt,
ConfigInfo->EntryType | PKT_ENTRY_TYPE_LOCAL | PKT_ENTRY_TYPE_PERMANENT,
&entryId,
NULL,
PKT_ENTRY_SUPERSEDE,
&entry);
DebugTrace(0, Dbg, "PktCreateEntry returned 0x%x\n", ULongToPtr( status ));
}
if (NT_SUCCESS(status)) {
PDFS_PKT_ENTRY subEntry;
PDFS_PKT_ENTRY_ID subId;
PDFS_PKT_ENTRY_ID lastSubId;
//
// We trim the subordinates off the entry that are not
// included in the relation info.
//
PktTrimSubordinates(Pkt, entry, relationInfo);
//
// Go through and create/update all the subordinates.
//
subId = relationInfo->SubordinateIdList;
lastSubId = &subId[ relationInfo->SubordinateIdCount ];
for (subId = relationInfo->SubordinateIdList; subId < lastSubId; subId++) {
PktCreateSubordinateEntry(
Pkt,
entry,
PKT_ENTRY_TYPE_LOCAL_XPOINT | PKT_ENTRY_TYPE_PERMANENT,
subId,
NULL,
PKT_ENTRY_SUPERSEDE,
&subEntry);
DebugTrace(0, Dbg, "PktCreateSubordinateEntry returned 0x%x\n", ULongToPtr( status ));
}
if (NT_SUCCESS(status)) {
//
// We set the local service of this entry...
//
status = PktEntrySetLocalService(
Pkt,
entry,
localService,
localVolEntry,
LocalVolumeName,
&ConfigInfo->Share);
DebugTrace(0, Dbg, "PktEntrySetLocalService returned 0x%x\n", ULongToPtr( status ));
}
if (NT_SUCCESS(status) &&
!(entry->Type & PKT_ENTRY_TYPE_LEAFONLY)) {
status = DfsAttachVolume(
LocalVolumeName,
&localService->pProvider);
if (!NT_SUCCESS(status)) {
PktEntryUnsetLocalService( Pkt, entry, LocalVolumeName );
ExFreePool(localVolEntry);
}
}
if (!NT_SUCCESS(status)) {
//
// We take somewhat draconian measures here. We could
// not complete the initialization so we basically
// invalidate everything to do with this entry.
//
while ((subEntry = PktEntryFirstSubordinate(entry)) != NULL) {
PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE);
}
PktEntryDestroy(entry, Pkt, (BOOLEAN)TRUE);
//
// We need to destroy this as well since it will not get destroyed
// as part of above.
//
PktServiceDestroy(localService, (BOOLEAN)TRUE);
DebugTrace(0, Dbg,
"PktInitializeLocalPartition: Error creating subordinate!\n",0);
}
} else {
//
// we could not create the entry so we need to deallocate the
// service we allocated.
//
PktEntryIdDestroy(&entryId, FALSE);
PktServiceDestroy(localService, (BOOLEAN)TRUE);
ExFreePool(localVolEntry);
DebugTrace(0, Dbg,
"PktInitializeLocalPartition: Cannot create entry!\n", 0);
}
if (NT_SUCCESS(status)) {
if (localService->Type & DFS_SERVICE_TYPE_OFFLINE) {
localService->ProviderId = localService->pProvider->eProviderId;
status = DfspTakeVolumeOffline( Pkt, entry );
}
}
DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
ULongToPtr( status ) );
return status;
}
//+-------------------------------------------------------------------------
//
// Function: RemoveLastComponent, public
//
// Synopsis: Removes the last component of the string passed.
//
// Arguments: [Prefix] -- The prefix whose last component is to be returned.
// [newPrefix] -- The new Prefix with the last component removed.
//
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
//
// Notes: On return, the newPrefix points to the same memory buffer
// as Prefix.
//
//--------------------------------------------------------------------------
void
RemoveLastComponent(
PUNICODE_STRING Prefix,
PUNICODE_STRING newPrefix
)
{
PWCHAR pwch;
USHORT i=0;
*newPrefix = *Prefix;
pwch = newPrefix->Buffer;
pwch += (Prefix->Length/sizeof(WCHAR)) - 1;
while ((*pwch != UNICODE_PATH_SEP) && (pwch != newPrefix->Buffer)) {
i += sizeof(WCHAR);
pwch--;
}
newPrefix->Length = newPrefix->Length - i;
}
//+-------------------------------------------------------------------------
//
// Function: PktCreateEntry, public
//
// Synopsis: PktCreateEntry creates a new partition table entry or
// updates an existing one. The PKT must be acquired
// exclusively for this operation.
//
// Arguments: [Pkt] - pointer to an initialized (and exclusively acquired) PKT
// [PktEntryType] - the type of entry to create/update.
// [PktEntryId] - pointer to the Id of the entry to create
// [PktEntryInfo] - pointer to the guts of the entry
// [CreateDisposition] - specifies whether to overwrite if
// an entry already exists, etc.
// [ppPktEntry] - the new entry is placed here.
//
// Returns: [STATUS_SUCCESS] - if all is well.
//
// [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was
// set to PKT_REPLACE_ENTRY and no entry of the specified
// Id exists to replace.
//
// [DFS_STATUS_ENTRY_EXISTS] - a create disposition of
// PKT_CREATE_ENTRY was specified and an entry of the
// specified Id already exists.
//
// [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would
// required the invalidation of a local entry or exit point.
//
// [STATUS_INVALID_PARAMETER] - the Id specified for the
// new entry is invalid.
//
// [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
// available to complete the operation.
//
// Notes: The PktEntryId and PktEntryInfo structures are MOVED (not
// COPIED) to the new entry. The memory used for UNICODE_STRINGS
// and DFS_SERVICE arrays is used by the new entry. The
// associated fields in the PktEntryId and PktEntryInfo
// structures passed as arguments are Zero'd to indicate that
// the memory has been "deallocated" from these strutures and
// reallocated to the newly created PktEntry. Note that this
// routine does not deallocate the PktEntryId structure or
// the PktEntryInfo structure itself. On successful return from
// this function, the PktEntryId structure will be modified
// to have a NULL Prefix entry, and the PktEntryInfo structure
// will be modified to have zero services and a null ServiceList
// entry.
//
//--------------------------------------------------------------------------
NTSTATUS
PktCreateEntry(
IN PDFS_PKT Pkt,
IN ULONG PktEntryType,
IN PDFS_PKT_ENTRY_ID PktEntryId,
IN PDFS_PKT_ENTRY_INFO PktEntryInfo OPTIONAL,
IN ULONG CreateDisposition,
OUT PDFS_PKT_ENTRY *ppPktEntry
)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT_ENTRY pfxMatchEntry = NULL;
PDFS_PKT_ENTRY uidMatchEntry = NULL;
PDFS_PKT_ENTRY entryToUpdate = NULL;
PDFS_PKT_ENTRY entryToInvalidate = NULL;
PDFS_PKT_ENTRY SupEntry = NULL;
UNICODE_STRING remainingPath = {0, 0, NULL};
UNICODE_STRING newRemainingPath;
ASSERT(ARGUMENT_PRESENT(Pkt) &&
ARGUMENT_PRESENT(PktEntryId) &&
ARGUMENT_PRESENT(ppPktEntry));
DebugTrace(+1, Dbg, "PktCreateEntry: Entered\n", 0);
//
// We're pessimistic at first...
//
*ppPktEntry = NULL;
//
// See if there exists an entry with this prefix. The prefix
// must match exactly (i.e. No remaining path).
//
pfxMatchEntry = PktLookupEntryByPrefix(Pkt,
&PktEntryId->Prefix,
&remainingPath);
if ((remainingPath.Length > 0) ||
(PktEntryId->Prefix.Length == 0)) {
SupEntry = pfxMatchEntry;
pfxMatchEntry = NULL;
} else {
UNICODE_STRING newPrefix;
RemoveLastComponent(&PktEntryId->Prefix, &newPrefix);
SupEntry = PktLookupEntryByPrefix(Pkt,
&newPrefix,
&newRemainingPath);
}
//
// Now search for an entry that has the same Uid.
//
uidMatchEntry = PktLookupEntryByUid(Pkt, &PktEntryId->Uid);
//
// Now we must determine if during this create, we are going to be
// updating or invalidating any existing entries. If an existing
// entry is found that has the same Uid as the one we are trying to
// create, the entry becomes a target for "updating". If the Uid
// passed in is NULL, then we check to see if an entry exists that
// has a NULL Uid AND a Prefix that matches. If this is the case,
// that entry becomes the target for "updating".
//
// To determine if there is an entry to invalidate, we look for an
// entry with the same Prefix as the one we are trying to create, BUT,
// which has a different Uid. If we detect such a situation, we
// we make the entry with the same Prefix the target for invalidation
// (we do not allow two entries with the same Prefix, and we assume
// that the new entry takes precedence).
//
if (uidMatchEntry != NULL) {
entryToUpdate = uidMatchEntry;
if (pfxMatchEntry != uidMatchEntry)
entryToInvalidate = pfxMatchEntry;
} else if ((pfxMatchEntry != NULL) &&
NullGuid(&pfxMatchEntry->Id.Uid)) {
entryToUpdate = pfxMatchEntry;
} else {
entryToInvalidate = pfxMatchEntry;
}
//
// Now we check to make sure that our create disposition is
// consistent with what we are about to do.
//
if ((CreateDisposition & PKT_ENTRY_CREATE) && entryToUpdate != NULL) {
*ppPktEntry = entryToUpdate;
status = DFS_STATUS_ENTRY_EXISTS;
} else if ((CreateDisposition & PKT_ENTRY_REPLACE) && entryToUpdate==NULL) {
status = DFS_STATUS_NO_SUCH_ENTRY;
}
//
// if we have an error here we can get out now!
//
if (!NT_SUCCESS(status)) {
DebugTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr( status ) );
return status;
}
//
// At this point, we have two possible entries - entryToUpdate and
// entryToInvalidate. We make an additional check to see if there is
// a conflict with an 8.3 prefix. This logic works according to the
// following table:
//
// entryToUpdate | entryToInvalidate | 8.3 match || Action
// | | ||
// 0 | 0 | 0 || Create
// | | ||
// 1 | 0 | 0 || Update
// | | ||
// 0 | 1 | 0 || Invalidate/Create
// | | ||
// 1 | 1 | 0 || Invalidate/Update
// | | ||
// 0 | 0 | 1 || 8.3 name conflict
// | | ||
// 1 | 0 | 1 || In entryToUpdate is
// | | || the 8.3 match, ok
// 0 | 1 | 1 || If entryToInvalidate
// | | || is the 8.3 match,
// 1 | 1 | 1 || then invalidate,
// | | || else 8.3 name conflict
//
if (PktEntryId->ShortPrefix.Length != 0) {
PDFS_PKT_ENTRY shortpfxMatch;
shortpfxMatch = PktLookupEntryByShortPrefix(
Pkt,
&PktEntryId->ShortPrefix,
&remainingPath);
if (remainingPath.Length > 0)
shortpfxMatch = NULL;
if (shortpfxMatch != NULL) {
if (entryToUpdate == NULL && entryToInvalidate == NULL) {
status = STATUS_DUPLICATE_NAME;
} else if (entryToUpdate != NULL && entryToInvalidate == NULL) {
if (shortpfxMatch != entryToUpdate) {
status = STATUS_DUPLICATE_NAME;
}
} else if (entryToInvalidate != NULL) {
if (shortpfxMatch != entryToInvalidate) {
status = STATUS_DUPLICATE_NAME;
}
}
}
}
if (!NT_SUCCESS(status)) {
DebugTrace(-1, Dbg,
"PktCreateEntry: (Short name conflict) Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//
// At this point we must insure that we are not going to
// be invalidating any local partition entries.
//
if ((entryToInvalidate != NULL) &&
(!(entryToInvalidate->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) ) &&
(entryToInvalidate->Type &
(PKT_ENTRY_TYPE_LOCAL |
PKT_ENTRY_TYPE_LOCAL_XPOINT |
PKT_ENTRY_TYPE_PERMANENT))) {
DebugTrace(-1, Dbg, "PktCreateEntry(1): Exit -> %08lx\n",
ULongToPtr( DFS_STATUS_LOCAL_ENTRY ) );
return DFS_STATUS_LOCAL_ENTRY;
}
//
// We go up the links till we reach a REFERRAL entry type. Actually
// we may never go up since we always link to a REFERRAL entry. Anyway
// no harm done!
//
while ((SupEntry != NULL) &&
!(SupEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC)) {
SupEntry = SupEntry->ClosestDC;
}
//
// If we had success then we need to see if we have to
// invalidate an entry.
//
if (NT_SUCCESS(status) && entryToInvalidate != NULL)
PktEntryDestroy(entryToInvalidate, Pkt, (BOOLEAN)TRUE);
//
// If we are not updating an entry we must construct a new one
// from scratch. Otherwise we need to update.
//
if (entryToUpdate != NULL) {
status = PktEntryReassemble(entryToUpdate,
Pkt,
PktEntryType,
PktEntryId,
PktEntryInfo);
if (NT_SUCCESS(status)) {
(*ppPktEntry) = entryToUpdate;
PktEntryLinkChild(SupEntry, entryToUpdate);
}
} else {
//
// Now we are going to create a new entry. So we have to set
// the ClosestDC Entry pointer while creating this entry. The
// ClosestDC entry value is already in SupEntry.
//
PDFS_PKT_ENTRY newEntry;
newEntry = (PDFS_PKT_ENTRY) ExAllocatePoolWithTag(
PagedPool,
sizeof(DFS_PKT_ENTRY),
' sfD');
if (newEntry == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
status = PktEntryAssemble(newEntry,
Pkt,
PktEntryType,
PktEntryId,
PktEntryInfo);
if (!NT_SUCCESS(status)) {
ExFreePool(newEntry);
} else {
(*ppPktEntry) = newEntry;
PktEntryLinkChild(SupEntry, newEntry);
}
}
}
DebugTrace(-1, Dbg, "PktCreateEntry(2): Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktCreateSubordinateEntry, public
//
// Synopsis: PktCreateSubordinateEntry creates/updates an entry to be
// subordinate to an existing entry.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Superior] - a pointer to the superior entry.
// [SubordinateType] - the type of subordinate entry to
// create/update.
// [SubordinateId] - the Id of the entry to create/update
// to be subordinate.
// [SubordinateInfo] - the Info of the entry to create/update.
// [CreateDisposition] - identifies whether or not to supersede,
// create, or update.
// [Subordinate] - the (potentially new) subordinate entry.
//
// Returns: [STATUS_SUCCESS] - if all is well.
// [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was
// set to PKT_REPLACE_ENTRY and the Subordinate entry does
// not exist.
// [DFS_STATUS_ENTRY_EXISTS] - a create disposition of
// PKT_CREATE_ENTRY was specified and the subordinate entry
// already exists.
// [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry
// would have required that a local entry or exit point
// be invalidated.
// [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT
// has been discovered.
// [STATUS_INVALID_PARAMETER] - the Id specified for the
// subordinate is invalid.
// [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
// available to complete the operation.
//
//
// Notes: If the subordinate exists and is currently a subordinate
// of some other entry (then the Superior specified), it is
// first removed from the old superior before making it
// a subordinate of the Superior specified.
//
// The SubordinateId and SubordinateInfo structures are MOVED (not
// COPIED) to the new entry. The memory used for UNICODE_STRINGS
// and DFS_SERVICE arrays is used by the new entry. The
// associated fields in the SubordinateId and SubordinateInfo
// structures passed as arguments are Zero'd to indicate that
// the memory has been "deallocated" from these strutures and
// reallocated to the newly created Subordinate. Note that this
// routine does not deallocate the SubordinateId structure or
// the SubordinateInfo structure itself. On successful return from
// this function, the SubordinateId structure will be modified
// to have a NULL Prefix entry, and the SubordinateInfo structure
// will be modified to have zero services and a null ServiceList
// entry.
//--------------------------------------------------------------------------
NTSTATUS
PktCreateSubordinateEntry(
IN PDFS_PKT Pkt,
IN PDFS_PKT_ENTRY Superior,
IN ULONG SubordinateType,
IN PDFS_PKT_ENTRY_ID SubordinateId,
IN PDFS_PKT_ENTRY_INFO SubordinateInfo OPTIONAL,
IN ULONG CreateDisposition,
IN OUT PDFS_PKT_ENTRY *Subordinate
)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT_ENTRY subEntry;
DebugTrace(+1, Dbg, "PktCreateSubordinateEntry: Entered\n", 0);
ASSERT(ARGUMENT_PRESENT(Pkt));
ASSERT(ARGUMENT_PRESENT(Superior));
ASSERT(ARGUMENT_PRESENT(SubordinateId));
ASSERT(ARGUMENT_PRESENT(Subordinate));
//
// Now we go ahead and create the new sub entry...
//
status = PktCreateEntry(
Pkt,
SubordinateType,
SubordinateId,
SubordinateInfo,
CreateDisposition,
&subEntry
);
if (NT_SUCCESS(status)) {
PktSetTypeInheritance(Superior, subEntry)
//
// Link the child to the parent...note that this removes the
// child from any other parent.
//
PktEntryLinkSubordinate(Superior, subEntry);
//
// Don't forget to set the return value...
//
(*Subordinate) = subEntry;
}
DebugTrace(-1, Dbg, "PktCreateSubordinateEntry: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktEntryModifyPrefix, public
//
// Synopsis: PktEntryModifyPrefix finds an entry that has a
// specified prefix. The PKT must be acquired for
// this operation.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Prefix] - the volume's new entry path
// [Entry] - pointer to the PKT entry that needs to be modified.
//
// Returns: [DFS_STATUS_BAD_EXIT_POINT] -- If the new prefix could
// not be inserted into the prefix table.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- If room for the new
// prefix could not be allocated.
//
// [STATUS_SUCCESS] -- If everything succeeds.
//
// Notes: If everything succeeds, the old Entry->Id.Prefix.Buffer is
// freed up. If this function fails, then everything, including
// the prefix table, is left intact.
//
//--------------------------------------------------------------------------
NTSTATUS
PktEntryModifyPrefix(
IN PDFS_PKT Pkt,
IN PUNICODE_STRING Prefix,
IN PDFS_PKT_ENTRY Entry)
{
NTSTATUS status;
UNICODE_STRING oldPrefix = Entry->Id.Prefix;
DebugTrace(+1, Dbg, "PktEntryModifyPrefix: Entered\n", 0);
//
// First, try to allocate space for the new prefix. The old one has
// already been saved in oldPrefix
//
Entry->Id.Prefix.Buffer = ExAllocatePoolWithTag(PagedPool, Prefix->MaximumLength, ' sfD');
if (Entry->Id.Prefix.Buffer != NULL) {
//
// Next, get rid of the existing prefix from the PrefixTable.
//
DfsRemoveUnicodePrefix(&(Pkt->PrefixTable), &oldPrefix);
//
// Now we will plug in the actual prefix.
//
wcscpy(Entry->Id.Prefix.Buffer, Prefix->Buffer);
Entry->Id.Prefix.Length = Prefix->Length;
Entry->Id.Prefix.MaximumLength = Prefix->MaximumLength;
if (DfsInsertUnicodePrefix(&Pkt->PrefixTable,
&(Entry->Id.Prefix),
&(Entry->PrefixTableEntry))) {
ExFreePool(oldPrefix.Buffer);
status = STATUS_SUCCESS;
} else {
ExFreePool( Entry->Id.Prefix.Buffer );
Entry->Id.Prefix = oldPrefix;
DfsInsertUnicodePrefix(&Pkt->PrefixTable,
&(Entry->Id.Prefix),
&(Entry->PrefixTableEntry));
status = DFS_STATUS_BAD_EXIT_POINT;
}
} else {
DebugTrace(0, Dbg,
"PktEntryModifyPrefix: Unable to allocate %d bytes\n",
Prefix->MaximumLength);
Entry->Id.Prefix = oldPrefix;
status = STATUS_INSUFFICIENT_RESOURCES;
}
DebugTrace(-1, Dbg, "PktEntryModifyPrefix: Exit -> %08lx\n", ULongToPtr( status ));
return(status);
}
//+-------------------------------------------------------------------------
//
// Function: PktLookupEntryById, public
//
// Synopsis: PktLookupEntryById finds an entry that has a
// specified Entry Id. The PKT must be acquired for
// this operation.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Id] - the partitions Id to lookup.
//
// Returns: The PKT_ENTRY that has the exact same Id, or NULL,
// if none exists.
//
// Notes:
//
//--------------------------------------------------------------------------
PDFS_PKT_ENTRY
PktLookupEntryById(
IN PDFS_PKT Pkt,
IN PDFS_PKT_ENTRY_ID Id
)
{
PDFS_PKT_ENTRY ep;
UNICODE_STRING remaining;
DebugTrace(+1, Dbg, "PktLookupEntryById: Entered\n", 0);
ASSERT(ARGUMENT_PRESENT(Pkt) &&
ARGUMENT_PRESENT(Id));
ep = PktLookupEntryByPrefix(Pkt, &Id->Prefix, &remaining);
if (ep != NULL) {
if (remaining.Length != 0 || !GuidEqual(&Id->Uid, &ep->Id.Uid))
ep = NULL;
}
DebugTrace(-1, Dbg, "PktLookupEntryById: Exit -> %08lx\n", ep );
return ep;
}
//+-------------------------------------------------------------------------
//
// Function: PktLookupEntryByPrefix, public
//
// Synopsis: PktLookupEntryByPrefix finds an entry that has a
// specified prefix. The PKT must be acquired for
// this operation.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Prefix] - the partitions prefix to lookup.
// [Remaining] - any remaining path. Points within
// the Prefix to where any trailing (nonmatched)
// characters are.
//
// Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
// if none exists.
//
// Notes:
//
//--------------------------------------------------------------------------
PDFS_PKT_ENTRY
PktLookupEntryByPrefix(
IN PDFS_PKT Pkt,
IN PUNICODE_STRING Prefix,
OUT PUNICODE_STRING Remaining
)
{
PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
PDFS_PKT_ENTRY pktEntry;
UNICODE_STRING PrefixTail;
UNICODE_STRING EntryTail;
DebugTrace(+1, Dbg, "PktLookupEntryByPrefix: Entered\n", 0);
//
// If there really is a prefix to lookup, use the prefix table
// to initially find an entry
//
if ((Prefix->Length != 0) &&
(pfxEntry = DfsFindUnicodePrefix(&Pkt->PrefixTable,Prefix,Remaining))) {
USHORT pfxLength;
//
// reset a pointer to the corresponding entry
//
pktEntry = CONTAINING_RECORD(pfxEntry,
DFS_PKT_ENTRY,
PrefixTableEntry
);
RemoveFirstComponent(Prefix,&PrefixTail);
RemoveFirstComponent(&pktEntry->Id.Prefix,&EntryTail);
pfxLength = EntryTail.Length;
//
// Now calculate the remaining path and return
// the entry we found. Note that we bump the length
// up by one char so that we skip any path separater.
//
if ((pfxLength < PrefixTail.Length) &&
(PrefixTail.Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
pfxLength += sizeof(WCHAR);
if (pfxLength <= PrefixTail.Length) {
Remaining->Length = (USHORT)(PrefixTail.Length - pfxLength);
Remaining->Buffer = &PrefixTail.Buffer[pfxLength/sizeof(WCHAR)];
Remaining->MaximumLength = (USHORT)(PrefixTail.MaximumLength - pfxLength);
DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: Remaining = %wZ\n",
Remaining);
} else {
Remaining->Length = Remaining->MaximumLength = 0;
Remaining->Buffer = NULL;
DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: No Remaining\n", 0);
}
DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n",
pktEntry);
return pktEntry;
}
DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n", NULL);
return NULL;
}
//+-------------------------------------------------------------------------
//
// Function: PktLookupEntryByShortPrefix, public
//
// Synopsis: PktLookupEntryByShortPrefix finds an entry that has a
// specified short (8.3) prefix. The PKT must be acquired for
// this operation.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Prefix] - the partitions prefix to lookup.
// [Remaining] - any remaining path. Points within
// the Prefix to where any trailing (nonmatched)
// characters are.
//
// Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
// if none exists.
//
// Notes:
//
//--------------------------------------------------------------------------
PDFS_PKT_ENTRY
PktLookupEntryByShortPrefix(
IN PDFS_PKT Pkt,
IN PUNICODE_STRING Prefix,
OUT PUNICODE_STRING Remaining
)
{
PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
PDFS_PKT_ENTRY pktEntry;
DebugTrace(+1, Dbg, "PktLookupEntryByShortPrefix: Entered\n", 0);
//
// If there really is a prefix to lookup, use the prefix table
// to initially find an entry
//
if ((Prefix->Length != 0) &&
(pfxEntry = DfsFindUnicodePrefix(&Pkt->ShortPrefixTable,Prefix,Remaining))) {
USHORT pfxLength;
//
// reset a pointer to the corresponding entry
//
pktEntry = CONTAINING_RECORD(pfxEntry,
DFS_PKT_ENTRY,
PrefixTableEntry
);
pfxLength = pktEntry->Id.ShortPrefix.Length;
//
// Now calculate the remaining path and return
// the entry we found. Note that we bump the length
// up by one char so that we skip any path separater.
//
if ((pfxLength < Prefix->Length) &&
(Prefix->Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
pfxLength += sizeof(WCHAR);
if (pfxLength <= Prefix->Length) {
Remaining->Length = (USHORT)(Prefix->Length - pfxLength);
Remaining->Buffer = &Prefix->Buffer[pfxLength/sizeof(WCHAR)];
Remaining->MaximumLength = (USHORT)(Prefix->MaximumLength - pfxLength);
DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: Remaining = %wZ\n",
Remaining);
} else {
Remaining->Length = Remaining->MaximumLength = 0;
Remaining->Buffer = NULL;
DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: No Remaining\n", 0);
}
DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n",
pktEntry);
return pktEntry;
}
DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n", NULL);
return NULL;
}
//+-------------------------------------------------------------------------
//
// Function: PktLookupEntryByUid, public
//
// Synopsis: PktLookupEntryByUid finds an entry that has a
// specified Uid. The PKT must be acquired for this operation.
//
// Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
// [Uid] - a pointer to the partitions Uid to lookup.
//
// Returns: A pointer to the PKT_ENTRY that has the exact same
// Uid, or NULL, if none exists.
//
// Notes: The input Uid cannot be the Null GUID.
//
// On a DC where there may be *lots* of entries in the PKT,
// we may want to consider using some other algorithm for
// looking up by ID.
//
//--------------------------------------------------------------------------
PDFS_PKT_ENTRY
PktLookupEntryByUid(
IN PDFS_PKT Pkt,
IN GUID *Uid
) {
PDFS_PKT_ENTRY entry;
DebugTrace(+1, Dbg, "PktLookupEntryByUid: Entered\n", 0);
//
// We don't lookup NULL Uids
//
if (NullGuid(Uid)) {
DebugTrace(0, Dbg, "PktLookupEntryByUid: NULL Guid\n", NULL);
entry = NULL;
} else {
entry = PktFirstEntry(Pkt);
}
while (entry != NULL) {
if (GuidEqual(&entry->Id.Uid, Uid))
break;
entry = PktNextEntry(Pkt, entry);
}
DebugTrace(-1, Dbg, "PktLookupEntryByUid: Exit -> %08lx\n", entry);
return entry;
}
//+-------------------------------------------------------------------------
//
// Function: PktSetRelationInfo, public
//
// Synopsis: PktSetRelationInfo takes the information specified in a
// relation info structure and sets the Pkt entries accordingly.
//
// Arguments: [Pkt] - a pointer to an exclusively acquired Pkt.
// [RelationInfo] - a pointer to a relation info structure
// specifying the relationship that is to be set.
//
// Returns: [STATUS_SUCCESS] - if all is well.
// [DFS_STATUS_NO_SUCH_ENTRY] - the EntryId specified in the
// Relation Info structure does not exist.
// [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry
// would have required that a local entry or exit point
// be invalidated.
// [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT
// has been discovered.
// [STATUS_INVALID_PARAMETER] - the Id specified for a
// subordinate is invalid.
// [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
// available to complete the operation.
//
//
// Notes: If this operation fails, all subordinates of the entry
// are cleared.
//
//--------------------------------------------------------------------------
NTSTATUS
PktSetRelationInfo(
IN PDFS_PKT Pkt,
IN PDFS_PKT_RELATION_INFO RelationInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT_ENTRY entry;
ULONG i;
DebugTrace(+1, Dbg, "PktSetRelationalInfo: Entered\n", 0);
ASSERT(ARGUMENT_PRESENT(Pkt));
ASSERT(ARGUMENT_PRESENT(RelationInfo));
//
// We need to lookup the entry for which we are setting relation
// information on.
//
if ((entry = PktLookupEntryById(Pkt, &RelationInfo->EntryId)) == NULL) {
DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n",
ULongToPtr( DFS_STATUS_NO_SUCH_ENTRY ));
return DFS_STATUS_NO_SUCH_ENTRY;
}
//
// Now we go and trim off any subordinates that aren't
// currently identified in the Relation Info structure.
//
PktTrimSubordinates(Pkt, entry, RelationInfo);
//
// Go through the relation info structure creating subordinates
//
for (i = 0; i < RelationInfo->SubordinateIdCount; i++) {
PDFS_PKT_ENTRY subEntry;
status = PktCreateSubordinateEntry(
Pkt,
entry,
0L,
&RelationInfo->SubordinateIdList[i],
NULL,
PKT_ENTRY_SUPERSEDE,
&subEntry
);
if (!NT_SUCCESS(status)) {
//
// If there was an error, we clear away all subordinates.
// ...It's an all or nothing proposition...
//
PktEntryClearSubordinates(entry);
break;
}
}
DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktTrimSubordinates, public
//
// Synopsis: PktTrimSubordinates invalidates all subordinate entries
// that are not specified in the relation info structure
// supplied.
//
// Arguments: [Pkt] - a pointer to an exclusively acquired Pkt.
// [PktEntry] - a pointer to an entry that is to have all its
// subordinates unlinked.
// [RelationInfo] - a pointer to a relation info structure
// specifying the relationship that the Pkt is to
// be trimmed to.
//
// Returns: VOID
//
// Notes: This operation does not insure that all the subordinates
// exist, it only insures that no subordinates that are
// NOT specified in the relation info structure exist.
//
//--------------------------------------------------------------------------
VOID
PktTrimSubordinates(
IN PDFS_PKT Pkt,
IN PDFS_PKT_ENTRY Entry,
IN PDFS_PKT_RELATION_INFO RInfo
)
{
PDFS_PKT_ENTRY subEntry;
DebugTrace(+1, Dbg, "PktTrimSubordinates: Entered\n", 0);
ASSERT(ARGUMENT_PRESENT(Entry));
ASSERT(ARGUMENT_PRESENT(RInfo));
ASSERT(PktEntryIdEqual(&Entry->Id, &RInfo->EntryId));
//
// go through the list of subordinate entries
//
subEntry = PktEntryFirstSubordinate(Entry);
while (subEntry != NULL) {
PDFS_PKT_ENTRY_ID id;
PDFS_PKT_ENTRY nextSubEntry;
BOOLEAN onTheList;
//
// Search the list of subordinate ids to insure that this
// subordinate is on it.
//
for (onTheList = FALSE, id = RInfo->SubordinateIdList;
id < &RInfo->SubordinateIdList[RInfo->SubordinateIdCount];
id++) {
if (PktEntryIdEqual(&subEntry->Id, id)) {
onTheList = TRUE;
break;
}
}
//
// If we didn't find the subordinate on the list, we destroy...
// Note that we have to get the next subordinate prior to this
// just in case the current one gets nuked!
//
nextSubEntry = PktEntryNextSubordinate(Entry, subEntry);
if (!onTheList)
PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE);
//
// go to the next subordinate entry...
//
subEntry = nextSubEntry;
}
DebugTrace(-1, Dbg, "PktTrimSubordinates: Exit -> VOID\n", 0);
}
//+----------------------------------------------------------------------------
//
// Function: PktpPruneExtraVolume
//
// Synopsis: Sometimes a DC thinks this server has an extra volume, so
// that volume's knowledge needs to be pruned from the pkt and
// registry, and the volume's exit points need to be deleted
// from the disk. This routine is a helper routine to do that.
//
// Arguments: [RelationInfo] -- The Relation Info for the local volume
// that needs to be pruned.
//
// Returns: [STATUS_SUCCESS] -- Local volume and its exit pts were deleted
//
// [STATUS_UNSUCCESSFUL] -- Some errors were encountered in
// deleting the local volume; for each error, a message
// was logged.
//
// Notes: Assumes Pkt has been acquired exclusive
//
// History: 05-April-95 Milans created
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpPruneExtraVolume(
IN PDFS_PKT_RELATION_INFO RelationInfo)
{
NTSTATUS status, returnStatus;
PDFS_PKT_ENTRY_ID peid;
UNICODE_STRING puStr[2];
ULONG i;
puStr[1].MaximumLength = sizeof(L"LocalMachine");
puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
puStr[1].Buffer = L"LocalMachine";
//
// First we delete all the exit Points.
//
returnStatus = STATUS_SUCCESS;
peid = RelationInfo->SubordinateIdList;
for (i = 0; i < RelationInfo->SubordinateIdCount; i++) {
status = DfsInternalDeleteExitPoint(peid, PKT_ENTRY_TYPE_CAIRO);
if (!NT_SUCCESS(status)) {
DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: DeletingExitPt "
"failed: %08lx\n", ULongToPtr( status ));
puStr[0] = peid->Prefix;
LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr);
returnStatus = STATUS_UNSUCCESSFUL;
}
peid++;
}
status = DfsInternalDeleteLocalVolume(&RelationInfo->EntryId);
if (!NT_SUCCESS(status)) {
puStr[0] = RelationInfo->EntryId.Prefix;
DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: Deleting "
"Extra Local Volume failed: %08lx\n", ULongToPtr( status ));
LogWriteMessage(EXTRA_VOLUME_NOT_DELETED, status, 2, puStr);
returnStatus = STATUS_UNSUCCESSFUL;
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: PktpFixupRelationInfo
//
// Synopsis: Sometimes a DC will discover that this server has the wrong
// information about a local volume. This routine will fix up
// the local knowledge to that of the DC.
//
// Arguments:
//
// Returns: [STATUS_SUCCESS] -- We managed to completely sync up with
// the DC's relation info.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory.
//
// [STATUS_UNSUCCESSFUL] -- We were unable to fully sync up -
// a message was logged for the errors encountered.
//
// Notes: Assumes Pkt has been acquired exclusive
//
// History: 05-April-95 Milans created
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpFixupRelationInfo(
IN PDFS_PKT_RELATION_INFO Local,
IN PDFS_PKT_RELATION_INFO Remote)
{
NTSTATUS status, returnStatus;
PUNICODE_STRING lpfx, rpfx;
ULONG i, j=0;
ULONG *pulExitPtUsed = NULL;
UNICODE_STRING LocalMachStr;
UNICODE_STRING puStr[3];
UNICODE_STRING unusedShortPrefix;
LocalMachStr.MaximumLength = sizeof(L"LocalMachine");
LocalMachStr.Length = LocalMachStr.MaximumLength - sizeof(WCHAR);
LocalMachStr.Buffer = L"LocalMachine";
returnStatus = status = STATUS_SUCCESS;
//
// The GUIDs of this volume have already been matched otherwise we
// would not be here. So we don't even look at that. We still
// need to match the prefixes. If the prefixes are different then we
// need to fix that.
//
lpfx = &Local->EntryId.Prefix;
rpfx = &Remote->EntryId.Prefix;
if (RtlCompareUnicodeString(lpfx, rpfx, TRUE)) {
//
// The Prefixes are different we need to fix this now.
// But first let us log this event.
//
DebugTrace(0, Dbg, "Fixed Prefix [%wZ]\n", rpfx);
DebugTrace(0, Dbg, "To be [%wZ]\n", lpfx);
puStr[0] = Local->EntryId.Prefix;
puStr[1] = Remote->EntryId.Prefix;
puStr[2] = LocalMachStr;
LogWriteMessage(PREFIX_MISMATCH, status, 3, puStr);
status = DfsInternalModifyPrefix(&Remote->EntryId);
if (NT_SUCCESS(status)) {
LogWriteMessage(PREFIX_MISMATCH_FIXED, status, 3, puStr);
} else {
DebugTrace(0, 1, "Dfs - PktRelationInfoValidate: "
"Status from DfsModifyePrefix = %08lx\n", ULongToPtr( status ));
LogWriteMessage(PREFIX_MISMATCH_NOT_FIXED, status, 3,puStr);
}
}
if (Remote->SubordinateIdCount != 0) {
ULONG size = sizeof(ULONG) * Remote->SubordinateIdCount;
pulExitPtUsed = ExAllocatePoolWithTag( PagedPool, size, ' sfD' );
if (pulExitPtUsed == NULL) {
return ( STATUS_INSUFFICIENT_RESOURCES );
} else {
RtlZeroMemory( pulExitPtUsed, size );
}
}
//
// We step through each exit point in the local knowledge and
// make sure that is right. If not we attempt to delete the exit
// point from this machine. So this takes care of EXTRA
// ExitPoints at this machine. We will still need to deal with
// ExitPoints which the DC knows of whereas the this machine does
// not. So we keep track of all the remote exit points which have
// been acounted for by the local Relational info and then we
// take the rest and create those exit points at this machine.
// This takes care of TOO FEW ExitPoints at this machine.
//
for (i = 0; i < Local->SubordinateIdCount; i++) {
ULONG j;
GUID *lguid, *rguid;
rpfx = &Local->SubordinateIdList[i].Prefix;
rguid = &Local->SubordinateIdList[i].Uid;
status = DFS_STATUS_BAD_EXIT_POINT;
for (j = 0; j < Remote->SubordinateIdCount; j++) {
lpfx = &Remote->SubordinateIdList[j].Prefix;
lguid = &Remote->SubordinateIdList[j].Uid;
if (!RtlCompareUnicodeString(lpfx, rpfx, TRUE) &&
GuidEqual(lguid, rguid)) {
status = STATUS_SUCCESS;
ASSERT(pulExitPtUsed[j] == FALSE);
pulExitPtUsed[j] = TRUE;
break;
}
}
if (!NT_SUCCESS(status)) {
//
// In this case we have an exit point which the DC does not
// recognise. We need to delete this.
//
puStr[0] = Local->SubordinateIdList[i].Prefix;
puStr[1] = LocalMachStr;
LogWriteMessage(EXTRA_EXIT_POINT, status, 2, puStr);
status =
DfsInternalDeleteExitPoint(&Local->SubordinateIdList[i],
PKT_ENTRY_TYPE_CAIRO);
if (!NT_SUCCESS(status)) {
//
// We want to Log an event here actually.
//
DebugTrace(0, 1,
"Dfs - PktpFixupRelationInfo: Failed to delete [%wZ]\n",
&Local->SubordinateIdList[i].Prefix );
LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr);
returnStatus = STATUS_UNSUCCESSFUL;
} else {
LogWriteMessage(EXTRA_EXIT_POINT_DELETED, status, 2, puStr);
}
}
}
//
// Now that we are done with getting rid of extra exit points
// we only need to deal with any exit point that we dont have
// and create any such that might exist.
//
for (i = 0; i < Remote->SubordinateIdCount; i++) {
if (pulExitPtUsed[i] == FALSE) {
puStr[0] = Remote->SubordinateIdList[i].Prefix;
puStr[1] = LocalMachStr;
LogWriteMessage(MISSING_EXIT_POINT, status, 2, puStr);
RtlInitUnicodeString(&unusedShortPrefix, NULL);
status = DfsInternalCreateExitPoint(
&Remote->SubordinateIdList[i],
PKT_ENTRY_TYPE_CAIRO,
FILE_OPEN_IF,
&unusedShortPrefix);
if (NT_SUCCESS(status) && unusedShortPrefix.Buffer != NULL) {
ExFreePool(unusedShortPrefix.Buffer);
}
if (!NT_SUCCESS(status)) {
//
// We want to Log an event here actually.
//
DebugTrace(0, 1, "DFS - PktpFixupRelationInfo: "
"Failed to Create ExitPt [%wZ]\n",
&Remote->SubordinateIdList[i].Prefix);
LogWriteMessage(MISSING_EXIT_POINT_NOT_CREATED,
status,
2,
puStr);
returnStatus = STATUS_UNSUCCESSFUL;
} else {
LogWriteMessage(MISSING_EXIT_POINT_CREATED,
status,
2,
puStr);
}
}
} // end for each subordinate in remote relation info
if (pulExitPtUsed != NULL) {
ExFreePool(pulExitPtUsed);
}
return( returnStatus );
}
//+----------------------------------------------------------------------------
//
// Function: PktShuffleServiceList
//
// Synopsis: Randomizes a service list for proper load balancing. This
// routine assumes that the service list is ordered based on
// site costs. For each equivalent cost group, this routine
// shuffles the service list.
//
// Arguments: [pInfo] -- Pointer to PktEntryInfo whose service list needs to
// be shuffled.
//
// Returns: Nothing, unless rand() fails!
//
//-----------------------------------------------------------------------------
VOID
PktShuffleServiceList(
PDFS_PKT_ENTRY_INFO pInfo)
{
PktShuffleGroup(pInfo, 0, pInfo->ServiceCount);
}
//+----------------------------------------------------------------------------
//
// Function: PktShuffleGroup
//
// Synopsis: Shuffles a cost equivalent group of services around for load
// balancing. Uses the classic card shuffling algorithm - for
// each card in the deck, exchange it with a random card in the
// deck.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
VOID
PktShuffleGroup(
PDFS_PKT_ENTRY_INFO pInfo,
ULONG nStart,
ULONG nEnd)
{
ULONG i;
LARGE_INTEGER seed;
ASSERT( nStart < pInfo->ServiceCount );
ASSERT( nEnd <= pInfo->ServiceCount );
KeQuerySystemTime( &seed );
for (i = nStart; i < nEnd; i++) {
DFS_SERVICE TempService;
ULONG j;
ASSERT (nEnd - nStart != 0);
j = (RtlRandom( &seed.LowPart ) % (nEnd - nStart)) + nStart;
ASSERT( j >= nStart && j <= nEnd );
TempService = pInfo->ServiceList[i];
pInfo->ServiceList[i] = pInfo->ServiceList[j];
pInfo->ServiceList[j] = TempService;
}
}
//+----------------------------------------------------------------------------
//
// Function: DfsBuildConnectionRequest
//
// Synopsis: Builds the EA and file names necessary to setup an
// authenticated connection to a server.
//
// Arguments: [pService] -- Pointer to DFS_SERVICE describing server
// [pProvider] -- Pointer to PROVIDER_DEF describing the
// provider to use to establish the connection.
// [pShareName] -- Share name to open.
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
//-----------------------------------------------------------------------------
NTSTATUS DfsBuildConnectionRequest(
IN PDFS_SERVICE pService,
IN PPROVIDER_DEF pProvider,
OUT PUNICODE_STRING pShareName)
{
ASSERT(pService != NULL);
ASSERT(pProvider != NULL);
RtlInitUnicodeString(pShareName, NULL);
pShareName->Length = 0;
pShareName->MaximumLength = pProvider->DeviceName.Length +
sizeof(UNICODE_PATH_SEP_STR) +
pService->Name.Length +
sizeof(ROOT_SHARE_NAME);
pShareName->Buffer = ExAllocatePoolWithTag(PagedPool, pShareName->MaximumLength, ' sfD');
if (pShareName->Buffer == NULL) {
DebugTrace(0, Dbg, "Unable to allocate pool for share name!\n", 0);
pShareName->Length = pShareName->MaximumLength = 0;
return( STATUS_INSUFFICIENT_RESOURCES );
}
RtlAppendUnicodeStringToString( pShareName, &pProvider->DeviceName );
RtlAppendUnicodeToString( pShareName, UNICODE_PATH_SEP_STR );
RtlAppendUnicodeStringToString( pShareName, &pService->Name );
RtlAppendUnicodeToString( pShareName, ROOT_SHARE_NAME );
return( STATUS_SUCCESS );
}
//+----------------------------------------------------------------------------
//
// Function: DfsFreeConnectionRequest
//
// Synopsis: Frees up the stuff allocated on a successful call to
// DfsBuildConnectionRequest
//
// Arguments: [pShareName] -- Unicode string holding share name.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID
DfsFreeConnectionRequest(
IN OUT PUNICODE_STRING pShareName)
{
if (pShareName->Buffer != NULL) {
ExFreePool ( pShareName->Buffer );
}
}
//+-------------------------------------------------------------------------
//
// Function: DfsCreateConnection -- Create a connection to a server
//
// Synopsis: DfsCreateConnection will attempt to create a connection
// to some server's IPC$ share.
//
// Arguments: [pService] -- the Service entry, giving the server principal
// name
// [remoteHandle] -- This is where the handle is returned.
//
// Returns: NTSTATUS - the status of the operation
//
// Notes: The Pkt must be acquired shared before calling this! It will
// be released and reacquired in this routine.
//
// History: 31 Mar 1993 SudK Created
//
//--------------------------------------------------------------------------
NTSTATUS
DfsCreateConnection(
IN PDFS_SERVICE pService,
IN PPROVIDER_DEF pProvider,
OUT PHANDLE remoteHandle
) {
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING ShareName;
NTSTATUS Status;
ASSERT(pService != NULL);
ASSERT(pProvider != NULL);
ASSERT(ExIsResourceAcquiredSharedLite( &DfsData.Pkt.Resource ));
Status = DfsBuildConnectionRequest(
pService,
pProvider,
&ShareName);
if (!NT_SUCCESS(Status)) {
return( Status );
}
InitializeObjectAttributes(
&ObjectAttributes,
&ShareName, // File Name
0, // Attributes
NULL, // Root Directory
NULL // Security
);
//
// Create or open a tree connection
//
PktRelease( &DfsData.Pkt );
Status = ZwCreateFile(
remoteHandle,
SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
PktAcquireShared( &DfsData.Pkt, TRUE );
if ( NT_SUCCESS( Status ) ) {
DebugTrace(0, Dbg, "Created Connection Successfully\n", 0);
Status = IoStatusBlock.Status;
}
DfsFreeConnectionRequest( &ShareName );
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: DfsCloseConnection -- Close a connection to a server
//
// Synopsis: DfsCloseConnection will attempt to Close a connection
// to some server.
//
// Effects: The file object referring to the the connection will be
// closed.
//
// Arguments: pService - the Service entry, giving the server connection
// handle
//
// Returns: NTSTATUS - the status of the operation
//
// History: 28 May 1992 Alanw Created
//
//--------------------------------------------------------------------------
NTSTATUS
DfsCloseConnection(
IN PDFS_SERVICE pService
)
{
ASSERT( pService->ConnFile != NULL );
ObDereferenceObject(pService->ConnFile);
pService->ConnFile = NULL;
return STATUS_SUCCESS;
}
//+-------------------------------------------------------------------------
//
// Function: DfsConcatenateFilePath, public
//
// Synopsis: DfsConcatenateFilePath will concatenate two strings
// representing file path names, assuring that they are
// separated by a single '\' character.
//
// Arguments: [Dest] - a pointer to the destination string
// [RemainingPath] - the final part of the path name
// [Length] - the length (in bytes) of RemainingPath
//
// Returns: BOOLEAN - TRUE unless Dest is too small to
// hold the result (assert).
//
//--------------------------------------------------------------------------
BOOLEAN
DfsConcatenateFilePath (
IN PUNICODE_STRING Dest,
IN PWSTR RemainingPath,
IN USHORT Length
) {
PWSTR OutBuf = (PWSTR)&(((PCHAR)Dest->Buffer)[Dest->Length]);
if (Dest->Length > 0) {
ASSERT(OutBuf[-1] != UNICODE_NULL);
}
if (Dest->Length > 0 && OutBuf[-1] != UNICODE_PATH_SEP) {
*OutBuf++ = UNICODE_PATH_SEP;
Dest->Length += sizeof (WCHAR);
}
if (Length > 0 && *RemainingPath == UNICODE_PATH_SEP) {
RemainingPath++;
Length -= sizeof (WCHAR);
}
ASSERT(Dest->MaximumLength >= (USHORT)(Dest->Length + Length));
if (Length > 0) {
RtlMoveMemory(OutBuf, RemainingPath, Length);
Dest->Length += Length;
}
return TRUE;
}