windows-nt/Source/XPSP1/NT/base/fs/dfs/driver/pktfsctl.c

1467 lines
40 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+----------------------------------------------------------------------------
//
// Copyright (C) 1992, Microsoft Corporation.
//
// File: PKTFSCTL.C
//
// Contents: This module contains the implementation for FS controls
// which manipulate the PKT.
//
// Functions: PktFsctrlGetRelationInfo -
// PktFsctrlSetRelationInfo -
// PktFsctrlIsChildnameLegal -
// PktFsctrlCreateEntry -
// PktFsctrlCreateSubordinateEntry -
// PktFsctrlDestroyEntry -
// PktFsctrlUpdateSiteCosts -
// DfsAgePktEntries - Flush PKT entries periodically
//
// Private Functions
//
// DfspCreateExitPathOnRoot
// PktpHashSiteCostList
// PktpLookupSiteCost
// PktpUpdateSiteCosts
//
// Debug Only Functions
//
// PktFsctrlFlushCache - Flush PKT entries on command
//
// History: 12 Jul 1993 Alanw Created from localvol.c.
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include <dfserr.h>
#include <netevent.h>
#include "fsctrl.h"
#include "log.h"
#include "know.h"
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_LOCALVOL)
NTSTATUS
DfspCreateExitPathOnRoot(
PDFS_SERVICE service,
PUNICODE_STRING RemPath
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, PktFsctrlGetRelationInfo )
#pragma alloc_text( PAGE, PktFsctrlVerifyLocalVolumeKnowledge )
#pragma alloc_text( PAGE, PktFsctrlPruneLocalVolume )
#pragma alloc_text( PAGE, PktFsctrlCreateEntry )
#pragma alloc_text( PAGE, PktFsctrlCreateSubordinateEntry )
#pragma alloc_text( PAGE, PktFsctrlDestroyEntry )
#pragma alloc_text( PAGE, DfsAgePktEntries )
#pragma alloc_text( PAGE, DfspCreateExitPathOnRoot )
#if DBG
#pragma alloc_text( PAGE, PktFsctrlFlushCache )
#endif // DBG
#endif // ALLOC_PRAGMA
//+-------------------------------------------------------------------------
//
// Function: DfspCreateExitPathOnRoot
//
// Synopsis: This function creates an on disk exit path on the ORGROOT vol
//
// Arguments:
//
// Returns:
//
//--------------------------------------------------------------------------
NTSTATUS
DfspCreateExitPathOnRoot(
PDFS_SERVICE service,
PUNICODE_STRING RemPath
)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ExitPath;
status = BuildLocalVolPath(&ExitPath, service, RemPath);
if (NT_SUCCESS(status)) {
//
// For now make sure that StorageId Exists. Dont worry about the
// actual exit pt bit on it. Fix when EXIT_PTs come along.
//
if (DfsFixExitPath(ExitPath.Buffer)) {
DebugTrace(0, Dbg, "Succeeded to Create ExitPth on Orgroot %wZ\n",
&ExitPath);
status = STATUS_SUCCESS;
}
else {
DebugTrace(0, Dbg, "Failed to Create ExitPath on Orgroot %wZ\n",
&ExitPath);
status = DFS_STATUS_BAD_EXIT_POINT;
}
ExFreePool(ExitPath.Buffer);
}
else {
DebugTrace(0, Dbg, "Failed to create localvol path for %wZ \n",
RemPath);
}
return(status);
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlGetRelationInfo, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlGetRelationInfo(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
DFS_PKT_ENTRY_ID EntryId;
DFS_PKT_RELATION_INFO relationInfo;
ULONG size = 0;
MARSHAL_BUFFER marshalBuffer;
STD_FSCTRL_PROLOGUE(PktFsctrlGetRelationInfo, TRUE, TRUE );
//
// Unmarshal the argument...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiPktEntryId, &EntryId);
if (NT_SUCCESS(status)) {
PDFS_PKT pkt = _GetPkt();
status = PktRelationInfoConstruct(&relationInfo, pkt, &EntryId);
if (NT_SUCCESS(status)) {
DfsRtlSize(&MiPktRelationInfo, &relationInfo, &size);
if (size>OutputBufferLength) {
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
MarshalBufferInitialize(&marshalBuffer,
size,
OutputBuffer);
DfsRtlPut(&marshalBuffer,
&MiPktRelationInfo,
&relationInfo);
}
//
// Now we have to free up the relation info struct that we
// created above.
//
PktRelationInfoDestroy(&relationInfo, FALSE);
}
PktEntryIdDestroy(&EntryId, FALSE);
} else
DebugTrace(0, Dbg,
"PktFsctrlGetRelationInfo: Unmarshalling Error!\n", 0);
Irp->IoStatus.Information = marshalBuffer.Current - marshalBuffer.First;
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "PktFsctrlGetRelationInfo: Exit -> %08lx\n", ULongToPtr( status ));
return(status);
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlSetRelationInfo, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlSetRelationInfo(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
DFS_PKT_RELATION_INFO relationInfo;
MARSHAL_BUFFER marshalBuffer;
STD_FSCTRL_PROLOGUE(PktFsctrlSetRelationInfo, TRUE, FALSE);
//
// Unmarshal the argument...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiPktRelationInfo, &relationInfo);
if (NT_SUCCESS(status)) {
PDFS_PKT pkt = _GetPkt();
status = PktSetRelationInfo(
pkt,
&relationInfo
);
//
// Need to deallocate the relationInfo...
//
PktRelationInfoDestroy(&relationInfo, FALSE);
} else
DebugTrace(0, Dbg,
"PktFsctrlSetRelationInfo: Unmarshalling Error!\n", 0);
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "PktFsctrlSetRelationInfo: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+----------------------------------------------------------------------------
//
// Function: PktFsctrlIsChildnameLegal, public
//
// Synopsis: Determines whether the given childname is a valid one for
// the given parent prefix.
//
// Arguments:
//
// Returns: [STATUS_SUCCESS] -- The childname is legal
//
// [STATUS_OBJECT_NAME_COLLISION] -- The childname conflicts with
// another child of the parent prefix.
//
// [STATUS_OBJECT_PATH_NOT_FOUND] -- The childname is not a
// hierarchically related to the parent
//
// [STATUS_INVALID_PARAMETER] -- The childname is bogus and
// doesn't start with a backslash
//
// [STATUS_DATA_ERROR] -- If the input buffer could not be
// unmarshalled.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory unmarshalling
// input buffer.
//
//-----------------------------------------------------------------------------
NTSTATUS
PktFsctrlIsChildnameLegal(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength)
{
NTSTATUS status;
MARSHAL_BUFFER marshalBuffer;
DFS_PKT_ENTRY_ID idParent;
DFS_PKT_ENTRY_ID idChild;
UNICODE_STRING ustrRem;
STD_FSCTRL_PROLOGUE(PktFsctrlIsChildnameLegal, TRUE, FALSE);
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &idParent );
if (NT_SUCCESS(status)) {
status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &idChild );
if (NT_SUCCESS(status)) {
PDFS_PKT pPkt = _GetPkt();
PDFS_PKT_ENTRY pPktEntry, pSuperiorEntry;
ustrRem.Length = ustrRem.MaximumLength = 0;
ustrRem.Buffer = NULL;
PktAcquireShared( pPkt, TRUE );
pPktEntry = PktLookupEntryByPrefix(
pPkt,
&idChild.Prefix,
&ustrRem);
if (pPktEntry != NULL) {
if (ustrRem.Length != 0) {
//
// There is no exact match for the child, so
// lets check to see if the match occured with the
// parent prefix.
//
if (RtlCompareUnicodeString(
&idParent.Prefix,
&pPktEntry->Id.Prefix,
FALSE) == 0) {
status = STATUS_SUCCESS;
} else {
status = STATUS_OBJECT_NAME_COLLISION;
}
} else {
//
// This might be a legal child name. Check to see if the
// passed-in child guid matches the one in the pkt entry
// we found; if so, then this is a valid child name.
//
if (GuidEqual(&idChild.Uid, &pPktEntry->Id.Uid)) {
status = STATUS_SUCCESS;
} else {
status = STATUS_OBJECT_NAME_COLLISION;
}
}
} else {
status = STATUS_INVALID_PARAMETER;
}
PktRelease( pPkt );
PktEntryIdDestroy(&idChild, FALSE);
}
PktEntryIdDestroy(&idParent, FALSE);
}
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "PktFsctrlIsChildnameLegal: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlCreateEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlCreateEntry(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
DFS_PKT_CREATE_ENTRY_ARG arg;
MARSHAL_BUFFER marshalBuffer;
STD_FSCTRL_PROLOGUE(PktFsctrlCreateEntry, TRUE, FALSE);
//
// Unmarshal the argument...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiPktCreateEntryArg, &arg);
if (NT_SUCCESS(status)) {
PDFS_PKT pkt = _GetPkt();
PDFS_PKT_ENTRY entry;
ULONG i;
PktAcquireExclusive(pkt, TRUE);
try {
status = PktCreateEntry(pkt,
arg.EntryType,
&arg.EntryId,
&arg.EntryInfo,
arg.CreateDisposition,
&entry);
} finally {
PktRelease(pkt);
}
//
// Need to deallocate the entry Id...
//
PktEntryIdDestroy(&arg.EntryId, FALSE);
PktEntryInfoDestroy(&arg.EntryInfo, FALSE);
} else
DebugTrace(0, Dbg, "PktFsctrlCreateEntry: Unmarshalling Error!\n", 0);
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "PktFsctrlCreateEntry: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlCreateSubordinateEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlCreateSubordinateEntry(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
DFS_PKT_CREATE_SUBORDINATE_ENTRY_ARG arg;
MARSHAL_BUFFER marshalBuffer;
STD_FSCTRL_PROLOGUE(PktFsctrlCreateSubordinateEntry, TRUE, FALSE);
//
// Unmarshal the argument...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiPktCreateSubordinateEntryArg, &arg);
if (NT_SUCCESS(status)) {
PDFS_PKT pkt = _GetPkt();
PDFS_PKT_ENTRY superior;
PDFS_PKT_ENTRY subEntry;
PktAcquireExclusive(pkt, TRUE);
try {
superior = PktLookupEntryById(pkt, &arg.EntryId);
if (superior != NULL) {
status = PktCreateSubordinateEntry(
pkt,
superior,
arg.SubEntryType,
&arg.SubEntryId,
&arg.SubEntryInfo,
arg.CreateDisposition,
&subEntry);
} else {
DebugTrace(0, Dbg,
"PktFsctrlCreateSubordinateEntry: No Superior!\n", 0);
status = DFS_STATUS_NO_SUCH_ENTRY;
}
} finally {
PktRelease(pkt);
}
//
// Need to deallocate the entry Id...
//
PktEntryIdDestroy(&arg.EntryId, FALSE);
PktEntryIdDestroy(&arg.SubEntryId, FALSE);
PktEntryInfoDestroy(&arg.SubEntryInfo, FALSE);
} else {
DebugTrace(0, Dbg,
"PktFsctrlCreateSubordinateEntry: Unmarshalling Error!\n", 0);
}
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg,
"PktFsctrlCreateSubordinateEntry: Exit -> %08lx\n", ULongToPtr( status ));
return status;
}
//+-------------------------------------------------------------------------
//
// Function: PktFsctrlDestroyEntry, public
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// Notes: We only process this FSCTRL from the file system process,
// never from the driver.
//
//--------------------------------------------------------------------------
NTSTATUS
PktFsctrlDestroyEntry(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
DFS_PKT_ENTRY_ID Id;
MARSHAL_BUFFER marshalBuffer;
PDFS_PKT_ENTRY victim;
STD_FSCTRL_PROLOGUE(PktFsctrlDestroyEntry, TRUE, FALSE);
//
// Unmarshal the argument...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(&marshalBuffer, &MiPktEntryId, &Id);
if (NT_SUCCESS(status)) {
PDFS_PKT pkt = _GetPkt();
PktAcquireExclusive(pkt, TRUE);
victim = PktLookupEntryById(pkt, &Id);
if (victim != NULL) {
//
// If there is a local service we first need to delete this
// explicitly before we call PktEntryDestroy.
//
if (victim->LocalService) {
UNICODE_STRING a, b;
RtlInitUnicodeString(&b, L"\\");
BuildLocalVolPath(&a, victim->LocalService, &b);
PktEntryRemoveLocalService(pkt, victim, &a);
}
PktEntryDestroy( victim, pkt, (BOOLEAN) TRUE);
} else {
DebugTrace(0, Dbg, "PktFsctrlDestroyEntry: No Superior!\n", 0);
status = DFS_STATUS_NO_SUCH_ENTRY;
}
PktRelease(pkt);
//
// Need to deallocate the entry Id...
//
PktEntryIdDestroy(&Id, FALSE);
} else
DebugTrace(0, Dbg,
"PktFsctrlDestroyEntry: Unmarshalling Error!\n", 0);
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg,
"PktFsctrlDestroyEntry: Exit -> %08lx\n", ULongToPtr(status) );
return status;
}
//+----------------------------------------------------------------------------
//
// Function: PktpPruneAllExtraVolumes
//
// Synopsis: Given a set of relation infos, this helper routine will
// prune all local volume entries in the pkt that are not present
// in the input set of relation infos.
//
// Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
// exclusive
// [cInfo] -- The number of config infos in the set
// [pInfo] -- The set of config infos
//
// Returns: [STATUS_SUCCESS] -- No extra volumes were found.
//
// [STATUS_REGISTRY_RECOVERED] -- Extra volumes were found and
// were successfully recovered.
//
// [STATUS_UNSUCCESSFUL] -- Extra volumes were found but could
// not be deleted. A detailed error was logged.
//
// Notes: Assumes Pkt has been acquired exclusive
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpPruneAllExtraVolumes(
PDFS_PKT pPkt,
ULONG cInfo,
PDFS_LOCAL_VOLUME_CONFIG pInfo)
{
//
// 447479: init return status.
NTSTATUS status, returnStatus = STATUS_UNSUCCESSFUL;
PDFS_PKT_ENTRY pPktEntry;
ULONG i, j;
BOOLEAN fExtra;
//
// This is a pretty brute-force algorithm - for each Pkt entry that is
// local, we scan the entire set of infos looking for a match. If a
// match is not found, we delete the local volume.
//
pPktEntry = CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
for (i = 0, status = STATUS_SUCCESS;
i < pPkt->EntryCount && NT_SUCCESS(status);
i++) {
for (j = 0, fExtra = TRUE; j < cInfo && fExtra; j++) {
if (GuidEqual( &pInfo[j].RelationInfo.EntryId.Uid, &pPktEntry->Id.Uid)) {
fExtra = FALSE;
}
}
if (fExtra && !(pPktEntry->Type & PKT_ENTRY_TYPE_MACHINE)) {
DebugTrace(0, Dbg,
"Pruning Extra volume [%wZ]\n", &pPktEntry->Id.Prefix);
status = DfsInternalDeleteLocalVolume( &pPktEntry->Id );
if (!NT_SUCCESS(status)) {
UNICODE_STRING puStr[2];
puStr[0] = pPktEntry->Id.Prefix;
puStr[1].MaximumLength = sizeof(L"LocalMachine");
puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
puStr[1].Buffer = L"LocalMachine";
LogWriteMessage(
EXTRA_VOLUME_NOT_DELETED,
status,
2,
puStr);
returnStatus = STATUS_UNSUCCESSFUL;
} else {
returnStatus = STATUS_REGISTRY_RECOVERED;
}
}
pPktEntry =
CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
}
return( returnStatus );
}
//+----------------------------------------------------------------------------
//
// Function: PktpResetOneLocalVolume
//
// Synopsis: Given a relation info (as sent over by the DC), this routine
// will locate a pkt entry for the given volume. If such an
// entry is found, this routine will try to sync up the relation
// info to that of the passed in info.
//
// Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
// exclusive
// [pRemoteInfo] -- The DFS_LOCAL_VOLUME_CONFIG_INFO sent by the
// DC.
//
// Returns: [STATUS_SUCCESS] -- Either there is no such local volume in
// the Pkt, or the local volume's relation info is in
// exact sync.
//
// [STATUS_REGISTRY_RECOVERED] -- Found a local volume, and
// steps were taken to bring it in sync with the
// passed in relation info.
//
// [STATUS_UNSUCCESSFUL] -- Found a local volume, and in
// taking steps to bring it in sync, an error was
// encountered. A detailed message has been logged.
//
// History: April 6, 1995 Milans created
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpResetOneLocalVolume(
PDFS_PKT pPkt,
PDFS_LOCAL_VOLUME_CONFIG pRemoteInfo)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT_ENTRY pPktEntry;
UNICODE_STRING LocalMachStr;
LocalMachStr.MaximumLength = sizeof(L"LocalMachine");
LocalMachStr.Length = LocalMachStr.MaximumLength - sizeof(WCHAR);
LocalMachStr.Buffer = L"LocalMachine";
pPktEntry = PktLookupEntryByUid( pPkt, &pRemoteInfo->RelationInfo.EntryId.Uid );
if (pPktEntry != NULL) {
DFS_PKT_RELATION_INFO LocalInfo;
//
// We found a matching pkt entry in the local pkt. Lets see
// if it is in sync with the input relation info.
//
status = PktRelationInfoConstruct(
&LocalInfo,
pPkt,
&pPktEntry->Id);
if (NT_SUCCESS(status)) {
status = PktRelationInfoValidate(
&LocalInfo,
&pRemoteInfo->RelationInfo,
LocalMachStr);
if (status == DFS_STATUS_RESYNC_INFO) {
status = PktpFixupRelationInfo(
&LocalInfo,
&pRemoteInfo->RelationInfo);
if (NT_SUCCESS(status)) {
status = STATUS_REGISTRY_RECOVERED;
}
}
}
} else {
status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: PktpCreateIfMissing
//
// Synopsis: Given a relation info for a local volume, this routine
// will create a local volume matching the relation info if
// a volume with the given guid does not already exist.
//
// Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
// exclusive
// [pInfo] -- The local volume config info required to recreate
// the local volume.
//
// Returns: [STATUS_SUCCESS] -- The local volume already exists. Doesn't
// guarantee that the relation info matches, just that
// there is already a pkt entry for the given guid.
//
// [STATUS_REGISTRY_RECOVERED] -- The local volume was missing
// and was successfully recreated.
//
// [STATUS_UNSUCCESSFUL] -- The local volume is missing, and
// an error was encountered while recreating it; a
// more detailed error message has been logged.
//
// History: April 6, 1995 Milans created
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpCreateIfMissing(
PDFS_PKT pPkt,
PDFS_LOCAL_VOLUME_CONFIG pInfo)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PKT_ENTRY pPktEntry;
pPktEntry = PktLookupEntryByUid( pPkt, &pInfo->RelationInfo.EntryId.Uid );
if (pPktEntry == NULL) {
//
// There is no local volume matching pInfo. We try to recreate it.
//
pInfo->EntryType = PKT_ENTRY_TYPE_CAIRO;
pInfo->ServiceType |= DFS_SERVICE_TYPE_MASTER;
status = DfsInternalCreateLocalPartition(
&pInfo->StgId,
TRUE,
pInfo);
if (!NT_SUCCESS(status)) {
UNICODE_STRING puStr[2];
puStr[0] = pInfo->RelationInfo.EntryId.Prefix;
puStr[1].MaximumLength = sizeof(L"LocalMachine");
puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
puStr[1].Buffer = L"LocalMachine";
LogWriteMessage(
MISSING_VOLUME_NOT_CREATED,
status,
2,
puStr);
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_REGISTRY_RECOVERED;
}
}
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: PktpResetLocalVolumes
//
// Synopsis: Given an array of relation infos for local volumes, this
// routine will set the pkt to match the entire set of infos.
// Local volumes in the pkt but not in the set of infos will
// be deleted. Local volumes in the pkt and in the set will
// be modified if needed to match the info in the set. Lastly,
// infos in the set but not in the pkt will result in a new
// local volume being created.
//
// Arguments: [cInfo] -- The number of config infos passed in.
// [pInfo] -- The array of DFS_LOCAL_VOLUME_CONFIG structs.
//
// Returns: [STATUS_SUCCESS] -- The pkt is already in sync with the
// passed in set of relation infos.
//
// [STATUS_REGISTRY_RECOVERED] -- The pkt was successfully
// brought in sync with the passed in infos; some
// needed changes were made and messages were logged.
// THIS IS AN NT INFORMATION STATUS CODE!
//
// [STATUS_UNSUCCESSFUL] -- Unable to bring the pkt in sync;
// The problem was logged.
//
//-----------------------------------------------------------------------------
NTSTATUS
PktpResetLocalVolumes(
ULONG cInfo,
PDFS_LOCAL_VOLUME_CONFIG pInfo)
{
PDFS_PKT pPkt;
NTSTATUS status, returnStatus;
ULONG i;
pPkt = _GetPkt();
PktAcquireExclusive( pPkt, TRUE );
//
// First, we need to see if we have any extra volumes, and if so, we
// need to prune them
//
status = PktpPruneAllExtraVolumes( pPkt, cInfo, pInfo );
if (NT_SUCCESS(status)) {
returnStatus = status;
//
// Next, we need to sync up all the local volumes which are
// out of sync
//
for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
status = PktpResetOneLocalVolume( pPkt, &pInfo[i] );
if (status == STATUS_REGISTRY_RECOVERED) {
returnStatus = status;
}
}
//
// Lastly, we need to create any missing volumes
//
for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
status = PktpCreateIfMissing( pPkt, &pInfo[i] );
if (status == STATUS_REGISTRY_RECOVERED) {
returnStatus = status;
}
}
}
PktRelease( pPkt );
if (!NT_SUCCESS(status)) {
returnStatus = STATUS_UNSUCCESSFUL;
}
return( returnStatus );
}
//+----------------------------------------------------------------------------
//
// Function: PktFsctrlSetServerInfo
//
// Synopsis: During the course of Dfs admin operations, the DC might
// discover that a particular server's knowledge does not agree
// with its own. If that is the case, the DC will try to force
// the server to sync up to its knowledge.
//
// Arguments:
//
// Returns: [STATUS_SUCCESS] -- The pkt is already in sync with the
// passed in set of relation infos.
//
// [STATUS_REGISTRY_RECOVERED] -- The pkt was successfully
// brought in sync with the passed in infos; some
// needed changes were made and messages were logged.
// THIS IS AN NT INFORMATION STATUS CODE!
//
// [STATUS_UNSUCCESSFUL] -- Unable to bring the pkt in sync;
// The problem was logged.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to unmarshal
// arguments or otherwise out of memory
//
// [STATUS_INVALID_DOMAIN_ROLE] -- Can't set server info because
// this machine is a DC.
//
//-----------------------------------------------------------------------------
NTSTATUS
PktFsctrlSetServerInfo(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength)
{
NTSTATUS status = STATUS_SUCCESS;
MARSHAL_BUFFER marshalBuffer;
ULONG i, cInfo;
PDFS_LOCAL_VOLUME_CONFIG pInfos = NULL;
STD_FSCTRL_PROLOGUE(PktFsctrlSetServerInfo, TRUE, FALSE);
//
// First, check to see if this machine is a DC. If so, we should not
// muck with our Pkt!
//
if (DfsData.MachineState == DFS_ROOT_SERVER) {
DebugTrace(0, Dbg, "Ignoring SetServerInfo call on DC!\n", 0);
status = STATUS_INVALID_DOMAIN_ROLE;
} else {
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
status = DfsRtlGetUlong( &marshalBuffer, &cInfo );
}
if (NT_SUCCESS(status) && cInfo > 0) {
//
// We want to get all the config infos first, and then fix up each
// instead of unmarshalling and fixing them one by one. This way,
// we won't get messeded up if we hit an unmarshalling error after
// having fixed up some of our local volumes.
//
ULONG cbSize;
cbSize = sizeof(DFS_LOCAL_VOLUME_CONFIG) * cInfo;
if ((cbSize / cInfo) == sizeof(DFS_LOCAL_VOLUME_CONFIG)) {
pInfos = ExAllocatePoolWithTag(PagedPool,cbSize, ' sfD');
if (pInfos != NULL) {
DebugTrace(0, Dbg, "Unmarshalling %d Config Infos\n", ULongToPtr( cInfo ));
for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
status = DfsRtlGet(
&marshalBuffer,
&MiLocalVolumeConfig,
&pInfos[i]);
}
if (!NT_SUCCESS(status)) {
//
// Unmarshalling error - cleanup
//
DebugTrace(0, Dbg, "Error %08lx unmarshalling ", ULongToPtr( status ));
DebugTrace(0, Dbg, "the %d th relation info", ULongToPtr( i ));
for ( ; i > 0; i--) {
LocalVolumeConfigInfoDestroy( &pInfos[i-1], FALSE );
}
}
} else {
DebugTrace(0, Dbg, "Unable to allocate %d bytes\n", ULongToPtr( cbSize ));
status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
DebugTrace(0, Dbg, "Interger overflow in %s\n", __FILE__);
status = STATUS_INVALID_PARAMETER;
}
if (NT_SUCCESS(status)) {
DebugTrace(0, Dbg, "Successfully unmarshalled %d Infos\n", ULongToPtr( cInfo ));
status = PktpResetLocalVolumes( cInfo, pInfos );
for (i = 0; i < cInfo; i++) {
LocalVolumeConfigInfoDestroy( &pInfos[i], FALSE );
}
}
} else {
DebugTrace(0, Dbg, "Error %08lx getting count\n", ULongToPtr( status ));
}
if (pInfos != NULL) {
ExFreePool( pInfos );
}
DfsCompleteRequest( Irp, status );
DebugTrace(-1,Dbg, "PktFsctrlSetServerInfo: Exit -> %08lx\n", ULongToPtr( status ));
return(status);
}
//+------------------------------------------------------------------
//
// Function: PktFsctrlVerifyLocalVolumeKnowledge
//
// Synopsis: This method runs on a Dfs Server and validates the local
// volume knowledge with the one passed in.
//
// Arguments: [InputBuffer] -- Marshalled DFS_PKT_RELATION_INFO to compare
// with.
//
// [InputBufferLength] -- the length in bytes of InputBuffer
//
// Returns: [STATUS_SUCCESS] -- Verified that local volume knowledge was
// already in sync with passed in argument.
//
// [STATUS_REGISTRY_RECOVERED] -- Synced up local volume
// knowledge with passed in argument
//
// [STATUS_UNSUCCESSFUL] -- Unable to fully sync up - a message
// was logged to the local event log.
//
// [STATUS_DATA_ERROR] -- Passed in argument could not be
// unmarshalled.
//
// [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- Local volume not found.
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory.
//
//-------------------------------------------------------------------
NTSTATUS
PktFsctrlVerifyLocalVolumeKnowledge(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
MARSHAL_BUFFER marshalBuffer;
DFS_LOCAL_VOLUME_CONFIG remoteInfo;
PDFS_PKT pkt = _GetPkt();
STD_FSCTRL_PROLOGUE(PktFsctrlVerifyLocalVolumeKnowledge, TRUE, FALSE);
//
// unmarshal the arguments...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
RtlZeroMemory(&remoteInfo, sizeof(remoteInfo));
status = DfsRtlGet(
&marshalBuffer,
&MiPktRelationInfo,
&remoteInfo.RelationInfo);
if (NT_SUCCESS(status)) {
PktAcquireExclusive(pkt, TRUE);
status = PktpResetOneLocalVolume(pkt, &remoteInfo);
PktRelease(pkt);
PktRelationInfoDestroy(&remoteInfo.RelationInfo, FALSE);
} else
DebugTrace(0, Dbg,
"PktFsctrlVerifyLocalVolumeKnowledge: Unmarshalling Error\n",0);
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "DfsFsctrlVerifyLocalVolumeKnowledge: Exit -> %08lx\n",
ULongToPtr( status ));
return status;
}
//+----------------------------------------------------------------------------
//
// Function: PktFsctrlPruneLocalVolume, public
//
// Synopsis: Prunes information about an extra local volume.
//
// Arguments: [InputBuffer] -- Marshalled EntryId of the local volume.
//
// [InputBufferLength] -- length of InputBuffer
//
// Returns: [STATUS_REGISTRY_RECOVERED] -- Volume pruned successfully.
//
// [STATUS_UNSUCCESSFUL] -- Unable to delete volume - proper
// event has been logged to eventlog
//
// [STATUS_DATA_ERROR] -- Unable to unmarshal input arguments
//
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory
//
//-----------------------------------------------------------------------------
NTSTATUS
PktFsctrlPruneLocalVolume(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
MARSHAL_BUFFER marshalBuffer;
DFS_PKT_ENTRY_ID EntryId;
PDFS_PKT pkt = _GetPkt();
STD_FSCTRL_PROLOGUE(PktFsctrlPruneLocalVolume, TRUE, FALSE);
//
// unmarshal the arguments...
//
MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
status = DfsRtlGet(
&marshalBuffer,
&MiPktEntryId,
&EntryId);
if (NT_SUCCESS(status)) {
status = DfsInternalDeleteLocalVolume(&EntryId);
if (!NT_SUCCESS(status)) {
UNICODE_STRING puStr[2];
puStr[0] = EntryId.Prefix;
puStr[1].MaximumLength = sizeof(L"LocalMachine");
puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
puStr[1].Buffer = L"LocalMachine";
LogWriteMessage(
EXTRA_VOLUME_NOT_DELETED,
status,
2,
puStr);
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_REGISTRY_RECOVERED;
}
PktEntryIdDestroy(&EntryId, FALSE);
} else
DebugTrace(0, Dbg,
"PktFsctrlPruneLocalVolume: Unmarshalling Error\n",0);
DfsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "DfsFsctrlPruneLocalVolume: Exit -> %08lx\n",
ULongToPtr( 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 Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG Type;
PDFS_PKT Pkt;
PDFS_PKT_ENTRY curEntry, nextEntry;
STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE);
//
// Unmarshalling is very simple here. We only expect a ULONG.
//
Type = (*((ULONG *)InputBuffer));
Pkt = _GetPkt();
PktAcquireExclusive(Pkt, TRUE);
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(Pkt);
DfsCompleteRequest( Irp, status );
DebugTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr( status ));
return(status);
}
//+----------------------------------------------------------------------------
//
// Function: PktFsctrlShufflePktEntry
//
// Synopsis: Shuffles a pkt entry. Useful for testing.
//
// Arguments: [Irp]
// [InputBuffer] -- Marshalled Pkt entry to shuffle.
// [InputBufferLength] -- size of InputBuffer.
//
// Returns:
//
//-----------------------------------------------------------------------------
VOID
PktShuffleServiceList(
PDFS_PKT_ENTRY_INFO pInfo);
NTSTATUS
PktFsctrlShufflePktEntry(
IN PIRP Irp,
IN PVOID InputBuffer,
IN ULONG InputBufferLength)
{
NTSTATUS Status;
MARSHAL_BUFFER marshalBuffer;
DFS_PKT_ENTRY_ID PktEntryId;
PDFS_PKT_ENTRY pPktEntry;
UNICODE_STRING ustrRemaining;
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &PktEntryId );
if (NT_SUCCESS(Status)) {
pPktEntry = PktLookupEntryByPrefix(
&DfsData.Pkt,
&PktEntryId.Prefix,
&ustrRemaining);
if (pPktEntry == NULL || ustrRemaining.Length != 0) {
DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry : [%wZ] is not an entry\n", &PktEntryId.Prefix);
Status = STATUS_NOT_FOUND;
} else {
PktShuffleServiceList( &pPktEntry->Info );
}
PktEntryIdDestroy(&PktEntryId, FALSE);
} else {
DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry : DfsRtlGet returned %08lx\n", ULongToPtr( Status ) );
}
DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry - returning %08lx\n", ULongToPtr( Status ));
DfsCompleteRequest( Irp, Status );
return( Status );
}
#endif // DBG