|
|
//+----------------------------------------------------------------------------
//
// 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
|