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