blob: 99d5e9dc0a2eed159ffe04641c27c84ab58bf569 [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>
swissChilia664e722021-07-27 17:47:55 -07004#include <dri/fs/ext2/ext2_vfs.h>
5#include <vfs.h>
swissChili4749d022021-07-19 12:33:06 -07006#include <io.h>
swissChilief829f32021-06-13 20:00:54 -07007#include <kint.h>
swissChili4418ca52021-06-14 17:36:00 -07008#include <log.h>
swissChilib7ef65d2021-07-17 12:51:52 -07009
swissChilid98781b2021-07-25 21:04:17 -070010#define F(f,t) [EXT2_S_##f >> 12] = EXT2_FT_##t,
11const uchar ext2_s_to_ft[] =
12{
13 0,
14 F(IFSOCK, SOCK)
15 F(IFLINK, SYMLINK)
16 F(IFREG, REGULAR_FILE)
17 F(IFBLK, BLKDEV)
18 F(IFDIR, DIR)
19 F(IFCHR, CHRDEV)
20 F(IFIFO, FIFO)
21};
22#undef F
23
swissChilib7ef65d2021-07-17 12:51:52 -070024void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
25{
26 uint block_size = ext2_block_size(sb) / 512;
27 uint block_start = block_size * block;
28
29 ata_pio_read_sectors(buffer, block_start, block_size);
30}
swissChili4418ca52021-06-14 17:36:00 -070031
swissChili4749d022021-07-19 12:33:06 -070032void ext2_write_block(struct ext2_superblock *sb, void *buffer, uint block)
33{
34 uint block_size = ext2_block_size(sb) / 512;
35 uint block_start = block_size * block;
36
37 ata_pio_write_sectors(block_start, block_size, buffer);
38}
39
swissChili4418ca52021-06-14 17:36:00 -070040struct ext2_superblock ext2_read_superblock()
41{
42 uchar buffer[512 * 2];
43 ata_pio_read_sectors(buffer, 2, 2);
44
45 struct ext2_superblock *sb = (void *)(buffer);
46 return *sb;
47}
swissChilief829f32021-06-13 20:00:54 -070048
swissChilie5adca52021-06-16 21:00:31 -070049uint ext2_num_block_groups(struct ext2_superblock *sb)
50{
51 // This is a mildly janky way of rounding up
swissChili36ed5d72021-07-23 14:56:36 -070052 uint a = IDIV_CEIL(sb->total_blocks, sb->blocks_per_block_group);
53 uint b = IDIV_CEIL(sb->total_inodes, sb->inodes_per_block_group);
swissChilie5adca52021-06-16 21:00:31 -070054
55 if (a == b)
56 {
57 return a;
58 }
59 else
60 {
61 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
62 "should equal.\n",
63 a, b);
64 kpanic("Corrupted filesystem");
65 }
66}
67
swissChili480f1762021-07-26 22:17:34 -070068void ext2_write_bgd(struct ext2_superblock *sb, uint block_group,
69 struct ext2_block_group_descriptor *d)
70{
71 ext2_load_or_write_bgd(sb, block_group, d, true);
72}
73
74struct ext2_block_group_descriptor ext2_load_bgd(
swissChilib7ef65d2021-07-17 12:51:52 -070075 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070076{
swissChili480f1762021-07-26 22:17:34 -070077 struct ext2_block_group_descriptor bgd;
78 ext2_load_or_write_bgd(sb, block_group, &bgd, false);
79
80 return bgd;
81}
82
83void ext2_load_or_write_bgd(struct ext2_superblock *sb,
84 uint block_group,
85 struct ext2_block_group_descriptor *d,
86 bool set)
87{
swissChilie5adca52021-06-16 21:00:31 -070088 /**
89 * The BGDT (not to be confused with the GDT) is located the block after the
90 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
91 * block size is specified by X where 1024 << X is the real size) this is
92 * the second block (0-indexed, so 1). On 1024 this is the third block.
93 */
94 uint bgdt_block = 1;
95 uint block_size = ext2_block_size(sb);
96
97 if (block_size == 1024)
98 bgdt_block = 2;
99
swissChilib7ef65d2021-07-17 12:51:52 -0700100 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
101
102 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
103 uint hd_page = block_group / (512 / bgd_size);
104 // The offset from the beginning of that page the BGD is at
105 uint bgd_offset = block_group % (512 / bgd_size);
106
107 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
108 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
109
110 uint lba = (block_size / 512) * bgdt_block + hd_page;
111
swissChili480f1762021-07-26 22:17:34 -0700112 ata_pio_read_sectors(descriptors, lba, 1);
swissChilib7ef65d2021-07-17 12:51:52 -0700113
swissChili480f1762021-07-26 22:17:34 -0700114 if (set)
115 {
116 descriptors[bgd_offset] = *d;
117 ata_pio_write_sectors(lba, 1, (ushort *)descriptors);
118 }
119 else
120 {
121 *d = descriptors[bgd_offset];
122 }
swissChilib7ef65d2021-07-17 12:51:52 -0700123}
124
swissChilid98781b2021-07-25 21:04:17 -0700125static bool print_entry(uint inode, const char *name, uint l, void *sb)
swissChilib7ef65d2021-07-17 12:51:52 -0700126{
127 kprintf("%d\t %s\n", inode, name);
swissChilicbd43632021-07-17 16:19:44 -0700128
swissChilid98781b2021-07-25 21:04:17 -0700129 return true;
swissChili36ed5d72021-07-23 14:56:36 -0700130
swissChilicbd43632021-07-17 16:19:44 -0700131 struct ext2_inode in;
132
133 if (ext2_find_inode(sb, inode, &in))
134 {
135 if ((in.mode & EXT2_F_TYPE) == EXT2_S_IFREG)
136 {
137 char buffer[65];
138 uint read = ext2_read_inode(sb, &in, buffer, 64);
139 buffer[read] = 0;
140
141 kprintf("contents: %d\n'%s'\n", read, buffer);
142 }
143 }
144
swissChilid98781b2021-07-25 21:04:17 -0700145 return true;
swissChilie5adca52021-06-16 21:00:31 -0700146}
147
swissChilief829f32021-06-13 20:00:54 -0700148void ext2_mount(struct fs_node *where)
149{
swissChilid98781b2021-07-25 21:04:17 -0700150
swissChilia664e722021-07-27 17:47:55 -0700151 struct ext2_superblock *sb = malloc(sizeof(struct ext2_superblock));
152 *sb = ext2_read_superblock();
swissChili4418ca52021-06-14 17:36:00 -0700153
swissChilia664e722021-07-27 17:47:55 -0700154 struct fs_node *ext2_root = ext2_inode2vfs(sb, 2, "/", 1);
155 uint err;
swissChili4749d022021-07-19 12:33:06 -0700156
swissChilia664e722021-07-27 17:47:55 -0700157 if ((err = fs_mount(where, ext2_root)))
swissChilib7ef65d2021-07-17 12:51:52 -0700158 {
swissChilia664e722021-07-27 17:47:55 -0700159 kprintf(WARN "Failed to mount EXT2: error %d\n", err);
swissChilib7ef65d2021-07-17 12:51:52 -0700160 }
swissChilief829f32021-06-13 20:00:54 -0700161}
swissChili9bd74de2021-06-15 20:30:48 -0700162
163bool ext2_valid_filesystem()
164{
165 struct ext2_superblock sb = ext2_read_superblock();
166
swissChili4749d022021-07-19 12:33:06 -0700167 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature,
168 sb.signature);
swissChili276b8cf2021-07-16 13:24:42 -0700169
swissChili9bd74de2021-06-15 20:30:48 -0700170 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700171}
swissChilib7ef65d2021-07-17 12:51:52 -0700172
173void ext2_write_superblock(struct ext2_superblock *sb)
174{
175 ushort *wp = (ushort *)sb;
176
177 ata_pio_write_sectors(2, 2, wp);
178}
179
180void ext2_corrupt_superblock_for_fun()
181{
182 struct ext2_superblock sb = ext2_read_superblock();
183 sb.signature = 0xDEAD;
184 ext2_write_superblock(&sb);
185}
186
swissChilid98781b2021-07-25 21:04:17 -0700187bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
188 struct ext2_inode *inode, bool set)
swissChilib7ef65d2021-07-17 12:51:52 -0700189{
190 if (number == 0)
191 return false;
192
193 uint block_group = (number - 1) / sb->inodes_per_block_group;
194 uint local_index = (number - 1) % sb->inodes_per_block_group;
195
196 // Load this from the block group descriptor table
197 struct ext2_block_group_descriptor descriptor =
swissChili480f1762021-07-26 22:17:34 -0700198 ext2_load_bgd(sb, block_group);
swissChilib7ef65d2021-07-17 12:51:52 -0700199
swissChilib7ef65d2021-07-17 12:51:52 -0700200 // We need to figure out what FS block the inode is on, we know how many
201 // inodes there are total in this BGD and the number per page, so this is
202 // simple.
203
204 const uint block_size = ext2_block_size(sb);
205
swissChilid98781b2021-07-25 21:04:17 -0700206 const uint inodes_per_block =
207 block_size / sizeof(struct ext2_inode);
swissChilib7ef65d2021-07-17 12:51:52 -0700208
209 uint inode_block = local_index / inodes_per_block;
210 uint inode_index = local_index % inodes_per_block;
211
212 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
213
swissChilid98781b2021-07-25 21:04:17 -0700214 const uint fs_block = descriptor.inode_table_start_block +
215 inode_block;
swissChilib7ef65d2021-07-17 12:51:52 -0700216
swissChilid98781b2021-07-25 21:04:17 -0700217 ext2_read_block(sb, inodes, fs_block);
218
219 if (set)
220 {
221 inodes[inode_index] = *inode;
222
223 ext2_write_block(sb, inodes, fs_block);
224 }
225 else
226 {
227 *inode = inodes[inode_index];
228 }
swissChilib7ef65d2021-07-17 12:51:52 -0700229
230 return true;
231}
232
swissChilid98781b2021-07-25 21:04:17 -0700233bool ext2_find_inode(struct ext2_superblock *sb, uint number,
234 struct ext2_inode *inode)
235{
236 return ext2_get_or_set_inode(sb, number, inode, false);
237}
238
239bool ext2_set_inode(struct ext2_superblock *sb, uint number,
240 struct ext2_inode *inode)
241{
242 return ext2_get_or_set_inode(sb, number, inode, true);
243}
244
swissChili4749d022021-07-19 12:33:06 -0700245bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
swissChilid98781b2021-07-25 21:04:17 -0700246 bool (*cb)(uint inode, const char *name, uint name_len,
247 void *data),
swissChilib7ef65d2021-07-17 12:51:52 -0700248 void *data)
249{
250 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
251 return false;
252
swissChilid98781b2021-07-25 21:04:17 -0700253 for (uint i = 0; i < dir->num_blocks; i++)
swissChilib7ef65d2021-07-17 12:51:52 -0700254 {
255 uchar buffer[ext2_block_size(sb)];
256 ext2_read_inode_block(sb, dir, buffer, i);
257
258 struct ext2_dirent *ent = (void *)buffer;
259
260 // While there are files in this block
swissChilicbd43632021-07-17 16:19:44 -0700261 while ((uint)ent < (uint)(buffer + ext2_block_size(sb)))
swissChilib7ef65d2021-07-17 12:51:52 -0700262 {
263 if (ent->inode == 0)
264 return true;
265
266 if (cb)
267 {
swissChili36ed5d72021-07-23 14:56:36 -0700268 char name[256];
269 uint name_len = MIN(ent->name_len, 255);
swissChilib7ef65d2021-07-17 12:51:52 -0700270
swissChili36ed5d72021-07-23 14:56:36 -0700271 memcpy(name, ent->name, name_len);
272 name[name_len] = '\0';
swissChilicbd43632021-07-17 16:19:44 -0700273
swissChilid98781b2021-07-25 21:04:17 -0700274 if (!cb(ent->inode, name, name_len, data))
275 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700276 }
277
278 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
279 }
280 // We ran out of files in this block, continue to the next one. This
281 // works because files cannot span blocks
282 }
283
284 return true;
285}
286
swissChili36ed5d72021-07-23 14:56:36 -0700287static void ext2_show_dirent(struct ext2_dirent *ent)
288{
289 char name[ent->name_len + 1];
290 memcpy(name, ent->name, ent->name_len);
291 name[ent->name_len] = '\0';
292
293 kprintf(DEBUG "<ent ft=%p, i=%d, s=%s, l=%d>\n", ent->file_type, ent->inode,
294 ent->name, ent->rec_len);
295}
296
swissChilid98781b2021-07-25 21:04:17 -0700297bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
298 char *name, uint name_len, uint inode)
299{
300 struct ext2_inode in;
301
302 if (!ext2_dir_contains(sb, dir, name, name_len) &&
303 ext2_find_inode(sb, inode, &in))
304 {
305 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
306 {
307 return false;
308 }
309
310 // Increment the reference count to this inode
311 in.links_count++;
312 ext2_set_inode(sb, inode, &in);
313
314 // Insert it into the directory
315 uchar type = EXT2_S_TO_FT(in.mode);
316 ext2_insert_into_dir(sb, dir, name, name_len, inode, type);
317
318 return true;
319 }
320 else
321 {
322 return false;
323 }
324}
325
swissChili36ed5d72021-07-23 14:56:36 -0700326void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
327 char *name, uint name_len, uint inode, uchar type)
328{
329 name_len = MIN(name_len, 255);
330 const uint min_size = PAD(name_len + sizeof(struct ext2_dirent));
331 const uint block_size = ext2_block_size(sb);
332
333 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
334 return;
335
336 uchar buffer[block_size];
337 uint i; // block #
338
339 for (i = 0; i < dir->num_blocks; i++)
340 {
341 ext2_read_inode_block(sb, dir, buffer, i);
342
343 struct ext2_dirent *ent = (void *)buffer;
344
345 // While there are files in this block
346 while ((uint)ent < (uint)(buffer + block_size))
347 {
348 // kprintf(" %d@%db,%d-%d", ent->inode, i, (uint)ent - (uint)buffer,
349 // ent->rec_len);
350 if (ent->inode == 0)
351 {
352 // This is the last item, just insert it at the end
353 // TODO: check this actually fits!
354 // TODO: if we are in a new block, actually create it!
355
356 ent->rec_len = min_size;
357 ent->name_len = name_len;
358 memcpy(ent->name, name, name_len);
359 ent->inode = inode;
360 ent->file_type = type;
361
362 kprintf(DEBUG
363 "Inserted into dir (appending) at block=%d, b=%p \n",
364 i, (uint)ent - (uint)buffer);
365
366 goto finish;
367 }
368
369 uint this_min_size =
370 PAD(ent->name_len + sizeof(struct ext2_dirent));
371 uint available_size = ent->rec_len - this_min_size;
372
swissChilid98781b2021-07-25 21:04:17 -0700373 // kprintf(",%d=%d/%d", ent->name_len, this_min_size,
374 // available_size);
swissChili36ed5d72021-07-23 14:56:36 -0700375
376 if (available_size >= min_size)
377 {
378 // We can fit this in here
379 struct ext2_dirent *inserting =
380 (void *)(((uint)(void *)ent) + this_min_size);
381
382 ent->rec_len = this_min_size;
383
384 inserting->rec_len = available_size;
385 inserting->name_len = name_len;
386 inserting->inode = inode;
387 inserting->file_type = type;
388 memcpy(inserting->name, name, name_len);
389
390 kprintf(DEBUG
391 "Inserted into dir (splicing) at block=%d, b=%p \n",
392 i, (uint)inserting - (uint)buffer);
393
394 // Done!
395 goto finish;
396 }
397
398 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
399 }
400 // We ran out of files in this block, continue to the next one. This
401 // works because files cannot span blocks
402 }
403
404 kprintf("\n");
405
406 kprintf(WARN "Failed to insert!\n");
407
408finish:
409 kprintf("\n");
410 ext2_write_inode_block(sb, dir, buffer, i);
411 kprintf(DEBUG "[insert] writing inode block %d\n", i);
412}
413
swissChili4749d022021-07-19 12:33:06 -0700414ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
415 void *buffer, ssize_t size)
swissChilicbd43632021-07-17 16:19:44 -0700416{
417 const uint block_size = ext2_block_size(sb);
418 char transfer[block_size];
419
420 uint fsize = MIN(inode->size, size);
421 uint i;
422
423 // Transfer full blocks straight to the output buffer
424 for (i = 0; i < fsize / block_size; i++)
425 {
426 ext2_read_inode_block(sb, inode, buffer + i * block_size, i);
427 }
428
swissChili4749d022021-07-19 12:33:06 -0700429 // If we have part of a block left over read it here first, then transfer
430 // what we need
swissChilicbd43632021-07-17 16:19:44 -0700431 if (i * block_size < fsize)
432 {
433 uint remainder = fsize % block_size;
434
435 ext2_read_inode_block(sb, inode, transfer, i);
436 memcpy(buffer + i * block_size, transfer, remainder);
437 }
438
439 return fsize;
440}
441
swissChili36ed5d72021-07-23 14:56:36 -0700442static uint ext2_compute_absolute_block(struct ext2_superblock *sb,
443 struct ext2_inode *inode, uint block)
swissChilib7ef65d2021-07-17 12:51:52 -0700444{
445 if (block >= 12)
446 {
swissChili4749d022021-07-19 12:33:06 -0700447 kprintf(ERROR
448 "Sorry, EXT2 can only access the first 12 (direct) blocks "
449 "of an inode for now. Indirect look-up will be added later\n");
swissChilib7ef65d2021-07-17 12:51:52 -0700450 kpanic("Invalid inode block");
451 }
452
swissChili36ed5d72021-07-23 14:56:36 -0700453 return block;
454}
455
456bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
457 void *buffer, uint block)
458{
459 block = ext2_compute_absolute_block(sb, inode, block);
swissChilib7ef65d2021-07-17 12:51:52 -0700460 uint block_address = inode->blocks[block];
461
462 ext2_read_block(sb, buffer, block_address);
swissChilicbd43632021-07-17 16:19:44 -0700463
464 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700465}
swissChili4749d022021-07-19 12:33:06 -0700466
swissChili36ed5d72021-07-23 14:56:36 -0700467bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
468 void *buffer, uint block)
469{
470 block = ext2_compute_absolute_block(sb, dir, block);
471 uint block_address = dir->blocks[block];
472
473 kprintf(DEBUG "Writing size=%d, inode block %p, b=%d\n",
474 ext2_block_size(sb), block_address * ext2_block_size(sb), block);
475
476 ext2_write_block(sb, buffer, block_address);
477
478 return true;
479}
480
swissChili4749d022021-07-19 12:33:06 -0700481static const uint ext2_bitmap_block(struct ext2_superblock *sb,
482 uint *bitmap_block, uint *index)
483{
484 const uint block_size = ext2_block_size(sb);
485
swissChilicaa24782021-07-19 14:29:58 -0700486 while (*index > block_size)
swissChili4749d022021-07-19 12:33:06 -0700487 {
swissChilicaa24782021-07-19 14:29:58 -0700488 *index -= block_size;
489 *bitmap_block += 1;
swissChili4749d022021-07-19 12:33:06 -0700490 }
491
492 return block_size;
493}
494
495bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
496 uint index)
497{
498 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
499
500 uint byte = index / 8;
501 uint bit = index % 8;
502
503 uchar buffer[block_size];
504
505 ext2_read_block(sb, buffer, bitmap_block);
506
507 return !!(buffer[byte] & (1 << bit));
508}
509
510void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
511 uint index, bool value)
512{
513 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
514
515 uint byte = index / 8;
516 uint bit = index % 8;
517
518 uchar buffer[block_size];
519
520 ext2_read_block(sb, buffer, bitmap_block);
521
522 uchar target_bit = 1 << bit;
523 buffer[byte] =
524 value ? (buffer[byte] | target_bit) : (buffer[byte] | ~target_bit);
525
526 ext2_write_block(sb, buffer, bitmap_block);
527}
528
529uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
530 uint num_blocks, uint start_at)
531{
532 uint block_size = ext2_block_size(sb);
533
534 for (uint block = bitmap_block; block < bitmap_block + num_blocks; block++)
535 {
536 // dword-array for performance
537 uint buffer[block_size / 4];
538
539 ext2_read_block(sb, buffer, block);
540
541 // If this is the first block start at start_at, otherwise 0
542 for (int i = 0; i < block_size / 4; i++)
543 {
544 // The bitwise negative will be non-zero if there are zero bits in
545 // the original.
546 if (~buffer[i])
547 {
548 // 4 bytes * 8 bits * i dwords
549 uint index =
550 (4 * 8 * i) + (block - bitmap_block) * 8 * block_size;
551
swissChilicaa24782021-07-19 14:29:58 -0700552 // __builtin_ffs gives us 1+the index of the least-significant 1
swissChili4749d022021-07-19 12:33:06 -0700553 // bit. Since we take the bitwise inverse this is actuall the
554 // least significant 0 bit. This is a GCC intrinsic. This works
555 // particularly well on little-endian systems where the least
556 // significant bit happens to also correspond to the first bit
557 // in the dword bitset.
558 //
559 // ________ ________ ________ ________
560 // ^ this is the LSB ^
561 // | this is the MSB
562 //
563 // This means that the LSB is also the first bit in the bitset.
swissChilicaa24782021-07-19 14:29:58 -0700564 uint trailing = __builtin_ffs(~buffer[i]) - 1;
swissChili4749d022021-07-19 12:33:06 -0700565
swissChili4749d022021-07-19 12:33:06 -0700566 return trailing + index;
567 }
568 }
569 }
570
571 return -1;
572}
573
574uint ext2_first_free_inode(struct ext2_superblock *sb)
575{
swissChili36ed5d72021-07-23 14:56:36 -0700576 uint num_block_groups = ext2_num_block_groups(sb);
swissChili4749d022021-07-19 12:33:06 -0700577
swissChili36ed5d72021-07-23 14:56:36 -0700578 kprintf(INFO "%d block groups\n", num_block_groups);
swissChili4749d022021-07-19 12:33:06 -0700579
swissChili36ed5d72021-07-23 14:56:36 -0700580 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
swissChili4749d022021-07-19 12:33:06 -0700581 {
swissChili36ed5d72021-07-23 14:56:36 -0700582 struct ext2_block_group_descriptor bgd =
swissChili480f1762021-07-26 22:17:34 -0700583 ext2_load_bgd(sb, 0);
swissChili36ed5d72021-07-23 14:56:36 -0700584
585 const uint block_size = ext2_block_size(sb);
586 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
587 // yield 1, should 2)
588 uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
589
590 // inodes start at 1
591 uint inode =
592 ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
593 // This will overflow back to zero if no inode was found
594
595 if (inode)
596 return inode;
swissChili4749d022021-07-19 12:33:06 -0700597 }
598
swissChili36ed5d72021-07-23 14:56:36 -0700599 return 0;
600}
601
602// ^
603// | this and | this are awfully similar, should refactor
604// v
605
606uint ext2_first_free_block(struct ext2_superblock *sb)
607{
608 uint num_block_groups = ext2_num_block_groups(sb);
609
610 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
611 {
612 struct ext2_block_group_descriptor bgd =
swissChili480f1762021-07-26 22:17:34 -0700613 ext2_load_bgd(sb, 0);
swissChili36ed5d72021-07-23 14:56:36 -0700614
615 const uint block_size = ext2_block_size(sb);
616 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
617 // yield 1, should 2)
618 uint bitset_blocks = (sb->blocks_per_block_group / 8) / block_size + 1;
619
620 // inodes start at 1
621 uint block_no =
622 ext2_first_zero_bit(sb, bgd.block_bitmap, bitset_blocks, 0);
623 // This will overflow back to zero if no inode was found
624
625 if (block_no != 0xffffffff)
626 return block_no;
627 }
628
629 return 0;
swissChili4749d022021-07-19 12:33:06 -0700630}
swissChilid98781b2021-07-25 21:04:17 -0700631
632struct ext2_dir_contains_data
633{
634 char *name;
635 uint len;
636 bool found;
637};
638
639static bool ext2_dir_contains_cb(uint inode, const char *name,
640 uint name_len,
641 struct ext2_dir_contains_data *d)
642{
643 if (strncmp((char *)name, d->name, MIN(name_len, d->len)) == 0)
644 {
645 d->found = true;
646 return false;
647 }
648
649 return true;
650}
651
652bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
653 char *name, uint len)
654{
655 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
656 {
657 return false;
658 }
659
660 struct ext2_dir_contains_data d =
661 {
662 .name = name,
663 .len = len,
664 .found = false,
665 };
666
667 ext2_dir_ls(sb, dir, ext2_dir_contains_cb, &d);
668
669 return d.found;
670}
671
672struct ext2_dir_find_data
673{
674 char *name;
675 uint len;
676 uint inode;
677};
678
679bool ext2_dir_find_cb(uint inode, const char *name, uint len,
680 struct ext2_dir_find_data *d)
681{
682 if (strncmp((char *)name, d->name, MIN(len, d->len)) == 0)
683 {
684 d->inode = inode;
685 return false;
686 }
687
688 return true;
689}
690
691uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
692 char *name, uint name_len)
693{
694 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
695 {
696 return false;
697 }
698
699 struct ext2_dir_find_data d =
700 {
701 .name = name,
702 .len = name_len,
703 .inode = 0,
704 };
705
706 ext2_dir_ls(sb, dir, ext2_dir_find_cb, &d);
707
708 return d.inode;
709}
swissChili480f1762021-07-26 22:17:34 -0700710
711uint ext2_alloc_new_block(struct ext2_superblock *sb,
712 uint block_group)
713{
714 struct ext2_block_group_descriptor bgd =
715 ext2_load_bgd(sb, block_group);
716
717 if (bgd.unallocated_blocks == 0)
718 // TODO: handle out of blocks
719 return ext2_alloc_new_block(sb, block_group + 1);
720
721 // We can safely pass ~0 here as long as the FS is well formed
722 // because we know there is at least 1 free block
723 uint block = ext2_first_zero_bit(sb, bgd.block_bitmap, ~0, 0);
724
725 ext2_set_in_bitmap(sb, bgd.block_bitmap, block, true);
726 bgd.unallocated_blocks--;
727
728 ext2_write_bgd(sb, block_group, &bgd);
729
730 return block;
731}