#include "ext2.h" #include #include #include "mount.h" #include "kernel.h" #include "log.h" #include "lib/string/string.h" #include // THE SUPERBLOCK typedef struct ext2_superblock_struct { uint32_t inodes_count; uint32_t blocks_count; uint32_t blocks_reserved_count; uint32_t inodes_unalloc_count; uint32_t blocks_unalloc_count; uint32_t superblock_number; uint32_t block_size; uint32_t fragment_size; uint32_t blocks_per_group; uint32_t fragments_per_group; uint32_t inodes_per_group; uint8_t skip[12]; // last mount time, last written time, numer of times mounted, number of mounts before checking. uint16_t ext2_sig; // 0xef5 uint16_t fs_state; uint16_t error_handle; uint16_t version_minor; uint8_t skip2[8]; // last check, check interval uint32_t os_id; uint32_t version_major; uint16_t uid_reserved; uint16_t gid_reserved; }ext2_superblock; /* we dont use this for now */ /* typedef struct ext2_superblock_ext_struct { uint32_t first_inode; uint16_t size_inode; uint16_t blockgroup; uint32_t features_opt; uint32_t features_req; uint32_t features_write; uint32_t blkid[4]; char vol_name[16]; char last_path[64]; uint32_t compression; uint8_t prealloc_files; uint8_t prealloc_dirs; uint8_t unused[2]; uint32_t journalid[4]; uint32_t journal_inode; uint32_t journal_device; uint32_t orpan_head; }ext2_superblock_ext; */ // BLOCKGROUP DESCRIPTOR TABLE typedef struct ext2_blockgroup_desc_struct { uint32_t addr_block_bitmap; uint32_t addr_inode_bitmap;; uint32_t addr_inode_table; uint16_t unalloc_blocks_count; uint16_t unalloc_inodes_count; uint16_t dir_count; uint8_t unused[14]; }ext2_blockgroup_desc; typedef struct ext2_dir_struct { uint32_t inode; uint16_t size; uint8_t name_length_low; uint8_t name_length_high; // name follows }ext2_dir; typedef struct ext2_inode_struct { uint16_t permissions; uint16_t user_id; uint32_t size_low; uint32_t skip[4]; uint16_t group_id; uint16_t hardlink_count; uint32_t disk_sectors; uint32_t flags; uint32_t os_specific; uint32_t direct_pointer[12]; uint32_t indirect1; uint32_t indirect2; uint32_t indirect3; uint32_t gen_num; uint32_t acl; uint32_t size_high; uint32_t frag; uint32_t os_spec2[3]; }ext2_inode; static ext2_superblock *ext2_check(uint32_t ext2_start_addr) { ext2_superblock *super=ext2_start_addr+1024; if(super->ext2_sig!=0xef53){ kpanic("no ext2 signature found, where ram-image expected at addr: 8X%08X",ext2_start_addr+1024); } return super; } void ext2_dump_info(uint32_t ext2_start_addr) { ext2_superblock *super=ext2_check(ext2_start_addr); klog("ext2 fs version %d.%d found",super->version_major, super->version_minor); klog("block_size %d",1024<block_size); klog("blocks per group %d",super->blocks_per_group); klog("inodes per group %d",super->inodes_per_group); klog("free inodes: %d / %d",super->inodes_unalloc_count,super->inodes_count+super->inodes_unalloc_count); klog("free blocks: %d / %d (%d reserved)",super->blocks_unalloc_count,super->blocks_count+super->blocks_unalloc_count,super->blocks_reserved_count); } // inode numbers start a 1! ext2_inode *ext2_get_inode(uint32_t ext2_start_addr,uint32_t inode_num) { uint32_t ptr; //will temporarily hold adress of some structs // check signature and get pointer to superblock. ext2_superblock *super=ext2_check(ext2_start_addr); // get blockgroup descriptor for the block group containing // our inode. int block_group=(inode_num-1)/super->inodes_per_group; int descriptor_start_block=1024<block_size==1024?2:1; ptr=ext2_start_addr+(1024<block_size)*descriptor_start_block; ptr+=sizeof(ext2_blockgroup_desc)*block_group; // skip to descriptor for our inode's block ext2_blockgroup_desc *desc=ptr; // read the inode ptr=ext2_start_addr+(1024<block_size)*desc->addr_inode_table; ptr+=128*((inode_num-1)%super->inodes_per_group); ext2_inode *inode=ptr; return inode; } static void* ext2_get_blockstart(void* start, uint32_t block_size, uint32_t block_idx) { return (start+block_size*block_idx); } static void* ext2_get_indirectstart(void *start, uint32_t block_size, uint32_t indirect1_idx, uint32_t block_idx) { uint32_t *indirect_ptr=ext2_get_blockstart(start,block_size,indirect1_idx); void *ptr=ext2_get_blockstart(start,block_size,indirect_ptr[block_idx]); return ptr; } static void* ext2_get_indirectstart_double(void *start, uint32_t block_size, uint32_t indirect2_idx, uint32_t block_idx) { //doubly indirect list uint32_t *dil=ext2_get_blockstart(start,block_size,indirect2_idx); int indirect1_idx=block_idx/(block_size/4); int idx=block_idx%(block_size/4); return ext2_get_indirectstart(start,block_size,dil[indirect1_idx],idx); } // uint32_t ext2_inode_blockstart(uint32_t ext2_start_addr,uint32_t inode_nr,uint32_t block) { ext2_superblock *super=ext2_check(ext2_start_addr); int block_size=1024<block_size; ext2_inode *inode=ext2_get_inode(ext2_start_addr,inode_nr); uint8_t *ptr=0; if(block<12) { ptr=ext2_get_blockstart(ext2_start_addr,block_size,inode->direct_pointer[block]); } else if(block-12indirect1,block-12); } else if(block-12-block_size/4<1024/4*1024/4) { ptr=ext2_get_indirectstart_double(ext2_start_addr,block_size,inode->indirect2,block-12-block_size/4); } return ptr; } static uint32_t ext2_filename_to_inode_traverse(uint32_t ext2_start_addr, char *path,uint32_t inode_start) { uint32_t len=0; // true if final filename bool final=false; // skip leading slashes while(*path=='/')path++; char *first=path; // find end of dir or file name while(path[len]!='/'&&path[len]!=0)len++; // no more slashes if(path[len]==0)final=true; //klog("looking for %s '%s' in inode: %d",final?"file":"dir",first,inode_start); uint32_t pos=0; while(1) { struct dirent dirs; uint32_t ret=ext2_read_dir(VMEM_EXT2_RAMIMAGE,inode_start, &dirs,&pos); if(!ret)break; if(strlen(dirs.d_name)==len && !strcmp_l(first,dirs.d_name,len)) { // klog("found inode %d %s%s (in inode %d)",dirs.d_ino,dirs.d_name,dirs.type==FS_FILE_TYPE_DIR?"/ ":" ",inode_start); if(final)return dirs.d_ino; return ext2_filename_to_inode_traverse(ext2_start_addr,&path[len]+1,dirs.d_ino); } } return 0; } uint32_t ext2_filename_to_inode(uint32_t ext2_start_addr, char *path) { if(!strcmp_l(path,"/",0))return 2; // root is inode 2 by definition uint32_t ret= ext2_filename_to_inode_traverse(ext2_start_addr,path,2); if(ret==0)klog("file not found! : %s",path); return ret; } uint32_t ext2_read_inode(uint32_t ext2_start_addr, int inode_nr, char *buf, uint32_t *pos, uint32_t max_size) { uint32_t count=0; ext2_superblock *super=ext2_check(ext2_start_addr); ext2_inode *inode=ext2_get_inode(ext2_start_addr,inode_nr); uint32_t block_size=1024<block_size; while((*pos)size_low) { if(count==max_size)return count; // get ptr to pos uint32_t block=(*pos)/block_size; uint32_t ptr = ext2_inode_blockstart(ext2_start_addr,inode_nr,block)+((*pos)%block_size); buf[count]=*((char *)ptr); *pos+=1; count++; } return count; } int ext2_read_dir(uint32_t ext2_start_addr, int inode_nr, struct dirent *dirs, uint32_t *pos) { ext2_superblock *super=ext2_check(ext2_start_addr); ext2_inode *inode=ext2_get_inode(ext2_start_addr,inode_nr); uint32_t block_size=1024<block_size; while(*possize_low) { // get ptr to pos uint32_t block=(*pos)/block_size; uint32_t ptr = ext2_inode_blockstart(ext2_start_addr,inode_nr,block)+((*pos)%block_size); //dir data ext2_dir *dir=ptr; if(dir->inode) //otherwise skip { dirs->type=FS_FILE_TYPE_FILE; ext2_inode *inode_current=ext2_get_inode(ext2_start_addr,dir->inode); if(inode_current->permissions&0x4000)dirs->type=FS_FILE_TYPE_DIR; memcpy(dirs->d_name,ptr+8,dir->name_length_low); if(dir->name_length_low>255)dirs->d_name[255]=0; dirs->d_name[dir->name_length_low]=0; // null temrinate dirs->d_ino=dir->inode; *pos+=dir->size; return 1; } *pos+=dir->size; } return 0; } /* mount interface */ fd ext2_mount_file_open(mount *m,char *path) { return fd_from_path(path); } int ext2_mount_read_dir(mount *m,char *path, struct dirent *dirs, uint32_t *pos) { uint32_t inode= ext2_filename_to_inode(VMEM_EXT2_RAMIMAGE,path); if(inode==0)return -1; ext2_inode *inode_current=ext2_get_inode(VMEM_EXT2_RAMIMAGE,inode); if(!(inode_current->permissions&0x4000))return -1; return ext2_read_dir(m->data, inode, dirs, pos); } void ext2_mount(char *path) { mount m; m.type=MOUNT_TYPE_EXT2; memcpy(m.path,path,strlen(path)+1); m.mount_file_open=ext2_mount_file_open; m.mount_read_dir=ext2_mount_read_dir; m.data=VMEM_EXT2_RAMIMAGE; mount_add(m); }