1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: extents.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
Ext2MapExtent(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Index,IN BOOLEAN Alloc,OUT PULONG Block,OUT PULONG Number)25 Ext2MapExtent(
26 IN PEXT2_IRP_CONTEXT IrpContext,
27 IN PEXT2_VCB Vcb,
28 IN PEXT2_MCB Mcb,
29 IN ULONG Index,
30 IN BOOLEAN Alloc,
31 OUT PULONG Block,
32 OUT PULONG Number
33 )
34 {
35 EXT4_EXTENT_HEADER *eh;
36 struct buffer_head bh_got = {0};
37 int flags, rc;
38 ULONG max_blocks = 0;
39
40 memset(&bh_got, 0, sizeof(struct buffer_head));
41 eh = get_ext4_header(&Mcb->Inode);
42
43 if (eh->eh_magic != EXT4_EXT_MAGIC) {
44 if (Alloc) {
45 /* now initialize inode extent root node */
46 ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
47 } else {
48 /* return empty-mapping when inode extent isn't initialized */
49 if (Block)
50 *Block = 0;
51 if (Number) {
52 LONGLONG _len = _len = Mcb->Inode.i_size;
53 if (Mcb->Fcb)
54 _len = Mcb->Fcb->Header.AllocationSize.QuadPart;
55 *Number = (ULONG)((_len + BLOCK_SIZE - 1) >> BLOCK_BITS);
56 }
57 return STATUS_SUCCESS;
58 }
59 }
60
61 /* IrpContext is NULL when called during journal initialization */
62 if (IsMcbDirectory(Mcb) || IrpContext == NULL ||
63 IrpContext->MajorFunction == IRP_MJ_WRITE || !Alloc){
64 flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
65 max_blocks = EXT_INIT_MAX_LEN;
66 } else {
67 flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
68 max_blocks = EXT_UNWRITTEN_MAX_LEN;
69 }
70
71 if (Alloc) {
72 if (Number && !*Number) {
73 if (max_blocks > *Number) {
74 max_blocks = *Number;
75 }
76 } else {
77 max_blocks = 1;
78 }
79 }
80
81 if ((rc = ext4_ext_get_blocks(
82 IrpContext,
83 NULL,
84 &Mcb->Inode,
85 Index,
86 max_blocks,
87 &bh_got,
88 Alloc,
89 flags)) < 0) {
90 DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc));
91 return Ext2WinntError(rc);
92 }
93 if (Alloc)
94 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
95 if (Number)
96 *Number = rc ? rc : 1;
97 if (Block)
98 *Block = (ULONG)bh_got.b_blocknr;
99
100 return STATUS_SUCCESS;
101 }
102
103
104 NTSTATUS
Ext2DoExtentExpand(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Index,IN OUT PULONG Block,IN OUT PULONG Number)105 Ext2DoExtentExpand(
106 IN PEXT2_IRP_CONTEXT IrpContext,
107 IN PEXT2_VCB Vcb,
108 IN PEXT2_MCB Mcb,
109 IN ULONG Index,
110 IN OUT PULONG Block,
111 IN OUT PULONG Number
112 )
113 {
114 EXT4_EXTENT_HEADER *eh;
115 struct buffer_head bh_got;
116 int rc, flags;
117
118 if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) {
119 flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
120 } else {
121 flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
122 }
123
124 memset(&bh_got, 0, sizeof(struct buffer_head));
125 eh = get_ext4_header(&Mcb->Inode);
126
127 if (eh->eh_magic != EXT4_EXT_MAGIC) {
128 ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
129 }
130
131 if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index,
132 *Number, &bh_got, 1, flags)) < 0) {
133 DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u,"
134 " err: %d\n", *Number, rc));
135 DbgBreak();
136 return Ext2WinntError(rc);
137 }
138
139 if (Number)
140 *Number = rc ? rc : 1;
141 if (Block)
142 *Block = (ULONG)bh_got.b_blocknr;
143
144 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
145
146 return STATUS_SUCCESS;
147 }
148
149
150 NTSTATUS
Ext2ExpandExtent(PEXT2_IRP_CONTEXT IrpContext,PEXT2_VCB Vcb,PEXT2_MCB Mcb,ULONG Start,ULONG End,PLARGE_INTEGER Size)151 Ext2ExpandExtent(
152 PEXT2_IRP_CONTEXT IrpContext,
153 PEXT2_VCB Vcb,
154 PEXT2_MCB Mcb,
155 ULONG Start,
156 ULONG End,
157 PLARGE_INTEGER Size
158 )
159 {
160 ULONG Count = 0, Number = 0, Block = 0;
161 NTSTATUS Status = STATUS_SUCCESS;
162
163 if (End <= Start)
164 return Status;
165
166 while (End > Start + Count) {
167
168 Number = End - Start - Count;
169 Status = Ext2DoExtentExpand(IrpContext, Vcb, Mcb, Start + Count,
170 &Block, &Number);
171 if (!NT_SUCCESS(Status)) {
172 Status = STATUS_INSUFFICIENT_RESOURCES;
173 break;
174 }
175 if (Number == 0) {
176 Status = STATUS_INSUFFICIENT_RESOURCES;
177 break;
178 }
179
180 if (Block && IsZoneInited(Mcb)) {
181 if (!Ext2AddBlockExtent(Vcb, Mcb, Start + Count, Block, Number)) {
182 DbgBreak();
183 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
184 Ext2ClearAllExtents(&Mcb->Extents);
185 }
186 }
187 Count += Number;
188 }
189
190 Size->QuadPart = ((LONGLONG)(Start + Count)) << BLOCK_BITS;
191
192 /* save inode whatever it succeeds to expand or not */
193 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
194
195 return Status;
196 }
197
198
199 NTSTATUS
Ext2TruncateExtent(PEXT2_IRP_CONTEXT IrpContext,PEXT2_VCB Vcb,PEXT2_MCB Mcb,PLARGE_INTEGER Size)200 Ext2TruncateExtent(
201 PEXT2_IRP_CONTEXT IrpContext,
202 PEXT2_VCB Vcb,
203 PEXT2_MCB Mcb,
204 PLARGE_INTEGER Size
205 )
206 {
207 NTSTATUS Status = STATUS_SUCCESS;
208
209 ULONG Extra = 0;
210 ULONG Wanted = 0;
211 ULONG End;
212 ULONG Removed;
213 int err;
214
215 /* translate file size to block */
216 End = Vcb->max_data_blocks;
217 Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
218
219 /* calculate blocks to be freed */
220 Extra = End - Wanted;
221
222 err = ext4_ext_truncate(IrpContext, &Mcb->Inode, Wanted);
223 if (err == 0) {
224 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
225 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
226 Ext2ClearAllExtents(&Mcb->Extents);
227 }
228 Extra = 0;
229 } else {
230 Status = STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 if (!NT_SUCCESS(Status)) {
234 Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
235 }
236
237 if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
238 Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
239
240 /* Save modifications on i_blocks field and i_size field of the inode. */
241 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
242
243 return Status;
244 }
245