3588752221545d2270907adcc9a0b334045f0708
[reactos.git] / reactos / lib / fslib / ext2lib / Memory.c
1 /*
2 * PROJECT: Mke2fs
3 * FILE: Memory.c
4 * PROGRAMMER: Matt Wu <mattwu@163.com>
5 * HOMEPAGE: http://ext2.yeah.net
6 */
7
8 /* INCLUDES **************************************************************/
9
10 #include "Mke2fs.h"
11 #include <debug.h>
12
13 /* DEFINITIONS ***********************************************************/
14
15 extern char *device_name;
16
17 /* FUNCTIONS *************************************************************/
18
19
20 /*
21 * Return the group # of an inode number
22 */
23 int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino)
24 {
25 return (ino - 1) / fs->ext2_sb->s_inodes_per_group;
26 }
27
28 /*
29 * Return the group # of a block
30 */
31 int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk)
32 {
33 return (blk - fs->ext2_sb->s_first_data_block) /
34 fs->ext2_sb->s_blocks_per_group;
35 }
36
37 void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino,
38 int inuse, int isdir)
39 {
40 int group = ext2_group_of_ino(fs, ino);
41
42 if (inuse > 0)
43 ext2_mark_inode_bitmap(fs->inode_map, ino);
44 else
45 ext2_unmark_inode_bitmap(fs->inode_map, ino);
46
47 fs->group_desc[group].bg_free_inodes_count -= inuse;
48
49 if (isdir)
50 fs->group_desc[group].bg_used_dirs_count += inuse;
51
52 fs->ext2_sb->s_free_inodes_count -= inuse;
53 }
54
55
56 void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse)
57 {
58 ext2_inode_alloc_stats2(fs, ino, inuse, 0);
59 }
60
61 void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse)
62 {
63 int group = ext2_group_of_blk(fs, blk);
64
65 if (inuse > 0)
66 ext2_mark_block_bitmap(fs->block_map, blk);
67 else
68 ext2_unmark_block_bitmap(fs->block_map, blk);
69
70 fs->group_desc[group].bg_free_blocks_count -= inuse;
71 fs->ext2_sb->s_free_blocks_count -= inuse;
72 }
73
74
75 bool ext2_allocate_tables(PEXT2_FILESYS Ext2Sys)
76 {
77 bool retval;
78 ULONG i;
79
80 for (i = 0; i < Ext2Sys->group_desc_count; i++)
81 {
82 retval = ext2_allocate_group_table(Ext2Sys, i, Ext2Sys->block_map);
83
84 if (!retval)
85 return retval;
86 }
87
88 return true;
89 }
90
91
92 bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group,
93 PEXT2_BLOCK_BITMAP bmap)
94 {
95 bool retval;
96 ULONG group_blk, start_blk, last_blk, new_blk, blk;
97 int j;
98
99 group_blk = fs->ext2_sb->s_first_data_block +
100 (group * fs->ext2_sb->s_blocks_per_group);
101
102 last_blk = group_blk + fs->ext2_sb->s_blocks_per_group;
103 if (last_blk >= fs->ext2_sb->s_blocks_count)
104 last_blk = fs->ext2_sb->s_blocks_count - 1;
105
106 start_blk = group_blk + 3 + fs->desc_blocks;
107 if (start_blk > last_blk)
108 start_blk = group_blk;
109
110 if (!bmap)
111 bmap = fs->block_map;
112
113 /*
114 * Allocate the inode table
115 */
116 if (!fs->group_desc[group].bg_inode_table)
117 {
118 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
119 fs->inode_blocks_per_group,
120 bmap, &new_blk);
121 if (!retval)
122 return retval;
123
124 for (j=0, blk = new_blk;
125 j < fs->inode_blocks_per_group;
126 j++, blk++)
127 ext2_mark_block_bitmap(bmap, blk);
128
129 fs->group_desc[group].bg_inode_table = new_blk;
130 }
131
132 /*
133 * Allocate the block and inode bitmaps, if necessary
134 */
135 if (fs->stride)
136 {
137 start_blk += fs->inode_blocks_per_group;
138 start_blk += ((fs->stride * group) %
139 (last_blk - start_blk));
140 if (start_blk > last_blk)
141 /* should never happen */
142 start_blk = group_blk;
143 }
144 else
145 {
146 start_blk = group_blk;
147 }
148
149 if (!fs->group_desc[group].bg_block_bitmap)
150 {
151 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
152 1, bmap, &new_blk);
153
154 if (!retval)
155 retval = ext2_get_free_blocks(fs, group_blk,
156 last_blk, 1, bmap, &new_blk);
157
158 if (!retval)
159 return retval;
160
161 ext2_mark_block_bitmap(bmap, new_blk);
162 fs->group_desc[group].bg_block_bitmap = new_blk;
163 }
164
165 if (!fs->group_desc[group].bg_inode_bitmap)
166 {
167 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
168 1, bmap, &new_blk);
169 if (!retval)
170 retval = ext2_get_free_blocks(fs, group_blk,
171 last_blk, 1, bmap, &new_blk);
172 if (!retval)
173 return retval;
174
175 ext2_mark_block_bitmap(bmap, new_blk);
176 fs->group_desc[group].bg_inode_bitmap = new_blk;
177 }
178
179 return true;
180 }
181
182
183 bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,
184 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret)
185 {
186 ULONG b = start;
187
188 if (!map)
189 map = fs->block_map;
190
191 if (!map)
192 return false;
193
194 if (!b)
195 b = fs->ext2_sb->s_first_data_block;
196
197 if (!finish)
198 finish = start;
199
200 if (!num)
201 num = 1;
202
203 do
204 {
205 if (b+num-1 > fs->ext2_sb->s_blocks_count)
206 b = fs->ext2_sb->s_first_data_block;
207
208 if (ext2_test_block_bitmap_range(map, b, num))
209 {
210 *ret = b;
211 return true;
212 }
213
214 b++;
215
216 } while (b != finish);
217
218 return false;
219 }
220
221
222 bool write_inode_tables(PEXT2_FILESYS fs)
223 {
224 bool retval;
225 ULONG blk, num;
226 int i;
227
228 for (i = 0; (ULONG)i < fs->group_desc_count; i++)
229 {
230 blk = fs->group_desc[i].bg_inode_table;
231 num = fs->inode_blocks_per_group;
232
233 retval = zero_blocks(fs, blk, num, &blk, &num);
234 if (!retval)
235 {
236 DPRINT1("\nMke2fs: Could not write %lu blocks "
237 "in inode table starting at %lu.\n",
238 num, blk);
239
240 zero_blocks(0, 0, 0, 0, 0);
241 return false;
242 }
243 }
244
245 zero_blocks(0, 0, 0, 0, 0);
246
247 return true;
248 }
249
250
251 /*
252 * Stupid algorithm --- we now just search forward starting from the
253 * goal. Should put in a smarter one someday....
254 */
255 bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,
256 PEXT2_BLOCK_BITMAP map, ULONG *ret)
257 {
258 ULONG i;
259
260 if (!map)
261 map = fs->block_map;
262
263 if (!map)
264 return false;
265
266 if (!goal || (goal >= fs->ext2_sb->s_blocks_count))
267 goal = fs->ext2_sb->s_first_data_block;
268
269 i = goal;
270
271 do
272 {
273 if (!ext2_test_block_bitmap(map, i))
274 {
275 *ret = i;
276 return true;
277 }
278
279 i++;
280
281 if (i >= fs->ext2_sb->s_blocks_count)
282 i = fs->ext2_sb->s_first_data_block;
283
284 } while (i != goal);
285
286 return false;
287 }
288
289
290 /*
291 * This function zeros out the allocated block, and updates all of the
292 * appropriate filesystem records.
293 */
294 bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret)
295 {
296 bool retval;
297 ULONG block;
298 char *buf = NULL;
299
300 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
301 if (!buf)
302 return false;
303
304 if (!fs->block_map)
305 {
306 retval = ext2_read_block_bitmap(fs);
307 if (!retval)
308 goto fail;
309 }
310
311 retval = ext2_new_block(fs, goal, 0, &block);
312
313 if (!retval)
314 goto fail;
315
316 retval = NT_SUCCESS(Ext2WriteDisk(
317 fs,
318 ((LONGLONG)block * fs->blocksize),
319 fs->blocksize, (unsigned char *)buf));
320
321 if (!retval)
322 {
323 goto fail;
324 }
325
326 ext2_block_alloc_stats(fs, block, +1);
327 *ret = block;
328
329 if (buf)
330 {
331 RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
332 }
333
334 return true;
335
336 fail:
337
338 if (buf)
339 {
340 RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
341 }
342
343 return false;
344 }
345
346
347 /*
348 * Create new directory block
349 */
350 bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,
351 ULONG parent_ino, char **block)
352 {
353 PEXT2_DIR_ENTRY dir = NULL;
354 char *buf;
355 int rec_len;
356 int filetype = 0;
357
358 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
359 if (!buf)
360 return false;
361
362 dir = (PEXT2_DIR_ENTRY) buf;
363 dir->rec_len = fs->blocksize;
364
365 if (dir_ino)
366 {
367 if (fs->ext2_sb->s_feature_incompat &
368 EXT2_FEATURE_INCOMPAT_FILETYPE)
369 filetype = EXT2_FT_DIR << 8;
370 /*
371 * Set up entry for '.'
372 */
373 dir->inode = dir_ino;
374 dir->name_len = 1 | filetype;
375 dir->name[0] = '.';
376 rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
377 dir->rec_len = EXT2_DIR_REC_LEN(1);
378
379 /*
380 * Set up entry for '..'
381 */
382 dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
383 dir->rec_len = rec_len;
384 dir->inode = parent_ino;
385 dir->name_len = 2 | filetype;
386 dir->name[0] = '.';
387 dir->name[1] = '.';
388 }
389
390 *block = buf;
391
392 return true;
393 }
394
395 bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
396 {
397 bool retval = false;
398
399 retval = NT_SUCCESS(Ext2WriteDisk(
400 fs,
401 ((ULONGLONG)block * fs->blocksize),
402 fs->blocksize, (unsigned char *)inbuf));
403
404 return retval;
405 }
406
407 bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
408 {
409 bool retval = false;
410
411 retval = NT_SUCCESS(Ext2ReadDisk(
412 fs,
413 ((ULONGLONG)block * fs->blocksize),
414 fs->blocksize, (unsigned char *)inbuf));
415
416 return retval;
417 }