#include <sys/memory.h>
#include <sys/types.h>
#include <dev/blockdev.h>
#include <fs/ext2.h>
#include <stdlib.h>
#define DEBUG
#include <debug.h>
#define PATH_MAX 255
ext2_mount *
fs_mount_ext2(struct blockdev *dev) {
ext2_mount *mnt = kmalloc(sizeof(ext2_mount));
mnt->dev = dev;
uint8_t buf[1024];
bdev_read(dev, buf, 2, 2);
memcpy(&(mnt->sb), buf, sizeof(ext2_superblock));
mnt->block_size = 1024 << mnt->sb.s_log_block_size;
if (mnt->sb.s_inode_size == 0) {
mnt->sb.s_inode_size = 128;
}
khexprint("inc", mnt->sb.s_inodes_count);
return mnt;
}
static uint32_t fs_lookup(ext2_mount *fs, ext2_inode *dir, const char *name);
static void
fs_read_block(ext2_mount *fs, uint32_t block_address, void *dst) {
uint32_t lba = (fs->block_size >> 9) * block_address;
bdev_read(fs->dev, dst, lba, fs->block_size / 512);
}
static void
fs_inode_read_block_direct(ext2_mount *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
uint32_t block_address = inode->i_block[block_index];
fs_read_block(fs, block_address, dst);
}
static void
fs_inode_read_block_indirect(ext2_mount *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
uint8_t buf[EXT2_MAX_BLOCK_SIZE];
uint32_t block_address = inode->i_block[12];
fs_read_block(fs, block_address, buf);
uint32_t indirect_block_index = block_index - 12;
uint32_t real_block_address = ((uint32_t *)buf)[indirect_block_index];
fs_read_block(fs, real_block_address, dst);
}
void
fs_inode_read_block(ext2_mount *fs, ext2_inode *inode, uint32_t block_index, void *dst) {
if (block_index > 10) {
khexprint("ERROR maybe indirect block?", block_index);
while(1) {};
}
fs_inode_read_block_direct(fs, inode, block_index, dst);
}
static uint32_t
fs_inode_table_address(ext2_mount *fs, uint32_t block_group) {
uint32_t bg_desc_block = fs->sb.s_first_data_block + 1;
uint8_t buf[8192];
fs_read_block(fs, bg_desc_block, buf);
ext2_block_group_desc *bg_desc = (void *)buf;
//khexprint("inode table block", bg_desc[block_group].bg_inode_table);
return bg_desc[block_group].bg_inode_table;
}
void fs_read_inode(ext2_mount *fs, uint32_t inode, ext2_inode *dst) {
uint32_t block_group = (inode - 1) / fs->sb.s_inodes_per_group;
int inode_index = (inode - 1) % fs->sb.s_inodes_per_group;
int inodes_per_block = fs->block_size / fs->sb.s_inode_size;
uint32_t inode_table_start = fs_inode_table_address(fs, block_group);
uint32_t inode_table_offset = inode_index / inodes_per_block;
uint32_t index_in_table = inode_index % inodes_per_block;
khexprint("read inode", inode);
khexprint("inode table start", inode_table_start);
khexprint("inode table offset", inode_table_offset);
khexprint("inode table index", index_in_table);
uint32_t read_block_index = inode_table_start + inode_table_offset;
khexprint("read block", read_block_index);
uint8_t buf[8192];
fs_read_block(fs, read_block_index, (void *)buf);
uint8_t *inode_start = buf + (fs->sb.s_inode_size * index_in_table);
memcpy(dst, inode_start, sizeof(ext2_inode));
/*for(unsigned int i=0;i<(sizeof(ext2_inode)); i++) {*/
/*[>khexprint("copy inode data", ((uint32_t)i) << 24 | inode_start[i]);<]*/
/**((uint8_t *)(dst + i)) = inode_start[i];*/
/*}*/
}
static inline uint32_t inode_block_count(ext2_mount *fs, ext2_inode *inode) {
return inode->i_blocks / (2 << fs->sb.s_log_block_size);
}
static uint32_t fs_lookup(ext2_mount *fs, ext2_inode *dir, const char *name) {
size_t search_name_len = strlen(name);
uint8_t buf[8192];
void *bufend = buf + 8192;
for (uint32_t i = 0; i < inode_block_count(fs, dir); i++) {
khexprint("lookup in block", i);
fs_inode_read_block(fs, dir, i, buf);
void *p = (void *)buf;
while(p < bufend) {
uint32_t entry_inode = *(uint32_t *)p;
uint16_t rec_len = *(uint16_t *)(p + 4);
uint16_t name_len = *(uint16_t *)(p + 6);
char *entry_name = (char *)(p + 8);
if (entry_inode) {
if (name_len == search_name_len && strncmp(name, entry_name, name_len) == 0) {
return entry_inode;
}
} else {
kprint("skip empty entry\n");
}
if (rec_len == 0) {
kprint("rec_len is 0\n");
while (1){};
}
p += rec_len;
}
}
kprint("lookup failed\n");
return 0;
}
uint32_t fs_find(ext2_mount *fs, const char *name) {
char buf_path[PATH_MAX];
ext2_inode ino;
uint32_t next_inode_num = EXT2_ROOT_INO;
const char *cstart = name + 1;
const char *cend = cstart;
while (*cend) {
cend = cstart;
while (*cend && *cend != '/') { cend++; };
memcpy(buf_path, cstart, (cend - cstart));
buf_path[cend - cstart] = 0;
cstart = cend + 1;
kprint("component: ");
kprint(buf_path);
kprint("\n");
fs_read_inode(fs, next_inode_num, &ino);
khexprint("read inode", next_inode_num);
next_inode_num = fs_lookup(fs, &ino, buf_path);
}
return next_inode_num;
}