Added a generic path_lookup method in vfs
authorYuanhan Liu <Aleaxander@gmail.com>
Sun, 25 Oct 2009 08:32:03 +0000 (16:32 +0800)
committerYuanhan Liu <Aleaxander@gmail.com>
Sun, 25 Oct 2009 08:32:03 +0000 (16:32 +0800)
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 <Aleaxander@gmail.com>
core/fs.c
core/fs/ext2/bmap.c [new file with mode: 0644]
core/fs/ext2/ext2.c
core/fs/ext2/ext2_fs.h
core/fs/fat/fat.c
core/fs/iso9660/iso9660.c
core/fs/pxe/pxe.c
core/include/core.h
core/include/fs.h
core/malloc.c [new file with mode: 0644]

index ed023af..3e489e5 100644 (file)
--- 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 (file)
index 0000000..7d13dec
--- /dev/null
@@ -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 <stdio.h>
+#include <fs.h>
+#include <disk.h>
+#include <cache.h>
+#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;
+}
index e0f289e..a416a88 100644 (file)
@@ -6,36 +6,11 @@
 #include <fs.h>
 #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<<ClustShift) + (block_off>>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
 };
index d579ead..0df983b 100644 (file)
@@ -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 */
index e7931b0..e8a82ac 100644 (file)
@@ -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
 };
index 6918a7f..1ab6d04 100644 (file)
@@ -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
 };
index 4d08191..237f943 100644 (file)
@@ -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
 };
index dbcbff1..1a9e1b9 100644 (file)
@@ -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);
index df10302..35d46ed 100644 (file)
 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 (file)
index 0000000..a033ff0
--- /dev/null
@@ -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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+/* 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;
+}