2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS *****************************************************************/
16 extern PEXT2_GLOBAL Ext2Global
;
18 /* DEFINITIONS *************************************************************/
26 IN PEXT2_IRP_CONTEXT IrpContext
,
39 NTSTATUS Status
= STATUS_SUCCESS
;
41 if (Layer
> 0 || IsMcbDirectory(Mcb
)) {
43 /* allocate buffer for new block */
44 pData
= (ULONG
*) Ext2AllocatePool(
50 DEBUG(DL_ERR
, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n"));
51 Status
= STATUS_INSUFFICIENT_RESOURCES
;
54 RtlZeroMemory(pData
, BLOCK_SIZE
);
55 INC_MEM_COUNT(PS_BLOCK_DATA
, pData
, BLOCK_SIZE
);
58 /* allocate block from disk */
59 Status
= Ext2NewBlock(
62 (Mcb
->Inode
.i_ino
- 1) / BLOCKS_PER_GROUP
,
68 if (!NT_SUCCESS(Status
)) {
72 /* increase inode i_blocks */
73 Mcb
->Inode
.i_blocks
+= (*Number
<< (BLOCK_BITS
- 9));
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
);
83 Ext2SaveBlock(IrpContext
, Vcb
, *Block
, (PVOID
)pData
);
86 /* add new Extent into Mcb */
87 if (!Ext2AddBlockExtent(Vcb
, Mcb
, Base
, (*Block
), *Number
)) {
89 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
90 Ext2ClearAllExtents(&Mcb
->Extents
);
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)) {
102 Ext2AddMcbMetaExts(Vcb
, Mcb
, *Block
+ i
, 1);
109 if (NT_SUCCESS(Status
)) {
110 *Hint
= *Block
+ *Number
;
113 ASSERT(*Number
== 1);
116 Ext2FreePool(pData
, EXT2_DATA_MAGIC
);
117 DEC_MEM_COUNT(PS_BLOCK_DATA
, pData
, BLOCK_SIZE
);
122 Ext2FreePool(pData
, EXT2_DATA_MAGIC
);
123 DEC_MEM_COUNT(PS_BLOCK_DATA
, pData
, BLOCK_SIZE
);
126 Ext2FreeBlock(IrpContext
, Vcb
, *Block
, *Number
);
127 Mcb
->Inode
.i_blocks
-= (*Number
<< (BLOCK_BITS
- 9));
137 IN PEXT2_IRP_CONTEXT IrpContext
,
144 IN PULONG BlockArray
,
151 NTSTATUS Status
= STATUS_SUCCESS
;
154 ULONG Slot
= 0, i
= 0;
157 LARGE_INTEGER Offset
;
162 if (BlockArray
[0] == 0 && bAlloc
) {
164 /* now allocate new block */
165 Status
= Ext2ExpandLast(
177 if (!NT_SUCCESS(Status
)) {
181 /* check the block is valid or not */
182 if (BlockArray
[0] >= TOTAL_BLOCKS
) {
184 Status
= STATUS_DISK_CORRUPT_ERROR
;
189 *Block
= BlockArray
[0];
190 for (i
=1; i
< SizeArray
; i
++) {
191 if (BlockArray
[i
] == BlockArray
[i
-1] + 1) {
192 *Number
= *Number
+ 1;
197 *Hint
= BlockArray
[*Number
- 1];
199 } else if (Layer
<= 3) {
201 /* check the block is valid or not */
202 if (BlockArray
[0] == 0 || BlockArray
[0] >= TOTAL_BLOCKS
) {
204 Status
= STATUS_DISK_CORRUPT_ERROR
;
208 /* add block to meta extents */
209 if (!Ext2AddMcbMetaExts(Vcb
, Mcb
, BlockArray
[0], 1)) {
212 Ext2AddMcbMetaExts(Vcb
, Mcb
, BlockArray
[0], 1);
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
),
224 DEBUG(DL_ERR
, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n",
226 Status
= STATUS_CANT_WAIT
;
231 Unit
= Vcb
->max_blocks_per_layer
[Layer
- 1];
237 Start
= Start
% Unit
;
239 if (pData
[Slot
] == 0) {
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. */
246 Status
= Ext2ExpandLast(
258 if (!NT_SUCCESS(Status
)) {
262 /* refresh hint block */
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
)) {
272 if (!Ext2AddVcbExtent(Vcb
, Offset
.QuadPart
,
273 (LONGLONG
)BLOCK_SIZE
)) {
274 Status
= STATUS_INSUFFICIENT_RESOURCES
;
279 /* save inode information here */
280 Ext2SaveInode(IrpContext
, Vcb
, &Mcb
->Inode
);
287 for (i
= Slot
+ 1; i
< BLOCK_SIZE
/4; i
++) {
289 *Number
= *Number
+ 1;
294 } else if (Layer
== 2) {
295 *Number
= BLOCK_SIZE
/4 - Start
;
297 *Number
= BLOCK_SIZE
/4;
304 /* transfer to next recursion call */
305 Status
= Ext2GetBlock(
320 if (!NT_SUCCESS(Status
)) {
327 /* free the memory of pData */
332 if (!NT_SUCCESS(Status
)) {
342 IN PEXT2_IRP_CONTEXT IrpContext
,
349 IN PULONG BlockArray
,
358 LARGE_INTEGER Offset
;
367 NTSTATUS Status
= STATUS_SUCCESS
;
372 * try to make all leaf block continuous to avoid fragments
375 Number
= min(SizeArray
, ((*Extra
+ (Start
& (BLOCK_SIZE
/4 - 1))) * 4 / BLOCK_SIZE
));
377 DEBUG(DL_BLK
, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n",
378 SizeArray
, *Extra
, Start
, Number
));
380 for (i
=0; i
< Number
; i
++) {
381 if (BlockArray
[i
] == 0) {
390 Status
= Ext2ExpandLast(
401 if (!NT_SUCCESS(Status
)) {
408 if (BlockArray
[i
] == 0) {
409 BlockArray
[i
] = Block
++;
416 } else if (Layer
== 0) {
419 * bulk allocation for inode data blocks
424 while (*Extra
&& i
< SizeArray
) {
429 for (j
= i
; j
< SizeArray
&& j
< i
+ *Extra
; j
++) {
431 if (BlockArray
[j
] >= TOTAL_BLOCKS
) {
436 if (BlockArray
[j
] == 0) {
445 /* add block extent into Mcb */
446 ASSERT(BlockArray
[i
] != 0);
447 if (!Ext2AddBlockExtent(Vcb
, Mcb
, Base
+ i
, BlockArray
[i
], 1)) {
449 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
450 Ext2ClearAllExtents(&Mcb
->Extents
);
456 Status
= Ext2ExpandLast(
467 if (!NT_SUCCESS(Status
)) {
472 for (j
= 0; j
< Number
; j
++) {
473 BlockArray
[i
+ j
] = Block
++;
486 * only for meta blocks allocation
489 for (i
= 0; *Extra
&& i
< SizeArray
; i
++) {
493 if (BlockArray
[i
] >= TOTAL_BLOCKS
) {
498 if (BlockArray
[i
] == 0) {
500 Status
= Ext2ExpandLast(
511 if (!NT_SUCCESS(Status
)) {
517 Offset
.QuadPart
= (((LONGLONG
)BlockArray
[i
]) << BLOCK_BITS
);
526 DEBUG(DL_ERR
, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n",
528 Status
= STATUS_CANT_WAIT
;
533 /* add block to meta extents */
534 if (!Ext2AddMcbMetaExts(Vcb
, Mcb
, BlockArray
[i
], 1)) {
537 Ext2AddMcbMetaExts(Vcb
, Mcb
, BlockArray
[i
], 1);
541 Skip
= Vcb
->max_blocks_per_layer
[Layer
] * i
;
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];
558 Status
= Ext2ExpandBlock(
572 CcSetDirtyPinnedData(Bcb
, NULL
);
573 if (!Ext2AddBlockExtent(Vcb
, NULL
,
578 if (!Ext2AddBlockExtent(Vcb
, NULL
,
584 Ext2SaveBlock(IrpContext
, Vcb
, BlockArray
[i
], (PVOID
)pData
);
592 Ext2FreePool(pData
, EXT2_DATA_MAGIC
);
593 DEC_MEM_COUNT(PS_BLOCK_DATA
, pData
, BLOCK_SIZE
);
598 if (!NT_SUCCESS(Status
)) {
611 Ext2IsBlockEmpty(PULONG BlockArray
, ULONG SizeArray
)
614 for (i
=0; i
< SizeArray
; i
++) {
619 return (i
== SizeArray
);
625 IN PEXT2_IRP_CONTEXT IrpContext
,
632 IN PULONG BlockArray
,
636 NTSTATUS Status
= STATUS_SUCCESS
;
647 for (i
= 0; i
< SizeArray
; i
++) {
653 while (Extra
&& SizeArray
> i
+ 1 && Number
< *Extra
) {
655 if (BlockArray
[SizeArray
- i
- 1] ==
656 BlockArray
[SizeArray
- i
- 2] + 1) {
658 BlockArray
[SizeArray
- i
- 1] = 0;
667 if (BlockArray
[SizeArray
- i
- 1]) {
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;
676 Mcb
->Inode
.i_blocks
-= (Number
<< (BLOCK_BITS
- 9));
678 BlockArray
[SizeArray
- i
- 1] = 0;
684 /* dec blocks count */
685 ASSERT(*Extra
>= Number
);
686 *Extra
= *Extra
- Number
;
688 /* remove block mapping frm Mcb Extents */
689 if (!Ext2RemoveBlockExtent(Vcb
, Mcb
, Base
+ SizeArray
- 1 - i
, Number
)) {
691 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
692 Ext2ClearAllExtents(&Mcb
->Extents
);
700 if (BlockArray
[SizeArray
- i
- 1] >= TOTAL_BLOCKS
) {
702 BlockArray
[SizeArray
- i
- 1] = 0;
707 Slot
= Start
/ Vcb
->max_blocks_per_layer
[Layer
- 1];
708 Start
= Start
% Vcb
->max_blocks_per_layer
[Layer
- 1];
711 Start
= (BLOCK_SIZE
/ 4) - 1;
714 Slot
= Start
= (BLOCK_SIZE
/ 4) - 1;
717 Skip
= (SizeArray
- i
- 1) * Vcb
->max_blocks_per_layer
[Layer
];
719 if (BlockArray
[SizeArray
- i
- 1]) {
721 Offset
= (LONGLONG
) (BlockArray
[SizeArray
- i
- 1]);
722 Offset
= Offset
<< BLOCK_BITS
;
724 if (!CcPinRead( Vcb
->Volume
,
725 (PLARGE_INTEGER
) (&Offset
),
731 DEBUG(DL_ERR
, ( "Ext2TruncateBlock: PinLock failed on block %xh ...\n",
732 BlockArray
[SizeArray
- i
- 1]));
733 Status
= STATUS_CANT_WAIT
;
738 Status
= Ext2TruncateBlock(
750 if (!NT_SUCCESS(Status
)) {
754 CcSetDirtyPinnedData(Bcb
, NULL
);
755 Ext2AddVcbExtent(Vcb
, Offset
, (LONGLONG
)BLOCK_SIZE
);
757 if (*Extra
|| Ext2IsBlockEmpty(pData
, BLOCK_SIZE
/4)) {
763 Base
+ Skip
, /* base */
767 &BlockArray
[SizeArray
- i
- 1],
771 if (!Ext2RemoveMcbMetaExts(Vcb
, Mcb
, BlockArray
[SizeArray
- i
- 1], 1)) {
774 Ext2RemoveMcbMetaExts(Vcb
, Mcb
, BlockArray
[SizeArray
- i
- 1], 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);
793 if (*Extra
> Slot
+ 1) {
794 *Extra
-= (Slot
+ 1);
800 if (!Ext2RemoveBlockExtent(Vcb
, Mcb
, Base
+ Skip
, (Start
+ 1))) {
802 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
803 Ext2ClearAllExtents(&Mcb
->Extents
);
808 if (Extra
&& *Extra
== 0) {
824 IN PEXT2_IRP_CONTEXT IrpContext
,
838 NTSTATUS Status
= STATUS_SUCCESS
;
843 for (Layer
= 0; Layer
< EXT2_BLOCK_TYPES
; Layer
++) {
845 if (Index
< Vcb
->max_blocks_per_layer
[Layer
]) {
847 ULONG dwRet
= 0, dwBlk
= 0, dwHint
= 0, dwArray
= 0;
849 Slot
= (Layer
==0) ? (Index
):(Layer
+ EXT2_NDIR_BLOCKS
- 1);
850 dwBlk
= Mcb
->Inode
.i_block
[Slot
];
862 dwHint
= Mcb
->Inode
.i_block
[Slot
- 1];
865 /* allocate and zero block if necessary */
867 Status
= Ext2ExpandLast(
879 if (!NT_SUCCESS(Status
)) {
883 /* save the it into inode*/
884 Mcb
->Inode
.i_block
[Slot
] = dwBlk
;
887 if (!Ext2SaveInode(IrpContext
, Vcb
, &Mcb
->Inode
)) {
889 Status
= STATUS_UNSUCCESSFUL
;
896 dwArray
= Vcb
->max_blocks_per_layer
[Layer
] - Index
;
900 /* querying block number of the index-th file block */
901 Status
= Ext2GetBlock(
909 (PULONG
)&Mcb
->Inode
.i_block
[Slot
],
916 if (NT_SUCCESS(Status
)) {
923 Index
-= Vcb
->max_blocks_per_layer
[Layer
];
933 PEXT2_IRP_CONTEXT IrpContext
,
941 NTSTATUS Status
= STATUS_SUCCESS
;
951 /* exceeds the biggest file size (indirect) */
952 if (End
> Vcb
->max_data_blocks
) {
953 return STATUS_INVALID_PARAMETER
;
956 for (Layer
= 0; Layer
< EXT2_BLOCK_TYPES
&& Extra
; Layer
++) {
958 if (Start
>= Vcb
->max_blocks_per_layer
[Layer
]) {
960 Base
+= Vcb
->max_blocks_per_layer
[Layer
];
961 Start
-= Vcb
->max_blocks_per_layer
[Layer
];
965 /* get the slot in i_block array */
969 Slot
= Layer
+ EXT2_NDIR_BLOCKS
- 1;
972 /* set block hint to avoid fragments */
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];
981 /* now expand this slot */
982 Status
= Ext2ExpandBlock(
989 (Layer
== 0) ? (Vcb
->max_blocks_per_layer
[Layer
] - Start
) : 1,
990 (PULONG
)&Mcb
->Inode
.i_block
[Slot
],
994 if (!NT_SUCCESS(Status
)) {
1002 Base
+= Vcb
->max_blocks_per_layer
[Layer
];
1006 Size
->QuadPart
= ((LONGLONG
)(End
- Extra
)) << BLOCK_BITS
;
1008 /* save inode whatever it succeeds to expand or not */
1009 Ext2SaveInode(IrpContext
, Vcb
, &Mcb
->Inode
);
1015 Ext2TruncateIndirectFast(
1016 PEXT2_IRP_CONTEXT IrpContext
,
1024 NTSTATUS Status
= STATUS_SUCCESS
;
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
)) {
1032 ClearLongFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1037 ASSERT (IsZoneInited(Mcb
));
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)
1045 /* now do data block free */
1046 Ext2FreeBlock(IrpContext
, Vcb
, (ULONG
)(Lba
- 1), (ULONG
)Length
);
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)
1056 /* now do meta block free */
1057 Ext2FreeBlock(IrpContext
, Vcb
, (ULONG
)(Lba
- 1), (ULONG
)Length
);
1061 /* clear data and meta extents */
1062 Ext2ClearAllExtents(&Mcb
->Extents
);
1063 Ext2ClearAllExtents(&Mcb
->MetaExts
);
1064 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
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);
1071 /* the caller will do inode save */
1079 Ext2TruncateIndirect(
1080 PEXT2_IRP_CONTEXT IrpContext
,
1086 NTSTATUS Status
= STATUS_SUCCESS
;
1095 ULONG SizeArray
= 0;
1096 PULONG BlockArray
= NULL
;
1098 /* translate file size to block */
1099 End
= Base
= Vcb
->max_data_blocks
;
1100 Wanted
= (ULONG
)((Size
->QuadPart
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1102 /* do fast deletion here */
1104 Status
= Ext2TruncateIndirectFast(IrpContext
, Vcb
, Mcb
);
1105 if (NT_SUCCESS(Status
))
1109 /* calculate blocks to be freed */
1110 Extra
= End
- Wanted
;
1112 for (Layer
= EXT2_BLOCK_TYPES
; Layer
> 0 && Extra
; Layer
--) {
1114 if (Vcb
->max_blocks_per_layer
[Layer
- 1] == 0) {
1118 Base
-= Vcb
->max_blocks_per_layer
[Layer
- 1];
1120 if (Layer
- 1 == 0) {
1121 BlockArray
= (PULONG
)&Mcb
->Inode
.i_block
[0];
1123 ASSERT(End
== EXT2_NDIR_BLOCKS
&& Base
== 0);
1125 BlockArray
= (PULONG
)&Mcb
->Inode
.i_block
[EXT2_NDIR_BLOCKS
- 1 + Layer
- 1];
1129 Status
= Ext2TruncateBlock(
1140 if (!NT_SUCCESS(Status
)) {
1149 if (!NT_SUCCESS(Status
)) {
1150 Size
->QuadPart
+= ((ULONGLONG
)Extra
<< BLOCK_BITS
);
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
);