aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-05-11 04:48:26 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-05-11 04:48:26 +0800
commitc884bf85b74b87db27359b4de22ccaf06a6ba933 (patch)
treef531bbee81452b26f79dded76e1dd66d5a01c58a
downloaddevel-c884bf85b74b87db27359b4de22ccaf06a6ba933.tar.gz
devel-c884bf85b74b87db27359b4de22ccaf06a6ba933.tar.xz
devel-c884bf85b74b87db27359b4de22ccaf06a6ba933.zip
The first version of v0.1
-rw-r--r--Makefile2
-rw-r--r--README45
-rwxr-xr-xa.outbin0 -> 27449 bytes
-rw-r--r--cache.c97
-rw-r--r--cache.h30
-rw-r--r--disklab.c41
-rw-r--r--disklab.h10
-rw-r--r--ext2.imgbin0 -> 1474560 bytes
-rw-r--r--ext2_fs.h207
-rw-r--r--extlinux.c704
-rw-r--r--main.c144
-rw-r--r--types.h17
12 files changed, 1297 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cb8eb69
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+a.out:cache.h cache.c main.c disklab.h disklab.c ext2_fs.h extlinux.c
+ gcc -g cache.c main.c disklab.c extlinux.c
diff --git a/README b/README
new file mode 100644
index 0000000..32fb39b
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+This is the ext2fs driver, it's a user program. And great thanks to stefab
+for the wonderful idea.
+
+I have patched the bin program a.out and the sample ext2 fs image ext2.img,
+which is just a floppy image. So you can test it.
+here is the dir tree(output from ls * -R):
+________________________________________________________________________________
+boot:
+extlinux
+
+boot/extlinux:
+bochsout.txt check.txt extlinux extlinux.conf extlinux.sys git.book hdt.c32
+
+boot/extlinux/extlinux:
+extlinux.conf hdt.c32
+
+link:
+bochsout.txt hdt
+
+lost+found:
+--------------------------------------------------------------------------------
+
+so you can test it as example:
+[xxxx yy]$ ./a.out ext2.img extlinux.conf
+it will output the content of file /boot/extlinux/extlinux.conf.
+the following command will do the same
+[xxxx yy]$ ./a.out ext2.img /boot/extlinux/extlinux.conf
+
+
+well, it can't handle fast symlink file(because the orignal driver can not
+handle it either, it can detect the fast symlink right). that;s to say the
+following code
+
+ flag = ThisInode.i_file_acl ? 1 : 0;
+
+ if ( ThisInode.i_blocks == flag ) {
+ /* fast symlink */
+ } else {
+ /* slow symlink */
+ }
+
+will do not do the right work. And as I don't know how to detect it either, so
+left it where it orignal was.
+
+Any advice or others would be appreciated very much. \ No newline at end of file
diff --git a/a.out b/a.out
new file mode 100755
index 0000000..227f57a
--- /dev/null
+++ b/a.out
Binary files differ
diff --git a/cache.c b/cache.c
new file mode 100644
index 0000000..bfcdf29
--- /dev/null
+++ b/cache.c
@@ -0,0 +1,97 @@
+#include "cache.h"
+#include <stdio.h>
+#include <malloc.h>
+
+
+/*
+ * Each CachePtr contains:
+ * - Block pointer
+ * - LRU previous pointer
+ * - LRU next pointer
+ * - Block data buffer address
+ * The first entry is the head node of the list
+ */
+struct cache_struct cache[CACHE_ENTRIES + 1] = {0,};
+
+
+/**
+ * cache_init:
+ *
+ * Initialize the cache data structres.
+ *
+ */
+void cache_init(void)
+{
+ struct cache_struct *prev, *cur;
+ int i;
+
+ cur = cache;
+ prev = &cache[CACHE_ENTRIES];
+
+ for ( i = 0; i < CACHE_ENTRIES + 1; i++ ) {
+ cur->sector = 0;
+ cur->prev = prev;
+ prev->next = cur;
+ cur->data = NULL;
+
+ prev = cur;
+ cur = &cache[i+1];
+ }
+}
+
+
+
+
+/**
+ * get_cache_sector:
+ *
+ * Check for a particular SECTOR in the sector cache,
+ * and if it is already there, just do nothing and return;
+ * otherwise load it and updata the relative cache
+ * structre with data pointer.
+ *
+ * @param: sector, the sector number we want check.
+ * @retrun: return the most recent cache structure pointer
+ *
+ */
+struct cache_struct * get_cache_sector(int sector)
+{
+ struct cache_struct *cs = &cache[1];
+ struct cache_struct *head, *last;
+ int i;
+
+ for ( i = 0; i < CACHE_ENTRIES; i ++ ) {
+ if ( cs->sector == sector )
+ goto hit;
+ else
+ cs = &cache[i + 1];
+ }
+
+ /* we missed it here, so we need to load it */
+ miss:
+ /* free the first cache's buffer first */
+ if ( cache[0].next->data)
+ free(cache[0].next->data);
+ /* store it at head of real cache */
+ cs = cache[0].next;
+
+ cs->sector = sector;
+ cs->data = (void*)getonesec(sector);
+
+ hit:
+ /* remove cs from current position in list */
+ cs->prev->next = cs->next;
+ cs->next->prev = cs->prev;
+
+
+ /* add to just before head node */
+ last = cache[0].prev;
+ head = cache;
+
+ last->next = cs;
+ cs->prev = last;
+ head->prev = cs;
+ cs->next = head;
+
+ return cs;
+}
diff --git a/cache.h b/cache.h
new file mode 100644
index 0000000..33e07b6
--- /dev/null
+++ b/cache.h
@@ -0,0 +1,30 @@
+#ifndef _CACHE_H
+#define _CACHE_H
+
+#include "types.h"
+
+
+#define CACHE_ENTRIES 0x04 /* just a test */
+
+
+
+/* The cache structure */
+struct cache_struct {
+ /*
+ * This structure is based on secotr and I am thinking
+ * if we should make it based on block for performace.
+ */
+ __u32 sector;
+ struct cache_struct *prev;
+ struct cache_struct *next;
+ void *data;
+};
+
+
+
+/* functions defined in cache.c */
+void cache_init(void);
+
+struct cache_struct *get_cache_sector( int );
+
+#endif /* cache.h */
diff --git a/disklab.c b/disklab.c
new file mode 100644
index 0000000..a3abe36
--- /dev/null
+++ b/disklab.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <malloc.h>
+
+
+extern int fd;
+
+void * getonesec(int sector)
+{
+ void *data;
+ int bytes_read;
+
+ if ( lseek(fd, sector * 512, SEEK_SET) < 0) {/* ... */
+ printf("seek file ext2.img error....\n");
+ return NULL;
+ }
+
+
+ data = malloc(512);
+
+ if ( (bytes_read = read(fd, data, 512)) < 512 )
+ printf("read %d bytes less than 512B...\n", bytes_read);
+
+
+ return data;
+}
+
+
+void getlinsec(char *buf, int sector, int sector_cnt)
+{
+ int bytes_read;
+
+ if ( lseek(fd, sector*512, SEEK_SET) < 0 ) {
+ printf("seek file ext2.img error ....\n");
+ return;
+ }
+
+ if ( (bytes_read = read(fd, buf, 512*sector_cnt)) < 512*sector_cnt)
+ printf("read %d bytes less than %d bytes..\n",
+ bytes_read, 512 * sector_cnt);
+
+}
diff --git a/disklab.h b/disklab.h
new file mode 100644
index 0000000..b57bc7a
--- /dev/null
+++ b/disklab.h
@@ -0,0 +1,10 @@
+#ifndef _DISKLAB_H
+#defein _DISKLAB_H
+
+
+
+
+/* disk lab functions */
+void *getonesec(int);
+
+#endif /* disklab.h */
diff --git a/ext2.img b/ext2.img
new file mode 100644
index 0000000..81290df
--- /dev/null
+++ b/ext2.img
Binary files differ
diff --git a/ext2_fs.h b/ext2_fs.h
new file mode 100644
index 0000000..eb6b61a
--- /dev/null
+++ b/ext2_fs.h
@@ -0,0 +1,207 @@
+#ifndef __EXT2_FS_H
+#define __EXT2_FS_H
+
+#include "types.h"
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#define EXT2_GOOD_OLD_REV 0 // The good old (original) format
+#define EXT2_DYNAMIC_REV 1 // V2 format w/ dynamic inode sizes
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+// Special inode numbers
+#define EXT2_BAD_INO 1 // Bad blocks inode
+#define EXT2_ROOT_INO 2 // Root inode
+#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode
+#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode
+#define EXT3_RESIZE_INO 7 // Reserved group descriptors inode
+#define EXT3_JOURNAL_INO 8 // Journal inode
+
+// We're readonly, so we only care about incompat features.
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1)
+
+/*
+ * File types and file modes
+ */
+#define S_IFDIR 0040000 // Directory
+#define S_IFCHR 0020000 // Character device
+#define S_IFBLK 0060000 // Block device
+#define S_IFREG 0100000 // Regular file
+#define S_IFIFO 0010000 // FIFO
+#define S_IFLNK 0120000 // Symbolic link
+#define S_IFSOCK 0140000 // Socket
+
+#define S_IFSHIFT 12
+
+#define T_IFDIR (S_IFDIR >> S_IFSHIFT)
+#define T_IFCHR (S_IFCHR >> S_IFSHIFT)
+#define T_IFBLK (S_IFBLK >> S_IFSHIFT)
+#define T_IFREG (S_IFREG >> S_IFSHIFT)
+#define T_IFIFO (S_IFIFO >> S_IFSHIFT)
+#define T_IFLNK (S_IFLNK >> S_IFSHIFT)
+#define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
+
+
+
+#define ext2_group_desc_lg2size 5
+
+
+
+
+
+
+/*
+ * super block structure:
+ * include/linux/ext2_fs.h
+ */
+struct ext2_super_block
+{
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __u32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level;
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks;
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_super_block_size != 1024
+#error ext2_super_block definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+/*
+ * ext2 group desc structure:
+ */
+struct ext2_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_group_desc_size != 32
+#error ext2_group_desc definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+/*
+ * ext2 inode structure:
+ */
+struct ext2_inode
+{
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Owner Uid */
+ __u32 i_size; /* 4: Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* 12: Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* 20: Deletion Time */
+ __u16 i_gid; /* Group Id */
+ __u16 i_links_count; /* 24: Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* 32: File flags */
+ __u32 l_i_reserved1;
+ __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ __u32 i_version; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u32 l_i_reserved2[2];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_inode_size != 128
+#error ext2_inode definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry {
+ unsigned int d_inode; /* Inode number */
+ unsigned short d_rec_len; /* Directory entry length */
+ unsigned char d_name_len; /* Name length */
+ unsigned char d_file_type;
+ char d_name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*******************************************************************************
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+*******************************************************************************/
+
+
+
+
+/* function declartion */
+/*******************************************************************************
+extern struct open_file_t * ext2_read(char *);
+extern int ext2_read(struct open_file_t *, char *, int);
+*******************************************************************************/
+
+
+#endif /* ext2_fs.h */
diff --git a/extlinux.c b/extlinux.c
new file mode 100644
index 0000000..9a1039d
--- /dev/null
+++ b/extlinux.c
@@ -0,0 +1,704 @@
+/**
+ * extlinux.c
+ *
+ *
+ */
+#include "ext2_fs.h"
+#include "cache.h"
+#include "types.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * File structure, This holds the information for each currently open file
+ */
+struct open_file_t {
+ __u32 file_bytesleft; /* Number of bytes left ( 0 = free ) */
+ __u32 file_sector; /* Next linear sector to read */
+ __u32 file_in_sec; /* Sector where inode lives */
+ __u16 file_in_off;
+ __u16 file_mode;
+};
+
+/*
+ struct getc_file {
+ __u16 gc_file;
+ __u16 gc_bufbytes;
+ __u16 gc_bufdata;
+ __u8 gc_unget_cnt;
+ __u8 gc_unget_buf[9];
+ };
+*/
+struct getc_file {
+ struct open_file_t * gc_file; /* file pointer */
+ __u16 gc_bufbytes; /* Bytes left in buffer */
+ __u16 gc_bufdata; /* pointer to data in buffer */
+ __u8 gc_unget_cnt; /* Character pushed back count */
+ __u8 gc_unget_buf[7]; /* Character pushed back buffer */
+};
+
+
+
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX_ ( 1 << FILENAME_MAX_LG2 )
+
+#define LDLINUX_MAGIC 0x3eb202fex
+
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN ( 1 << MAX_OPEN_LG2 )
+
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE ( 1 << SECTOR_SHIFT )
+
+
+#define MAX_SYMLINKS 64
+#define SYMLINK_SECTORS 2
+
+#define ROOT_DIR_WORD 0x002F
+#define CUR_DIR_DWORD 0x0000002F2E
+
+
+
+
+#define MAX_GETC_LG2 4
+#define MAX_GETC ( 1 << MAX_GETC_LG2 )
+#define bytes_per_getc_lg2 ( 16 - MAX_GETC_LG2 )
+#define bytes_per_getc ( 1 << bytes_per_getc_lg2 )
+#define secs_per_getc ( bytes_per_getc / SECTOR_SIZE )
+#define MAX_UNGET 7
+
+#define getc_file_lg2 4
+#define getc_file_size ( 1 << getc_file_lg2 )
+
+char GetCStack[getc_file_size * MAX_GETC] = {0,};
+__u32 CurrentGetC = (__u32) &GetCStack[getc_file_size * MAX_GETC];
+
+
+
+extern struct ext2_super_block sb;
+
+struct ext2_inode ThisInode;
+struct open_file_t Files[MAX_OPEN];
+
+
+__u32 ClustBytesShift, ClustSize, ClustShift;
+__u32 SecPerClust, ClustMask;
+__u32 PtrsPerBlock1, PtrsPerBlock2;
+
+/* a static value, which is the boot/extlinux's inode number */
+__u32 CurrentDir = 13;
+
+
+
+
+
+/**
+ * strecpy:
+ *
+ * just like the function strcpy(), except it returns non-zero if overflow.
+ *
+ * well, in Syslinux, strcpy() will advance both the dst and src string pointer.
+ *
+ */
+int strecpy(char *dst, char *src, char *end)
+{
+ while ( *src != '\0' )
+ *dst++ = *src++;
+ *dst = '\0';
+
+ if ( dst > end )
+ return 1;
+ else
+ return 0;
+}
+
+
+
+
+
+
+/*
+ * 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);
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
+{
+ return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
+}
+
+
+
+/**
+ * allocate_file:
+ *
+ * Allocate a file structure
+ *
+ * @return: if successful return the file pointer, or return NULL
+ *
+ */
+struct open_file_t *allocate_file()
+{
+ struct open_file_t *file;
+ int i = 0;
+
+ file = Files;
+
+ for (; i < MAX_OPEN; i ++ ) {
+ if ( file->file_bytesleft == 0 ) /* find it */
+ return file;
+ file ++;
+ }
+}
+
+
+/**
+ * getlinsec_ext:
+ *
+ * same as getlinsec, except load any sector from the zero
+ * block as all zeros; use to load any data derived from
+ * n ext2 block pointer, i.e. anything *except the superblock
+ *
+ */
+void getlinsec_ext(char *buf, int sector, int sector_cnt)
+{
+ int ext_cnt = 0;
+
+ if ( sector < SecPerClust ) {
+ ext_cnt = SecPerClust - sector;
+ memset(buf, 0, ext_cnt << SECTOR_SHIFT);
+ buf += ext_cnt << SECTOR_SHIFT;
+ }
+
+ sector += ext_cnt;
+ sector_cnt -= ext_cnt;
+ getlinsec(buf, sector, sector_cnt);
+
+
+}
+
+void getonesec_ext(char *buf, int sector)
+{
+ getlinsec_ext(buf, sector, 1);
+}
+
+
+
+/**
+ * open_inode:
+ *
+ * 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
+ *
+ */
+struct open_file_t * open_inode(unsigned int inr, __u32 *file_len)
+{
+ struct open_file_t *file;
+ struct ext2_group_desc *desc;
+ struct cache_struct *cs;
+
+ __u32 inode_group, inode_offset;
+ __u32 block_num, block_off;
+ __u32 sector_num, sector_off;
+
+
+ file = allocate_file();
+ if ( !file )
+ return NULL;
+
+ file->file_sector = 0;
+
+ inr --;
+ inode_group = inr / sb.s_inodes_per_group;
+ inode_offset = inr % sb.s_inodes_per_group;
+
+ /* get bytes offset in desc table */
+ inode_group <<= ext2_group_desc_lg2size;
+ block_num = inode_group / ClustSize;
+ block_off = inode_group % ClustSize;
+ /* finally we get the real block number where the desc stores */
+ block_num += sb.s_first_data_block + 1;
+
+ /* compute the sector number where the group descriptor stores */
+ sector_num = (block_num << ClustShift) + (block_off >> SECTOR_SHIFT);
+ sector_off = block_off & (SECTOR_SIZE - 1 );
+
+ cs = get_cache_sector(sector_num);
+ desc = (struct ext2_group_desc *)(cs->data + sector_off); /* got the group desc */
+
+
+ /* get the inode bytes offset in the inode table */
+ inode_offset *= sb.s_inode_size;
+ block_num = (inode_offset / ClustSize) + (desc->bg_inode_table);
+ block_off = inode_offset % ClustSize;
+
+ /* compute the sector number where the inode structure stores */
+ sector_num = (block_num << ClustShift) + (block_off >> SECTOR_SHIFT);
+ sector_off = block_off & (SECTOR_SIZE - 1);
+
+ file->file_in_sec = sector_num;
+ file->file_in_off = sector_off;
+
+ cs = get_cache_sector(sector_num);
+ memcpy(&ThisInode, cs->data + sector_off, EXT2_GOOD_OLD_INODE_SIZE);
+
+ file->file_mode = ThisInode.i_mode;
+ *file_len = file->file_bytesleft = ThisInode.i_size;
+
+ if ( *file_len == 0 )
+ return NULL;
+
+ return file;
+}
+
+
+/**
+ * close_file:
+ *
+ * Deallocates a file structure point by FILE
+ *
+ * @param: file, the file structure we want deallocate
+ *
+ */
+void close_file(struct open_file_t *file)
+{
+ if ( file == NULL )
+ return;
+
+ file->file_bytesleft = 0;
+
+}
+
+
+
+/**
+ * linsector:
+ *
+ * Convert a linear sector index in a file to linear sector number
+ *
+ * @param: line_sector, the linear sector number
+ * @param: file, the pointer to open_file_t structure
+ *
+ * @return: the linear sector number, aka, the physic sector number
+ */
+__u32 linsector(__u32 lin_sector, struct open_file_t *file)
+{
+
+
+ struct cache_struct *cs;
+ struct ext2_inode *inode;
+
+ __u32 sector;
+ __u32 the_block; /* the block we are in now */
+ __u32 next_block;
+ __u32 block = lin_sector >> ClustShift;
+ __u32 offset; /* the offset of sector where block number stores */
+
+ cs = get_cache_sector(file->file_in_sec);
+ inode = (struct ext2_inode *)((__u32)cs->data + file->file_in_off);
+
+ offset = (char *)&inode->i_block[block] - (char *)cs->data;
+ if ( block < EXT2_NDIR_BLOCKS )
+ goto direct;
+
+ offset = (char *)&inode->i_block[EXT2_IND_BLOCK] - (char *)cs->data;
+ block -= EXT2_NDIR_BLOCKS;
+ if ( block < PtrsPerBlock1 )
+ goto ind1;
+
+ offset = (char *)&inode->i_block[EXT2_DIND_BLOCK] - (char *)cs->data;
+ block -= PtrsPerBlock1;
+ if ( block < PtrsPerBlock2 )
+ goto ind2;
+
+ offset = (char *)&inode->i_block[EXT2_TIND_BLOCK] - (char *)cs->data;
+ block -= PtrsPerBlock2;
+
+ ind3:
+ the_block = block / PtrsPerBlock2;
+ next_block = block % PtrsPerBlock2;
+
+ sector = (*(__u32 *)(cs->data + offset) << ClustShift)
+ +(the_block >> (SECTOR_SHIFT - 2));
+ cs = get_cache_sector(sector);
+
+ offset = ( the_block & (SECTOR_SIZE >> 2) - 1 ) << 2;
+ block = next_block;
+
+ ind2:
+ the_block = block / PtrsPerBlock1;
+ next_block = block % PtrsPerBlock1;
+
+ sector = (*(__u32*)(cs->data + offset) << ClustShift)
+ +(the_block >> (SECTOR_SHIFT - 2));
+ cs = get_cache_sector(sector);
+ offset = ( the_block & (SECTOR_SIZE >> 2) - 1) << 2;
+ block = next_block;
+
+ ind1:
+ sector = (*(__u32*)(cs->data + offset) << ClustShift)
+ +(block >> (SECTOR_SHIFT - 2));
+ cs = get_cache_sector(sector);
+ offset = ( block & (SECTOR_SIZE >> 2) - 1) << 2;
+
+ direct:
+ sector = (*(__u32*)(cs->data + offset) << ClustShift)
+ +(lin_sector & ClustMask);
+
+ return sector;
+}
+
+
+
+
+
+/**
+ * getfssec:
+ *
+ * Get multiple sectors from a file
+ *
+ * same as above, execpt si is a pointer to a open_file_t
+ *
+ * @param: ES:BX ----> buffer
+ * @param: DS:SI ----> pointer to open_file_t
+ * @param: cx ----> sector count ( 0xffff = until end of file )
+ *
+ * @return: ecx = number of bytes read
+ *
+ */
+int getfssec(char *buf, struct open_file_t *file, int sectors, int *have_more)
+{
+ int sector_left, next_sector, sector_idx;
+ int frag_start, con_sec_cnt;
+ int bytes_read = sectors << SECTOR_SHIFT;
+
+
+ if ( file->file_bytesleft <= 0)
+ return 0;
+
+ sector_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+ if ( sectors > sector_left )
+ sectors = sector_left;
+
+ getfragment:
+ sector_idx = file->file_sector;
+ next_sector = frag_start = linsector(sector_idx, file);
+ con_sec_cnt = 0;
+
+ getseccnt:
+ do {
+ con_sec_cnt ++;
+ sectors --;
+ if ( sectors == 0 )
+ break;
+
+ /***
+ * well, in Syslinux that means in real mode, there's a
+ * 64k block limit, so we should need handle it here.
+ *
+ * But it's a user program that test the driver, so we
+ * don't need to do this here but should remember do it
+ * when we move into Sylinux.
+ */
+ sector_idx ++;
+ next_sector ++;
+ }while( next_sector == linsector(sector_idx, file) );
+
+
+ do_read:
+ /* Debug message */
+#if 0
+ printf("/**********************************************************\n");
+ printf(" the file you are reading stores at sector --0x%x--0x%x\n",
+ frag_start, frag_start + con_sec_cnt -1);
+ printf("**********************************************************/\n");
+#endif
+
+ getlinsec_ext(buf, frag_start, con_sec_cnt);
+ buf += con_sec_cnt << 9;
+ file->file_sector += con_sec_cnt; /* next sector index */
+
+ if ( sectors )
+ goto getfragment;
+ done:
+ if ( bytes_read >= file->file_bytesleft ) {
+ bytes_read = file->file_bytesleft;
+ close_file(file);
+ *have_more = 0;
+ return bytes_read;
+ }
+
+ file->file_bytesleft -= bytes_read;
+ *have_more = 1;
+
+ return bytes_read;
+}
+
+
+
+
+
+
+/**
+ * searchdir:
+ *
+ * Search the root directory for a pre-mangle filename in FILENAME.
+ *
+ * @param: filename, the filename we want to search.
+ *
+ * @out : a file pointer
+ * @out : file lenght in bytes
+ *
+ */
+struct open_file_t* searchdir(char * filename, __u32 *file_len)
+{
+ struct open_file_t *file;
+ struct ext2_dir_entry *de;
+ __u8 file_mode;
+ __u8 SymlinkCtr = MAX_SYMLINKS;
+
+
+ __u32 have_more;
+ __u32 inr = CurrentDir;
+ __u32 ThisDir;
+ __u32 EndBlock;
+
+ int flag;
+ int trackbufsize = 8192;
+ char trackbuf[trackbufsize];
+
+ char SymlinkBuf[SYMLINK_SECTORS * SECTOR_SIZE + 64];
+ char *SymlinkTmpBuf = trackbuf;
+ char *lnk_end;
+ char *SymlinkTmpBufEnd = trackbuf + SYMLINK_SECTORS * SECTOR_SIZE+64;
+
+
+
+ begin_path:
+ while ( *filename == '/' ) { /* Absolute filename */
+ inr = EXT2_ROOT_INO;
+ filename ++;
+ }
+ open:
+ if ( (file = open_inode(inr, file_len) ) == NULL )
+ goto done; /* if error, done */
+
+ file_mode = 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 ++;
+
+ EndBlock = (__u32 )trackbuf + (SecPerClust << SECTOR_SHIFT);
+ readdir:
+ /* read a clust at a time */
+ getfssec(trackbuf, file, SecPerClust, &have_more);
+
+
+ de = (struct ext2_dir_entry *)trackbuf;
+
+ getent:
+ while ( 1 ) {
+ if ( (char *)de >= (char *)EndBlock ) {
+ if (have_more)
+ goto readdir;
+ else
+ goto err;
+ }
+
+ /* Zero inode == void entry */
+ if ( de->d_inode == 0 ) {
+ de = ext2_next_entry(de);
+ continue;
+ }
+
+ if ( ext2_match_entry (filename, de) ) {
+ inr = de->d_inode;
+ filename += de->d_name_len;
+ if ( *filename == 0 )
+ goto finish;
+ if ( *filename != '/' ) {
+ /* not match, try next */
+ de = ext2_next_entry(de);
+ filename -= de->d_name_len;
+ continue;
+ }
+ finish:
+ close_file(file);
+ goto open;
+ }
+
+ de = ext2_next_entry(de);
+ }
+ }
+
+
+ /*
+ * 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 ) /* too many links */
+ goto err;
+ if ( *file_len >= SYMLINK_SECTORS * SECTOR_SIZE )
+ goto err; /* Symlink too long */
+
+ flag = ThisInode.i_file_acl ? 1 : 0;
+
+ if ( ThisInode.i_blocks == flag ) { /* fast symlink */
+
+ close_file(file); /* we've got all we need */
+ memcpy(SymlinkTmpBuf, ThisInode.i_block, *file_len);
+ lnk_end = SymlinkTmpBuf + *file_len;
+
+ } else { /* slow symlink */
+ getfssec(SymlinkTmpBuf, file, SYMLINK_SECTORS, &have_more);
+ lnk_end = SymlinkTmpBuf + *file_len;
+
+ }
+ symlink_finish:
+ /*
+ * well, this happens like:
+ * "/boot/xxx/y/z.abc" where xxx is a symlink to "/other/here"
+ * so, we should get a new name like:
+ * "/other/here/y/z.abc"
+ */
+ if ( *filename != 0 )
+ *lnk_end++ = '/';
+ no_slash:
+ if ( strecpy(lnk_end, filename, SymlinkTmpBufEnd) )
+ goto err_noclose; /* buffer overflow */
+
+ /*
+ * 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);
+ inr = ThisDir;
+ filename = SymlinkBuf;
+ goto begin_path; /* we got a new path, so search it again */
+ }
+
+ /* Otherwise, something bad ... */
+ err:
+ close_file(file);
+ err_noclose:
+ *file_len = 0;
+ file = NULL;
+ done:
+ return file;
+}
+
+
+
+
+
+
+
+/**
+ * open:
+ *
+ * open the file
+ *
+ * @param: filename
+ *
+ * @return: return 1 one successful, or 0
+ *
+ */
+struct open_file_t* ext2_open(char *filename)
+{
+ struct open_file_t *file;
+ struct getc_file *gc_file;
+ int file_len;
+
+ file = searchdir(filename, &file_len);
+ if ( !file )
+ return NULL;
+
+ CurrentGetC -= getc_file_size;
+ if ( (char *)CurrentGetC < GetCStack ) { /* Stack full */
+ close_file(file);
+ return NULL;
+ }
+
+ gc_file = (struct getc_file *) CurrentGetC;
+ gc_file->gc_file = file;
+ gc_file->gc_bufbytes = 0;
+ gc_file->gc_unget_cnt = 0;
+
+ return file;
+}
+
+
+/**
+ * read function:
+ * return the bytes read
+ */
+int ext2_read(struct open_file_t *file, char *buf, int size, int *have_more)
+{
+
+ int sector = (size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+ return getfssec(buf, file, sector, have_more);
+
+}
+
+/**
+ * init. the fs meta data
+ */
+void init_fs(struct ext2_super_block *sb)
+{
+
+ /* read the super block */
+ getlinsec(sb, 2, 2);
+
+ ClustBytesShift = sb->s_log_block_size + 10;
+ ClustSize = 1 << ClustBytesShift;
+ ClustShift = ClustBytesShift - SECTOR_SHIFT;
+
+ SecPerClust = ClustSize >> SECTOR_SHIFT;
+ ClustMask = SecPerClust - 1;
+
+ PtrsPerBlock1 = 1 << (ClustBytesShift - 2 );
+ PtrsPerBlock2 = 1 << ( (ClustBytesShift - 2) * 2);
+}
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..3dbcfa2
--- /dev/null
+++ b/main.c
@@ -0,0 +1,144 @@
+/**
+ * This is just a test program, it does nothing but just
+ * init the cache first then use get_cache_sector to test
+ * the LRU algorithm with 12 fake-sector number.
+ *
+ * And it work well here
+ *
+ */
+#include <stdio.h>
+#include "cache.h"
+#include "ext2_fs.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+
+struct ext2_super_block sb;
+
+int fd;
+
+extern struct cache_struct cache[CACHE_ENTRIES + 1];
+
+
+/**
+ * Just print the sector, and according the LRU algorithm,
+ * Left most value is the most least secotr, and Right most
+ * value is the most Recent sector. I see it's a Left Right Used
+ * (LRU) algorithm; Just kidding:)
+ */
+void print_cache(void)
+{
+ int i = 0;
+ struct cache_struct *cs = cache;
+ for (; i < CACHE_ENTRIES; i++) {
+ cs = cs->next;
+ printf("%d ", cs->sector);
+ }
+
+ printf("\n");
+}
+
+
+/* test function */
+void print_hex(char *data, int size)
+{
+ int i = 0;
+ while ( size --) {
+
+ if ( (i != 0) && (i % 16 == 0) )
+ printf("\n");
+ i ++;
+
+ if ( (*data < 0x20 ) || (*data > 0x80 ) ) {
+ printf(".");
+ data ++;
+ continue;
+ }
+ putc(*data, stdout);
+ data++;
+
+ }
+ printf("\n");
+}
+
+
+void usage(void)
+{
+ printf("USAGE: a.out ext2fs.img filename\n");
+ printf("---- ext2fs.img means a ext2 filesytem image\n");
+ printf("---- filename menas the file you wanna open, it can be \n");
+ printf(" in one of the two following forms:\n");
+ printf(" /file/name/xy.y, this is a full name, or \n");
+ printf(" file/name/xy.z, in this case, the program will search\n");
+ printf(" from the directory where the extlinux.sys stored\n");
+
+}
+
+
+
+
+/**
+ * well, it's just a test program that test if the fs driver
+ * would work on ext2/3(ext4 not added for now) filesystem
+ * well or not. so it's task is simple,too: open the ext2fs,
+ * then read what you want.
+ *
+ */
+int main(int argc, char *argv[])
+{
+
+ int bytes_read = 0;
+ int total_bytes = 0;
+ int have_more;
+ char *ext2fs = argv[1];
+ char *filename = argv[2];
+ char buf[1024];
+ struct cache_struct *cs;
+ struct open_file_t *file = NULL;
+
+
+ if (argc != 3 ) {
+ usage();
+ return 0;
+ }
+
+ /* init. the cache */
+ cache_init();
+
+
+ fd = open(ext2fs, O_RDONLY);
+ if ( fd < 0 ) {
+ printf("File %s open error....\n", ext2fs);
+ return 0;
+ }
+
+ init_fs(&sb);
+
+ file = (struct open_file_t *)ext2_open(filename);
+ if ( ! file ) {
+ printf("open file error: file %s not found ....\n", filename);
+ close(fd);
+ return 0;
+ }
+
+ /*
+ * The following message may be nosiy, but it told we how is it
+ * going well.
+ */
+ do {
+ bytes_read = ext2_read(file, buf, 1024, &have_more);
+ printf("--------read %d bytes-------\n", bytes_read);
+ printf("----------------\n");
+ print_hex(buf, bytes_read);
+
+ total_bytes += bytes_read;
+ }while(have_more);
+
+ printf("-------------total read %d bytes------\n", total_bytes);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/types.h b/types.h
new file mode 100644
index 0000000..79de0bd
--- /dev/null
+++ b/types.h
@@ -0,0 +1,17 @@
+#ifndef _TYPES_H
+#define _TYPES_H
+
+
+typedef unsigned int __u32;
+typedef unsigned short __u16;
+typedef unsigned char __u8;
+
+
+typedef int __s32;
+typedef short __s16;
+typedef char __s8;
+
+
+
+
+#endif /* types.h */