1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: indirect.c 5 * PROGRAMMER: Matt Wu <mattwu@163.com> 6 * HOMEPAGE: http://www.ext2fsd.com 7 * UPDATE HISTORY: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "ext2fs.h" 13 14 /* GLOBALS *****************************************************************/ 15 16 extern PEXT2_GLOBAL Ext2Global; 17 18 /* DEFINITIONS *************************************************************/ 19 20 #ifdef ALLOC_PRAGMA 21 #endif 22 23 24 NTSTATUS 25 Ext2ExpandLast( 26 IN PEXT2_IRP_CONTEXT IrpContext, 27 IN PEXT2_VCB Vcb, 28 IN PEXT2_MCB Mcb, 29 IN ULONG Base, 30 IN ULONG Layer, 31 IN PULONG * Data, 32 IN PULONG Hint, 33 IN PULONG Block, 34 IN OUT PULONG Number 35 ) 36 { 37 PULONG pData = NULL; 38 ULONG i; 39 NTSTATUS Status = STATUS_SUCCESS; 40 41 if (Layer > 0 || IsMcbDirectory(Mcb)) { 42 43 /* allocate buffer for new block */ 44 pData = (ULONG *) Ext2AllocatePool( 45 PagedPool, 46 BLOCK_SIZE, 47 EXT2_DATA_MAGIC 48 ); 49 if (!pData) { 50 DEBUG(DL_ERR, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n")); 51 Status = STATUS_INSUFFICIENT_RESOURCES; 52 goto errorout; 53 } 54 RtlZeroMemory(pData, BLOCK_SIZE); 55 INC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); 56 } 57 58 /* allocate block from disk */ 59 Status = Ext2NewBlock( 60 IrpContext, 61 Vcb, 62 (Mcb->Inode.i_ino - 1) / BLOCKS_PER_GROUP, 63 *Hint, 64 Block, 65 Number 66 ); 67 68 if (!NT_SUCCESS(Status)) { 69 goto errorout; 70 } 71 72 /* increase inode i_blocks */ 73 Mcb->Inode.i_blocks += (*Number << (BLOCK_BITS - 9)); 74 75 if (Layer == 0) { 76 77 if (IsMcbDirectory(Mcb)) { 78 /* for directory we need initialize it's entry structure */ 79 PEXT2_DIR_ENTRY2 pEntry; 80 pEntry = (PEXT2_DIR_ENTRY2) pData; 81 pEntry->rec_len = (USHORT)(BLOCK_SIZE); 82 ASSERT(*Number == 1); 83 Ext2SaveBlock(IrpContext, Vcb, *Block, (PVOID)pData); 84 } 85 86 /* add new Extent into Mcb */ 87 if (!Ext2AddBlockExtent(Vcb, Mcb, Base, (*Block), *Number)) { 88 DbgBreak(); 89 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 90 Ext2ClearAllExtents(&Mcb->Extents); 91 } 92 93 } else { 94 95 /* zero the content of all meta blocks */ 96 for (i = 0; i < *Number; i++) { 97 Ext2SaveBlock(IrpContext, Vcb, *Block + i, (PVOID)pData); 98 /* add block to meta extents */ 99 if (!Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1)) { 100 DbgBreak(); 101 Ext2Sleep(500); 102 Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1); 103 } 104 } 105 } 106 107 errorout: 108 109 if (NT_SUCCESS(Status)) { 110 *Hint = *Block + *Number; 111 if (Data) { 112 *Data = pData; 113 ASSERT(*Number == 1); 114 } else { 115 if (pData) { 116 Ext2FreePool(pData, EXT2_DATA_MAGIC); 117 DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); 118 } 119 } 120 } else { 121 if (pData) { 122 Ext2FreePool(pData, EXT2_DATA_MAGIC); 123 DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); 124 } 125 if (*Block) { 126 Ext2FreeBlock(IrpContext, Vcb, *Block, *Number); 127 Mcb->Inode.i_blocks -= (*Number << (BLOCK_BITS - 9)); 128 *Block = 0; 129 } 130 } 131 132 return Status; 133 } 134 135 NTSTATUS 136 Ext2GetBlock( 137 IN PEXT2_IRP_CONTEXT IrpContext, 138 IN PEXT2_VCB Vcb, 139 IN PEXT2_MCB Mcb, 140 IN ULONG Base, 141 IN ULONG Layer, 142 IN ULONG Start, 143 IN ULONG SizeArray, 144 IN PULONG BlockArray, 145 IN BOOLEAN bAlloc, 146 IN OUT PULONG Hint, 147 OUT PULONG Block, 148 OUT PULONG Number 149 ) 150 { 151 NTSTATUS Status = STATUS_SUCCESS; 152 PBCB Bcb = NULL; 153 PULONG pData = NULL; 154 ULONG Slot = 0, i = 0; 155 ULONG Unit = 1; 156 157 LARGE_INTEGER Offset; 158 159 if (Layer == 0) { 160 161 *Number = 1; 162 if (BlockArray[0] == 0 && bAlloc) { 163 164 /* now allocate new block */ 165 Status = Ext2ExpandLast( 166 IrpContext, 167 Vcb, 168 Mcb, 169 Base, 170 Layer, 171 NULL, 172 Hint, 173 &BlockArray[0], 174 Number 175 ); 176 177 if (!NT_SUCCESS(Status)) { 178 goto errorout; 179 } 180 } else { 181 /* check the block is valid or not */ 182 if (BlockArray[0] >= TOTAL_BLOCKS) { 183 DbgBreak(); 184 Status = STATUS_DISK_CORRUPT_ERROR; 185 goto errorout; 186 } 187 } 188 189 *Block = BlockArray[0]; 190 for (i=1; i < SizeArray; i++) { 191 if (BlockArray[i] == BlockArray[i-1] + 1) { 192 *Number = *Number + 1; 193 } else { 194 break; 195 } 196 } 197 *Hint = BlockArray[*Number - 1]; 198 199 } else if (Layer <= 3) { 200 201 /* check the block is valid or not */ 202 if (BlockArray[0] == 0 || BlockArray[0] >= TOTAL_BLOCKS) { 203 DbgBreak(); 204 Status = STATUS_DISK_CORRUPT_ERROR; 205 goto errorout; 206 } 207 208 /* add block to meta extents */ 209 if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1)) { 210 DbgBreak(); 211 Ext2Sleep(500); 212 Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1); 213 } 214 215 /* map memory in cache for the index block */ 216 Offset.QuadPart = ((LONGLONG)BlockArray[0]) << BLOCK_BITS; 217 if ( !CcPinRead( Vcb->Volume, 218 (PLARGE_INTEGER) (&Offset), 219 BLOCK_SIZE, 220 PIN_WAIT, 221 &Bcb, 222 #ifdef __REACTOS__ 223 (void **)&pData )) { 224 #else 225 &pData )) { 226 #endif 227 228 DEBUG(DL_ERR, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n", 229 BlockArray[0] )); 230 Status = STATUS_CANT_WAIT; 231 goto errorout; 232 } 233 234 if (Layer > 1) { 235 Unit = Vcb->max_blocks_per_layer[Layer - 1]; 236 } else { 237 Unit = 1; 238 } 239 240 Slot = Start / Unit; 241 Start = Start % Unit; 242 243 if (pData[Slot] == 0) { 244 245 if (bAlloc) { 246 247 /* we need allocate new block and zero all data in case 248 it's an in-direct block. Index stores the new block no. */ 249 ULONG Count = 1; 250 Status = Ext2ExpandLast( 251 IrpContext, 252 Vcb, 253 Mcb, 254 Base, 255 Layer, 256 NULL, 257 Hint, 258 &pData[Slot], 259 &Count 260 ); 261 262 if (!NT_SUCCESS(Status)) { 263 goto errorout; 264 } 265 266 /* refresh hint block */ 267 *Hint = pData[Slot]; 268 269 /* set dirty bit to notify system to flush */ 270 CcSetDirtyPinnedData(Bcb, NULL ); 271 SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); 272 if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, 273 (LONGLONG)BLOCK_SIZE)) { 274 DbgBreak(); 275 Ext2Sleep(100); 276 if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, 277 (LONGLONG)BLOCK_SIZE)) { 278 Status = STATUS_INSUFFICIENT_RESOURCES; 279 goto errorout; 280 } 281 } 282 283 /* save inode information here */ 284 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 285 286 } else { 287 288 *Number = 1; 289 290 if (Layer == 1) { 291 for (i = Slot + 1; i < BLOCK_SIZE/4; i++) { 292 if (pData[i] == 0) { 293 *Number = *Number + 1; 294 } else { 295 break; 296 } 297 } 298 } else if (Layer == 2) { 299 *Number = BLOCK_SIZE/4 - Start; 300 } else { 301 *Number = BLOCK_SIZE/4; 302 } 303 304 goto errorout; 305 } 306 } 307 308 /* transfer to next recursion call */ 309 Status = Ext2GetBlock( 310 IrpContext, 311 Vcb, 312 Mcb, 313 Base, 314 Layer - 1, 315 Start, 316 BLOCK_SIZE/4 - Slot, 317 &pData[Slot], 318 bAlloc, 319 Hint, 320 Block, 321 Number 322 ); 323 324 if (!NT_SUCCESS(Status)) { 325 goto errorout; 326 } 327 } 328 329 errorout: 330 331 /* free the memory of pData */ 332 if (Bcb) { 333 CcUnpinData(Bcb); 334 } 335 336 if (!NT_SUCCESS(Status)) { 337 *Block = 0; 338 } 339 340 return Status; 341 } 342 343 344 NTSTATUS 345 Ext2ExpandBlock( 346 IN PEXT2_IRP_CONTEXT IrpContext, 347 IN PEXT2_VCB Vcb, 348 IN PEXT2_MCB Mcb, 349 IN ULONG Base, 350 IN ULONG Layer, 351 IN ULONG Start, 352 IN ULONG SizeArray, 353 IN PULONG BlockArray, 354 IN PULONG Hint, 355 IN PULONG Extra 356 ) 357 { 358 ULONG i = 0; 359 ULONG j; 360 ULONG Slot; 361 ULONG Block = 0; 362 LARGE_INTEGER Offset; 363 364 PBCB Bcb = NULL; 365 PULONG pData = NULL; 366 ULONG Skip = 0; 367 368 ULONG Number; 369 ULONG Wanted; 370 371 NTSTATUS Status = STATUS_SUCCESS; 372 373 if (Layer == 1) { 374 375 /* 376 * try to make all leaf block continuous to avoid fragments 377 */ 378 379 Number = min(SizeArray, ((*Extra + (Start & (BLOCK_SIZE/4 - 1))) * 4 / BLOCK_SIZE)); 380 Wanted = 0; 381 DEBUG(DL_BLK, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n", 382 SizeArray, *Extra, Start, Number )); 383 384 for (i=0; i < Number; i++) { 385 if (BlockArray[i] == 0) { 386 Wanted += 1; 387 } 388 } 389 390 i = 0; 391 while (Wanted > 0) { 392 393 Number = Wanted; 394 Status = Ext2ExpandLast( 395 IrpContext, 396 Vcb, 397 Mcb, 398 Base, 399 Layer, 400 NULL, 401 Hint, 402 &Block, 403 &Number 404 ); 405 if (!NT_SUCCESS(Status)) { 406 goto errorout; 407 } 408 409 ASSERT(Number > 0); 410 Wanted -= Number; 411 while (Number) { 412 if (BlockArray[i] == 0) { 413 BlockArray[i] = Block++; 414 Number--; 415 } 416 i++; 417 } 418 } 419 420 } else if (Layer == 0) { 421 422 /* 423 * bulk allocation for inode data blocks 424 */ 425 426 i = 0; 427 428 while (*Extra && i < SizeArray) { 429 430 Wanted = 0; 431 Number = 1; 432 433 for (j = i; j < SizeArray && j < i + *Extra; j++) { 434 435 if (BlockArray[j] >= TOTAL_BLOCKS) { 436 DbgBreak(); 437 BlockArray[j] = 0; 438 } 439 440 if (BlockArray[j] == 0) { 441 Wanted += 1; 442 } else { 443 break; 444 } 445 } 446 447 if (Wanted == 0) { 448 449 /* add block extent into Mcb */ 450 ASSERT(BlockArray[i] != 0); 451 if (!Ext2AddBlockExtent(Vcb, Mcb, Base + i, BlockArray[i], 1)) { 452 DbgBreak(); 453 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 454 Ext2ClearAllExtents(&Mcb->Extents); 455 } 456 457 } else { 458 459 Number = Wanted; 460 Status = Ext2ExpandLast( 461 IrpContext, 462 Vcb, 463 Mcb, 464 Base + i, 465 0, 466 NULL, 467 Hint, 468 &Block, 469 &Number 470 ); 471 if (!NT_SUCCESS(Status)) { 472 goto errorout; 473 } 474 475 ASSERT(Number > 0); 476 for (j = 0; j < Number; j++) { 477 BlockArray[i + j] = Block++; 478 } 479 } 480 481 *Extra -= Number; 482 i += Number; 483 } 484 485 goto errorout; 486 } 487 488 489 /* 490 * only for meta blocks allocation 491 */ 492 493 for (i = 0; *Extra && i < SizeArray; i++) { 494 495 if (Layer <= 3) { 496 497 if (BlockArray[i] >= TOTAL_BLOCKS) { 498 DbgBreak(); 499 BlockArray[i] = 0; 500 } 501 502 if (BlockArray[i] == 0) { 503 Number = 1; 504 Status = Ext2ExpandLast( 505 IrpContext, 506 Vcb, 507 Mcb, 508 Base, 509 Layer, 510 &pData, 511 Hint, 512 &BlockArray[i], 513 &Number 514 ); 515 if (!NT_SUCCESS(Status)) { 516 goto errorout; 517 } 518 519 } else { 520 521 Offset.QuadPart = (((LONGLONG)BlockArray[i]) << BLOCK_BITS); 522 if (!CcPinRead( 523 Vcb->Volume, 524 &Offset, 525 BLOCK_SIZE, 526 PIN_WAIT, 527 &Bcb, 528 #ifdef __REACTOS__ 529 (void **)&pData )) { 530 #else 531 &pData )) { 532 #endif 533 534 DEBUG(DL_ERR, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n", 535 Offset.QuadPart)); 536 Status = STATUS_CANT_WAIT; 537 DbgBreak(); 538 goto errorout; 539 } 540 541 /* add block to meta extents */ 542 if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1)) { 543 DbgBreak(); 544 Ext2Sleep(500); 545 Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1); 546 } 547 } 548 549 Skip = Vcb->max_blocks_per_layer[Layer] * i; 550 551 if (i == 0) { 552 if (Layer > 1) { 553 Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; 554 Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; 555 Skip += Slot * Vcb->max_blocks_per_layer[Layer - 1]; 556 } else { 557 Slot = Start; 558 Start = 0; 559 Skip += Slot; 560 } 561 } else { 562 Start = 0; 563 Slot = 0; 564 } 565 566 Status = Ext2ExpandBlock( 567 IrpContext, 568 Vcb, 569 Mcb, 570 Base + Skip, 571 Layer - 1, 572 Start, 573 BLOCK_SIZE/4 - Slot, 574 &pData[Slot], 575 Hint, 576 Extra 577 ); 578 579 if (Bcb) { 580 CcSetDirtyPinnedData(Bcb, NULL); 581 if (!Ext2AddBlockExtent(Vcb, NULL, 582 BlockArray[i], 583 BlockArray[i], 1)) { 584 DbgBreak(); 585 Ext2Sleep(500); 586 if (!Ext2AddBlockExtent(Vcb, NULL, 587 BlockArray[i], 588 BlockArray[i], 1)) { 589 } 590 } 591 } else { 592 Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData); 593 } 594 595 if (pData) { 596 if (Bcb) { 597 CcUnpinData(Bcb); 598 Bcb = NULL; 599 } else { 600 Ext2FreePool(pData, EXT2_DATA_MAGIC); 601 DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); 602 } 603 pData = NULL; 604 } 605 606 if (!NT_SUCCESS(Status)) { 607 DbgBreak(); 608 break; 609 } 610 } 611 } 612 613 errorout: 614 615 return Status; 616 } 617 618 BOOLEAN 619 Ext2IsBlockEmpty(PULONG BlockArray, ULONG SizeArray) 620 { 621 ULONG i = 0; 622 for (i=0; i < SizeArray; i++) { 623 if (BlockArray[i]) { 624 break; 625 } 626 } 627 return (i == SizeArray); 628 } 629 630 631 NTSTATUS 632 Ext2TruncateBlock( 633 IN PEXT2_IRP_CONTEXT IrpContext, 634 IN PEXT2_VCB Vcb, 635 IN PEXT2_MCB Mcb, 636 IN ULONG Base, 637 IN ULONG Start, 638 IN ULONG Layer, 639 IN ULONG SizeArray, 640 IN PULONG BlockArray, 641 IN PULONG Extra 642 ) 643 { 644 NTSTATUS Status = STATUS_SUCCESS; 645 ULONG i = 0; 646 ULONG Slot = 0; 647 ULONG Skip = 0; 648 649 LONGLONG Offset; 650 PBCB Bcb = NULL; 651 PULONG pData = NULL; 652 653 ASSERT(Mcb != NULL); 654 655 for (i = 0; i < SizeArray; i++) { 656 657 if (Layer == 0) { 658 659 ULONG Number = 1; 660 661 while (Extra && SizeArray > i + 1 && Number < *Extra) { 662 663 if (BlockArray[SizeArray - i - 1] == 664 BlockArray[SizeArray - i - 2] + 1) { 665 666 BlockArray[SizeArray - i - 1] = 0; 667 Number++; 668 SizeArray--; 669 670 } else { 671 break; 672 } 673 } 674 675 if (BlockArray[SizeArray - i - 1]) { 676 677 Status = Ext2FreeBlock(IrpContext, Vcb, BlockArray[SizeArray - i - 1], Number); 678 if (NT_SUCCESS(Status)) { 679 ASSERT(Mcb->Inode.i_blocks >= (Number << (BLOCK_BITS - 9))); 680 if (Mcb->Inode.i_blocks < (Number << (BLOCK_BITS - 9))) { 681 Mcb->Inode.i_blocks = 0; 682 DbgBreak(); 683 } else { 684 Mcb->Inode.i_blocks -= (Number << (BLOCK_BITS - 9)); 685 } 686 BlockArray[SizeArray - i - 1] = 0; 687 } 688 } 689 690 if (Extra) { 691 692 /* dec blocks count */ 693 ASSERT(*Extra >= Number); 694 *Extra = *Extra - Number; 695 696 /* remove block mapping frm Mcb Extents */ 697 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + SizeArray - 1 - i, Number)) { 698 DbgBreak(); 699 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 700 Ext2ClearAllExtents(&Mcb->Extents); 701 } 702 } 703 704 } else { 705 706 ASSERT(Layer <= 3); 707 708 if (BlockArray[SizeArray - i - 1] >= TOTAL_BLOCKS) { 709 DbgBreak(); 710 BlockArray[SizeArray - i - 1] = 0; 711 } 712 713 if (i == 0) { 714 if (Layer > 1) { 715 Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; 716 Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; 717 } else { 718 Slot = Start; 719 Start = (BLOCK_SIZE / 4) - 1; 720 } 721 } else { 722 Slot = Start = (BLOCK_SIZE / 4) - 1; 723 } 724 725 Skip = (SizeArray - i - 1) * Vcb->max_blocks_per_layer[Layer]; 726 727 if (BlockArray[SizeArray - i - 1]) { 728 729 Offset = (LONGLONG) (BlockArray[SizeArray - i - 1]); 730 Offset = Offset << BLOCK_BITS; 731 732 if (!CcPinRead( Vcb->Volume, 733 (PLARGE_INTEGER) (&Offset), 734 BLOCK_SIZE, 735 PIN_WAIT, 736 &Bcb, 737 #ifdef __REACTOS__ 738 (void **)&pData )) { 739 #else 740 &pData )) { 741 #endif 742 743 DEBUG(DL_ERR, ( "Ext2TruncateBlock: PinLock failed on block %xh ...\n", 744 BlockArray[SizeArray - i - 1])); 745 Status = STATUS_CANT_WAIT; 746 DbgBreak(); 747 goto errorout; 748 } 749 750 Status = Ext2TruncateBlock( 751 IrpContext, 752 Vcb, 753 Mcb, 754 Base + Skip, 755 Start, 756 Layer - 1, 757 Slot + 1, 758 &pData[0], 759 Extra 760 ); 761 762 if (!NT_SUCCESS(Status)) { 763 break; 764 } 765 766 CcSetDirtyPinnedData(Bcb, NULL); 767 Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)BLOCK_SIZE); 768 769 if (*Extra || Ext2IsBlockEmpty(pData, BLOCK_SIZE/4)) { 770 771 Ext2TruncateBlock( 772 IrpContext, 773 Vcb, 774 Mcb, 775 Base + Skip, /* base */ 776 0, /* start */ 777 0, /* layer */ 778 1, 779 &BlockArray[SizeArray - i - 1], 780 NULL 781 ); 782 783 if (!Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1)) { 784 DbgBreak(); 785 Ext2Sleep(500); 786 Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1); 787 } 788 } 789 790 if (pData) { 791 CcUnpinData(Bcb); 792 Bcb = NULL; 793 pData = NULL; 794 } 795 796 } else { 797 798 if (Layer > 1) { 799 if (*Extra > Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1) { 800 *Extra -= (Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1); 801 } else { 802 *Extra = 0; 803 } 804 } else { 805 if (*Extra > Slot + 1) { 806 *Extra -= (Slot + 1); 807 } else { 808 *Extra = 0; 809 } 810 } 811 812 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + Skip, (Start + 1))) { 813 DbgBreak(); 814 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 815 Ext2ClearAllExtents(&Mcb->Extents); 816 } 817 } 818 } 819 820 if (Extra && *Extra == 0) { 821 break; 822 } 823 } 824 825 errorout: 826 827 if (pData) { 828 CcUnpinData(Bcb); 829 } 830 831 return Status; 832 } 833 834 NTSTATUS 835 Ext2MapIndirect( 836 IN PEXT2_IRP_CONTEXT IrpContext, 837 IN PEXT2_VCB Vcb, 838 IN PEXT2_MCB Mcb, 839 IN ULONG Index, 840 IN BOOLEAN bAlloc, 841 OUT PULONG pBlock, 842 OUT PULONG Number 843 ) 844 { 845 ULONG Layer; 846 ULONG Slot; 847 848 ULONG Base = Index; 849 850 NTSTATUS Status = STATUS_SUCCESS; 851 852 *pBlock = 0; 853 *Number = 0; 854 855 for (Layer = 0; Layer < EXT2_BLOCK_TYPES; Layer++) { 856 857 if (Index < Vcb->max_blocks_per_layer[Layer]) { 858 859 ULONG dwRet = 0, dwBlk = 0, dwHint = 0, dwArray = 0; 860 861 Slot = (Layer==0) ? (Index):(Layer + EXT2_NDIR_BLOCKS - 1); 862 dwBlk = Mcb->Inode.i_block[Slot]; 863 864 if (dwBlk == 0) { 865 866 if (!bAlloc) { 867 868 *Number = 1; 869 goto errorout; 870 871 } else { 872 873 if (Slot) { 874 dwHint = Mcb->Inode.i_block[Slot - 1]; 875 } 876 877 /* allocate and zero block if necessary */ 878 *Number = 1; 879 Status = Ext2ExpandLast( 880 IrpContext, 881 Vcb, 882 Mcb, 883 Base, 884 Layer, 885 NULL, 886 &dwHint, 887 &dwBlk, 888 Number 889 ); 890 891 if (!NT_SUCCESS(Status)) { 892 goto errorout; 893 } 894 895 /* save the it into inode*/ 896 Mcb->Inode.i_block[Slot] = dwBlk; 897 898 /* save the inode */ 899 if (!Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode)) { 900 DbgBreak(); 901 Status = STATUS_UNSUCCESSFUL; 902 goto errorout; 903 } 904 } 905 } 906 907 if (Layer == 0) 908 dwArray = Vcb->max_blocks_per_layer[Layer] - Index; 909 else 910 dwArray = 1; 911 912 /* querying block number of the index-th file block */ 913 Status = Ext2GetBlock( 914 IrpContext, 915 Vcb, 916 Mcb, 917 Base, 918 Layer, 919 Index, 920 dwArray, 921 #ifdef __REACTOS__ 922 (PULONG)&Mcb->Inode.i_block[Slot], 923 #else 924 &Mcb->Inode.i_block[Slot], 925 #endif 926 bAlloc, 927 &dwHint, 928 &dwRet, 929 Number 930 ); 931 932 if (NT_SUCCESS(Status)) { 933 *pBlock = dwRet; 934 } 935 936 break; 937 } 938 939 Index -= Vcb->max_blocks_per_layer[Layer]; 940 } 941 942 errorout: 943 944 return Status; 945 } 946 947 NTSTATUS 948 Ext2ExpandIndirect( 949 PEXT2_IRP_CONTEXT IrpContext, 950 PEXT2_VCB Vcb, 951 PEXT2_MCB Mcb, 952 ULONG Start, 953 ULONG End, 954 PLARGE_INTEGER Size 955 ) 956 { 957 NTSTATUS Status = STATUS_SUCCESS; 958 959 ULONG Layer = 0; 960 ULONG Extra = 0; 961 ULONG Hint = 0; 962 ULONG Slot = 0; 963 ULONG Base = 0; 964 965 Extra = End - Start; 966 967 /* exceeds the biggest file size (indirect) */ 968 if (End > Vcb->max_data_blocks) { 969 return STATUS_INVALID_PARAMETER; 970 } 971 972 for (Layer = 0; Layer < EXT2_BLOCK_TYPES && Extra; Layer++) { 973 974 if (Start >= Vcb->max_blocks_per_layer[Layer]) { 975 976 Base += Vcb->max_blocks_per_layer[Layer]; 977 Start -= Vcb->max_blocks_per_layer[Layer]; 978 979 } else { 980 981 /* get the slot in i_block array */ 982 if (Layer == 0) { 983 Base = Slot = Start; 984 } else { 985 Slot = Layer + EXT2_NDIR_BLOCKS - 1; 986 } 987 988 /* set block hint to avoid fragments */ 989 if (Hint == 0) { 990 if (Mcb->Inode.i_block[Slot] != 0) { 991 Hint = Mcb->Inode.i_block[Slot]; 992 } else if (Slot > 1) { 993 Hint = Mcb->Inode.i_block[Slot-1]; 994 } 995 } 996 997 /* now expand this slot */ 998 Status = Ext2ExpandBlock( 999 IrpContext, 1000 Vcb, 1001 Mcb, 1002 Base, 1003 Layer, 1004 Start, 1005 (Layer == 0) ? (Vcb->max_blocks_per_layer[Layer] - Start) : 1, 1006 #ifdef __REACTOS__ 1007 (PULONG)&Mcb->Inode.i_block[Slot], 1008 #else 1009 &Mcb->Inode.i_block[Slot], 1010 #endif 1011 &Hint, 1012 &Extra 1013 ); 1014 if (!NT_SUCCESS(Status)) { 1015 break; 1016 } 1017 1018 Start = 0; 1019 if (Layer == 0) { 1020 Base = 0; 1021 } 1022 Base += Vcb->max_blocks_per_layer[Layer]; 1023 } 1024 } 1025 1026 Size->QuadPart = ((LONGLONG)(End - Extra)) << BLOCK_BITS; 1027 1028 /* save inode whatever it succeeds to expand or not */ 1029 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1030 1031 return Status; 1032 } 1033 1034 NTSTATUS 1035 Ext2TruncateIndirectFast( 1036 PEXT2_IRP_CONTEXT IrpContext, 1037 PEXT2_VCB Vcb, 1038 PEXT2_MCB Mcb 1039 ) 1040 { 1041 LONGLONG Vba; 1042 LONGLONG Lba; 1043 LONGLONG Length; 1044 NTSTATUS Status = STATUS_SUCCESS; 1045 int i; 1046 1047 /* try to load all indirect blocks if mcb zone is not initialized */ 1048 if (!IsZoneInited(Mcb)) { 1049 Status = Ext2InitializeZone(IrpContext, Vcb, Mcb); 1050 if (!NT_SUCCESS(Status)) { 1051 DbgBreak(); 1052 ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED); 1053 goto errorout; 1054 } 1055 } 1056 1057 ASSERT (IsZoneInited(Mcb)); 1058 1059 /* delete all data blocks here */ 1060 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents) != 0) { 1061 for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->Extents, i, &Vba, &Lba, &Length); i++) { 1062 /* ignore the non-existing runs */ 1063 if (-1 == Lba || Vba == 0 || Length <= 0) 1064 continue; 1065 /* now do data block free */ 1066 Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); 1067 } 1068 } 1069 1070 /* delete all meta blocks here */ 1071 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts) != 0) { 1072 for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->MetaExts, i, &Vba, &Lba, &Length); i++) { 1073 /* ignore the non-existing runs */ 1074 if (-1 == Lba || Vba == 0 || Length <= 0) 1075 continue; 1076 /* now do meta block free */ 1077 Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); 1078 } 1079 } 1080 1081 /* clear data and meta extents */ 1082 Ext2ClearAllExtents(&Mcb->Extents); 1083 Ext2ClearAllExtents(&Mcb->MetaExts); 1084 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 1085 1086 /* clear inode blocks & sizes */ 1087 Mcb->Inode.i_blocks = 0; 1088 Mcb->Inode.i_size = 0; 1089 memset(&Mcb->Inode.i_block[0], 0, sizeof(__u32) * 15); 1090 1091 /* the caller will do inode save */ 1092 1093 errorout: 1094 1095 return Status; 1096 } 1097 1098 NTSTATUS 1099 Ext2TruncateIndirect( 1100 PEXT2_IRP_CONTEXT IrpContext, 1101 PEXT2_VCB Vcb, 1102 PEXT2_MCB Mcb, 1103 PLARGE_INTEGER Size 1104 ) 1105 { 1106 NTSTATUS Status = STATUS_SUCCESS; 1107 1108 ULONG Layer = 0; 1109 1110 ULONG Extra = 0; 1111 ULONG Wanted = 0; 1112 ULONG End; 1113 ULONG Base; 1114 1115 ULONG SizeArray = 0; 1116 PULONG BlockArray = NULL; 1117 1118 /* translate file size to block */ 1119 End = Base = Vcb->max_data_blocks; 1120 Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS); 1121 1122 /* do fast deletion here */ 1123 if (Wanted == 0) { 1124 Status = Ext2TruncateIndirectFast(IrpContext, Vcb, Mcb); 1125 if (NT_SUCCESS(Status)) 1126 goto errorout; 1127 } 1128 1129 /* calculate blocks to be freed */ 1130 Extra = End - Wanted; 1131 1132 for (Layer = EXT2_BLOCK_TYPES; Layer > 0 && Extra; Layer--) { 1133 1134 if (Vcb->max_blocks_per_layer[Layer - 1] == 0) { 1135 continue; 1136 } 1137 1138 Base -= Vcb->max_blocks_per_layer[Layer - 1]; 1139 1140 if (Layer - 1 == 0) { 1141 #ifdef __REACTOS__ 1142 BlockArray = (PULONG)&Mcb->Inode.i_block[0]; 1143 #else 1144 BlockArray = &Mcb->Inode.i_block[0]; 1145 #endif 1146 SizeArray = End; 1147 ASSERT(End == EXT2_NDIR_BLOCKS && Base == 0); 1148 } else { 1149 #ifdef __REACTOS__ 1150 BlockArray = (PULONG)&Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1]; 1151 #else 1152 BlockArray = &Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1]; 1153 #endif 1154 SizeArray = 1; 1155 } 1156 1157 Status = Ext2TruncateBlock( 1158 IrpContext, 1159 Vcb, 1160 Mcb, 1161 Base, 1162 End - Base - 1, 1163 Layer - 1, 1164 SizeArray, 1165 BlockArray, 1166 &Extra 1167 ); 1168 if (!NT_SUCCESS(Status)) { 1169 break; 1170 } 1171 1172 End = Base; 1173 } 1174 1175 errorout: 1176 1177 if (!NT_SUCCESS(Status)) { 1178 Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS); 1179 } 1180 1181 /* save inode */ 1182 if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart)) 1183 Mcb->Inode.i_size = (loff_t)(Size->QuadPart); 1184 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1185 1186 return Status; 1187 } 1188