aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-05-20 07:29:41 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-05-20 07:29:41 +0800
commit5bc175c2405a9c001882746eb77d9dcc88f62000 (patch)
treea1557b069c1deb2cea4e77634a6420a0ec288fa3
parent15bbff8d71dadc14b606a4731e6f2ca283cb8061 (diff)
parent7ae9080b65998c402cee3268161035d7c7afa7cd (diff)
downloaddevel-5bc175c2405a9c001882746eb77d9dcc88f62000.tar.gz
devel-5bc175c2405a9c001882746eb77d9dcc88f62000.tar.xz
devel-5bc175c2405a9c001882746eb77d9dcc88f62000.zip
Merge branch 'ldlinux'
-rw-r--r--Makefile12
-rw-r--r--disklab.c7
-rw-r--r--fat_fs.h111
-rw-r--r--ldlinux.c902
4 files changed, 1026 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 30c89bc..097a2c4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,10 @@
-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
+all:extlinux syslinux
+
+
+extlinux:cache.h disklab.h ext2_fs.h
+ gcc -g cache.c main.c disklab.c extlinux.c -o extlinux
+
+syslinux:cache.h disklab.h fat_fs.h
+ gcc -g main.c cache.c disklab.c ldlinux.c -o syslinux
clean:
- (rm -f *~ *.o) \ No newline at end of file
+ (rm -f *~ *.o syslinux) \ No newline at end of file
diff --git a/disklab.c b/disklab.c
index c0673ef..a30998f 100644
--- a/disklab.c
+++ b/disklab.c
@@ -21,7 +21,8 @@ void* getoneblk(__u32 block)
buf = malloc(blk_size);
if ( (bytes_read = read(fd, buf, blk_size)) < blk_size )
- printf("read %d bytes less than %dB..\n", bytes_read, blk_size);
+ printf("%s:%s: read %d bytes less than %dB..\n",
+ __FILE__, __FUNCTION__, bytes_read, blk_size);
return buf;
}
@@ -37,7 +38,7 @@ void getlinsec(char *buf, int sector, int sector_cnt)
}
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);
+ printf("%s:%s: read %d bytes less than %d bytes..\n",
+ __FILE__, __FUNCTION__, bytes_read, 512 * sector_cnt);
}
diff --git a/fat_fs.h b/fat_fs.h
new file mode 100644
index 0000000..a15bd82
--- /dev/null
+++ b/fat_fs.h
@@ -0,0 +1,111 @@
+#ifndef _FAT_FS_H
+#define _FAT_FS_H
+
+#include "types.h"
+
+
+#define FAT_DIR_ENTRY_SIZE 32
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+
+#define FAT_MAXFILE 256
+
+#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_VOLUME_ID)
+
+#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_DIRECTORY \
+ | FAT_ATTR_ARCHIVE)
+
+/*
+ * The fat file system structures
+ */
+
+struct fat_bpb {
+ __u8 jmp_boot[3];
+ __u8 oem_name[8];
+ __u16 sector_size;
+ __u8 bxSecPerClust;
+ __u16 bxResSectors;
+ __u8 bxFATs;
+ __u16 bxRootDirEnts;
+ __u16 bxSectors;
+ __u8 media;
+ __u16 bxFATsecs;
+ __u16 sectors_per_track;
+ __u16 num_heads;
+ __u32 num_hidden_sectors;
+ __u32 bsHugeSectors;
+
+ union {
+ struct {
+ __u8 num_ph_drive;
+ __u8 reserved;
+ __u8 boot_sig;
+ __u32 num_serial;
+ __u8 label[11];
+ __u8 fstype[8];
+ } __attribute__ ((packed)) fat12_16;
+
+ struct {
+ __u32 bxFATsecs_32;
+ __u16 extended_flags;
+ __u16 fs_version;
+ __u32 root_cluster;
+ __u16 fs_info;
+ __u16 backup_boot_sector;
+ __u8 reserved[12];
+ __u8 num_ph_drive;
+ __u8 reserved1;
+ __u8 boot_sig;
+ __u32 num_serial;
+ __u8 label[11];
+ __u8 fstype[8];
+ } __attribute__ ((packed)) fat32;
+
+ } __attribute__ ((packed)) u;
+
+} __attribute__ ((packed));
+
+
+
+struct fat_dir_entry {
+ __u8 name[11];
+ __u8 attr;
+ __u8 nt_reserved;
+ __u8 c_time_tenth;
+ __u16 c_time;
+ __u16 c_date;
+ __u16 a_date;
+ __u16 first_cluster_high;
+ __u16 w_time;
+ __u16 w_date;
+ __u16 first_cluster_low;
+ __u32 file_size;
+} __attribute__ ((packed));
+
+
+
+struct fat_long_name_entry {
+ __u8 id;
+ __u16 name1[5];
+ __u8 attr;
+ __u8 reserved;
+ __u8 checksum;
+ __u16 name2[6];
+ __u16 first_cluster;
+ __u16 name3[2];
+} __attribute__ ((packed));
+
+
+
+#endif /* fat_fs.h */
diff --git a/ldlinux.c b/ldlinux.c
new file mode 100644
index 0000000..4e4f776
--- /dev/null
+++ b/ldlinux.c
@@ -0,0 +1,902 @@
+#include "fat_fs.h"
+#include "cache.h"
+#include "disklab.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+
+/* some generic defines */
+#define FILENAME_MAX_LG2 6
+#define FILENAME_MAX_ ( 1 << FILENAME_MAX_LG2 )
+#define NULLFILE 0
+#define NULLOFFSET 0
+#define retry_count 16
+#define LDLINUX_MAGIC 0x3eb202fe
+
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN ( 1 << MAX_OPEN_LG2 )
+
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE ( 1 << SECTOR_SHIFT )
+
+#define DIRENT_SHIFT 5
+#define DIRENT_SIZE ( 1 << DIRENT_SHIFT )
+
+#define ROOT_DIR_WORD 0x002f
+
+enum fat_type{ FAT12, FAT16, FAT32 };
+__u8 FATType;
+
+
+/* generic information about FAT fs */
+
+__u32 FAT; /* Location of (first) FAT */
+__u32 RootDirArea; /* Location of root directory area */
+__u32 RootDir; /* Location of root directory proper */
+__u32 DataArea; /* Location of data area */
+__u32 TotalSectors; /* Total number of sectors */
+__u32 ClustSize; /* Bytes/cluster */
+__u32 ClustMask; /* Sector/cluster - 1 */
+__u8 CopySuper; /* Distinguish .bs versus .bss */
+__u8 DriveNumber; /* BIOS drive number */
+__u8 ClustShift; /* Shift count for sectors/cluster */
+__u8 ClustByteShift; /* Shift count for bytes/cluster */
+
+/* for SYSLINUX, the block size equal to the sector size */
+__u32 blk_size = 1 << SECTOR_SHIFT;
+
+/* used for long name dir entry */
+char *NameStart;
+int NameLen;
+
+
+/* file structure. This holds the information for each currently open file */
+struct open_file_t {
+ __u32 file_sector; /* sector pointer ( 0 = structure free ) */
+ __u32 file_bytesleft; /* number of bytes left */
+ __u32 file_left; /* number of sectors left */
+ __u32 pad; /* padding */
+};
+
+struct open_file_t Files[MAX_OPEN];
+
+#define trackbufsize 8192
+char trackbuf[trackbufsize];
+
+char MangleBuf[12];
+
+
+/* the fat bpb data */
+struct fat_bpb fat;
+
+
+
+
+/**
+ * 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_sector == 0 ) /* found it */
+ return file;
+ file ++;
+ }
+
+ return NULL; /* not found */
+}
+
+
+/**
+ * alloc_fill_dir:
+ *
+ * Allocate then fill a file structure for a directory starting in
+ * sector SECTOR. if successful, return the pointer of filled file
+ * structure, or return NULL.
+ *
+ */
+struct open_file_t* alloc_fill_dir(__u32 sector)
+{
+ struct open_file_t *file;
+
+ file = allocate_file();
+ if ( !file )
+ return NULL;
+
+ file->file_sector = sector; /* current sector */
+ file->file_bytesleft = 0; /* current offset */
+ file->file_left = sector; /* beginning sector */
+
+ return file;
+}
+
+
+/* Deallocates a file structure */
+void close_file(struct open_file_t *file)
+{
+ if ( file )
+ file->file_sector = 0;
+}
+
+
+
+/* Deallocates a directory structure */
+void close_dir(struct fat_dir_entry *dir)
+{
+ if ( dir )
+ *(__u32*)dir = 0;
+}
+
+
+
+
+
+/**
+ * getfatsector:
+ *
+ * check for a particular sector in the FAT cache.
+ *
+ */
+struct cache_struct *getfatsector(__u32 sector)
+{
+ return get_cache_block(FAT + sector);
+}
+
+
+/**
+ * nextcluster:
+ *
+ * Advance a cluster pointer in clust_num to the next cluster
+ * pointer at in the FAT tables. CF = 0 on return if end of file.
+ *
+ * @param: clust_num;
+ *
+ * @return: the next cluster number
+ *
+ */
+__u32 nextcluster(__u32 clust_num)
+{
+ __u32 next_cluster;
+ __u32 fat_sector;
+ struct cache_struct *cs;
+
+#if FATType == FAT12
+ int offset;
+ int lo, hi;
+#endif
+
+ switch(FATType) {
+ case FAT12:
+ fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT;
+ cs = getfatsector(fat_sector);
+ offset = (clust_num * 3 / 2) & ( SECTOR_SIZE -1 );
+ if ( offset == 0x1ff ) {
+ /*
+ * we got the end of the one fat sector,
+ * but we don't got we have(just one byte, we need two),
+ * so store the low part, then read the next fat
+ * sector, read the high part, then combine it.
+ */
+ lo = *(__u8 *)(cs->data + offset);
+ cs = getfatsector(fat_sector + 1);
+ hi = *(__u8 *)cs->data;
+ next_cluster = (hi << 8) + lo;
+ } else
+ next_cluster = *(__u16 *)(cs->data + offset);
+
+ if ( clust_num & 0x0001 )
+ next_cluster >>= 4; /* cluster number is ODD */
+ else
+ next_cluster &= 0x0fff; /* cluster number is EVEN */
+ if ( next_cluster > 0x0ff0 )
+ goto fail;
+ break;
+
+ case FAT16:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 2);
+ cs = getfatsector(fat_sector);
+ next_cluster = ((__u16 *)cs->data)[clust_num];
+ if ( next_cluster > 0xfff0 )
+ goto fail;
+ break;
+
+ case FAT32:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 2);
+ cs = getfatsector(fat_sector);
+ next_cluster = ((__u32 *)cs->data)[clust_num] & 0x0fffffff;
+ if ( next_cluster > 0x0ffffff0 )
+ goto fail;
+ break;
+ }
+
+ return next_cluster;
+
+ fail: /* got an unexcepted cluster number, so return ZERO */
+ return 0;
+}
+
+
+
+/**
+ * nextsector:
+ *
+ * given a sector on input, return the next sector of the
+ * same filesystem object, which may be the root directory or a
+ * cluster chain. Returns EOF.
+ *
+ */
+__u32 nextsector(__u32 sector)
+{
+
+ __u32 data_sector;
+ __u32 cluster;
+
+ if ( sector < DataArea ) {
+ sector ++;
+ /* if we reached the end of root area */
+ if ( sector == DataArea )
+ sector = 0; /* return 0 */
+ return sector;
+ }
+
+
+ data_sector = sector - DataArea;
+ if ( !data_sector & ClustMask ) /* in a cluster */
+ return (++sector);
+
+ /* got a new cluster */
+ cluster = nextcluster( (data_sector >> ClustShift) + 2 );
+ if ( !cluster )
+ return 0;
+
+ /* return the start of the new cluster */
+ sector = ( (cluster - 2) << ClustShift ) + DataArea;
+ return sector;
+ }
+
+
+
+
+
+/**
+ * __getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ * This routine makes sure the subransfers do not cross a 64K boundary
+ * and will correct the situation if it does, UNLESS *sectos* cross
+ * 64K boundaries.
+ *
+ * @param: buf
+ * @param: file structure
+ * @param: sectors
+ *
+ */
+void __getfssec(char *buf, struct open_file_t *file, __u32 sectors)
+{
+ __u32 curr_sector = file->file_sector;
+ __u32 frag_start , next_sector;
+ __u32 con_sec_cnt;
+
+ do {
+ /* get fragment */
+ con_sec_cnt = 0;
+ frag_start = curr_sector;
+
+ do {
+ /* get consective sector count */
+ con_sec_cnt ++;
+ sectors --;
+ if ( sectors == 0 )
+ break;
+
+ next_sector = nextsector(curr_sector);
+ if ( !next_sector )
+ break;
+ }while( next_sector == (++curr_sector) );
+
+#if 1 /* Debug message */
+ printf("/**************************************************\n");
+ printf("You are reading stores at sector --0x%x--0x%x\n",
+ frag_start, frag_start + con_sec_cnt -1);
+ printf("**************************************************/\n");
+#endif
+
+ /* do read */
+ getlinsec(buf, frag_start, con_sec_cnt);
+ buf += con_sec_cnt << 9;/* adjust buffer pointer */
+
+ if ( !sectors )
+ break;
+ //curr_sector --; /* this is the last sector actually read */
+ curr_sector = next_sector;
+ }while( sectors );
+
+ /* update the file_sector filed for the next read */
+ file->file_sector = nextsector(curr_sector);
+
+}
+
+
+
+/**
+ * getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ *
+ * @param: buf
+ * @param: file
+ * @param: sectors
+ * @param: have_more
+ *
+ * @return: number of bytes read
+ *
+ */
+__u32 getfssec(char *buf, struct open_file_t *file, __u32 sectors, int *have_more)
+{
+ __u32 bytes_read = sectors << SECTOR_SHIFT;
+
+ if ( sectors > file->file_left )
+ sectors = file->file_left;
+
+ __getfssec(buf, file, sectors);
+
+ if ( bytes_read >= file->file_bytesleft ) {
+ bytes_read = file->file_bytesleft;
+ file->file_bytesleft = 0;
+ *have_more = 0;
+ close_file(file);
+
+ } else {
+ file->file_bytesleft -= bytes_read;
+ *have_more = 1;
+ }
+
+ file->file_left -= sectors;
+
+ return bytes_read;
+}
+
+
+
+
+
+
+
+
+
+/**
+ * mangle_dos_name:
+ *
+ * Mangle a dos filename component pointed to by FILENAME
+ * into MangleBuf; ends on encountering any whitespace or
+ * slash.
+ *
+ * WARNING: saves pointers into the buffer for longname matchs!
+ *
+ * @param: filename
+ * @param: MangleBuf
+ *
+ */
+/**
+ * for now, it can't handle this case:
+ * xyxzxyxjfdkfjdjf.txt as it will just output the first 11 chars
+ * but not care the dot char at the later, so I think we need do
+ * this, but it seems that the SYSLINUX doesn't do it, so I will
+ * make it stay as what it was orignal.
+ *
+ */
+void mangle_dos_name(char *MangleBuf, char *filename)
+{
+
+ char *dst = MangleBuf;
+ char *src = filename;
+ char c;
+ int i = 0;
+
+ NameStart = filename;
+
+ for (; i < 11; i ++)
+ MangleBuf[i] = ' ';
+
+ for (i = 0; i < 11; i++) {
+ c = *src ++;
+
+ if ( (c <= ' ') || (c == '/') )
+ break;
+
+
+ if ( c == '.' ) {
+ dst = &MangleBuf[8];
+ i = 7;
+ continue;
+ }
+
+ if (c >= 'a' && c <= 'z')
+ c -= 32;
+ if ( (c == 0xe5) && (i == 11) )
+ c = 0x05;
+
+ *dst++ = c;
+ }
+ MangleBuf[12] = '\0';
+
+ while( (*src != '/') && (*src > ' ') )
+ src ++;
+
+ NameLen = src - filename;
+}
+
+
+char entry_name[13];
+
+
+void unicode_to_ascii(char *entry_name, __u16 *unicode_buf)
+{
+ int i = 0;
+
+ for (; i < 13; i++) {
+ if ( unicode_buf[i] == 0xffff ) {
+ entry_name[i] = '\0';
+ return;
+ }
+ entry_name[i] = (char)unicode_buf[i];
+ }
+}
+
+/**
+ * long_entry_name:
+ *
+ * get the long entry name
+ *
+ */
+void long_entry_name(struct fat_long_name_entry *dir)
+{
+ int id = dir->id & 0x3f;
+ __u16 unicode_buf[13];
+
+ memcpy(unicode_buf, dir->name1, 5 * 2);
+ memcpy(unicode_buf + 5, dir->name2, 6 * 2);
+ memcpy(unicode_buf + 11,dir->name3, 2 * 2);
+
+ unicode_to_ascii(entry_name, unicode_buf);
+
+}
+
+
+__u8 get_checksum(char *dir_name)
+{
+ int i;
+ __u8 sum=0;
+
+ for (i=11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++;
+ return sum;
+}
+
+__u32 first_sector(struct fat_dir_entry *dir)
+{
+ __u32 first_clust, sector;
+
+ first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
+ sector = ((first_clust - 2) << ClustShift) + DataArea;
+
+ return sector;
+}
+
+
+
+
+/**
+ * search_dos_dir:
+ *
+ * search a specific directory for a pre-mangled filename in
+ * MangleBuf, in the directory starting in sector SECTOR
+ *
+ * NOTE: This file considers finding a zero-length file an
+ * error. This is so we don't have to deal with that special
+ * case elsewhere in the program (most loops have the test
+ * at the end).
+ *
+ * @param: MangleBuf
+ * @param: dir_sector, directory sector
+ *
+ * @out: file pointer
+ * @out: file length (MAY BE ZERO!)
+ * @out: file attribute
+ * @out: dh, clobbered.
+ *
+ */
+struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector, \
+ __u32 *file_len, __u8 *attr)
+{
+ struct open_file_t* file;
+ struct cache_struct* cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+
+ __u8 VFATInit, VFATNext, VFATCsum;
+ __u8 id;
+ __u16 *unicode_buf;
+ __u32 slots;
+ __u32 entries;
+
+ int checksum;
+ int have_more;
+ char *long_name;
+
+ file = allocate_file();
+ if ( !file )
+ return NULL;
+
+ /*
+ * Compute the value of a possible VFAT longname
+ * "last" entry (which, of coures, comes first ...)
+ */
+ slots = (NameLen + 12) / 13;
+ long_name = (char *)malloc(13 * slots);
+ slots |= 0x40;
+
+ VFATInit = slots;
+ VFATNext = slots;
+
+
+ do {
+ cs = get_cache_block(dir_sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ entries = SECTOR_SIZE / 32;
+
+ /* scan all the entries in a sector */
+ do {
+ if ( dir->name[0] == 0 )
+ return NULL; /* Hit directory high water mark */
+
+ if ( dir->attr == 0x0f ) {
+ /* it's a long name entry */
+ long_dir = (struct fat_long_name_entry *)dir;
+ id = long_dir->id;
+ if ( id !=VFATNext )
+ goto not_match;
+
+ if ( id & 0x40 ) {
+ /*get the initial checksum value*/
+ VFATCsum = long_dir->checksum;
+ } else {
+ if ( long_dir->checksum != VFATCsum )
+ goto not_match;
+ }
+
+ id &= 0x3f;
+ VFATNext = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_dir);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ /*
+ * if we got the last entry?
+ * if so, check it, or go on with the next entry
+ */
+ if ( id == 0 ) {
+ if ( strcmp(long_name, NameStart) )
+ goto not_match;
+ }
+
+ goto next_entry;
+
+ } else {
+ /* it's a short entry */
+ if ( dir->attr & 0x08 ) /* ingore volume labels */
+ goto not_match;
+
+
+ /* If we have a long name match, then VFATNext must be 0 */
+ if ( !VFATNext ) {
+ /*
+ * we already have a VFAT long name match, however,
+ * the match is only valid if the checksum matchs.
+ */
+ checksum = get_checksum(dir->name);
+ if ( checksum == VFATCsum )
+ goto found; /* got a match on long name */
+
+ } else {
+ if ( strncmp(MangleBuf, dir->name, 11) == 0 )
+ goto found;
+ }
+ }
+
+ not_match:/* find it again */
+ VFATNext = VFATInit;
+
+ next_entry:
+ dir ++;
+
+ }while ( --entries );
+
+ dir_sector = nextsector(dir_sector);
+
+ }while ( dir_sector ); /* scan another secotr */
+
+ found:
+ *file_len = file->file_bytesleft = dir->file_size;
+ file->file_sector = first_sector(dir);
+ *attr = dir->attr;
+
+ return file;
+}
+
+
+__u32 CurrentDir = 0;
+
+
+/**
+ * searchdir:
+ *
+ * open a file
+ *
+ * @param: filename, the file we wanna open
+ * @param: file_len, to return the file length
+ *
+ * @return: return the file structure on successful, or NULL.
+ *
+ */
+struct open_file_t* searchdir(char *filename)
+{
+ __u32 dir_sector, prev_dir;
+ __u32 file_len;
+ __u8 attr;
+ char *p;
+
+ struct open_file_t *file;
+
+ dir_sector = CurrentDir;
+ if ( *filename == '/' ) {
+ dir_sector = RootDir;
+ filename ++;
+ }
+
+ while ( *filename ) {
+ p = filename;
+
+ /* try to find the end */
+ while ( (*p > ' ') && (*p != '/') )
+ p ++;
+
+ if (filename == p)
+ return NULL;
+
+ prev_dir = dir_sector;
+
+ mangle_dos_name(MangleBuf, filename);
+ file = search_dos_dir(MangleBuf, dir_sector, &file_len, &attr);
+ if ( !file ) {
+ file_len = 0;
+ return NULL;
+ }
+
+ if ( *p != '/' ) /* we got a file */
+ break;
+
+ if ( (attr & 0x10) == 0 ) /* subdirectory */
+ return NULL;
+
+ dir_sector = file->file_sector;
+ close_file(file);
+
+ filename = p + 1; /* search again */
+ }
+
+ if ( (attr & 0x18) || (file_len == 0) )
+ return NULL;
+
+ file->file_bytesleft = file_len;
+ file->file_left = ( file_len + SECTOR_SIZE -1 ) >> SECTOR_SHIFT;
+
+ return file;
+}
+
+
+
+
+/**
+ * readdir:
+ *
+ * read one file from a directory
+ *
+ * returns the file's name in the filename string buffer
+ *
+ * @param: filename
+ * @param: file
+ *
+ */
+struct open_file_t * readdir(struct open_file_t* dir_file, char* filename,
+ __u32 *file_len, __u8 *attr)
+{
+ __u32 sector, sec_off;
+
+ /* make it to be 1 to check if we have met a long name entry before */
+ __u8 id = 1;
+ __u8 init_id, next_id;
+ __u8 entries_left;
+ int i;
+ int have_more;
+
+ struct cache_struct *cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+ struct open_file_t *file;
+
+ sector = dir_file->file_sector;
+ sec_off = dir_file->file_bytesleft;
+ if ( !sector )
+ goto fail;
+
+ entries_left = (SECTOR_SIZE - sec_off) >> 5;
+ cs = get_cache_block(sector);
+ dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */
+
+ while ( 1 ) {
+ if ( dir->name[0] == 0 )
+ goto fail;
+
+ if ( dir->attr == 0x0f ) {
+ /* it's a long name */
+ long_dir = (struct fat_long_name_entry *)dir;
+
+ if ( long_dir->id & 0x40 )
+ init_id = id = long_dir->id & 0x3f;
+ else
+ next_id = (long_dir->id & 0x3f) - 1;
+
+ id --;
+
+ if ( id != next_id )
+ goto next_entry;
+
+ long_entry_name(long_dir);
+ memcpy(filename + id * 13, entry_name, 13);
+
+
+ /*
+ * we need go on with the next entry
+ * and we will fall through to next entry
+ */
+
+ } else {
+ /* it's a short entry */
+
+ if ( !id ) /* we got a long name match */
+ break;
+
+ if ( dir->attr & 0x08 )
+ goto next_entry;
+
+ for( i = 0; i < 8; i ++) {
+ if ( dir->name[i] == ' ' )
+ break;
+ *filename++ = dir->name[i];
+ }
+
+ *filename++ = '.';
+
+ for ( i = 8; i < 11; i ++) {
+ if ( dir->name[i] == ' ' )
+ break;
+ *filename ++ = dir->name[i];
+ }
+
+ /* check if we have got an extention */
+ if ( ! *(filename - 1) )
+ *(filename -2) = '\0';
+ else
+ *filename = '\0';
+
+ break;
+ }
+
+ next_entry:
+ dir ++;
+ entries_left --;
+
+ if ( !entries_left ) {
+ sector = nextsector(sector);
+ if ( !sector )
+ goto fail;
+ cs = (struct cache_struct *)get_cache_block(sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ }
+ }
+
+ /* finally , we get what we want */
+ entries_left --;
+ if ( !entries_left ) {
+ sector = nextsector(sector);
+ if ( !sector )
+ goto fail;
+ }
+
+ file->file_sector = sector;
+ file->file_bytesleft = (SECTOR_SIZE - (entries_left << DIRENT_SHIFT) ) & 0xffff;
+
+ *file_len = dir->file_size;
+ *attr = dir->attr;
+
+ return file;
+
+ fail:
+ close_dir(dir);
+ return NULL;
+}
+
+
+
+struct open_file_t* open_file(char *filename)
+{
+ struct open_file_t *file;
+
+ file = searchdir(filename);
+
+ /* if we failed, we also will get a NULL value */
+ return file;
+}
+
+__u32 read_file(struct open_file_t *file, char *buf, int size, int *have_more)
+{
+ __u32 sectors = ( size + SECTOR_SIZE - 1 ) >> SECTOR_SHIFT;
+
+ return getfssec(buf, file, sectors, have_more);
+}
+
+void bsr(__u8 *res, int num)
+{
+ *res = 0;
+}
+
+/* init. the fs meta data */
+void init_fs()
+{
+ int sectors_per_fat;
+ __u32 clust_num;
+ int RootDirSize;
+
+ /* get the fat bpb information */
+ getlinsec(&fat, 0, 1);
+
+ TotalSectors = fat.bxSectors ? : fat.bsHugeSectors;
+ FAT = fat.bxResSectors;
+
+ sectors_per_fat = fat.bxFATsecs ? : fat.u.fat32.bxFATsecs_32;
+ RootDir = RootDirArea = FAT + sectors_per_fat * fat.bxFATs;
+ RootDirSize = (fat.bxRootDirEnts+SECTOR_SIZE/32-1) >> (SECTOR_SHIFT-5);
+ DataArea = RootDirArea + RootDirSize;
+
+ bsr(&ClustShift, fat.bxSecPerClust);
+ ClustByteShift = ClustShift + SECTOR_SHIFT;
+ ClustMask = fat.bxSecPerClust - 1;
+ ClustSize = fat.bxSecPerClust << SECTOR_SHIFT;
+
+ blk_size = SECTOR_SIZE;
+
+ clust_num = (TotalSectors - DataArea) >> ClustShift;
+ if ( clust_num < 4085 )
+ FATType = FAT12;
+ else if ( clust_num < 65525 )
+ FATType = FAT16;
+ else
+ FATType = FAT32;
+}
+