mirror of
				https://gitlab.com/qemu-project/openbios.git
				synced 2024-02-13 08:34:06 +08:00 
			
		
		
		
	 51067854a7
			
		
	
	51067854a7
	
	
	
		
			
			Fix up warnings generated by building with -Werror under gcc 9. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
		
			
				
	
	
		
			594 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			594 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *   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) - 1 );
 | |
| 	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) - 1);
 | |
| 		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 );
 | |
| }
 |