diff options
author | Liu Aleaxander <Aleaxander@gmail.com> | 2009-05-18 16:04:20 +0800 |
---|---|---|
committer | Liu Aleaxander <Aleaxander@gmail.com> | 2009-05-18 16:04:20 +0800 |
commit | 2afc0ca8a0faa7e0c90063aa9a6ba2c10155da7a (patch) | |
tree | 42a45417141e4654c047cded5817d9d9b454f22d /ldlinux.c | |
parent | affba8c09a3ded66b97ebb09d5213edfaf74fb12 (diff) | |
download | devel-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.c | 346 |
1 files changed, 254 insertions, 92 deletions
@@ -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; } |