From: Liu Aleaxander Date: Wed, 9 Dec 2009 14:23:14 +0000 (+0800) Subject: LDLINUX: Applying the generic path_lookup to FAT fs X-Git-Tag: syslinux-4.00-pre9~2^2~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6747b1ba13fbb6266d7d7fe8f710e8475810610c;p=platform%2Fupstream%2Fsyslinux.git LDLINUX: Applying the generic path_lookup to FAT fs Well, it's far more to be done, esp. the relative path-searching. Signed-off-by: Liu Aleaxander --- diff --git a/core/fs.c b/core/fs.c index ee9488f..a821f95 100644 --- a/core/fs.c +++ b/core/fs.c @@ -127,7 +127,7 @@ void searchdir(com32sys_t *regs) char *p; int symlink_count = 6; -#if 0 +#if 1 printf("filename: %s\n", name); #endif diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index 0c3b5b9..cc9b48b 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -7,213 +7,155 @@ #include #include "fat_fs.h" -#define ROOT_DIR_WORD 0x002f -/* file structure. This holds the information for each currently open file */ -struct open_file_t { - sector_t file_sector; /* sector pointer (0 = structure free) */ - uint32_t file_bytesleft; /* number of bytes left */ - uint32_t file_left; /* number of sectors left */ -}; - -static struct open_file_t Files[MAX_OPEN]; - -extern uint8_t SecPerClust; - -/* the fat bpb data */ -static struct fat_bpb fat; -static int FATType = 0; - -/* generic information about FAT fs */ -static sector_t FAT; /* Location of (first) FAT */ -static sector_t RootDirArea; /* Location of root directory area */ -static sector_t RootDir; /* Location of root directory proper */ -static sector_t DataArea; /* Location of data area */ -static uint32_t TotalSectors; /* Total number of sectors */ -static uint32_t ClustSize; /* Bytes/cluster */ -static uint32_t ClustMask; /* Sector/cluster - 1 */ -static uint8_t ClustShift; /* Shift count for sectors/cluster */ -static uint8_t ClustByteShift; /* Shift count for bytes/cluster */ - -static int CurrentDir; -static int PrevDir; - -/* used for long name entry */ -static char MangleBuf[12]; -static char entry_name[14]; - -/* try with the biggest long name */ -static char long_name[0x40 * 13]; -static char *NameStart; -static int NameLen; - -/* - * Allocate a file structure, if successful return the file pointer, or NULL. - * - */ -static struct open_file_t *allocate_file(void) +static struct inode * new_fat_inode(void) { - struct open_file_t *file = Files; - int i = 0; + struct inode *inode = malloc(sizeof(*inode)); + if (!inode) + malloc_error("inode structure"); + memset(inode, 0, sizeof(*inode)); - for (; i < MAX_OPEN; i ++) { - if (file->file_sector == 0) /* found it */ - return file; - file ++; - } - - return NULL; /* not found */ -} - - -/* - * 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. - * - */ -static struct open_file_t *alloc_fill_dir(sector_t sector) -{ - struct open_file_t *file; + /* + * We just need allocate one uint32_t data to store the + * first cluster number. + */ + inode->data = malloc(sizeof(uint32_t)); + if (!inode->data) + malloc_error("inode->data"); - file = allocate_file(); - if (!file) - return NULL; + inode->blksize = 1 << SECTOR_SHIFT; - file->file_sector = sector; /* current sector */ - file->file_bytesleft = 0; /* current offset */ - file->file_left = sector; /* beginning sector */ - return file; + return inode; } -/* Deallocates a file structure */ -static inline void close_pvt(struct open_file_t *of) -{ - of->file_sector = 0; -} - static void vfat_close_file(struct file *file) { - close_pvt(file->open_file); + if (file->inode) { + file->offset = 0; + free_inode(file->inode); + } } /* - * check for a particular sector in the FAT cache. - * + * Check for a particular sector in the FAT cache */ -static struct cache_struct *getfatsector(struct fs_info *fs, sector_t sector) +static struct cache_struct * get_fat_sector(struct fs_info *fs, sector_t sector) { - return get_cache_block(fs->fs_dev, FAT + sector); + return get_cache_block(fs->fs_dev, FAT_SB(fs)->fat + sector); } - -/** - * Advance a cluster pointer in clust_num to the next cluster - * pointer at in the FAT tables. return the next cluster number - * if success, or return 0 if end of file. - * - */ -static uint32_t nextcluster(struct fs_info *fs, uint32_t clust_num) +static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) { uint32_t next_cluster; sector_t fat_sector; uint32_t offset; int lo, hi; struct cache_struct *cs; - - switch(FATType) { + + switch(FAT_SB(fs)->fat_type) { case FAT12: - fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT; - cs = getfatsector(fs, 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 = *(uint8_t *)(cs->data + offset); - cs = getfatsector(fs, fat_sector + 1); - hi = *(uint8_t *)cs->data; - next_cluster = (hi << 8) + lo; - } else - next_cluster = *(uint16_t *)(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; - + fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT; + cs = get_fat_sector(fs, fat_sector); + offset = (clust_num * 3 / 2) & ((1 << SECTOR_SHIFT) - 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 = *(uint8_t *)(cs->data + offset); + cs = get_fat_sector(fs, fat_sector + 1); + hi = *(uint8_t *)cs->data; + next_cluster = (hi << 8) + lo; + } else { + next_cluster = *(uint16_t *)(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 - 1); - offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1); - cs = getfatsector(fs, fat_sector); - next_cluster = ((uint16_t *)cs->data)[offset]; - if (next_cluster > 0xfff0) - goto fail; - break; - + fat_sector = clust_num >> (SECTOR_SHIFT - 1); + offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1); + cs = get_fat_sector(fs, fat_sector); + next_cluster = ((uint16_t *)cs->data)[offset]; + if (next_cluster > 0xfff0) + goto fail; + break; + case FAT32: - fat_sector = clust_num >> (SECTOR_SHIFT - 2); - offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1); - cs = getfatsector(fs, fat_sector); - next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff; - if (next_cluster > 0x0ffffff0) - goto fail; - break; + fat_sector = clust_num >> (SECTOR_SHIFT - 2); + offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1); + cs = get_fat_sector(fs, fat_sector); + next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff; + if (next_cluster > 0x0ffffff0) + goto fail; + break; } return next_cluster; - fail: +fail: /* got an unexcepted cluster number, so return ZERO */ return 0; } - -/* - * 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. - * - */ -static sector_t nextsector(struct fs_info *fs, sector_t sector) +static sector_t get_next_sector(struct fs_info* fs, uint32_t sector) { + sector_t data_area = FAT_SB(fs)->data; sector_t data_sector; uint32_t cluster; - if (sector < DataArea) { - sector ++; - /* if we reached the end of root area */ - if (sector == DataArea) - sector = 0; /* return 0 */ - return sector; + if (sector < data_area) { + sector++; + /* if we reached the end of root area */ + if (sector == data_area) + sector = 0; /* return 0 */ + return sector; } - data_sector = sector - DataArea; - if ((data_sector+1) & ClustMask) /* in a cluster */ - return (++sector); + data_sector = sector - data_area; + if ((data_sector + 1) & FAT_SB(fs)->clust_mask) /* in a cluster */ + return ++sector; - /* got a new cluster */ - cluster = nextcluster(fs, (data_sector >> ClustShift) + 2); + /* get a new cluster */ + cluster = get_next_cluster(fs, (data_sector >> FAT_SB(fs)->clust_shift) + 2); if (!cluster ) - return 0; + return 0; /* return the start of the new cluster */ - sector = ((cluster - 2) << ClustShift) + DataArea; + sector = ((cluster - 2) << FAT_SB(fs)->clust_shift) + data_area; return sector; } - - - +/* + * Here comes the place I don't like VFAT fs most; if we need seek + * the file to the right place, we need get the right sector address + * from begining everytime! Since it's a kind a signle link list, we + * need to traver from the head-node to find the right node in that list. + * + * What a waste of time! + */ +static sector_t get_the_right_sector(struct file *file) +{ + int i = 0; + int sector_pos = file->offset >> SECTOR_SHIFT; + sector_t sector = *file->inode->data; + + for (; i < sector_pos; i++) + sector = get_next_sector(file->fs, sector); + + return sector; +} /** * __getfssec: @@ -224,15 +166,11 @@ static sector_t nextsector(struct fs_info *fs, sector_t sector) * and will correct the situation if it does, UNLESS *sectos* cross * 64K boundaries. * - * @param: buf - * @param: file structure - * @param: sectors - * */ static void __getfssec(struct fs_info *fs, char *buf, - struct open_file_t *file, uint32_t sectors) + struct file *file, uint32_t sectors) { - sector_t curr_sector = file->file_sector; + sector_t curr_sector = get_the_right_sector(file); sector_t frag_start , next_sector; uint32_t con_sec_cnt; struct disk *disk = fs->fs_dev->disk; @@ -249,7 +187,7 @@ static void __getfssec(struct fs_info *fs, char *buf, if (sectors == 0) break; - next_sector = nextsector(fs, curr_sector); + next_sector = get_next_sector(fs, curr_sector); if (!next_sector) break; }while(next_sector == (++curr_sector)); @@ -261,16 +199,14 @@ static void __getfssec(struct fs_info *fs, char *buf, /* do read */ disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0); - buf += con_sec_cnt << 9;/* adjust buffer pointer */ + buf += con_sec_cnt << SECTOR_SHIFT;/* adjust buffer pointer */ if (!sectors) break; - //curr_sector --; /* this is the last sector actually read */ + curr_sector = next_sector; } - /* update the file_sector filed for the next read */ - file->file_sector = nextsector(fs, curr_sector); } @@ -279,32 +215,34 @@ static void __getfssec(struct fs_info *fs, char *buf, * get multiple sectors from a file * * @param: buf, the buffer to store the read data - * @param: gfile, the file structure pointer + * @param: file, the file structure pointer * @param: sectors, number of sectors wanna read * @param: have_more, set one if has more * * @return: number of bytes read * */ -static uint32_t vfat_getfssec(struct file *gfile, char *buf, int sectors, +static uint32_t vfat_getfssec(struct file *file, char *buf, int sectors, bool *have_more) { + uint32_t bytes_left = file->inode->size - file->offset; uint32_t bytes_read = sectors << SECTOR_SHIFT; - struct open_file_t *file = gfile->open_file; - struct fs_info *fs = gfile->fs; + int sector_left; + struct fs_info *fs = file->fs; - if (sectors > file->file_left) - sectors = file->file_left; + sector_left = (bytes_left + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + if (sectors > sector_left) + sectors = sector_left; __getfssec(fs, buf, file, sectors); - if (bytes_read >= file->file_bytesleft) { - bytes_read = file->file_bytesleft; + if (bytes_read >= bytes_left) { + bytes_read = bytes_left; *have_more = 0; - } else - *have_more = 1; - file->file_bytesleft -= bytes_read; - file->file_left -= sectors; + } else { + *have_more = 1; + } + file->offset += bytes_read; return bytes_read; } @@ -356,72 +294,56 @@ static void vfat_mangle_name(char *dst, const char *src) for (; i > 0; i --) *dst++ = '\0'; } - + /* - * 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! - */ -/** - * 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. - * + * Mangle a normal style string to DOS style string. */ -static void mangle_dos_name(char *MangleBuf, char *filename) -{ - - char *dst = MangleBuf; - char *src = filename; +static void mangle_dos_name(char *mangle_buf, char *src) +{ + char *dst = mangle_buf; int i = 0; unsigned char c; - NameStart = filename; - for (; i < 11; i ++) - MangleBuf[i] = ' '; + mangle_buf[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; + c = *src ++; + + if ((c <= ' ') || (c == '/')) + break; + + if (c == '.') { + dst = &mangle_buf[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; + mangle_buf[11] = '\0'; } + +/* try with the biggest long name */ +static char long_name[0x40 * 13]; +static char entry_name[14]; + static void unicode_to_ascii(char *entry_name, uint16_t *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]; + if (unicode_buf[i] == 0xffff) { + entry_name[i] = '\0'; + return; + } + entry_name[i] = (char)unicode_buf[i]; } } @@ -433,237 +355,188 @@ static void long_entry_name(struct fat_long_name_entry *dir) { uint16_t 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); + 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); } static uint8_t get_checksum(char *dir_name) { int i; - uint8_t sum=0; + uint8_t sum = 0; - for (i=11; i; i--) - sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++; + for (i = 11; i; i--) + sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++; return sum; } + /* compute the first sector number of one dir where the data stores */ static inline sector_t first_sector(struct fat_dir_entry *dir) { - uint32_t first_clust, sector; + struct fat_sb_info *sbi = FAT_SB(this_fs); + uint32_t first_clust; + sector_t sector; first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low; - sector = ((first_clust - 2) << ClustShift) + DataArea; + sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data; return sector; } +static inline int get_inode_mode(uint8_t attr) +{ + if (attr == FAT_ATTR_DIRECTORY) + return I_DIR; + else + return I_FILE; +} -/** - * 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 - * - */ -static struct open_file_t* -search_dos_dir(struct fs_info *fs, char *MangleBuf, - uint32_t dir_sector, uint32_t *file_len, uint8_t *attr) + +static struct inode *vfat_find_entry(char *dname, struct inode *dir) { - struct open_file_t* file; - struct cache_struct* cs; - struct fat_dir_entry *dir; - struct fat_long_name_entry *long_dir; - - uint8_t VFATInit, VFATNext, VFATCsum; - uint8_t id; - uint32_t slots; - uint32_t entries; + struct inode *inode = new_fat_inode(); + struct fat_dir_entry *de; + struct fat_long_name_entry *long_de; + struct cache_struct *cs; + + char mangled_name[12] = {0, }; + sector_t dir_sector = *dir->data; + + uint8_t vfat_init, vfat_next, vfat_csum = 0; + uint8_t id; + int slots; + int entries; int checksum; - - 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; - slots |= 0x40; - VFATInit = slots; - VFATNext = slots; - - do { - cs = get_cache_block(fs->fs_dev, 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(fs, 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; + slots = (strlen(dname) + 12) / 13 ; + slots |= 0x40; + vfat_init = vfat_next = slots; - return file; + while (1) { + cs = get_cache_block(this_fs->fs_dev, dir_sector); + de = (struct fat_dir_entry *)cs->data; + entries = 1 << (SECTOR_SHIFT - 5); + + while(entries--) { + if (de->name[0] == 0) + return NULL; + + if (de->attr == 0x0f) { + /* + * It's a long name entry. + */ + long_de = (struct fat_long_name_entry *)de; + id = long_de->id; + if (id != vfat_next) + goto not_match; + + if (id & 0x40) { + /* get the initial checksum value */ + vfat_csum = long_de->checksum; + id &= 0x3f; + } else { + if (long_de->checksum != vfat_csum) + goto not_match; + } + + vfat_next = --id; + + /* got the long entry name */ + long_entry_name(long_de); + memcpy(long_name + id * 13, entry_name, 13); + + /* + * If we got the last entry, check it. + * Or, go on with the next entry. + */ + if (id == 0) { + if (strcmp(long_name, dname)) + goto not_match; + } + + de++; + continue; /* Try the next entry */ + } else { + /* + * It's a short entry + */ + if (de->attr & 0x08) /* ignore volume labels */ + goto not_match; + + /* If we have a long name match, then vfat_next must be 0 */ + if (vfat_next == 0) { + /* + * We already have a VFAT long name match. However, the + * match is only valid if the checksum matches. + */ + checksum = get_checksum(de->name); + if (checksum == vfat_csum) + goto found; /* Got it */ + } else { + if (mangled_name[0] == 0) { + /* We haven't mangled it, mangle it first. */ + mangle_dos_name(mangled_name, dname); + } + + if (!strncmp(mangled_name, de->name, 11)) + goto found; + } + } + + not_match: + vfat_next = vfat_init; + + de++; + } + + /* Try with the next sector */ + dir_sector = get_next_sector(this_fs, dir_sector); + if (!dir_sector) + return NULL; + } + +found: + inode->size = de->file_size; + *inode->data = first_sector(de); + inode->mode = get_inode_mode(de->attr); + + return inode; } +static struct inode *vfat_iget_root(void) +{ + struct inode *inode = new_fat_inode(); + int root_size = FAT_SB(this_fs)->root_size; + + inode->size = root_size << SECTOR_SHIFT; + *inode->data = FAT_SB(this_fs)->root; + inode->mode = I_DIR; + + return inode; +} +static struct inode *vfat_iget(char *dname, struct inode *parent) +{ + return vfat_find_entry(dname, parent); +} -/** - * 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. - * - */ -static void vfat_searchdir(char *filename, struct file *file) +static char current_dir_name[32]; +static struct inode *vfat_iget_current(void) { - sector_t dir_sector; - uint32_t file_len = 0; - uint8_t attr = 0; - char *p; - struct open_file_t *open_file = NULL; - - dir_sector = CurrentDir; - if (*filename == '/') { - dir_sector = RootDir; - if (*(filename + 1) == 0) /* root dir is what we need */ - goto found_dir; - } - - while (*filename) { - if (*filename == '/') - filename++; /* skip '/' */ - p = filename; - if (*p == 0) - break; - PrevDir = dir_sector; - - /* try to find the end */ - while ((*p > ' ') && (*p != '/')) - p ++; - - if (filename == p) { - /* found a dir */ - dir_sector = PrevDir; - goto found_dir; - } - - mangle_dos_name(MangleBuf, filename); - /* close it before open a new dir file */ - if (open_file) - close_pvt(open_file); - open_file = search_dos_dir(file->fs, MangleBuf, dir_sector, &file_len, &attr); - if (!open_file) - goto fail; - - dir_sector = open_file->file_sector; - filename = p; - } + com32sys_t regs; + /* + * Use ConfigName again. + */ + memset(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + strcpy((void *)regs.edi.w[0], current_dir_name); + call16(core_open, ®s, ®s); - if (attr & 0x10) { - found_dir: - open_file = alloc_fill_dir(dir_sector); - } else if ((attr & 0x18) || (file_len == 0)) { - fail: - file_len = 0; - open_file = NULL; - } else { - open_file->file_bytesleft = file_len; - open_file->file_left = (file_len + SECTOR_SIZE -1) >> SECTOR_SHIFT; - } - - file->file_len = file_len; - file->open_file = open_file; + return handle_to_file(regs.esi.w[0])->inode; } /* @@ -678,124 +551,6 @@ void vfat_opendir(com32sys_t *regs) searchdir(regs); } -/* - * read one file from a directory; return the newly read de structure - */ -struct dirent* vfat_readdir(struct file *dir) -{ - uint32_t sector, sec_off; - /* make it to be 1 to check if we have met a long name entry before */ - uint8_t id = 1; - uint8_t init_id, next_id; - uint8_t checksum = 0; - uint8_t entries_left; - int i; - static struct dirent de; - char *de_name = de.d_name; - struct cache_struct *cs; - struct fat_dir_entry *fat_dir; - struct fat_long_name_entry *long_dir; - struct open_file_t *file = dir->open_file; - struct fs_info *fs = dir->fs; - - sector = file->file_sector; - sec_off = file->file_bytesleft; - if (!sector) - return NULL; - entries_left = (SECTOR_SIZE - sec_off) >> 5; - cs = get_cache_block(fs->fs_dev, sector); - fat_dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */ - - while (1) { - if (!entries_left) { - sector = nextsector(fs, sector); - if (!sector) - return NULL; - cs = get_cache_block(fs->fs_dev, sector); - fat_dir = (struct fat_dir_entry *)cs->data; - } - - if (fat_dir->name[0] == 0) - return NULL; - if (fat_dir->attr == FAT_ATTR_LONG_NAME) { - /* it's a long name */ - long_dir = (struct fat_long_name_entry *)fat_dir; - - if (long_dir->id & 0x40) { - checksum = long_dir->checksum; - init_id = id = long_dir->id & 0x3f; - id--; - } else { - next_id = (long_dir->id & 0x3f) - 1; - id--; - if (id != next_id || long_dir->checksum != checksum) - goto next_entry; - } - - long_entry_name(long_dir); - memcpy(de_name + 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) { - /* Got a long name match */ - if (get_checksum(fat_dir->name) != checksum) - goto next_entry; - - break; - } - - if (fat_dir->attr & FAT_ATTR_VOLUME_ID || - get_checksum(fat_dir->name) != checksum ) - goto next_entry; - - for(i = 0; i < 8; i ++) { - if (fat_dir->name[i] == ' ') - break; - *de_name++ = fat_dir->name[i]; - } - *de_name++ = '.'; - for (i = 8; i < 11; i ++) { - if (fat_dir->name[i] == ' ') - break; - *de_name ++ = fat_dir->name[i]; - } - /* check if we have got an extention */ - if (*(de_name - 1) == '.') - *(de_name - 1) = '\0'; - else - *de_name = '\0'; - - break; - } - - next_entry: - entries_left --; - fat_dir ++; - } - - /* found what we want, fill the de structure */ - de.d_reclen = DIR_REC_LEN(de.d_name); - de.d_type = fat_dir->attr; - - /* update the DIR structure */ - entries_left--; - if (!entries_left) { - sector = nextsector(fs, sector); - file->file_bytesleft = 0; - } else { - file->file_bytesleft = SECTOR_SIZE - (entries_left << 5); - } - file->file_sector = sector; - - return &de; -} /* Load the config file, return 1 if failed, or 0 */ static int vfat_load_config(void) @@ -808,9 +563,6 @@ static int vfat_load_config(void) { syslinux_cfg1, syslinux_cfg2, syslinux_cfg3 }; com32sys_t regs; int i = 0; - - *(uint16_t *)CurrentDirName = ROOT_DIR_WORD; - CurrentDir = RootDir; /* * we use the ConfigName to pass the config path because @@ -830,11 +582,24 @@ static int vfat_load_config(void) printf("no config file found\n"); return 1; /* no config file */ } + + /* Build the Current inode */ + strcpy(current_dir_name, syslinux_cfg[i]); + current_dir_name[strlen(syslinux_cfg[i]) - strlen(config_name)] = '\0'; + this_inode = vfat_iget_current(); + + memset(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + for (; i < 3; i++) { + strcpy(ConfigName, syslinux_cfg[i]); + call16(core_open, ®s, ®s); + /* if zf flag set, then failed; try another */ + if (! (regs.eflags.l & EFLAGS_ZF)) + break; + } + strcpy(ConfigName, config_name); - strcpy(CurrentDirName, syslinux_cfg[i]); - CurrentDirName[strlen(syslinux_cfg[i])-strlen(config_name)] = '\0'; - CurrentDir = PrevDir; return 0; } @@ -847,50 +612,60 @@ static inline __constfunc uint32_t bsr(uint32_t num) /* init. the fs meta data, return the block size in bits */ static int vfat_fs_init(struct fs_info *fs) { - int sectors_per_fat; - uint32_t clust_num; - int RootDirSize; + struct fat_bpb fat; + struct fat_sb_info *sbi; struct disk *disk = fs->fs_dev->disk; + int sectors_per_fat; + uint32_t clust_num; + sector_t total_sectors; - /* get the fat bpb information */ disk->rdwr_sectors(disk, &fat, 0, 1, 0); - TotalSectors = fat.bxSectors ? : fat.bsHugeSectors; - FAT = fat.bxResSectors; + sbi = malloc(sizeof(*sbi)); + if (!sbi) + malloc_error("fat_sb_info structure"); + fs->fs_info = sbi; + this_fs = fs; 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; - - ClustShift = bsr(fat.bxSecPerClust); - ClustByteShift = ClustShift + SECTOR_SHIFT; - ClustMask = fat.bxSecPerClust - 1; - ClustSize = fat.bxSecPerClust << SECTOR_SHIFT; - - clust_num = (TotalSectors - DataArea) >> ClustShift; + total_sectors = fat.bxSectors ? : fat.bsHugeSectors; + + sbi->fat = fat.bxResSectors; + sbi->root = sbi->fat + sectors_per_fat * fat.bxFATs; + sbi->root_size = root_dir_size(&fat); + sbi->data = sbi->root + sbi->root_size; + + sbi->clust_shift = bsr(fat.bxSecPerClust); + sbi->clust_byte_shift = sbi->clust_shift + SECTOR_SHIFT; + sbi->clust_mask = fat.bxSecPerClust - 1; + sbi->clust_size = fat.bxSecPerClust << SECTOR_SHIFT; + + clust_num = (total_sectors - sbi->data) >> sbi->clust_shift; if (clust_num < 4085) - FATType = FAT12; + sbi->fat_type = FAT12; else if (clust_num < 65525) - FATType = FAT16; - else - FATType = FAT32; + sbi->fat_type = FAT16; + else + sbi->fat_type = FAT32; + fs->blk_bits = 0; /* for SYSLINUX, the cache is based on sector size */ return SECTOR_SHIFT; } const struct fs_ops vfat_fs_ops = { .fs_name = "vfat", - .fs_flags = 0, + .fs_flags = FS_USEMEM, .fs_init = vfat_fs_init, - .searchdir = vfat_searchdir, + .searchdir = NULL, .getfssec = vfat_getfssec, .close_file = vfat_close_file, .mangle_name = vfat_mangle_name, .unmangle_name = generic_unmangle_name, .load_config = vfat_load_config, .opendir = vfat_opendir, - .readdir = vfat_readdir, - .iget_current = NULL + .readdir = NULL, + .iget_root = vfat_iget_root, + .iget_current = vfat_iget_current, + .iget = vfat_iget, }; diff --git a/core/fs/fat/fat_fs.h b/core/fs/fat/fat_fs.h index 71c1d9a..9453a67 100644 --- a/core/fs/fat/fat_fs.h +++ b/core/fs/fat/fat_fs.h @@ -76,9 +76,26 @@ struct fat_bpb { } __attribute__ ((packed)) u; -} __attribute__ ((packed)); + uint8_t pad[422]; /* padding to 512 Bytes (one sector) */ +} __attribute__ ((packed)); +/* + * The fat file system info in memory + */ +struct fat_sb_info { + sector_t fat; /* The FAT region */ + sector_t root; /* The root dir region */ + int root_size; /* The root dir size in sectores */ + sector_t data; /* The data region */ + + int clust_shift; /* based on sectors */ + int clust_byte_shift; /* based on bytes */ + int clust_mask; + int clust_size; + + int fat_type; +} __attribute__ ((packed)); struct fat_dir_entry { char name[11]; @@ -108,7 +125,21 @@ struct fat_long_name_entry { uint16_t name3[2]; } __attribute__ ((packed)); +static inline struct fat_sb_info *FAT_SB(struct fs_info *fs) +{ + return fs->fs_info; +} +/* + * Count the root dir size in sectors + */ +static inline int root_dir_size(struct fat_bpb *fat) +{ + int sector_size = 1 << SECTOR_SHIFT; + + return (fat->bxRootDirEnts + sector_size / sizeof(struct fat_dir_entry) + - 1) >> (SECTOR_SHIFT - 5); +} #endif /* fat_fs.h */