mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
781 lines
22 KiB
781 lines
22 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1992, Microsoft Corporation.
|
|
//
|
|
// File: PKTFSCTL.C
|
|
//
|
|
// Contents: This module contains the implementation for FS controls
|
|
// which manipulate the PKT.
|
|
//
|
|
// Functions: PktFsctrlUpdateDomainKnowledge -
|
|
// PktFsctrlGetRelationInfo -
|
|
// PktFsctrlSetRelationInfo -
|
|
// PktFsctrlIsChildnameLegal -
|
|
// PktFsctrlCreateEntry -
|
|
// PktFsctrlCreateSubordinateEntry -
|
|
// PktFsctrlDestroyEntry -
|
|
// PktFsctrlUpdateSiteCosts -
|
|
// DfsAgePktEntries - Flush PKT entries periodically
|
|
//
|
|
// Private Functions
|
|
//
|
|
// DfsCreateExitPathOnRoot
|
|
// PktpHashSiteCostList
|
|
// PktpLookupSiteCost
|
|
// PktpUpdateSiteCosts
|
|
//
|
|
// Debug Only Functions
|
|
//
|
|
// PktFsctrlFlushCache - Flush PKT entries on command
|
|
// PktFsctrlGetFirstSvc - Test hooks for testing replica
|
|
// PktFsctrlGetNextSvc - selection.
|
|
//
|
|
// History: 12 Jul 1993 Alanw Created from localvol.c.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "dfsprocs.h"
|
|
#include "dfserr.h"
|
|
#include "fsctrl.h"
|
|
#include "log.h"
|
|
#include "dnr.h"
|
|
#include "know.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_LOCALVOL)
|
|
|
|
//
|
|
// Local function prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
DfspProtocolToService(
|
|
IN PDS_TRANSPORT pdsTransport,
|
|
IN PWSTR pwszPrincipalName,
|
|
IN PWSTR pwszShareName,
|
|
IN OUT PDFS_SERVICE pService);
|
|
|
|
VOID
|
|
DfspFreeGluon(
|
|
IN PDS_GLUON pGluon);
|
|
|
|
VOID
|
|
DfspSvcListFromGluon(
|
|
PDFS_PKT_ENTRY_INFO pServiceInfo,
|
|
PDFS_SERVICE *ppActiveService,
|
|
PDS_GLUON pGluon);
|
|
|
|
#if DBG
|
|
NTSTATUS
|
|
PktFsctrlFlushCache(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, DfsAgePktEntries )
|
|
#pragma alloc_text( PAGE, DfspProtocolToService )
|
|
#pragma alloc_text( PAGE, DfspFreeGluon )
|
|
#pragma alloc_text( PAGE, DfspSvcListFromGluon )
|
|
#pragma alloc_text( PAGE, DfsFsctrlSetDomainGluon )
|
|
|
|
#if DBG
|
|
#pragma alloc_text( PAGE, PktFsctrlFlushCache )
|
|
#endif // DBG
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//+----------------------------------------------------------------------
|
|
//
|
|
// Function: DfsAgePktEntries, public
|
|
//
|
|
// Synopsis: This function gets called in the FSP to step through the PKT
|
|
// entries and delete those entries which are old.
|
|
//
|
|
// Arguments: [TimerContext] -- This context block contains a busy flag
|
|
// and a count of the number of ticks that
|
|
// have elapsed.
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
// Notes: In case the PKT cannot be acquired exclusive, the
|
|
// routine just returns without doing anything. We
|
|
// will have missed an aging interval, but aging is
|
|
// a non-critical activity.
|
|
//
|
|
// History: 04/23/93 SudK Created.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
VOID
|
|
DfsAgePktEntries(PDFS_TIMER_CONTEXT DfsTimerContext)
|
|
{
|
|
|
|
PDFS_PKT pkt = _GetPkt();
|
|
PDFS_PKT_ENTRY entry, nextEntry;
|
|
PLIST_ENTRY link;
|
|
PDFS_CREDENTIALS creds;
|
|
BOOLEAN pktLocked = FALSE;
|
|
|
|
DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0);
|
|
|
|
//
|
|
// First we need to acquire a lock on the PKT and step through the PKT
|
|
//
|
|
//
|
|
|
|
// If we can't get to the resource then let us return right away.
|
|
// This is really not that critical. We can always try again.
|
|
//
|
|
|
|
PktAcquireExclusive(FALSE, &pktLocked);
|
|
|
|
if (pktLocked == FALSE) {
|
|
|
|
DfsTimerContext->TickCount = 0;
|
|
|
|
DfsTimerContext->InUse = FALSE;
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan)\n", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ExAcquireResourceExclusive(&DfsData.Resource, FALSE) == FALSE) {
|
|
|
|
PktRelease();
|
|
|
|
DfsTimerContext->TickCount = 0;
|
|
|
|
DfsTimerContext->InUse = FALSE;
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
entry = PktFirstEntry(pkt);
|
|
|
|
while (entry != NULL) {
|
|
DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n",
|
|
&entry->Id.Prefix);
|
|
//
|
|
// We may lose this entry due to deletion. Let us get the Next
|
|
// entry before we go into the next stage.
|
|
//
|
|
nextEntry = PktNextEntry(pkt, entry);
|
|
|
|
//
|
|
// For each entry if it is not permanent and its expire time is
|
|
// less than DFS_MAX_TICKS then we can delete it else we just
|
|
// update its expire time and go on to the next entry.
|
|
//
|
|
|
|
if ( !(entry->Type & PKT_ENTRY_TYPE_PERMANENT)
|
|
|
|
&&
|
|
|
|
(entry->UseCount == 0)
|
|
|
|
&&
|
|
|
|
IsListEmpty(&entry->ChildList)) {
|
|
|
|
if (entry->ExpireTime < DfsTimerContext->TickCount) {
|
|
DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Deleted: %wZ\n",
|
|
&entry->Id.Prefix);
|
|
PktEntryDestroy(entry, pkt, (BOOLEAN) TRUE);
|
|
} else {
|
|
entry->ExpireTime -= DfsTimerContext->TickCount;
|
|
}
|
|
|
|
}
|
|
|
|
entry = nextEntry;
|
|
|
|
}
|
|
|
|
//
|
|
// Check the deleted credentials queue...
|
|
//
|
|
|
|
for (link = DfsData.DeletedCredentials.Flink;
|
|
link != &DfsData.DeletedCredentials;
|
|
NOTHING) {
|
|
|
|
creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);
|
|
|
|
link = link->Flink;
|
|
|
|
if (creds->RefCount == 0) {
|
|
|
|
RemoveEntryList( &creds->Link );
|
|
|
|
ExFreePool( creds );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
ExReleaseResource( &DfsData.Resource );
|
|
|
|
PktRelease();
|
|
|
|
//
|
|
// Finally we need to reset the count so that the Timer Routine can
|
|
// work fine. We also release the context block by resetting the InUse
|
|
// boolean. This will make sure that the next count towards the PKT
|
|
// aging will start again.
|
|
//
|
|
|
|
DfsTimerContext->TickCount = 0;
|
|
|
|
DfsTimerContext->InUse = FALSE;
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit\n", 0);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspProtocolToService
|
|
//
|
|
// Synopsis: Given a NetBIOS protocol definition in a DS_PROTOCOL structure
|
|
// this function creates a corresponding DFS_SERVICE structure.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfspProtocolToService(
|
|
IN PDS_TRANSPORT pdsTransport,
|
|
IN PWSTR pwszPrincipalName,
|
|
IN PWSTR pwszShareName,
|
|
IN OUT PDFS_SERVICE pService)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PTA_ADDRESS pTaddr = &pdsTransport->taddr;
|
|
PTDI_ADDRESS_NETBIOS pNBAddress;
|
|
USHORT i;
|
|
WCHAR NetBiosAddress[ TDI_ADDRESS_LENGTH_NETBIOS + 1];
|
|
ULONG cbUnused;
|
|
PUNICODE_STRING pServiceAddr;
|
|
|
|
DfsDbgTrace(+1, Dbg, "DfspProtocolToService - entered\n", 0);
|
|
|
|
//
|
|
// Initialize the service to nulls
|
|
//
|
|
|
|
RtlZeroMemory(pService, sizeof(DFS_SERVICE));
|
|
|
|
ASSERT(pTaddr->AddressType == TDI_ADDRESS_TYPE_NETBIOS);
|
|
|
|
pNBAddress = (PTDI_ADDRESS_NETBIOS) pTaddr->Address;
|
|
ASSERT(pTaddr->AddressLength == sizeof(TDI_ADDRESS_NETBIOS));
|
|
|
|
RtlMultiByteToUnicodeN(
|
|
NetBiosAddress,
|
|
sizeof(NetBiosAddress),
|
|
&cbUnused,
|
|
pNBAddress->NetbiosName,
|
|
16);
|
|
|
|
//
|
|
// Process a NetBIOS name. Throw away char 16, then ignore the trailing
|
|
// spaces
|
|
//
|
|
|
|
for (i = 14; NetBiosAddress[i] == L' '; i--) {
|
|
NOTHING;
|
|
}
|
|
NetBiosAddress[i+1] = UNICODE_NULL;
|
|
|
|
DfsDbgTrace(0, Dbg, "NetBIOS address is %ws\n", NetBiosAddress);
|
|
|
|
pService->Name.Length = wcslen(pwszPrincipalName) * sizeof(WCHAR);
|
|
pService->Name.MaximumLength = pService->Name.Length +
|
|
sizeof(UNICODE_NULL);
|
|
pService->Name.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
pService->Name.MaximumLength);
|
|
|
|
if (!pService->Name.Buffer) {
|
|
DfsDbgTrace(0, Dbg, "Unable to create principal name!\n", 0);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", status);
|
|
return(status);
|
|
}
|
|
|
|
RtlCopyMemory(pService->Name.Buffer, pwszPrincipalName, pService->Name.Length);
|
|
|
|
pService->Address.MaximumLength =
|
|
sizeof(UNICODE_PATH_SEP) +
|
|
pService->Name.Length +
|
|
sizeof(UNICODE_PATH_SEP) +
|
|
wcslen(pwszShareName) * sizeof(WCHAR) +
|
|
sizeof(UNICODE_NULL);
|
|
|
|
pService->Address.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
pService->Address.MaximumLength);
|
|
|
|
if (!pService->Address.Buffer) {
|
|
DfsDbgTrace(0, Dbg, "Unable to create address!\n", 0);
|
|
ExFreePool(pService->Name.Buffer);
|
|
pService->Name.Buffer = NULL;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", status);
|
|
return(status);
|
|
}
|
|
|
|
pService->Address.Length = sizeof(UNICODE_PATH_SEP);
|
|
|
|
pService->Address.Buffer[0] = UNICODE_PATH_SEP;
|
|
|
|
DnrConcatenateFilePath(
|
|
&pService->Address,
|
|
pService->Name.Buffer,
|
|
pService->Name.Length);
|
|
|
|
DnrConcatenateFilePath(
|
|
&pService->Address,
|
|
pwszShareName,
|
|
(USHORT) (wcslen(pwszShareName) * sizeof(WCHAR)));
|
|
|
|
DfsDbgTrace(0, Dbg, "Server Name is %wZ\n", &pService->Name);
|
|
|
|
DfsDbgTrace(0, Dbg, "Address is %wZ\n", &pService->Address);
|
|
|
|
pService->Type = DFS_SERVICE_TYPE_MASTER | DFS_SERVICE_TYPE_REFERRAL;
|
|
pService->Capability = PROV_DFS_RDR;
|
|
pService->ProviderId = PROV_ID_DFS_RDR;
|
|
pService->pProvider = NULL;
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", status);
|
|
return(status);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspFreeGluon
|
|
//
|
|
// Synopsis: Frees an unmarshalled gluon
|
|
//
|
|
// Arguments: [pGluon] -- pointer to gluon data structure
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DfspFreeGluon(
|
|
IN PDS_GLUON pGluon)
|
|
{
|
|
ULONG i, j, k;
|
|
|
|
|
|
if (pGluon->cMachines) {
|
|
for (i = pGluon->cMachines; i > 0; i--) {
|
|
|
|
PDS_MACHINE pMachine = pGluon->rpMachines[i-1];
|
|
|
|
if (pMachine) {
|
|
|
|
MarshalBufferFree(pMachine->pwszShareName);
|
|
|
|
if (pMachine->cPrincipals) {
|
|
for (j = pMachine->cPrincipals; j > 0; j--) {
|
|
MarshalBufferFree(pMachine->prgpwszPrincipals[j-1]);
|
|
}
|
|
}
|
|
MarshalBufferFree(pMachine->prgpwszPrincipals);
|
|
|
|
if (pMachine->cTransports) {
|
|
for (j = pMachine->cTransports; j > 0; j--) {
|
|
MarshalBufferFree(pMachine->rpTrans[j-1]);
|
|
}
|
|
}
|
|
|
|
MarshalBufferFree(pMachine);
|
|
}
|
|
}
|
|
}
|
|
|
|
MarshalBufferFree(pGluon);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspSvcListFromGluon
|
|
//
|
|
// Synopsis: Creates a service list corresponding to the list of DS_MACHINEs
|
|
// in a gluon. For each Service that this function creates it will
|
|
// strip the relevant DS_MACHINE structure from the gluon.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: No error code. But if for some reason one of the services is
|
|
// not created then there can be less SERVICES than the DS_MACHINEs
|
|
// passed in.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID
|
|
DfspSvcListFromGluon(
|
|
PDFS_PKT_ENTRY_INFO pServiceInfo,
|
|
PDFS_SERVICE *ppActiveService,
|
|
PDS_GLUON pGluon
|
|
)
|
|
{
|
|
ULONG i, j, k;
|
|
NTSTATUS status;
|
|
|
|
*ppActiveService = NULL;
|
|
|
|
//
|
|
// We'll traverse through each machine and each transport, and wean
|
|
// out the netbios names to create DFS_SERVICE structures.
|
|
//
|
|
|
|
for (i=0, j=0; i < pGluon->cMachines; i++) {
|
|
PDS_MACHINE pdsMachine;
|
|
|
|
pdsMachine = pGluon->rpMachines[i];
|
|
|
|
for (k=0; k < pdsMachine->cTransports; k++) {
|
|
PDS_TRANSPORT pdsTransport;
|
|
|
|
pdsTransport = pdsMachine->rpTrans[k];
|
|
|
|
//
|
|
// Support only SMB redir with NetBIOS addresses for now.
|
|
//
|
|
|
|
if ( pdsTransport->usFileProtocol == FSP_SMB
|
|
|
|
&&
|
|
|
|
pdsTransport->taddr.AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
|
|
|
|
ASSERT(j <= pGluon->cMachines);
|
|
|
|
status = DfspProtocolToService(
|
|
pdsTransport,
|
|
pdsMachine->prgpwszPrincipals[pdsTransport->iPrincipal],
|
|
pdsMachine->pwszShareName,
|
|
&pServiceInfo->ServiceList[j]);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
pServiceInfo->ServiceList[j].pMachEntry =
|
|
ExAllocatePool( PagedPool, sizeof(DFS_MACHINE_ENTRY) );
|
|
if (pServiceInfo->ServiceList[j].pMachEntry == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RtlZeroMemory(
|
|
(PVOID) pServiceInfo->ServiceList[j].pMachEntry,
|
|
sizeof(DFS_MACHINE_ENTRY));
|
|
}
|
|
}
|
|
if (NT_SUCCESS(status)) {
|
|
DfsDbgTrace(0, Dbg, "Added service # %d\n", j);
|
|
DfsDbgTrace(0, Dbg, "Name = %wZ\n",
|
|
&pServiceInfo->ServiceList[j].Name);
|
|
DfsDbgTrace(0, Dbg, "Address = %wZ\n",
|
|
&pServiceInfo->ServiceList[j].Address);
|
|
pServiceInfo->ServiceList[j].pMachEntry->pMachine = pdsMachine;
|
|
pServiceInfo->ServiceList[j].pMachEntry->UseCount = 1;
|
|
|
|
//
|
|
// Now strip the pdsMachine Structure from Gluon.
|
|
//
|
|
pGluon->rpMachines[i] = NULL;
|
|
|
|
//
|
|
// DfsSetDomainInfo in api\gluonapi.c sets the grfFlags
|
|
// field of the gluon to the index of the active service.
|
|
//
|
|
|
|
if (pGluon->grfFlags == i) {
|
|
*ppActiveService = &pServiceInfo->ServiceList[j];
|
|
}
|
|
j++;
|
|
|
|
} else {
|
|
DfsDbgTrace(0, 1, "Error %08lx creating service\n",
|
|
status);
|
|
}
|
|
break; // Get out of the loop for transports.
|
|
|
|
} // end if transport is SMB/NetBIOS
|
|
|
|
} // end for each transport
|
|
|
|
} // end for each machine
|
|
|
|
DfsDbgTrace(0, Dbg, "%d services found\n", j);
|
|
pServiceInfo->ServiceCount = j;
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlSetDomainGluon
|
|
//
|
|
// Synopsis: Inserts a pkt entry corresponding to the domain gluon.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsctrlSetDomainGluon(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
MARSHAL_BUFFER marshalBuffer;
|
|
DS_GLUON_P domainGluonP;
|
|
PDS_GLUON pDomainGluon;
|
|
DFS_PKT_ENTRY_ID domainId;
|
|
DFS_PKT_ENTRY_INFO domainInfo;
|
|
PDFS_SERVICE pActiveService;
|
|
PDFS_PKT_ENTRY pDCEntry;
|
|
PDFS_PKT pkt;
|
|
ULONG j;
|
|
BOOLEAN pktLocked;
|
|
|
|
|
|
STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainGluon, TRUE, FALSE, FALSE);
|
|
|
|
//
|
|
// Unmarshal the gluon.
|
|
//
|
|
|
|
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
|
|
status = DfsRtlGet(&marshalBuffer, &MiDSGluonP, &domainGluonP);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DfsDbgTrace(0, Dbg, "Unmarshalling of gluon failed %08lx\n", status);
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exited %08lx\n", status);
|
|
|
|
return(status);
|
|
}
|
|
pDomainGluon = domainGluonP.pDSGluon;
|
|
|
|
DfsDbgTrace(0, Dbg, "Unmarshalled gluon @ %08lx\n", pDomainGluon);
|
|
DfsDbgTrace(0, Dbg, "Name is %ws\n", pDomainGluon->pwszName);
|
|
DfsDbgTrace(0, Dbg, "# of services is %d\n", pDomainGluon->cMachines);
|
|
DfsDbgTrace(0, Dbg, "Unpacking gluon...\n", 0);
|
|
|
|
//
|
|
// Initialize the entry id for the domain service.
|
|
//
|
|
|
|
domainId.Prefix.Length = wcslen(pDomainGluon->pwszName)*sizeof(WCHAR);
|
|
domainId.Prefix.MaximumLength = domainId.Prefix.Length + sizeof(WCHAR);
|
|
domainId.Prefix.Buffer = ExAllocatePool(PagedPool, domainId.Prefix.MaximumLength);
|
|
if (domainId.Prefix.Buffer == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DfsDbgTrace(0, Dbg, "Unable to convert name to prefix %08lx\n", status);
|
|
|
|
DfspFreeGluon(pDomainGluon);
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
|
|
return status;
|
|
}
|
|
|
|
domainId.ShortPrefix.Length = domainId.Prefix.Length;
|
|
domainId.ShortPrefix.MaximumLength = domainId.Prefix.MaximumLength;
|
|
domainId.ShortPrefix.Buffer = ExAllocatePool(PagedPool, domainId.ShortPrefix.MaximumLength);
|
|
if (domainId.ShortPrefix.Buffer == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DfsDbgTrace(0, Dbg, "Unable to convert name to short prefix %08lx\n", status);
|
|
|
|
ExFreePool(domainId.Prefix.Buffer);
|
|
|
|
DfspFreeGluon(pDomainGluon);
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
|
|
return status;
|
|
}
|
|
|
|
wcscpy(domainId.Prefix.Buffer, pDomainGluon->pwszName);
|
|
wcscpy(domainId.ShortPrefix.Buffer, pDomainGluon->pwszName);
|
|
|
|
DfsDbgTrace(0, Dbg, "Prefix is %wZ\n", &domainId.Prefix);
|
|
|
|
RtlCopyMemory(&domainId.Uid, &pDomainGluon->guidThis, sizeof(GUID));
|
|
|
|
//
|
|
// Create a new info structure by disassembling the gluon
|
|
//
|
|
// BUGBUG - temporary code till we move to using DS_MACHINES entirely
|
|
//
|
|
|
|
domainInfo.ServiceList = ExAllocatePool(PagedPool,
|
|
pDomainGluon->cMachines * sizeof(DFS_SERVICE));
|
|
|
|
if (domainInfo.ServiceList == NULL) {
|
|
DfsDbgTrace(0, Dbg, "Unable to allocated %d bytes\n",
|
|
(pDomainGluon->cMachines * sizeof(DFS_SERVICE)));
|
|
|
|
DfspFreeGluon(pDomainGluon);
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: Exit -> %08lx\n", status);
|
|
|
|
return status;
|
|
}
|
|
|
|
DfspSvcListFromGluon(&domainInfo, &pActiveService, pDomainGluon);
|
|
|
|
//
|
|
// Now, lets acquire the Pkt and insert the domain pkt entry. That's
|
|
// all it takes!
|
|
//
|
|
|
|
pkt = _GetPkt();
|
|
PktAcquireExclusive(TRUE, &pktLocked);
|
|
|
|
status = PktCreateEntry(
|
|
pkt,
|
|
PKT_ENTRY_TYPE_REFERRAL_SVC,
|
|
&domainId,
|
|
&domainInfo,
|
|
PKT_ENTRY_SUPERSEDE,
|
|
&pDCEntry);
|
|
if (NT_SUCCESS(status)) {
|
|
DfsDbgTrace(0, Dbg, "Created domain pkt entry @ %08lx\n", pDCEntry);
|
|
pDCEntry->ActiveService = pActiveService;
|
|
} else {
|
|
DfsDbgTrace(0, Dbg, "Error %08lx creating domain pkt entry\n", status);
|
|
status = DFS_STATUS_INCONSISTENT;
|
|
|
|
//
|
|
// Do some cleanup.
|
|
//
|
|
|
|
ExFreePool(domainId.Prefix.Buffer);
|
|
for (j = 0; j < domainInfo.ServiceCount; j++) {
|
|
PktServiceDestroy(&domainInfo.ServiceList[j], FALSE);
|
|
}
|
|
ExFreePool(domainInfo.ServiceList);
|
|
}
|
|
|
|
PktRelease();
|
|
|
|
DfspFreeGluon(pDomainGluon);
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFsctrlSetDomainGluon: exited %08lx\n", status);
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PktFsctrlFlushCache, public
|
|
//
|
|
// Synopsis: This function will flush all entries which have all the
|
|
// bits specified in the TYPE vairable set in their own Type field.
|
|
// However, this function will refuse to delete and Permanent
|
|
// entries of the PKT.
|
|
//
|
|
// Arguments: Type - Specifies which entries to delete.
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: We only process this FSCTRL from the file system process,
|
|
// never from the driver.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS
|
|
PktFsctrlFlushCache(
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG Type;
|
|
PDFS_PKT Pkt;
|
|
PDFS_PKT_ENTRY curEntry, nextEntry;
|
|
BOOLEAN pktLocked;
|
|
|
|
|
|
STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE, TRUE);
|
|
|
|
//
|
|
// Unmarshalling is very simple here. We only expect a ULONG.
|
|
//
|
|
|
|
Type = (*((ULONG *)InputBuffer));
|
|
|
|
Pkt = _GetPkt();
|
|
PktAcquireExclusive(TRUE, &pktLocked);
|
|
curEntry = PktFirstEntry(Pkt);
|
|
|
|
while (curEntry!=NULL) {
|
|
nextEntry = PktNextEntry(Pkt, curEntry);
|
|
|
|
if (((curEntry->Type & Type) == Type) &&
|
|
!(curEntry->Type & PKT_ENTRY_TYPE_LOCAL) &&
|
|
!(curEntry->Type & PKT_ENTRY_TYPE_LOCAL_XPOINT)) {
|
|
|
|
//
|
|
// Entry has all the Type bits specified in variable
|
|
// "Type" set and hence we can destroy this entry.
|
|
//
|
|
|
|
PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
|
|
|
|
}
|
|
curEntry = nextEntry;
|
|
}
|
|
PktRelease();
|
|
|
|
DfsCompleteRequest( IrpContext, Irp, status );
|
|
|
|
DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", status);
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
#endif // DBG
|
|
|