1#include <block/block.h>
2#include <fs/ext2.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <string.h>
6
7uint32_t ext2_block_to_lba(struct ext2_fs *fs, uint32_t block_num) {
8 if (!fs)
9 return -1;
10
11 struct partition *p = fs->partition;
12
13 uint32_t base_lba = block_num * fs->sectors_per_block;
14 uint32_t lba = base_lba + p->start_lba;
15 return lba;
16}
17
18uint8_t *ext2_block_read(struct ext2_fs *fs, uint32_t block_num,
19 struct bcache_entry **out) {
20 if (!fs)
21 return NULL;
22
23 struct block_device *d = fs->drive;
24
25 uint32_t lba = ext2_block_to_lba(fs, block_num);
26 uint32_t spb = fs->sectors_per_block;
27
28 uint8_t *buf = bcache_get(disk: d, lba, block_size: fs->block_size, spb, false, out_entry: out);
29 if (!buf)
30 return NULL;
31
32 bcache_ent_acquire(ent: *out);
33 return buf;
34}
35
36bool ext2_block_write(struct ext2_fs *fs, struct bcache_entry *ent,
37 enum bio_request_priority prio) {
38 if (!fs || !ent)
39 return false;
40
41 struct block_device *d = fs->drive;
42
43 bcache_write_queue(disk: d, ent, spb: fs->sectors_per_block, prio);
44
45 return true;
46}
47
48struct ext2_inode *ext2_inode_read(struct ext2_fs *fs, uint32_t inode_idx,
49 struct bcache_entry **out_ent) {
50 if (!fs || inode_idx == 0 || inode_idx > fs->inodes_count) {
51 return NULL;
52 }
53
54 uint32_t inodes_per_group = fs->inodes_per_group;
55 uint32_t inode_size = fs->inode_size;
56
57 uint32_t group = ext2_get_inode_group(fs, inode: inode_idx);
58 uint32_t index_in_group = (inode_idx - 1) % inodes_per_group;
59
60 struct ext2_group_desc *desc = &fs->group_desc[group];
61 uint32_t inode_table_block = desc->inode_table;
62
63 uint32_t offset_bytes = index_in_group * inode_size;
64 uint32_t block_offset = offset_bytes / fs->block_size;
65 uint32_t offset_in_block = offset_bytes % fs->block_size;
66
67 uint32_t inode_block_num = inode_table_block + block_offset;
68
69 struct bcache_entry *ent;
70 uint8_t *buf = ext2_block_read(fs, block_num: inode_block_num, out: &ent);
71 if (!buf)
72 return NULL;
73
74 if (out_ent)
75 *out_ent = ent;
76
77 struct ext2_inode *inode_ptr =
78 (struct ext2_inode *) (buf + offset_in_block);
79 return inode_ptr;
80}
81
82bool ext2_inode_write(struct ext2_fs *fs, uint32_t inode_num,
83 const struct ext2_inode *inode) {
84 uint32_t group = ext2_get_inode_group(fs, inode: inode_num);
85 uint32_t index = (inode_num - 1) % fs->inodes_per_group;
86 uint32_t offset = index * fs->inode_size;
87
88 uint32_t inode_table_block = fs->group_desc[group].inode_table;
89 uint32_t block_size = fs->block_size;
90
91 uint32_t block_offset = offset % block_size;
92 uint32_t block_index = offset / block_size;
93
94 uint32_t inode_block_num = (inode_table_block + block_index);
95 struct bcache_entry *ent;
96 uint8_t *block_buf = ext2_block_read(fs, block_num: inode_block_num, out: &ent);
97 if (!block_buf)
98 return false;
99
100 memcpy(block_buf + block_offset, inode, fs->inode_size);
101 bcache_ent_release(ent);
102
103 bool status = ext2_block_write(fs, ent, EXT2_PRIO_INODE);
104 return status;
105}
106