#include <fs.h>
#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:
* 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;
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));
/* 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);
}
* 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;
}
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];
}
}
{
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;
}
/*
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)
{ 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
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;
}
/* 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,
};