diff --git a/NTOSKRNL/CC/ccloghandler.cpp b/NTOSKRNL/CC/ccloghandler.cpp index 09ba03a..b942857 100644 --- a/NTOSKRNL/CC/ccloghandler.cpp +++ b/NTOSKRNL/CC/ccloghandler.cpp @@ -21,9 +21,123 @@ CcGetDirtyPages(IN PVOID LogHandle, IN PVOID Context1, IN PVOID Context2) { - /* IMPLEMENTATION INCOMPLETE*/ + __try +{ + KIRQL OldIrql = {0}; + PSHARED_CACHE_MAP SharedCacheMap = nullptr; + PFILE_OBJECT *FileObject = nullptr; + PCC_BCB Bcb = nullptr, + PCC_BCB BcbToUnpin = nullptr; + PLIST_ENTRY Entry = &CcDirtyLoggedStreamLinks; + LARGE_INTEGER OldestLsn = {0}; + LARGE_INTEGER Result = {0}; + BOOLEAN FirstIteration = TRUE; + + // Acquire Master Lock + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + + // Iterate through all Dirty Shared Cache Maps + for (auto it = ListEntryIterator::begin(Entry); it != ListEntryIterator::end(Entry); ++it) + { + SharedCacheMap = CONTAINING_RECORD(*it, SHARED_CACHE_MAP, LoggedStreamLinks); + + // Check flags and validate LogHandle + if ((SharedCacheMap->Flags & 0x800) != 0) + { + DBGPRINT("CcGetDirtyPages::Invalid Flag \n") + return; + } + + if ((SharedCacheMap->Flags & 0x2000000) != 0 && SharedCacheMap->LogHandle == LogHandle) + { + SharedCacheMap->OpenCount++; + SharedCacheMap->DirtyPages++; + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + + /* Reference the shared cache map file object*/ + FileObject = CcReferenceSharedCacheMapFileObject(SharedCacheMap); + + /* Acquire the BCB Lock */ + oldIrql = ExAcquireSpinLockShared (&SharedCacheMap->BcbSpinLock); + + /* Iterate over BCB List */ + for (auto it = ListEntryIterator::begin(&SharedCacheMap->BcbList); it != ListEntryIterator::end(&SharedCacheMap->BcbList); ++it) + { + Bcb = CONTAINING_RECORD(*it, CC_BCB, BcbLinks); + + /* Ensure the BCB is marked as dirty */ + if (Bcb->NodeTypeCode == NODE_TYPE_DIRTY_BCB && Bcb->NodeByteCode) + { LocalFileOffset = Bcb->BaseData; + LocalOldestLsn = Bcb->OldestLsn; + LocalNewestLsn = Bcb->NewestLsn; + + /*Increment the PinCount to keep the BCB pinned*/ + Bcb->PinCount++; + + /*Release the BCB lock temporarily for the callback*/ + ExReleaseSpinLockShared (&SharedCacheMap->BcbSpinLock,oldIrql); + + /*Unpin any previously pinned BCB*/ + if (BcbToUnpin) + { + CcUnpinFileDataEx(BcbToUnpin, 1, 0); + BcbToUnpin = NULL; + } + + /* Invoke the provided dirty page routine*/ + DirtyPageRoutine(FileObject, + &LocalFileOffset, + SharedCacheMap, + &LocalOldestLsn, + &LocalNewestLsn, + Context1, + Context2); + if (LocalOldestLsn.QuadPart && OldestLsn.QuadPart || LocalOldestLsn.QuadPart < OldestLsn.QuadPart) + { + OldestLsn = LocalOldestLsn; + } + } + + // Reacquire the BCB lock + oldIrql = ExAcquireSpinLockShared (&SharedCacheMap->BcbSpinLock); + // Decrement the PinCount or mark for unpinning + if (Bcb->PinCount > 1) + { + Bcb->PinCount--; + BcbToUnpin = NULL; + } + else + { + BcbToUnpin = Bcb; + } + } + } + + /*Release the BCB lock*/ + ExReleaseSpinLockShared (&SharedCacheMap->BcbSpinLock,oldIrql); + + /* Dereference the shared cache map file object*/ + CcDereferenceSharedCacheMapFileObject(SharedCacheMap, FileObject); + + /*Unpin any remaining BCB*/ + if (BcbToUnpin) + { + CcUnpinFileDataEx(BcbToUnpin, 1,0); + BcbToUnpin = NULL; + } + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + + /*Decrement the OpenCount and DirtyPages*/ + SharedCacheMap->OpenCount--; + SharedCacheMap->DirtyPages--; + KeReleaseQueuedSpinLock(LockQueueMasterLock,OldIrql); + } } +} + + LARGE_INTEGER NTAPI CcGetLsnForFileObject(IN PFILE_OBJECT FileObject, @@ -113,3 +227,99 @@ CcSetLogHandleForFile(IN PFILE_OBJECT FileObject, SharedCacheMap->FlushToLsnRoutine = FlushToLsnRoutine; } +VOID +NTAPI +CcSetLogHandleForFileEx( + IN PFILE_OBJECT FileObject, + IN PVOID LogHandle, + IN PFLUSH_TO_LSN FlushToLsnRoutine + IN PQUERY_LOG_USAGE QueryLogUsageRoutine + IN PFILE_OBJECT RelatedLogHandleFileObject +) +{ + PSHARED_CACHE_MAP SharedCacheMap; + KIRQL OldIrql; + LOG_HANDLE_CONTEXT LogHandleContext; + PLOG_HANDLE_CONTEXT VolumeLogHandleContext; + LIST_ENTRY *ListHead; + LIST_ENTRY *PrevEntry; + + // Retrieve the Shared Cache Map + SharedCacheMap = (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; + + // Validate Shared Cache Map + if (!SharedCacheMap || SharedCacheMap->OpenCount == 0) { + + return; + } + if (SharedCacheMap->Flags & FLAG_LOGHANDLE_SET) { + return; + } + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + + /* Remove the existing log handle if present*/ + if (SharedCacheMap->LogHandle) + { + RemoveEntryList(&SharedCacheMap->LoggedStreamLinks); + } + + /*Handle the case when a new log handle is not provided*/ + if (!LogHandle) + { + SharedCacheMap->Flags &= ~FLAG_LOGHANDLE_NOT_SET; + SharedCacheMap->LogHandle = NULL; + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + return; + } + + /* Determine the appropriate list based on whether there are dirty pages*/ + if (SharedCacheMap->DirtyPages) + { + ListHead = &CcDirtyLoggedStreamLinks; + } + else + { + ListHead = &CcCleanLoggedStreamLinks; + } + + PrevEntry = ListHead->Blink; + InsertTailList(ListHead, &SharedCacheMap->LoggedStreamLinks); + + /*Initialize the volume log handle context if not already present*/ + VolumeLogHandleContext = &SharedCacheMap->VolumeCacheMap->LogHandleContext; + + if (VolumeLogHandleContext->LogHandle == NULL) + { + RtlZeroMemory(&LogHandleContext, sizeof(LOG_HANDLE_CONTEXT)); + LogHandleContext.LastLWTimeStamp.QuadPart = -1; + LogHandleContext.LogHandle = LogHandle; + LogHandleContext.FlushToLsnRoutine = FlushToLsnRoutine; + LogHandleContext.QueryLogUsageRoutine = QueryLogUsageRoutine; + + if (RelatedLogHandleFileObject) + { + ObfReferenceObjectWithTag(RelatedLogHandleFileObject, 'tlFD'); + LogHandleContext.RelatedFileObject = RelatedLogHandleFileObject; + } + + RtlCopyMemory(VolumeLogHandleContext, &LogHandleContext, sizeof(LOG_HANDLE_CONTEXT)); + } + + + SharedCacheMap->LogHandle = VolumeLogHandleContext; + + /*Update the flags and dirty page statistics*/ + if (!(SharedCacheMap->Flags & FLAG_LOGHANDLE_NOT_SET)) + { + if (SharedCacheMap->DirtyPages) + { + VolumeLogHandleContext->DirtyPageStatistics.DirtyPages += SharedCacheMap->DirtyPages; + } + } + + SharedCacheMap->Flags |= FLAG_LOGHANDLE_NOT_SET; + + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); +} +