LDLINUX: Applying the generic path_lookup to FAT fs
authorLiu Aleaxander <Aleaxander@gmail.com>
Wed, 9 Dec 2009 14:23:14 +0000 (22:23 +0800)
committerLiu Aleaxander <Aleaxander@gmail.com>
Wed, 9 Dec 2009 14:23:14 +0000 (22:23 +0800)
Well, it's far more to be done, esp. the relative path-searching.

Signed-off-by: Liu Aleaxander <Aleaxander@gmail.com>
core/fs.c
core/fs/fat/fat.c
core/fs/fat/fat_fs.h

index ee9488f..a821f95 100644 (file)
--- 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
 
index 0c3b5b9..cc9b48b 100644 (file)
 #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:
@@ -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(&regs, 0, sizeof regs);
+    regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+    strcpy((void *)regs.edi.w[0], current_dir_name);
+    call16(core_open, &regs, &regs);
     
-    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(&regs, 0, sizeof regs);
+    regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+    for (; i < 3; i++) {
+        strcpy(ConfigName, syslinux_cfg[i]);
+        call16(core_open, &regs, &regs);
 
+        /* 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,
 };
index 71c1d9a..9453a67 100644 (file)
@@ -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 */