diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 45 | ||||
-rwxr-xr-x | a.out | bin | 0 -> 27449 bytes | |||
-rw-r--r-- | cache.c | 97 | ||||
-rw-r--r-- | cache.h | 30 | ||||
-rw-r--r-- | disklab.c | 41 | ||||
-rw-r--r-- | disklab.h | 10 | ||||
-rw-r--r-- | ext2.img | bin | 0 -> 1474560 bytes | |||
-rw-r--r-- | ext2_fs.h | 207 | ||||
-rw-r--r-- | extlinux.c | 704 | ||||
-rw-r--r-- | main.c | 144 | ||||
-rw-r--r-- | types.h | 17 |
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 @@ -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 Binary files differ@@ -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; +} @@ -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 Binary files differnew file mode 100644 index 0000000..81290df --- /dev/null +++ b/ext2.img 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); +} + @@ -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; +} @@ -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 */ |