diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/fs/hfs/hfs_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/hfs/hfs_fs.c')
-rw-r--r-- | qemu/roms/openbios/fs/hfs/hfs_fs.c | 593 |
1 files changed, 593 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/hfs/hfs_fs.c b/qemu/roms/openbios/fs/hfs/hfs_fs.c new file mode 100644 index 000000000..2d62ec0c6 --- /dev/null +++ b/qemu/roms/openbios/fs/hfs/hfs_fs.c @@ -0,0 +1,593 @@ +/* + * Creation Date: <2001/05/06 22:47:23 samuel> + * Time-stamp: <2004/01/12 10:24:35 samuel> + * + * /packages/hfs-files + * + * HFS world interface + * + * Copyright (C) 2001-2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2010 Mark Cave-Ayland (mark.cave-ayland@siriusit.co.uk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "fs/fs.h" +#include "libc/vsprintf.h" +#include "libc/diskio.h" +#include "libhfs.h" + +#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */ +#define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */ +#define MAC_OS_ROM_NAME "Mac OS ROM" + +#define FINDER_TYPE 0x464E4452 /* 'FNDR' */ +#define FINDER_CREATOR 0x4D414353 /* 'MACS' */ +#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */ +#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */ + +#define VOLNAME_SIZE 64 + +extern void hfs_init( void ); + +typedef struct { + enum { FILE, DIR } type; + union { + hfsdir *dir; + hfsfile *file; + }; +} hfscommon; + +typedef struct { + hfsvol *vol; + hfscommon *common; +} hfs_info_t; + +DECLARE_NODE( hfs, 0, sizeof(hfs_info_t), "+/packages/hfs-files" ); + +/************************************************************************/ +/* Search Functions */ +/************************************************************************/ + +static int +_find_file( hfsvol *vol, const char *path, unsigned long type, unsigned long creator ) +{ + hfsdirent ent; + hfsdir *dir; + int ret=1; + + if( !(dir=hfs_opendir(vol, path)) ) + return 1; + + while( ret && !hfs_readdir(dir, &ent) ) { + if( ent.flags & HFS_ISDIR ) + continue; + ret = !(*(unsigned long*)ent.u.file.type == type && *(unsigned long*)ent.u.file.creator == creator ); + } + + hfs_closedir( dir ); + return ret; +} + + +/* ret: 0=success, 1=not_found, 2=not_a_dir */ +static int +_search( hfsvol *vol, const char *path, const char *sname, hfsfile **ret_fd ) +{ + hfsdir *dir; + hfsdirent ent; + int topdir=0, status = 1; + char *p, buf[256]; + + strncpy( buf, path, sizeof(buf) ); + if( buf[strlen(buf)-1] != ':' ) + strncat( buf, ":", sizeof(buf) ); + buf[sizeof(buf)-1] = 0; + p = buf + strlen( buf ); + + if( !(dir=hfs_opendir(vol, path)) ) + return 2; + + /* printk("DIRECTORY: %s\n", path ); */ + + while( status && !hfs_readdir(dir, &ent) ) { + unsigned long type, creator; + + *p = 0; + topdir = 0; + + strncat( buf, ent.name, sizeof(buf) ); + if( (status=_search(vol, buf, sname, ret_fd)) != 2 ) + continue; + topdir = 1; + + /* name search? */ + if( sname ) { + status = strcasecmp( ent.name, sname ); + continue; + } + + type = *(unsigned long*)ent.u.file.type; + creator = *(unsigned long*)ent.u.file.creator; + + /* look for Mac OS ROM, System and Finder in the same directory */ + if( type == MAC_OS_ROM_TYPE && creator == MAC_OS_ROM_CREATOR ) { + if( strcasecmp(ent.name, MAC_OS_ROM_NAME) ) + continue; + + status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR ) + || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR ); + } + } + if( !status && topdir && ret_fd && !(*ret_fd=hfs_open(vol, buf)) ) { + printk("Unexpected error: failed to open matched ROM\n"); + status = 1; + } + + hfs_closedir( dir ); + return status; +} + +static hfsfile * +_do_search( hfs_info_t *mi, const char *sname ) +{ + hfsvol *vol = hfs_getvol( NULL ); + + mi->common->type = FILE; + (void)_search( vol, ":", sname, &mi->common->file ); + + return mi->common->file; +} + + +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 ) +{ + hfscommon *common = (hfscommon*)fd; + hfsdirent ent; + + if (common->type != DIR) + return; + + forth_printf("\n"); + while( !hfs_readdir(common->dir, &ent) ) { + forth_printf("% 10d ", ent.u.file.dsize); + print_date(ent.mddate); + if( ent.flags & HFS_ISDIR ) + forth_printf("%s\\\n", ent.name); + else + forth_printf("%s\n", ent.name); + } +} +*/ + +/************************************************************************/ +/* Standard package methods */ +/************************************************************************/ + +/* ( -- success? ) */ +static void +hfs_files_open( hfs_info_t *mi ) +{ + int fd; + char *path = my_args_copy(); + + const char *s; + char buf[256]; + + fd = open_ih( my_parent() ); + if ( fd == -1 ) { + free( path ); + RET( 0 ); + } + + mi->vol = hfs_mount(fd, 0); + if (!mi->vol) { + RET( 0 ); + } + + if( !strncmp(path, "\\\\", 2) ) { + hfsvolent ent; + + /* \\ is an alias for the (blessed) system folder */ + if( hfs_vstat(mi->vol, &ent) < 0 || hfs_setcwd(mi->vol, ent.blessed) ) { + free(path); + RET( -1 ); + } + path += 2; + } else { + hfs_chdir( mi->vol, ":" ); + } + + mi->common = malloc(sizeof(hfscommon)); + if (!mi->common) { + free(path); + RET( 0 ); + } + + if (strcmp(path, "\\") == 0) { + /* root directory is in fact ":" */ + mi->common->dir = hfs_opendir(mi->vol, ":"); + mi->common->type = DIR; + free(path); + RET( -1 ); + } + + if (path[strlen(path) - 1] == '\\') { + path[strlen(path) - 1] = 0; + } + + for( path-- ;; ) { + int n; + + s = ++path; + path = strchr(s, '\\'); + if( !path || !path[1]) + break; + n = MIN( sizeof(buf)-1, (path-s) ); + if( !n ) + continue; + + strncpy( buf, s, n ); + buf[n] = 0; + if( hfs_chdir(mi->vol, buf) ) { + free(mi->common); + free(path); + RET( 0 ); + } + } + + /* support the ':filetype' syntax */ + if( *s == ':' ) { + unsigned long id, oldid = hfs_getcwd(mi->vol); + hfsdirent ent; + hfsdir *dir; + + s++; + id = oldid; + hfs_dirinfo( mi->vol, &id, buf ); + hfs_setcwd( mi->vol, id ); + + if( !(dir=hfs_opendir(mi->vol, buf)) ) { + free(mi->common); + free(path); + RET( 0 ); + } + hfs_setcwd( mi->vol, oldid ); + + while( !hfs_readdir(dir, &ent) ) { + if( ent.flags & HFS_ISDIR ) + continue; + if( !strncmp(s, ent.u.file.type, 4) ) { + mi->common->type = FILE; + mi->common->file = hfs_open( mi->vol, ent.name ); + break; + } + } + hfs_closedir( dir ); + free(path); + RET( -1 ); + } + + mi->common->dir = hfs_opendir(mi->vol, s); + if (!mi->common->dir) { + mi->common->file = hfs_open( mi->vol, s ); + if (mi->common->file == NULL) { + free(mi->common); + free(path); + RET( 0 ); + } + mi->common->type = FILE; + free(path); + RET( -1 ); + } + mi->common->type = DIR; + free(path); + + RET( -1 ); +} + +/* ( -- ) */ +static void +hfs_files_close( hfs_info_t *mi ) +{ + hfscommon *common = mi->common; + if (common->type == FILE) + hfs_close( common->file ); + else if (common->type == DIR) + hfs_closedir( common->dir ); + free(common); +} + +/* ( buf len -- actlen ) */ +static void +hfs_files_read( hfs_info_t *mi ) +{ + int count = POP(); + char *buf = (char *)cell2pointer(POP()); + + hfscommon *common = mi->common; + if (common->type != FILE) + RET( -1 ); + + RET ( hfs_read( common->file, buf, count ) ); +} + +/* ( pos.d -- status ) */ +static void +hfs_files_seek( hfs_info_t *mi ) +{ + long long pos = DPOP(); + int offs = (int)pos; + int whence = SEEK_SET; + int ret; + hfscommon *common = mi->common; + + if (common->type != FILE) + RET( -1 ); + + switch( whence ) { + case SEEK_END: + whence = HFS_SEEK_END; + break; + default: + case SEEK_SET: + whence = HFS_SEEK_SET; + break; + } + + ret = hfs_seek( common->file, offs, whence ); + if (ret != -1) + RET( 0 ); + else + RET( -1 ); +} + +/* ( addr -- size ) */ +static void +hfs_files_load( hfs_info_t *mi ) +{ + char *buf = (char *)cell2pointer(POP()); + int count; + + hfscommon *common = mi->common; + if (common->type != FILE) + RET( -1 ); + + /* Seek to the end in order to get the file size */ + hfs_seek(common->file, 0, HFS_SEEK_END); + count = common->file->pos; + hfs_seek(common->file, 0, HFS_SEEK_SET); + + RET ( hfs_read( common->file, buf, count ) ); +} + +/* ( -- success? ) */ +static void +hfs_files_open_nwrom( hfs_info_t *mi ) +{ + /* Switch to an existing ROM image file on the fs! */ + if ( _do_search( mi, NULL ) ) + RET( -1 ); + + RET( 0 ); +} + +/* ( -- cstr ) */ +static void +hfs_files_get_path( hfs_info_t *mi ) +{ + char buf[256], buf2[256]; + hfscommon *common = mi->common; + hfsvol *vol = hfs_getvol( NULL ); + hfsdirent ent; + int start, ns; + unsigned long id; + + if (common->type != FILE) + RET( 0 ); + + hfs_fstat( common->file, &ent ); + start = sizeof(buf) - strlen(ent.name) - 1; + if( start <= 0 ) + RET ( 0 ); + strcpy( buf+start, ent.name ); + buf[--start] = '\\'; + + ns = start; + for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) { + start = ns; + ns -= strlen(buf2); + if( ns <= 0 ) + RET( 0 ); + strcpy( buf+ns, buf2 ); + buf[--ns] = buf[start] = '\\'; + } + if( strlen(buf) >= sizeof(buf) ) + RET( 0 ); + + RET( pointer2cell(strdup(buf+start)) ); +} + +/* ( -- cstr ) */ +static void +hfs_files_get_fstype( hfs_info_t *mi ) +{ + PUSH( pointer2cell(strdup("HFS")) ); +} + +/* ( -- cstr|0 ) */ +static void +hfs_files_volume_name( hfs_info_t *mi ) +{ + int fd; + char *volname = malloc(VOLNAME_SIZE); + + fd = open_ih(my_self()); + if (fd >= 0) { + get_hfs_vol_name(fd, volname, VOLNAME_SIZE); + close_io(fd); + } else { + volname[0] = '\0'; + } + + PUSH(pointer2cell(volname)); +} + +/* static method, ( pathstr len ihandle -- ) */ +static void +hfs_files_dir( hfs_info_t *dummy ) +{ + hfsvol *volume; + hfscommon *common; + hfsdirent ent; + int i; + int fd; + + ihandle_t ih = POP(); + char *path = pop_fstr_copy(); + + fd = open_ih( ih ); + if ( fd == -1 ) { + free( path ); + return; + } + + volume = hfs_mount(fd, 0); + if (!volume) { + return; + } + + common = malloc(sizeof(hfscommon)); + + /* HFS paths are colon separated, not backslash separated */ + for (i = 0; i < strlen(path); i++) + if (path[i] == '\\') + path[i] = ':'; + + common->dir = hfs_opendir(volume, path); + + forth_printf("\n"); + while( !hfs_readdir(common->dir, &ent) ) { + forth_printf("% 10ld ", ent.u.file.dsize); + print_date(ent.mddate); + if( ent.flags & HFS_ISDIR ) + forth_printf("%s\\\n", ent.name); + else + forth_printf("%s\n", ent.name); + } + + hfs_closedir( common->dir ); + hfs_umount( volume ); + + close_io( fd ); + + free( common ); + free( path ); +} + +/* static method, ( pos.d ih -- flag? ) */ +static void +hfs_files_probe( hfs_info_t *dummy ) +{ + ihandle_t ih = POP_ih(); + long long offs = DPOP(); + int fd, ret = 0; + + fd = open_ih(ih); + if (fd >= 0) { + if (hfs_probe(fd, offs)) { + ret = -1; + } + close_io(fd); + } else { + ret = -1; + } + + RET (ret); +} + +static void +hfs_initializer( hfs_info_t *dummy ) +{ + fword("register-fs-package"); +} + +NODE_METHODS( hfs ) = { + { "probe", hfs_files_probe }, + { "open", hfs_files_open }, + { "close", hfs_files_close }, + { "read", hfs_files_read }, + { "seek", hfs_files_seek }, + { "load", hfs_files_load }, + { "dir", hfs_files_dir }, + + /* special */ + { "open-nwrom", hfs_files_open_nwrom }, + { "get-path", hfs_files_get_path }, + { "get-fstype", hfs_files_get_fstype }, + { "volume-name", hfs_files_volume_name }, + + { NULL, hfs_initializer }, +}; + +void +hfs_init( void ) +{ + REGISTER_NODE( hfs ); +} |