From 6fcebf4ed2be8de96ff106c3755c7776f1c66804 Mon Sep 17 00:00:00 2001 From: Liu Aleaxander Date: Thu, 27 Aug 2009 07:37:44 +0800 Subject: [PATCH] Core: opendir/readdir/closedir stuff added 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 --- com32/include/dirent.h | 15 +++-- com32/lib/closedir.c | 26 ++++---- com32/lib/opendir.c | 20 +++--- com32/lib/readdir.c | 40 ++--------- com32/modules/Makefile | 2 +- com32/modules/dir.c | 35 ++++++++++ com32/rosh/rosh.c | 11 ++-- core/comboot.inc | 18 ++--- core/dir.c | 84 +++++++++++++++++++++++ core/extern.inc | 6 +- core/fs.c | 1 + core/fs/fat/fat.c | 176 +++++++++++++++++++++++-------------------------- core/include/dir.h | 32 +++++++++ core/include/fs.h | 12 ++++ 14 files changed, 297 insertions(+), 181 deletions(-) create mode 100644 com32/modules/dir.c create mode 100644 core/dir.c create mode 100644 core/include/dir.h diff --git a/com32/include/dirent.h b/com32/include/dirent.h index d99b21f..0fc2e13 100644 --- a/com32/include/dirent.h +++ b/com32/include/dirent.h @@ -15,17 +15,18 @@ #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 *); diff --git a/com32/lib/closedir.c b/com32/lib/closedir.c index f8bbbab..dcf1704 100644 --- a/com32/lib/closedir.c +++ b/com32/lib/closedir.c @@ -13,17 +13,19 @@ int closedir(DIR * dir) { - int rv; - com32sys_t regs; - if (dir == NULL) { + int rv = -1; + + if (dir) { + /* + com32sys_t regs; + memset(®s, 0, sizeof regs); + regs.eax.w[0] = 0x0022; + regs.esi.l = OFFS_WRT(dir, 0); + __com32.cs_intcall(0x22, ®s, ®s); + */ + free(dir); rv = 0; - } else { - memset(®s, 0, sizeof regs); /* ?Needed? */ - regs.eax.w[0] = 0x0022; - regs.esi.w[0] = dir->dd_fd; - __com32.cs_intcall(0x22, ®s, ®s); - free(dir); /* garbage collection? */ - rv = 0; - } - return rv; + } + + return rv; } diff --git a/com32/lib/opendir.c b/com32/lib/opendir.c index 6fc0f14..669a04a 100644 --- a/com32/lib/opendir.c +++ b/com32/lib/opendir.c @@ -13,11 +13,9 @@ 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, ®s, ®s); - + 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 */ diff --git a/com32/lib/readdir.c b/com32/lib/readdir.c index 2ec7c7b..7fca476 100644 --- a/com32/lib/readdir.c +++ b/com32/lib/readdir.c @@ -13,42 +13,16 @@ 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(®s, 0, sizeof(regs)); - + + if ((dir !=NULL) && (dir->dd_sect != 0) && (dir->dd_stat != 0xffff)) { + memset(®s, 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, ®s, ®s); - - /* 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; } diff --git a/com32/modules/Makefile b/com32/modules/Makefile index e0e103b..23cd31f 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -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 index 0000000..a3c9815 --- /dev/null +++ b/com32/modules/dir.c @@ -0,0 +1,35 @@ +/* + * A dir test module + */ +#include +#include +#include +#include +#include + +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; +} + diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c index 631c780..c634a94 100644 --- a/com32/rosh/rosh.c +++ b/com32/rosh/rosh.c @@ -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); diff --git a/core/comboot.inc b/core/comboot.inc index 28f0bc2..b078aa5 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -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 index 0000000..0701125 --- /dev/null +++ b/core/dir.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include + +/* 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; +} + + diff --git a/core/extern.inc b/core/extern.inc index d944bb1..37024ec 100644 --- a/core/extern.inc +++ b/core/extern.inc @@ -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 diff --git a/core/fs.c b/core/fs.c index 2804468..1730378 100644 --- 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; diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index 2f0bac7..f219995 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -4,6 +4,7 @@ #include #include #include +#include #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 index 0000000..454ca48 --- /dev/null +++ b/core/include/dir.h @@ -0,0 +1,32 @@ +#ifndef DIR_H +#define DIR_H + +#include +#include +#include +#include +#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 */ diff --git a/core/include/fs.h b/core/include/fs.h index 04e85ef..d16a568 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -7,6 +7,7 @@ #include #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 */ -- 2.7.4