Core: opendir/readdir/closedir stuff added
authorLiu Aleaxander <Aleaxander@gmail.com>
Wed, 26 Aug 2009 23:37:44 +0000 (07:37 +0800)
committerLiu Aleaxander <Aleaxander@gmail.com>
Wed, 26 Aug 2009 23:37:44 +0000 (07:37 +0800)
Here're some big changes:
1. The vfs-dir stuff added.
2. The dir-functions in com32/lib are mostly rewritten.
3. with little change on rosh for avoid the compile error

Well, I don't think it's a good vfs-dir interface.

Signed-off-by: Liu Aleaxander <Aleaxander@gmail.com>
14 files changed:
com32/include/dirent.h
com32/lib/closedir.c
com32/lib/opendir.c
com32/lib/readdir.c
com32/modules/Makefile
com32/modules/dir.c [new file with mode: 0644]
com32/rosh/rosh.c
core/comboot.inc
core/dir.c [new file with mode: 0644]
core/extern.inc
core/fs.c
core/fs/fat/fat.c
core/include/dir.h [new file with mode: 0644]
core/include/fs.h

index d99b21f..0fc2e13 100644 (file)
 #endif
 
 struct dirent {
-    long d_ino;                        /* Inode/File number */
-    off_t d_size;              /* Size of file */
-    mode_t d_mode;             /* Type of file */
+    uint32_t d_ino;
+    uint32_t d_off;
+    uint16_t d_reclen;
+    uint16_t d_type;
     char d_name[NAME_MAX + 1];
 };
 
 typedef struct {
-    short dd_stat;             /* status return from last lookup */
-    uint16_t dd_fd;
-    size_t dd_sect;
-    char dd_name[NAME_MAX + 1];        /* directory */
+    uint16_t dd_stat;
+    uint16_t dd_sect;
+    uint64_t dd_offset;
+    char dd_name[NAME_MAX + 1];
 } DIR;
 
 __extern DIR *opendir(const char *);
index f8bbbab..dcf1704 100644 (file)
 
 int closedir(DIR * dir)
 {
-    int rv;
-    com32sys_t regs;
-    if (dir == NULL) {
+    int rv = -1;
+       
+    if (dir) {
+       /*
+         com32sys_t regs;
+         memset(&regs, 0, sizeof regs);
+         regs.eax.w[0] = 0x0022;
+         regs.esi.l = OFFS_WRT(dir, 0);
+         __com32.cs_intcall(0x22, &regs, &regs);
+       */
+       free(dir);
        rv = 0;
-    } else {
-       memset(&regs, 0, sizeof regs);  /* ?Needed? */
-       regs.eax.w[0] = 0x0022;
-       regs.esi.w[0] = dir->dd_fd;
-       __com32.cs_intcall(0x22, &regs, &regs);
-       free(dir);              /* garbage collection? */
-       rv = 0;
-    }
-    return rv;
+       }
+       
+       return rv;
 }
index 6fc0f14..669a04a 100644 (file)
 
 DIR *opendir(const char *pathname)
 {
-    DIR *newdir;
+    DIR *newdir = NULL;
     com32sys_t regs;
-
-    newdir = NULL;
-
+       
     strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size);
 
     regs.eax.w[0] = 0x0020;
@@ -25,14 +23,14 @@ DIR *opendir(const char *pathname)
     regs.es = SEG(__com32.cs_bounce);
 
     __com32.cs_intcall(0x22, &regs, &regs);
-
+       
     if (!(regs.eflags.l & EFLAGS_CF)) {
-       /* Initialization: malloc() then zero */
-       newdir = calloc(1, sizeof(DIR));
-       strcpy(newdir->dd_name, pathname);
-       newdir->dd_fd = regs.esi.w[0];
-       newdir->dd_sect = regs.eax.l;
-       newdir->dd_stat = 0;
+        /* Initialization: malloc() then zero */
+        newdir = calloc(1, sizeof(DIR));
+        strcpy(newdir->dd_name, pathname);
+        newdir->dd_sect = regs.eax.l;
+        newdir->dd_offset = 0;
+        newdir->dd_stat = 0;
     }
 
     /* We're done */
index 2ec7c7b..7fca476 100644 (file)
 
 struct dirent *readdir(DIR * dir)
 {
-    struct dirent *newde;
+    struct dirent *newde = NULL;;
     com32sys_t regs;
-
-    newde = NULL;
-    if ((dir != NULL) && (dir->dd_fd != 0) && (dir->dd_stat >= 0)) {
-       memset(__com32.cs_bounce, 0, 32);
-       memset(&regs, 0, sizeof(regs));
-
+           
+    if ((dir !=NULL) && (dir->dd_sect != 0) && (dir->dd_stat != 0xffff)) {
+       memset(&regs, 0, sizeof(regs));         
        regs.eax.w[0] = 0x0021;
-       regs.esi.w[0] = dir->dd_fd;
-       regs.edi.w[0] = OFFS(__com32.cs_bounce);
-       regs.es = SEG(__com32.cs_bounce);
-
+       regs.esi.l = (uint32_t)dir;
        __com32.cs_intcall(0x22, &regs, &regs);
-
-       /* Don't do this as we won't be able to rewind.
-          dir->dd_fd = regs.esi.w[0];  /* Shouldn't be needed? */
-       if ((!(regs.eflags.l & EFLAGS_CF)) && (regs.esi.w[0] != 0)) {
-           newde = calloc(1, sizeof(newde));
-           if (newde != NULL) {
-               strcpy(newde->d_name, __com32.cs_bounce);
-               newde->d_mode = regs.edx.b[0];
-               newde->d_size = regs.eax.l;
-               newde->d_ino = regs.ebx.l;
-               dir->dd_stat = 1;
-           } else {
-               dir->dd_stat = -2;
-               errno = ENOMEM;
-           }
-       } else {
-           dir->dd_stat = -1;
-           errno = EIO;        /* Is this the right nmber? */
-       }
-    } else {
-       errno = EBADF;
+       newde = (struct dirent *)(regs.eax.l);
     }
-
+       
     return newde;
 }
index e0e103b..23cd31f 100644 (file)
@@ -21,7 +21,7 @@ include ../MCONFIG
 MODULES          = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
            pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 meminfo.c32 \
            sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 kbdmap.c32 cmd.c32 \
-           vpdtest.c32 host.c32
+           vpdtest.c32 host.c32 dir.c32
 
 TESTFILES =
 
diff --git a/com32/modules/dir.c b/com32/modules/dir.c
new file mode 100644 (file)
index 0000000..a3c9815
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * A dir test module
+ */
+#include <stdio.h>
+#include <console.h>
+#include <string.h>
+#include <com32.h>
+#include <dirent.h>
+
+int main(int argc, char *argv[])
+{
+       DIR *dir;
+       struct dirent *de;
+       
+       openconsole(&dev_null_r, &dev_stdcon_w);
+
+       if (argc != 2) {
+               printf("Usage: dir direcotry\n");
+               return 0;
+       }
+       
+       dir = opendir(argv[1]);
+       if (dir == NULL) {
+               printf("Unable to read dir: %s\n", argv[1]);
+               return 0;
+       }
+               
+       while ((de = readdir(dir)) != NULL)
+               printf("%s\n", de->d_name);
+       
+       closedir(dir);
+       
+       return 0;
+}
+  
index 631c780..c634a94 100644 (file)
@@ -389,7 +389,7 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
        ROSH_DEBUG("--'%s'\n", filestr);
     }
     fd = open(filestr, O_RDONLY);
-    if (fd != -1) {
+    if (fd == -1) {
        status = fstat(fd, &fdstat);
         if (S_ISDIR(fdstat.st_mode)) {
            ROSH_DEBUG("PATH '%s' is a directory\n", ifilstr);
@@ -428,14 +428,14 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
            filepos = 0;
             d = opendir(filestr);
            if (d != NULL) {
-               printf("DIR:'%s'    %08x %8d\n", d->dd_name, d->dd_fd,
-                      d->dd_sect);
+               printf("DIR:'%s'    %08x %8d\n", d->dd_name, (int)d->dd_sect, 
+                      d->dd_offset);
                de = readdir(d);
                while (de != NULL) {
                    filepos++;
 #ifdef DO_DEBUG
 // if (strlen(de->d_name) > 25) de->d_name[25] = 0;
-                   switch (de->d_mode) {
+                   switch (de->d_type) {
                    case 16:
                        ty = 'D';
                        break;
@@ -445,8 +445,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
                    default:
                        ty = '*';
                    }
-                   printf("@%8d:%8d:%4d ", (int)de->d_ino, (int)de->d_size,
-                          de->d_mode);
 #endif /* DO_DEBUG */
 //                                      printf("%s\n", de->d_name);
                    printf("'%s'\n", de->d_name);
@@ -458,7 +456,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
                    de = readdir(d);
 // if(filepos>15){      de = NULL;      printf("Force Break\n");}
                }
-               printf("Dir.dd_fd: '%8d'\n", d->dd_fd);
                closedir(d);
            } else {
                rosh_error(0, "dir:NULL", filestr);
index 28f0bc2..b078aa5 100644 (file)
@@ -901,13 +901,10 @@ comapi_getcwd:
 ;
 %if IS_SYSLINUX
 comapi_opendir:
-               push ds
-               mov ds,P_ES
+               mov es,P_ES
                mov si,P_SI
                mov di,InitRD
-               pm_call mangle_name
-               pop ds
-               pm_call searchdir
+               pm_call opendir
                jz comapi_err   ; Didn't find a directory
                cmp eax,0
                jz comapi_err   ; Found nothing
@@ -925,14 +922,9 @@ comapi_opendir     equ comapi_err
 ;
 %if IS_SYSLINUX
 comapi_readdir:
-               mov es,P_ES
-               mov di,P_DI
-               mov si,P_SI
-               pm_call vfat_readdir
-               mov P_EAX,eax
-               mov P_DL,dl
-               mov P_EBX,ebx
-               mov P_SI,si
+               mov esi,P_ESI       ; The address of DIR structure
+               pm_call readdir
+               mov P_EAX,eax       ; The address of newly read dirent structure
                ret
 %else
 comapi_readdir equ comapi_err
diff --git a/core/dir.c b/core/dir.c
new file mode 100644 (file)
index 0000000..0701125
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <string.h>
+#include <dir.h>
+#include <fs.h>
+#include <core.h>
+
+/* The dir log structure, to log the status of the dir_buf. */
+struct dir_log {
+    int offset;   /* how far from the dir_buf */
+    int index;    /* which dir entry have we go */
+};
+static struct dir_log log = {0, 0};
+
+/* The dir buffer used by fill_dir to store the newly read dirs*/
+#define DB_SIZE 2048
+char dir_buf[DB_SIZE];
+
+void opendir(com32sys_t *regs)
+{      
+    int ds = regs->ds; /* save ds */
+       
+    regs->ds = regs->es;
+    regs->es = ds;
+    mangle_name(regs);
+    regs->ds = ds;  /* restore ds */
+    searchdir(regs);   
+}
+
+/*
+ * Fill the dir buffer; return 1 for not full, 0 for full
+ */
+int fill_dir(struct dirent *de)
+{
+    int de_len = de->d_reclen;
+    if (log.offset + de_len <= DB_SIZE) {
+       memcpy(dir_buf + log.offset, de, de_len);
+       log.offset += de_len;
+       log.index ++;
+       return 1;
+    }
+
+       return 0;
+}
+
+/*
+ * Read one dirent at one time. 
+ *
+ * @input: _esi_ register stores the address of DIR structure
+ * @output: _eax_ register stores the address of newly read dirent structure
+ */
+void readdir(com32sys_t *regs)
+{
+    extern struct fs_info *this_fs;
+    DIR *dir = (DIR *)regs->esi.l;     
+    struct dirent *de = NULL;
+    static int offset;
+       
+       /* If we haven't fill the dir buffer, fill it */
+    if (log.index == 0) {
+       this_fs->fs_ops->readdir(this_fs, dir);
+       if (log.offset == 0) {
+               regs->eax.l = 0;
+               return;
+       }
+       offset = 0; /* reset the _offset_ */
+    }
+       
+    if (offset < log.offset) {
+       de = (struct dirent *)(dir_buf + offset);
+       offset += de->d_reclen;
+    } 
+    if (offset >= log.offset) /* reach the end of buffer, reset it */
+       memset(&log, 0, sizeof log);
+       
+    /* Return the newly read de in _eax_ register */
+    regs->eax.l = (uint32_t)de;
+}
+
+void closedir(com32sys_t *regs)
+{
+    regs->esi.w[0] = 0;
+}
+
+
index d944bb1..37024ec 100644 (file)
@@ -16,9 +16,7 @@
        extern fs_init, searchdir, getfssec, mangle_name, load_config
         extern unmangle_name, close_file
 
-%if IS_SYSLINUX
-        ; fat.c
-        extern vfat_readdir
-%endif
+        ; dir.c
+        extern opendir, readdir, readdir
 
 %endif ; EXTERN_INC
index 2804468..1730378 100644 (file)
--- a/core/fs.c
+++ b/core/fs.c
@@ -22,6 +22,7 @@ static struct file *alloc_file(void)
     for (i = 0; i < MAX_OPEN; i++) {
        if (!file->open_file)
            return file;
+       file++;
     }
 
     return NULL;
index 2f0bac7..f219995 100644 (file)
@@ -4,6 +4,7 @@
 #include <core.h>
 #include <disk.h>
 #include <fs.h>
+#include <dir.h>
 #include "fat_fs.h"
 
 #define ROOT_DIR_WORD    0x002f
@@ -345,7 +346,9 @@ static void vfat_mangle_name(char *dst, const char *src)
     /* Strip terminal slashes or whitespace */
     while (1) {
         if (dst == p)
-            break;        
+            break;
+               if (*(dst-1) == '/' && dst-1 == p) /* it's the '/' case */
+                       break;
         if ((*(dst-1) != '/') && (*(dst-1) != '.'))
             break;
         
@@ -654,8 +657,7 @@ static void vfat_searchdir(char *filename, struct file *file)
     }
     
     if (attr & 0x10) {
-        dir_sector = PrevDir;
-    found_dir:
+       found_dir:
         open_file = alloc_fill_dir(dir_sector);
         /* 
          * for dir, we use the file->file_len to store the sector number 
@@ -678,69 +680,64 @@ static void vfat_searchdir(char *filename, struct file *file)
 
 
 
-/**
- * readdir:
- *
+/*
  * read one file from a directory
- *
- * returns the file's name in the filename string buffer
- *
- * @param: filename
- * @param: file
- *
+ * return 1 if error, or 0 if success
  */
-void vfat_readdir(com32sys_t *regs)/*
-                                struct fs_info *fs, struct open_file_t* dir_file,
-                                char* filename, uint32_t *file_len, uint8_t *attr)
-                              */
+void vfat_readdir(struct fs_info *fs, DIR *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;
-
-    char *filename = MK_PTR(regs->es, regs->edi.w[0]);
-    struct open_file_t *dir_file = MK_PTR(regs->ds, regs->esi.w[0]);
-    
+       int not_full = 1;
+    struct dirent de;
+    char *de_name = de.d_name;        
     struct cache_struct  *cs;
-    struct fat_dir_entry *dir;
-    struct fat_long_name_entry *long_dir;
-    struct open_file_t file;
-    
-    sector  = dir_file->file_sector;
-    sec_off = dir_file->file_bytesleft;
+    struct fat_dir_entry *fat_dir;
+    struct fat_long_name_entry *long_dir;    
+
+    sector  = dir->dd_sect;
+    sec_off = dir->dd_offset;
     if (!sector)
-        goto fail;
-    
+        return 1;    
     entries_left = (SECTOR_SIZE - sec_off) >> 5;
     cs = get_cache_block(this_fs->fs_dev, sector);
-    dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */
+    fat_dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */
     
-    while (1) {
-        if (dir->name[0] == 0)
-            goto fail;                
-        
-        if  (dir->attr == FAT_ATTR_LONG_NAME) {
+    while (not_full) {
+               if (!entries_left) {
+            sector = nextsector(fs, sector);
+            if (!sector)
+                goto end;
+            cs = get_cache_block(fs->fs_dev, sector);
+            fat_dir = (struct fat_dir_entry *)cs->data;
+        }
+               
+        if (fat_dir->name[0] == 0)
+                       goto end;
+        if  (fat_dir->attr == FAT_ATTR_LONG_NAME) {
             /* it's a long name */
-            long_dir = (struct fat_long_name_entry *)dir;
+            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)
+                if (id != next_id || long_dir->checksum != checksum)
                     goto next_entry;
             }
             
             long_entry_name(long_dir);
-            memcpy(filename + id * 13, entry_name, 13);
-            
+            memcpy(de_name + id * 13, entry_name, 13);           
             
-            /* 
+                       /* 
              * we need go on with the next entry 
              * and we will fall through to next entry
              */
@@ -748,73 +745,65 @@ void vfat_readdir(com32sys_t *regs)/*
         } else {
             /* it's a short entry */
             
-            if (!id) /* we got a long name match */
-                break;
+            if (!id) {
+                               /* Got a long name match */
+                               //if (get_checksum(fat_dir->name) != checksum)
+                               //goto next_entry;
+                               
+                               /* reset _id_ and _checksum_ */
+                               id = 1;
+                               checksum = 0;
+                               goto fill;
+                       }
             
-            if (dir->attr & FAT_ATTR_VOLUME_ID) 
-                goto next_entry;
+            if (fat_dir->attr & FAT_ATTR_VOLUME_ID ||
+                               get_checksum(fat_dir->name) != checksum ) 
+                               goto next_entry;
             
             for(i = 0; i < 8; i ++) {
-                if (dir->name[i] == ' ')
+                if (fat_dir->name[i] == ' ')
                     break;
-                *filename++ = dir->name[i];
-            }
-            
-            *filename++ = '.';
-                        
+                *de_name++ = fat_dir->name[i];
+            }            
+            *de_name++ = '.';                        
             for (i = 8; i < 11; i ++) {
-                if (dir->name[i] == ' ')
+                if (fat_dir->name[i] == ' ')
                     break;
-                *filename ++ = dir->name[i];
-            }
-            
+                *de_name ++ = fat_dir->name[i];
+            }            
             /* check if we have got an extention */
-            if (*(filename - 1) == '.') 
-                *(filename - 1) = '\0';
+            if (*(de_name - 1) == '.') 
+                *(de_name - 1) = '\0';
             else
-                *filename = '\0';      
-            
-            break;
+                *de_name = '\0';      
+           
+               fill:
+                       de.d_type = fat_dir->attr;
+                       de.d_reclen = DIR_REC_LEN(de.d_name);
+                       not_full = fill_dir(&de);
+                       de_name = de.d_name;    /* reset the de_name pointer */
         }
         
     next_entry:
-        dir ++;
-        entries_left --;
-        
-        if (!entries_left) {
-            sector = nextsector(this_fs, sector);
-            if (!sector)
-                goto fail;
-            cs = get_cache_block(this_fs->fs_dev, sector);
-            dir = (struct fat_dir_entry *)cs->data;
-        }
+               entries_left --;
+        fat_dir ++;
     }
     
-    /* finally , we get what we want */
-    entries_left --;
-    if (!entries_left) {
-        sector = nextsector(this_fs, sector);
+    /* dir buffer filled, now it's time to update the DIR structure */
+       if (!entries_left) {
+        sector = nextsector(fs, sector);
         if (!sector)
-            goto fail;
-        dir_file->file_bytesleft = 0;
-    } else 
-        dir_file->file_bytesleft = SECTOR_SIZE - (entries_left << 5);
-    dir_file->file_sector = sector;
-
-    file.file_sector = sector;
-    file.file_bytesleft = (SECTOR_SIZE - (entries_left << DIRENT_SHIFT)) & 0xffff;
-    
-    regs->eax.l = dir->file_size;
-    regs->ebx.l = first_sector(dir);
-    regs->edx.b[0] = dir->attr;
-    
-    return;
-    
- fail:
-    //close_dir(dir);
-    regs->eax.l = 0;
-    regs->esi.w[0] = 0;
-    regs->eflags.l |= EFLAGS_CF;
+            return 1;
+        dir->dd_offset = 0;
+    } else {
+        dir->dd_offset = SECTOR_SIZE - (entries_left << 5);
+       }
+    dir->dd_sect = sector;     
+       return;
+
+ end:
+       /* Reach the end of this directory */
+       dir->dd_stat = -1;
 }
 
 static void vfat_load_config(com32sys_t *regs)
@@ -908,5 +897,6 @@ const struct fs_ops vfat_fs_ops = {
     .close_file    = vfat_close_file,
     .mangle_name   = vfat_mangle_name,
     .unmangle_name = generic_unmangle_name,
-    .load_config   = vfat_load_config
+    .load_config   = vfat_load_config,
+       .readdir       = vfat_readdir
 };
diff --git a/core/include/dir.h b/core/include/dir.h
new file mode 100644 (file)
index 0000000..454ca48
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef DIR_H
+#define DIR_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <com32.h>
+#include "disk.h"
+
+struct dirent {
+       uint32_t d_ino;
+       uint32_t d_off;
+       uint16_t d_reclen;
+       uint16_t d_type;
+       char d_name[256];
+};
+
+typedef struct {
+       uint16_t dd_stat;
+       uint16_t dd_sect;
+       sector_t dd_offset;
+       char dd_name[256];
+} DIR;
+
+#define DIR_REC_LEN(name) (12 + strlen(name) + 1 + 3) & ~3
+
+/*
+ * funtions 
+ */
+int fill_dir(struct dirent *);
+
+#endif /* dir.h */
index 04e85ef..d16a568 100644 (file)
@@ -7,6 +7,7 @@
 #include <com32.h>
 #include "core.h"
 #include "disk.h"
+#include "dir.h"
 
 /*
  * Maximum number of open files.  This is *currently* constrained by the
@@ -49,6 +50,9 @@ struct fs_ops {
     void     (*mangle_name)(char *, const char *);
     char *   (*unmangle_name)(char *, const char *);
     void     (*load_config)(com32sys_t *);
+
+       /* the _dir_ stuff */
+       void     (*readdir)(struct fs_info *, DIR *);
 };
 
 enum dev_type {CHS, EDD};
@@ -83,4 +87,12 @@ static inline bool not_whitespace(char c)
   return (unsigned char)c > ' ';
 }
 
+/* 
+ * functions
+ */
+void mangle_name(com32sys_t *);
+void searchdir(com32sys_t *);
+
+
+
 #endif /* FS_H */