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 (void **)&pData )) { 223 224 DEBUG(DL_ERR, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n", 225 BlockArray[0] )); 226 Status = STATUS_CANT_WAIT; 227 goto errorout; 228 } 229 230 if (Layer > 1) { 231 Unit = Vcb->max_blocks_per_layer[Layer - 1]; 232 } else { 233 Unit = 1; 234 } 235 236 Slot = Start / Unit; 237 Start = Start % Unit; 238 239 if (pData[Slot] == 0) { 240 241 if (bAlloc) { 242 243 /* we need allocate new block and zero all data in case 244 it's an in-direct block. Index stores the new block no. */ 245 ULONG Count = 1; 246 Status = Ext2ExpandLast( 247 IrpContext, 248 Vcb, 249 Mcb, 250 Base, 251 Layer, 252 NULL, 253 Hint, 254 &pData[Slot], 255 &Count 256 ); 257 258 if (!NT_SUCCESS(Status)) { 259 goto errorout; 260 } 261 262 /* refresh hint block */ 263 *Hint = pData[Slot]; 264 265 /* set dirty bit to notify system to flush */ 266 CcSetDirtyPinnedData(Bcb, NULL ); 267 SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); 268 if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, 269 (LONGLONG)BLOCK_SIZE)) { 270 DbgBreak(); 271 Ext2Sleep(100); 272 if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, 273 (LONGLONG)BLOCK_SIZE)) { 274 Status = STATUS_INSUFFICIENT_RESOURCES; 275 goto errorout; 276 } 277 } 278 279 /* save inode information here */ 280 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 281 282 } else { 283 284 *Number = 1; 285 286 if (Layer == 1) { 287 for (i = Slot + 1; i < BLOCK_SIZE/4; i++) { 288 if (pData[i] == 0) { 289 *Number = *Number + 1; 290 } else { 291 break; 292 } 293 } 294 } else if (Layer == 2) { 295 *Number = BLOCK_SIZE/4 - Start; 296 } else { 297 *Number = BLOCK_SIZE/4; 298 } 299 300 goto errorout; 301 } 302 } 303 304 /* transfer to next recursion call */ 305 Status = Ext2GetBlock( 306 IrpContext, 307 Vcb, 308 Mcb, 309 Base, 310 Layer - 1, 311 Start, 312 BLOCK_SIZE/4 - Slot, 313 &pData[Slot], 314 bAlloc, 315 Hint, 316 Block, 317 Number 318 ); 319 320 if (!NT_SUCCESS(Status)) { 321 goto errorout; 322 } 323 } 324 325 errorout: 326 327 /* free the memory of pData */ 328 if (Bcb) { 329 CcUnpinData(Bcb); 330 } 331 332 if (!NT_SUCCESS(Status)) { 333 *Block = 0; 334 } 335 336 return Status; 337 } 338 339 340 NTSTATUS 341 Ext2ExpandBlock( 342 IN PEXT2_IRP_CONTEXT IrpContext, 343 IN PEXT2_VCB Vcb, 344 IN PEXT2_MCB Mcb, 345 IN ULONG Base, 346 IN ULONG Layer, 347 IN ULONG Start, 348 IN ULONG SizeArray, 349 IN PULONG BlockArray, 350 IN PULONG Hint, 351 IN PULONG Extra 352 ) 353 { 354 ULONG i = 0; 355 ULONG j; 356 ULONG Slot; 357 ULONG Block = 0; 358 LARGE_INTEGER Offset; 359 360 PBCB Bcb = NULL; 361 PULONG pData = NULL; 362 ULONG Skip = 0; 363 364 ULONG Number; 365 ULONG Wanted; 366 367 NTSTATUS Status = STATUS_SUCCESS; 368 369 if (Layer == 1) { 370 371 /* 372 * try to make all leaf block continuous to avoid fragments 373 */ 374 375 Number = min(SizeArray, ((*Extra + (Start & (BLOCK_SIZE/4 - 1))) * 4 / BLOCK_SIZE)); 376 Wanted = 0; 377 DEBUG(DL_BLK, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n", 378 SizeArray, *Extra, Start, Number )); 379 380 for (i=0; i < Number; i++) { 381 if (BlockArray[i] == 0) { 382 Wanted += 1; 383 } 384 } 385 386 i = 0; 387 while (Wanted > 0) { 388 389 Number = Wanted; 390 Status = Ext2ExpandLast( 391 IrpContext, 392 Vcb, 393 Mcb, 394 Base, 395 Layer, 396 NULL, 397 Hint, 398 &Block, 399 &Number 400 ); 401 if (!NT_SUCCESS(Status)) { 402 goto errorout; 403 } 404 405 ASSERT(Number > 0); 406 Wanted -= Number; 407 while (Number) { 408 if (BlockArray[i] == 0) { 409 BlockArray[i] = Block++; 410 Number--; 411 } 412 i++; 413 } 414 } 415 416 } else if (Layer == 0) { 417 418 /* 419 * bulk allocation for inode data blocks 420 */ 421 422 i = 0; 423 424 while (*Extra && i < SizeArray) { 425 426 Wanted = 0; 427 Number = 1; 428 429 for (j = i; j < SizeArray && j < i + *Extra; j++) { 430 431 if (BlockArray[j] >= TOTAL_BLOCKS) { 432 DbgBreak(); 433 BlockArray[j] = 0; 434 } 435 436 if (BlockArray[j] == 0) { 437 Wanted += 1; 438 } else { 439 break; 440 } 441 } 442 443 if (Wanted == 0) { 444 445 /* add block extent into Mcb */ 446 ASSERT(BlockArray[i] != 0); 447 if (!Ext2AddBlockExtent(Vcb, Mcb, Base + i, BlockArray[i], 1)) { 448 DbgBreak(); 449 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 450 Ext2ClearAllExtents(&Mcb->Extents); 451 } 452 453 } else { 454 455 Number = Wanted; 456 Status = Ext2ExpandLast( 457 IrpContext, 458 Vcb, 459 Mcb, 460 Base + i, 461 0, 462 NULL, 463 Hint, 464 &Block, 465 &Number 466 ); 467 if (!NT_SUCCESS(Status)) { 468 goto errorout; 469 } 470 471 ASSERT(Number > 0); 472 for (j = 0; j < Number; j++) { 473 BlockArray[i + j] = Block++; 474 } 475 } 476 477 *Extra -= Number; 478 i += Number; 479 } 480 481 goto errorout; 482 } 483 484 485 /* 486 * only for meta blocks allocation 487 */ 488 489 for (i = 0; *Extra && i < SizeArray; i++) { 490 491 if (Layer <= 3) { 492 493 if (BlockArray[i] >= TOTAL_BLOCKS) { 494 DbgBreak(); 495 BlockArray[i] = 0; 496 } 497 498 if (BlockArray[i] == 0) { 499 Number = 1; 500 Status = Ext2ExpandLast( 501 IrpContext, 502 Vcb, 503 Mcb, 504 Base, 505 Layer, 506 &pData, 507 Hint, 508 &BlockArray[i], 509 &Number 510 ); 511 if (!NT_SUCCESS(Status)) { 512 goto errorout; 513 } 514 515 } else { 516 517 Offset.QuadPart = (((LONGLONG)BlockArray[i]) << BLOCK_BITS); 518 if (!CcPinRead( 519 Vcb->Volume, 520 &Offset, 521 BLOCK_SIZE, 522 PIN_WAIT, 523 &Bcb, 524 (void **)&pData )) { 525 526 DEBUG(DL_ERR, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n", 527 Offset.QuadPart)); 528 Status = STATUS_CANT_WAIT; 529 DbgBreak(); 530 goto errorout; 531 } 532 533 /* add block to meta extents */ 534 if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1)) { 535 DbgBreak(); 536 Ext2Sleep(500); 537 Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1); 538 } 539 } 540 541 Skip = Vcb->max_blocks_per_layer[Layer] * i; 542 543 if (i == 0) { 544 if (Layer > 1) { 545 Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; 546 Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; 547 Skip += Slot * Vcb->max_blocks_per_layer[Layer - 1]; 548 } else { 549 Slot = Start; 550 Start = 0; 551 Skip += Slot; 552 } 553 } else { 554 Start = 0; 555 Slot = 0; 556 } 557 558 Status = Ext2ExpandBlock( 559 IrpContext, 560 Vcb, 561 Mcb, 562 Base + Skip, 563 Layer - 1, 564 Start, 565 BLOCK_SIZE/4 - Slot, 566 &pData[Slot], 567 Hint, 568 Extra 569 ); 570 571 if (Bcb) { 572 CcSetDirtyPinnedData(Bcb, NULL); 573 if (!Ext2AddBlockExtent(Vcb, NULL, 574 BlockArray[i], 575 BlockArray[i], 1)) { 576 DbgBreak(); 577 Ext2Sleep(500); 578 if (!Ext2AddBlockExtent(Vcb, NULL, 579 BlockArray[i], 580 BlockArray[i], 1)) { 581 } 582 } 583 } else { 584 Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData); 585 } 586 587 if (pData) { 588 if (Bcb) { 589 CcUnpinData(Bcb); 590 Bcb = NULL; 591 } else { 592 Ext2FreePool(pData, EXT2_DATA_MAGIC); 593 DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); 594 } 595 pData = NULL; 596 } 597 598 if (!NT_SUCCESS(Status)) { 599 DbgBreak(); 600 break; 601 } 602 } 603 } 604 605 errorout: 606 607 return Status; 608 } 609 610 BOOLEAN 611 Ext2IsBlockEmpty(PULONG BlockArray, ULONG SizeArray) 612 { 613 ULONG i = 0; 614 for (i=0; i < SizeArray; i++) { 615 if (BlockArray[i]) { 616 break; 617 } 618 } 619 return (i == SizeArray); 620 } 621 622 623 NTSTATUS 624 Ext2TruncateBlock( 625 IN PEXT2_IRP_CONTEXT IrpContext, 626 IN PEXT2_VCB Vcb, 627 IN PEXT2_MCB Mcb, 628 IN ULONG Base, 629 IN ULONG Start, 630 IN ULONG Layer, 631 IN ULONG SizeArray, 632 IN PULONG BlockArray, 633 IN PULONG Extra 634 ) 635 { 636 NTSTATUS Status = STATUS_SUCCESS; 637 ULONG i = 0; 638 ULONG Slot = 0; 639 ULONG Skip = 0; 640 641 LONGLONG Offset; 642 PBCB Bcb = NULL; 643 PULONG pData = NULL; 644 645 ASSERT(Mcb != NULL); 646 647 for (i = 0; i < SizeArray; i++) { 648 649 if (Layer == 0) { 650 651 ULONG Number = 1; 652 653 while (Extra && SizeArray > i + 1 && Number < *Extra) { 654 655 if (BlockArray[SizeArray - i - 1] == 656 BlockArray[SizeArray - i - 2] + 1) { 657 658 BlockArray[SizeArray - i - 1] = 0; 659 Number++; 660 SizeArray--; 661 662 } else { 663 break; 664 } 665 } 666 667 if (BlockArray[SizeArray - i - 1]) { 668 669 Status = Ext2FreeBlock(IrpContext, Vcb, BlockArray[SizeArray - i - 1], Number); 670 if (NT_SUCCESS(Status)) { 671 ASSERT(Mcb->Inode.i_blocks >= (Number << (BLOCK_BITS - 9))); 672 if (Mcb->Inode.i_blocks < (Number << (BLOCK_BITS - 9))) { 673 Mcb->Inode.i_blocks = 0; 674 DbgBreak(); 675 } else { 676 Mcb->Inode.i_blocks -= (Number << (BLOCK_BITS - 9)); 677 } 678 BlockArray[SizeArray - i - 1] = 0; 679 } 680 } 681 682 if (Extra) { 683 684 /* dec blocks count */ 685 ASSERT(*Extra >= Number); 686 *Extra = *Extra - Number; 687 688 /* remove block mapping frm Mcb Extents */ 689 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + SizeArray - 1 - i, Number)) { 690 DbgBreak(); 691 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 692 Ext2ClearAllExtents(&Mcb->Extents); 693 } 694 } 695 696 } else { 697 698 ASSERT(Layer <= 3); 699 700 if (BlockArray[SizeArray - i - 1] >= TOTAL_BLOCKS) { 701 DbgBreak(); 702 BlockArray[SizeArray - i - 1] = 0; 703 } 704 705 if (i == 0) { 706 if (Layer > 1) { 707 Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; 708 Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; 709 } else { 710 Slot = Start; 711 Start = (BLOCK_SIZE / 4) - 1; 712 } 713 } else { 714 Slot = Start = (BLOCK_SIZE / 4) - 1; 715 } 716 717 Skip = (SizeArray - i - 1) * Vcb->max_blocks_per_layer[Layer]; 718 719 if (BlockArray[SizeArray - i - 1]) { 720 721 Offset = (LONGLONG) (BlockArray[SizeArray - i - 1]); 722 Offset = Offset << BLOCK_BITS; 723 724 if (!CcPinRead( Vcb->Volume, 725 (PLARGE_INTEGER) (&Offset), 726 BLOCK_SIZE, 727 PIN_WAIT, 728 &Bcb, 729 (void **)&pData )) { 730 731 DEBUG(DL_ERR, ( "Ext2TruncateBlock: PinLock failed on block %xh ...\n", 732 BlockArray[SizeArray - i - 1])); 733 Status = STATUS_CANT_WAIT; 734 DbgBreak(); 735 goto errorout; 736 } 737 738 Status = Ext2TruncateBlock( 739 IrpContext, 740 Vcb, 741 Mcb, 742 Base + Skip, 743 Start, 744 Layer - 1, 745 Slot + 1, 746 &pData[0], 747 Extra 748 ); 749 750 if (!NT_SUCCESS(Status)) { 751 break; 752 } 753 754 CcSetDirtyPinnedData(Bcb, NULL); 755 Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)BLOCK_SIZE); 756 757 if (*Extra || Ext2IsBlockEmpty(pData, BLOCK_SIZE/4)) { 758 759 Ext2TruncateBlock( 760 IrpContext, 761 Vcb, 762 Mcb, 763 Base + Skip, /* base */ 764 0, /* start */ 765 0, /* layer */ 766 1, 767 &BlockArray[SizeArray - i - 1], 768 NULL 769 ); 770 771 if (!Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1)) { 772 DbgBreak(); 773 Ext2Sleep(500); 774 Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1); 775 } 776 } 777 778 if (pData) { 779 CcUnpinData(Bcb); 780 Bcb = NULL; 781 pData = NULL; 782 } 783 784 } else { 785 786 if (Layer > 1) { 787 if (*Extra > Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1) { 788 *Extra -= (Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1); 789 } else { 790 *Extra = 0; 791 } 792 } else { 793 if (*Extra > Slot + 1) { 794 *Extra -= (Slot + 1); 795 } else { 796 *Extra = 0; 797 } 798 } 799 800 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + Skip, (Start + 1))) { 801 DbgBreak(); 802 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 803 Ext2ClearAllExtents(&Mcb->Extents); 804 } 805 } 806 } 807 808 if (Extra && *Extra == 0) { 809 break; 810 } 811 } 812 813 errorout: 814 815 if (pData) { 816 CcUnpinData(Bcb); 817 } 818 819 return Status; 820 } 821 822 NTSTATUS 823 Ext2MapIndirect( 824 IN PEXT2_IRP_CONTEXT IrpContext, 825 IN PEXT2_VCB Vcb, 826 IN PEXT2_MCB Mcb, 827 IN ULONG Index, 828 IN BOOLEAN bAlloc, 829 OUT PULONG pBlock, 830 OUT PULONG Number 831 ) 832 { 833 ULONG Layer; 834 ULONG Slot; 835 836 ULONG Base = Index; 837 838 NTSTATUS Status = STATUS_SUCCESS; 839 840 *pBlock = 0; 841 *Number = 0; 842 843 for (Layer = 0; Layer < EXT2_BLOCK_TYPES; Layer++) { 844 845 if (Index < Vcb->max_blocks_per_layer[Layer]) { 846 847 ULONG dwRet = 0, dwBlk = 0, dwHint = 0, dwArray = 0; 848 849 Slot = (Layer==0) ? (Index):(Layer + EXT2_NDIR_BLOCKS - 1); 850 dwBlk = Mcb->Inode.i_block[Slot]; 851 852 if (dwBlk == 0) { 853 854 if (!bAlloc) { 855 856 *Number = 1; 857 goto errorout; 858 859 } else { 860 861 if (Slot) { 862 dwHint = Mcb->Inode.i_block[Slot - 1]; 863 } 864 865 /* allocate and zero block if necessary */ 866 *Number = 1; 867 Status = Ext2ExpandLast( 868 IrpContext, 869 Vcb, 870 Mcb, 871 Base, 872 Layer, 873 NULL, 874 &dwHint, 875 &dwBlk, 876 Number 877 ); 878 879 if (!NT_SUCCESS(Status)) { 880 goto errorout; 881 } 882 883 /* save the it into inode*/ 884 Mcb->Inode.i_block[Slot] = dwBlk; 885 886 /* save the inode */ 887 if (!Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode)) { 888 DbgBreak(); 889 Status = STATUS_UNSUCCESSFUL; 890 goto errorout; 891 } 892 } 893 } 894 895 if (Layer == 0) 896 dwArray = Vcb->max_blocks_per_layer[Layer] - Index; 897 else 898 dwArray = 1; 899 900 /* querying block number of the index-th file block */ 901 Status = Ext2GetBlock( 902 IrpContext, 903 Vcb, 904 Mcb, 905 Base, 906 Layer, 907 Index, 908 dwArray, 909 (PULONG)&Mcb->Inode.i_block[Slot], 910 bAlloc, 911 &dwHint, 912 &dwRet, 913 Number 914 ); 915 916 if (NT_SUCCESS(Status)) { 917 *pBlock = dwRet; 918 } 919 920 break; 921 } 922 923 Index -= Vcb->max_blocks_per_layer[Layer]; 924 } 925 926 errorout: 927 928 return Status; 929 } 930 931 NTSTATUS 932 Ext2ExpandIndirect( 933 PEXT2_IRP_CONTEXT IrpContext, 934 PEXT2_VCB Vcb, 935 PEXT2_MCB Mcb, 936 ULONG Start, 937 ULONG End, 938 PLARGE_INTEGER Size 939 ) 940 { 941 NTSTATUS Status = STATUS_SUCCESS; 942 943 ULONG Layer = 0; 944 ULONG Extra = 0; 945 ULONG Hint = 0; 946 ULONG Slot = 0; 947 ULONG Base = 0; 948 949 Extra = End - Start; 950 951 /* exceeds the biggest file size (indirect) */ 952 if (End > Vcb->max_data_blocks) { 953 return STATUS_INVALID_PARAMETER; 954 } 955 956 for (Layer = 0; Layer < EXT2_BLOCK_TYPES && Extra; Layer++) { 957 958 if (Start >= Vcb->max_blocks_per_layer[Layer]) { 959 960 Base += Vcb->max_blocks_per_layer[Layer]; 961 Start -= Vcb->max_blocks_per_layer[Layer]; 962 963 } else { 964 965 /* get the slot in i_block array */ 966 if (Layer == 0) { 967 Base = Slot = Start; 968 } else { 969 Slot = Layer + EXT2_NDIR_BLOCKS - 1; 970 } 971 972 /* set block hint to avoid fragments */ 973 if (Hint == 0) { 974 if (Mcb->Inode.i_block[Slot] != 0) { 975 Hint = Mcb->Inode.i_block[Slot]; 976 } else if (Slot > 1) { 977 Hint = Mcb->Inode.i_block[Slot-1]; 978 } 979 } 980 981 /* now expand this slot */ 982 Status = Ext2ExpandBlock( 983 IrpContext, 984 Vcb, 985 Mcb, 986 Base, 987 Layer, 988 Start, 989 (Layer == 0) ? (Vcb->max_blocks_per_layer[Layer] - Start) : 1, 990 (PULONG)&Mcb->Inode.i_block[Slot], 991 &Hint, 992 &Extra 993 ); 994 if (!NT_SUCCESS(Status)) { 995 break; 996 } 997 998 Start = 0; 999 if (Layer == 0) { 1000 Base = 0; 1001 } 1002 Base += Vcb->max_blocks_per_layer[Layer]; 1003 } 1004 } 1005 1006 Size->QuadPart = ((LONGLONG)(End - Extra)) << BLOCK_BITS; 1007 1008 /* save inode whatever it succeeds to expand or not */ 1009 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1010 1011 return Status; 1012 } 1013 1014 NTSTATUS 1015 Ext2TruncateIndirectFast( 1016 PEXT2_IRP_CONTEXT IrpContext, 1017 PEXT2_VCB Vcb, 1018 PEXT2_MCB Mcb 1019 ) 1020 { 1021 LONGLONG Vba; 1022 LONGLONG Lba; 1023 LONGLONG Length; 1024 NTSTATUS Status = STATUS_SUCCESS; 1025 int i; 1026 1027 /* try to load all indirect blocks if mcb zone is not initialized */ 1028 if (!IsZoneInited(Mcb)) { 1029 Status = Ext2InitializeZone(IrpContext, Vcb, Mcb); 1030 if (!NT_SUCCESS(Status)) { 1031 DbgBreak(); 1032 ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED); 1033 goto errorout; 1034 } 1035 } 1036 1037 ASSERT (IsZoneInited(Mcb)); 1038 1039 /* delete all data blocks here */ 1040 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents) != 0) { 1041 for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->Extents, i, &Vba, &Lba, &Length); i++) { 1042 /* ignore the non-existing runs */ 1043 if (-1 == Lba || Vba == 0 || Length <= 0) 1044 continue; 1045 /* now do data block free */ 1046 Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); 1047 } 1048 } 1049 1050 /* delete all meta blocks here */ 1051 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts) != 0) { 1052 for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->MetaExts, i, &Vba, &Lba, &Length); i++) { 1053 /* ignore the non-existing runs */ 1054 if (-1 == Lba || Vba == 0 || Length <= 0) 1055 continue; 1056 /* now do meta block free */ 1057 Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); 1058 } 1059 } 1060 1061 /* clear data and meta extents */ 1062 Ext2ClearAllExtents(&Mcb->Extents); 1063 Ext2ClearAllExtents(&Mcb->MetaExts); 1064 ClearFlag(Mcb->Flags, MCB_ZONE_INITED); 1065 1066 /* clear inode blocks & sizes */ 1067 Mcb->Inode.i_blocks = 0; 1068 Mcb->Inode.i_size = 0; 1069 memset(&Mcb->Inode.i_block[0], 0, sizeof(__u32) * 15); 1070 1071 /* the caller will do inode save */ 1072 1073 errorout: 1074 1075 return Status; 1076 } 1077 1078 NTSTATUS 1079 Ext2TruncateIndirect( 1080 PEXT2_IRP_CONTEXT IrpContext, 1081 PEXT2_VCB Vcb, 1082 PEXT2_MCB Mcb, 1083 PLARGE_INTEGER Size 1084 ) 1085 { 1086 NTSTATUS Status = STATUS_SUCCESS; 1087 1088 ULONG Layer = 0; 1089 1090 ULONG Extra = 0; 1091 ULONG Wanted = 0; 1092 ULONG End; 1093 ULONG Base; 1094 1095 ULONG SizeArray = 0; 1096 PULONG BlockArray = NULL; 1097 1098 /* translate file size to block */ 1099 End = Base = Vcb->max_data_blocks; 1100 Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS); 1101 1102 /* do fast deletion here */ 1103 if (Wanted == 0) { 1104 Status = Ext2TruncateIndirectFast(IrpContext, Vcb, Mcb); 1105 if (NT_SUCCESS(Status)) 1106 goto errorout; 1107 } 1108 1109 /* calculate blocks to be freed */ 1110 Extra = End - Wanted; 1111 1112 for (Layer = EXT2_BLOCK_TYPES; Layer > 0 && Extra; Layer--) { 1113 1114 if (Vcb->max_blocks_per_layer[Layer - 1] == 0) { 1115 continue; 1116 } 1117 1118 Base -= Vcb->max_blocks_per_layer[Layer - 1]; 1119 1120 if (Layer - 1 == 0) { 1121 BlockArray = (PULONG)&Mcb->Inode.i_block[0]; 1122 SizeArray = End; 1123 ASSERT(End == EXT2_NDIR_BLOCKS && Base == 0); 1124 } else { 1125 BlockArray = (PULONG)&Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1]; 1126 SizeArray = 1; 1127 } 1128 1129 Status = Ext2TruncateBlock( 1130 IrpContext, 1131 Vcb, 1132 Mcb, 1133 Base, 1134 End - Base - 1, 1135 Layer - 1, 1136 SizeArray, 1137 BlockArray, 1138 &Extra 1139 ); 1140 if (!NT_SUCCESS(Status)) { 1141 break; 1142 } 1143 1144 End = Base; 1145 } 1146 1147 errorout: 1148 1149 if (!NT_SUCCESS(Status)) { 1150 Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS); 1151 } 1152 1153 /* save inode */ 1154 if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart)) 1155 Mcb->Inode.i_size = (loff_t)(Size->QuadPart); 1156 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1157 1158 return Status; 1159 } 1160