From f648cd2b9438748069d875c9f07199c1912067b3 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 22 Jan 2020 15:36:58 +0200 Subject: [PATCH] Get rid of old ext2 --- etc/make/conf.mk | 5 - include/sys/fs/ext2.h | 149 ------- sys/init.c | 1 - sys/vfs/ext2/ext2.c | 157 ------- sys/vfs/ext2/ext2alloc.c | 345 ---------------- sys/vfs/ext2/ext2blk.c | 133 ------ sys/vfs/ext2/ext2dir.c | 177 -------- sys/vfs/ext2/ext2vnop.c | 867 --------------------------------------- 8 files changed, 1834 deletions(-) delete mode 100644 include/sys/fs/ext2.h delete mode 100644 sys/vfs/ext2/ext2.c delete mode 100644 sys/vfs/ext2/ext2alloc.c delete mode 100644 sys/vfs/ext2/ext2blk.c delete mode 100644 sys/vfs/ext2/ext2dir.c delete mode 100644 sys/vfs/ext2/ext2vnop.c diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 9da222a..19abf73 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -66,11 +66,6 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/net/in.o \ $(O)/sys/net/netdev.o \ $(O)/sys/vfs/pseudo.o \ - $(O)/sys/vfs/ext2/ext2.o \ - $(O)/sys/vfs/ext2/ext2vnop.o \ - $(O)/sys/vfs/ext2/ext2blk.o \ - $(O)/sys/vfs/ext2/ext2alloc.o \ - $(O)/sys/vfs/ext2/ext2dir.o \ $(O)/sys/vfs/tar.o \ $(O)/sys/blk/ram.o \ $(O)/sys/tty.o \ diff --git a/include/sys/fs/ext2.h b/include/sys/fs/ext2.h deleted file mode 100644 index 16148c1..0000000 --- a/include/sys/fs/ext2.h +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once -#include -#include "fs.h" - -#define EXT2_MAGIC ((uint16_t) 0xEF53) - -#define EXT2_SBSIZ 1024 -#define EXT2_SBOFF 1024 - -#define EXT2_ROOTINO 2 - -#define EXT2_GOOD ((uint16_t) 1) -#define EXT2_BAD ((uint16_t) 2) - -#define EXT2_EACT_IGN ((uint16_t) 1) -#define EXT2_EACT_REM ((uint16_t) 2) -#define EXT2_EACT_PAN ((uint16_t) 3) - -#define EXT2_TYPE_REG ((uint16_t) 0x8000) -#define EXT2_TYPE_DIR ((uint16_t) 0x4000) -#define EXT2_TYPE_LNK ((uint16_t) 0xA000) - -struct ext2_sb { - uint32_t inode_count; - uint32_t block_count; - uint32_t su_reserved; - uint32_t free_block_count; - uint32_t free_inode_count; - uint32_t sb_block_number; - uint32_t block_size_log; - uint32_t frag_size_log; - uint32_t block_group_size_blocks; - uint32_t block_group_size_frags; - uint32_t block_group_size_inodes; - uint32_t last_mount_time; - uint32_t last_mtime; - uint16_t mount_count_since_fsck; - uint16_t mount_max_before_fsck; - uint16_t magic; - uint16_t fs_state; - uint16_t error_action; - uint16_t version_minor; - uint32_t last_fsck_time; - uint32_t os_id; - uint32_t version_major; - uint16_t su_uid; - uint16_t su_gid; - uint32_t first_non_reserved; - uint16_t inode_struct_size; - uint16_t backup_group_number; - uint32_t optional_features; - uint32_t required_features; - uint32_t ro_required_features; - char fsid[16]; - char volname[16]; - char last_mount_path[64]; - uint32_t compression; - uint8_t prealloc_file_block_number; - uint8_t prealloc_dir_block_number; - uint16_t __un0; - char journal_id[16]; - uint32_t journal_inode; - uint32_t journal_dev; - uint32_t orphan_inode_head; -} __attribute__((packed)); - -struct ext2_info { - union { - char __sb_data[1024]; - struct ext2_sb sb; - }; - // driver-specific info - uint32_t block_size; - uint32_t block_group_count; - uint32_t block_group_descriptor_table_block; - uint32_t block_group_descriptor_table_size_blocks; - struct ext2_grp_desc *block_group_descriptor_table; -}; - -struct ext2_grp_desc { - uint32_t block_usage_bitmap_block; - uint32_t inode_usage_bitmap_block; - uint32_t inode_table_block; - uint16_t free_blocks; - uint16_t free_inodes; - uint16_t dir_count; - char __pad[14]; -} __attribute__((packed)); - -struct ext2_inode { - uint16_t type_perm; - uint16_t uid; - uint32_t size_lower; - uint32_t atime; - uint32_t ctime; - uint32_t mtime; - uint32_t dtime; - uint16_t gid; - uint16_t hard_link_count; - uint32_t disk_sector_count; - uint32_t flags; - uint32_t os_value_1; - uint32_t direct_blocks[12]; - uint32_t l1_indirect_block; - uint32_t l2_indirect_block; - uint32_t l3_indirect_block; - uint32_t gen_number; - uint32_t acl; - union { - uint32_t dir_acl; - uint32_t size_upper; - }; - uint32_t frag_block_addr; - char os_value_2[12]; -} __attribute__((packed)); - -struct ext2_dirent { - uint32_t ino; - uint16_t len; - uint8_t name_len; - uint8_t type_ind; - char name[]; -} __attribute__((packed)); - -void ext2_class_init(void); -enum vnode_type ext2_inode_type(struct ext2_inode *i); - -// Implemented in ext2blk.c -int ext2_write_superblock(struct fs *ext2); -int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf); -int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf); -int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf); -int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf); -int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino); -int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino); - -// Implemented in ext2alloc.c -int ext2_alloc_block(struct fs *ext2, uint32_t *block_no); -int ext2_free_block(struct fs *ext2, uint32_t block_no); -int ext2_inode_alloc_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); -int ext2_free_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); -int ext2_free_inode(struct fs *ext2, uint32_t ino); -int ext2_alloc_inode(struct fs *ext2, uint32_t *ino); - -// Implemented in ext2dir.c -int ext2_dir_add_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino); -int ext2_dir_remove_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino); - -extern struct vnode_operations ext2_vnode_ops; diff --git a/sys/init.c b/sys/init.c index 4cb63d6..14556c3 100644 --- a/sys/init.c +++ b/sys/init.c @@ -5,7 +5,6 @@ #include "sys/binfmt_elf.h" #include "sys/amd64/cpu.h" #include "sys/config.h" -#include "sys/fs/ext2.h" #include "sys/vmalloc.h" #include "sys/string.h" #include "sys/assert.h" diff --git a/sys/vfs/ext2/ext2.c b/sys/vfs/ext2/ext2.c deleted file mode 100644 index dbc6848..0000000 --- a/sys/vfs/ext2/ext2.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "sys/fs/ext2.h" -#include "sys/fs/vfs.h" -#include "sys/debug.h" -#include "sys/panic.h" -#include "sys/errno.h" -#include "sys/heap.h" - -enum vnode_type ext2_inode_type(struct ext2_inode *i) { - uint16_t v = i->type_perm & 0xF000; - switch (v) { - case EXT2_TYPE_DIR: - return VN_DIR; - case EXT2_TYPE_REG: - return VN_REG; - case EXT2_TYPE_LNK: - return VN_LNK; - default: - // fprintf(stderr, "Unknown file type: %x\n", v); - // abort(); - panic("Unknown file type: %x\n", v); - return 0; - } -} - -static int ext2_fs_init(struct fs *fs, const char *opt) { - int res; - kdebug("ext2_fs_init()\n"); - struct ext2_info *info; - // ext2's private data is its superblock structure - info = kmalloc(sizeof(struct ext2_info)); - fs->fs_private = info; - - // Read the superblock from blkdev - if ((res = blk_read(fs->blk, info, EXT2_SBOFF, EXT2_SBSIZ)) != EXT2_SBSIZ) { - kfree(fs->fs_private); - - kerror("ext2: superblock read failed\n"); - return -EINVAL; - } - - // Check if superblock is ext2 - if (info->sb.magic != EXT2_MAGIC) { - kfree(info); - - kdebug("ext2: magic mismatch\n"); - return -EINVAL; - } - - // Check if we have an extended ext2 sb - if (info->sb.version_major == 0) { - // Initialize params which are missing in non-extended sbs - info->sb.inode_struct_size = 128; - info->sb.first_non_reserved = 11; - } - info->block_size = 1024 << info->sb.block_size_log; - - // Load block group descriptor table - // Get descriptor table size - uint32_t block_group_descriptor_table_length = info->sb.block_count / info->sb.block_group_size_blocks; - if (block_group_descriptor_table_length * info->sb.block_group_size_blocks < info->sb.block_count) { - ++block_group_descriptor_table_length; - } - info->block_group_count = block_group_descriptor_table_length; - - uint32_t block_group_descriptor_table_size_blocks = 32 * block_group_descriptor_table_length / - info->block_size + 1; - - uint32_t block_group_descriptor_table_block = 2; - if (info->block_size > 1024) { - block_group_descriptor_table_block = 1; - } - info->block_group_descriptor_table_block = block_group_descriptor_table_block; - info->block_group_descriptor_table_size_blocks = block_group_descriptor_table_size_blocks; - - // Load all block group descriptors into memory - kdebug("Allocating %u bytes for BGDT\n", info->block_group_descriptor_table_size_blocks * info->block_size); - info->block_group_descriptor_table = kmalloc(info->block_group_descriptor_table_size_blocks * info->block_size); - - for (size_t i = 0; i < info->block_group_descriptor_table_size_blocks; ++i) { - ext2_read_block(fs, i + info->block_group_descriptor_table_block, - (void *) (((uintptr_t) info->block_group_descriptor_table) + i * info->block_size)); - } - - return 0; -} - -static int ext2_fs_umount(struct fs *fs) { - struct ext2_info *info = fs->fs_private; - // Free block group descriptor table - kfree(info->block_group_descriptor_table); - // Free superblock - kfree(info); - return 0; -} - -static struct vnode *ext2_fs_get_root(struct fs *fs) { - struct ext2_info *info = fs->fs_private; - kdebug("ext2_fs_get_root()\n"); - - struct ext2_inode *inode = kmalloc(info->sb.inode_struct_size); - // Read root inode (2) - if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) { - kfree(inode); - return NULL; - } - - struct vnode *res = vnode_create(VN_DIR, NULL); - - res->ino = EXT2_ROOTINO; - res->fs = fs; - res->fs_data = inode; - res->op = &ext2_vnode_ops; - res->type = ext2_inode_type(inode); - - res->uid = inode->uid; - res->gid = inode->gid; - res->mode = inode->type_perm; - - return res; -} - -static int ext2_fs_statvfs(struct fs *fs, struct statvfs *st) { - struct ext2_info *info = fs->fs_private; - - st->f_blocks = info->sb.block_count; - st->f_bfree = info->sb.free_block_count; - st->f_bavail = info->sb.block_count - info->sb.su_reserved; - - st->f_files = info->sb.inode_count; - st->f_ffree = info->sb.free_inode_count; - st->f_favail = info->sb.inode_count - info->sb.first_non_reserved + 1; - - st->f_bsize = info->block_size; - st->f_frsize = info->block_size; - - // XXX: put something here - st->f_fsid = 0; - st->f_flag = 0; - st->f_namemax = 256; - - return 0; -} - - -static struct fs_class ext2_class = { - .name = "ext2", - .get_root = ext2_fs_get_root, - .init = ext2_fs_init, - .mount = NULL, - .umount = ext2_fs_umount, - .statvfs = ext2_fs_statvfs -}; - -void ext2_class_init(void) { - fs_class_register(&ext2_class); -} - diff --git a/sys/vfs/ext2/ext2alloc.c b/sys/vfs/ext2/ext2alloc.c deleted file mode 100644 index d4bcbf6..0000000 --- a/sys/vfs/ext2/ext2alloc.c +++ /dev/null @@ -1,345 +0,0 @@ -// ext2fs block/inode alloc/free -#include "sys/fs/ext2.h" -#include "sys/string.h" -#include "sys/assert.h" -#include "sys/debug.h" -#include "sys/errno.h" - -// #include -// #include -// #include -// #include - -int ext2_alloc_block(struct fs *ext2, uint32_t *block_no) { - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - uint32_t res_block_no = 0; - uint32_t res_group_no = 0; - uint32_t res_block_no_in_group = 0; - int found = 0; - int res; - - for (size_t i = 0; i < info->block_group_count; ++i) { - if (info->block_group_descriptor_table[i].free_blocks > 0) { - // Found a free block here - kdebug("Allocating a block in group #%u\n", i); - - if ((res = ext2_read_block(ext2, - info->block_group_descriptor_table[i].block_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - for (size_t j = 0; j < info->block_size / sizeof(uint64_t); ++j) { - uint64_t qw = ((uint64_t *) block_buffer)[j]; - if (qw != (uint64_t) -1) { - for (size_t k = 0; k < 64; ++k) { - if (!(qw & (1 << k))) { - res_block_no_in_group = k + j * 64; - res_group_no = i; - // XXX: had to increment the resulting block_no - // because for some reason linux's ext2 - // impl hasn't marked #531 as used in one - // case, but it was actually a L1-indirect - // block. So I just had to make it allocate - // #532 instead as a workaround (though - // block numbering should start with 0) - res_block_no = res_block_no_in_group + i * info->sb.block_group_size_blocks + 1; - found = 1; - break; - } - } - - if (found) { - break; - } - } - } - if (found) { - break; - } - } - } - - if (!found) { - return -ENOSPC; - } - - // Write block usage bitmap - ((uint64_t *) block_buffer)[res_block_no_in_group / 64] |= (1 << (res_block_no_in_group % 64)); - if ((res = ext2_write_block(ext2, - info->block_group_descriptor_table[res_group_no].block_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Update BGDT - --info->block_group_descriptor_table[res_group_no].free_blocks; - for (size_t i = 0; i < info->block_group_descriptor_table_size_blocks; ++i) { - void *blk_ptr = (void *) (((uintptr_t) info->block_group_descriptor_table) + i * info->block_size); - - if ((res = ext2_write_block(ext2, info->block_group_descriptor_table_block + i, blk_ptr)) < 0) { - return res; - } - } - - // Update global block count and flush superblock - --info->sb.free_block_count; - if ((res = ext2_write_superblock(ext2)) < 0) { - return res; - } - - *block_no = res_block_no; - kdebug("Allocated block #%u\n", res_block_no); - return 0; -} - -int ext2_free_block(struct fs *ext2, uint32_t block_no) { - _assert(block_no); - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - int res; - - uint32_t block_group_no = (block_no - 1) / info->sb.block_group_size_blocks; - uint32_t block_no_in_group = (block_no - 1) % info->sb.block_group_size_blocks; - - // Read block ussge bitmap block - if ((res = ext2_read_block(ext2, - info->block_group_descriptor_table[block_group_no].block_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Update the bitmap - _assert(((uint64_t *) block_buffer)[block_no_in_group / 64] & (1 << (block_no_in_group % 64))); - ((uint64_t *) block_buffer)[block_no_in_group / 64] &= ~(1 << (block_no_in_group % 64)); - - if ((res = ext2_write_block(ext2, - info->block_group_descriptor_table[block_group_no].block_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Update BGDT - ++info->block_group_descriptor_table[block_group_no].free_blocks; - for (size_t i = 0; i < info->block_group_descriptor_table_size_blocks; ++i) { - void *blk_ptr = (void *) (((uintptr_t) info->block_group_descriptor_table) + i * info->block_size); - - if ((res = ext2_write_block(ext2, info->block_group_descriptor_table_block + i, blk_ptr)) < 0) { - return res; - } - } - - // Update global block count - ++info->sb.free_block_count; - if ((res = ext2_write_superblock(ext2)) < 0) { - return res; - } - - kdebug("Freed block #%u\n", block_no); - - return 0; -} - -int ext2_inode_alloc_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index) { - struct ext2_info *info = ext2->fs_private; - - int res; - uint32_t block_no; - - // Allocate the block itself - if ((res = ext2_alloc_block(ext2, &block_no)) < 0) { - return res; - } - - if (index < 12) { - // Write direct block list entry - inode->direct_blocks[index] = block_no; - } else if (index < 12 + (info->block_size / 4)) { - // Also allocate L1 indirection block if needed - char buf[info->block_size]; - if (!inode->l1_indirect_block) { - uint32_t l1_block; - if ((res = ext2_alloc_block(ext2, &l1_block)) < 0) { - return res; - } - inode->l1_indirect_block = l1_block; - _assert(inode->l1_indirect_block); - memset(buf, 0, info->block_size); - } else { - // Read indirection block - if ((res = ext2_read_block(ext2, inode->l1_indirect_block, buf)) < 0) { - return res; - } - } - - ((uint32_t *) buf)[index - 12] = block_no; - - // Write the block back - if ((res = ext2_write_block(ext2, inode->l1_indirect_block, buf)) < 0) { - return res; - } - } else { - panic("Inode block index has too high indirection level\n"); - } - - // Flush changes to the device - return ext2_write_inode(ext2, inode, ino); -} - -//int ext2_free_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index) { -// if (index >= 12) { -// panic("Not implemented\n"); -// } -// // All sanity checks regarding whether the block is present -// // at all are left to the caller -// -// int res; -// uint32_t block_no; -// -// // Get block number -// block_no = inode->direct_blocks[index]; -// -// // Free the block -// if ((res = ext2_free_block(ext2, block_no)) < 0) { -// return res; -// } -// -// // Write updated inode -// inode->direct_blocks[index] = 0; -// return ext2_write_inode(ext2, inode, ino); -//} - -int ext2_free_inode(struct fs *ext2, uint32_t ino) { - _assert(ino); - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - uint32_t ino_block_group_number = (ino - 1) / info->sb.block_group_size_inodes; - uint32_t ino_inode_index_in_group = (ino - 1) % info->sb.block_group_size_inodes; - int res; - - // Read inode usage block - if ((res = ext2_read_block(ext2, - info->block_group_descriptor_table[ino_block_group_number].inode_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Remove usage bit - _assert(((uint64_t *) block_buffer)[ino_inode_index_in_group / 64] & (1 << (ino_inode_index_in_group % 64))); - ((uint64_t *) block_buffer)[ino_inode_index_in_group / 64] &= ~(1 << (ino_inode_index_in_group % 64)); - - // Write modified bitmap back - if ((res = ext2_write_block(ext2, - info->block_group_descriptor_table[ino_block_group_number].inode_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Increment free inode count in BGDT entry and write it back - // TODO: this code is repetitive and maybe should be moved to - // ext2_bgdt_inode_inc/_dec() - ++info->block_group_descriptor_table[ino_block_group_number].free_inodes; - for (size_t i = 0; i < info->block_group_descriptor_table_size_blocks; ++i) { - void *blk_ptr = (void *) (((uintptr_t) info->block_group_descriptor_table) + i * info->block_size); - - if ((res = ext2_write_block(ext2, info->block_group_descriptor_table_block + i, blk_ptr)) < 0) { - return res; - } - } - - // Update global inode count - ++info->sb.free_inode_count; - if ((res = ext2_write_superblock(ext2)) < 0) { - return res; - } - - kdebug("Freed inode #%u\n", ino); - return 0; -} - -int ext2_alloc_inode(struct fs *ext2, uint32_t *ino) { - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - uint32_t res_ino = 0; - uint32_t res_group_no = 0; - uint32_t res_ino_number_in_group = 0; - int res; - - // Look through BGDT to find any block groups with free inodes - for (size_t i = 0; i < info->block_group_count; ++i) { - if (info->block_group_descriptor_table[i].free_inodes > 0) { - // Found a block group with free inodes - kdebug("Allocating an inode inside block group #%u\n", i); - - // Read inode usage bitmap - if ((res = ext2_read_block(ext2, - info->block_group_descriptor_table[i].inode_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Find a free bit - // Think this should be fine on amd64 - for (size_t j = 0; j < info->block_size / sizeof(uint64_t); ++j) { - // Get bitmap qword - uint64_t qw = ((uint64_t *) block_buffer)[j]; - // If not all bits are set in this qword, find exactly which one - if (qw != ((uint64_t) -1)) { - for (size_t k = 0; k < 64; ++k) { - if (!(qw & (1 << k))) { - res_ino_number_in_group = k + j * 64; - res_group_no = i; - res_ino = res_ino_number_in_group + i * info->sb.block_group_size_inodes + 1; - break; - } - } - - if (res_ino) { - break; - } - } - - if (res_ino) { - break; - } - } - } - - if (res_ino) { - break; - } - } - if (res_ino == 0) { - return -ENOSPC; - } - - // Write updated bitmap - ((uint64_t *) block_buffer)[res_ino_number_in_group / 64] |= (1 << (res_ino_number_in_group % 64)); - if ((res = ext2_write_block(ext2, - info->block_group_descriptor_table[res_group_no].inode_usage_bitmap_block, - block_buffer)) < 0) { - return res; - } - - // Write updated BGDT - --info->block_group_descriptor_table[res_group_no].free_inodes; - for (size_t i = 0; i < info->block_group_descriptor_table_size_blocks; ++i) { - void *blk_ptr = (void *) (((uintptr_t) info->block_group_descriptor_table) + i * info->block_size); - - if ((res = ext2_write_block(ext2, info->block_group_descriptor_table_block + i, blk_ptr)) < 0) { - return res; - } - } - - // Update global inode count and flush superblock - --info->sb.free_inode_count; - if ((res = ext2_write_superblock(ext2)) < 0) { - return res; - } - - *ino = res_ino; - - return 0; -} - diff --git a/sys/vfs/ext2/ext2blk.c b/sys/vfs/ext2/ext2blk.c deleted file mode 100644 index e67193f..0000000 --- a/sys/vfs/ext2/ext2blk.c +++ /dev/null @@ -1,133 +0,0 @@ -#include "sys/fs/ext2.h" -#include "sys/string.h" -#include "sys/assert.h" -#include "sys/errno.h" -#include "sys/debug.h" - -#define ext2_super(e) ((struct ext2_info *) (e)->fs_private) - -int ext2_write_superblock(struct fs *ext2) { - struct ext2_info *info = ext2->fs_private; - return blk_write(ext2->blk, info, EXT2_SBOFF, EXT2_SBSIZ); -} - -int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf) { - if (!block_no) { - return -1; - } - //printf("ext2_read_block %u\n", block_no); - int res = blk_read(ext2->blk, buf, block_no * ext2_super(ext2)->block_size, ext2_super(ext2)->block_size); - - if (res < 0) { - //fprintf(stderr, "ext2: Failed to read %uth block\n", block_no); - kerror("ext2: Failed to read %uth block\n", block_no); - } - - return res; -} - -int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf) { - if (!block_no) { - return -1; - } - - int res = blk_write(ext2->blk, buf, block_no * ext2_super(ext2)->block_size, ext2_super(ext2)->block_size); - - if (res < 0) { - //fprintf(stderr, "ext2: Failed to write %uth block\n", block_no); - kerror("ext2: Failed to write %uth block\n", block_no); - } - - return res; -} - -static uint32_t ext2_get_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index) { - if (index < 12) { - return inode->direct_blocks[index]; - } else { - struct ext2_info *info = ext2->fs_private; - char buf[1024]; - int res; - - if (index < 12 + (info->block_size / 4)) { - if ((res = ext2_read_block(ext2, inode->l1_indirect_block, buf)) < 0) { - return res; - } - - return ((uint32_t *) buf)[index - 12]; - } else { - panic("Inode block index has too high indirection level\n"); - } - } -} - -int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf) { - uint32_t block_number = ext2_get_inode_block(ext2, inode, index); - return ext2_write_block(ext2, block_number, buf); -} - -int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf) { - uint32_t block_number = ext2_get_inode_block(ext2, inode, index); - return ext2_read_block(ext2, block_number, buf); -} - -int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino) { - struct ext2_info *info = ext2->fs_private; - //printf("ext2_read_inode %d\n", ino); - char inode_block_buffer[info->block_size]; - - uint32_t ino_block_group_number = (ino - 1) / info->sb.block_group_size_inodes; - //printf("inode block group number = %d\n", ino_block_group_number); - uint32_t ino_inode_table_block = info->block_group_descriptor_table[ino_block_group_number].inode_table_block; - //printf("inode table is at block %d\n", ino_inode_table_block); - uint32_t ino_inode_index_in_group = (ino - 1) % info->sb.block_group_size_inodes; - //printf("inode entry index in the group = %d\n", ino_inode_index_in_group); - uint32_t ino_inode_block_in_group = (ino_inode_index_in_group * info->sb.inode_struct_size) / info->block_size; - //printf("inode entry offset is %d blocks\n", ino_inode_block_in_group); - uint32_t ino_inode_block_number = ino_inode_block_in_group + ino_inode_table_block; - //printf("inode block number is %uth block\n", ino_inode_block_number); - - //struct ext2_inode *root_inode_block_inode_table = (struct ext2_inode *) root_inode_block_buf; - if (ext2_read_block(ext2, ino_inode_block_number, inode_block_buffer) < 0) { - kerror("ext2: failed to load inode#%d block\n", ino); - return -1; - } - - uint32_t ino_entry_in_block = (ino_inode_index_in_group * info->sb.inode_struct_size) % info->block_size; - memcpy(inode, &inode_block_buffer[ino_entry_in_block], info->sb.inode_struct_size); - - return 0; -} - -int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino) { - struct ext2_info *info = ext2->fs_private; - //printf("ext2_read_inode %d\n", ino); - char inode_block_buffer[info->block_size]; - int res; - - uint32_t ino_block_group_number = (ino - 1) / info->sb.block_group_size_inodes; - //printf("inode block group number = %d\n", ino_block_group_number); - uint32_t ino_inode_table_block = info->block_group_descriptor_table[ino_block_group_number].inode_table_block; - //printf("inode table is at block %d\n", ino_inode_table_block); - uint32_t ino_inode_index_in_group = (ino - 1) % info->sb.block_group_size_inodes; - //printf("inode entry index in the group = %d\n", ino_inode_index_in_group); - uint32_t ino_inode_block_in_group = (ino_inode_index_in_group * info->sb.inode_struct_size) / info->block_size; - //printf("inode entry offset is %d blocks\n", ino_inode_block_in_group); - uint32_t ino_inode_block_number = ino_inode_block_in_group + ino_inode_table_block; - //printf("inode block number is %uth block\n", ino_inode_block_number); - - // Need to read the block to modify it - if ((res = ext2_read_block(ext2, ino_inode_block_number, inode_block_buffer)) < 0) { - return res; - } - - uint32_t ino_entry_in_block = (ino_inode_index_in_group * info->sb.inode_struct_size) % info->block_size; - memcpy(&inode_block_buffer[ino_entry_in_block], inode, info->sb.inode_struct_size); - - // Write the block back - if ((res = ext2_write_block(ext2, ino_inode_block_number, inode_block_buffer)) < 0) { - return res; - } - - return 0; -} diff --git a/sys/vfs/ext2/ext2dir.c b/sys/vfs/ext2/ext2dir.c deleted file mode 100644 index a6c947c..0000000 --- a/sys/vfs/ext2/ext2dir.c +++ /dev/null @@ -1,177 +0,0 @@ -// ext2fs directory content operations -#include "sys/fs/ext2.h" -#include "sys/string.h" -#include "sys/assert.h" -#include "sys/debug.h" -#include "sys/errno.h" - -// #include -// #include -// #include -// #include -// #include - -// Add an inode to directory -int ext2_dir_add_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino) { - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - struct ext2_inode *dir_inode = dir->fs_data; - struct ext2_dirent *current_dirent, *result_dirent; - int res; - - size_t req_free = strlen(name) + sizeof(struct ext2_dirent); - // Align up 4 bytes - req_free = (req_free + 3) & ~3; - - // Try reading parent dirent blocks to see if any has - // some space to fit our file - size_t dir_size_blocks = (dir_inode->size_lower + info->block_size - 1) / info->block_size; - for (size_t i = 0; i < dir_size_blocks; ++i) { - current_dirent = NULL; - result_dirent = NULL; - size_t off = 0; - - // Read directory content block - if ((res = ext2_read_inode_block(ext2, dir_inode, i, block_buffer)) < 0) { - return res; - } - - // Check if any of the entries can be split to fit our entry - while (off < info->block_size) { - current_dirent = (struct ext2_dirent *) &block_buffer[off]; - if (current_dirent->ino == 0) { - kwarn("ext2: found dirent with ino = 0\n"); - } - - // Check how much space we need to still store the entry - size_t real_len = current_dirent->name_len + sizeof(struct dirent); - real_len = (real_len + 3) & ~3; - - // And check how much is left to fit our entry - if (real_len < current_dirent->len /* Sanity? */ && - current_dirent->len - real_len >= req_free) { - // Yay, can fit our dirent in there - - // Sanity check that we're aligned properly - _assert(((off + real_len) & 3) == 0); - result_dirent = (struct ext2_dirent *) &block_buffer[off + real_len]; - result_dirent->len = current_dirent->len - real_len; - result_dirent->name_len = strlen(name); - result_dirent->type_ind = 0; - result_dirent->ino = ino; - strncpy(result_dirent->name, name, result_dirent->name_len); - current_dirent->len = real_len; - - if ((res = ext2_write_inode_block(ext2, dir_inode, i, block_buffer)) < 0) { - return res; - } - - return 0; - } - - off += current_dirent->len; - } - } - - dir_inode->size_lower += info->block_size; - if ((res = ext2_inode_alloc_block(ext2, dir_inode, dir->ino, dir_size_blocks)) < 0) { - dir_inode->size_lower -= info->block_size; - return res; - } - - memset(block_buffer, 0, info->block_size); - current_dirent = (struct ext2_dirent *) block_buffer; - current_dirent->ino = ino; - current_dirent->len = info->block_size; - current_dirent->name_len = strlen(name); - current_dirent->type_ind = 0; - strncpy(current_dirent->name, name, current_dirent->name_len); - - return ext2_write_inode_block(ext2, dir_inode, dir_size_blocks, block_buffer); -} - -// Not only free the block itself, but also remove it from index list -static int ext2_free_block_index(struct fs *ext2, struct ext2_inode *inode, uint32_t index, uint32_t ino, size_t sz) { - if (index >= 12) { - // TODO: Implement this - panic("Not implemented\n"); - } - - int res; - uint32_t block_no = inode->direct_blocks[index]; - - if ((res = ext2_free_block(ext2, block_no)) < 0) { - return res; - } - - // Shift direct indexed blocks - for (uint32_t i = index; i < 11; ++i) { - inode->direct_blocks[i] = inode->direct_blocks[i + 1]; - } - // TODO: inode->direct_blocks[11] becomes the first block of indirect block - inode->direct_blocks[11] = 0; - - inode->size_lower -= sz; - - return ext2_write_inode(ext2, inode, ino); -} - -int ext2_dir_remove_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino) { - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - struct ext2_inode *dir_inode = dir->fs_data; - struct ext2_dirent *current_dirent, *prev_dirent; - int res; - - size_t dir_size_blocks = (dir_inode->size_lower + info->block_size - 1) / info->block_size; - - for (size_t i = 0; i < dir_size_blocks; ++i) { - if ((res = ext2_read_inode_block(ext2, dir_inode, i, block_buffer)) < 0) { - return res; - } - - size_t off = 0; - current_dirent = NULL; - prev_dirent = NULL; - - while (off < info->block_size) { - prev_dirent = current_dirent; - current_dirent = (struct ext2_dirent *) &block_buffer[off]; - - if (current_dirent->ino == 0) { - kwarn("ext2: found dirent with ino = 0\n"); - } - - if (current_dirent->name_len == strlen(name) && - !strncmp(current_dirent->name, name, current_dirent->name_len)) { - // Found matching dirent - // Sanity - _assert(current_dirent->ino == ino); - - if (current_dirent->len + off >= info->block_size) { - // It's the last node in the list - if (!prev_dirent) { - return ext2_free_block_index(ext2, dir_inode, i, dir->ino, info->block_size); - } - - // Resize the previous node - prev_dirent->len += current_dirent->len; - return ext2_write_inode_block(ext2, dir_inode, i, block_buffer); - } else { - // It's not the last one - relocate the next entry - uint32_t len = current_dirent->len; - struct ext2_dirent *next_dirent = (struct ext2_dirent *) &block_buffer[off + len]; - memmove(current_dirent, next_dirent, next_dirent->len); - next_dirent = current_dirent; - next_dirent->len += len; - _assert(((off + len) & 3) == 0); - return ext2_write_inode_block(ext2, dir_inode, i, block_buffer); - } - } - - off += current_dirent->len; - } - } - - return -EIO; -} diff --git a/sys/vfs/ext2/ext2vnop.c b/sys/vfs/ext2/ext2vnop.c deleted file mode 100644 index ae88d71..0000000 --- a/sys/vfs/ext2/ext2vnop.c +++ /dev/null @@ -1,867 +0,0 @@ -// ext2fs vnode operations -#include "sys/fs/ext2.h" -#include "sys/fs/node.h" -#include "sys/fs/ofile.h" -#include "sys/fcntl.h" -#include "sys/fs/vfs.h" -#include "sys/string.h" -#include "sys/debug.h" -#include "sys/assert.h" -#include "sys/panic.h" -#include "sys/errno.h" -#include "sys/time.h" -#include "sys/heap.h" - -// #include -// #include -// #include -// #include -// #include -// #include - -// Forward declaration of ext2 vnode functions -static int ext2_vnode_find(struct vnode *vn, const char *name, struct vnode **resvn); -static int ext2_vnode_creat(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode); -static int ext2_vnode_mkdir(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode); -static int ext2_vnode_open(struct ofile *fd, int opt); -static int ext2_vnode_opendir(struct ofile *fd); -static ssize_t ext2_vnode_read(struct ofile *fd, void *buf, size_t count); -static ssize_t ext2_vnode_write(struct ofile *fd, const void *buf, size_t count); -static int ext2_vnode_truncate(struct vnode *vn, size_t length); -static ssize_t ext2_vnode_readdir(struct ofile *fd, struct dirent *ent); -//static void ext2_vnode_destroy(vnode_t *vn); -static int ext2_vnode_stat(struct vnode *vn, struct stat *st); -static int ext2_vnode_chmod(struct vnode *vn, mode_t mode); -static int ext2_vnode_chown(struct vnode *vn, uid_t uid, gid_t gid); -static int ext2_vnode_unlink(struct vnode *vn); -//static int ext2_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode); -static int ext2_vnode_readlink(struct vnode *vn, char *dst, size_t lim); -//static int ext2_vnode_symlink(vnode_t *at, struct vfs_ioctx *ctx, const char *name, const char *dst); -static off_t ext2_vnode_lseek(struct ofile *fd, off_t offset, int whence); - -struct vnode_operations ext2_vnode_ops = { - .find = ext2_vnode_find, - .creat = ext2_vnode_creat, - .lseek = ext2_vnode_lseek, - .mkdir = ext2_vnode_mkdir, -// .destroy = ext2_vnode_destroy, -// - .readlink = ext2_vnode_readlink, -// .symlink = ext2_vnode_symlink, -// - .chmod = ext2_vnode_chmod, - .chown = ext2_vnode_chown, - .stat = ext2_vnode_stat, - .unlink = ext2_vnode_unlink, -// .access = ext2_vnode_access, -// - .opendir = ext2_vnode_opendir, - .readdir = ext2_vnode_readdir, - - .open = ext2_vnode_open, - .read = ext2_vnode_read, - .write = ext2_vnode_write, - .truncate = ext2_vnode_truncate, -}; - -//// vnode function implementation - -static int ext2_vnode_find(struct vnode *vn, const char *name, struct vnode **res) { - struct fs *ext2 = vn->fs; - struct ext2_info *info = vn->fs->fs_private; - struct ext2_inode *inode = vn->fs_data; - - char buffer[info->block_size]; - struct ext2_dirent *dirent = NULL; - - size_t block_count = (inode->size_lower + (info->block_size - 1)) / info->block_size; - // char ent_name[256]; - size_t index = 0; - - while (index < block_count) { - // Read directory contents block - if (ext2_read_inode_block(ext2, inode, index, buffer) < 0) { - return -EIO; - } - - size_t offset = 0; - while (1) { - dirent = (struct ext2_dirent *) &buffer[offset]; - if (!dirent->len) { - break; - } - if (dirent->ino) { - if (strlen(name) == dirent->name_len && !strncmp(dirent->name, name, dirent->name_len)) { - // Found the entry - inode = kmalloc(info->sb.inode_struct_size); - if (ext2_read_inode(ext2, inode, dirent->ino) != 0) { - return -EIO; - } - - struct vnode *node = vnode_create(ext2_inode_type(inode), name); - node->fs = ext2; - node->fs_data = inode; - node->ino = dirent->ino; - node->op = &ext2_vnode_ops; - - node->mode = inode->type_perm & VFS_MODE_MASK; - node->uid = inode->uid; - node->gid = inode->gid; - - node->open_count = 0; - - *res = node; - - return 0; - } - } - offset += dirent->len; - if (offset >= info->block_size) { - break; - } - } - - ++index; - } - - return -ENOENT; -} - -static int ext2_vnode_opendir(struct ofile *fd) { - _assert(fd); - _assert(fd->vnode); - _assert(fd->vnode->type == VN_DIR); - - fd->pos = 0; - - return 0; -} - -static int ext2_vnode_open(struct ofile *fd, int opt) { - _assert(fd); - _assert(fd->vnode); - _assert(fd->vnode->type == VN_REG); - - if (opt & O_APPEND) { - struct ext2_inode *inode = (struct ext2_inode *) fd->vnode->fs_data; - _assert(inode); - fd->pos = inode->size_lower; - } else { - fd->pos = 0; - } - - return 0; -} - -static int ext2_vnode_mkdir(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode) { - struct fs *ext2 = at->fs; - _assert(at->type == VN_DIR); - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - - uint32_t new_ino, new_block_no; - int res; - - // Allocate a new inode for the directory - if ((res = ext2_alloc_inode(ext2, &new_ino)) != 0) { - kerror("ext2: Failed to allocate an inode\n"); - return res; - } - - // Allocate a block for "." and ".." entries - if ((res = ext2_alloc_block(ext2, &new_block_no)) < 0) { - kerror("ext2: Failed to allocate a block\n"); - return res; - } - - struct ext2_inode *ent_inode = (struct ext2_inode *) kmalloc(info->sb.inode_struct_size); - - // Now create an entry in parents dirent list - if ((res = ext2_dir_add_inode(ext2, at, name, new_ino)) < 0) { - return res; - } - - // Fill the inode - ent_inode->flags = 0; - ent_inode->dir_acl = 0; - ent_inode->frag_block_addr = 0; - ent_inode->gen_number = 0; - ent_inode->hard_link_count = 1; - ent_inode->acl = 0; - ent_inode->os_value_1 = 0; - memset(ent_inode->os_value_2, 0, sizeof(ent_inode->os_value_2)); - time_t cur_time = time(); - ent_inode->atime = cur_time; - ent_inode->mtime = cur_time; - ent_inode->ctime = cur_time; - ent_inode->dtime = 0; - - memset(ent_inode->direct_blocks, 0, sizeof(ent_inode->direct_blocks)); - ent_inode->direct_blocks[0] = new_block_no; - ent_inode->l1_indirect_block = 0; - ent_inode->l2_indirect_block = 0; - ent_inode->l3_indirect_block = 0; - - ent_inode->type_perm = (mode & VFS_MODE_MASK) | EXT2_TYPE_DIR; - ent_inode->uid = uid; - ent_inode->gid = gid; - ent_inode->disk_sector_count = 0; - ent_inode->size_lower = info->block_size; - - memset(block_buffer, 0, info->block_size); - // "." - struct ext2_dirent *dirent = (struct ext2_dirent *) block_buffer; - dirent->ino = new_ino; - dirent->name_len = 1; - dirent->len = (sizeof(struct ext2_dirent) + 4) & ~3; - dirent->name[0] = '.'; - dirent->type_ind = 0; - - // ".." - dirent = (struct ext2_dirent *) &block_buffer[dirent->len]; - dirent->ino = at->ino; - dirent->name_len = 2; - dirent->len = info->block_size - ((sizeof(struct ext2_dirent) + 4) & ~3); - dirent->name[0] = '.'; - dirent->name[1] = '.'; - dirent->type_ind = 0; - - // Write directory's first block - if ((res = ext2_write_block(ext2, new_block_no, block_buffer)) < 0) { - return res; - } - - // Write directory inode - if ((res = ext2_write_inode(ext2, ent_inode, new_ino)) < 0) { - return res; - } - - return 0; -} - -static int ext2_vnode_creat(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode) { - struct fs *ext2 = at->fs; - _assert(at->type == VN_DIR); - _assert(/* Don't support making directories like this */ !(mode & O_DIRECTORY)); - struct ext2_info *info = ext2->fs_private; - - uint32_t new_ino; - int res; - - // Allocate new inode number - if ((res = ext2_alloc_inode(ext2, &new_ino)) != 0) { - kerror("Failed to allocate inode\n"); - return res; - } - - kdebug("Allocated inode %d\n", new_ino); - - // Create an inode struct in memory - struct ext2_inode *ent_inode = (struct ext2_inode *) kmalloc(info->sb.inode_struct_size); - - // Now create an entry in parents dirent list - if ((res = ext2_dir_add_inode(ext2, at, name, new_ino)) < 0) { - return res; - } - - // Fill the inode - ent_inode->flags = 0; - ent_inode->dir_acl = 0; - ent_inode->frag_block_addr = 0; - ent_inode->gen_number = 0; - ent_inode->hard_link_count = 1; - ent_inode->acl = 0; - ent_inode->os_value_1 = 0; - memset(ent_inode->os_value_2, 0, sizeof(ent_inode->os_value_2)); - - time_t cur_time = time(); - ent_inode->atime = cur_time; - ent_inode->mtime = cur_time; - ent_inode->ctime = cur_time; - ent_inode->dtime = 0; - - memset(ent_inode->direct_blocks, 0, sizeof(ent_inode->direct_blocks)); - ent_inode->l1_indirect_block = 0; - ent_inode->l2_indirect_block = 0; - ent_inode->l3_indirect_block = 0; - - ent_inode->uid = uid; - ent_inode->gid = gid; - // NOTE: only regular files can be created this way now - ent_inode->type_perm = (mode & VFS_MODE_MASK) | (EXT2_TYPE_REG); - ent_inode->disk_sector_count = 0; - ent_inode->size_lower = 0; - - // Write the inode - if ((res = ext2_write_inode(ext2, ent_inode, new_ino)) < 0) { - return res; - } - - kfree(ent_inode); - - return 0; -} -// -static ssize_t ext2_vnode_read(struct ofile *fd, void *buf, size_t count) { - struct vnode *vn = fd->vnode; - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - struct ext2_info *info = vn->fs->fs_private; - - size_t nread = MIN(inode->size_lower - fd->pos, count); - - if (nread == 0) { - return -1; - } - - size_t block_number = fd->pos / info->block_size; - size_t nblocks = (nread + info->block_size - 1) / info->block_size; - char block_buffer[info->block_size]; - - for (size_t i = 0; i < nblocks; ++i) { - if (ext2_read_inode_block(vn->fs, inode, i + block_number, block_buffer) < 0) { - kerror("Failed to read inode %d block #%u\n", vn->ino, i + block_number); - return -EIO; - } - if (i == 0) { - size_t ncpy = MIN(info->block_size - fd->pos % info->block_size, nread); - memcpy(buf, block_buffer + fd->pos % info->block_size, ncpy); - } else { - size_t ncpy = MIN(info->block_size, nread - info->block_size * i); - memcpy((void *) (((uintptr_t) buf) + info->block_size * i), block_buffer, ncpy); - } - } - - fd->pos += nread; - - return nread; -} - -static ssize_t ext2_vnode_write(struct ofile *fd, const void *buf, size_t count) { - struct vnode *vn = fd->vnode; - _assert(vn); - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - struct fs *ext2 = vn->fs; - struct ext2_info *info = ext2->fs_private; - char block_buffer[info->block_size]; - int res; - - if (fd->pos > inode->size_lower) { - // This shouldn't be possible, yeah? - return -ESPIPE; - } - - // How many bytes can we write into the blocks already allocated - size_t size_blocks = (inode->size_lower + info->block_size - 1) / info->block_size; - size_t can_write = size_blocks * info->block_size - inode->size_lower; - size_t current_block = fd->pos / info->block_size; - size_t written = 0; - size_t remaining = count; - - // Update mtime on writes - // TODO: something like nomtime option - inode->mtime = time(); - - if (can_write) { - size_t can_write_blocks = (can_write + info->block_size - 1) / info->block_size; - - for (size_t i = 0; i < can_write_blocks; ++i) { - size_t block_index = current_block + i; - size_t pos_in_block = fd->pos % info->block_size; - size_t need_write = MIN(remaining, info->block_size - pos_in_block); - - kdebug("Write %uB to block %u offset %u\n", need_write, block_index, pos_in_block); - if (need_write == info->block_size) { - // Can write block without reading it - // TODO: implement this - panic("Not implemented\n"); - } else { - // Read the block to change its contents - // and write it back again - if ((res = ext2_read_inode_block(ext2, inode, block_index, block_buffer)) < 0) { - break; - } - - memcpy(block_buffer + pos_in_block, (void *) (((uintptr_t) buf) + written), need_write); - - if ((res = ext2_write_inode_block(ext2, inode, block_index, block_buffer)) < 0) { - break; - } - } - - written += need_write; - fd->pos += need_write; - remaining -= need_write; - } - - inode->size_lower = MAX(fd->pos, inode->size_lower); - current_block += can_write_blocks; - } - - if (remaining) { - // Need to allocate additional blocks - size_t need_blocks = (remaining + info->block_size - 1) / info->block_size; - - for (size_t i = 0; i < need_blocks; ++i) { - size_t block_index = current_block + i; - size_t need_write = MIN(remaining, info->block_size); - - // Update the size here so it gets written when the block is allocated - // and inode struct is flushed - inode->size_lower += need_write; - // Allocate a block for the index - if ((res = ext2_inode_alloc_block(ext2, inode, vn->ino, block_index)) < 0) { - kerror("Could not allocate a block for writing\n"); - break; - } - - - if (need_write == info->block_size) { - // TODO: implement this - panic("Not implemented\n"); - } else { - // Writing the last block - memcpy(block_buffer, (void *) (((uintptr_t) buf) + written), need_write); - - if ((res = ext2_write_inode_block(ext2, inode, block_index, block_buffer)) < 0) { - break; - } - } - - written += need_write; - fd->pos += need_write; - remaining -= need_write; - } - } - - ext2_write_inode(ext2, inode, vn->ino); - - return written; -} - -static int ext2_vnode_truncate(struct vnode *vn, size_t length) { - _assert(vn); - struct fs *ext2 = vn->fs; - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - struct ext2_info *info = vn->fs->fs_private; - int res; - - if (length == inode->size_lower) { - // Already good - return 0; - } - - size_t was_blocks = (inode->size_lower + info->block_size - 1) / info->block_size; - size_t now_blocks = (length + info->block_size - 1) / info->block_size; - ssize_t delta_blocks = now_blocks - was_blocks; - - if (delta_blocks < 0) { - int ind1 = 0; - char buf1[info->block_size]; - // Free truncated blocks - for (size_t i = now_blocks; i < was_blocks; ++i) { - inode->size_lower -= info->block_size; - - if (i < 12) { - if ((res = ext2_free_block(ext2, inode->direct_blocks[i])) < 0) { - panic("Failed to release inode block\n"); - } - inode->direct_blocks[i] = 0; - } else if (i < 12 + (info->block_size / 4)) { - if (!ind1) { - // Read indirection block only once - if ((res = ext2_read_block(ext2, inode->l1_indirect_block, buf1)) < 0) { - // TODO: rollback inode struct and return error - panic("Failed to read indirection block\n"); - } - ind1 = 1; - } - - if ((res = ext2_free_block(ext2, ((uint32_t *) buf1)[i - 12])) < 0) { - panic("Failed to release inode block\n"); - } - ((uint32_t *) buf1)[i - 12] = 0; - } else { - panic("Inode block index has too high indirection level\n"); - } - } - - // All the blocks were successfully freed, can set proper file length - if (inode->size_lower != length) { - // If requested size is not block-aligned, we need to write inode - // struct to disk once again - inode->size_lower = length; - - if ((res = ext2_write_inode(ext2, inode, vn->ino)) < 0) { - return res; - } - } - - return 0; - } else { - kerror("Not implemented: upwards truncation (ext2)\n"); - return -EINVAL; - } -} - -static ssize_t ext2_vnode_readdir(struct ofile *fd, struct dirent *vfsdir) { - struct vnode *vn = fd->vnode; - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - struct ext2_info *info = vn->fs->fs_private; - ssize_t res; - - if (fd->pos >= inode->size_lower) { - return -1; - } - - size_t block_number = fd->pos / info->block_size; - char block_buffer[info->block_size]; - - if ((res = ext2_read_inode_block(vn->fs, inode, block_number, block_buffer)) < 0) { - return res; - } - - size_t block_offset = fd->pos % info->block_size; - struct ext2_dirent *ext2dir = (struct ext2_dirent *) &block_buffer[block_offset]; - - if (ext2dir->len == 0) { - // If entry size is zero, guess we're finished - align the fd->pos up to block size - fd->pos = (fd->pos + info->block_size - 1) / info->block_size; - return ext2_vnode_readdir(fd, vfsdir); - } - - vfsdir->d_ino = ext2dir->ino; - strncpy(vfsdir->d_name, ext2dir->name, ext2dir->name_len); - vfsdir->d_name[ext2dir->name_len] = 0; - vfsdir->d_reclen = ext2dir->len; - if (info->sb.required_features & 2 /* Directory entries contain type field */) { - switch (ext2dir->type_ind) { - case 1: - // Regular file - vfsdir->d_type = DT_REG; - break; - case 2: - // Directory - vfsdir->d_type = DT_DIR; - break; - // XXX: Don't know if I should have ANY devices in ext2, we have devfs for that - // kind of shit - case 0: - default: - vfsdir->d_type = DT_UNKNOWN; - break; - } - } else { - // Have to read each fucking inode to sort this mess out - struct ext2_inode ent_inode_buf; - - if ((res = ext2_read_inode(vn->fs, &ent_inode_buf, ext2dir->ino)) < 0) { - return res; - } - - switch (ent_inode_buf.type_perm & 0xF000) { - case EXT2_TYPE_REG: - vfsdir->d_type = DT_REG; - break; - case EXT2_TYPE_DIR: - vfsdir->d_type = DT_DIR; - break; - default: - vfsdir->d_type = DT_UNKNOWN; - break; - } - } - // Not implemented, I guess - vfsdir->d_off = 0; - - fd->pos += ext2dir->len; - - return ext2dir->len; -} - -//static void ext2_vnode_destroy(vnode_t *vn) { -// // Release inode struct -// kfree(vn->fs_data); -//} - -static int ext2_vnode_stat(struct vnode *vn, struct stat *st) { - _assert(vn && vn->fs); - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - _assert(inode); - struct ext2_info *info = vn->fs->fs_private; - _assert(info); - - st->st_atime = inode->atime; - st->st_ctime = inode->ctime; - st->st_mtime = inode->mtime; - st->st_dev = 0; // Not implemented - st->st_rdev = 0; // Not implemented - st->st_gid = inode->gid; - st->st_uid = inode->uid; - st->st_mode = inode->type_perm; - st->st_size = inode->size_lower; - st->st_blocks = (inode->size_lower + info->block_size - 1) / info->block_size; - st->st_blksize = info->block_size; - st->st_nlink = 0; - st->st_ino = vn->ino; - - return 0; -} - -static int ext2_vnode_chmod(struct vnode *vn, mode_t mode) { - _assert(vn && vn->fs && vn->fs_data); - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - - // Update only access mode - inode->type_perm &= ~VFS_MODE_MASK; - inode->type_perm |= mode & VFS_MODE_MASK; - - // Write the inode back - return ext2_write_inode(vn->fs, inode, vn->ino); -} - -static int ext2_vnode_chown(struct vnode *vn, uid_t uid, gid_t gid) { - _assert(vn && vn->fs && vn->fs_data); - struct ext2_inode *inode = (struct ext2_inode *) vn->fs_data; - - inode->gid = gid; - inode->uid = uid; - - // Write the inode back - return ext2_write_inode(vn->fs, inode, vn->ino); -} - -static int ext2_vnode_unlink(struct vnode *node) { - _assert(node); - _assert(node->parent); - struct vnode *at = node->parent; - - struct ext2_inode *inode = node->fs_data; - struct ext2_inode *at_inode = at->fs_data; - struct fs *ext2 = node->fs; - struct ext2_info *info = ext2->fs_private; - uint32_t ino = node->ino; - int res; - - if (node->type == VN_DIR) { - // Check if the directory we're unlinking has any entries besides - // . and .. - // Can tell this just by looking at the first block - if (inode->size_lower > info->block_size) { - // Directory size is more than one block - totally - // has something inside - return -EISDIR; - } - char block_buffer[info->block_size]; - size_t off = 0; - - if ((res = ext2_read_inode_block(ext2, inode, 0, block_buffer)) < 0) { - return res; - } - - while (off < info->block_size) { - struct ext2_dirent *ent = (struct ext2_dirent *) &block_buffer[off]; - if (!ent->ino) { - break; - } - if (ent->name_len == 1 && ent->name[0] == '.') { - off += ent->len; - continue; - } - if (ent->name_len == 2 && ent->name[1] == '.' && ent->name[0] == '.') { - off += ent->len; - continue; - } - - return -EISDIR; - } - } - - // Free blocks used by the inode - truncate the file to zero - size_t nblocks = (inode->size_lower + info->block_size - 1) / info->block_size; - int ind1 = 0; - char buf1[info->block_size]; - - for (size_t i = 0; i < nblocks; ++i) { - if (i < 12) { - if ((res = ext2_free_block(ext2, inode->direct_blocks[i])) < 0) { - panic("Failed to release inode block\n"); - } - inode->direct_blocks[i] = 0; - } else if (i < 12 + (info->block_size / 4)) { - if (!ind1) { - // Read indirection block only once - if ((res = ext2_read_block(ext2, inode->l1_indirect_block, buf1)) < 0) { - // TODO: rollback inode struct and return error - panic("Failed to read indirection block\n"); - } - ind1 = 1; - } - - if ((res = ext2_free_block(ext2, ((uint32_t *) buf1)[i - 12])) < 0) { - panic("Failed to release inode block\n"); - } - ((uint32_t *) buf1)[i - 12] = 0; - } else { - panic("Inode block index has too high indirection level\n"); - } - } - - // Free the inode itself - if ((res = ext2_free_inode(ext2, ino)) < 0) { - return res; - } - - // Now remove the entry from directory - if ((res = ext2_dir_remove_inode(ext2, at, node->name, ino)) < 0) { - return res; - } - - return 0; -} - -//static int ext2_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode) { -// _assert(vn && vn->fs_data); -// struct ext2_inode *inode = vn->fs_data; -// -// *uid = inode->uid; -// *gid = inode->gid; -// *mode = inode->type_perm & VFS_MODE_MASK; -// -// return 0; -//} -// -static int ext2_vnode_readlink(struct vnode *vn, char *dst, size_t lim) { - _assert(vn && vn->fs_data); - struct ext2_inode *inode = vn->fs_data; - struct fs *ext2 = vn->fs; - struct ext2_info *info = ext2->fs_private; - - if (lim <= inode->size_lower) { - return -1; - } - - if (inode->size_lower >= 60) { - char block_buffer[info->block_size]; - int res; - - if ((res = ext2_read_inode_block(ext2, inode, 0, block_buffer)) < 0) { - return res; - } - - strncpy(dst, block_buffer, inode->size_lower); - dst[inode->size_lower] = 0; - } else { - const char *src = (const char *) inode->direct_blocks; - strncpy(dst, src, inode->size_lower); - dst[inode->size_lower] = 0; - } - - return 0; -} -// -//static int ext2_vnode_symlink(vnode_t *at, struct vfs_ioctx *ctx, const char *name, const char *dst) { -// _assert(at && at->fs && at->fs_data); -// struct ext2_inode *inode = at->fs_data; -// fs_t *ext2 = at->fs; -// struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private; -// -// uint32_t new_ino; -// int res; -// -// // Allocate new inode number -// if ((res = ext2_alloc_inode(ext2, &new_ino)) != 0) { -// kerror("Failed to allocate inode\n"); -// return res; -// } -// -// kdebug("Allocated inode %d\n", new_ino); -// -// // Create an inode struct in memory -// struct ext2_inode *ent_inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size); -// -// // Now create an entry in parents dirent list -// if ((res = ext2_dir_add_inode(ext2, at, name, new_ino)) < 0) { -// return res; -// } -// -// // Fill the inode -// ent_inode->flags = 0; -// ent_inode->dir_acl = 0; -// ent_inode->frag_block_addr = 0; -// ent_inode->gen_number = 0; -// ent_inode->hard_link_count = 1; -// ent_inode->acl = 0; -// ent_inode->os_value_1 = 0; -// memset(ent_inode->os_value_2, 0, sizeof(ent_inode->os_value_2)); -// // TODO: time support in kernel -// ent_inode->atime = 0; -// ent_inode->mtime = 0; -// ent_inode->ctime = 0; -// ent_inode->dtime = 0; -// -// ent_inode->size_lower = strlen(dst); -// -// if (ent_inode->size_lower <= 60) { -// char *dst_str = (char *) ent_inode->direct_blocks; -// memset(dst_str, 0, 60); -// -// strncpy(dst_str, dst, ent_inode->size_lower); -// } else { -// char block_buffer[sb->block_size]; -// uint32_t block_no; -// -// if ((res = ext2_alloc_block(ext2, &block_no)) < 0) { -// return res; -// } -// -// memset(block_buffer, 0, sb->block_size); -// strncpy(block_buffer, dst, sb->block_size); -// -// if ((res = ext2_write_block(ext2, block_no, block_buffer)) < 0) { -// return res; -// } -// -// memset(ent_inode->direct_blocks, 0, sizeof(ent_inode->direct_blocks)); -// ent_inode->l1_indirect_block = 0; -// ent_inode->l2_indirect_block = 0; -// ent_inode->l3_indirect_block = 0; -// -// ent_inode->direct_blocks[0] = block_no; -// } -// -// ent_inode->uid = ctx->uid; -// ent_inode->gid = ctx->gid; -// ent_inode->type_perm = 0777 | EXT2_TYPE_LNK; -// -// // Write the inode -// if ((res = ext2_write_inode(ext2, ent_inode, new_ino)) < 0) { -// return res; -// } -// -// return 0; -//} - -static off_t ext2_vnode_lseek(struct ofile *fd, off_t offset, int whence) { - _assert(fd); - struct vnode *node = fd->vnode; - _assert(node); - _assert(node->type == VN_REG); - struct ext2_inode *inode = node->fs_data; - _assert(inode); - - size_t max = inode->size_lower; - - switch (whence) { - case SEEK_SET: - if ((size_t) offset > max) { - // Don't support seeking beyond file end - return -ENXIO; - } - fd->pos = offset; - break; - default: - panic("Unsupported whence: %d\n", whence); - } - - return fd->pos; -}