diff options
author | 2015-08-28 09:58:54 +0800 | |
---|---|---|
committer | 2015-09-01 12:44:00 +0800 | |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/fs/ext2/ext2_fs.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openbios/fs/ext2/ext2_fs.c')
-rw-r--r-- | qemu/roms/openbios/fs/ext2/ext2_fs.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/ext2/ext2_fs.c b/qemu/roms/openbios/fs/ext2/ext2_fs.c new file mode 100644 index 000000000..66eb0b438 --- /dev/null +++ b/qemu/roms/openbios/fs/ext2/ext2_fs.c @@ -0,0 +1,309 @@ +/* + * /packages/ext2-files + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * (c) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "libext2.h" +#include "ext2_utils.h" +#include "fs/fs.h" +#include "libc/vsprintf.h" +#include "libc/diskio.h" + +extern void ext2_init( void ); + +typedef struct { + enum { FILE, DIR } type; + union { + ext2_FILE *file; + ext2_DIR *dir; + }; +} ext2_COMMON; + +typedef struct { + ext2_VOLUME *volume; + ext2_COMMON *common; +} ext2_info_t; + +DECLARE_NODE( ext2, 0, sizeof(ext2_info_t), "+/packages/ext2-files" ); + + +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); +} + + +/************************************************************************/ +/* Standard package methods */ +/************************************************************************/ + +/* ( -- success? ) */ +static void +ext2_files_open( ext2_info_t *mi ) +{ + int fd; + char *path = my_args_copy(); + + fd = open_ih( my_parent() ); + if ( fd == -1 ) { + free( path ); + RET( 0 ); + } + + mi->volume = ext2_mount(fd); + if (!mi->volume) { + RET( 0 ); + } + + mi->common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON)); + if (mi->common == NULL) + RET( 0 ); + + mi->common->dir = ext2_opendir(mi->volume, path); + if (mi->common->dir == NULL) { + mi->common->file = ext2_open(mi->volume, path); + if (mi->common->file == NULL) { + free(mi->common); + RET( 0 ); + } + mi->common->type = FILE; + RET( -1 ); + } + mi->common->type = DIR; + RET( -1 ); +} + +/* ( -- ) */ +static void +ext2_files_close( ext2_info_t *mi ) +{ + ext2_COMMON *common = mi->common; + + if (common->type == FILE) + ext2_close(common->file); + else if (common->type == DIR) + ext2_closedir(common->dir); + free(common); + + ext2_umount(mi->volume); +} + +/* ( buf len -- actlen ) */ +static void +ext2_files_read( ext2_info_t *mi ) +{ + int count = POP(); + char *buf = (char *)cell2pointer(POP()); + + ext2_COMMON *common = mi->common; + if (common->type != FILE) + RET( -1 ); + + RET ( ext2_read( common->file, buf, count ) ); +} + +/* ( pos.d -- status ) */ +static void +ext2_files_seek( ext2_info_t *mi ) +{ + long long pos = DPOP(); + int offs = (int)pos; + int whence = SEEK_SET; + int ret; + ext2_COMMON *common = mi->common; + + if (common->type != FILE) + RET( -1 ); + + ret = ext2_lseek(common->file, offs, whence); + if (ret) + RET( -1 ); + else + RET( 0 ); +} + +/* ( addr -- size ) */ +static void +ext2_files_load( ext2_info_t *mi ) +{ + char *buf = (char *)cell2pointer(POP()); + int count; + + ext2_COMMON *common = mi->common; + if (common->type != FILE) + RET( -1 ); + + /* Seek to the end in order to get the file size */ + ext2_lseek(common->file, 0, SEEK_END); + count = common->file->offset; + ext2_lseek(common->file, 0, SEEK_SET); + + RET ( ext2_read( common->file, buf, count ) ); +} + +/* ( -- cstr ) */ +static void +ext2_files_get_path( ext2_info_t *mi ) +{ + ext2_COMMON *common = mi->common; + + if (common->type != FILE) + RET( 0 ); + + RET( pointer2cell(strdup(common->file->path)) ); +} + +/* ( -- cstr ) */ +static void +ext2_files_get_fstype( ext2_info_t *mi ) +{ + PUSH( pointer2cell(strdup("ext2")) ); +} + +/* static method, ( pathstr len ihandle -- ) */ +static void +ext2_files_dir( ext2_info_t *dummy ) +{ + ext2_COMMON *common; + ext2_VOLUME *volume; + struct ext2_dir_entry_2 *entry; + struct ext2_inode inode; + int fd; + + ihandle_t ih = POP(); + char *path = pop_fstr_copy(); + + fd = open_ih( ih ); + if ( fd == -1 ) { + free( path ); + return; + } + + volume = ext2_mount(fd); + if (!volume) { + return; + } + + common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON)); + common->dir = ext2_opendir(volume, path); + + 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); + } + + ext2_closedir( common->dir ); + ext2_umount( volume ); + + close_io( fd ); + + free( common ); + free( path ); +} + +/* static method, ( pos.d ih -- flag? ) */ +static void +ext2_files_probe( ext2_info_t *dummy ) +{ + ihandle_t ih = POP_ih(); + long long offs = DPOP(); + int fd, ret = 0; + + fd = open_ih(ih); + if (fd >= 0) { + if (ext2_probe(fd, offs)) { + ret = -1; + } + close_io(fd); + } else { + ret = -1; + } + + RET (ret); +} + + +static void +ext2_initializer( ext2_info_t *dummy ) +{ + fword("register-fs-package"); +} + +NODE_METHODS( ext2 ) = { + { "probe", ext2_files_probe }, + { "open", ext2_files_open }, + { "close", ext2_files_close }, + { "read", ext2_files_read }, + { "seek", ext2_files_seek }, + { "load", ext2_files_load }, + { "dir", ext2_files_dir }, + + /* special */ + { "get-path", ext2_files_get_path }, + { "get-fstype", ext2_files_get_fstype }, + + { NULL, ext2_initializer }, +}; + +void +ext2_init( void ) +{ + REGISTER_NODE( ext2 ); +} |