blob: 9952948403bbeb4212c84a82c6a7ad5627678c7a [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 -070022void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
23{
24 uint block_size = ext2_block_size(sb) / 512;
25 uint block_start = block_size * block;
26
27 ata_pio_read_sectors(buffer, block_start, block_size);
28}
swissChili4418ca52021-06-14 17:36:00 -070029
swissChili4749d022021-07-19 12:33:06 -070030void ext2_write_block(struct ext2_superblock *sb, void *buffer, uint block)
31{
32 uint block_size = ext2_block_size(sb) / 512;
33 uint block_start = block_size * block;
34
35 ata_pio_write_sectors(block_start, block_size, buffer);
36}
37
swissChili4418ca52021-06-14 17:36:00 -070038struct ext2_superblock ext2_read_superblock()
39{
40 uchar buffer[512 * 2];
41 ata_pio_read_sectors(buffer, 2, 2);
42
43 struct ext2_superblock *sb = (void *)(buffer);
44 return *sb;
45}
swissChilief829f32021-06-13 20:00:54 -070046
swissChilie5adca52021-06-16 21:00:31 -070047uint ext2_num_block_groups(struct ext2_superblock *sb)
48{
49 // This is a mildly janky way of rounding up
swissChili36ed5d72021-07-23 14:56:36 -070050 uint a = IDIV_CEIL(sb->total_blocks, sb->blocks_per_block_group);
51 uint b = IDIV_CEIL(sb->total_inodes, sb->inodes_per_block_group);
swissChilie5adca52021-06-16 21:00:31 -070052
53 if (a == b)
54 {
55 return a;
56 }
57 else
58 {
59 kprintf(ERROR "EXT2 cannot find number of block groups, %d and %d "
60 "should equal.\n",
61 a, b);
62 kpanic("Corrupted filesystem");
63 }
64}
65
swissChili480f1762021-07-26 22:17:34 -070066void ext2_write_bgd(struct ext2_superblock *sb, uint block_group,
67 struct ext2_block_group_descriptor *d)
68{
69 ext2_load_or_write_bgd(sb, block_group, d, true);
70}
71
72struct ext2_block_group_descriptor ext2_load_bgd(
swissChilib7ef65d2021-07-17 12:51:52 -070073 struct ext2_superblock *sb, uint block_group)
swissChilie5adca52021-06-16 21:00:31 -070074{
swissChili480f1762021-07-26 22:17:34 -070075 struct ext2_block_group_descriptor bgd;
76 ext2_load_or_write_bgd(sb, block_group, &bgd, false);
77
78 return bgd;
79}
80
81void ext2_load_or_write_bgd(struct ext2_superblock *sb,
82 uint block_group,
83 struct ext2_block_group_descriptor *d,
84 bool set)
85{
swissChilie5adca52021-06-16 21:00:31 -070086 /**
87 * The BGDT (not to be confused with the GDT) is located the block after the
88 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
89 * block size is specified by X where 1024 << X is the real size) this is
90 * the second block (0-indexed, so 1). On 1024 this is the third block.
91 */
92 uint bgdt_block = 1;
93 uint block_size = ext2_block_size(sb);
94
95 if (block_size == 1024)
96 bgdt_block = 2;
97
swissChilib7ef65d2021-07-17 12:51:52 -070098 const uint bgd_size = sizeof(struct ext2_block_group_descriptor);
99
100 // Disk page that the BGD is on relative to the initial FILE SYSTEM block
101 uint hd_page = block_group / (512 / bgd_size);
102 // The offset from the beginning of that page the BGD is at
103 uint bgd_offset = block_group % (512 / bgd_size);
104
105 struct ext2_block_group_descriptor descriptors[512 / bgd_size];
106 kassert(sizeof(descriptors) == 512, "Wrong BGD size");
107
108 uint lba = (block_size / 512) * bgdt_block + hd_page;
109
swissChili480f1762021-07-26 22:17:34 -0700110 ata_pio_read_sectors(descriptors, lba, 1);
swissChilib7ef65d2021-07-17 12:51:52 -0700111
swissChili480f1762021-07-26 22:17:34 -0700112 if (set)
113 {
114 descriptors[bgd_offset] = *d;
115 ata_pio_write_sectors(lba, 1, (ushort *)descriptors);
116 }
117 else
118 {
119 *d = descriptors[bgd_offset];
120 }
swissChilib7ef65d2021-07-17 12:51:52 -0700121}
122
swissChilid98781b2021-07-25 21:04:17 -0700123static bool print_entry(uint inode, const char *name, uint l, void *sb)
swissChilib7ef65d2021-07-17 12:51:52 -0700124{
125 kprintf("%d\t %s\n", inode, name);
swissChilicbd43632021-07-17 16:19:44 -0700126
swissChilid98781b2021-07-25 21:04:17 -0700127 return true;
swissChili36ed5d72021-07-23 14:56:36 -0700128
swissChilicbd43632021-07-17 16:19:44 -0700129 struct ext2_inode in;
130
131 if (ext2_find_inode(sb, inode, &in))
132 {
133 if ((in.mode & EXT2_F_TYPE) == EXT2_S_IFREG)
134 {
135 char buffer[65];
136 uint read = ext2_read_inode(sb, &in, buffer, 64);
137 buffer[read] = 0;
138
139 kprintf("contents: %d\n'%s'\n", read, buffer);
140 }
141 }
142
swissChilid98781b2021-07-25 21:04:17 -0700143 return true;
swissChilie5adca52021-06-16 21:00:31 -0700144}
145
swissChilief829f32021-06-13 20:00:54 -0700146void ext2_mount(struct fs_node *where)
147{
swissChilid98781b2021-07-25 21:04:17 -0700148 UNUSED(where)
149
swissChili4418ca52021-06-14 17:36:00 -0700150 struct ext2_superblock sb = ext2_read_superblock();
151
swissChilie5adca52021-06-16 21:00:31 -0700152 kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);
swissChili4749d022021-07-19 12:33:06 -0700153
swissChilib7ef65d2021-07-17 12:51:52 -0700154 // Read the root inode 2
155 struct ext2_inode root;
swissChilie5adca52021-06-16 21:00:31 -0700156
swissChilib7ef65d2021-07-17 12:51:52 -0700157 if (ext2_find_inode(&sb, 2, &root))
158 {
swissChili4749d022021-07-19 12:33:06 -0700159 kprintf(OKAY "Found root inode 2 (size=0x%x, num_blocks=0x%x)\n",
160 root.size, root.num_blocks);
swissChilib7ef65d2021-07-17 12:51:52 -0700161 // kprintf(DEBUG "Root.mode = 0x%x\n", root.mode & 0xf000);
swissChili4749d022021-07-19 12:33:06 -0700162 kassert((root.mode & 0xf000) == EXT2_S_IFDIR,
163 "Root (inode 2) is not a directory.");
swissChilib7ef65d2021-07-17 12:51:52 -0700164
swissChili36ed5d72021-07-23 14:56:36 -0700165 char *name = "hello-hl.txt";
166 kprintf(INFO "Creating hard link %s -> hello.txt\n", name);
swissChilid98781b2021-07-25 21:04:17 -0700167 ext2_hard_link(&sb, &root, name, strlen(name), 12);
swissChili36ed5d72021-07-23 14:56:36 -0700168
swissChilib7ef65d2021-07-17 12:51:52 -0700169 kprintf("ls /\n");
170 kprintf("inode\t name\n");
171 kprintf("--------------------\n");
swissChilicbd43632021-07-17 16:19:44 -0700172 ext2_dir_ls(&sb, &root, print_entry, &sb);
swissChilib7ef65d2021-07-17 12:51:52 -0700173 }
174 else
175 {
176 kprintf(WARN "Failed to find root inode 2\n");
177 }
swissChili4749d022021-07-19 12:33:06 -0700178
179 kprintf(INFO "First free inode is %d\n", ext2_first_free_inode(&sb));
swissChilief829f32021-06-13 20:00:54 -0700180}
swissChili9bd74de2021-06-15 20:30:48 -0700181
182bool ext2_valid_filesystem()
183{
184 struct ext2_superblock sb = ext2_read_superblock();
185
swissChili4749d022021-07-19 12:33:06 -0700186 kprintf(DEBUG "superblock signature is %d (0x%x)\n", sb.signature,
187 sb.signature);
swissChili276b8cf2021-07-16 13:24:42 -0700188
swissChili9bd74de2021-06-15 20:30:48 -0700189 return sb.signature == EXT2_SIGNATURE;
swissChilie5adca52021-06-16 21:00:31 -0700190}
swissChilib7ef65d2021-07-17 12:51:52 -0700191
192void ext2_write_superblock(struct ext2_superblock *sb)
193{
194 ushort *wp = (ushort *)sb;
195
196 ata_pio_write_sectors(2, 2, wp);
197}
198
199void ext2_corrupt_superblock_for_fun()
200{
201 struct ext2_superblock sb = ext2_read_superblock();
202 sb.signature = 0xDEAD;
203 ext2_write_superblock(&sb);
204}
205
swissChilid98781b2021-07-25 21:04:17 -0700206bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
207 struct ext2_inode *inode, bool set)
swissChilib7ef65d2021-07-17 12:51:52 -0700208{
209 if (number == 0)
210 return false;
211
212 uint block_group = (number - 1) / sb->inodes_per_block_group;
213 uint local_index = (number - 1) % sb->inodes_per_block_group;
214
215 // Load this from the block group descriptor table
216 struct ext2_block_group_descriptor descriptor =
swissChili480f1762021-07-26 22:17:34 -0700217 ext2_load_bgd(sb, block_group);
swissChilib7ef65d2021-07-17 12:51:52 -0700218
swissChilib7ef65d2021-07-17 12:51:52 -0700219 // We need to figure out what FS block the inode is on, we know how many
220 // inodes there are total in this BGD and the number per page, so this is
221 // simple.
222
223 const uint block_size = ext2_block_size(sb);
224
swissChilid98781b2021-07-25 21:04:17 -0700225 const uint inodes_per_block =
226 block_size / sizeof(struct ext2_inode);
swissChilib7ef65d2021-07-17 12:51:52 -0700227
228 uint inode_block = local_index / inodes_per_block;
229 uint inode_index = local_index % inodes_per_block;
230
231 struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];
232
swissChilid98781b2021-07-25 21:04:17 -0700233 const uint fs_block = descriptor.inode_table_start_block +
234 inode_block;
swissChilib7ef65d2021-07-17 12:51:52 -0700235
swissChilid98781b2021-07-25 21:04:17 -0700236 ext2_read_block(sb, inodes, fs_block);
237
238 if (set)
239 {
240 inodes[inode_index] = *inode;
241
242 ext2_write_block(sb, inodes, fs_block);
243 }
244 else
245 {
246 *inode = inodes[inode_index];
247 }
swissChilib7ef65d2021-07-17 12:51:52 -0700248
249 return true;
250}
251
swissChilid98781b2021-07-25 21:04:17 -0700252bool ext2_find_inode(struct ext2_superblock *sb, uint number,
253 struct ext2_inode *inode)
254{
255 return ext2_get_or_set_inode(sb, number, inode, false);
256}
257
258bool ext2_set_inode(struct ext2_superblock *sb, uint number,
259 struct ext2_inode *inode)
260{
261 return ext2_get_or_set_inode(sb, number, inode, true);
262}
263
swissChili4749d022021-07-19 12:33:06 -0700264bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
swissChilid98781b2021-07-25 21:04:17 -0700265 bool (*cb)(uint inode, const char *name, uint name_len,
266 void *data),
swissChilib7ef65d2021-07-17 12:51:52 -0700267 void *data)
268{
269 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
270 return false;
271
swissChilid98781b2021-07-25 21:04:17 -0700272 for (uint i = 0; i < dir->num_blocks; i++)
swissChilib7ef65d2021-07-17 12:51:52 -0700273 {
274 uchar buffer[ext2_block_size(sb)];
275 ext2_read_inode_block(sb, dir, buffer, i);
276
277 struct ext2_dirent *ent = (void *)buffer;
278
279 // While there are files in this block
swissChilicbd43632021-07-17 16:19:44 -0700280 while ((uint)ent < (uint)(buffer + ext2_block_size(sb)))
swissChilib7ef65d2021-07-17 12:51:52 -0700281 {
282 if (ent->inode == 0)
283 return true;
284
285 if (cb)
286 {
swissChili36ed5d72021-07-23 14:56:36 -0700287 char name[256];
288 uint name_len = MIN(ent->name_len, 255);
swissChilib7ef65d2021-07-17 12:51:52 -0700289
swissChili36ed5d72021-07-23 14:56:36 -0700290 memcpy(name, ent->name, name_len);
291 name[name_len] = '\0';
swissChilicbd43632021-07-17 16:19:44 -0700292
swissChilid98781b2021-07-25 21:04:17 -0700293 if (!cb(ent->inode, name, name_len, data))
294 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700295 }
296
297 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
298 }
299 // We ran out of files in this block, continue to the next one. This
300 // works because files cannot span blocks
301 }
302
303 return true;
304}
305
swissChili36ed5d72021-07-23 14:56:36 -0700306static void ext2_show_dirent(struct ext2_dirent *ent)
307{
308 char name[ent->name_len + 1];
309 memcpy(name, ent->name, ent->name_len);
310 name[ent->name_len] = '\0';
311
312 kprintf(DEBUG "<ent ft=%p, i=%d, s=%s, l=%d>\n", ent->file_type, ent->inode,
313 ent->name, ent->rec_len);
314}
315
swissChilid98781b2021-07-25 21:04:17 -0700316bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
317 char *name, uint name_len, uint inode)
318{
319 struct ext2_inode in;
320
321 if (!ext2_dir_contains(sb, dir, name, name_len) &&
322 ext2_find_inode(sb, inode, &in))
323 {
324 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
325 {
326 return false;
327 }
328
329 // Increment the reference count to this inode
330 in.links_count++;
331 ext2_set_inode(sb, inode, &in);
332
333 // Insert it into the directory
334 uchar type = EXT2_S_TO_FT(in.mode);
335 ext2_insert_into_dir(sb, dir, name, name_len, inode, type);
336
337 return true;
338 }
339 else
340 {
341 return false;
342 }
343}
344
swissChili36ed5d72021-07-23 14:56:36 -0700345void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
346 char *name, uint name_len, uint inode, uchar type)
347{
348 name_len = MIN(name_len, 255);
349 const uint min_size = PAD(name_len + sizeof(struct ext2_dirent));
350 const uint block_size = ext2_block_size(sb);
351
352 if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
353 return;
354
355 uchar buffer[block_size];
356 uint i; // block #
357
358 for (i = 0; i < dir->num_blocks; i++)
359 {
360 ext2_read_inode_block(sb, dir, buffer, i);
361
362 struct ext2_dirent *ent = (void *)buffer;
363
364 // While there are files in this block
365 while ((uint)ent < (uint)(buffer + block_size))
366 {
367 // kprintf(" %d@%db,%d-%d", ent->inode, i, (uint)ent - (uint)buffer,
368 // ent->rec_len);
369 if (ent->inode == 0)
370 {
371 // This is the last item, just insert it at the end
372 // TODO: check this actually fits!
373 // TODO: if we are in a new block, actually create it!
374
375 ent->rec_len = min_size;
376 ent->name_len = name_len;
377 memcpy(ent->name, name, name_len);
378 ent->inode = inode;
379 ent->file_type = type;
380
381 kprintf(DEBUG
382 "Inserted into dir (appending) at block=%d, b=%p \n",
383 i, (uint)ent - (uint)buffer);
384
385 goto finish;
386 }
387
388 uint this_min_size =
389 PAD(ent->name_len + sizeof(struct ext2_dirent));
390 uint available_size = ent->rec_len - this_min_size;
391
swissChilid98781b2021-07-25 21:04:17 -0700392 // kprintf(",%d=%d/%d", ent->name_len, this_min_size,
393 // available_size);
swissChili36ed5d72021-07-23 14:56:36 -0700394
395 if (available_size >= min_size)
396 {
397 // We can fit this in here
398 struct ext2_dirent *inserting =
399 (void *)(((uint)(void *)ent) + this_min_size);
400
401 ent->rec_len = this_min_size;
402
403 inserting->rec_len = available_size;
404 inserting->name_len = name_len;
405 inserting->inode = inode;
406 inserting->file_type = type;
407 memcpy(inserting->name, name, name_len);
408
409 kprintf(DEBUG
410 "Inserted into dir (splicing) at block=%d, b=%p \n",
411 i, (uint)inserting - (uint)buffer);
412
413 // Done!
414 goto finish;
415 }
416
417 ent = (void *)(((uint)(void *)ent) + ent->rec_len);
418 }
419 // We ran out of files in this block, continue to the next one. This
420 // works because files cannot span blocks
421 }
422
423 kprintf("\n");
424
425 kprintf(WARN "Failed to insert!\n");
426
427finish:
428 kprintf("\n");
429 ext2_write_inode_block(sb, dir, buffer, i);
430 kprintf(DEBUG "[insert] writing inode block %d\n", i);
431}
432
swissChili4749d022021-07-19 12:33:06 -0700433ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
434 void *buffer, ssize_t size)
swissChilicbd43632021-07-17 16:19:44 -0700435{
436 const uint block_size = ext2_block_size(sb);
437 char transfer[block_size];
438
439 uint fsize = MIN(inode->size, size);
440 uint i;
441
442 // Transfer full blocks straight to the output buffer
443 for (i = 0; i < fsize / block_size; i++)
444 {
445 ext2_read_inode_block(sb, inode, buffer + i * block_size, i);
446 }
447
swissChili4749d022021-07-19 12:33:06 -0700448 // If we have part of a block left over read it here first, then transfer
449 // what we need
swissChilicbd43632021-07-17 16:19:44 -0700450 if (i * block_size < fsize)
451 {
452 uint remainder = fsize % block_size;
453
454 ext2_read_inode_block(sb, inode, transfer, i);
455 memcpy(buffer + i * block_size, transfer, remainder);
456 }
457
458 return fsize;
459}
460
swissChili36ed5d72021-07-23 14:56:36 -0700461static uint ext2_compute_absolute_block(struct ext2_superblock *sb,
462 struct ext2_inode *inode, uint block)
swissChilib7ef65d2021-07-17 12:51:52 -0700463{
464 if (block >= 12)
465 {
swissChili4749d022021-07-19 12:33:06 -0700466 kprintf(ERROR
467 "Sorry, EXT2 can only access the first 12 (direct) blocks "
468 "of an inode for now. Indirect look-up will be added later\n");
swissChilib7ef65d2021-07-17 12:51:52 -0700469 kpanic("Invalid inode block");
470 }
471
swissChili36ed5d72021-07-23 14:56:36 -0700472 return block;
473}
474
475bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
476 void *buffer, uint block)
477{
478 block = ext2_compute_absolute_block(sb, inode, block);
swissChilib7ef65d2021-07-17 12:51:52 -0700479 uint block_address = inode->blocks[block];
480
481 ext2_read_block(sb, buffer, block_address);
swissChilicbd43632021-07-17 16:19:44 -0700482
483 return true;
swissChilib7ef65d2021-07-17 12:51:52 -0700484}
swissChili4749d022021-07-19 12:33:06 -0700485
swissChili36ed5d72021-07-23 14:56:36 -0700486bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
487 void *buffer, uint block)
488{
489 block = ext2_compute_absolute_block(sb, dir, block);
490 uint block_address = dir->blocks[block];
491
492 kprintf(DEBUG "Writing size=%d, inode block %p, b=%d\n",
493 ext2_block_size(sb), block_address * ext2_block_size(sb), block);
494
495 ext2_write_block(sb, buffer, block_address);
496
497 return true;
498}
499
swissChili4749d022021-07-19 12:33:06 -0700500static const uint ext2_bitmap_block(struct ext2_superblock *sb,
501 uint *bitmap_block, uint *index)
502{
503 const uint block_size = ext2_block_size(sb);
504
swissChilicaa24782021-07-19 14:29:58 -0700505 while (*index > block_size)
swissChili4749d022021-07-19 12:33:06 -0700506 {
swissChilicaa24782021-07-19 14:29:58 -0700507 *index -= block_size;
508 *bitmap_block += 1;
swissChili4749d022021-07-19 12:33:06 -0700509 }
510
511 return block_size;
512}
513
514bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
515 uint index)
516{
517 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
518
519 uint byte = index / 8;
520 uint bit = index % 8;
521
522 uchar buffer[block_size];
523
524 ext2_read_block(sb, buffer, bitmap_block);
525
526 return !!(buffer[byte] & (1 << bit));
527}
528
529void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
530 uint index, bool value)
531{
532 const uint block_size = ext2_bitmap_block(sb, &bitmap_block, &index);
533
534 uint byte = index / 8;
535 uint bit = index % 8;
536
537 uchar buffer[block_size];
538
539 ext2_read_block(sb, buffer, bitmap_block);
540
541 uchar target_bit = 1 << bit;
542 buffer[byte] =
543 value ? (buffer[byte] | target_bit) : (buffer[byte] | ~target_bit);
544
545 ext2_write_block(sb, buffer, bitmap_block);
546}
547
548uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
549 uint num_blocks, uint start_at)
550{
551 uint block_size = ext2_block_size(sb);
552
553 for (uint block = bitmap_block; block < bitmap_block + num_blocks; block++)
554 {
555 // dword-array for performance
556 uint buffer[block_size / 4];
557
558 ext2_read_block(sb, buffer, block);
559
560 // If this is the first block start at start_at, otherwise 0
561 for (int i = 0; i < block_size / 4; i++)
562 {
563 // The bitwise negative will be non-zero if there are zero bits in
564 // the original.
565 if (~buffer[i])
566 {
567 // 4 bytes * 8 bits * i dwords
568 uint index =
569 (4 * 8 * i) + (block - bitmap_block) * 8 * block_size;
570
swissChilicaa24782021-07-19 14:29:58 -0700571 // __builtin_ffs gives us 1+the index of the least-significant 1
swissChili4749d022021-07-19 12:33:06 -0700572 // bit. Since we take the bitwise inverse this is actuall the
573 // least significant 0 bit. This is a GCC intrinsic. This works
574 // particularly well on little-endian systems where the least
575 // significant bit happens to also correspond to the first bit
576 // in the dword bitset.
577 //
578 // ________ ________ ________ ________
579 // ^ this is the LSB ^
580 // | this is the MSB
581 //
582 // This means that the LSB is also the first bit in the bitset.
swissChilicaa24782021-07-19 14:29:58 -0700583 uint trailing = __builtin_ffs(~buffer[i]) - 1;
swissChili4749d022021-07-19 12:33:06 -0700584
swissChili4749d022021-07-19 12:33:06 -0700585 return trailing + index;
586 }
587 }
588 }
589
590 return -1;
591}
592
593uint ext2_first_free_inode(struct ext2_superblock *sb)
594{
swissChili36ed5d72021-07-23 14:56:36 -0700595 uint num_block_groups = ext2_num_block_groups(sb);
swissChili4749d022021-07-19 12:33:06 -0700596
swissChili36ed5d72021-07-23 14:56:36 -0700597 kprintf(INFO "%d block groups\n", num_block_groups);
swissChili4749d022021-07-19 12:33:06 -0700598
swissChili36ed5d72021-07-23 14:56:36 -0700599 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
swissChili4749d022021-07-19 12:33:06 -0700600 {
swissChili36ed5d72021-07-23 14:56:36 -0700601 struct ext2_block_group_descriptor bgd =
swissChili480f1762021-07-26 22:17:34 -0700602 ext2_load_bgd(sb, 0);
swissChili36ed5d72021-07-23 14:56:36 -0700603
604 const uint block_size = ext2_block_size(sb);
605 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
606 // yield 1, should 2)
607 uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
608
609 // inodes start at 1
610 uint inode =
611 ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
612 // This will overflow back to zero if no inode was found
613
614 if (inode)
615 return inode;
swissChili4749d022021-07-19 12:33:06 -0700616 }
617
swissChili36ed5d72021-07-23 14:56:36 -0700618 return 0;
619}
620
621// ^
622// | this and | this are awfully similar, should refactor
623// v
624
625uint ext2_first_free_block(struct ext2_superblock *sb)
626{
627 uint num_block_groups = ext2_num_block_groups(sb);
628
629 for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
630 {
631 struct ext2_block_group_descriptor bgd =
swissChili480f1762021-07-26 22:17:34 -0700632 ext2_load_bgd(sb, 0);
swissChili36ed5d72021-07-23 14:56:36 -0700633
634 const uint block_size = ext2_block_size(sb);
635 // + 1 because we need to round up (ie 1025 for 1024 size blocks will
636 // yield 1, should 2)
637 uint bitset_blocks = (sb->blocks_per_block_group / 8) / block_size + 1;
638
639 // inodes start at 1
640 uint block_no =
641 ext2_first_zero_bit(sb, bgd.block_bitmap, bitset_blocks, 0);
642 // This will overflow back to zero if no inode was found
643
644 if (block_no != 0xffffffff)
645 return block_no;
646 }
647
648 return 0;
swissChili4749d022021-07-19 12:33:06 -0700649}
swissChilid98781b2021-07-25 21:04:17 -0700650
651struct ext2_dir_contains_data
652{
653 char *name;
654 uint len;
655 bool found;
656};
657
658static bool ext2_dir_contains_cb(uint inode, const char *name,
659 uint name_len,
660 struct ext2_dir_contains_data *d)
661{
662 if (strncmp((char *)name, d->name, MIN(name_len, d->len)) == 0)
663 {
664 d->found = true;
665 return false;
666 }
667
668 return true;
669}
670
671bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
672 char *name, uint len)
673{
674 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
675 {
676 return false;
677 }
678
679 struct ext2_dir_contains_data d =
680 {
681 .name = name,
682 .len = len,
683 .found = false,
684 };
685
686 ext2_dir_ls(sb, dir, ext2_dir_contains_cb, &d);
687
688 return d.found;
689}
690
691struct ext2_dir_find_data
692{
693 char *name;
694 uint len;
695 uint inode;
696};
697
698bool ext2_dir_find_cb(uint inode, const char *name, uint len,
699 struct ext2_dir_find_data *d)
700{
701 if (strncmp((char *)name, d->name, MIN(len, d->len)) == 0)
702 {
703 d->inode = inode;
704 return false;
705 }
706
707 return true;
708}
709
710uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
711 char *name, uint name_len)
712{
713 if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
714 {
715 return false;
716 }
717
718 struct ext2_dir_find_data d =
719 {
720 .name = name,
721 .len = name_len,
722 .inode = 0,
723 };
724
725 ext2_dir_ls(sb, dir, ext2_dir_find_cb, &d);
726
727 return d.inode;
728}
swissChili480f1762021-07-26 22:17:34 -0700729
730uint ext2_alloc_new_block(struct ext2_superblock *sb,
731 uint block_group)
732{
733 struct ext2_block_group_descriptor bgd =
734 ext2_load_bgd(sb, block_group);
735
736 if (bgd.unallocated_blocks == 0)
737 // TODO: handle out of blocks
738 return ext2_alloc_new_block(sb, block_group + 1);
739
740 // We can safely pass ~0 here as long as the FS is well formed
741 // because we know there is at least 1 free block
742 uint block = ext2_first_zero_bit(sb, bgd.block_bitmap, ~0, 0);
743
744 ext2_set_in_bitmap(sb, bgd.block_bitmap, block, true);
745 bgd.unallocated_blocks--;
746
747 ext2_write_bgd(sb, block_group, &bgd);
748
749 return block;
750}