From 4014a36377ff69f6433e7b0af2144bc3a7d29ca7 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Thu, 16 Apr 2020 19:06:33 +0200 Subject: Many fix attempts for the divide by zero exception --- src/kernel/acpi/acpi.c | 4 +- src/kernel/fs/ata.c | 16 +- src/kernel/fs/ata.h | 6 +- src/kernel/fs/elf.c | 8 +- src/kernel/fs/ext2.c | 787 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel/fs/ext2.h | 211 ++++++++++++ src/kernel/fs/ext2/ext2.c | 790 --------------------------------------------- src/kernel/fs/ext2/ext2.h | 211 ------------ src/kernel/fs/vfs.c | 370 +++++++++++++++++++++ src/kernel/fs/vfs.h | 149 +++++++++ src/kernel/fs/vfs/vfs.c | 369 --------------------- src/kernel/fs/vfs/vfs.h | 149 --------- src/kernel/graphics/vesa.c | 8 +- src/kernel/kernel.c | 4 +- src/kernel/net/rtl8139.c | 2 +- src/kernel/pci/pci.c | 5 +- 16 files changed, 1541 insertions(+), 1548 deletions(-) create mode 100644 src/kernel/fs/ext2.c create mode 100644 src/kernel/fs/ext2.h delete mode 100644 src/kernel/fs/ext2/ext2.c delete mode 100644 src/kernel/fs/ext2/ext2.h create mode 100644 src/kernel/fs/vfs.c create mode 100644 src/kernel/fs/vfs.h delete mode 100644 src/kernel/fs/vfs/vfs.c delete mode 100644 src/kernel/fs/vfs/vfs.h (limited to 'src') diff --git a/src/kernel/acpi/acpi.c b/src/kernel/acpi/acpi.c index 8eee5f1..8733987 100644 --- a/src/kernel/acpi/acpi.c +++ b/src/kernel/acpi/acpi.c @@ -184,7 +184,7 @@ void acpi_poweroff() { cli(); if (SCI_EN == 0) { - warn("ACPI shutdown is not supported\n"); + warn("ACPI shutdown is not supported"); return; } @@ -207,4 +207,4 @@ void reboot() good = inb(0x64); outb(0x64, 0xFE); halt_loop(); -} \ No newline at end of file +} diff --git a/src/kernel/fs/ata.c b/src/kernel/fs/ata.c index 817bb98..ac42275 100644 --- a/src/kernel/fs/ata.c +++ b/src/kernel/fs/ata.c @@ -8,7 +8,7 @@ #include #include -uint32_t ata_device; +uint32_t ata_device = 0x00000000; ata_dev_t primary_master = { .slave = 0 }; ata_dev_t primary_slave = { .slave = 1 }; @@ -30,7 +30,7 @@ void software_reset(ata_dev_t *dev) outb(dev->control, CONTROL_ZERO); } -void ata_handler(struct regs *reg) +void ata_handler(struct regs *r) { inb(primary_master.status); inb(primary_master.BMR_STATUS); @@ -240,14 +240,14 @@ void ata_device_detect(ata_dev_t *dev, int primary) outb(dev->command, COMMAND_IDENTIFY); if (!inb(dev->status)) { - log("Device does not exist"); + warn("Device does not exist: %s", dev->mountpoint); return; } uint8_t lba_lo = inb(dev->lba_lo); uint8_t lba_hi = inb(dev->lba_high); if (lba_lo != 0 || lba_hi != 0) { - log("Device is not ata-compatible"); + warn("Device is not ata-compatible: %s", dev->mountpoint); return; } uint8_t drq = 0, err = 0; @@ -256,7 +256,7 @@ void ata_device_detect(ata_dev_t *dev, int primary) err = inb(dev->status) & STATUS_ERR; } if (err) { - log("Error while polling"); + warn("Error while polling: %s", dev->mountpoint); return; } @@ -283,10 +283,10 @@ void ata_init() { pci_scan(&ata_find, -1, &ata_device); - irq_install_handler(32 + 14, ata_handler); + irq_install_handler(14, ata_handler); ata_device_detect(&primary_master, 1); ata_device_detect(&primary_slave, 1); - ata_device_detect(&secondary_master, 0); - ata_device_detect(&secondary_slave, 0); + /* ata_device_detect(&secondary_master, 0); */ + /* ata_device_detect(&secondary_slave, 0); */ } diff --git a/src/kernel/fs/ata.h b/src/kernel/fs/ata.h index 72ded20..4a2951f 100644 --- a/src/kernel/fs/ata.h +++ b/src/kernel/fs/ata.h @@ -1,7 +1,7 @@ #ifndef ATA_DRIVER_H #define ATA_DRIVER_H -#include +#include #include #include @@ -56,7 +56,7 @@ typedef struct ata_dev { char mountpoint[32]; } __attribute__((packed)) ata_dev_t; -// ATA PCI info +// ATA PCI info of QEMU // TODO: Remove Qemu based device id #define ATA_VENDOR_ID 0x8086 #define ATA_DEVICE_ID 0x7010 @@ -116,4 +116,4 @@ void ata_device_detect(ata_dev_t *dev, int primary); void ata_init(); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/fs/elf.c b/src/kernel/fs/elf.c index b6d90c9..493bdac 100644 --- a/src/kernel/fs/elf.c +++ b/src/kernel/fs/elf.c @@ -40,16 +40,16 @@ uint32_t load_elf(char *elf_data) v_begin = p_entry->vaddr; v_end = p_entry->vaddr + p_entry->memsz; if (v_begin < USER_OFFSET) { - warn("load_elf(): can't load executable below %x\n", USER_OFFSET); + warn("load_elf(): can't load executable below %x", USER_OFFSET); return 0; } if (v_end > USER_STACK) { - warn("load_elf(): can't load executable above %x\n", USER_STACK); + warn("load_elf(): can't load executable above %x", USER_STACK); return 0; } - printf("ELF: entry flags: %x (%d)\n", p_entry->flags, p_entry->flags); + log("ELF: entry flags: %x (%d)", p_entry->flags, p_entry->flags); memcpy((uint8_t *)v_begin, (uint8_t *)(elf_data + p_entry->offset), p_entry->filesz); @@ -63,4 +63,4 @@ uint32_t load_elf(char *elf_data) } return hdr->entry; -} \ No newline at end of file +} diff --git a/src/kernel/fs/ext2.c b/src/kernel/fs/ext2.c new file mode 100644 index 0000000..bc17db6 --- /dev/null +++ b/src/kernel/fs/ext2.c @@ -0,0 +1,787 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +uint32_t ext2_file_size(vfs_node_t *node) +{ + ext2_fs_t *ext2fs = node->device; + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, node->inode_num); + uint32_t ret = inode->size; + kfree(inode); + return ret; +} + +void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission) +{ + ext2_fs_t *ext2fs = parent->device; + uint32_t inode_idx = alloc_inode(ext2fs); + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, inode_idx); + inode->permission = EXT2_S_IFDIR; + inode->permission |= 0xFFF & permission; + inode->atime = 0; + inode->ctime = 0; + inode->dtime = 0; + inode->gid = 0; + inode->userid = 0; + inode->f_block_addr = 0; + inode->num_sectors = 0; + inode->size = ext2fs->block_size; + inode->hard_links = 2; + inode->flags = 0; + inode->file_acl = 0; + inode->dir_acl = 0; + inode->generation = 0; + inode->os_specific1 = 0; + memset(inode->blocks, 0, sizeof(inode->blocks)); + memset(inode->os_specific2, 0, 12); + alloc_inode_block(ext2fs, inode, inode_idx, 0); + write_inode_metadata(ext2fs, inode, inode_idx); + ext2_create_entry(parent, name, inode_idx); + + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + p_inode->hard_links++; + write_inode_metadata(ext2fs, p_inode, parent->inode_num); + rewrite_bgds(ext2fs); +} + +void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission) +{ + ext2_fs_t *ext2fs = parent->device; + uint32_t inode_idx = alloc_inode(ext2fs); + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, inode_idx); + inode->permission = EXT2_S_IFREG; + inode->permission |= 0xFFF & permission; + inode->atime = 0; + inode->ctime = 0; + inode->dtime = 0; + inode->gid = 0; + inode->userid = 0; + inode->f_block_addr = 0; + inode->num_sectors = 0; + inode->size = ext2fs->block_size; + inode->hard_links = 2; + inode->flags = 0; + inode->file_acl = 0; + inode->dir_acl = 0; + inode->generation = 0; + inode->os_specific1 = 0; + memset(inode->blocks, 0, sizeof(inode->blocks)); + memset(inode->os_specific2, 0, 12); + alloc_inode_block(ext2fs, inode, inode_idx, 0); + write_inode_metadata(ext2fs, inode, inode_idx); + ext2_create_entry(parent, name, inode_idx); + + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + p_inode->hard_links++; + write_inode_metadata(ext2fs, p_inode, parent->inode_num); + rewrite_bgds(ext2fs); +} + +void ext2_unlink(vfs_node_t *parent, char *name) +{ + ext2_fs_t *ext2fs = parent->device; + ext2_remove_entry(parent, name); + + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + p_inode->hard_links--; + write_inode_metadata(ext2fs, p_inode, parent->inode_num); + rewrite_bgds(ext2fs); +} + +char **ext2_listdir(vfs_node_t *parent) +{ + ext2_fs_t *ext2fs = parent->device; + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + uint32_t curr_offset = 0; + uint32_t block_offset = 0; + uint32_t in_block_offset = 0; + int size = 0, cap = 10; + char **ret = kmalloc(sizeof(char *) * cap); + char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); + while (curr_offset < p_inode->size) { + if (in_block_offset >= ext2fs->block_size) { + block_offset++; + in_block_offset = 0; + block_buf = read_inode_block(ext2fs, p_inode, block_offset); + } + if (size + 1 == cap) { + ret = krealloc(ret, sizeof(char *) * cap * 2); + cap = cap * 2; + } + + direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); + if (curr_dir->inode != 0) { + char *temp = kcalloc(curr_dir->name_len + 1, 1); + memcpy(temp, curr_dir->name, curr_dir->name_len); + ret[size++] = temp; + } + uint32_t expected_size = + ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; + uint32_t real_size = curr_dir->size; + if (real_size != expected_size) { + break; + } + in_block_offset += curr_dir->size; + curr_offset += curr_dir->size; + } + ret[size] = NULL; + return ret; +} + +vfs_node_t *vfsnode_from_direntry(ext2_fs_t *ext2fs, direntry_t *dir, inode_t *inode) +{ + vfs_node_t *ret = kcalloc(sizeof(vfs_node_t), 1); + + ret->device = (void *)ext2fs; + ret->inode_num = dir->inode; + memcpy(ret->name, dir->name, dir->name_len); + + ret->uid = inode->userid; + ret->uid = inode->gid; + ret->size = inode->size; + ret->mask = inode->permission & 0xFFF; + ret->nlink = inode->hard_links; + + ret->flags = 0; + if ((inode->permission & EXT2_S_IFREG) == EXT2_S_IFREG) { + ret->flags |= FS_FILE; + ret->read = ext2_read; + ret->write = ext2_write; + ret->unlink = ext2_unlink; + ret->get_file_size = ext2_file_size; + } + if ((inode->permission & EXT2_S_IFDIR) == EXT2_S_IFDIR) { + ret->flags |= FS_DIRECTORY; + ret->mkdir = ext2_mkdir; + ret->finddir = ext2_finddir; + ret->unlink = ext2_unlink; + ret->create = ext2_mkfile; + ret->listdir = ext2_listdir; + ret->read = ext2_read; + ret->write = ext2_write; + } + if ((inode->permission & EXT2_S_IFBLK) == EXT2_S_IFBLK) { + ret->flags |= FS_BLOCKDEVICE; + } + if ((inode->permission & EXT2_S_IFCHR) == EXT2_S_IFCHR) { + ret->flags |= FS_CHARDEVICE; + } + if ((inode->permission & EXT2_S_IFIFO) == EXT2_S_IFIFO) { + ret->flags |= FS_PIPE; + } + if ((inode->permission & EXT2_S_IFLNK) == EXT2_S_IFLNK) { + ret->flags |= FS_SYMLINK; + } + + ret->access_time = inode->atime; + ret->modified_time = inode->mtime; + ret->create_time = inode->ctime; + + ret->chmod = ext2_chmod; + ret->open = ext2_open; + ret->close = ext2_close; + return ret; +} + +vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name) +{ + ext2_fs_t *ext2fs = parent->device; + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + uint32_t expected_size; + uint32_t real_size; + uint32_t curr_offset = 0; + uint32_t block_offset = 0; + uint32_t in_block_offset = 0; + char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); + while (curr_offset < p_inode->size) { + if (in_block_offset >= ext2fs->block_size) { + block_offset++; + in_block_offset = 0; + block_buf = read_inode_block(ext2fs, p_inode, block_offset); + } + + direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); + char *temp = kcalloc(curr_dir->name_len + 1, 1); + memcpy(temp, curr_dir->name, curr_dir->name_len); + if (curr_dir->inode != 0 && !strcmp(temp, name)) { + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, curr_dir->inode); + return vfsnode_from_direntry(ext2fs, curr_dir, inode); + } + if (((sizeof(direntry_t) + curr_dir->name_len) & 0x00000003) != 0) + expected_size = + ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; + else + expected_size = ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc); + real_size = curr_dir->size; + if (real_size != expected_size) { + break; + } + in_block_offset += curr_dir->size; + curr_offset += curr_dir->size; + } + return NULL; +} + +void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode) +{ + ext2_fs_t *ext2fs = parent->device; + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + uint32_t curr_offset = 0; + uint32_t block_offset = 0; + uint32_t in_block_offset = 0; + uint32_t found = 0; + uint32_t entry_name_len = strlen(entry_name); + char *check = kcalloc(entry_name_len + 1, 1); + char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); + + while (curr_offset < p_inode->size) { + if (in_block_offset >= ext2fs->block_size) { + block_offset++; + in_block_offset = 0; + block_buf = read_inode_block(ext2fs, p_inode, block_offset); + } + direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); + if (curr_dir->name_len == entry_name_len) { + memcpy(check, curr_dir->name, entry_name_len); + if (curr_dir->inode != 0 && !strcmp(entry_name, check)) { + log("Entry by the same name %s already exist", check); + return; + } + } + if (found) { + curr_dir->inode = entry_inode; + curr_dir->size = + (uint32_t)block_buf + ext2fs->block_size - (uint32_t)curr_dir; + curr_dir->name_len = strlen(entry_name); + curr_dir->type = 0; + memcpy(curr_dir->name, entry_name, strlen(entry_name)); + write_inode_block(ext2fs, p_inode, block_offset, block_buf); + in_block_offset += curr_dir->size; + if (in_block_offset >= ext2fs->block_size) { + block_offset++; + in_block_offset = 0; + block_buf = read_inode_block(ext2fs, p_inode, block_offset); + } + curr_dir = (direntry_t *)(block_buf + in_block_offset); + memset(curr_dir, 0, sizeof(direntry_t)); + write_inode_block(ext2fs, p_inode, block_offset, block_buf); + return; + } + uint32_t expected_size = + ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; + uint32_t real_size = curr_dir->size; + if (real_size != expected_size) { + found = 1; + curr_dir->size = expected_size; + in_block_offset += expected_size; + curr_offset += expected_size; + continue; + } + in_block_offset += curr_dir->size; + curr_offset += curr_dir->size; + } +} + +void ext2_remove_entry(vfs_node_t *parent, char *entry_name) +{ + ext2_fs_t *ext2fs = parent->device; + inode_t *p_inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, p_inode, parent->inode_num); + uint32_t curr_offset = 0; + uint32_t block_offset = 0; + uint32_t in_block_offset = 0; + uint32_t entry_name_len = strlen(entry_name); + char *check = kcalloc(entry_name_len + 1, 1); + char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); + while (curr_offset < p_inode->size) { + if (in_block_offset >= ext2fs->block_size) { + block_offset++; + in_block_offset = 0; + block_buf = read_inode_block(ext2fs, p_inode, block_offset); + } + direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); + if (curr_dir->name_len == entry_name_len) { + memcpy(check, curr_dir->name, entry_name_len); + if (curr_dir->inode != 0 && !strcmp(entry_name, check)) { + curr_dir->inode = 0; + write_inode_block(ext2fs, p_inode, block_offset, block_buf); + return; + } + } + uint32_t expected_size = + ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; + uint32_t real_size = curr_dir->size; + if (real_size != expected_size) + return; + in_block_offset += curr_dir->size; + curr_offset += curr_dir->size; + } +} + +void ext2_chmod(vfs_node_t *file, uint32_t mode) +{ + ext2_fs_t *ext2fs = file->device; + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, file->inode_num); + inode->permission = (inode->permission & 0xFFFFF000) | mode; + write_inode_metadata(ext2fs, inode, file->inode_num); +} + +uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf) +{ + ext2_fs_t *ext2fs = file->device; + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, file->inode_num); + read_inode_filedata(ext2fs, inode, offset, size, buf); + return size; +} + +uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf) +{ + ext2_fs_t *ext2fs = file->device; + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, file->inode_num); + write_inode_filedata(ext2fs, inode, file->inode_num, offset, size, buf); + return size; +} + +void ext2_open(vfs_node_t *file, uint32_t flags) +{ + ext2_fs_t *ext2fs = file->device; + if (flags & O_TRUNC) { + inode_t *inode = kmalloc(sizeof(inode_t)); + read_inode_metadata(ext2fs, inode, file->inode_num); + inode->size = 0; + write_inode_metadata(ext2fs, inode, file->inode_num); + } +} + +void ext2_close() +{ + return; +} + +void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx) +{ + uint32_t group = inode_idx / ext2fs->inodes_per_group; + uint32_t inode_table_block = ext2fs->bgds[group].inode_table; + uint32_t idx_in_group = inode_idx - group * ext2fs->inodes_per_group; + uint32_t block_offset = (idx_in_group - 1) * ext2fs->sb->inode_size / ext2fs->block_size; + uint32_t offset_in_block = + (idx_in_group - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size); + char *block_buf = kmalloc(ext2fs->block_size); + read_disk_block(ext2fs, inode_table_block + block_offset, block_buf); + memcpy(inode, block_buf + offset_in_block * ext2fs->sb->inode_size, ext2fs->sb->inode_size); + kfree(block_buf); +} + +void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx) +{ + uint32_t group = inode_idx / ext2fs->inodes_per_group; + uint32_t inode_table_block = ext2fs->bgds[group].inode_table; + uint32_t block_offset = (inode_idx - 1) * ext2fs->sb->inode_size / ext2fs->block_size; + uint32_t offset_in_block = + (inode_idx - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size); + char *block_buf = kmalloc(ext2fs->block_size); + read_disk_block(ext2fs, inode_table_block + block_offset, block_buf); + memcpy(block_buf + offset_in_block * ext2fs->sb->inode_size, inode, ext2fs->sb->inode_size); + write_disk_block(ext2fs, inode_table_block + block_offset, block_buf); + kfree(block_buf); +} + +uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size, + char *buf) +{ + uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size); + uint32_t start_block = offset / ext2fs->block_size; + uint32_t end_block = end_offset / ext2fs->block_size; + uint32_t start_off = offset % ext2fs->block_size; + uint32_t end_size = end_offset - end_block * ext2fs->block_size; + + uint32_t i = start_block; + uint32_t curr_off = 0; + while (i <= end_block) { + uint32_t left = 0, right = ext2fs->block_size - 1; + char *block_buf = read_inode_block(ext2fs, inode, i); + if (i == start_block) + left = start_off; + if (i == end_block) + right = end_size - 1; + memcpy(buf + curr_off, block_buf + left, (right - left + 1)); + curr_off = curr_off + (right - left + 1); + kfree(block_buf); + i++; + } + return end_offset - offset; +} + +void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset, + uint32_t size, char *buf) +{ + if (offset + size > inode->size) { + inode->size = offset + size; + write_inode_metadata(ext2fs, inode, inode_idx); + } + uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size); + uint32_t start_block = offset / ext2fs->block_size; + uint32_t end_block = end_offset / ext2fs->block_size; + uint32_t start_off = offset % ext2fs->block_size; + uint32_t end_size = end_offset - end_block * ext2fs->block_size; + + uint32_t i = start_block; + uint32_t curr_off = 0; + while (i <= end_block) { + uint32_t left = 0, right = ext2fs->block_size; + char *block_buf = read_inode_block(ext2fs, inode, i); + + if (i == start_block) + left = start_off; + if (i == end_block) + right = end_size - 1; + memcpy(block_buf + left, buf + curr_off, (right - left + 1)); + curr_off = curr_off + (right - left + 1); + write_inode_block(ext2fs, inode, i, block_buf); + kfree(block_buf); + i++; + } +} + +char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock) +{ + char *buf = kmalloc(ext2fs->block_size); + uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock); + read_disk_block(ext2fs, disk_block, buf); + return buf; +} + +void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf) +{ + uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock); + write_disk_block(ext2fs, disk_block, buf); +} + +void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf) +{ + vfs_read(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf); +} + +void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf) +{ + vfs_write(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf); +} + +void rewrite_bgds(ext2_fs_t *ext2fs) +{ + for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++) + write_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size); +} + +void rewrite_superblock(ext2_fs_t *ext2fs) +{ + write_disk_block(ext2fs, 1, (void *)ext2fs->sb); +} + +int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode, + uint32_t inode_idx, char *buffer, unsigned int block_overwrite) +{ + if (!(*block_ptr)) { + unsigned int block_no = ext2_alloc_block(ext2fs); + if (!block_no) + return 0; + *block_ptr = block_no; + if (buffer) + write_disk_block(ext2fs, block_overwrite, (void *)buffer); + else + write_inode_metadata(ext2fs, inode, inode_idx); + return 1; + } + return 0; +} + +uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block) +{ + unsigned int p = ext2fs->block_size / 4; + int a, b, c, d, e, f, g; + uint32_t *tmp = kmalloc(ext2fs->block_size); + uint32_t ret = -1; + a = inode_block - EXT2_DIRECT_BLOCKS; + if (a < 0) { + ret = inode->blocks[inode_block]; + goto done; + } + b = a - p; + if (b < 0) { + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); + ret = tmp[a]; + goto done; + } + c = b - p * p; + if (c < 0) { + c = b / p; + d = b - c * p; + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp); + read_disk_block(ext2fs, tmp[c], (void *)tmp); + ret = tmp[d]; + goto done; + } + d = c - p * p * p; + if (d < 0) { + e = c / (p * p); + f = (c - e * p * p) / p; + g = (c - e * p * p - f * p); + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp); + read_disk_block(ext2fs, tmp[e], (void *)tmp); + read_disk_block(ext2fs, tmp[f], (void *)tmp); + ret = tmp[g]; + goto done; + } +done: + kfree(tmp); + return ret; +} + +void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, + uint32_t inode_block, uint32_t disk_block) +{ + unsigned int p = ext2fs->block_size / 4; + int a, b, c, d, e, f, g; + int iblock = inode_block; + uint32_t *tmp = kmalloc(ext2fs->block_size); + + a = iblock - EXT2_DIRECT_BLOCKS; + if (a <= 0) { + inode->blocks[inode_block] = disk_block; + goto done; + } + b = a - p; + if (b <= 0) { + if(!alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS]), ext2fs, inode, inode_idx, NULL, 0)); + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); + ((unsigned int *)tmp)[a] = disk_block; + write_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); + tmp[a] = disk_block; + goto done; + } + c = b - p * p; + if (c <= 0) { + c = b / p; + d = b - c * p; + if(!alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 1]), ext2fs, inode, inode_idx, NULL, 0)); + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp); + if(!alloc_inode_metadata_block(&(tmp[c]), ext2fs, inode, inode_idx, (void*)tmp, inode->blocks[EXT2_DIRECT_BLOCKS + 1])); + unsigned int temp = tmp[c]; + read_disk_block(ext2fs, temp, (void *)tmp); + tmp[d] = disk_block; + write_disk_block(ext2fs, temp, (void *)tmp); + goto done; + } + d = c - p * p * p; + if (d <= 0) { + e = c / (p * p); + f = (c - e * p * p) / p; + g = (c - e * p * p - f * p); + if(!alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 2]), ext2fs, inode, inode_idx, NULL, 0)); + read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp); + if(!alloc_inode_metadata_block(&(tmp[e]), ext2fs, inode, inode_idx, (void*)tmp, inode->blocks[EXT2_DIRECT_BLOCKS + 2])); + unsigned int temp = tmp[e]; + read_disk_block(ext2fs, tmp[e], (void *)tmp); + if(!alloc_inode_metadata_block(&(tmp[f]), ext2fs, inode, inode_idx, (void*)tmp, temp)); + temp = tmp[f]; + read_disk_block(ext2fs, tmp[f], (void *)tmp); + tmp[g] = disk_block; + write_disk_block(ext2fs, temp, (void *)tmp); + goto done; + } +done: + kfree(tmp); +} + +uint32_t ext2_alloc_block(ext2_fs_t *ext2fs) +{ + uint32_t *buf = kcalloc(ext2fs->block_size, 1); + for (uint32_t i = 0; i < ext2fs->total_groups; i++) { + if (!ext2fs->bgds[i].free_blocks) + continue; + + uint32_t bitmap_block = ext2fs->bgds[i].block_bitmap; + read_disk_block(ext2fs, bitmap_block, (void *)buf); + for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) { + uint32_t sub_bitmap = buf[j]; + if (sub_bitmap == 0xFFFFFFFF) + continue; + for (uint32_t k = 0; k < 32; k++) { + uint32_t free = !((sub_bitmap >> k) & 0x1); + if (free) { + uint32_t mask = (0x1 << k); + buf[j] = buf[j] | mask; + write_disk_block(ext2fs, bitmap_block, (void *)buf); + ext2fs->bgds[i].free_blocks--; + rewrite_bgds(ext2fs); + return i * ext2fs->blocks_per_group + j * 32 + k; + } + } + } + } + panic("We're out of blocks!"); + return (uint32_t)-1; +} + +void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block) +{ + uint32_t *buf = kcalloc(ext2fs->block_size, 1); + uint32_t group_idx = block / ext2fs->blocks_per_group; + uint32_t sub_bitmap_idx = (block - (ext2fs->blocks_per_group * group_idx)) / 4; + uint32_t idx = (block - (ext2fs->blocks_per_group * group_idx)) % 4; + + uint32_t bitmap_block = ext2fs->bgds[group_idx].block_bitmap; + read_disk_block(ext2fs, bitmap_block, (void *)buf); + + uint32_t mask = ~(0x1 << idx); + buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask; + + write_disk_block(ext2fs, bitmap_block, (void *)buf); + + ext2fs->bgds[group_idx].free_blocks++; + rewrite_bgds(ext2fs); +} + +void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block) +{ + uint32_t ret = ext2_alloc_block(ext2fs); + set_disk_block_number(ext2fs, inode, inode_idx, block, ret); + inode->num_sectors = (block + 1) * (ext2fs->block_size / 512); + write_inode_metadata(ext2fs, inode, inode_idx); +} + +void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block) +{ + uint32_t ret = get_disk_block_number(ext2fs, inode, block); + ext2_free_block(ext2fs, ret); + set_disk_block_number(ext2fs, inode, inode_idx, ret, 0); + write_inode_metadata(ext2fs, inode, inode_idx); +} + +uint32_t alloc_inode(ext2_fs_t *ext2fs) +{ + uint32_t *buf = kcalloc(ext2fs->block_size, 1); + for (uint32_t i = 0; i < ext2fs->total_groups; i++) { + if (!ext2fs->bgds[i].free_inodes) + continue; + + uint32_t bitmap_block = ext2fs->bgds[i].inode_bitmap; + read_disk_block(ext2fs, bitmap_block, (void *)buf); + for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) { + uint32_t sub_bitmap = buf[j]; + if (sub_bitmap == 0xFFFFFFFF) + continue; + for (uint32_t k = 0; k < 32; k++) { + uint32_t free = !((sub_bitmap >> k) & 0x1); + if (free) { + uint32_t mask = (0x1 << k); + buf[j] = buf[j] | mask; + write_disk_block(ext2fs, bitmap_block, (void *)buf); + ext2fs->bgds[i].free_inodes--; + rewrite_bgds(ext2fs); + return i * ext2fs->inodes_per_group + j * 32 + k; + } + } + } + } + panic("We're out of inodes!"); + return (uint32_t)-1; +} + +void free_inode(ext2_fs_t *ext2fs, uint32_t inode) +{ + uint32_t *buf = kcalloc(ext2fs->block_size, 1); + uint32_t group_idx = inode / ext2fs->inodes_per_group; + uint32_t sub_bitmap_idx = (inode - (ext2fs->inodes_per_group * group_idx)) / 4; + uint32_t idx = (inode - (ext2fs->inodes_per_group * group_idx)) % 4; + + uint32_t bitmap_block = ext2fs->bgds[group_idx].inode_bitmap; + read_disk_block(ext2fs, bitmap_block, (void *)buf); + + uint32_t mask = ~(0x1 << idx); + buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask; + + write_disk_block(ext2fs, bitmap_block, (void *)buf); + + ext2fs->bgds[group_idx].free_inodes++; + rewrite_bgds(ext2fs); +} + +vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode) +{ + vfs_node_t *ext2root = kcalloc(sizeof(vfs_node_t), 1); + strcpy(ext2root->name, "/"); + ext2root->device = ext2fs; + ext2root->mask = inode->permission; + ext2root->inode_num = ROOT_INODE_NUMBER; + + ext2root->access_time = inode->atime; + ext2root->modified_time = inode->mtime; + ext2root->create_time = inode->ctime; + + ext2root->flags |= FS_DIRECTORY; + ext2root->read = NULL; + ext2root->write = NULL; + ext2root->chmod = ext2_chmod; + ext2root->open = ext2_open; + ext2root->close = ext2_close; + ext2root->read = ext2_read; + ext2root->write = ext2_write; + ext2root->mkdir = ext2_mkdir; + ext2root->create = ext2_mkfile; + ext2root->listdir = ext2_listdir; + ext2root->finddir = ext2_finddir; + ext2root->unlink = ext2_unlink; + return ext2root; +} + +void ext2_init(char *device_path, char *mountpoint) +{ + ext2_fs_t *ext2fs = kcalloc(sizeof(ext2_fs_t), 1); + ext2fs->disk_device = file_open(device_path, 0); + log("%s", ext2fs->disk_device->name); + ext2fs->sb = kmalloc(SUPERBLOCK_SIZE); + ext2fs->block_size = 1024; + read_disk_block(ext2fs, 1, (void *)ext2fs->sb); //! + log("%x", ext2fs->sb->ext2_magic); + log("%x", ext2fs->sb->total_inodes); + ext2fs->block_size = (1024 << ext2fs->sb->log2block_size); + ext2fs->blocks_per_group = ext2fs->sb->blocks_per_group; + ext2fs->inodes_per_group = ext2fs->sb->inodes_per_group; + + ext2fs->total_groups = ext2fs->sb->total_blocks / + ext2fs->blocks_per_group; // REMEMBER: Zero Division Exception + if (ext2fs->blocks_per_group * ext2fs->total_groups < ext2fs->total_groups) + ext2fs->total_groups++; + + ext2fs->bgd_blocks = (ext2fs->total_groups * sizeof(bgd_t)) / ext2fs->block_size; + if (ext2fs->bgd_blocks * ext2fs->block_size < ext2fs->total_groups * sizeof(bgd_t)) + ext2fs->bgd_blocks++; + + ext2fs->bgds = kcalloc(sizeof(bgd_t), ext2fs->bgd_blocks * ext2fs->block_size); + for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++) { + read_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size); + } + + inode_t *root_inode = kcalloc(sizeof(inode_t), 1); + read_inode_metadata(ext2fs, root_inode, ROOT_INODE_NUMBER); + vfs_mount(mountpoint, get_ext2_root(ext2fs, root_inode)); +} diff --git a/src/kernel/fs/ext2.h b/src/kernel/fs/ext2.h new file mode 100644 index 0000000..62105c7 --- /dev/null +++ b/src/kernel/fs/ext2.h @@ -0,0 +1,211 @@ +#ifndef MELVIX_EXT2_H +#define MELVIX_EXT2_H + +#include +#include + +#define EXT2_DIRECT_BLOCKS 12 + +#define SUPERBLOCK_SIZE 1024 +#define ROOT_INODE_NUMBER 2 + +#define EXT2_S_IFSOCK 0xC000 +#define EXT2_S_IFLNK 0xA000 +#define EXT2_S_IFREG 0x8000 +#define EXT2_S_IFBLK 0x6000 +#define EXT2_S_IFDIR 0x4000 +#define EXT2_S_IFCHR 0x2000 +#define EXT2_S_IFIFO 0x1000 + +// http://wiki.osdev.org/Ext2#Locating_the_Superblock +typedef struct superblock { + uint32_t total_inodes; + uint32_t total_blocks; + uint32_t su_blocks; + uint32_t free_blocks; + uint32_t free_inodes; + uint32_t superblock_idx; + uint32_t log2block_size; + uint32_t log2frag_size; + uint32_t blocks_per_group; + uint32_t frags_per_group; + uint32_t inodes_per_group; + + uint32_t mtime; + uint32_t wtime; + + uint16_t mount_count; + uint16_t mount_allowed_count; + uint16_t ext2_magic; + uint16_t fs_state; + uint16_t err; + uint16_t minor; + + uint32_t last_check; + uint32_t interval; + uint32_t os_id; + uint32_t major; + + uint16_t r_userid; + uint16_t r_groupid; + + // Extensions + uint32_t first_inode; + uint16_t inode_size; + uint16_t superblock_group; + uint32_t optional_feature; + uint32_t required_feature; + uint32_t readonly_feature; + char fs_id[16]; + char vol_name[16]; + char last_mount_path[64]; + uint32_t compression_method; + uint8_t file_pre_alloc_blocks; + uint8_t dir_pre_alloc_blocks; + uint16_t unused1; + char journal_id[16]; + uint32_t journal_inode; + uint32_t journal_device; + uint32_t orphan_head; + + char unused2[1024 - 236]; +} __attribute__((packed)) superblock_t; + +typedef struct bgd { + uint32_t block_bitmap; + uint32_t inode_bitmap; + uint32_t inode_table; + uint32_t free_blocks; + uint32_t free_inodes; + uint32_t num_dirs; + uint32_t unused1; + uint32_t unused2; +} __attribute__((packed)) bgd_t; + +typedef struct direntry { + uint32_t inode; + uint16_t size; + uint8_t name_len; + uint8_t type; + char name[]; +} __attribute__((packed)) direntry_t; + +typedef struct inode { + uint16_t permission; + uint16_t userid; + uint32_t size; + uint32_t atime; + uint32_t ctime; + uint32_t mtime; + uint32_t dtime; + uint16_t gid; + uint16_t hard_links; + uint32_t num_sectors; + uint32_t flags; + uint32_t os_specific1; + uint32_t blocks[EXT2_DIRECT_BLOCKS + 3]; + uint32_t generation; + uint32_t file_acl; + union { + uint32_t dir_acl; + uint32_t size_high; + }; + uint32_t f_block_addr; + char os_specific2[12]; +} __attribute__((packed)) inode_t; + +typedef struct ext2_cache { + uint32_t block; + uint32_t times; + uint8_t dirty; + char *block_data; +} ext2_cache_t; + +typedef struct ext2_fs { + vfs_node_t *disk_device; + + superblock_t *sb; + bgd_t *bgds; + uint32_t block_size; + uint32_t blocks_per_group; + uint32_t inodes_per_group; + uint32_t total_groups; + + uint32_t bgd_blocks; +} ext2_fs_t; + +uint32_t ext2_file_size(vfs_node_t *node); + +void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission); + +void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission); + +void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode); + +void ext2_unlink(vfs_node_t *parent, char *name); + +char **ext2_listdir(vfs_node_t *parent); + +vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name); + +void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode); + +void ext2_remove_entry(vfs_node_t *parent, char *entry_name); + +void ext2_chmod(vfs_node_t *file, uint32_t mode); + +uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf); + +uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf); + +void ext2_open(vfs_node_t *file, uint32_t flags); + +void ext2_close(); + +void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx); + +void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx); + +uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size, + char *buf); + +void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset, + uint32_t size, char *buf); + +char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock); + +void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf); + +void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf); + +void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf); + +void rewrite_bgds(ext2_fs_t *ext2fs); + +void rewrite_superblock(ext2_fs_t *ext2fs); + +int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode, + uint32_t inode_idx, char *buffer, unsigned int block_overwrite); + +uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block); + +void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, + uint32_t inode_block, uint32_t disk_block); + +uint32_t ext2_alloc_block(ext2_fs_t *ext2fs); + +void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block); + +void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block); + +void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block); + +uint32_t alloc_inode(ext2_fs_t *ext2fs); + +void free_inode(ext2_fs_t *ext2fs, uint32_t inode); + +vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode); + +void ext2_init(char *device_path, char *mountpoint); + +#endif diff --git a/src/kernel/fs/ext2/ext2.c b/src/kernel/fs/ext2/ext2.c deleted file mode 100644 index b14d726..0000000 --- a/src/kernel/fs/ext2/ext2.c +++ /dev/null @@ -1,790 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -uint32_t ext2_file_size(vfs_node_t *node) -{ - ext2_fs_t *ext2fs = node->device; - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, node->inode_num); - uint32_t ret = inode->size; - kfree(inode); - return ret; -} - -void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission) -{ - ext2_fs_t *ext2fs = parent->device; - uint32_t inode_idx = alloc_inode(ext2fs); - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, inode_idx); - inode->permission = EXT2_S_IFDIR; - inode->permission |= 0xFFF & permission; - inode->atime = 0; - inode->ctime = 0; - inode->dtime = 0; - inode->gid = 0; - inode->userid = 0; - inode->f_block_addr = 0; - inode->num_sectors = 0; - inode->size = ext2fs->block_size; - inode->hard_links = 2; - inode->flags = 0; - inode->file_acl = 0; - inode->dir_acl = 0; - inode->generation = 0; - inode->os_specific1 = 0; - memset(inode->blocks, 0, sizeof(inode->blocks)); - memset(inode->os_specific2, 0, 12); - alloc_inode_block(ext2fs, inode, inode_idx, 0); - write_inode_metadata(ext2fs, inode, inode_idx); - ext2_create_entry(parent, name, inode_idx); - - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - p_inode->hard_links++; - write_inode_metadata(ext2fs, p_inode, parent->inode_num); - rewrite_bgds(ext2fs); -} - -void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission) -{ - ext2_fs_t *ext2fs = parent->device; - uint32_t inode_idx = alloc_inode(ext2fs); - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, inode_idx); - inode->permission = EXT2_S_IFREG; - inode->permission |= 0xFFF & permission; - inode->atime = 0; - inode->ctime = 0; - inode->dtime = 0; - inode->gid = 0; - inode->userid = 0; - inode->f_block_addr = 0; - inode->num_sectors = 0; - inode->size = ext2fs->block_size; - inode->hard_links = 2; - inode->flags = 0; - inode->file_acl = 0; - inode->dir_acl = 0; - inode->generation = 0; - inode->os_specific1 = 0; - memset(inode->blocks, 0, sizeof(inode->blocks)); - memset(inode->os_specific2, 0, 12); - alloc_inode_block(ext2fs, inode, inode_idx, 0); - write_inode_metadata(ext2fs, inode, inode_idx); - ext2_create_entry(parent, name, inode_idx); - - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - p_inode->hard_links++; - write_inode_metadata(ext2fs, p_inode, parent->inode_num); - rewrite_bgds(ext2fs); -} - -void ext2_unlink(vfs_node_t *parent, char *name) -{ - ext2_fs_t *ext2fs = parent->device; - ext2_remove_entry(parent, name); - - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - p_inode->hard_links--; - write_inode_metadata(ext2fs, p_inode, parent->inode_num); - rewrite_bgds(ext2fs); -} - -char **ext2_listdir(vfs_node_t *parent) -{ - ext2_fs_t *ext2fs = parent->device; - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - uint32_t curr_offset = 0; - uint32_t block_offset = 0; - uint32_t in_block_offset = 0; - int size = 0, cap = 10; - char **ret = kmalloc(sizeof(char *) * cap); - char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); - while (curr_offset < p_inode->size) { - if (in_block_offset >= ext2fs->block_size) { - block_offset++; - in_block_offset = 0; - block_buf = read_inode_block(ext2fs, p_inode, block_offset); - } - if (size + 1 == cap) { - ret = krealloc(ret, sizeof(char *) * cap * 2); - cap = cap * 2; - } - - direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); - if (curr_dir->inode != 0) { - char *temp = kcalloc(curr_dir->name_len + 1, 1); - memcpy(temp, curr_dir->name, curr_dir->name_len); - ret[size++] = temp; - } - uint32_t expected_size = - ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; - uint32_t real_size = curr_dir->size; - if (real_size != expected_size) { - break; - } - in_block_offset += curr_dir->size; - curr_offset += curr_dir->size; - } - ret[size] = NULL; - return ret; -} - -vfs_node_t *vfsnode_from_direntry(ext2_fs_t *ext2fs, direntry_t *dir, inode_t *inode) -{ - vfs_node_t *ret = kcalloc(sizeof(vfs_node_t), 1); - - ret->device = (void *)ext2fs; - ret->inode_num = dir->inode; - memcpy(ret->name, dir->name, dir->name_len); - - ret->uid = inode->userid; - ret->uid = inode->gid; - ret->size = inode->size; - ret->mask = inode->permission & 0xFFF; - ret->nlink = inode->hard_links; - - ret->flags = 0; - if ((inode->permission & EXT2_S_IFREG) == EXT2_S_IFREG) { - ret->flags |= FS_FILE; - ret->read = ext2_read; - ret->write = ext2_write; - ret->unlink = ext2_unlink; - ret->get_file_size = ext2_file_size; - } - if ((inode->permission & EXT2_S_IFDIR) == EXT2_S_IFDIR) { - ret->flags |= FS_DIRECTORY; - ret->mkdir = ext2_mkdir; - ret->finddir = ext2_finddir; - ret->unlink = ext2_unlink; - ret->create = ext2_mkfile; - ret->listdir = ext2_listdir; - ret->read = ext2_read; - ret->write = ext2_write; - } - if ((inode->permission & EXT2_S_IFBLK) == EXT2_S_IFBLK) { - ret->flags |= FS_BLOCKDEVICE; - } - if ((inode->permission & EXT2_S_IFCHR) == EXT2_S_IFCHR) { - ret->flags |= FS_CHARDEVICE; - } - if ((inode->permission & EXT2_S_IFIFO) == EXT2_S_IFIFO) { - ret->flags |= FS_PIPE; - } - if ((inode->permission & EXT2_S_IFLNK) == EXT2_S_IFLNK) { - ret->flags |= FS_SYMLINK; - } - - ret->access_time = inode->atime; - ret->modified_time = inode->mtime; - ret->create_time = inode->ctime; - - ret->chmod = ext2_chmod; - ret->open = ext2_open; - ret->close = ext2_close; - return ret; -} - -vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name) -{ - ext2_fs_t *ext2fs = parent->device; - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - uint32_t expected_size; - uint32_t real_size; - uint32_t curr_offset = 0; - uint32_t block_offset = 0; - uint32_t in_block_offset = 0; - char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); - while (curr_offset < p_inode->size) { - if (in_block_offset >= ext2fs->block_size) { - block_offset++; - in_block_offset = 0; - block_buf = read_inode_block(ext2fs, p_inode, block_offset); - } - - direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); - char *temp = kcalloc(curr_dir->name_len + 1, 1); - memcpy(temp, curr_dir->name, curr_dir->name_len); - if (curr_dir->inode != 0 && !strcmp(temp, name)) { - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, curr_dir->inode); - return vfsnode_from_direntry(ext2fs, curr_dir, inode); - } - if (((sizeof(direntry_t) + curr_dir->name_len) & 0x00000003) != 0) - expected_size = - ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; - else - expected_size = ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc); - real_size = curr_dir->size; - if (real_size != expected_size) { - break; - } - in_block_offset += curr_dir->size; - curr_offset += curr_dir->size; - } - return NULL; -} - -void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode) -{ - ext2_fs_t *ext2fs = parent->device; - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - uint32_t curr_offset = 0; - uint32_t block_offset = 0; - uint32_t in_block_offset = 0; - uint32_t found = 0; - uint32_t entry_name_len = strlen(entry_name); - char *check = kcalloc(entry_name_len + 1, 1); - char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); - - while (curr_offset < p_inode->size) { - if (in_block_offset >= ext2fs->block_size) { - block_offset++; - in_block_offset = 0; - block_buf = read_inode_block(ext2fs, p_inode, block_offset); - } - direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); - if (curr_dir->name_len == entry_name_len) { - memcpy(check, curr_dir->name, entry_name_len); - if (curr_dir->inode != 0 && !strcmp(entry_name, check)) { - log("Entry by the same name %s already exist\n", check); - return; - } - } - if (found) { - curr_dir->inode = entry_inode; - curr_dir->size = - (uint32_t)block_buf + ext2fs->block_size - (uint32_t)curr_dir; - curr_dir->name_len = strlen(entry_name); - curr_dir->type = 0; - memcpy(curr_dir->name, entry_name, strlen(entry_name)); - write_inode_block(ext2fs, p_inode, block_offset, block_buf); - in_block_offset += curr_dir->size; - if (in_block_offset >= ext2fs->block_size) { - block_offset++; - in_block_offset = 0; - block_buf = read_inode_block(ext2fs, p_inode, block_offset); - } - curr_dir = (direntry_t *)(block_buf + in_block_offset); - memset(curr_dir, 0, sizeof(direntry_t)); - write_inode_block(ext2fs, p_inode, block_offset, block_buf); - return; - } - uint32_t expected_size = - ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; - uint32_t real_size = curr_dir->size; - if (real_size != expected_size) { - found = 1; - curr_dir->size = expected_size; - in_block_offset += expected_size; - curr_offset += expected_size; - continue; - } - in_block_offset += curr_dir->size; - curr_offset += curr_dir->size; - } -} - -void ext2_remove_entry(vfs_node_t *parent, char *entry_name) -{ - ext2_fs_t *ext2fs = parent->device; - inode_t *p_inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, p_inode, parent->inode_num); - uint32_t curr_offset = 0; - uint32_t block_offset = 0; - uint32_t in_block_offset = 0; - uint32_t entry_name_len = strlen(entry_name); - char *check = kcalloc(entry_name_len + 1, 1); - char *block_buf = read_inode_block(ext2fs, p_inode, block_offset); - while (curr_offset < p_inode->size) { - if (in_block_offset >= ext2fs->block_size) { - block_offset++; - in_block_offset = 0; - block_buf = read_inode_block(ext2fs, p_inode, block_offset); - } - direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset); - if (curr_dir->name_len == entry_name_len) { - memcpy(check, curr_dir->name, entry_name_len); - if (curr_dir->inode != 0 && !strcmp(entry_name, check)) { - curr_dir->inode = 0; - write_inode_block(ext2fs, p_inode, block_offset, block_buf); - return; - } - } - uint32_t expected_size = - ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4; - uint32_t real_size = curr_dir->size; - if (real_size != expected_size) - return; - in_block_offset += curr_dir->size; - curr_offset += curr_dir->size; - } -} - -void ext2_chmod(vfs_node_t *file, uint32_t mode) -{ - ext2_fs_t *ext2fs = file->device; - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, file->inode_num); - inode->permission = (inode->permission & 0xFFFFF000) | mode; - write_inode_metadata(ext2fs, inode, file->inode_num); -} - -uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf) -{ - ext2_fs_t *ext2fs = file->device; - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, file->inode_num); - read_inode_filedata(ext2fs, inode, offset, size, buf); - return size; -} - -uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf) -{ - ext2_fs_t *ext2fs = file->device; - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, file->inode_num); - write_inode_filedata(ext2fs, inode, file->inode_num, offset, size, buf); - return size; -} - -void ext2_open(vfs_node_t *file, uint32_t flags) -{ - ext2_fs_t *ext2fs = file->device; - if (flags & O_TRUNC) { - inode_t *inode = kmalloc(sizeof(inode_t)); - read_inode_metadata(ext2fs, inode, file->inode_num); - inode->size = 0; - write_inode_metadata(ext2fs, inode, file->inode_num); - } -} - -void ext2_close() -{ - return; -} - -void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx) -{ - uint32_t group = inode_idx / ext2fs->inodes_per_group; - uint32_t inode_table_block = ext2fs->bgds[group].inode_table; - uint32_t idx_in_group = inode_idx - group * ext2fs->inodes_per_group; - uint32_t block_offset = (idx_in_group - 1) * ext2fs->sb->inode_size / ext2fs->block_size; - uint32_t offset_in_block = - (idx_in_group - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size); - char *block_buf = kmalloc(ext2fs->block_size); - read_disk_block(ext2fs, inode_table_block + block_offset, block_buf); - memcpy(inode, block_buf + offset_in_block * ext2fs->sb->inode_size, ext2fs->sb->inode_size); - kfree(block_buf); -} - -void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx) -{ - uint32_t group = inode_idx / ext2fs->inodes_per_group; - uint32_t inode_table_block = ext2fs->bgds[group].inode_table; - uint32_t block_offset = (inode_idx - 1) * ext2fs->sb->inode_size / ext2fs->block_size; - uint32_t offset_in_block = - (inode_idx - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size); - char *block_buf = kmalloc(ext2fs->block_size); - read_disk_block(ext2fs, inode_table_block + block_offset, block_buf); - memcpy(block_buf + offset_in_block * ext2fs->sb->inode_size, inode, ext2fs->sb->inode_size); - write_disk_block(ext2fs, inode_table_block + block_offset, block_buf); - kfree(block_buf); -} - -uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size, - char *buf) -{ - uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size); - uint32_t start_block = offset / ext2fs->block_size; - uint32_t end_block = end_offset / ext2fs->block_size; - uint32_t start_off = offset % ext2fs->block_size; - uint32_t end_size = end_offset - end_block * ext2fs->block_size; - - uint32_t i = start_block; - uint32_t curr_off = 0; - while (i <= end_block) { - uint32_t left = 0, right = ext2fs->block_size - 1; - char *block_buf = read_inode_block(ext2fs, inode, i); - if (i == start_block) - left = start_off; - if (i == end_block) - right = end_size - 1; - memcpy(buf + curr_off, block_buf + left, (right - left + 1)); - curr_off = curr_off + (right - left + 1); - kfree(block_buf); - i++; - } - return end_offset - offset; -} - -void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset, - uint32_t size, char *buf) -{ - if (offset + size > inode->size) { - inode->size = offset + size; - write_inode_metadata(ext2fs, inode, inode_idx); - } - uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size); - uint32_t start_block = offset / ext2fs->block_size; - uint32_t end_block = end_offset / ext2fs->block_size; - uint32_t start_off = offset % ext2fs->block_size; - uint32_t end_size = end_offset - end_block * ext2fs->block_size; - - uint32_t i = start_block; - uint32_t curr_off = 0; - while (i <= end_block) { - uint32_t left = 0, right = ext2fs->block_size; - char *block_buf = read_inode_block(ext2fs, inode, i); - - if (i == start_block) - left = start_off; - if (i == end_block) - right = end_size - 1; - memcpy(block_buf + left, buf + curr_off, (right - left + 1)); - curr_off = curr_off + (right - left + 1); - write_inode_block(ext2fs, inode, i, block_buf); - kfree(block_buf); - i++; - } -} - -char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock) -{ - char *buf = kmalloc(ext2fs->block_size); - uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock); - read_disk_block(ext2fs, disk_block, buf); - return buf; -} - -void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf) -{ - uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock); - write_disk_block(ext2fs, disk_block, buf); -} - -void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf) -{ - vfs_read(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf); -} - -void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf) -{ - vfs_write(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf); -} - -void rewrite_bgds(ext2_fs_t *ext2fs) -{ - for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++) - write_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size); -} - -void rewrite_superblock(ext2_fs_t *ext2fs) -{ - write_disk_block(ext2fs, 1, (void *)ext2fs->sb); -} - -int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode, - uint32_t inode_idx, char *buffer, unsigned int block_overwrite) -{ - if (!(*block_ptr)) { - unsigned int block_no = ext2_alloc_block(ext2fs); - if (!block_no) - return 0; - *block_ptr = block_no; - if (buffer) - write_disk_block(ext2fs, block_overwrite, (void *)buffer); - else - write_inode_metadata(ext2fs, inode, inode_idx); - return 1; - } - return 0; -} - -uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block) -{ - unsigned int p = ext2fs->block_size / 4; - int a, b, c, d, e, f, g; - uint32_t *tmp = kmalloc(ext2fs->block_size); - uint32_t ret = -1; - a = inode_block - EXT2_DIRECT_BLOCKS; - if (a < 0) { - ret = inode->blocks[inode_block]; - goto done; - } - b = a - p; - if (b < 0) { - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); - ret = tmp[a]; - goto done; - } - c = b - p * p; - if (c < 0) { - c = b / p; - d = b - c * p; - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp); - read_disk_block(ext2fs, tmp[c], (void *)tmp); - ret = tmp[d]; - goto done; - } - d = c - p * p * p; - if (d < 0) { - e = c / (p * p); - f = (c - e * p * p) / p; - g = (c - e * p * p - f * p); - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp); - read_disk_block(ext2fs, tmp[e], (void *)tmp); - read_disk_block(ext2fs, tmp[f], (void *)tmp); - ret = tmp[g]; - goto done; - } -done: - kfree(tmp); - return ret; -} - -void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, - uint32_t inode_block, uint32_t disk_block) -{ - unsigned int p = ext2fs->block_size / 4; - int a, b, c, d, e, f, g; - int iblock = inode_block; - uint32_t *tmp = kmalloc(ext2fs->block_size); - - a = iblock - EXT2_DIRECT_BLOCKS; - if (a <= 0) { - inode->blocks[inode_block] = disk_block; - goto done; - } - b = a - p; - if (b <= 0) { - alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS]), ext2fs, inode, - inode_idx, NULL, 0); - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); - ((unsigned int *)tmp)[a] = disk_block; - write_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp); - tmp[a] = disk_block; - goto done; - } - c = b - p * p; - if (c <= 0) { - c = b / p; - d = b - c * p; - alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 1]), ext2fs, inode, - inode_idx, NULL, 0); - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp); - alloc_inode_metadata_block(&(tmp[c]), ext2fs, inode, inode_idx, (void *)tmp, - inode->blocks[EXT2_DIRECT_BLOCKS + 1]); - unsigned int temp = tmp[c]; - read_disk_block(ext2fs, temp, (void *)tmp); - tmp[d] = disk_block; - write_disk_block(ext2fs, temp, (void *)tmp); - goto done; - } - d = c - p * p * p; - if (d <= 0) { - e = c / (p * p); - f = (c - e * p * p) / p; - g = (c - e * p * p - f * p); - alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 2]), ext2fs, inode, - inode_idx, NULL, 0); - read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp); - alloc_inode_metadata_block(&(tmp[e]), ext2fs, inode, inode_idx, (void *)tmp, - inode->blocks[EXT2_DIRECT_BLOCKS + 2]); - unsigned int temp = tmp[e]; - read_disk_block(ext2fs, tmp[e], (void *)tmp); - alloc_inode_metadata_block(&(tmp[f]), ext2fs, inode, inode_idx, (void *)tmp, temp); - temp = tmp[f]; - read_disk_block(ext2fs, tmp[f], (void *)tmp); - tmp[g] = disk_block; - write_disk_block(ext2fs, temp, (void *)tmp); - goto done; - } -done: - kfree(tmp); -} - -uint32_t ext2_alloc_block(ext2_fs_t *ext2fs) -{ - uint32_t *buf = kcalloc(ext2fs->block_size, 1); - for (uint32_t i = 0; i < ext2fs->total_groups; i++) { - if (!ext2fs->bgds[i].free_blocks) - continue; - - uint32_t bitmap_block = ext2fs->bgds[i].block_bitmap; - read_disk_block(ext2fs, bitmap_block, (void *)buf); - for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) { - uint32_t sub_bitmap = buf[j]; - if (sub_bitmap == 0xFFFFFFFF) - continue; - for (uint32_t k = 0; k < 32; k++) { - uint32_t free = !((sub_bitmap >> k) & 0x1); - if (free) { - uint32_t mask = (0x1 << k); - buf[j] = buf[j] | mask; - write_disk_block(ext2fs, bitmap_block, (void *)buf); - ext2fs->bgds[i].free_blocks--; - rewrite_bgds(ext2fs); - return i * ext2fs->blocks_per_group + j * 32 + k; - } - } - } - } - panic("We're out of blocks!\n"); - return (uint32_t)-1; -} - -void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block) -{ - uint32_t *buf = kcalloc(ext2fs->block_size, 1); - uint32_t group_idx = block / ext2fs->blocks_per_group; - uint32_t sub_bitmap_idx = (block - (ext2fs->blocks_per_group * group_idx)) / 4; - uint32_t idx = (block - (ext2fs->blocks_per_group * group_idx)) % 4; - - uint32_t bitmap_block = ext2fs->bgds[group_idx].block_bitmap; - read_disk_block(ext2fs, bitmap_block, (void *)buf); - - uint32_t mask = ~(0x1 << idx); - buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask; - - write_disk_block(ext2fs, bitmap_block, (void *)buf); - - ext2fs->bgds[group_idx].free_blocks++; - rewrite_bgds(ext2fs); -} - -void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block) -{ - uint32_t ret = ext2_alloc_block(ext2fs); - set_disk_block_number(ext2fs, inode, inode_idx, block, ret); - inode->num_sectors = (block + 1) * (ext2fs->block_size / 512); - write_inode_metadata(ext2fs, inode, inode_idx); -} - -void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block) -{ - uint32_t ret = get_disk_block_number(ext2fs, inode, block); - ext2_free_block(ext2fs, ret); - set_disk_block_number(ext2fs, inode, inode_idx, ret, 0); - write_inode_metadata(ext2fs, inode, inode_idx); -} - -uint32_t alloc_inode(ext2_fs_t *ext2fs) -{ - uint32_t *buf = kcalloc(ext2fs->block_size, 1); - for (uint32_t i = 0; i < ext2fs->total_groups; i++) { - if (!ext2fs->bgds[i].free_inodes) - continue; - - uint32_t bitmap_block = ext2fs->bgds[i].inode_bitmap; - read_disk_block(ext2fs, bitmap_block, (void *)buf); - for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) { - uint32_t sub_bitmap = buf[j]; - if (sub_bitmap == 0xFFFFFFFF) - continue; - for (uint32_t k = 0; k < 32; k++) { - uint32_t free = !((sub_bitmap >> k) & 0x1); - if (free) { - uint32_t mask = (0x1 << k); - buf[j] = buf[j] | mask; - write_disk_block(ext2fs, bitmap_block, (void *)buf); - ext2fs->bgds[i].free_inodes--; - rewrite_bgds(ext2fs); - return i * ext2fs->inodes_per_group + j * 32 + k; - } - } - } - } - panic("We're out of inodes!\n"); - return (uint32_t)-1; -} - -void free_inode(ext2_fs_t *ext2fs, uint32_t inode) -{ - uint32_t *buf = kcalloc(ext2fs->block_size, 1); - uint32_t group_idx = inode / ext2fs->inodes_per_group; - uint32_t sub_bitmap_idx = (inode - (ext2fs->inodes_per_group * group_idx)) / 4; - uint32_t idx = (inode - (ext2fs->inodes_per_group * group_idx)) % 4; - - uint32_t bitmap_block = ext2fs->bgds[group_idx].inode_bitmap; - read_disk_block(ext2fs, bitmap_block, (void *)buf); - - uint32_t mask = ~(0x1 << idx); - buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask; - - write_disk_block(ext2fs, bitmap_block, (void *)buf); - - ext2fs->bgds[group_idx].free_inodes++; - rewrite_bgds(ext2fs); -} - -vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode) -{ - vfs_node_t *ext2root = kcalloc(sizeof(vfs_node_t), 1); - strcpy(ext2root->name, "/"); - ext2root->device = ext2fs; - ext2root->mask = inode->permission; - ext2root->inode_num = ROOT_INODE_NUMBER; - - ext2root->access_time = inode->atime; - ext2root->modified_time = inode->mtime; - ext2root->create_time = inode->ctime; - - ext2root->flags |= FS_DIRECTORY; - ext2root->read = NULL; - ext2root->write = NULL; - ext2root->chmod = ext2_chmod; - ext2root->open = ext2_open; - ext2root->close = ext2_close; - ext2root->read = ext2_read; - ext2root->write = ext2_write; - ext2root->mkdir = ext2_mkdir; - ext2root->create = ext2_mkfile; - ext2root->listdir = ext2_listdir; - ext2root->finddir = ext2_finddir; - ext2root->unlink = ext2_unlink; - return ext2root; -} - -void ext2_init(char *device_path, char *mountpoint) -{ - ext2_fs_t *ext2fs = kcalloc(sizeof(ext2_fs_t), 1); - ext2fs->disk_device = file_open(device_path, 0); - ext2fs->sb = kmalloc(SUPERBLOCK_SIZE); - ext2fs->block_size = 1024; - read_disk_block(ext2fs, 1, (void *)ext2fs->sb); - log("%x", ext2fs->sb->ext2_magic); - ext2fs->block_size = (1024 << ext2fs->sb->log2block_size); - ext2fs->blocks_per_group = ext2fs->sb->blocks_per_group; - ext2fs->inodes_per_group = ext2fs->sb->inodes_per_group; - - ext2fs->total_groups = ext2fs->sb->total_blocks / - ext2fs->blocks_per_group; // REMEMBER: Zero Division Exception - if (ext2fs->blocks_per_group * ext2fs->total_groups < ext2fs->total_groups) - ext2fs->total_groups++; - - ext2fs->bgd_blocks = (ext2fs->total_groups * sizeof(bgd_t)) / ext2fs->block_size; - if (ext2fs->bgd_blocks * ext2fs->block_size < ext2fs->total_groups * sizeof(bgd_t)) - ext2fs->bgd_blocks++; - - ext2fs->bgds = kcalloc(sizeof(bgd_t), ext2fs->bgd_blocks * ext2fs->block_size); - for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++) { - read_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size); - } - - inode_t *root_inode = kcalloc(sizeof(inode_t), 1); - read_inode_metadata(ext2fs, root_inode, ROOT_INODE_NUMBER); - vfs_mount(mountpoint, get_ext2_root(ext2fs, root_inode)); -} diff --git a/src/kernel/fs/ext2/ext2.h b/src/kernel/fs/ext2/ext2.h deleted file mode 100644 index 3996ba5..0000000 --- a/src/kernel/fs/ext2/ext2.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef MELVIX_EXT2_H -#define MELVIX_EXT2_H - -#include -#include - -#define EXT2_DIRECT_BLOCKS 12 - -#define SUPERBLOCK_SIZE 1024 -#define ROOT_INODE_NUMBER 2 - -#define EXT2_S_IFSOCK 0xC000 -#define EXT2_S_IFLNK 0xA000 -#define EXT2_S_IFREG 0x8000 -#define EXT2_S_IFBLK 0x6000 -#define EXT2_S_IFDIR 0x4000 -#define EXT2_S_IFCHR 0x2000 -#define EXT2_S_IFIFO 0x1000 - -// http://wiki.osdev.org/Ext2#Locating_the_Superblock -typedef struct superblock { - uint32_t total_inodes; - uint32_t total_blocks; - uint32_t su_blocks; - uint32_t free_blocks; - uint32_t free_inodes; - uint32_t superblock_idx; - uint32_t log2block_size; - uint32_t log2frag_size; - uint32_t blocks_per_group; - uint32_t frags_per_group; - uint32_t inodes_per_group; - - uint32_t mtime; - uint32_t wtime; - - uint16_t mount_count; - uint16_t mount_allowed_count; - uint16_t ext2_magic; - uint16_t fs_state; - uint16_t err; - uint16_t minor; - - uint32_t last_check; - uint32_t interval; - uint32_t os_id; - uint32_t major; - - uint16_t r_userid; - uint16_t r_groupid; - - // Extensions - uint32_t first_inode; - uint16_t inode_size; - uint16_t superblock_group; - uint32_t optional_feature; - uint32_t required_feature; - uint32_t readonly_feature; - char fs_id[16]; - char vol_name[16]; - char last_mount_path[64]; - uint32_t compression_method; - uint8_t file_pre_alloc_blocks; - uint8_t dir_pre_alloc_blocks; - uint16_t unused1; - char journal_id[16]; - uint32_t journal_inode; - uint32_t journal_device; - uint32_t orphan_head; - - char unused2[1024 - 236]; -} __attribute__((packed)) superblock_t; - -typedef struct bgd { - uint32_t block_bitmap; - uint32_t inode_bitmap; - uint32_t inode_table; - uint32_t free_blocks; - uint32_t free_inodes; - uint32_t num_dirs; - uint32_t unused1; - uint32_t unused2; -} __attribute__((packed)) bgd_t; - -typedef struct direntry { - uint32_t inode; - uint16_t size; - uint8_t name_len; - uint8_t type; - char name[]; -} __attribute__((packed)) direntry_t; - -typedef struct inode { - uint16_t permission; - uint16_t userid; - uint32_t size; - uint32_t atime; - uint32_t ctime; - uint32_t mtime; - uint32_t dtime; - uint16_t gid; - uint16_t hard_links; - uint32_t num_sectors; - uint32_t flags; - uint32_t os_specific1; - uint32_t blocks[EXT2_DIRECT_BLOCKS + 3]; - uint32_t generation; - uint32_t file_acl; - union { - uint32_t dir_acl; - uint32_t size_high; - }; - uint32_t f_block_addr; - char os_specific2[12]; -} __attribute__((packed)) inode_t; - -typedef struct ext2_cache { - uint32_t block; - uint32_t times; - uint8_t dirty; - char *block_data; -} ext2_cache_t; - -typedef struct ext2_fs { - vfs_node_t *disk_device; - - superblock_t *sb; - bgd_t *bgds; - uint32_t block_size; - uint32_t blocks_per_group; - uint32_t inodes_per_group; - uint32_t total_groups; - - uint32_t bgd_blocks; -} ext2_fs_t; - -uint32_t ext2_file_size(vfs_node_t *node); - -void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission); - -void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission); - -void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode); - -void ext2_unlink(vfs_node_t *parent, char *name); - -char **ext2_listdir(vfs_node_t *parent); - -vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name); - -void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode); - -void ext2_remove_entry(vfs_node_t *parent, char *entry_name); - -void ext2_chmod(vfs_node_t *file, uint32_t mode); - -uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf); - -uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf); - -void ext2_open(vfs_node_t *file, uint32_t flags); - -void ext2_close(); - -void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx); - -void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx); - -uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size, - char *buf); - -void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset, - uint32_t size, char *buf); - -char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock); - -void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf); - -void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf); - -void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf); - -void rewrite_bgds(ext2_fs_t *ext2fs); - -void rewrite_superblock(ext2_fs_t *ext2fs); - -int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode, - uint32_t inode_idx, char *buffer, unsigned int block_overwrite); - -uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block); - -void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, - uint32_t inode_block, uint32_t disk_block); - -uint32_t ext2_alloc_block(ext2_fs_t *ext2fs); - -void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block); - -void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block); - -void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block); - -uint32_t alloc_inode(ext2_fs_t *ext2fs); - -void free_inode(ext2_fs_t *ext2fs, uint32_t inode); - -vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode); - -void ext2_init(char *device_path, char *mountpoint); - -#endif \ No newline at end of file diff --git a/src/kernel/fs/vfs.c b/src/kernel/fs/vfs.c new file mode 100644 index 0000000..9dc684c --- /dev/null +++ b/src/kernel/fs/vfs.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +gtree_t *vfs_tree; +vfs_node_t *vfs_root; + +uint32_t vfs_get_file_size(vfs_node_t *node) +{ + if (node && node->get_file_size) { + return node->get_file_size(node); + } + return 0; +} + +void vfs_db_listdir(char *name) +{ + vfs_node_t *n = file_open(name, 0); + if (!n) { + log("Could not list a directory that does not exist"); + return; + } + if (!n->listdir) + return; + char **files = n->listdir(n); + char **save = files; + while (*files) { + log("%s ", *files); + kfree(*files); + files++; + } + kfree(save); +} + +void print_vfstree_recur(gtreenode_t *node, int parent_offset) +{ + if (!node) + return; + char *tmp = kmalloc(512); + int len = 0; + memset(tmp, 0, 512); + for (int i = 0; i < parent_offset; ++i) { + strcat(tmp, " "); + } + struct vfs_entry *fnode = (struct vfs_entry *)node->value; + if (fnode->file) { + log("%s(0x%x, %s)", fnode->name, (uint32_t)fnode->file, fnode->file->name); + } else { + log("%s(empty)", fnode->name); + } + log("%s", tmp); + len = strlen(fnode->name); + kfree(tmp); + foreach(child, node->children) + { + print_vfstree_recur(child->val, parent_offset + len + 1); + } +} + +void print_vfstree() +{ + print_vfstree_recur(vfs_tree->root, 0); +} + +uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) +{ + if (node && node->read) { + uint32_t ret = node->read(node, offset, size, buffer); + return ret; + } + return -1; +} + +uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) +{ + if (node && node->write) { + uint32_t ret = node->write(node, offset, size, buffer); + return ret; + } + return -1; +} + +void vfs_open(struct vfs_node *node, uint32_t flags) +{ + if (!node) + return; + if (node->refcount >= 0) + node->refcount++; + node->open(node, flags); +} + +void vfs_close(vfs_node_t *node) +{ + if (!node || node == vfs_root || node->refcount == -1) + return; + node->refcount--; + if (node->refcount == 0) + node->close(node); +} + +void vfs_chmod(vfs_node_t *node, uint32_t mode) +{ + if (node->chmod) + return node->chmod(node, mode); +} + +struct dirent *vfs_readdir(vfs_node_t *node, uint32_t index) +{ + if (node && (node->flags & FS_DIRECTORY) && node->readdir) + return node->readdir(node, index); + return NULL; +} + +vfs_node_t *vfs_finddir(vfs_node_t *node, char *name) +{ + if (node && (node->flags & FS_DIRECTORY) && node->finddir) + return node->finddir(node, name); + return NULL; +} + +int vfs_ioctl(vfs_node_t *node, int request, void *argp) +{ + if (!node) + return -1; + if (node->ioctl) + return node->ioctl(node, request, argp); + return -1; // ENOTTY +} + +void vfs_mkdir(char *name, unsigned short permission) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + } + + // mkdir + if (parent_node->mkdir) + parent_node->mkdir(parent_node, dirname, permission); + kfree(save_dirname); + + vfs_close(parent_node); +} + +int vfs_create_file(char *name, unsigned short permission) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + return -1; + } + if (parent_node->create) + parent_node->create(parent_node, dirname, permission); + kfree(save_dirname); + vfs_close(parent_node); + return 0; +} + +void vfs_unlink(char *name) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + } + if (parent_node->unlink) + parent_node->unlink(parent_node, dirname); + kfree(save_dirname); + vfs_close(parent_node); +} + +char *expand_path(char *input) +{ + list_t *input_list = str_split(input, "/", NULL); + char *ret = list2str(input_list, "/"); + return ret; +} + +vfs_node_t *get_mountpoint_recur(char **path, gtreenode_t *subroot) +{ + int found = 0; + char *curr_token = strsep(path, "/"); + if (curr_token == NULL || !strcmp(curr_token, "")) { + struct vfs_entry *ent = (struct vfs_entry *)subroot->value; + return ent->file; + } + foreach(child, subroot->children) + { + gtreenode_t *tchild = (gtreenode_t *)child->val; + struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); + if (strcmp(ent->name, curr_token) == 0) { + found = 1; + subroot = tchild; + break; + } + } + + if (!found) { + *path = curr_token; + return ((struct vfs_entry *)(subroot->value))->file; + } + return get_mountpoint_recur(path, subroot); +} + +vfs_node_t *get_mountpoint(char **path) +{ + if (strlen(*path) > 1 && (*path)[strlen(*path) - 1] == '/') + *(path)[strlen(*path) - 1] = '\0'; + if (!*path || *(path)[0] != '/') + return NULL; + if (strlen(*path) == 1) { + *path = '\0'; + struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; + return ent->file; + } + (*path)++; + return get_mountpoint_recur(path, vfs_tree->root); +} + +vfs_node_t *file_open(const char *file_name, uint32_t flags) +{ + char *curr_token = NULL; + char *filename = strdup(file_name); + char *free_filename = filename; + char *save = strdup(filename); + char *original_filename = filename; + char *new_start = NULL; + vfs_node_t *nextnode = NULL; + vfs_node_t *startpoint = get_mountpoint(&filename); + if (!startpoint) + return NULL; + if (filename) + new_start = strstr(save + (filename - original_filename), filename); + while (filename != NULL && ((curr_token = strsep(&new_start, "/")) != NULL)) { + nextnode = vfs_finddir(startpoint, curr_token); + if (!nextnode) + return NULL; + startpoint = nextnode; + } + if (!nextnode) + nextnode = startpoint; + vfs_open(nextnode, flags); + kfree(save); + kfree(free_filename); + return nextnode; +} + +void vfs_init() +{ + vfs_tree = tree_create(); + struct vfs_entry *root = kmalloc(sizeof(struct vfs_entry)); + root->name = strdup("root"); + root->file = NULL; + tree_insert(vfs_tree, NULL, root); +} + +void vfs_mount_dev(char *mountpoint, vfs_node_t *node) +{ + vfs_mount(mountpoint, node); +} + +void vfs_mount_recur(char *path, gtreenode_t *subroot, vfs_node_t *fs_obj) +{ + int found = 0; + char *curr_token = strsep(&path, "/"); + + if (curr_token == NULL || !strcmp(curr_token, "")) { + struct vfs_entry *ent = (struct vfs_entry *)subroot->value; + if (ent->file) { + warn("The path is already mounted, please unmount before mounting again"); + return; + } + if (!strcmp(ent->name, "/")) + vfs_root = fs_obj; + ent->file = fs_obj; + return; + } + + foreach(child, subroot->children) + { + gtreenode_t *tchild = (gtreenode_t *)child->val; + struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); + if (strcmp(ent->name, curr_token) == 0) { + found = 1; + subroot = tchild; + } + } + + if (!found) { + struct vfs_entry *ent = kcalloc(sizeof(struct vfs_entry), 1); + ent->name = strdup(curr_token); + subroot = tree_insert(vfs_tree, subroot, ent); + } + vfs_mount_recur(path, subroot, fs_obj); +} + +void vfs_mount(char *path, vfs_node_t *fs_obj) +{ + fs_obj->refcount = -1; + fs_obj->fs_type = 0; + if (path[0] == '/' && strlen(path) == 1) { + struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; + if (ent->file) { + warn("The path is already mounted, please unmount before mounting again"); + return; + } + vfs_root = fs_obj; + ent->file = fs_obj; + return; + } + vfs_mount_recur(path + 1, vfs_tree->root, fs_obj); +} diff --git a/src/kernel/fs/vfs.h b/src/kernel/fs/vfs.h new file mode 100644 index 0000000..b31767e --- /dev/null +++ b/src/kernel/fs/vfs.h @@ -0,0 +1,149 @@ +#ifndef MELVIX_VFS_H +#define MELVIX_VFS_H + +#include + +#define PATH_SEPARATOR '/' +#define PATH_SEPARATOR_STRING "/" +#define PATH_UP ".." +#define PATH_DOT "." +#define VFS_EXT2_MAGIC 0xeeee2222 + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 +#define O_NOFOLLOW 0x1000 +#define O_PATH 0x2000 + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x04 +#define FS_BLOCKDEVICE 0x08 +#define FS_PIPE 0x10 +#define FS_SYMLINK 0x20 +#define FS_MOUNTPOINT 0x40 + +#define _IFMT 0170000 /* type of file */ +#define _IFDIR 0040000 /* directory */ +#define _IFCHR 0020000 /* character special */ +#define _IFBLK 0060000 /* block special */ +#define _IFREG 0100000 /* regular */ +#define _IFLNK 0120000 /* symbolic link */ +#define _IFSOCK 0140000 /* socket */ +#define _IFIFO 0010000 /* fifo */ + +struct vfs_node; + +typedef uint32_t (*get_file_size_callback)(struct vfs_node *node); +typedef uint32_t (*read_callback)(struct vfs_node *, uint32_t, uint32_t, char *); +typedef uint32_t (*write_callback)(struct vfs_node *, uint32_t, uint32_t, char *); +typedef void (*open_callback)(struct vfs_node *, uint32_t flags); +typedef void (*close_callback)(struct vfs_node *); +typedef struct dirent *(*readdir_callback)(struct vfs_node *, uint32_t); +typedef struct vfs_node *(*finddir_callback)(struct vfs_node *, char *name); +typedef void (*create_callback)(struct vfs_node *, char *name, uint16_t permission); +typedef void (*unlink_callback)(struct vfs_node *, char *name); +typedef void (*mkdir_callback)(struct vfs_node *, char *name, uint16_t permission); +typedef int (*ioctl_callback)(struct vfs_node *, int request, void *argp); +typedef int (*get_size_callback)(struct vfs_node *); +typedef void (*chmod_callback)(struct vfs_node *, uint32_t mode); +typedef char **(*listdir_callback)(struct vfs_node *); + +typedef struct vfs_node { + char name[256]; + void *device; + uint32_t mask; + uint32_t uid; + uint32_t gid; + uint32_t flags; + uint32_t inode_num; + uint32_t size; + uint32_t fs_type; + uint32_t open_flags; + uint32_t create_time; + uint32_t access_time; + uint32_t modified_time; + + uint32_t offset; + unsigned nlink; + int refcount; + + // File operations + read_callback read; + write_callback write; + open_callback open; + close_callback close; + readdir_callback readdir; + finddir_callback finddir; + create_callback create; + unlink_callback unlink; + mkdir_callback mkdir; + ioctl_callback ioctl; + get_size_callback get_size; + chmod_callback chmod; + get_file_size_callback get_file_size; + + listdir_callback listdir; +} vfs_node_t; + +struct dirent { + char name[256]; + uint32_t inode_num; +}; + +typedef struct vfs_entry { + char *name; + vfs_node_t *file; +} vfs_entry_t; + +uint32_t vfs_get_file_size(vfs_node_t *node); + +uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); + +uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); + +void vfs_open(struct vfs_node *node, uint32_t flags); + +void vfs_close(vfs_node_t *node); + +vfs_node_t *vfs_finddir(vfs_node_t *node, char *name); + +void vfs_mkdir(char *name, uint16_t permission); + +void vfs_mkfile(char *name, uint16_t permission); + +int vfs_create_file(char *name, uint16_t permission); + +vfs_node_t *file_open(const char *file_name, uint32_t flags); + +char *expand_path(char *input); + +int vfs_ioctl(vfs_node_t *node, int request, void *argp); + +void vfs_chmod(vfs_node_t *node, uint32_t mode); + +void vfs_unlink(char *name); + +int vfs_symlink(char *value, char *name); + +int vfs_readlink(vfs_node_t *node, char *buf, uint32_t size); + +void vfs_init(); + +void vfs_mount(char *path, vfs_node_t *local_root); + +typedef vfs_node_t *(*vfs_mount_callback)(char *arg, char *mountpoint); + +void vfs_register(char *name, vfs_mount_callback callme); + +void vfs_mount_dev(char *mountpoint, vfs_node_t *node); + +void print_vfstree(); + +void vfs_db_listdir(char *name); + +#endif \ No newline at end of file diff --git a/src/kernel/fs/vfs/vfs.c b/src/kernel/fs/vfs/vfs.c deleted file mode 100644 index 10d3c21..0000000 --- a/src/kernel/fs/vfs/vfs.c +++ /dev/null @@ -1,369 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -gtree_t *vfs_tree; -vfs_node_t *vfs_root; - -uint32_t vfs_get_file_size(vfs_node_t *node) -{ - if (node && node->get_file_size) { - return node->get_file_size(node); - } - return 0; -} - -void vfs_db_listdir(char *name) -{ - vfs_node_t *n = file_open(name, 0); - if (!n) { - log("Could not list a directory that does not exist"); - return; - } - if (!n->listdir) - return; - char **files = n->listdir(n); - char **save = files; - while (*files) { - log("%s ", *files); - kfree(*files); - files++; - } - kfree(save); -} - -void print_vfstree_recur(gtreenode_t *node, int parent_offset) -{ - if (!node) - return; - char *tmp = kmalloc(512); - int len = 0; - memset(tmp, 0, 512); - for (int i = 0; i < parent_offset; ++i) { - strcat(tmp, " "); - } - struct vfs_entry *fnode = (struct vfs_entry *)node->value; - if (fnode->file) { - log("%s(0x%x, %s)", fnode->name, (uint32_t)fnode->file, fnode->file->name); - } else { - log("%s(empty)", fnode->name); - } - log("%s\n", tmp); - len = strlen(fnode->name); - kfree(tmp); - foreach(child, node->children) - { - print_vfstree_recur(child->val, parent_offset + len + 1); - } -} - -void print_vfstree() -{ - print_vfstree_recur(vfs_tree->root, 0); -} - -uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) -{ - if (node && node->read) { - uint32_t ret = node->read(node, offset, size, buffer); - return ret; - } - return -1; -} - -uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) -{ - if (node && node->write) { - uint32_t ret = node->write(node, offset, size, buffer); - return ret; - } - return -1; -} - -void vfs_open(struct vfs_node *node, uint32_t flags) -{ - if (!node) - return; - if (node->refcount >= 0) - node->refcount++; - node->open(node, flags); -} - -void vfs_close(vfs_node_t *node) -{ - if (!node || node == vfs_root || node->refcount == -1) - return; - node->refcount--; - if (node->refcount == 0) - node->close(node); -} - -void vfs_chmod(vfs_node_t *node, uint32_t mode) -{ - if (node->chmod) - return node->chmod(node, mode); -} - -struct dirent *vfs_readdir(vfs_node_t *node, uint32_t index) -{ - if (node && (node->flags & FS_DIRECTORY) && node->readdir) - return node->readdir(node, index); - return NULL; -} - -vfs_node_t *vfs_finddir(vfs_node_t *node, char *name) -{ - if (node && (node->flags & FS_DIRECTORY) && node->finddir) - return node->finddir(node, name); - return NULL; -} - -int vfs_ioctl(vfs_node_t *node, int request, void *argp) -{ - if (!node) - return -1; - if (node->ioctl) - return node->ioctl(node, request, argp); - return -1; // ENOTTY -} - -void vfs_mkdir(char *name, unsigned short permission) -{ - // Find parent directory - int i = strlen(name); - char *dirname = strdup(name); - char *save_dirname = dirname; - char *parent_path = "/"; - while (i >= 0) { - if (dirname[i] == '/') { - if (i != 0) { - dirname[i] = '\0'; - parent_path = dirname; - } - dirname = &dirname[i + 1]; - break; - } - i--; - } - - // Open file - vfs_node_t *parent_node = file_open(parent_path, 0); - if (!parent_node) { - kfree(save_dirname); - } - - // mkdir - if (parent_node->mkdir) - parent_node->mkdir(parent_node, dirname, permission); - kfree(save_dirname); - - vfs_close(parent_node); -} - -int vfs_create_file(char *name, unsigned short permission) -{ - // Find parent directory - int i = strlen(name); - char *dirname = strdup(name); - char *save_dirname = dirname; - char *parent_path = "/"; - while (i >= 0) { - if (dirname[i] == '/') { - if (i != 0) { - dirname[i] = '\0'; - parent_path = dirname; - } - dirname = &dirname[i + 1]; - break; - } - i--; - } - - // Open file - vfs_node_t *parent_node = file_open(parent_path, 0); - if (!parent_node) { - kfree(save_dirname); - return -1; - } - if (parent_node->create) - parent_node->create(parent_node, dirname, permission); - kfree(save_dirname); - vfs_close(parent_node); - return 0; -} - -void vfs_unlink(char *name) -{ - // Find parent directory - int i = strlen(name); - char *dirname = strdup(name); - char *save_dirname = dirname; - char *parent_path = "/"; - while (i >= 0) { - if (dirname[i] == '/') { - if (i != 0) { - dirname[i] = '\0'; - parent_path = dirname; - } - dirname = &dirname[i + 1]; - break; - } - i--; - } - - // Open file - vfs_node_t *parent_node = file_open(parent_path, 0); - if (!parent_node) { - kfree(save_dirname); - } - if (parent_node->unlink) - parent_node->unlink(parent_node, dirname); - kfree(save_dirname); - vfs_close(parent_node); -} - -char *expand_path(char *input) -{ - list_t *input_list = str_split(input, "/", NULL); - char *ret = list2str(input_list, "/"); - return ret; -} - -vfs_node_t *get_mountpoint_recur(char **path, gtreenode_t *subroot) -{ - int found = 0; - char *curr_token = strsep(path, "/"); - if (curr_token == NULL || !strcmp(curr_token, "")) { - struct vfs_entry *ent = (struct vfs_entry *)subroot->value; - return ent->file; - } - foreach(child, subroot->children) - { - gtreenode_t *tchild = (gtreenode_t *)child->val; - struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); - if (strcmp(ent->name, curr_token) == 0) { - found = 1; - subroot = tchild; - break; - } - } - - if (!found) { - *path = curr_token; - return ((struct vfs_entry *)(subroot->value))->file; - } - return get_mountpoint_recur(path, subroot); -} -vfs_node_t *get_mountpoint(char **path) -{ - if (strlen(*path) > 1 && (*path)[strlen(*path) - 1] == '/') - *(path)[strlen(*path) - 1] = '\0'; - if (!*path || *(path)[0] != '/') - return NULL; - if (strlen(*path) == 1) { - *path = '\0'; - struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; - return ent->file; - } - (*path)++; - return get_mountpoint_recur(path, vfs_tree->root); -} - -vfs_node_t *file_open(const char *file_name, uint32_t flags) -{ - char *curr_token = NULL; - char *filename = strdup(file_name); - char *free_filename = filename; - char *save = strdup(filename); - char *original_filename = filename; - char *new_start = NULL; - vfs_node_t *nextnode = NULL; - vfs_node_t *startpoint = get_mountpoint(&filename); - if (!startpoint) - return NULL; - if (filename) - new_start = strstr(save + (filename - original_filename), filename); - while (filename != NULL && ((curr_token = strsep(&new_start, "/")) != NULL)) { - nextnode = vfs_finddir(startpoint, curr_token); - if (!nextnode) - return NULL; - startpoint = nextnode; - } - if (!nextnode) - nextnode = startpoint; - vfs_open(nextnode, flags); - kfree(save); - kfree(free_filename); - return nextnode; -} - -void vfs_init() -{ - vfs_tree = tree_create(); - struct vfs_entry *root = kmalloc(sizeof(struct vfs_entry)); - root->name = strdup("root"); - root->file = NULL; - tree_insert(vfs_tree, NULL, root); -} - -void vfs_mount_dev(char *mountpoint, vfs_node_t *node) -{ - vfs_mount(mountpoint, node); -} - -void vfs_mount_recur(char *path, gtreenode_t *subroot, vfs_node_t *fs_obj) -{ - int found = 0; - char *curr_token = strsep(&path, "/"); - - if (curr_token == NULL || !strcmp(curr_token, "")) { - struct vfs_entry *ent = (struct vfs_entry *)subroot->value; - if (ent->file) { - log("The path is already mounted, plz unmount before mounting again\n"); - return; - } - if (!strcmp(ent->name, "/")) - vfs_root = fs_obj; - ent->file = fs_obj; - return; - } - - foreach(child, subroot->children) - { - gtreenode_t *tchild = (gtreenode_t *)child->val; - struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); - if (strcmp(ent->name, curr_token) == 0) { - found = 1; - subroot = tchild; - } - } - - if (!found) { - struct vfs_entry *ent = kcalloc(sizeof(struct vfs_entry), 1); - ent->name = strdup(curr_token); - subroot = tree_insert(vfs_tree, subroot, ent); - } - vfs_mount_recur(path, subroot, fs_obj); -} - -void vfs_mount(char *path, vfs_node_t *fs_obj) -{ - fs_obj->refcount = -1; - fs_obj->fs_type = 0; - if (path[0] == '/' && strlen(path) == 1) { - struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; - if (ent->file) { - log("The path is already mounted, plz unmount before mounting again\n"); - return; - } - vfs_root = fs_obj; - ent->file = fs_obj; - return; - } - vfs_mount_recur(path + 1, vfs_tree->root, fs_obj); -} diff --git a/src/kernel/fs/vfs/vfs.h b/src/kernel/fs/vfs/vfs.h deleted file mode 100644 index b31767e..0000000 --- a/src/kernel/fs/vfs/vfs.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef MELVIX_VFS_H -#define MELVIX_VFS_H - -#include - -#define PATH_SEPARATOR '/' -#define PATH_SEPARATOR_STRING "/" -#define PATH_UP ".." -#define PATH_DOT "." -#define VFS_EXT2_MAGIC 0xeeee2222 - -#define O_RDONLY 0x0000 -#define O_WRONLY 0x0001 -#define O_RDWR 0x0002 -#define O_APPEND 0x0008 -#define O_CREAT 0x0200 -#define O_TRUNC 0x0400 -#define O_EXCL 0x0800 -#define O_NOFOLLOW 0x1000 -#define O_PATH 0x2000 - -#define FS_FILE 0x01 -#define FS_DIRECTORY 0x02 -#define FS_CHARDEVICE 0x04 -#define FS_BLOCKDEVICE 0x08 -#define FS_PIPE 0x10 -#define FS_SYMLINK 0x20 -#define FS_MOUNTPOINT 0x40 - -#define _IFMT 0170000 /* type of file */ -#define _IFDIR 0040000 /* directory */ -#define _IFCHR 0020000 /* character special */ -#define _IFBLK 0060000 /* block special */ -#define _IFREG 0100000 /* regular */ -#define _IFLNK 0120000 /* symbolic link */ -#define _IFSOCK 0140000 /* socket */ -#define _IFIFO 0010000 /* fifo */ - -struct vfs_node; - -typedef uint32_t (*get_file_size_callback)(struct vfs_node *node); -typedef uint32_t (*read_callback)(struct vfs_node *, uint32_t, uint32_t, char *); -typedef uint32_t (*write_callback)(struct vfs_node *, uint32_t, uint32_t, char *); -typedef void (*open_callback)(struct vfs_node *, uint32_t flags); -typedef void (*close_callback)(struct vfs_node *); -typedef struct dirent *(*readdir_callback)(struct vfs_node *, uint32_t); -typedef struct vfs_node *(*finddir_callback)(struct vfs_node *, char *name); -typedef void (*create_callback)(struct vfs_node *, char *name, uint16_t permission); -typedef void (*unlink_callback)(struct vfs_node *, char *name); -typedef void (*mkdir_callback)(struct vfs_node *, char *name, uint16_t permission); -typedef int (*ioctl_callback)(struct vfs_node *, int request, void *argp); -typedef int (*get_size_callback)(struct vfs_node *); -typedef void (*chmod_callback)(struct vfs_node *, uint32_t mode); -typedef char **(*listdir_callback)(struct vfs_node *); - -typedef struct vfs_node { - char name[256]; - void *device; - uint32_t mask; - uint32_t uid; - uint32_t gid; - uint32_t flags; - uint32_t inode_num; - uint32_t size; - uint32_t fs_type; - uint32_t open_flags; - uint32_t create_time; - uint32_t access_time; - uint32_t modified_time; - - uint32_t offset; - unsigned nlink; - int refcount; - - // File operations - read_callback read; - write_callback write; - open_callback open; - close_callback close; - readdir_callback readdir; - finddir_callback finddir; - create_callback create; - unlink_callback unlink; - mkdir_callback mkdir; - ioctl_callback ioctl; - get_size_callback get_size; - chmod_callback chmod; - get_file_size_callback get_file_size; - - listdir_callback listdir; -} vfs_node_t; - -struct dirent { - char name[256]; - uint32_t inode_num; -}; - -typedef struct vfs_entry { - char *name; - vfs_node_t *file; -} vfs_entry_t; - -uint32_t vfs_get_file_size(vfs_node_t *node); - -uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); - -uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); - -void vfs_open(struct vfs_node *node, uint32_t flags); - -void vfs_close(vfs_node_t *node); - -vfs_node_t *vfs_finddir(vfs_node_t *node, char *name); - -void vfs_mkdir(char *name, uint16_t permission); - -void vfs_mkfile(char *name, uint16_t permission); - -int vfs_create_file(char *name, uint16_t permission); - -vfs_node_t *file_open(const char *file_name, uint32_t flags); - -char *expand_path(char *input); - -int vfs_ioctl(vfs_node_t *node, int request, void *argp); - -void vfs_chmod(vfs_node_t *node, uint32_t mode); - -void vfs_unlink(char *name); - -int vfs_symlink(char *value, char *name); - -int vfs_readlink(vfs_node_t *node, char *buf, uint32_t size); - -void vfs_init(); - -void vfs_mount(char *path, vfs_node_t *local_root); - -typedef vfs_node_t *(*vfs_mount_callback)(char *arg, char *mountpoint); - -void vfs_register(char *name, vfs_mount_callback callme); - -void vfs_mount_dev(char *mountpoint, vfs_node_t *node); - -void print_vfstree(); - -void vfs_db_listdir(char *name); - -#endif \ No newline at end of file diff --git a/src/kernel/graphics/vesa.c b/src/kernel/graphics/vesa.c index 490c8ea..ca190ad 100644 --- a/src/kernel/graphics/vesa.c +++ b/src/kernel/graphics/vesa.c @@ -119,13 +119,9 @@ void set_optimal_resolution() continue; } - log("Found mode: (0x%x) %dx%dx%d", *mode, mode_info->width, mode_info->height, - mode_info->bpp); - if (mode_info->width > vbe_width || (mode_info->width == vbe_width && (mode_info->bpp >> 3) > vbe_bpl)) { // if (mode_info->bpp == 32) { // Force specific bpp for debugging - // (float) mode_info->width / (float) mode_info->height < 2.0 &&) { highest = *mode; vbe_width = mode_info->width; vbe_height = mode_info->height; @@ -139,7 +135,6 @@ void set_optimal_resolution() kfree(video_modes); if (highest == 0) { - log("Mode detection failed!\nTrying common modes..."); vga_log("Mode detection failed!"); vga_log("Trying common modes..."); struct vbe_mode_info *mode_info; @@ -211,7 +206,6 @@ void set_optimal_resolution() info("Successfully switched to video mode!"); log("Using mode: (0x%x) %dx%dx%d", highest, vbe_width, vbe_height, vbe_bpl << 3); - debug("Using mode: %dx%dx%d", vbe_width, vbe_height, vbe_bpl << 3); } const uint32_t default_text_color = vesa_white; @@ -375,4 +369,4 @@ void vesa_set_color(uint32_t color) { vesa_convert_color(terminal_color, color); vesa_convert_color(terminal_background, default_background_color); -} \ No newline at end of file +} diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 08980cf..3339381 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include void kernel_main(uint32_t magic, multiboot_info_t *grub_header) { diff --git a/src/kernel/net/rtl8139.c b/src/kernel/net/rtl8139.c index a934e52..2a6a3e8 100644 --- a/src/kernel/net/rtl8139.c +++ b/src/kernel/net/rtl8139.c @@ -100,4 +100,4 @@ void rtl8139_install() if (rtl8139_init() == 0) info("Installed rtl8139 network driver"); -} \ No newline at end of file +} diff --git a/src/kernel/pci/pci.c b/src/kernel/pci/pci.c index 7ba48ab..57bfe94 100644 --- a/src/kernel/pci/pci.c +++ b/src/kernel/pci/pci.c @@ -1,5 +1,6 @@ -#include #include +#include +#include #include #include @@ -136,4 +137,4 @@ int pci_get_interrupt(uint32_t device) } else { return (int)pci_read_field(device, PCI_INTERRUPT_LINE, 1); } -} \ No newline at end of file +} -- cgit v1.2.3