[VFATLIB] Never touch the file system if not in interactive or RW mode.
[reactos.git] / sdk / 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, j;
97
98 group_blk = fs->ext2_sb->s_first_data_block +
99 (group * fs->ext2_sb->s_blocks_per_group);
100
101 last_blk = group_blk + fs->ext2_sb->s_blocks_per_group;
102 if (last_blk >= fs->ext2_sb->s_blocks_count)
103 last_blk = fs->ext2_sb->s_blocks_count - 1;
104
105 start_blk = group_blk + 3 + fs->desc_blocks;
106 if (start_blk > last_blk)
107 start_blk = group_blk;
108
109 if (!bmap)
110 bmap = fs->block_map;
111
112 /*
113 * Allocate the inode table
114 */
115 if (!fs->group_desc[group].bg_inode_table)
116 {
117 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
118 fs->inode_blocks_per_group,
119 bmap, &new_blk);
120 if (!retval)
121 return retval;
122
123 for (j=0, blk = new_blk;
124 j < fs->inode_blocks_per_group;
125 j++, blk++)
126 ext2_mark_block_bitmap(bmap, blk);
127
128 fs->group_desc[group].bg_inode_table = new_blk;
129 }
130
131 /*
132 * Allocate the block and inode bitmaps, if necessary
133 */
134 if (fs->stride)
135 {
136 start_blk += fs->inode_blocks_per_group;
137 start_blk += ((fs->stride * group) %
138 (last_blk - start_blk));
139 if (start_blk > last_blk)
140 /* should never happen */
141 start_blk = group_blk;
142 }
143 else
144 {
145 start_blk = group_blk;
146 }
147
148 if (!fs->group_desc[group].bg_block_bitmap)
149 {
150 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
151 1, bmap, &new_blk);
152
153 if (!retval)
154 retval = ext2_get_free_blocks(fs, group_blk,
155 last_blk, 1, bmap, &new_blk);
156
157 if (!retval)
158 return retval;
159
160 ext2_mark_block_bitmap(bmap, new_blk);
161 fs->group_desc[group].bg_block_bitmap = new_blk;
162 }
163
164 if (!fs->group_desc[group].bg_inode_bitmap)
165 {
166 retval = ext2_get_free_blocks(fs, start_blk, last_blk,
167 1, bmap, &new_blk);
168 if (!retval)
169 retval = ext2_get_free_blocks(fs, group_blk,
170 last_blk, 1, bmap, &new_blk);
171 if (!retval)
172 return retval;
173
174 ext2_mark_block_bitmap(bmap, new_blk);
175 fs->group_desc[group].bg_inode_bitmap = new_blk;
176 }
177
178 return true;
179 }
180
181
182 bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,
183 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret)
184 {
185 ULONG b = start;
186
187 if (!map)
188 map = fs->block_map;
189
190 if (!map)
191 return false;
192
193 if (!b)
194 b = fs->ext2_sb->s_first_data_block;
195
196 if (!finish)
197 finish = start;
198
199 if (!num)
200 num = 1;
201
202 do
203 {
204 if (b+num-1 > fs->ext2_sb->s_blocks_count)
205 b = fs->ext2_sb->s_first_data_block;
206
207 if (ext2_test_block_bitmap_range(map, b, num))
208 {
209 *ret = b;
210 return true;
211 }
212
213 b++;
214
215 } while (b != finish);
216
217 return false;
218 }
219
220
221 bool write_inode_tables(PEXT2_FILESYS fs)
222 {
223 bool retval;
224 ULONG blk, num;
225 int i;
226
227 for (i = 0; (ULONG)i < fs->group_desc_count; i++)
228 {
229 blk = fs->group_desc[i].bg_inode_table;
230 num = fs->inode_blocks_per_group;
231
232 retval = zero_blocks(fs, blk, num, &blk, &num);
233 if (!retval)
234 {
235 DPRINT1("\nMke2fs: Could not write %lu blocks "
236 "in inode table starting at %lu.\n",
237 num, blk);
238
239 zero_blocks(0, 0, 0, 0, 0);
240 return false;
241 }
242 }
243
244 zero_blocks(0, 0, 0, 0, 0);
245
246 return true;
247 }
248
249
250 /*
251 * Stupid algorithm --- we now just search forward starting from the
252 * goal. Should put in a smarter one someday....
253 */
254 bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,
255 PEXT2_BLOCK_BITMAP map, ULONG *ret)
256 {
257 ULONG i;
258
259 if (!map)
260 map = fs->block_map;
261
262 if (!map)
263 return false;
264
265 if (!goal || (goal >= fs->ext2_sb->s_blocks_count))
266 goal = fs->ext2_sb->s_first_data_block;
267
268 i = goal;
269
270 do
271 {
272 if (!ext2_test_block_bitmap(map, i))
273 {
274 *ret = i;
275 return true;
276 }
277
278 i++;
279
280 if (i >= fs->ext2_sb->s_blocks_count)
281 i = fs->ext2_sb->s_first_data_block;
282
283 } while (i != goal);
284
285 return false;
286 }
287
288
289 /*
290 * This function zeros out the allocated block, and updates all of the
291 * appropriate filesystem records.
292 */
293 bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret)
294 {
295 bool retval;
296 ULONG block;
297 char *buf = NULL;
298
299 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
300 if (!buf)
301 return false;
302
303 if (!fs->block_map)
304 {
305 retval = ext2_read_block_bitmap(fs);
306 if (!retval)
307 goto fail;
308 }
309
310 retval = ext2_new_block(fs, goal, 0, &block);
311
312 if (!retval)
313 goto fail;
314
315 retval = NT_SUCCESS(Ext2WriteDisk(
316 fs,
317 ((LONGLONG)block * fs->blocksize),
318 fs->blocksize, (unsigned char *)buf));
319
320 if (!retval)
321 {
322 goto fail;
323 }
324
325 ext2_block_alloc_stats(fs, block, +1);
326 *ret = block;
327
328 if (buf)
329 {
330 RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
331 }
332
333 return true;
334
335 fail:
336
337 if (buf)
338 {
339 RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
340 }
341
342 return false;
343 }
344
345
346 /*
347 * Create new directory block
348 */
349 bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,
350 ULONG parent_ino, char **block)
351 {
352 PEXT2_DIR_ENTRY dir = NULL;
353 char *buf;
354 int rec_len;
355 int filetype = 0;
356
357 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
358 if (!buf)
359 return false;
360
361 dir = (PEXT2_DIR_ENTRY) buf;
362 dir->rec_len = fs->blocksize;
363
364 if (dir_ino)
365 {
366 if (fs->ext2_sb->s_feature_incompat &
367 EXT2_FEATURE_INCOMPAT_FILETYPE)
368 filetype = EXT2_FT_DIR << 8;
369 /*
370 * Set up entry for '.'
371 */
372 dir->inode = dir_ino;
373 dir->name_len = 1 | filetype;
374 dir->name[0] = '.';
375 rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
376 dir->rec_len = EXT2_DIR_REC_LEN(1);
377
378 /*
379 * Set up entry for '..'
380 */
381 dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
382 dir->rec_len = rec_len;
383 dir->inode = parent_ino;
384 dir->name_len = 2 | filetype;
385 dir->name[0] = '.';
386 dir->name[1] = '.';
387 }
388
389 *block = buf;
390
391 return true;
392 }
393
394 bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
395 {
396 bool retval = false;
397
398 retval = NT_SUCCESS(Ext2WriteDisk(
399 fs,
400 ((ULONGLONG)block * fs->blocksize),
401 fs->blocksize, (unsigned char *)inbuf));
402
403 return retval;
404 }
405
406 bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
407 {
408 bool retval = false;
409
410 retval = NT_SUCCESS(Ext2ReadDisk(
411 fs,
412 ((ULONGLONG)block * fs->blocksize),
413 fs->blocksize, (unsigned char *)inbuf));
414
415 return retval;
416 }