diff --git a/fs/ext2/ext2_fs.c b/fs/ext2/ext2_fs.c index 22388da..d6dab84 100644 --- a/fs/ext2/ext2_fs.c +++ b/fs/ext2/ext2_fs.c @@ -9,6 +9,15 @@ #include "libext2.h" #include "ext2_utils.h" #include "openbios/fs.h" +#include "libc/vsprintf.h" + +typedef struct { + enum { FILE, DIR } type; + union { + ext2_FILE *file; + ext2_DIR *dir; + }; +} ext2_COMMON; static void umount( fs_ops_t *fs ) @@ -18,23 +27,110 @@ umount( fs_ops_t *fs ) ext2_umount( volume ); } +static const int days_month[12] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static const int days_month_leap[12] = + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static inline int is_leap(int year) +{ + return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); +} + +static void +print_date(time_t sec) +{ + unsigned int second, minute, hour, month, day, year; + int current; + const int *days; + + second = sec % 60; + sec /= 60; + + minute = sec % 60; + sec /= 60; + + hour = sec % 24; + sec /= 24; + + year = sec * 100 / 36525; + sec -= year * 36525 / 100; + year += 1970; + + days = is_leap(year) ? days_month_leap : days_month; + + current = 0; + month = 0; + while (month < 12) { + if (sec <= current + days[month]) { + break; + } + current += days[month]; + month++; + } + month++; + + day = sec - current + 1; + + forth_printf("%d-%02d-%02d %02d:%02d:%02d ", + year, month, day, hour, minute, second); +} + +static void +dir_fs ( file_desc_t *fd) +{ + ext2_COMMON *common = (ext2_COMMON *)fd; + struct ext2_dir_entry_2 *entry; + struct ext2_inode inode; + + if (common->type != DIR) + return; + + forth_printf("\n"); + while ( (entry = ext2_readdir(common->dir)) ) { + ext2_get_inode(common->dir->volume, entry->inode, &inode); + forth_printf("% 10d ", inode.i_size); + print_date(inode.i_mtime); + if (S_ISDIR(inode.i_mode)) + forth_printf("%s\\\n", entry->name); + else + forth_printf("%s\n", entry->name); + } +} + static file_desc_t * open_path( fs_ops_t *fs, const char *path ) { ext2_VOLUME *volume = (ext2_VOLUME *)fs->fs_data; - ext2_FILE *file; + ext2_COMMON *common; - file = ext2_open(volume, path); + common = (ext2_COMMON*)malloc(sizeof(*common)); + if (common == NULL) + return NULL; - return (file_desc_t *)file; + common->dir = ext2_opendir(volume, path); + if (common->dir == NULL) { + common->file = ext2_open(volume, path); + if (common->file == NULL) { + free(common); + return NULL; + } + common->type = FILE; + return (file_desc_t *)common; + } + common->type = DIR; + return (file_desc_t *)common; } static char * get_path( file_desc_t *fd, char *buf, int size ) { - ext2_FILE *file = (ext2_FILE *)fd; + ext2_COMMON *common =(ext2_COMMON *)fd; - strncpy(buf, file->path, size); + if (common->type != FILE) + return NULL; + + strncpy(buf, common->file->path, size); return buf; } @@ -42,25 +138,35 @@ get_path( file_desc_t *fd, char *buf, int size ) static int file_lseek( file_desc_t *fd, off_t offs, int whence ) { - ext2_FILE *file = (ext2_FILE *)fd; + ext2_COMMON *common =(ext2_COMMON *)fd; - return ext2_lseek(file, offs, whence); + if (common->type != FILE) + return -1; + + return ext2_lseek(common->file, offs, whence); } static void file_close( file_desc_t *fd ) { - ext2_FILE *file = (ext2_FILE *)fd; + ext2_COMMON *common =(ext2_COMMON *)fd; - ext2_close(file); + if (common->type == FILE) + ext2_close(common->file); + else if (common->type == DIR) + ext2_closedir(common->dir); + free(common); } static int file_read( file_desc_t *fd, void *buf, size_t count ) { - ext2_FILE *file = (ext2_FILE *)fd; + ext2_COMMON *common =(ext2_COMMON *)fd; - return ext2_read(file, buf, count); + if (common->type != FILE) + return -1; + + return ext2_read(common->file, buf, count); } static const char * @@ -70,6 +176,7 @@ get_fstype( fs_ops_t *fs) } static const fs_ops_t ext2_ops = { + .dir = dir_fs, .close_fs = umount, .open_path = open_path,