[PSDK]
[reactos.git] / reactos / drivers / filesystems / ext2_new / src / ext4 / extents.c
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
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;
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 ((rc = ext4_ext_get_blocks(
72 IrpContext,
73 NULL,
74 &Mcb->Inode,
75 Index,
76 max_blocks,
77 &bh_got,
78 Alloc,
79 flags)) < 0) {
80 DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc));
81 return Ext2WinntError(rc);
82 }
83 if (Alloc)
84 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
85 if (Number)
86 *Number = rc ? rc : 1;
87 if (Block)
88 *Block = (ULONG)bh_got.b_blocknr;
89
90 return STATUS_SUCCESS;
91 }
92
93
94 NTSTATUS
95 Ext2DoExtentExpand(
96 IN PEXT2_IRP_CONTEXT IrpContext,
97 IN PEXT2_VCB Vcb,
98 IN PEXT2_MCB Mcb,
99 IN ULONG Index,
100 IN OUT PULONG Block,
101 IN OUT PULONG Number
102 )
103 {
104 EXT4_EXTENT_HEADER *eh;
105 struct buffer_head bh_got;
106 int rc, flags;
107
108 if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) {
109 flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
110 } else {
111 flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
112 }
113
114 memset(&bh_got, 0, sizeof(struct buffer_head));
115 eh = get_ext4_header(&Mcb->Inode);
116
117 if (eh->eh_magic != EXT4_EXT_MAGIC) {
118 ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
119 }
120
121 if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index,
122 *Number, &bh_got, 1, flags)) < 0) {
123 DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u,"
124 " err: %d\n", *Number, rc));
125 DbgBreak();
126 return Ext2WinntError(rc);
127 }
128
129 if (Number)
130 *Number = rc ? rc : 1;
131 if (Block)
132 *Block = (ULONG)bh_got.b_blocknr;
133
134 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
135
136 return STATUS_SUCCESS;
137 }
138
139
140 NTSTATUS
141 Ext2ExpandExtent(
142 PEXT2_IRP_CONTEXT IrpContext,
143 PEXT2_VCB Vcb,
144 PEXT2_MCB Mcb,
145 ULONG Start,
146 ULONG End,
147 PLARGE_INTEGER Size
148 )
149 {
150 ULONG Count = 0, Number = 0, Block = 0;
151 NTSTATUS Status = STATUS_SUCCESS;
152
153 if (End <= Start)
154 return Status;
155
156 while (End > Start + Count) {
157
158 Number = End - Start - Count;
159 Status = Ext2DoExtentExpand(IrpContext, Vcb, Mcb, Start + Count,
160 &Block, &Number);
161 if (!NT_SUCCESS(Status)) {
162 Status = STATUS_INSUFFICIENT_RESOURCES;
163 break;
164 }
165 if (Number == 0) {
166 Status = STATUS_INSUFFICIENT_RESOURCES;
167 break;
168 }
169
170 if (Block && IsZoneInited(Mcb)) {
171 if (!Ext2AddBlockExtent(Vcb, Mcb, Start + Count, Block, Number)) {
172 DbgBreak();
173 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
174 Ext2ClearAllExtents(&Mcb->Extents);
175 }
176 }
177 Count += Number;
178 }
179
180 Size->QuadPart = ((LONGLONG)(Start + Count)) << BLOCK_BITS;
181
182 /* save inode whatever it succeeds to expand or not */
183 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
184
185 return Status;
186 }
187
188
189 NTSTATUS
190 Ext2TruncateExtent(
191 PEXT2_IRP_CONTEXT IrpContext,
192 PEXT2_VCB Vcb,
193 PEXT2_MCB Mcb,
194 PLARGE_INTEGER Size
195 )
196 {
197 NTSTATUS Status = STATUS_SUCCESS;
198
199 ULONG Extra = 0;
200 ULONG Wanted = 0;
201 ULONG End;
202 ULONG Removed;
203 int err;
204
205 /* translate file size to block */
206 End = Vcb->max_data_blocks;
207 Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
208
209 /* calculate blocks to be freed */
210 Extra = End - Wanted;
211
212 err = ext4_ext_remove_space(IrpContext, &Mcb->Inode, Wanted);
213 if (err == 0) {
214 if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
215 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
216 Ext2ClearAllExtents(&Mcb->Extents);
217 }
218 Extra = 0;
219 } else {
220 Status = STATUS_INSUFFICIENT_RESOURCES;
221 }
222
223 if (!NT_SUCCESS(Status)) {
224 Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
225 }
226
227 /* save inode */
228 if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
229 Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
230 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
231
232 return Status;
233 }