aboutsummaryrefslogtreecommitdiffstats
path: root/ldlinux.c
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-05-18 16:04:20 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-05-18 16:04:20 +0800
commit2afc0ca8a0faa7e0c90063aa9a6ba2c10155da7a (patch)
tree42a45417141e4654c047cded5817d9d9b454f22d /ldlinux.c
parentaffba8c09a3ded66b97ebb09d5213edfaf74fb12 (diff)
downloaddevel-2afc0ca8a0faa7e0c90063aa9a6ba2c10155da7a.tar.gz
devel-2afc0ca8a0faa7e0c90063aa9a6ba2c10155da7a.tar.xz
devel-2afc0ca8a0faa7e0c90063aa9a6ba2c10155da7a.zip
finally got all the things written but surely not work
Diffstat (limited to 'ldlinux.c')
-rw-r--r--ldlinux.c346
1 files changed, 254 insertions, 92 deletions
diff --git a/ldlinux.c b/ldlinux.c
index c81d254..7fe13f9 100644
--- a/ldlinux.c
+++ b/ldlinux.c
@@ -26,6 +26,9 @@
#define ROOT_DIR_WORD 0x002f
+enum fat_type{ FAT12, FAT16, FAT32 };
+__u8 FATType;
+
/* generic information about FAT fs */
@@ -44,6 +47,8 @@ __u8 ClustByteShift; /* Shift count for bytes/cluster */
/* for SYSLINUX, the block size equal to the sector size */
__u32 blk_size = 1 << SECTOR_SHIFT;
+int NameLen;
+
/* file structure. This holds the information for each currently open file */
struct open_file_t {
@@ -117,17 +122,17 @@ struct open_file_t* alloc_fill_dir(__u32 sector)
/* Deallocates a file structure */
void close_file(struct open_file_t *file)
{
- if ( !file )
+ if ( file )
file->file_sector = 0;
}
/* Deallocates a directory structure */
-void close_dir(xxx* yy)
+void close_dir(struct fat_dir_entry *dir)
{
- if ( !yy )
- *yy = 0;
+ if ( dir )
+ *(char*)dir = 0;
}
@@ -182,9 +187,6 @@ void __getfssec(char *buf, __u32 curr_sector, __u32 sectors)
-
-
-
/**
* getfssec:
*
@@ -194,11 +196,12 @@ void __getfssec(char *buf, __u32 curr_sector, __u32 sectors)
* @param: buf
* @param: file
* @param: sectors
+ * @param: have_more
*
* @return: number of bytes read
*
*/
-void getfssec(char *buf, struct open_file_t *file, __u32 sectors)
+void getfssec(char *buf, struct open_file_t *file, __u32 sectors, int *have_more)
{
__u32 bytes_read;
@@ -212,10 +215,13 @@ void getfssec(char *buf, struct open_file_t *file, __u32 sectors)
if ( bytes_read >= file->file_bytesleft ) {
bytes_read = file->file_bytesleft;
file->file_bytesleft = 0;
+ *have_more = 0;
close_file(file);
- } else
+ } else {
file->file_bytesleft -= bytes_read;
+ *have_more = 1;
+ }
return bytes_read;
}
@@ -225,8 +231,7 @@ void getfssec(char *buf, struct open_file_t *file, __u32 sectors)
-
-
+char *NameStart;
/**
@@ -257,6 +262,8 @@ void mangle_dos_name(char *MangleBuf, char *filename)
char *src = filename;
char c;
int i = 0;
+
+ NameStart = filename;
for (; i < 11; i ++)
MangleBuf[i] = ' ';
@@ -290,6 +297,7 @@ void mangle_dos_name(char *MangleBuf, char *filename)
}
+char entry_name[13];
/**
* long_entry_name:
@@ -297,19 +305,14 @@ void mangle_dos_name(char *MangleBuf, char *filename)
* get the long entry name
*
*/
-char * long_entry_name(dir)
+char * long_entry_name(struct fat_dir_entry *dir)
{
- id &= 0x3f;
- while (id ) {
- if ( !id )
- goto not_us;
-
- VFATNext = --id;
- vfat_cmp:
- memcpy(unicode_buf, long_name->name1, 5 * 2);
- memcpy(unicode_buf + 5, long_name->name2, 6 * 2);
- memcpy(unicode_buf + 11,long_name->name3, 2 * 2);
- }
+ int id = dir->id & 0x3f;
+ __u16 unicode_buf[13];
+
+ memcpy(unicode_buf, long_name->name1, 5 * 2);
+ memcpy(unicode_buf + 5, long_name->name2, 6 * 2);
+ memcpy(unicode_buf + 11,long_name->name3, 2 * 2);
unicode_to_ascii(entry_name, unicode_buf);
@@ -317,6 +320,26 @@ char * long_entry_name(dir)
}
+__u8 get_checksum(char *entry_name)
+{
+ int i;
+ __u8 sum=0;
+
+ for (i=11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + *entry_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 = (fisrt_clust - 2) << ClustShift + DataArea;
+
+ return sector;
+}
+
@@ -340,7 +363,8 @@ char * long_entry_name(dir)
* @out: dh, clobbered.
*
*/
-struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
+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;
@@ -359,13 +383,13 @@ struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
* "last" entry (which, of coures, comes first ...)
*/
slots = (NameLen + 12) / 13;
- unicode_buf = (__u16 *)malloc(13 * slots);
+ long_name = (char *)malloc(13 * slots);
slots |= 0x40;
VFATInit = slots;
VFATNext = slots;
- scansector:
+
do {
cs = get_cache_block(dir_sector);
dir = (struct fat_dir_entry *)cs->data;
@@ -374,59 +398,64 @@ struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
/* scan all the entries in a sector */
do {
if ( *(char *)dir == 0 )
- goto failure;
- if ( dir->attr != 0x0f )
- goto short_entry;
+ 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;
- /* Else it's a long name entry */
- long_dir = (struct fat_long_name_entry *)dir;
- id = long_dir->id;
- if ( id !=VFATNext )
- goto not_us;
-
- if ( id & 0x40 )
- VFATCsum = long_dir->checksum;/*get the initial checksum value*/
- else {
- if ( long_dir->checksum != VFATCsum )
- goto not_us;
- }
-
- id &= 0x3f;
- slot = --id;
+ 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 */
+ entry_name = long_entry_name(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;
+ }
- /* got the long entry name */
- entry_name = long_entry_name(dir);
- memcpy(long_name + id * 13, entry_name, 13);
- if ( id )
goto next_entry;
-
- if ( strcmp(long_name, NameStart) )
- goto nomatch;
-
- short_entry:
- if ( dir->attr & 0x08 ) /* ingore volume labels */
- goto nomacth;
+ } else {
+ /* it's a short entry */
+ if ( dir->attr & 0x08 ) /* ingore volume labels */
+ goto not_macth;
- /* If we have a long name match, then VFATNext must be 0 */
- if ( VFATNext ) {
- if ( strncmp(MangleBuf, entry_name, 11) == 0 )
- goto found;
-
- } else {
-
- /*
- * we already have a VFAT long name match, however,
- * the match is only valid if the checksum matchs.
- */
- checksum = get_checksum(dir);
- if ( checksum = VFATCsum )
- goto found; /* got a match on long name */
+ /* 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;
+ }
}
-
- nomatch:
+ not_match:/* find it again */
VFATNext = VFATInit;
next_entry:
@@ -436,18 +465,14 @@ struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
dir_sector = nextsector(dir_sector, &have_more);
- }while ( have_more ); /* scan another secotr */
+ }while ( dir_sector ); /* scan another secotr */
found:
- file_len = file->file_bytesleft = dir->file_size;
-
- first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
- file->file_sector = (fisrt_clust - 2) << ClustShift + DataArea;
-
- attr = dir->attr;
+ *file_len = file->file_bytesleft = dir->file_size;
+ file->file_sector = first_sector(dir);
+ *attr = dir->attr;
return file;
-
}
@@ -468,6 +493,8 @@ struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
struct open_file_t* searchdir(char *filename, __u32 *file_len)
{
__u32 dir_sector, prev_dir;
+ __u32 file_len;
+ __u8 attr;
char *p;
struct open_file_t *file;
@@ -481,17 +508,17 @@ struct open_file_t* searchdir(char *filename, __u32 *file_len)
while ( *pathname ) {
p = filename;
+ /* try to find the end */
while ( (*p > ' ') && (*p != '/') )
p ++;
- //xchg(filename, p);
if (filename == p)
- return;
+ return NULL;
prev_dir = dir_sector;
mangle_dos_name(MangleBuf, filename);
- file = search_dos_dir(MangleBuf);
+ file = search_dos_dir(MangleBuf, dir_sector, &file_len, &attr);
if ( !file ) {
*file_len = 0;
return NULL;
@@ -504,16 +531,16 @@ struct open_file_t* searchdir(char *filename, __u32 *file_len)
return NULL;
dir_sector = file->file_sector;
- close(file);
+ close_file(file);
filename = p + 1; /* search again */
}
- if ( (attr & 0x18) || (*file_len == 0) )
+ if ( (attr & 0x18) || (file_len == 0) )
return NULL;
- file->file_bytesleft = *file_len; /**/
- file->file_left = ( *file_len + SECTOR_SIZE -1 ) >> SECTOR_SHIFT;
+ file->file_bytesleft = file_len;
+ file->file_left = ( file_len + SECTOR_SIZE -1 ) >> SECTOR_SHIFT;
return file;
}
@@ -532,12 +559,122 @@ struct open_file_t* searchdir(char *filename, __u32 *file_len)
* @param: file
*
*/
-void readdir(struct open_file_t* file, char* filename)
+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 entries_left;
+
+ struct cache_struct *cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+
+ 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 ( dir->id & 0x40 )
+ init_id = id = dir->id & 0x3f;
+ else
+ id_next = (dir->id & 0x3f) - 1;
+
+ id --;
+
+ if ( id != id_next )
+ goto next_entry;
+
+ entry_name = long_entry_name(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->atrr & 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 = next_sector(sector, &have_more);
+ if ( !sector )
+ goto fail;
+ cs = get_cache_sector(sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ }
+ }
+
+ /* finally , we get what we want */
+ entries_left --;
+ if ( !entries_left ) {
+ sector = next_sector(sector, &have_more);
+ 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->atr;
+
+ return file;
+
+ fail:
+ close_dir(dir_file);
+ return NULL;
}
+
/**
* getfatsector:
@@ -559,14 +696,14 @@ struct cache_struct *getfatsector(__u32 sector)
* cluster chain. Returns EOF.
*
*/
-void nextsector(__u32 sector, int *have_more)
+__u32 nextsector(__u32 sector, int *have_more)
{
__u32 data_sector;
__u32 cluster;
-
- *have_more = 1;
+ *have_more = 1;
+
if ( sector < DataArea ) {
sector ++;
if ( sector >= DataArea )
@@ -602,8 +739,10 @@ void nextsector(__u32 sector, int *have_more)
*
* @param: clust_num;
*
+ * @return: the next cluster number
+ *
*/
-void nextcluster(__u32 clust_num)
+__u32 nextcluster(__u32 clust_num)
{
__u32 nextcluster;
__u32 fat_sector;
@@ -647,13 +786,29 @@ void nextcluster(__u32 clust_num)
+struct open_file_t open_file(char *filename)
+{
+ struct open_file_t *file;
+
+ file = searchdir(filename, &file_len);
+
+ /* 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);
+}
/* init. the fs meta data */
void init_fs()
{
- int sectors_per_fat;
+ int sectors_per_fat;
+ __u32 clust_num;
/* get the fat bpb information */
getlinsec(&fat, 0, 1);
@@ -673,5 +828,12 @@ void init_fs()
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;
}