blob: 9ecbe515aa6e5be19437116494d00cc4ad9a6333 [file] [log] [blame]
swissChili4749d022021-07-19 12:33:06 -07001#include <alloc.h>
swissChili4418ca52021-06-14 17:36:00 -07002#include <dri/ata_pio/ata_pio.h>
swissChilie5adca52021-06-16 21:00:31 -07003#include <dri/fs/ext2/ext2.h>
swissChili4749d022021-07-19 12:33:06 -07004#include <io.h>
swissChilief829f32021-06-13 20:00:54 -07005#include <kint.h>
swissChili4418ca52021-06-14 17:36:00 -07006#include <log.h>
swissChilib7ef65d2021-07-17 12:51:52 -07007
swissChilid98781b2021-07-25 21:04:17 -07008#define F(f,t) [EXT2_S_##f >> 12] = EXT2_FT_##t,
9const uchar ext2_s_to_ft[] =
10{
11 0,
12 F(IFSOCK, SOCK)
13 F(IFLINK, SYMLINK)
14 F(IFREG, REGULAR_FILE)
15 F(IFBLK, BLKDEV)
16 F(IFDIR, DIR)
17 F(IFCHR, CHRDEV)
18 F(IFIFO, FIFO)
19};
20#undef F
21
swissChilib7ef65d2021-07-17 12:51:52 -070022inline uint ext2_block_size(struct ext2_superblock *sb)
23{
24 return 1024 << sb->block_size_shift;
25}
26
27void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
28{
29 uint block_size = ext2_block_size(sb) / 512;
30 uint block_start = block_size * block;
31
32 ata_pio_read_sectors(buffer, block_start, block_size);
33}
swissChili4418ca52021-06-14 17:36:00 -070034
swissChili4749d022021-07-19 12:33:06 -070035void ext2_write_block(struct ext2_superblock *sb, void *buffer, uint block)
36{
37 uint block_size = ext2_block_size(sb) / 512;
38 uint block_start = block_size * block;
39
40 ata_pio_write_sectors(block_start, block_size, buffer);
41}
42
swissChili4418ca52021-06-14 17:36:00 -070043struct ext2_superblock ext2_read_superblock()
44{
45 uchar buffer[512 * 2];
46 ata_pio_read_sectors(buffer, 2, 2);
47
48 struct ext2_superblock *sb = (void *)(buffer);
49 return *sb;
50}
swissChilief829f32021-06-13 20:00:54 -070051
swissChilie5adca52021-06-16 21:00:31 -070052uint ext2_num_block_groups(struct ext2_superblock *sb)
53{
54 // This is a mildly janky way of rounding up
swissChili36ed5d72021-07-23 14:56:36 -070055 uint a = IDIV_CEIL(sb->total_blocks, sb->blocks_per_block_group);
56 uint b = IDIV_CEIL(sb->total_inodes, sb->inodes_per_block_group);
swissChilie5adca52021-06-16 21:00:31 -070057
58 if (a == b)
59 {
60 return a;
61 }
62 else
63 {
64 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
65 "should equal.\n",
66 a, b);
67 kpanic("Corrupted filesystem");
68 }
69}
70
swissChilib7ef65d2021-07-17 12:51:52 -070071struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
72 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070073{
74 /**
75 * The BGDT (not to be confused with the GDT) is located the block after the
76 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
77 * block size is specified by X where 1024 << X is the real size) this is
78 * the second block (0-indexed, so 1). On 1024 this is the third block.
79 */
80 uint bgdt_block = 1;
81 uint block_size = ext2_block_size(sb);
82
83 if (block_size == 1024)
84 bgdt_block = 2;
85
swissChilib7ef65d2021-07-17 12:51:52 -070086 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
87
88 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
89 uint hd_page = block_group / (512 / bgd_size);
90 // The offset from the beginning of that page the BGD is at
91 uint bgd_offset = block_group % (512 / bgd_size);
92
93 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
94 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
95
96 uint lba = (block_size / 512) * bgdt_block + hd_page;
97
98 ata_pio_read_sectors(&descriptors, lba, 1);
99
100 return descriptors[bgd_offset];
101}
102
swissChilid98781b2021-07-25 21:04:17 -0700103static bool print_entry(uint inode, const char *name, uint l, void *sb)
swissChilib7ef65d2021-07-17 12:51:52 -0700104{
105 kprintf("%d\t %s\n", inode, name);
swissChilicbd43632021-07-17 16:19:44 -0700106
swissChilid98781b2021-07-25 21:04:17 -0700107 return true;
swissChili36ed5d72021-07-23 14:56:36 -0700108
swissChilicbd43632021-07-17 16:19:44 -0700109 struct ext2_inode in;
110
111 if (ext2_find_inode(sb, inode, &in))
112 {
113 if ((in.mode & EXT2_F_TYPE) == EXT2_S_IFREG)
114 {
115 char buffer[65];
116 uint read = ext2_read_inode(sb, &in, buffer, 64);
117 buffer[read] = 0;
118
119 kprintf("contents: %d\n'%s'\n", read, buffer);
120 }
121 }
122
swissChilid98781b2021-07-25 21:04:17 -0700123 return true;
swissChilie5adca52021-06-16 21:00:31 -0700124}
125
swissChilief829f32021-06-13 20:00:54 -0700126void ext2_mount(struct fs_node *where)
127{
swissChilid98781b2021-07-25 21:04:17 -0700128 UNUSED(where)
129
swissChili4418ca52021-06-14 17:36:00 -0700130 struct ext2_superblock sb = ext2_read_superblock();
131
swissChilie5adca52021-06-16 21:00:31 -0700132 kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
swissChili4749d022021-07-19 12:33:06 -0700133
swissChilib7ef65d2021-07-17 12:51:52 -0700134 // Read the root inode 2
135 struct ext2_inode root;
swissChilie5adca52021-06-16 21:00:31 -0700136
swissChilib7ef65d2021-07-17 12:51:52 -0700137 if (ext2_find_inode(&sb, 2, &root))
138 {
swissChili4749d022021-07-19 12:33:06 -0700139 kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n",
140 root.size, root.num_blocks);
swissChilib7ef65d2021-07-17 12:51:52 -0700141 // kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
swissChili4749d022021-07-19 12:33:06 -0700142 kassert((root.mode & 0xf000) == EXT2_S_IFDIR,
143 "Root (inode 2) is not a directory.");
swissChilib7ef65d2021-07-17 12:51:52 -0700144
swissChili36ed5d72021-07-23 14:56:36 -0700145 char *name = "hello-hl.txt";
146 kprintf(INFO "Creating hard link %s -> hello.txt\n", name);
swissChilid98781b2021-07-25 21:04:17 -0700147 ext2_hard_link(&sb, &root, name, strlen(name), 12);
swissChili36ed5d72021-07-23 14:56:36 -0700148
swissChilib7ef65d2021-07-17 12:51:52 -0700149 kprintf("ls /\n");
150 kprintf("inode\t name\n");
151 kprintf("--------------------\n");
swissChilicbd43632021-07-17 16:19:44 -0700152 ext2_dir_ls(&sb, &root, print_entry, &sb);
swissChilib7ef65d2021-07-17 12:51:52 -0700153 }
154 else
155 {
156 kprintf(WARN "Failed to find root inode 2\n");
157 }
swissChili4749d022021-07-19 12:33:06 -0700158
159 kprintf(INFO "First free inode is %d\n", ext2_first_free_inode(&sb));
swissChilief829f32021-06-13 20:00:54 -0700160}
swissChili9bd74de2021-06-15 20:30:48 -0700161
162bool ext2_valid_filesystem()
163{
164 struct ext2_superblock sb = ext2_read_superblock();
165
swissChili4749d022021-07-19 12:33:06 -0700166 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature,
167 sb.signature);
swissChili276b8cf2021-07-16 13:24:42 -0700168
swissChili9bd74de2021-06-15 20:30:48 -0700169 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700170}
swissChilib7ef65d2021-07-17 12:51:52 -0700171
172void ext2_write_superblock(struct ext2_superblock *sb)
173{
174 ushort *wp = (ushort *)sb;
175
176 ata_pio_write_sectors(2, 2, wp);
177}
178
179void ext2_corrupt_superblock_for_fun()
180{
181 struct ext2_superblock sb = ext2_read_superblock();
182 sb.signature = 0xDEAD;
183 ext2_write_superblock(&sb);
184}
185
swissChilid98781b2021-07-25 21:04:17 -0700186bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
187 struct ext2_inode *inode, bool set)
swissChilib7ef65d2021-07-17 12:51:52 -0700188{
189 if (number == 0)
190 return false;
191
192 uint block_group = (number - 1) / sb->inodes_per_block_group;
193 uint local_index = (number - 1) % sb->inodes_per_block_group;
194
195 // Load this from the block group descriptor table
196 struct ext2_block_group_descriptor descriptor =
197 ext2_load_block_group_descriptor(sb, block_group);
198
swissChilib7ef65d2021-07-17 12:51:52 -0700199 // We need to figure out what FS block the inode is on, we know how many
200 // inodes there are total in this BGD and the number per page, so this is
201 // simple.
202
203 const uint block_size = ext2_block_size(sb);
204
swissChilid98781b2021-07-25 21:04:17 -0700205 const uint inodes_per_block =
206 block_size / sizeof(struct ext2_inode);
swissChilib7ef65d2021-07-17 12:51:52 -0700207
208 uint inode_block = local_index / inodes_per_block;
209 uint inode_index = local_index % inodes_per_block;
210
211 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
212
swissChilid98781b2021-07-25 21:04:17 -0700213 const uint fs_block = descriptor.inode_table_start_block +
214 inode_block;
swissChilib7ef65d2021-07-17 12:51:52 -0700215
swissChilid98781b2021-07-25 21:04:17 -0700216 ext2_read_block(sb, inodes, fs_block);
217
218 if (set)
219 {
220 inodes[inode_index] = *inode;
221
222 ext2_write_block(sb, inodes, fs_block);
223 }
224 else
225 {
226 *inode = inodes[inode_index];
227 }
swissChilib7ef65d2021-07-17 12:51:52 -0700228
229 return true;
230}
231
swissChilid98781b2021-07-25 21:04:17 -0700232bool ext2_find_inode(struct ext2_superblock *sb, uint number,
233 struct ext2_inode *inode)
234{
235 return ext2_get_or_set_inode(sb, number, inode, false);
236}
237
238bool ext2_set_inode(struct ext2_superblock *sb, uint number,
239 struct ext2_inode *inode)
240{
241 return ext2_get_or_set_inode(sb, number, inode, true);
242}
243
swissChili4749d022021-07-19 12:33:06 -0700244bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
swissChilid98781b2021-07-25 21:04:17 -0700245 bool (*cb)(uint inode, const char *name, uint name_len,
246 void *data),
swissChilib7ef65d2021-07-17 12:51:52 -0700247 void *data)
248{
249 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
250 return false;
251
swissChilid98781b2021-07-25 21:04:17 -0700252 for (uint i = 0; i < dir->num_blocks; i++)
swissChilib7ef65d2021-07-17 12:51:52 -0700253 {
254 uchar buffer[ext2_block_size(sb)];
255 ext2_read_inode_block(sb, dir, buffer, i);
256
257 struct ext2_dirent *ent = (void *)buffer;
258
259 // While there are files in this block
swissChilicbd43632021-07-17 16:19:44 -0700260 while ((uint)ent < (uint)(buffer + ext2_block_size(sb)))
swissChilib7ef65d2021-07-17 12:51:52 -0700261 {
262 if (ent->inode == 0)
263 return true;
264
265 if (cb)
266 {
swissChili36ed5d72021-07-23 14:56:36 -0700267 char name[256];
268 uint name_len = MIN(ent->name_len, 255);
swissChilib7ef65d2021-07-17 12:51:52 -0700269
swissChili36ed5d72021-07-23 14:56:36 -0700270 memcpy(name, ent->name, name_len);
271 name[name_len] = '\0';
swissChilicbd43632021-07-17 16:19:44 -0700272
swissChilid98781b2021-07-25 21:04:17 -0700273 if (!cb(ent->inode, name, name_len, data))
274 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700275 }
276
277 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
278 }
279 // We ran out of files in this block, continue to the next one. This
280 // works because files cannot span blocks
281 }
282
283 return true;
284}
285
swissChili36ed5d72021-07-23 14:56:36 -0700286static void ext2_show_dirent(struct ext2_dirent *ent)
287{
288 char name[ent->name_len + 1];
289 memcpy(name, ent->name, ent->name_len);
290 name[ent->name_len] = '\0';
291
292 kprintf(DEBUG "<ent ft=%p, i=%d, s=%s, l=%d>\n", ent->file_type, ent->inode,
293 ent->name, ent->rec_len);
294}
295
swissChilid98781b2021-07-25 21:04:17 -0700296bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
297 char *name, uint name_len, uint inode)
298{
299 struct ext2_inode in;
300
301 if (!ext2_dir_contains(sb, dir, name, name_len) &&
302 ext2_find_inode(sb, inode, &in))
303 {
304 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
305 {
306 return false;
307 }
308
309 // Increment the reference count to this inode
310 in.links_count++;
311 ext2_set_inode(sb, inode, &in);
312
313 // Insert it into the directory
314 uchar type = EXT2_S_TO_FT(in.mode);
315 ext2_insert_into_dir(sb, dir, name, name_len, inode, type);
316
317 return true;
318 }
319 else
320 {
321 return false;
322 }
323}
324
swissChili36ed5d72021-07-23 14:56:36 -0700325void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
326 char *name, uint name_len, uint inode, uchar type)
327{
328 name_len = MIN(name_len, 255);
329 const uint min_size = PAD(name_len + sizeof(struct ext2_dirent));
330 const uint block_size = ext2_block_size(sb);
331
332 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
333 return;
334
335 uchar buffer[block_size];
336 uint i; // block #
337
338 for (i = 0; i < dir->num_blocks; i++)
339 {
340 ext2_read_inode_block(sb, dir, buffer, i);
341
342 struct ext2_dirent *ent = (void *)buffer;
343
344 // While there are files in this block
345 while ((uint)ent < (uint)(buffer + block_size))
346 {
347 // kprintf(" %d@%db,%d-%d", ent->inode, i, (uint)ent - (uint)buffer,
348 // ent->rec_len);
349 if (ent->inode == 0)
350 {
351 // This is the last item, just insert it at the end
352 // TODO: check this actually fits!
353 // TODO: if we are in a new block, actually create it!
354
355 ent->rec_len = min_size;
356 ent->name_len = name_len;
357 memcpy(ent->name, name, name_len);
358 ent->inode = inode;
359 ent->file_type = type;
360
361 kprintf(DEBUG
362 "Inserted into dir (appending) at block=%d, b=%p \n",
363 i, (uint)ent - (uint)buffer);
364
365 goto finish;
366 }
367
368 uint this_min_size =
369 PAD(ent->name_len + sizeof(struct ext2_dirent));
370 uint available_size = ent->rec_len - this_min_size;
371
swissChilid98781b2021-07-25 21:04:17 -0700372 // kprintf(",%d=%d/%d", ent->name_len, this_min_size,
373 // available_size);
swissChili36ed5d72021-07-23 14:56:36 -0700374
375 if (available_size >= min_size)
376 {
377 // We can fit this in here
378 struct ext2_dirent *inserting =
379 (void *)(((uint)(void *)ent) + this_min_size);
380
381 ent->rec_len = this_min_size;
382
383 inserting->rec_len = available_size;
384 inserting->name_len = name_len;
385 inserting->inode = inode;
386 inserting->file_type = type;
387 memcpy(inserting->name, name, name_len);
388
389 kprintf(DEBUG
390 "Inserted into dir (splicing) at block=%d, b=%p \n",
391 i, (uint)inserting - (uint)buffer);
392
393 // Done!
394 goto finish;
395 }
396
397 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
398 }
399 // We ran out of files in this block, continue to the next one. This
400 // works because files cannot span blocks
401 }
402
403 kprintf("\n");
404
405 kprintf(WARN "Failed to insert!\n");
406
407finish:
408 kprintf("\n");
409 ext2_write_inode_block(sb, dir, buffer, i);
410 kprintf(DEBUG "[insert] writing inode block %d\n", i);
411}
412
swissChili4749d022021-07-19 12:33:06 -0700413ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
414 void *buffer, ssize_t size)
swissChilicbd43632021-07-17 16:19:44 -0700415{
416 const uint block_size = ext2_block_size(sb);
417 char transfer[block_size];
418
419 uint fsize = MIN(inode->size, size);
420 uint i;
421
422 // Transfer full blocks straight to the output buffer
423 for (i = 0; i < fsize / block_size; i++)
424 {
425 ext2_read_inode_block(sb, inode, buffer + i * block_size, i);
426 }
427
swissChili4749d022021-07-19 12:33:06 -0700428 // If we have part of a block left over read it here first, then transfer
429 // what we need
swissChilicbd43632021-07-17 16:19:44 -0700430 if (i * block_size < fsize)
431 {
432 uint remainder = fsize % block_size;
433
434 ext2_read_inode_block(sb, inode, transfer, i);
435 memcpy(buffer + i * block_size, transfer, remainder);
436 }
437
438 return fsize;
439}
440
swissChili36ed5d72021-07-23 14:56:36 -0700441static uint ext2_compute_absolute_block(struct ext2_superblock *sb,
442 struct ext2_inode *inode, uint block)
swissChilib7ef65d2021-07-17 12:51:52 -0700443{
444 if (block >= 12)
445 {
swissChili4749d022021-07-19 12:33:06 -0700446 kprintf(ERROR
447 "Sorry, EXT2 can only access the first 12 (direct) blocks "
448 "of an inode for now. Indirect look-up will be added later\n");
swissChilib7ef65d2021-07-17 12:51:52 -0700449 kpanic("Invalid inode block");
450 }
451
swissChili36ed5d72021-07-23 14:56:36 -0700452 return block;
453}
454
455bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
456 void *buffer, uint block)
457{
458 block = ext2_compute_absolute_block(sb, inode, block);
swissChilib7ef65d2021-07-17 12:51:52 -0700459 uint block_address = inode->blocks[block];
460
461 ext2_read_block(sb, buffer, block_address);
swissChilicbd43632021-07-17 16:19:44 -0700462
463 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700464}
swissChili4749d022021-07-19 12:33:06 -0700465
swissChili36ed5d72021-07-23 14:56:36 -0700466bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
467 void *buffer, uint block)
468{
469 block = ext2_compute_absolute_block(sb, dir, block);
470 uint block_address = dir->blocks[block];
471
472 kprintf(DEBUG "Writing size=%d, inode block %p, b=%d\n",
473 ext2_block_size(sb), block_address * ext2_block_size(sb), block);
474
475 ext2_write_block(sb, buffer, block_address);
476
477 return true;
478}
479
swissChili4749d022021-07-19 12:33:06 -0700480static const uint ext2_bitmap_block(struct ext2_superblock *sb,
481 uint *bitmap_block, uint *index)
482{
483 const uint block_size = ext2_block_size(sb);
484
swissChilicaa24782021-07-19 14:29:58 -0700485 while (*index > block_size)
swissChili4749d022021-07-19 12:33:06 -0700486 {
swissChilicaa24782021-07-19 14:29:58 -0700487 *index -= block_size;
488 *bitmap_block += 1;
swissChili4749d022021-07-19 12:33:06 -0700489 }
490
491 return block_size;
492}
493
494bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
495 uint index)
496{
497 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
498
499 uint byte = index / 8;
500 uint bit = index % 8;
501
502 uchar buffer[block_size];
503
504 ext2_read_block(sb, buffer, bitmap_block);
505
506 return !!(buffer[byte] & (1 << bit));
507}
508
509void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
510 uint index, bool value)
511{
512 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
513
514 uint byte = index / 8;
515 uint bit = index % 8;
516
517 uchar buffer[block_size];
518
519 ext2_read_block(sb, buffer, bitmap_block);
520
521 uchar target_bit = 1 << bit;
522 buffer[byte] =
523 value ? (buffer[byte] | target_bit) : (buffer[byte] | ~target_bit);
524
525 ext2_write_block(sb, buffer, bitmap_block);
526}
527
528uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
529 uint num_blocks, uint start_at)
530{
531 uint block_size = ext2_block_size(sb);
532
533 for (uint block = bitmap_block; block < bitmap_block + num_blocks; block++)
534 {
535 // dword-array for performance
536 uint buffer[block_size / 4];
537
538 ext2_read_block(sb, buffer, block);
539
540 // If this is the first block start at start_at, otherwise 0
541 for (int i = 0; i < block_size / 4; i++)
542 {
543 // The bitwise negative will be non-zero if there are zero bits in
544 // the original.
545 if (~buffer[i])
546 {
547 // 4 bytes * 8 bits * i dwords
548 uint index =
549 (4 * 8 * i) + (block - bitmap_block) * 8 * block_size;
550
swissChilicaa24782021-07-19 14:29:58 -0700551 // __builtin_ffs gives us 1+the index of the least-significant 1
swissChili4749d022021-07-19 12:33:06 -0700552 // bit. Since we take the bitwise inverse this is actuall the
553 // least significant 0 bit. This is a GCC intrinsic. This works
554 // particularly well on little-endian systems where the least
555 // significant bit happens to also correspond to the first bit
556 // in the dword bitset.
557 //
558 // ________ ________ ________ ________
559 // ^ this is the LSB ^
560 // | this is the MSB
561 //
562 // This means that the LSB is also the first bit in the bitset.
swissChilicaa24782021-07-19 14:29:58 -0700563 uint trailing = __builtin_ffs(~buffer[i]) - 1;
swissChili4749d022021-07-19 12:33:06 -0700564
swissChili4749d022021-07-19 12:33:06 -0700565 return trailing + index;
566 }
567 }
568 }
569
570 return -1;
571}
572
573uint ext2_first_free_inode(struct ext2_superblock *sb)
574{
swissChili36ed5d72021-07-23 14:56:36 -0700575 uint num_block_groups = ext2_num_block_groups(sb);
swissChili4749d022021-07-19 12:33:06 -0700576
swissChili36ed5d72021-07-23 14:56:36 -0700577 kprintf(INFO "%d block groups\n", num_block_groups);
swissChili4749d022021-07-19 12:33:06 -0700578
swissChili36ed5d72021-07-23 14:56:36 -0700579 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
swissChili4749d022021-07-19 12:33:06 -0700580 {
swissChili36ed5d72021-07-23 14:56:36 -0700581 struct ext2_block_group_descriptor bgd =
582 ext2_load_block_group_descriptor(sb, 0);
583
584 const uint block_size = ext2_block_size(sb);
585 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
586 // yield 1, should 2)
587 uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
588
589 // inodes start at 1
590 uint inode =
591 ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
592 // This will overflow back to zero if no inode was found
593
594 if (inode)
595 return inode;
swissChili4749d022021-07-19 12:33:06 -0700596 }
597
swissChili36ed5d72021-07-23 14:56:36 -0700598 return 0;
599}
600
601// ^
602// | this and | this are awfully similar, should refactor
603// v
604
605uint ext2_first_free_block(struct ext2_superblock *sb)
606{
607 uint num_block_groups = ext2_num_block_groups(sb);
608
609 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
610 {
611 struct ext2_block_group_descriptor bgd =
612 ext2_load_block_group_descriptor(sb, 0);
613
614 const uint block_size = ext2_block_size(sb);
615 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
616 // yield 1, should 2)
617 uint bitset_blocks = (sb->blocks_per_block_group / 8) / block_size + 1;
618
619 // inodes start at 1
620 uint block_no =
621 ext2_first_zero_bit(sb, bgd.block_bitmap, bitset_blocks, 0);
622 // This will overflow back to zero if no inode was found
623
624 if (block_no != 0xffffffff)
625 return block_no;
626 }
627
628 return 0;
swissChili4749d022021-07-19 12:33:06 -0700629}
swissChilid98781b2021-07-25 21:04:17 -0700630
631struct ext2_dir_contains_data
632{
633 char *name;
634 uint len;
635 bool found;
636};
637
638static bool ext2_dir_contains_cb(uint inode, const char *name,
639 uint name_len,
640 struct ext2_dir_contains_data *d)
641{
642 if (strncmp((char *)name, d->name, MIN(name_len, d->len)) == 0)
643 {
644 d->found = true;
645 return false;
646 }
647
648 return true;
649}
650
651bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
652 char *name, uint len)
653{
654 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
655 {
656 return false;
657 }
658
659 struct ext2_dir_contains_data d =
660 {
661 .name = name,
662 .len = len,
663 .found = false,
664 };
665
666 ext2_dir_ls(sb, dir, ext2_dir_contains_cb, &d);
667
668 return d.found;
669}
670
671struct ext2_dir_find_data
672{
673 char *name;
674 uint len;
675 uint inode;
676};
677
678bool ext2_dir_find_cb(uint inode, const char *name, uint len,
679 struct ext2_dir_find_data *d)
680{
681 if (strncmp((char *)name, d->name, MIN(len, d->len)) == 0)
682 {
683 d->inode = inode;
684 return false;
685 }
686
687 return true;
688}
689
690uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
691 char *name, uint name_len)
692{
693 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
694 {
695 return false;
696 }
697
698 struct ext2_dir_find_data d =
699 {
700 .name = name,
701 .len = name_len,
702 .inode = 0,
703 };
704
705 ext2_dir_ls(sb, dir, ext2_dir_find_cb, &d);
706
707 return d.inode;
708}