| 1 | #include <block/block.h> |
| 2 | #include <fs/ext2.h> |
| 3 | #include <stdbool.h> |
| 4 | #include <stdint.h> |
| 5 | #include <string.h> |
| 6 | |
| 7 | uint32_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 | |
| 18 | uint8_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 | |
| 36 | bool 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 | |
| 48 | struct 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 | |
| 82 | bool 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 | |