From 84b1443afbfe24eb6e338e8636e8e3759b9093d5 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Sun, 25 Oct 2009 16:32:03 +0800 Subject: [PATCH] Added a generic path_lookup method in vfs Well, for now, just applied to EXTLINUX. Here is the main change: 1) Add to union structure in file to make the older path_lookup method work. 2) Add a generic inode structure, to represent one file. 3) Add three more methods in fs_ops; they are: iget_root, get the root inode of a fs iget_current, get the 'pwd' iget, do_open a file 4) Add a *TEMP* memory managemant system. Signed-off-by: Yuanhan Liu --- core/fs.c | 103 ++++-- core/fs/ext2/bmap.c | 191 +++++++++++ core/fs/ext2/ext2.c | 804 ++++++++++++++++------------------------------ core/fs/ext2/ext2_fs.h | 74 ++++- core/fs/fat/fat.c | 13 +- core/fs/iso9660/iso9660.c | 19 +- core/fs/pxe/pxe.c | 19 +- core/include/core.h | 5 + core/include/fs.h | 70 +++- core/malloc.c | 216 +++++++++++++ 10 files changed, 927 insertions(+), 587 deletions(-) create mode 100644 core/fs/ext2/bmap.c create mode 100644 core/malloc.c diff --git a/core/fs.c b/core/fs.c index ed023af..3e489e5 100644 --- a/core/fs.c +++ b/core/fs.c @@ -6,7 +6,8 @@ /* The currently mounted filesystem */ struct fs_info *this_fs = NULL; -struct fs_info fs; +static struct fs_info fs; +struct inode *this_inode = NULL; /* Actual file structures (we don't have malloc yet...) */ struct file files[MAX_OPEN]; @@ -20,7 +21,7 @@ static struct file *alloc_file(void) struct file *file = files; for (i = 0; i < MAX_OPEN; i++) { - if (!file->open_file) + if (!file->fs) return file; file++; } @@ -38,7 +39,7 @@ static inline void free_file(struct file *file) void _close_file(struct file *file) { - if (file->open_file) + if (file->fs) file->fs->fs_ops->close_file(file); free_file(file); } @@ -118,28 +119,83 @@ void getfssec(com32sys_t *regs) void searchdir(com32sys_t *regs) { - char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);; + char *name = MK_PTR(regs->ds, regs->edi.w[0]); + struct inode *inode; + struct inode *parent; struct file *file; - + char part[256]; + char *p; + int symlink_count = 6; + #if 0 - printf("filename: %s\n", filename); + printf("filename: %s\n", name); #endif - file = alloc_file(); - - if (file) { - file->fs = this_fs; - file->fs->fs_ops->searchdir(filename, file); + if (!(file = alloc_file())) + goto err; + file->fs = this_fs; + + /* for now, we just applied the universal path_lookup to EXTLINUX */ + if (strcmp(this_fs->fs_ops->fs_name, "ext2") != 0) { + file->fs->fs_ops->searchdir(name, file); - if (file->open_file) { + if (file->u1.open_file) { regs->esi.w[0] = file_to_handle(file); - regs->eax.l = file->file_len; + regs->eax.l = file->u2.file_len; regs->eflags.l &= ~EFLAGS_ZF; return; } + + goto err; + } + + + + if (*name == '/') { + inode = this_fs->fs_ops->iget_root(); + while(*name == '/') + name++; + } else { + inode = this_inode; + } + parent = inode; + + while (*name) { + p = part; + while(*name && *name != '/') + *p++ = *name++; + *p = '\0'; + inode = this_fs->fs_ops->iget(part, parent); + if (!inode) + goto err; + if (inode->mode == I_SYMLINK) { + if (!this_fs->fs_ops->follow_symlink || + --symlink_count == 0 || /* limit check */ + inode->size >= (uint32_t)inode->blksize) + goto err; + name = this_fs->fs_ops->follow_symlink(inode, name); + free_inode(inode); + continue; + } + + if (parent != this_inode) + free_inode(parent); + parent = inode; + if (! *name) + break; + while(*name == '/') + name++; } - /* failure... */ + file->u1.inode = inode; + file->u2.offset = 0; + + regs->esi.w[0] = file_to_handle(file); + regs->eax.l = inode->size; + regs->eflags.l &= ~EFLAGS_ZF; + return; + +err: regs->esi.w[0] = 0; regs->eax.l = 0; regs->eflags.l |= EFLAGS_ZF; @@ -158,10 +214,12 @@ void close_file(com32sys_t *regs) /* * it will do: + * initialize the memory management function; * set up the vfs fs structure; * initialize the device structure; * invoke the fs-specific init function; - * finally, initialize the cache if we need one + * initialize the cache if we need one; + * finally, get the current inode for relative path looking. * */ void fs_init(com32sys_t *regs) @@ -169,8 +227,12 @@ void fs_init(com32sys_t *regs) int blk_shift; const struct fs_ops *ops = (const struct fs_ops *)regs->eax.l; + if (strcmp(ops->fs_name, "ext2") == 0) + mem_init(); + /* set up the fs stucture */ fs.fs_ops = ops; + this_fs = &fs; /* this is a total hack... */ if (ops->fs_flags & FS_NODEV) @@ -179,12 +241,17 @@ void fs_init(com32sys_t *regs) fs.fs_dev = device_init(regs->edx.b[0], regs->edx.b[1], regs->ecx.l, regs->esi.w[0], regs->edi.w[0]); - this_fs = &fs; - /* invoke the fs-specific init code */ - blk_shift = fs.fs_ops->fs_init(&fs); + blk_shift = fs.fs_ops->fs_init(&fs); + if (blk_shift < 0) { + printf("%s fs init error\n", fs.fs_ops->fs_name); + for(;;) ; /* halt */ + } /* initialize the cache */ if (fs.fs_dev && fs.fs_dev->cache_data) cache_init(fs.fs_dev, blk_shift); + + if (fs.fs_ops->iget_current) + this_inode = fs.fs_ops->iget_current(); } diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c new file mode 100644 index 0000000..7d13dec --- /dev/null +++ b/core/fs/ext2/bmap.c @@ -0,0 +1,191 @@ +/* + * The logical block -> physical block routine. + * + * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file + * may be redistributed under the terms of the GNU Public License. + */ + +#include +#include +#include +#include +#include "ext2_fs.h" + + +static struct ext4_extent_header * +ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block) +{ + struct ext4_extent_idx *index; + struct cache_struct *cs; + block_t blk; + int i; + + while (1) { + if (eh->eh_magic != EXT4_EXT_MAGIC) + return NULL; + if (eh->eh_depth == 0) + return eh; + + index = EXT4_FIRST_INDEX(eh); + for (i = 0; i < (int)eh->eh_entries; i++) { + if (block < index[i].ei_block) + break; + } + if (--i < 0) + return NULL; + + blk = index[i].ei_leaf_hi; + blk = (blk << 32) + index[i].ei_leaf_lo; + cs = get_cache_block(fs->fs_dev, blk); + eh = (struct ext4_extent_header *)cs->data; + } +} + +/* handle the ext4 extents to get the phsical block number */ +static uint64_t bmap_extent(struct fs_info *fs, + struct inode *inode, + uint32_t block) +{ + struct ext4_extent_header *leaf; + struct ext4_extent *ext; + int i; + block_t start; + + leaf = ext4_find_leaf(fs, (struct ext4_extent_header *)inode->data, block); + if (!leaf) { + printf("ERROR, extent leaf not found\n"); + return 0; + } + + ext = EXT4_FIRST_EXTENT(leaf); + for (i = 0; i < leaf->eh_entries; i++) { + if (block < ext[i].ee_block) + break; + } + if (--i < 0) { + printf("ERROR, not find the right block\n"); + return 0; + } + + /* got it */ + block -= ext[i].ee_block; + if (block >= ext[i].ee_len) + return 0; + start = ext[i].ee_start_hi; + start = (start << 32) + ext[i].ee_start_lo; + + return start + block; +} + + +/* + * handle the traditional block map, like indirect, double indirect + * and triple indirect + */ +static unsigned int bmap_traditional(struct fs_info *fs, + struct inode *inode, + uint32_t block) +{ + int block_size = 1 << (SECTOR_SHIFT + fs->blk_bits); + int addr_per_block = block_size >> 2; + uint32_t direct_blocks = EXT2_NDIR_BLOCKS, + indirect_blocks = addr_per_block, + double_blocks = addr_per_block * addr_per_block, + triple_blocks = double_blocks * addr_per_block; + struct cache_struct *cs; + + /* direct blocks */ + if (block < direct_blocks) + return inode->data[block]; + + /* indirect blocks */ + block -= direct_blocks; + if (block < indirect_blocks) { + block_t ind_block = inode->data[EXT2_IND_BLOCK]; + + if (!ind_block) + return 0; + cs = get_cache_block(fs->fs_dev, ind_block); + + return ((uint32_t *)cs->data)[block]; + } + + + /* double indirect blocks */ + block -= indirect_blocks; + if (block < double_blocks) { + block_t dou_block = inode->data[EXT2_DIND_BLOCK]; + + if (!dou_block) + return 0; + cs = get_cache_block(fs->fs_dev, dou_block); + + dou_block = ((uint32_t *)cs->data)[block / indirect_blocks]; + if (!dou_block) + return 0; + cs = get_cache_block(fs->fs_dev, dou_block); + + return ((uint32_t *)cs->data)[block % addr_per_block]; + } + + + /* triple indirect block */ + block -= double_blocks; + if (block < triple_blocks) { + block_t tri_block = inode->data[EXT2_TIND_BLOCK]; + + if (!tri_block) + return 0; + cs = get_cache_block(fs->fs_dev, tri_block); + + tri_block = ((uint32_t *)cs->data)[block / double_blocks]; + if (!tri_block) + return 0; + cs = get_cache_block(fs->fs_dev, tri_block); + + tri_block = (block / addr_per_block) % addr_per_block; + tri_block = ((uint32_t *)cs->data)[tri_block]; + if (!tri_block) + return 0; + cs = get_cache_block(fs->fs_dev, tri_block); + + return ((uint32_t *)cs->data)[block % addr_per_block]; + } + + + /* File too big, can not handle */ + printf("ERROR, file too big\n"); + return 0; +} + + +/** + * Map the logical block to physic block where the file data stores. + * In EXT4, there are two ways to handle the map process, extents and indirect. + * EXT4 uses a inode flag to mark extent file and indirect block file. + * + * @fs: the fs_info structure. + * @inode: the inode structure. + * @block: the logical blcok needed to be maped. + * @retrun: the physic block number. + * + */ +block_t bmap(struct fs_info *fs, struct inode * inode, int block) +{ + block_t ret; + + if (block < 0) + return 0; + + if (inode->flags & EXT4_EXTENTS_FLAG) + ret = bmap_extent(fs, inode, block); + else + ret = bmap_traditional(fs, inode, block); + + if (!ret) { + printf("ERROR: something error happend at linsector..\n"); + return 0; + } + + return ret; +} diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c index e0f289e..a416a88 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -6,36 +6,11 @@ #include #include "ext2_fs.h" -#define MAX_SYMLINKS 64 -#define SYMLINK_SECTORS 2 -static char SymlinkBuf[SYMLINK_SECTORS * SECTOR_SIZE + 64]; - -/* - * File structure, This holds the information for each currently open file - */ -struct open_file_t { - uint32_t file_bytesleft; /* Number of bytes left (0 = free) */ - uint32_t file_sector; /* Next linear sector to read */ - sector_t file_in_sec; /* Sector where inode lives */ - uint16_t file_in_off; - uint16_t file_mode; - uint32_t pad[3]; /* pad to 2^5 == 0x20 bytes */ -}; -static struct open_file_t Files[MAX_OPEN]; - -static struct ext2_inode this_inode; -static struct ext2_super_block sb; - -static uint16_t ClustByteShift, ClustShift; -static uint32_t SecPerClust, ClustSize, ClustMask; -static uint32_t PtrsPerBlock1, PtrsPerBlock2, PtrsPerBlock3; -static int DescPerBlock, InodePerBlock; - /* * just like the function strcpy(), except it returns non-zero if overflow. * */ -static int strecpy(char *dst, char *src, char *end) +static int strecpy(char *dst, const char *src, char *end) { while (*src != '\0') *dst++ = *src++; @@ -47,278 +22,34 @@ static int strecpy(char *dst, char *src, char *end) return 0; } - -/* - * Allocate a file structure, if successful return the file pointer, or NULL. - * - */ -static struct open_file_t *allocate_file(void) -{ - struct open_file_t *file = Files; - int i; - - for (i = 0; i < MAX_OPEN; i++) { - if (file->file_bytesleft == 0) /* found it */ - return file; - file++; - } - - return NULL; /* not found */ -} - - -/** - * ext2_close_file: - * - * Deallocates a file structure point by FILE - * - * @param: file, the file structure we want deallocate - * - */ -static inline void close_pvt(struct open_file_t *of) -{ - of->file_bytesleft = 0; -} - static void ext2_close_file(struct file *file) { - close_pvt(file->open_file); + if (file->u1.inode) { + file->u2.offset = 0; + free_inode(file->u1.inode); + } } -/** +/* * get the group's descriptor of group_num - * - * @param: group_num, the group number; - * - * @return: the pointer of the group's descriptor - * - */ -static struct ext2_group_desc * -get_group_desc(struct fs_info *fs, uint32_t group_num) -{ - block_t block_num; - uint32_t offset; - struct ext2_group_desc *desc; - struct cache_struct *cs; - - block_num = group_num / DescPerBlock; - offset = group_num % DescPerBlock; - - block_num += sb.s_first_data_block + 1; - cs = get_cache_block(fs->fs_dev, block_num); - desc = (struct ext2_group_desc *)cs->data + offset; - - return desc; -} - - -/** - * read the right inode structure to _dst_. - * - * @param: inode_offset, the inode offset within a group; - * @prarm: dst, wher we will store the inode structure; - * @param: desc, the pointer to the group's descriptor - * @param: block, a pointer used for retruning the blk number for file structure - * @param: offset, same as block - * - */ -static void read_inode(struct fs_info *fs, uint32_t inode_offset, - struct ext2_inode *dst, struct ext2_group_desc *desc, - block_t *block, uint32_t *offset) -{ - struct cache_struct *cs; - struct ext2_inode *inode; - - *block = inode_offset / InodePerBlock + desc->bg_inode_table; - *offset = inode_offset % InodePerBlock; - - cs = get_cache_block(fs->fs_dev, *block); - - /* well, in EXT4, the inode structure usually be 256 */ - inode = (struct ext2_inode *)(cs->data + (*offset * (sb.s_inode_size))); - memcpy(dst, inode, EXT2_GOOD_OLD_INODE_SIZE); - - /* for file structure */ - *offset = (inode_offset * sb.s_inode_size) % ClustSize; -} - - -/** - * open a file indicated by an inode number in INR - * - * @param : inr, the inode number - * @return: a open_file_t structure pointer - * file length in bytes - * the first 128 bytes of the inode, stores in ThisInode - * */ -static struct open_file_t * -open_inode(struct fs_info *fs, uint32_t inr, uint32_t *file_len) -{ - struct open_file_t *file; - struct ext2_group_desc *desc; - - uint32_t inode_group, inode_offset; - block_t block_num; - uint32_t block_off; - - file = allocate_file(); - if (!file) - return NULL; - - file->file_sector = 0; - - inr --; - inode_group = inr / sb.s_inodes_per_group; - - /* get the group desc */ - desc = get_group_desc(fs, inode_group); - - inode_offset = inr % sb.s_inodes_per_group; - read_inode(fs, inode_offset, &this_inode, desc, &block_num, &block_off); - - /* Finally, we need to convet it to sector for now */ - file->file_in_sec = (block_num<>SECTOR_SHIFT); - file->file_in_off = block_off & (SECTOR_SIZE - 1); - file->file_mode = this_inode.i_mode; - *file_len = file->file_bytesleft = this_inode.i_size; - - if (*file_len == 0) - return NULL; - - return file; -} - - - -static struct ext4_extent_header * -ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block) -{ - struct ext4_extent_idx *index; - struct cache_struct *cs; - block_t blk; - int i; - - while (1) { - if (eh->eh_magic != EXT4_EXT_MAGIC) - return NULL; - - /* got it */ - if (eh->eh_depth == 0) - return eh; - - index = EXT4_FIRST_INDEX(eh); - for (i = 0; i < eh->eh_entries; i++) { - if (block < index[i].ei_block) - break; - } - if (--i < 0) - return NULL; - - blk = index[i].ei_leaf_hi; - blk = (blk << 32) + index[i].ei_leaf_lo; - - /* read the blk to memeory */ - cs = get_cache_block(fs->fs_dev, blk); - eh = (struct ext4_extent_header *)(cs->data); - } -} - -/* handle the ext4 extents to get the phsical block number */ -static block_t linsector_extent(struct fs_info *fs, block_t block, - struct ext2_inode *inode) +struct ext2_group_desc * ext2_get_group_desc(uint32_t group_num) { - struct ext4_extent_header *leaf; - struct ext4_extent *ext; - int i; - block_t start; - - leaf = ext4_find_leaf(fs, (struct ext4_extent_header*)inode->i_block, block); - if (!leaf) { - printf("ERROR, extent leaf not found\n"); - return 0; - } - - ext = EXT4_FIRST_EXTENT(leaf); - for (i = 0; i < leaf->eh_entries; i++) { - if (block < ext[i].ee_block) - break; - } - if (--i < 0) { - printf("ERROR, not find the right block\n"); - return 0; - } - - /* got it */ - block -= ext[i].ee_block; - if (block >= ext[i].ee_len) - return 0; - - start = ext[i].ee_start_hi; - start = (start << 32) + ext[i].ee_start_lo; - - return start + block; + struct ext2_sb_info *sbi = EXT2_SB(this_fs); + + if (group_num >= sbi->s_groups_count) { + printf ("ext2_get_group_desc" + "block_group >= groups_count - " + "block_group = %d, groups_count = %d", + group_num, sbi->s_groups_count); + + return NULL; + } + + return sbi->s_group_desc[group_num]; } -/** - * linsector_direct: - * - * @param: block, the block index - * @param: inode, the inode structure - * - * @return: the physic block number - */ -static block_t linsector_direct(struct fs_info *fs, uint32_t block, struct ext2_inode *inode) -{ - struct cache_struct *cs; - - /* direct blocks */ - if (block < EXT2_NDIR_BLOCKS) - return inode->i_block[block]; - - - /* indirect blocks */ - block -= EXT2_NDIR_BLOCKS; - if (block < PtrsPerBlock1) { - block_t ind_block = inode->i_block[EXT2_IND_BLOCK]; - cs = get_cache_block(fs->fs_dev, ind_block); - - return ((uint32_t *)cs->data)[block]; - } - - /* double indirect blocks */ - block -= PtrsPerBlock1; - if (block < PtrsPerBlock2) { - block_t dou_block = inode->i_block[EXT2_DIND_BLOCK]; - cs = get_cache_block(fs->fs_dev, dou_block); - - dou_block = ((uint32_t *)cs->data)[block / PtrsPerBlock1]; - cs = get_cache_block(fs->fs_dev, dou_block); - - return ((uint32_t*)cs->data)[block % PtrsPerBlock1]; - } - - /* triple indirect block */ - block -= PtrsPerBlock2; - if (block < PtrsPerBlock3) { - block_t tri_block = inode->i_block[EXT2_TIND_BLOCK]; - cs = get_cache_block(fs->fs_dev, tri_block); - - tri_block = ((uint32_t *)cs->data)[block / PtrsPerBlock2]; - cs = get_cache_block(fs->fs_dev, tri_block); - - tri_block = ((uint32_t *)cs->data)[block % PtrsPerBlock2]; - cs = get_cache_block(fs->fs_dev, tri_block); - - return ((uint32_t*)cs->data)[block % PtrsPerBlock1]; - } - - /* File too big, can not handle */ - printf("ERROR, file too big\n"); - return 0; -} - /** * linsector: @@ -332,52 +63,16 @@ static block_t linsector_direct(struct fs_info *fs, uint32_t block, struct ext2_ * * @return: physic sector number */ -static sector_t linsector(struct fs_info *fs, uint32_t lin_sector) +static sector_t linsector(struct fs_info *fs, + struct inode *inode, + uint32_t lin_sector) { - uint32_t block = lin_sector >> ClustShift; - block_t ret; - struct ext2_inode *inode; - - /* well, this is what I think the variable this_inode used for */ - inode = &this_inode; - - if (inode->i_flags & EXT4_EXTENTS_FLAG) - ret = linsector_extent(fs, block, inode); - else - ret = linsector_direct(fs, block, inode); - - if (!ret) { - printf("ERROR: something error happend at linsector..\n"); - return 0; - } + block_t block = bmap(fs, inode, lin_sector >> fs->blk_bits); - /* finally convert it to sector */ - return ((ret << ClustShift) + (lin_sector & ClustMask)); -} - - -/* - * NOTE! unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure. - * - * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. - */ -static inline int ext2_match_entry (const char * const name, - struct ext2_dir_entry * de) -{ - if (!de->d_inode) - return 0; - return !strncmp(name, de->d_name, de->d_name_len); + return (block << fs->blk_bits) + (lin_sector & ((1 << fs->blk_bits) - 1)); } -/* - * p is at least 6 bytes before the end of page - */ -static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p) -{ - return (struct ext2_dir_entry *)((char*)p + p->d_rec_len); -} - /** * getlinsec_ext: * @@ -387,13 +82,14 @@ static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p) * */ static void getlinsec_ext(struct fs_info *fs, char *buf, - sector_t sector, int sector_cnt) + sector_t sector, int sector_cnt) { int ext_cnt = 0; + int sec_per_block = 1 << fs->blk_bits; struct disk *disk = fs->fs_dev->disk; - if (sector < SecPerClust) { - ext_cnt = SecPerClust - sector; + if (sector < sec_per_block) { + ext_cnt = sec_per_block - sector; memset(buf, 0, ext_cnt << SECTOR_SHIFT); buf += ext_cnt << SECTOR_SHIFT; } @@ -412,25 +108,26 @@ static void getlinsec_ext(struct fs_info *fs, char *buf, * do. So, let it be based on sectors. * */ -static uint32_t ext2_getfssec(struct file *gfile, char *buf, +static uint32_t ext2_getfssec(struct file *file, char *buf, int sectors, bool *have_more) { int sector_left, next_sector, sector_idx; int frag_start, con_sec_cnt; int bytes_read = sectors << SECTOR_SHIFT; - struct open_file_t *file = gfile->open_file; - struct fs_info *fs = gfile->fs; + struct inode *inode = file->u1.inode; + struct fs_info *fs = file->fs; + uint32_t bytesleft = inode->size - file->u2.offset; - sector_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + sector_left = (bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT; if (sectors > sector_left) sectors = sector_left; + sector_idx = file->u2.offset >> SECTOR_SHIFT; while (sectors) { /* * get the frament */ - sector_idx = file->file_sector; - next_sector = frag_start = linsector(fs, sector_idx); + next_sector = frag_start = linsector(fs, inode, sector_idx); con_sec_cnt = 0; /* get the consective sectors count */ @@ -446,226 +143,217 @@ static uint32_t ext2_getfssec(struct file *gfile, char *buf, sector_idx ++; next_sector ++; - } while (next_sector == linsector(fs, sector_idx)); + } while (next_sector == linsector(fs, inode, sector_idx)); -#if 0 +#if 0 printf("You are reading data stored at sector --0x%x--0x%x\n", frag_start, frag_start + con_sec_cnt -1); #endif getlinsec_ext(fs, buf, frag_start, con_sec_cnt); - buf += con_sec_cnt << 9; - file->file_sector += con_sec_cnt; /* next sector index */ + buf += con_sec_cnt << SECTOR_SHIFT; } while(sectors); - if (bytes_read >= file->file_bytesleft) { - bytes_read = file->file_bytesleft; + if (bytes_read >= bytesleft) { + bytes_read = bytesleft; *have_more = 0; } else { *have_more = 1; } - file->file_bytesleft -= bytes_read; - + file->u2.offset += bytes_read; + return bytes_read; } - +/* + * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure. + */ +static inline int ext2_match_entry (const char * const name, + struct ext2_dir_entry * de) +{ + if (!de->d_inode) + return 0; + if (strlen(name) != de->d_name_len) + return 0; + return !strncmp(name, de->d_name, de->d_name_len); +} + + +/* + * p is at least 6 bytes before the end of page + */ +static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p) +{ + return (struct ext2_dir_entry *)((char*)p + p->d_rec_len); +} /* * find a dir entry, return it if found, or return NULL. - * */ -static struct ext2_dir_entry* -find_dir_entry(struct fs_info *fs, struct open_file_t *file, char *filename) +static struct ext2_dir_entry * +ext2_find_entry(struct fs_info *fs, struct inode *inode, char *dname) { - bool have_more; - char *EndBlock = trackbuf + (SecPerClust << SECTOR_SHIFT);; + int index = 0; + block_t block; + uint32_t i = 0; struct ext2_dir_entry *de; - struct file xfile; - - /* Fake out a VFS file structure */ - xfile.fs = fs; - xfile.open_file = file; + struct cache_struct *cs; - /* read a clust at a time */ - ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more); - de = (struct ext2_dir_entry *)trackbuf; + if (!(block = bmap(fs, inode, index++))) + return NULL; + cs = get_cache_block(fs->fs_dev, block); + de = (struct ext2_dir_entry *)cs->data; + + while(i < (int)inode->size) { + if (ext2_match_entry(dname, de)) + return de; + i += de->d_rec_len; + if (i >= (int)inode->size) + break; + if ((char *)de >= (char *)cs->data + inode->blksize) { + if (!(block = bmap(fs, inode, index++))) + break; + cs = get_cache_block(fs->fs_dev, block); + de = (struct ext2_dir_entry *)cs->data; + continue; + } + + de = ext2_next_entry(de); + } - while (1) { - if ((char *)de >= (char *)EndBlock) { - if (!have_more) - return NULL; - ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more); - de = (struct ext2_dir_entry *)trackbuf; - } - - /* Zero inode == void entry */ - if (de->d_inode == 0) { - de = ext2_next_entry(de); - continue; - } - - if (ext2_match_entry (filename, de)) { - filename += de->d_name_len; - if ((*filename == 0) || (*filename == '/')) - return de; /* got it */ - - /* not match, restore the filename then try next */ - filename -= de->d_name_len; - } - - de = ext2_next_entry(de); - } + return NULL; } - -static char *do_symlink(struct fs_info *fs, struct open_file_t *file, - uint32_t file_len, char *filename) +static struct ext2_inode * get_inode(int inr) { - int flag; - bool have_more; - - char *SymlinkTmpBuf = trackbuf; - char *lnk_end; - char *SymlinkTmpBufEnd = trackbuf + SYMLINK_SECTORS * SECTOR_SIZE+64; - struct file xfile; - xfile.fs = fs; - xfile.open_file = file; - - flag = this_inode.i_file_acl ? SecPerClust : 0; - if (this_inode.i_blocks == flag) { - /* fast symlink */ - close_pvt(file); /* we've got all we need */ - memcpy(SymlinkTmpBuf, this_inode.i_block, file_len); - lnk_end = SymlinkTmpBuf + file_len; - - } else { - /* slow symlink */ - ext2_getfssec(&xfile, SymlinkTmpBuf, SYMLINK_SECTORS, &have_more); - lnk_end = SymlinkTmpBuf + file_len; - } + struct ext2_group_desc *desc; + struct cache_struct *cs; + uint32_t inode_group, inode_offset; + uint32_t block_num, block_off; - if (*filename != 0) - *lnk_end++ = '/'; + inr--; + inode_group = inr / EXT2_INODES_PER_GROUP(this_fs); + inode_offset = inr % EXT2_INODES_PER_GROUP(this_fs); + desc = ext2_get_group_desc (inode_group); + if (!desc) + return NULL; - if (strecpy(lnk_end, filename, SymlinkTmpBufEnd)) - return NULL; /* buffer overflow */ + block_num = desc->bg_inode_table + + inode_offset / EXT2_INODES_PER_BLOCK(this_fs); + block_off = inode_offset % EXT2_INODES_PER_BLOCK(this_fs); - /* - * now copy it to the "real" buffer; we need to have - * two buffers so we avoid overwriting the tail on - * the next copy. - */ - strcpy(SymlinkBuf, SymlinkTmpBuf); + cs = get_cache_block(this_fs->fs_dev, block_num); - /* return the new path */ - return SymlinkBuf; + return cs->data + block_off * EXT2_SB(this_fs)->s_inode_size; } +static inline int get_inode_mode(int mode) +{ + mode >>= S_IFSHIFT; + if (mode == T_IFDIR) + mode = I_DIR; + else if (mode == T_IFLNK) + mode = I_SYMLINK; + else + mode = I_FILE; /* we treat others as FILE */ + return mode; +} +static void fill_inode(struct inode *inode, struct ext2_inode *e_inode) +{ + inode->mode = get_inode_mode(e_inode->i_mode); + inode->size = e_inode->i_size; + inode->atime = e_inode->i_atime; + inode->ctime = e_inode->i_ctime; + inode->mtime = e_inode->i_mtime; + inode->dtime = e_inode->i_dtime; + inode->blocks = e_inode->i_blocks; + inode->flags = e_inode->i_flags; + inode->blksize = 1 << (SECTOR_SHIFT + this_fs->blk_bits); + inode->file_acl = e_inode->i_file_acl; + + inode->data = malloc(EXT2_N_BLOCKS * sizeof(uint32_t *)); + if (!inode->data) { + malloc_error("inode data filed"); + return ; + } + memcpy(inode->data, e_inode->i_block, EXT2_N_BLOCKS * sizeof(uint32_t *)); +} +static struct inode *ext2_iget_by_inr(uint32_t inr) +{ + struct ext2_inode *e_inode; + struct inode *inode; + + e_inode = get_inode(inr); + if (!(inode = malloc(sizeof(*inode)))) + return NULL; + fill_inode(inode, e_inode); + inode->ino = inr; + + return inode; +} -/** - * Search the root directory for a pre-mangle filename in FILENAME. - * - * @param: filename, the filename we want to search. - * - * @out : a open_file_t structure pointer, stores in file->open_file - * @out : file lenght in bytes, stores in file->file_len - * - */ -static void ext2_searchdir(char *filename, struct file *file) +static struct inode *ext2_iget_root() +{ + return ext2_iget_by_inr(EXT2_ROOT_INO); +} + +static struct inode *ext2_iget_current() { extern int CurrentDir; - struct open_file_t *open_file; - struct ext2_dir_entry *de; - uint8_t file_mode; - uint8_t SymlinkCtr = MAX_SYMLINKS; - uint32_t inr = CurrentDir; - uint32_t ThisDir = CurrentDir; - uint32_t file_len; - - begin_path: - while (*filename == '/') { /* Absolute filename */ - inr = EXT2_ROOT_INO; - filename ++; - } - open: - if ((open_file = open_inode(file->fs, inr, &file_len)) == NULL) - goto err_noclose; - - file_mode = open_file->file_mode >> S_IFSHIFT; - - /* It's a file */ - if (file_mode == T_IFREG) { - if (*filename == '\0') - goto done; - else - goto err; - } - - - /* It's a directory */ - if (file_mode == T_IFDIR) { - ThisDir = inr; - - if (*filename == 0) - goto err; - while (*filename == '/') - filename ++; + if (CurrentDir) + return ext2_iget_by_inr(CurrentDir); +} + +static struct inode *ext2_iget(char *dname, struct inode *parent) +{ + struct ext2_dir_entry *de; - de = find_dir_entry(file->fs, open_file, filename); - if (!de) - goto err; + de = ext2_find_entry(this_fs, parent, dname); + if (!de) + return NULL; - inr = de->d_inode; - filename += de->d_name_len; - close_pvt(open_file); - goto open; - } + return ext2_iget_by_inr(de->d_inode); +} + + +static char * ext2_follow_symlink(struct inode *inode, const char *name_left) +{ + int sec_per_block = 1 << this_fs->blk_bits; + int fast_symlink; + char *symlink_buf; + char *p; + struct cache_struct *cs; - - /* - * It's a symlink. We have to determine if it's a fast symlink - * (data stored in the inode) or not (data stored as a regular - * file.) Either which way, we start from the directory - * which we just visited if relative, or from the root directory - * if absolute, and append any remaining part of the path. - */ - if (file_mode == T_IFLNK) { - if (--SymlinkCtr==0 || file_len>=SYMLINK_SECTORS*SECTOR_SIZE) - goto err; /* too many links or symlink too long */ - - filename = do_symlink(file->fs, open_file, file_len, filename); - if (!filename) - goto err_noclose;/* buffer overflow */ - - inr = ThisDir; - goto begin_path; /* we got a new path, so search it again */ + symlink_buf = malloc(inode->blksize); + if (!symlink_buf) { + malloc_error("symlink buffer"); + return NULL; } + fast_symlink = (inode->file_acl ? sec_per_block : 0) == inode->blocks; + if (fast_symlink) { + memcpy(symlink_buf, inode->data, inode->size); + } else { + cs = get_cache_block(this_fs->fs_dev, *(uint32_t *)inode->data); + memcpy(symlink_buf, cs->data, inode->size); + } + p = symlink_buf + inode->size; - /* Otherwise, something bad ... */ - err: - close_pvt(open_file); - err_noclose: - file_len = 0; - open_file = NULL; - done: - - file->file_len = file_len; - file->open_file = (void*)open_file; - -#if 0 - if (open_file) { - printf("file bytesleft: %d\n", open_file->file_bytesleft); - printf("file sector : %d\n", open_file->file_sector); - printf("file in sector: %d\n", open_file->file_in_sec); - printf("file offsector: %d\n", open_file->file_in_off); + if (*name_left) + *p++ = '/'; + if (strecpy(p, name_left, symlink_buf + inode->blksize)) { + free(symlink_buf); + return NULL; } -#endif - + if(!(p = strdup(symlink_buf))) + return symlink_buf; + + free(symlink_buf); + return p; } + /* Load the config file, return 1 if failed, or 0 */ static int ext2_load_config(void) { @@ -689,35 +377,93 @@ static int ext2_load_config(void) static int ext2_fs_init(struct fs_info *fs) { struct disk *disk = fs->fs_dev->disk; - - /* read the super block */ - disk->rdwr_sectors(disk, &sb, 2, 2, 0); + struct ext2_sb_info *sbi; + struct ext2_super_block *esb; + int block_size; + int block_shift; + int db_count; + int i; + int desc_block; + char *desc_buffer; - ClustByteShift = sb.s_log_block_size + 10; - ClustSize = 1 << ClustByteShift; - ClustShift = ClustByteShift - SECTOR_SHIFT; + esb = malloc(sizeof(struct ext2_super_block)); + if (!esb) { + malloc_error("ext2_super_block structure"); + return -1; + } - DescPerBlock = ClustSize >> ext2_group_desc_lg2size; - InodePerBlock = ClustSize / sb.s_inode_size; + /* read the super block */ + disk->rdwr_sectors(disk, esb, 2, 2, 0); + - SecPerClust = ClustSize >> SECTOR_SHIFT; - ClustMask = SecPerClust - 1; + sbi = malloc(sizeof(*sbi)); + if (!sbi) { + malloc_error("ext2_sb_info structure"); + return -1; + } + fs->fs_info = sbi; + sbi->s_es = esb; - PtrsPerBlock1 = 1 << (ClustByteShift - 2); - PtrsPerBlock2 = 1 << ((ClustByteShift - 2) * 2); - PtrsPerBlock3 = 1 << ((ClustByteShift - 2) * 3); + if (esb->s_magic != EXT2_SUPER_MAGIC) { + printf("ext2 mount error: can't found ext2 file system!\n"); + return 0; + } + + block_shift = esb->s_log_block_size + 10; + block_size = 1 << block_shift; + fs->blk_bits = block_shift - SECTOR_SHIFT; + + sbi->s_inodes_per_group = esb->s_inodes_per_group; + sbi->s_blocks_per_group = esb->s_blocks_per_group; + sbi->s_inodes_per_block = block_size / esb->s_inode_size; + sbi->s_itb_per_group = sbi->s_inodes_per_group / + sbi->s_inodes_per_block; + if (esb->s_desc_size < sizeof(struct ext2_group_desc)) + esb->s_desc_size = sizeof(struct ext2_group_desc); + sbi->s_desc_per_block = block_size / esb->s_desc_size; + sbi->s_groups_count = (esb->s_blocks_count - esb->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(fs) - 1) + / EXT2_BLOCKS_PER_GROUP(fs); + db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(fs) - 1) / + EXT2_DESC_PER_BLOCK(fs); + sbi->s_gdb_count = db_count; + sbi->s_inode_size = esb->s_inode_size; + + /* read the descpritors */ + desc_block = esb->s_first_data_block + 1; + desc_buffer = malloc(db_count * block_size); + if (!desc_buffer) { + malloc_error("desc_buffer"); + return -1; + } + disk->rdwr_sectors(disk, desc_buffer, desc_block << fs->blk_bits, + db_count << fs->blk_bits, 0); + sbi->s_group_desc = malloc(sizeof(struct ext2_group_desc *) + * sbi->s_groups_count); + if (!sbi->s_group_desc) { + malloc_error("sbi->s_group_desc"); + return -1; + } + for (i = 0; i < (int)sbi->s_groups_count; i++) { + sbi->s_group_desc[i] = (struct ext2_group_desc *)desc_buffer; + desc_buffer += esb->s_desc_size; + } - return ClustByteShift; + return block_shift; } const struct fs_ops ext2_fs_ops = { .fs_name = "ext2", .fs_flags = 0, .fs_init = ext2_fs_init, - .searchdir = ext2_searchdir, + .searchdir = NULL, .getfssec = ext2_getfssec, .close_file = ext2_close_file, .mangle_name = generic_mangle_name, .unmangle_name = generic_unmangle_name, - .load_config = ext2_load_config + .load_config = ext2_load_config, + .iget_root = ext2_iget_root, + .iget_current = ext2_iget_current, + .iget = ext2_iget, + .follow_symlink = ext2_follow_symlink }; diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h index d579ead..0df983b 100644 --- a/core/fs/ext2/ext2_fs.h +++ b/core/fs/ext2/ext2_fs.h @@ -105,8 +105,37 @@ struct ext2_super_block { uint32_t s_algorithm_usage_bitmap; /* For compression */ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ uint8_t s_prealloc_dir_blocks; - uint16_t s_padding1; - uint32_t s_reserved[204]; /* Padding to the end of the block */ + uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */ + /* + * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. + */ + uint8_t s_journal_uuid[16]; /* uuid of journal superblock */ + uint32_t s_journal_inum; /* inode number of journal file */ + uint32_t s_journal_dev; /* device number of journal file */ + uint32_t s_last_orphan; /* start of list of inodes to delete */ + uint32_t s_hash_seed[4]; /* HTREE hash seed */ + uint8_t s_def_hash_version; /* Default hash version to use */ + uint8_t s_reserved_char_pad; + uint16_t s_desc_size; /* size of group descriptor */ + uint32_t s_default_mount_opts; + uint32_t s_first_meta_bg; /* First metablock block group */ + uint32_t s_mkfs_time; /* When the filesystem was created */ + uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */ + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ + uint32_t s_blocks_count_hi; /* Blocks count */ + uint32_t s_r_blocks_count_hi; /* Reserved blocks count */ + uint32_t s_free_blocks_count_hi;/* Free blocks count */ + uint16_t s_min_extra_isize; /* All inodes have at least # bytes */ + uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */ + uint32_t s_flags; /* Miscellaneous flags */ + uint16_t s_raid_stride; /* RAID stride */ + uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */ + uint64_t s_mmp_block; /* Block for multi-mount protection */ + uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + uint8_t s_log_groups_per_flex; /* FLEX_BG group size */ + uint8_t s_reserved_char_pad2; + uint16_t s_reserved_pad; + uint32_t s_reserved[162]; /* Padding to the end of the block */ }; /******************************************************************************* @@ -237,16 +266,45 @@ struct ext4_extent_header { #define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) ) +/* + * The ext2 super block information in memory + */ +struct ext2_sb_info { + uint32_t s_inodes_per_block;/* Number of inodes per block */ + uint32_t s_blocks_per_group;/* Number of blocks in a group */ + uint32_t s_inodes_per_group;/* Number of inodes in a group */ + uint32_t s_itb_per_group; /* Number of inode table blocks per group */ + uint32_t s_gdb_count; /* Number of group descriptor blocks */ + uint32_t s_desc_per_block; /* Number of group descriptors per block */ + uint32_t s_groups_count; /* Number of groups in the fs */ + int s_addr_per_block_bits; + int s_desc_per_block_bits; + int s_inode_size; + int s_first_ino; + struct ext2_super_block * s_es; + /* + * Here did not like Linux Kernel did; the group descriptor cache + * here is based on ext2_group_desc structure, instead of buffer + * head structure in Linux Kernel, where cache one block data. + */ + struct ext2_group_desc ** s_group_desc; +}; +static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs) +{ + return fs->fs_info; +} +#define EXT2_BLOCKS_PER_GROUP(fs) (EXT2_SB(fs)->s_blocks_per_group) +#define EXT2_INODES_PER_GROUP(fs) (EXT2_SB(fs)->s_inodes_per_group) +#define EXT2_INODES_PER_BLOCK(fs) (EXT2_SB(fs)->s_inodes_per_block) +#define EXT2_DESC_PER_BLOCK(fs) (EXT2_SB(fs)->s_desc_per_block) - -/* function declartion */ -/******************************************************************************* -extern struct open_file_t * ext2_read(char *); -extern int ext2_read(struct open_file_t *, char *, int); -*******************************************************************************/ +/* + * functions + */ +block_t bmap(struct fs_info *, struct inode *, int); #endif /* ext2_fs.h */ diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index e7931b0..e8a82ac 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -95,7 +95,7 @@ static inline void close_pvt(struct open_file_t *of) static void vfat_close_file(struct file *file) { - close_pvt(file->open_file); + close_pvt(file->u1.open_file); } @@ -290,7 +290,7 @@ static uint32_t vfat_getfssec(struct file *gfile, char *buf, int sectors, bool *have_more) { uint32_t bytes_read = sectors << SECTOR_SHIFT; - struct open_file_t *file = gfile->open_file; + struct open_file_t *file = gfile->u1.open_file; struct fs_info *fs = gfile->fs; if (sectors > file->file_left) @@ -662,8 +662,8 @@ static void vfat_searchdir(char *filename, struct file *file) open_file->file_left = (file_len + SECTOR_SIZE -1) >> SECTOR_SHIFT; } - file->file_len = file_len; - file->open_file = open_file; + file->u2.file_len = file_len; + file->u1.open_file = open_file; } /* @@ -695,7 +695,7 @@ struct dirent* vfat_readdir(struct file *dir) struct cache_struct *cs; struct fat_dir_entry *fat_dir; struct fat_long_name_entry *long_dir; - struct open_file_t *file = dir->open_file; + struct open_file_t *file = dir->u1.open_file; struct fs_info *fs = dir->fs; sector = file->file_sector; @@ -891,5 +891,6 @@ const struct fs_ops vfat_fs_ops = { .unmangle_name = generic_unmangle_name, .load_config = vfat_load_config, .opendir = vfat_opendir, - .readdir = vfat_readdir + .readdir = vfat_readdir, + .iget_current = NULL }; diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c index 6918a7f..1ab6d04 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -69,7 +69,7 @@ static inline void close_pvt(struct open_file_t *file) static void iso_close_file(struct file *file) { - close_pvt(file->open_file); + close_pvt(file->u1.open_file); } /* @@ -205,7 +205,7 @@ static uint32_t iso_getfssec(struct file *gfile, char *buf, int sectors, bool *have_more) { uint32_t bytes_read = sectors << ISO_SECTOR_SHIFT; - struct open_file_t *file = gfile->open_file; + struct open_file_t *file = gfile->u1.open_file; struct disk *disk = gfile->fs->fs_dev->disk; if ( sectors > file->file_left ) @@ -258,7 +258,7 @@ static int do_search_dir(struct fs_info *fs, struct dir_t *dir, file->file_sector = dir->dir_lba; xfile.fs = fs; - xfile.open_file = file; + xfile.u1.open_file = file; iso_getfssec(&xfile, trackbuf, BufSafe, &have_more); de = (struct iso_dir_entry *)trackbuf; @@ -428,8 +428,8 @@ static void iso_searchdir(char *filename, struct file *file) open_file = NULL; found: - file->file_len = file_len; - file->open_file = (void*)open_file; + file->u2.file_len = file_len; + file->u1.open_file = (void*)open_file; #if 0 if (open_file) { @@ -490,10 +490,10 @@ static int iso_fs_init(struct fs_info *fs) iso_dir = boot_dir; file.fs = fs; iso_searchdir(boot_dir, &file); /* search for /boot/isolinux */ - if ( !file.file_len ) { + if ( !file.u2.file_len ) { iso_dir = isolinux_dir; iso_searchdir(isolinux_dir, &file); /* search for /isolinux */ - if ( !file.file_len ) { + if ( !file.u2.file_len ) { printf("No isolinux directory found!\n"); return 0; } @@ -504,7 +504,7 @@ static int iso_fs_init(struct fs_info *fs) CurrentDirName[len] = '/'; CurrentDirName[len+1] = '\0'; - open_file = (struct open_file_t *)file.open_file; + open_file = (struct open_file_t *)file.u1.open_file; CurrentDir.dir_len = open_file->file_bytesleft; CurrentDir.dir_clust = open_file->file_left; CurrentDir.dir_lba = open_file->file_sector; @@ -528,5 +528,6 @@ const struct fs_ops iso_fs_ops = { .close_file = iso_close_file, .mangle_name = iso_mangle_name, .unmangle_name = generic_unmangle_name, - .load_config = iso_load_config + .load_config = iso_load_config, + .iget_current = NULL }; diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c index 4d08191..237f943 100644 --- a/core/fs/pxe/pxe.c +++ b/core/fs/pxe/pxe.c @@ -119,7 +119,7 @@ static void free_socket(struct open_file_t *file) static void pxe_close_file(struct file *file) { - struct open_file_t *open_file = file->open_file; + struct open_file_t *open_file = file->u1.open_file; if (open_file->tftp_localport && !open_file->tftp_goteof) tftp_error(open_file, 0, "No error, file close"); @@ -662,7 +662,7 @@ static void fill_buffer(struct open_file_t *file) static uint32_t pxe_getfssec(struct file *gfile, char *buf, int blocks, bool *have_more) { - struct open_file_t *file = gfile->open_file; + struct open_file_t *file = gfile->u1.open_file; int count = blocks; int chunk; int bytes_read = 0; @@ -748,8 +748,8 @@ static void pxe_searchdir(char *filename, struct file *file) open_file = allocate_socket(); if (!open_file) { - file->file_len = 0; - file->open_file = NULL; + file->u2.file_len = 0; + file->u1.open_file = NULL; return; } @@ -980,12 +980,12 @@ static void pxe_searchdir(char *filename, struct file *file) done: if (!open_file->tftp_filesize) { free_socket(open_file); - file->file_len = 0; - file->open_file = NULL; + file->u2.file_len = 0; + file->u1.open_file = NULL; return; } - file->open_file = (void *)open_file; - file->file_len = open_file->tftp_filesize; + file->u1.open_file = (void *)open_file; + file->u2.file_len = open_file->tftp_filesize; return; err_reply: @@ -1569,5 +1569,6 @@ const struct fs_ops pxe_fs_ops = { .close_file = pxe_close_file, .mangle_name = pxe_mangle_name, .unmangle_name = pxe_unmangle_name, - .load_config = pxe_load_config + .load_config = pxe_load_config, + .iget_current = NULL }; diff --git a/core/include/core.h b/core/include/core.h index dbcbff1..1a9e1b9 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -23,6 +23,11 @@ extern void (*idle_hook_func)(void); /* hello.c */ extern void myputs(const char*); +/* malloc.c */ +extern void *malloc(int); +extern void free(void *); +extern void mem_init(void); + void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *); void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *); int __cdecl core_cfarcall(uint32_t, const void *, uint32_t); diff --git a/core/include/fs.h b/core/include/fs.h index df10302..35d46ed 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -23,17 +23,14 @@ struct fs_info { const struct fs_ops *fs_ops; struct device *fs_dev; + void *fs_info; /* The fs-specific information */ + int blk_bits; /* block_size = 1 << (blk_bits + SECTOR_SHIFT */ }; -struct open_file_t; /* Filesystem private structure */ -struct dirent; /* Directory entry structure */ - -struct file { - struct open_file_t *open_file; /* Filesystem private data */ - struct fs_info *fs; - uint32_t file_len; -}; +extern struct fs_info *this_fs; +struct dirent; /* Directory entry structure */ +struct file; enum fs_flags { FS_NODEV = 1, }; @@ -51,11 +48,54 @@ struct fs_ops { char * (*unmangle_name)(char *, const char *); int (*load_config)(); + struct inode * (*iget_root)(void); + struct inode * (*iget_current)(void); + struct inode * (*iget)(char *, struct inode *); + char * (*follow_symlink)(struct inode *, const char *); + /* the _dir_ stuff */ void (*opendir)(com32sys_t *); struct dirent * (*readdir)(struct file *); }; +enum inode_mode {I_FILE, I_DIR, I_SYMLINK}; + +/* + * The inode structure, including the detail file information + */ +struct inode { + int mode; /* FILE , DIR or SYMLINK */ + uint32_t size; + uint32_t ino; /* Inode number */ + uint32_t atime; /* Access time */ + uint32_t mtime; /* Modify time */ + uint32_t ctime; /* Create time */ + uint32_t dtime; /* Delete time */ + int blocks; /* How many blocks the file take */ + uint32_t * data; /* The block address array where the file stored */ + uint32_t flags; + int blkbits; + int blksize; + uint32_t file_acl; +}; + +extern struct inode *this_inode; + +struct open_file_t; + +struct file { + struct fs_info *fs; + union { + struct inode *inode; /* the file-specific information */ + struct open_file_t *open_file; + } u1; + union { + uint32_t offset; /* for next read */ + uint32_t file_len; + } u2; +}; + + enum dev_type {CHS, EDD}; /* @@ -88,6 +128,20 @@ static inline bool not_whitespace(char c) return (unsigned char)c > ' '; } +static inline void free_inode(struct inode * inode) +{ + if (inode) { + if (inode->data) + free(inode->data); + free(inode); + } +} + +static inline void malloc_error(char *obj) +{ + printf("Out of memory: can't allocate memory for %s\n", obj); +} + /* * functions */ diff --git a/core/malloc.c b/core/malloc.c new file mode 100644 index 0000000..a033ff0 --- /dev/null +++ b/core/malloc.c @@ -0,0 +1,216 @@ +/* + * A simple temp malloc for Sysliux project from fstk. For now, just used + * in fsc branch, which it's would be easy to remove it when we have a + * powerful one, as hpa said this would happen when elflink branch do the + * work. + * + * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file + * may be redistributed under the terms of the GNU Public License. + */ + + +#include +#include +#include + +/* The memory managemant structure */ +struct mem_struct { + struct mem_struct *prev; + int size; + int free; +}; + + +/* First, assume we just need 64K memory */ +static char memory[0x10000]; + +/* Next free memory address */ +static struct mem_struct *next_start = (struct mem_struct *)memory; +static uint32_t mem_end = (uint32_t)(memory + 0x10000); + + +static inline struct mem_struct *get_next(struct mem_struct *mm) +{ + uint32_t next = (uint32_t)mm + mm->size; + + if (next >= mem_end) + return NULL; + else + return (struct mem_struct *)next; +} + +/* + * Here are the _merge_ functions, that merges a adjacent memory region, + * from front, or from back, or even merges both. It returns the headest + * region mem_struct. + * + */ + +static struct mem_struct * merge_front(struct mem_struct *mm, + struct mem_struct *prev) +{ + struct mem_struct *next = get_next(mm); + + prev->size += mm->size; + if (next) + next->prev = prev; + return prev; +} + +static struct mem_struct * merge_back(struct mem_struct *mm, + struct mem_struct *next) +{ + mm->free = 1; /* Mark it free first */ + mm->size += next->size; + + next = get_next(next); + if (next) + next->prev = mm; + return mm; +} + +static struct mem_struct * merge_both(struct mem_struct *mm, + struct mem_struct *prev, + struct mem_struct *next) +{ + prev->size += mm->size + next->size; + + next = get_next(next); + if (next) + next->prev = prev; + return prev; +} + +static inline struct mem_struct * try_merge_front(struct mem_struct *mm) +{ + mm->free = 1; + if (mm->prev->free) + mm = merge_front(mm, mm->prev); + return mm; +} + +static inline struct mem_struct * try_merge_back(struct mem_struct *mm) +{ + struct mem_struct *next = get_next(mm); + + mm->free = 1; + if (next->free) + merge_back(mm, next); + return mm; +} + +/* + * Here's the main function, malloc, which allocates a memory rigon + * of size _size_. Returns NULL if failed, or the address newly allocated. + * + */ +void *malloc(int size) +{ + struct mem_struct *next = next_start; + struct mem_struct *good = next, *prev; + int size_needed = (size + sizeof(struct mem_struct) + 3) & ~3; + + while(next) { + if (next->free && next->size >= size_needed) { + good = next; + break; + } + next = get_next(next); + } + if (good->size < size_needed) { + printf("Out of memory, maybe we need append it\n"); + return NULL; + } else if (good->size == size_needed) { + /* + * We just found a right memory that with the exact + * size we want. So we just Mark it _not_free_ here, + * and move on the _next_start_ pointer, even though + * the next may not be a right next start. + */ + good->free = 0; + next_start = get_next(good); + goto out; + } else + size = good->size; /* save the total size */ + + /* + * Note: allocate a new memory region will not change + * it's prev memory, so we don't need change it here. + */ + good->free = 0; /* Mark it not free any more */ + good->size = size_needed; + + next = get_next(good); + if (next) { + next->size = size - size_needed; + /* check if it can contain 1 byte allocation at least */ + if (next->size <= (int)sizeof(struct mem_struct)) { + good->size = size; /* restore the original size */ + next_start = get_next(good); + goto out; + } + + next->prev = good; + next->free = 1; + next_start = next; /* Update next_start */ + + prev = next; + next = get_next(next); + if (next) + next->prev = prev; + } else + next_start = (struct mem_struct *)memory; +out: + return (void *)((uint32_t)good + sizeof(struct mem_struct)); +} + +void free(void *ptr) +{ + struct mem_struct *mm = ptr - sizeof(*mm); + struct mem_struct *prev = mm->prev; + struct mem_struct *next = get_next(mm); + + if (!prev) + mm = try_merge_back(mm); + else if (!next) + mm = try_merge_front(mm); + else if (prev->free && !next->free) + merge_front(mm, prev); + else if (!prev->free && next->free) + merge_back(mm, next); + else if (prev->free && next->free) + merge_both(mm, prev, next); + else + mm->free = 1; + + if (mm < next_start) + next_start = mm; +} + +/* + * The debug function + */ +void check_mem(void) +{ + struct mem_struct *next = (struct mem_struct *)memory; + + printf("____________\n"); + while (next) { + printf("%-6d %s\n", next->size, next->free ? "Free" : "Notf"); + next = get_next(next); + } + printf("\n"); +} + + +void mem_init(void) +{ + + struct mem_struct *first = (struct mem_struct *)memory; + + first->prev = NULL; + first->size = 0x10000; + first->free = 1; + + next_start = first; +} -- 2.7.4