xref: /reactos/sdk/lib/fslib/ext2lib/Memory.c (revision 8a978a17)
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 }
417