Reactos

[NTOS/FSRTL] Fix MCB tests

- Fix behaviour when adding or removing entries in the middle of an existing run
- Do not touch output parameters when failing, caller might rely on this.

+58 -15
+58 -15
ntoskrnl/fsrtl/largemcb.c
··· 143 143 LARGE_MCB_MAPPING_ENTRY Node, NeedleRun; 144 144 PLARGE_MCB_MAPPING_ENTRY LowerRun, HigherRun; 145 145 BOOLEAN NewElement; 146 - LONGLONG IntLbn; 146 + LONGLONG IntLbn, IntSectorCount; 147 147 148 148 DPRINT("FsRtlAddBaseMcbEntry(%p, %I64d, %I64d, %I64d)\n", OpaqueMcb, Vbn, Lbn, SectorCount); 149 149 ··· 159 159 goto quit; 160 160 } 161 161 162 - IntResult = FsRtlLookupBaseMcbEntry(OpaqueMcb, Vbn, &IntLbn, NULL, NULL, NULL, NULL); 162 + IntResult = FsRtlLookupBaseMcbEntry(OpaqueMcb, Vbn, &IntLbn, &IntSectorCount, NULL, NULL, NULL); 163 163 if (IntResult) 164 164 { 165 165 if (IntLbn != -1 && IntLbn != Lbn) 166 166 { 167 167 Result = FALSE; 168 + goto quit; 169 + } 170 + 171 + if ((IntLbn != -1) && (IntSectorCount >= SectorCount)) 172 + { 173 + /* This is a no-op */ 168 174 goto quit; 169 175 } 170 176 } ··· 314 320 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant? 315 321 * 316 322 * Retrieves the parameters of the specified run with index @RunIndex. 317 - * 323 + * 318 324 * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping. 319 325 * libcaptive does not store 'hole' information to its #GTree. 320 326 * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1. ··· 336 342 ULONGLONG LastVbn = 0; 337 343 ULONGLONG LastSectorCount = 0; 338 344 339 - // Traverse the tree 345 + // Traverse the tree 340 346 for (Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, TRUE); 341 347 Run; 342 348 Run = (PLARGE_MCB_MAPPING_ENTRY)RtlEnumerateGenericTable(&Mcb->Mapping->Table, FALSE)) ··· 372 378 LastVbn = Run->RunStartVbn.QuadPart; 373 379 LastSectorCount = Run->RunEndVbn.QuadPart - Run->RunStartVbn.QuadPart; 374 380 } 375 - 376 - // these values are meaningless when returning false (but setting them can be helpful for debugging purposes) 377 - *Vbn = 0xdeadbeef; 378 - *Lbn = 0xdeadbeef; 379 - *SectorCount = 0xdeadbeef; 380 381 381 382 quit: 382 383 DPRINT("FsRtlGetNextBaseMcbEntry(%p, %d, %p, %p, %p) = %d (%I64d, %I64d, %I64d)\n", Mcb, RunIndex, Vbn, Lbn, SectorCount, Result, *Vbn, *Lbn, *SectorCount); ··· 542 543 } 543 544 } 544 545 545 - if (Lbn) 546 - *Lbn = -1; 547 - if (StartingLbn) 548 - *StartingLbn = -1; 549 - 550 546 quit: 551 547 DPRINT("FsRtlLookupBaseMcbEntry(%p, %I64d, %p, %p, %p, %p, %p) = %d (%I64d, %I64d, %I64d, %I64d, %d)\n", 552 548 OpaqueMcb, Vbn, Lbn, SectorCountFromLbn, StartingLbn, SectorCountFromStartingLbn, Index, Result, ··· 821 817 822 818 NeedleRun.RunStartVbn.QuadPart = Vbn; 823 819 NeedleRun.RunEndVbn.QuadPart = Vbn + SectorCount; 824 - NeedleRun.StartingLbn.QuadPart = ~0ULL; 820 + NeedleRun.StartingLbn.QuadPart = -1; 825 821 826 822 /* adjust/destroy all intersecting ranges */ 827 823 Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; ··· 829 825 { 830 826 if (HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunStartVbn.QuadPart) 831 827 { 828 + LONGLONG HaystackRunEnd = HaystackRun->RunEndVbn.QuadPart; 832 829 ASSERT(HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunStartVbn.QuadPart); 830 + 833 831 HaystackRun->RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart; 832 + 833 + if (HaystackRunEnd > NeedleRun.RunEndVbn.QuadPart) 834 + { 835 + /* The run we are deleting is included in the run we just truncated. 836 + * Add the tail back. */ 837 + LARGE_MCB_MAPPING_ENTRY TailRun; 838 + BOOLEAN NewElement; 839 + 840 + TailRun.RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart; 841 + TailRun.RunEndVbn.QuadPart = HaystackRunEnd; 842 + TailRun.StartingLbn.QuadPart = HaystackRun->StartingLbn.QuadPart + (NeedleRun.RunEndVbn.QuadPart - HaystackRun->RunStartVbn.QuadPart); 843 + 844 + Mcb->Mapping->Table.CompareRoutine = McbMappingCompare; 845 + 846 + RtlInsertElementGenericTable(&Mcb->Mapping->Table, &TailRun, sizeof(TailRun), &NewElement); 847 + ++Mcb->PairCount; 848 + ASSERT(NewElement); 849 + 850 + Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; 851 + } 834 852 } 835 853 else if (HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunEndVbn.QuadPart) 836 854 { 855 + LONGLONG HaystackRunStart = HaystackRun->RunStartVbn.QuadPart; 856 + LONGLONG HaystackStartingLbn = HaystackRun->StartingLbn.QuadPart; 857 + 837 858 ASSERT(HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunEndVbn.QuadPart); 838 859 HaystackRun->RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart; 860 + /* Adjust the starting LBN */ 861 + HaystackRun->StartingLbn.QuadPart += NeedleRun.RunEndVbn.QuadPart - HaystackRunStart; 862 + 863 + if (HaystackRunStart < NeedleRun.RunStartVbn.QuadPart) 864 + { 865 + /* The run we are deleting is included in the run we just truncated. 866 + * Add the head back. */ 867 + LARGE_MCB_MAPPING_ENTRY HeadRun; 868 + BOOLEAN NewElement; 869 + 870 + HeadRun.RunStartVbn.QuadPart = HaystackRunStart; 871 + HeadRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart; 872 + HeadRun.StartingLbn.QuadPart = HaystackStartingLbn; 873 + 874 + Mcb->Mapping->Table.CompareRoutine = McbMappingCompare; 875 + 876 + RtlInsertElementGenericTable(&Mcb->Mapping->Table, &HeadRun, sizeof(HeadRun), &NewElement); 877 + ++Mcb->PairCount; 878 + ASSERT(NewElement); 879 + 880 + Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare; 881 + } 839 882 } 840 883 else 841 884 {