// ext2.c // Author: Josh Holtrop // Date: 08/22/04 // Modified: 12/24/04 #include "hos_defines.h" #include "fs/devices.h" #include "display/kout.h" #include "ext2.h" #include "mm/vmm.h" #include "fs/vfs.h" #include "lang/lang.h" #include "functions.h" /* Turning an inode number into a (group, inode_index) pair: * group = (inode - 1) / s_inodes_per_group * index = (inode - 1) % s_inodes_per_group */ vfs_fs_t ext2_driver = {ext2_mount_super, ext2_umount_super, ext2_stat, ext2__get_root_dir_inode, ext2__link_deref, ext2__free_inodes, ext2__total_inodes, ext2__free_blocks, ext2__total_blocks, ext2_alloc_inode, ext2_free_inode, ext2_alloc_block, ext2_free_block, ext2__open_dir, ext2__read_dir, ext2__close_dir, ext2__open_file, ext2__read_file, ext2__close_file, ext2__open_block_file, ext2__read_block_file, ext2__block_file_seek, ext2__close_block_file}; // initialize the filesystem driver int ext2_init(int fsID) { vfs_fs_t *fs; if (( fs = New(vfs_fs_t) )) // give the VFS our FS structure { *fs = ext2_driver; vfs_register_fs(fsID, fs); return 0; } return -1; } // lookup a file name in a directory and store the directory entry for it int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry) { ext2_open_dir_t *dir = ext2_open_dir(mount, dir_inode); if (!dir) return -1; // bad directory inode number ext2_dir_entry_t dentry; while (!ext2_dir_read_entry(mount, dir, &dentry)) { char *dentryName = kcalloc(1, dentry.name_length + 1); memcpy(dentryName, dentry.name, dentry.name_length); int res = strcmp(fileName, dentryName); kfree(dentryName); if (!res) { *direntry = dentry; ext2_close_dir(mount, dir); return 0; } } ext2_close_dir(mount, dir); return -2; } // open a directory by inode number for reading ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number) { ext2_open_dir_t *open_dir = New(ext2_open_dir_t); ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); if (!open_inode) { kfree(open_dir); return NULL; } if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR) { ext2_close_inode(mount, open_inode); kfree(open_dir); return NULL; } open_dir->open_inode = open_inode; open_dir->position = 0; return open_dir; } int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry) { ext2_super_block_t *super = mount->super; if (open_dir->position >= open_dir->open_inode->inode.i_size) return -1; // EOF u32_t dir_block = open_dir->position >> (10 + super->s_log_block_size); char *block = kmalloc(2048 << super->s_log_block_size); ext2_inode_seek(mount, open_dir->open_inode, dir_block); if (ext2_read_inode_block(mount, open_dir->open_inode, block)) ext2_read_inode_block(mount, open_dir->open_inode, block + (1024 << super->s_log_block_size)); ext2_dir_entry_t *dir_entry = (ext2_dir_entry_t *)(block + open_dir->position % (1024 << super->s_log_block_size)); if (!dir_entry->inode) { kfree(block); return -2; // EOF } memcpy(dentry, dir_entry, min(dir_entry->length, sizeof(ext2_dir_entry_t))); open_dir->position += dir_entry->length; kfree(block); return 0; } int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir) { ext2_close_inode(mount, open_dir->open_inode); kfree(open_dir); return 0; } // open an inode for reading ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number) { ext2_open_inode_t *open_inode = New(ext2_open_inode_t); if ( ext2_read_inode(mount, inode_number, &(open_inode->inode)) ) { kfree(open_inode); return NULL; } open_inode->block = 0; open_inode->block_pointers = NULL; open_inode->block_pointers_start = 0; mount->refs++; return open_inode; } // seek to a certain block of an open inode int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number) { ext2_super_block_t *super = mount->super; if (open_inode->inode.i_size <= (block_number << (10 + super->s_log_block_size))) return -1; // at or past EOF open_inode->block = block_number; return 0; } // returns number of bytes read int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block) { ext2_super_block_t *super = mount->super; if (open_inode->inode.i_size <= (open_inode->block << (10 + super->s_log_block_size))) return 0; // at or past EOF u32_t leftover_bytes = open_inode->inode.i_size - (open_inode->block << (10 + super->s_log_block_size)); u32_t block_number = ext2_block_number(mount, open_inode); block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_number, super), 2 << super->s_log_block_size, block); open_inode->block++; return min(leftover_bytes, 1024 << super->s_log_block_size); } // close an open inode int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode) { mount->refs--; if (open_inode->block_pointers) kfree(open_inode->block_pointers); // free the block pointers cache kfree(open_inode); return 0; } // check the status of an inode (1-based inode number) // -1: invalid inode number // 0: free inode // 1: allocated inode int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number) { ext2_super_block_t *super = mount->super; if (inode_number < 1 || inode_number > super->s_inodes_count) // inode number invalid return -1; inode_number--; // turn inode_number into a 0-based index u32_t group = inode_number / super->s_inodes_per_group; u32_t index = inode_number % super->s_inodes_per_group; u32_t inode_bitmap_block = ext2_get_group_desc(mount, group).bg_inode_bitmap + (index >> (13 + super->s_log_block_size)); u32_t bitmap_index = index % (8192 << super->s_log_block_size); u8_t *inode_bitmap = kmalloc(1024 << super->s_log_block_size); block_read(mount->major, mount->minor, ext2_FSToDiskBlock(inode_bitmap_block, super), 2 << super->s_log_block_size, inode_bitmap); int inode_status = (inode_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; kfree(inode_bitmap); return inode_status; } // check the status of a block // -1: invalid block number // 0: free block // 1: allocated block int ext2_block_status(vfs_mount_t *mount, u32_t block_number) { ext2_super_block_t *super = mount->super; if (block_number < super->s_first_data_block || block_number > super->s_blocks_count) // block number invalid return -1; block_number -= super->s_first_data_block; u32_t group = block_number / super->s_blocks_per_group; u32_t index = block_number % super->s_blocks_per_group; u32_t block_bitmap_block = ext2_get_group_desc(mount, group).bg_block_bitmap + (index >> (13 + super->s_log_block_size)); u32_t bitmap_index = index % (8192 << super->s_log_block_size); u8_t *block_bitmap = kmalloc(1024 << super->s_log_block_size); block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_bitmap_block, super), 2 << super->s_log_block_size, block_bitmap); int block_status = (block_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; kfree(block_bitmap); return block_status; } // transform open_inode->block (a relative block number) to an absolute block number for the filesystem u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode) { if (open_inode->block < 12) return open_inode->inode.i_block[open_inode->block]; ext2_super_block_t *super = mount->super; int pointersPerBlock = 256 << super->s_log_block_size; if (open_inode->block_pointers && // there is a block pointers cache block allocated (open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it (open_inode->block < (open_inode->block_pointers_start + pointersPerBlock))) return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start]; u32_t rel_block = open_inode->block - 12; if (!open_inode->block_pointers) open_inode->block_pointers = kmalloc(pointersPerBlock << 2); if (rel_block < pointersPerBlock) // indirect block in i_block[12] { block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super), 2 << super->s_log_block_size, open_inode->block_pointers); open_inode->block_pointers_start = 12; return open_inode->block_pointers[rel_block]; } rel_block -= pointersPerBlock; if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13] { block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super), 2 << super->s_log_block_size, open_inode->block_pointers); u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock]; block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super), 2 << super->s_log_block_size, open_inode->block_pointers); open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock); return open_inode->block_pointers[rel_block % pointersPerBlock]; } // this code shouldn't run unless we are dealing with a 65+mb file ... rel_block -= pointersPerBlock * pointersPerBlock; block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super), 2 << super->s_log_block_size, open_inode->block_pointers); u32_t index_1 = rel_block / (pointersPerBlock * pointersPerBlock); u32_t leftover_1 = rel_block % (pointersPerBlock * pointersPerBlock); u32_t block_1 = open_inode->block_pointers[index_1]; block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super), 2 << super->s_log_block_size, open_inode->block_pointers); u32_t index_2 = leftover_1 / pointersPerBlock; u32_t leftover_2 = leftover_1 % pointersPerBlock; u32_t block_2 = open_inode->block_pointers[index_2]; block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_2, super), 2 << super->s_log_block_size, open_inode->block_pointers); open_inode->block_pointers_start = 12 + (pointersPerBlock + 1) * pointersPerBlock + rel_block - (rel_block % pointersPerBlock); return open_inode->block_pointers[leftover_2]; } // read the inode structure from the device int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) { if (ext2_inode_status(mount, inode) != 1) return -1; // free or invalid inode number ext2_super_block_t *super = mount->super; inode--; // turn inode into a 0-based index u32_t group = inode / super->s_inodes_per_group; u32_t index = inode % super->s_inodes_per_group; u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table << (10 + super->s_log_block_size)) + (index << 7); void *block = kmalloc(512); block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block); memcpy(dat, (block + (inodeAddr & 0x1FF)), sizeof(ext2_inode_t)); kfree(block); return 0; } // write an inode structure to the device int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) { if (ext2_inode_status(mount, inode) != 1) return -1; // free or invalid inode number ext2_super_block_t *super = mount->super; inode--; // turn inode into a 0-based index u32_t group = inode / super->s_inodes_per_group; u32_t index = inode % super->s_inodes_per_group; u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table << (10 + super->s_log_block_size)) + (index << 7); void *block = kmalloc(512); block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block); memcpy( (block + (inodeAddr & 0x1FF)), dat, sizeof(ext2_inode_t)); block_write(mount->major, mount->minor, inodeAddr >> 9, 1, block); kfree(block); return 0; } // read the group descriptor structure from the device and return it ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group) { ext2_super_block_t *super = mount->super; u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group << 5); void *block = kmalloc(512); block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block); ext2_group_desc_t gd = *(ext2_group_desc_t *)(block + (groupDescAddr & 0x1FF)); kfree(block); return gd; } // write the group descriptor structure to the device void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd) { ext2_super_block_t *super = mount->super; u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group_num << 5); void *block = kmalloc(512); block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block); memcpy( (block + (groupDescAddr & 0x1FF)), gd, sizeof(ext2_group_desc_t) ); block_write(mount->major, mount->minor, groupDescAddr >> 9, 1, block); kfree(block); } // allocate an inode and return its number u32_t ext2_alloc_inode(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; if (!super->s_free_inodes_count) return 0; // no free inodes int bg, bg_max = ext2_num_block_groups(super); for (bg = 0; bg < bg_max; bg++) { ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); if (group_desc.bg_free_inodes_count) { u32_t node = ext2_reserve_node(mount, group_desc.bg_inode_bitmap, super->s_inodes_per_group); group_desc.bg_free_inodes_count--; ext2_write_group_desc(mount, bg, &group_desc); super->s_free_inodes_count--; return bg * super->s_inodes_per_group + node + 1; } } return 0; } int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number) { ext2_super_block_t *super = mount->super; if (inode_number < 11 || inode_number > super->s_inodes_count) return -1; // invalid inode number if (ext2_inode_status(mount, inode_number) != 1) return -2; // inode not allocated inode_number--; // now a 0-based inode number int bg = inode_number / super->s_inodes_per_group; ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); ext2_free_node(mount, group_desc.bg_inode_bitmap, inode_number % super->s_inodes_per_group); group_desc.bg_free_inodes_count++; ext2_write_group_desc(mount, bg, &group_desc); super->s_free_inodes_count++; return 0; } // allocate a block and return its number u32_t ext2_alloc_block(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; if (!super->s_free_blocks_count) return 0; // no free blocks int bg, bg_max = ext2_num_block_groups(super); for (bg = 0; bg < bg_max; bg++) { ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); if (group_desc.bg_free_blocks_count) { u32_t node = ext2_reserve_node(mount, group_desc.bg_block_bitmap, super->s_blocks_per_group); group_desc.bg_free_blocks_count--; ext2_write_group_desc(mount, bg, &group_desc); super->s_free_blocks_count--; return bg * super->s_blocks_per_group + node + super->s_first_data_block; } } return 0; } int ext2_free_block(vfs_mount_t *mount, u32_t block_number) { ext2_super_block_t *super = mount->super; if (block_number < super->s_first_data_block || block_number > (super->s_blocks_count + super->s_first_data_block - 1)) return -1; // invalid block number if (ext2_block_status(mount, block_number) != 1) return -2; // block not allocated block_number -= super->s_first_data_block; // now a 0-based block number int bg = block_number / super->s_blocks_per_group; ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); ext2_free_node(mount, group_desc.bg_block_bitmap, block_number % super->s_blocks_per_group); group_desc.bg_free_blocks_count++; ext2_write_group_desc(mount, bg, &group_desc); super->s_free_blocks_count++; return 0; } int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size) { ext2_inode_t inode; if ( ext2_read_inode(mount, inode_number, &inode) ) return -1; ext2_super_block_t *super = mount->super; int current_blocks = (inode.i_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); int new_blocks = (new_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); if ( new_blocks == current_blocks ) return 0; // TODO: resize u32_t block_size = 1024 << super->s_log_block_size; u32_t pointers_per_block = block_size >> 2; u32_t *pointer_cache1 = kmalloc(3 * block_size); u32_t *pointer_cache2 = pointer_cache1 + pointers_per_block; u32_t *pointer_cache3 = pointer_cache2 + pointers_per_block; u32_t c1_start, c2_start, c3_start; c1_start = c2_start = c3_start = 0; while (new_blocks < current_blocks) // delete, decrease current_blocks { current_blocks--; // now delete block number current_blocks } while (current_blocks < new_blocks) // add, increase current_blocks { } } // reserve a node of a inode or block bitmap and mark its entry allocated u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size) { ext2_super_block_t *super = mount->super; u32_t *bitmap = kmalloc(1024 << super->s_log_block_size); int block, max_block = (bitmap_size - 1) / (8192 << super->s_log_block_size) + 1; for (block = 0; block < max_block; block++) { block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super), 2 << super->s_log_block_size, bitmap); int num, num_max = 256 << super->s_log_block_size; u32_t *block_pointer = bitmap; int done = 0; for (num = 0; num < num_max && !done; num++) { if (*block_pointer != 0xFFFFFFFF) { done = 1; int bit; for (bit = 0; bit < 32; bit++) { if (!(*block_pointer & (1 << bit))) { u32_t node_number = (block * 8192 << super->s_log_block_size) + (num << 5) + bit; if (node_number < bitmap_size) { // found a node, mark it allocated, write the bitmap, return *block_pointer |= (1 << bit); block_write(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super), 2 << super->s_log_block_size, bitmap); kfree(bitmap); return node_number; } kfree(bitmap); return 0; } } } block_pointer++; } } kfree(bitmap); return 0; } int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number) { ext2_super_block_t *super = mount->super; u32_t block_num = node_number >> (13 + super->s_log_block_size); byte *block = kmalloc(1024 << super->s_log_block_size); block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super), 2 << super->s_log_block_size, block); u32_t node_bit_offset = node_number % (8192 << super->s_log_block_size); u32_t node_byte_offset = node_bit_offset >> 3; block[node_byte_offset] &= (0xFF ^ (1 << (node_bit_offset & 0x7))); block_write(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super), 2 << super->s_log_block_size, block); kfree(block); return 0; } // return how many block groups are on the filesystem int ext2_num_block_groups(ext2_super_block_t *super) { return (super->s_inodes_count / super->s_inodes_per_group) + 1; } void ext2_write_super(vfs_mount_t *mount) { block_write(mount->major, mount->minor, 2, 2, mount->super); } /***************** VFS INTERFACE FUNCTIONS *******************/ // mount the superblock of the filesystem and return a pointer to it, if valid void *ext2_mount_super(major_t major, minor_t minor) { ext2_super_block_t *super = kmalloc(1024); block_read(major, minor, 2, 2, super); if (super->s_magic != EXT2_MAGIC) // not an ext2 filesystem { kfree(super); return NULL; } return super; } // called when we are unmounting this filesystem mount int ext2_umount_super(vfs_mount_t *mount) { ext2_write_super(mount); return kfree(mount->super); // free memory that the superblock was taking } // stat a file, return a structure of info about it int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat) { if (ext2_inode_status(mount, inode_number) != 1) return -1; ext2_inode_t *inode = New(ext2_inode_t); if ( ext2_read_inode(mount, inode_number, inode) ) { kfree(inode); return -2; } stat->dev = 0; switch(inode->i_mode & EXT2_I_MODE_TYPE_MASK) { case EXT2_I_MODE_FIFO: stat->type = VFS_FT_FIFO; break; case EXT2_I_MODE_CHAR: stat->type = VFS_FT_CHAR; stat->dev = inode->i_block[0]; break; case EXT2_I_MODE_DIR: stat->type = VFS_FT_DIR; break; case EXT2_I_MODE_BLOCK: stat->type = VFS_FT_BLOCK; stat->dev = inode->i_block[0]; break; case EXT2_I_MODE_FILE: stat->type = VFS_FT_FILE; break; case EXT2_I_MODE_SYM: stat->type = VFS_FT_SYMLINK; break; case EXT2_I_MODE_SOCK: stat->type = VFS_FT_SOCK; break; default: stat->type = VFS_FT_UNKNOWN; break; } stat->size = inode->i_size; stat->inode = inode_number; stat->permissions = inode->i_mode & EXT2_I_MODE_ATTR_MASK; stat->uid = inode->i_uid; stat->gid = inode->i_gid; stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; stat->links = inode->i_links_count; kfree(inode); return 0; } // what is the inode of the root directory? u32_t ext2__get_root_dir_inode(vfs_mount_t *mount) { return 2; } // VFS interface function to dereference a symbolic link int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link) { ext2_inode_t inode; if (ext2_read_inode(mount, link_inode, &inode)) return -1; if ( (inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM ) return -2; if (!inode.i_size) return -4; if (inode.i_size < 61) { memcpy(link, inode.i_block, inode.i_size); link[inode.i_size] = 0; return 0; } else { ext2_open_inode_t *open_inode; if (!(open_inode = ext2_open_inode(mount, link_inode))) return -3; ext2_super_block_t *super = mount->super; void *buffer = kmalloc(1024 << super->s_log_block_size); memset(link, 0, 4096); int copied = 0; while (copied < 4096) { int bytes_read = ext2_read_inode_block(mount, open_inode, buffer); if (bytes_read == 0) break; memcpy(link + copied, buffer, bytes_read); copied += bytes_read; } ext2_close_inode(mount, open_inode); kfree(buffer); return 0; } } // VFS interface function to return the number of free inodes int ext2__free_inodes(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; return super->s_free_inodes_count; } // VFS interface function to return the total number of inodes int ext2__total_inodes(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; return super->s_inodes_count; } // VFS interface function to return the number of free 512-byte blocks int ext2__free_blocks(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; return super->s_free_blocks_count << (1 + super->s_log_block_size); } // VFS interface function to return the total number of 512-byte blocks int ext2__total_blocks(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; return super->s_blocks_count << (1 + super->s_log_block_size); } // VFS interface function to open a directory int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir) { if (ext2_inode_status(mount, inode_number) != 1) return -1; ext2_open_dir_t *open_dir = ext2_open_dir(mount, inode_number); if (!open_dir) return -2; dir->fs_data = open_dir; return 0; } // VFS interface function to read a directory entry from an open directory int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry) { ext2_dir_entry_t t_dentry; int status = ext2_dir_read_entry(mount, dir->fs_data, &t_dentry); if (status) return status; memcpy(dentry->name, t_dentry.name, t_dentry.name_length); dentry->name[t_dentry.name_length] = 0; dentry->inode_number = t_dentry.inode; return 0; } // VFS interface function to close an open directory int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir) { return ext2_close_dir(mount, dir->fs_data); } // VFS interface function to open a file for reading a byte at a time int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) { if (ext2_inode_status(mount, inode_number) != 1) return -1; return 0; } // VFS interface function to read a byte from an open file int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file) { return 0; } // VFS interface function to close a byte-file int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file) { return 0; } // VFS interface function to open a file for reading 512-byte blocks at a time int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) { if (ext2_inode_status(mount, inode_number) != 1) return -1; ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); if (!open_inode) return -2; if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE) { ext2_close_inode(mount, open_inode); return -3; } ext2__open_block_file_t *open_block_file = New(ext2__open_block_file_t); open_block_file->open_inode = open_inode; open_block_file->block = 0; open_file->fs_data = open_block_file; return 0; } // VFS interface function to read a block from an open block file // returns the number of bytes read int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer) { ext2_super_block_t *super = mount->super; ext2__open_block_file_t *open_block_file = open_file->fs_data; if (ext2_inode_seek(mount, open_block_file->open_inode, ext2_diskToFSBlock(open_block_file->block, super))) return 0; // EOF u8_t *block = kmalloc(1024 << super->s_log_block_size); u32_t file_position_read = (1024 << super->s_log_block_size) * open_block_file->open_inode->block; u32_t file_position_want = open_block_file->block << 9; u32_t data_offset = file_position_want - file_position_read; int bytes_read = ext2_read_inode_block(mount, open_block_file->open_inode, block); if (bytes_read <= data_offset) { kfree(block); return 0; // EOF } memcpy(buffer, block + data_offset, min(512, bytes_read - data_offset)); kfree(block); open_block_file->block++; return min(512, bytes_read - data_offset); } // VFS interface function to seek to a certain block number of an open block file int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number) { ext2__open_block_file_t *open_block_file = open_file->fs_data; return ext2_inode_seek(mount, open_block_file->open_inode, ext2_FSToDiskBlock(block_number, mount->super)); } // VFS interface function to close an open block file int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file) { ext2__open_block_file_t *open_block_file = open_file->fs_data; ext2_close_inode(mount, open_block_file->open_inode); kfree(open_block_file); return 0; }