diff options
Diffstat (limited to 'roms/openbios/fs')
106 files changed, 23649 insertions, 0 deletions
diff --git a/roms/openbios/fs/build.xml b/roms/openbios/fs/build.xml new file mode 100644 index 00000000..9ecc0055 --- /dev/null +++ b/roms/openbios/fs/build.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<build> + + <library name="fs" type="static" target="target"> +  <object source="ioglue.c"/> + </library> +	 + <include href="grubfs/build.xml"/> + <include href="hfs/build.xml"/> + <include href="hfsplus/build.xml"/> + <include href="iso9660/build.xml"/> + <include href="ext2/build.xml"/> + +</build> diff --git a/roms/openbios/fs/ext2/build.xml b/roms/openbios/fs/ext2/build.xml new file mode 100644 index 00000000..98e9e056 --- /dev/null +++ b/roms/openbios/fs/ext2/build.xml @@ -0,0 +1,14 @@ +<build> + <library name="fs" type="static" target="target"> +  <object source="ext2_close.c" condition="EXT2"/> +  <object source="ext2_closedir.c" condition="EXT2"/> +  <object source="ext2_fs.c" condition="EXT2"/> +  <object source="ext2_lseek.c" condition="EXT2"/> +  <object source="ext2_mount.c" condition="EXT2"/> +  <object source="ext2_open.c" condition="EXT2"/> +  <object source="ext2_opendir.c" condition="EXT2"/> +  <object source="ext2_read.c" condition="EXT2"/> +  <object source="ext2_readdir.c" condition="EXT2"/> +  <object source="ext2_utils.c" condition="EXT2"/> + </library> +</build> diff --git a/roms/openbios/fs/ext2/ext2.h b/roms/openbios/fs/ext2/ext2.h new file mode 100644 index 00000000..ad858928 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2.h @@ -0,0 +1,33 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#ifndef __EXT2_H__ +#define __EXT2_H__ + +#include "ext2_fs.h" + +typedef struct ext2_VOLUME { +        int fd; +	struct ext2_super_block *super; +	unsigned int current; +	char *buffer; +} ext2_VOLUME; + +typedef struct ext2_DIR { +        ext2_VOLUME *volume; +	struct ext2_inode *inode; +	off_t index; +} ext2_DIR; + +typedef struct ext2_FILE { +        ext2_VOLUME *volume; +	struct ext2_inode *inode; +	off_t offset; +	char *path; +} ext2_FILE; +#endif /* __LIBEXT2_H__ */ diff --git a/roms/openbios/fs/ext2/ext2_close.c b/roms/openbios/fs/ext2/ext2_close.c new file mode 100644 index 00000000..f370e181 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_close.c @@ -0,0 +1,18 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" + +void ext2_close(ext2_FILE *file) +{ +	if (file == NULL) +		return; +	free(file->inode); +	free(file->path); +	free(file); +} diff --git a/roms/openbios/fs/ext2/ext2_closedir.c b/roms/openbios/fs/ext2/ext2_closedir.c new file mode 100644 index 00000000..e9f06319 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_closedir.c @@ -0,0 +1,18 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" + +void ext2_closedir(ext2_DIR *dir) +{ +	if (dir == NULL) +		return; +	free(dir->inode); +	free(dir); +} diff --git a/roms/openbios/fs/ext2/ext2_fs.c b/roms/openbios/fs/ext2/ext2_fs.c new file mode 100644 index 00000000..66eb0b43 --- /dev/null +++ b/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 ); +} diff --git a/roms/openbios/fs/ext2/ext2_fs.h b/roms/openbios/fs/ext2/ext2_fs.h new file mode 100644 index 00000000..4a7adff7 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_fs.h @@ -0,0 +1,534 @@ +/* + *  This file has been copied from + *  linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + *  from + * + *  linux/include/linux/minix_fs.h + * + *  Copyright (C) 1991, 1992  Linus Torvalds + */ + +#ifndef _EXT2_FS_H +#define _EXT2_FS_H + +/* from /usr/include/linux/magic.h */ + +#define EXT2_SUPER_MAGIC	0xEF53 + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2_RESERVATION to reserve data blocks for expanding files + */ +#define EXT2_DEFAULT_RESERVE_BLOCKS     8 +/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */ +#define EXT2_MAX_RESERVE_BLOCKS         1027 +#define EXT2_RESERVE_WINDOW_NOT_ALLOCATED 0 +/* + * The second extended file system version + */ +#define EXT2FS_DATE		"95/08/09" +#define EXT2FS_VERSION		"0.5b" + +/* + * Debug code + */ +#ifdef EXT2FS_DEBUG +#	define ext2_debug(f, a...)	{ \ +					printk ("EXT2-fs DEBUG (%s, %d): %s:", \ +						__FILE__, __LINE__, __FUNCTION__); \ +				  	printk (f, ## a); \ +					} +#else +#	define ext2_debug(f, a...)	/**/ +#endif + +/* + * Special inode numbers + */ +#define	EXT2_BAD_INO		 1	/* Bad blocks inode */ +#define EXT2_ROOT_INO		 2	/* Root inode */ +#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO	11 + +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block.  This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb)	(sb) + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX		32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE		1024 +#define	EXT2_MAX_BLOCK_SIZE		4096 +#define EXT2_MIN_BLOCK_LOG_SIZE		  10 +# define EXT2_BLOCK_SIZE(s)		(EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (uint32_t)) +# define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10) +#define EXT2_INODE_SIZE(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ +				 EXT2_GOOD_OLD_INODE_SIZE : \ +				 (s)->s_inode_size) +#define EXT2_FIRST_INO(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ +				 EXT2_GOOD_OLD_FIRST_INO : \ +				 (s)->s_first_ino) + +/* + * Macro-instructions used to manage fragments + */ +#define EXT2_MIN_FRAG_SIZE		1024 +#define	EXT2_MAX_FRAG_SIZE		4096 +#define EXT2_MIN_FRAG_LOG_SIZE		  10 +# define EXT2_FRAG_SIZE(s)		(EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ +	uint32_t	bg_block_bitmap;		/* Blocks bitmap block */ +	uint32_t	bg_inode_bitmap;		/* Inodes bitmap block */ +	uint32_t	bg_inode_table;		/* Inodes table block */ +	uint16_t	bg_free_blocks_count;	/* Free blocks count */ +	uint16_t	bg_free_inodes_count;	/* Free inodes count */ +	uint16_t	bg_used_dirs_count;	/* Directories count */ +	uint16_t	bg_pad; +	uint32_t	bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +# define EXT2_BLOCKS_PER_GROUP(s)	((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s)	((s)->s_inodes_per_group) + +/* + * Constants relative to the data blocks + */ +#define	EXT2_NDIR_BLOCKS		12 +#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS +#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1) +#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1) +#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1) + +/* + * Inode flags (GETFLAGS/SETFLAGS) + */ +#define	EXT2_SECRM_FL			FS_SECRM_FL	/* Secure deletion */ +#define	EXT2_UNRM_FL			FS_UNRM_FL	/* Undelete */ +#define	EXT2_COMPR_FL			FS_COMPR_FL	/* Compress file */ +#define EXT2_SYNC_FL			FS_SYNC_FL	/* Synchronous updates */ +#define EXT2_IMMUTABLE_FL		FS_IMMUTABLE_FL	/* Immutable file */ +#define EXT2_APPEND_FL			FS_APPEND_FL	/* writes to file may only append */ +#define EXT2_NODUMP_FL			FS_NODUMP_FL	/* do not dump file */ +#define EXT2_NOATIME_FL			FS_NOATIME_FL	/* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL			FS_DIRTY_FL +#define EXT2_COMPRBLK_FL		FS_COMPRBLK_FL	/* One or more compressed clusters */ +#define EXT2_NOCOMP_FL			FS_NOCOMP_FL	/* Don't compress */ +#define EXT2_ECOMPR_FL			FS_ECOMPR_FL	/* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL			FS_BTREE_FL	/* btree format dir */ +#define EXT2_INDEX_FL			FS_INDEX_FL	/* hash-indexed directory */ +#define EXT2_IMAGIC_FL			FS_IMAGIC_FL	/* AFS directory */ +#define EXT2_JOURNAL_DATA_FL		FS_JOURNAL_DATA_FL /* Reserved for ext3 */ +#define EXT2_NOTAIL_FL			FS_NOTAIL_FL	/* file tail should not be merged */ +#define EXT2_DIRSYNC_FL			FS_DIRSYNC_FL	/* dirsync behaviour (directories only) */ +#define EXT2_TOPDIR_FL			FS_TOPDIR_FL	/* Top of directory hierarchies*/ +#define EXT2_RESERVED_FL		FS_RESERVED_FL	/* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE		FS_FL_USER_VISIBLE	/* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE		FS_FL_USER_MODIFIABLE	/* User modifiable flags */ + +/* + * ioctl commands + */ +#define	EXT2_IOC_GETFLAGS		FS_IOC_GETFLAGS +#define	EXT2_IOC_SETFLAGS		FS_IOC_SETFLAGS +#define	EXT2_IOC_GETVERSION		FS_IOC_GETVERSION +#define	EXT2_IOC_SETVERSION		FS_IOC_SETVERSION +#define	EXT2_IOC_GETRSVSZ		_IOR('f', 5, long) +#define	EXT2_IOC_SETRSVSZ		_IOW('f', 6, long) + +/* + * ioctl commands in 32 bit emulation + */ +#define EXT2_IOC32_GETFLAGS		FS_IOC32_GETFLAGS +#define EXT2_IOC32_SETFLAGS		FS_IOC32_SETFLAGS +#define EXT2_IOC32_GETVERSION		FS_IOC32_GETVERSION +#define EXT2_IOC32_SETVERSION		FS_IOC32_SETVERSION + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { +	uint16_t	i_mode;		/* File mode */ +	uint16_t	i_uid;		/* Low 16 bits of Owner Uid */ +	uint32_t	i_size;		/* Size in bytes */ +	uint32_t	i_atime;	/* Access time */ +	uint32_t	i_ctime;	/* Creation time */ +	uint32_t	i_mtime;	/* Modification time */ +	uint32_t	i_dtime;	/* Deletion Time */ +	uint16_t	i_gid;		/* Low 16 bits of Group Id */ +	uint16_t	i_links_count;	/* Links count */ +	uint32_t	i_blocks;	/* Blocks count */ +	uint32_t	i_flags;	/* File flags */ +	union { +		struct { +			uint32_t  l_i_reserved1; +		} linux1; +		struct { +			uint32_t  h_i_translator; +		} hurd1; +		struct { +			uint32_t  m_i_reserved1; +		} masix1; +	} osd1;				/* OS dependent 1 */ +	uint32_t	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ +	uint32_t	i_generation;	/* File version (for NFS) */ +	uint32_t	i_file_acl;	/* File ACL */ +	uint32_t	i_dir_acl;	/* Directory ACL */ +	uint32_t	i_faddr;	/* Fragment address */ +	union { +		struct { +			uint8_t	l_i_frag;	/* Fragment number */ +			uint8_t	l_i_fsize;	/* Fragment size */ +			uint16_t	i_pad1; +			uint16_t	l_i_uid_high;	/* these 2 fields    */ +			uint16_t	l_i_gid_high;	/* were reserved2[0] */ +			uint32_t	l_i_reserved2; +		} linux2; +		struct { +			uint8_t	h_i_frag;	/* Fragment number */ +			uint8_t	h_i_fsize;	/* Fragment size */ +			uint16_t	h_i_mode_high; +			uint16_t	h_i_uid_high; +			uint16_t	h_i_gid_high; +			uint32_t	h_i_author; +		} hurd2; +		struct { +			uint8_t	m_i_frag;	/* Fragment number */ +			uint8_t	m_i_fsize;	/* Fragment size */ +			uint16_t	m_pad1; +			uint32_t	m_i_reserved2[2]; +		} masix2; +	} osd2;				/* OS dependent 2 */ +}; + +#define i_size_high	i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1	osd1.linux1.l_i_reserved1 +#define i_frag		osd2.linux2.l_i_frag +#define i_fsize		osd2.linux2.l_i_fsize +#define i_uid_low	i_uid +#define i_gid_low	i_gid +#define i_uid_high	osd2.linux2.l_i_uid_high +#define i_gid_high	osd2.linux2.l_i_gid_high +#define i_reserved2	osd2.linux2.l_i_reserved2 +#endif + +#ifdef	__hurd__ +#define i_translator	osd1.hurd1.h_i_translator +#define i_frag		osd2.hurd2.h_i_frag; +#define i_fsize		osd2.hurd2.h_i_fsize; +#define i_uid_high	osd2.hurd2.h_i_uid_high +#define i_gid_high	osd2.hurd2.h_i_gid_high +#define i_author	osd2.hurd2.h_i_author +#endif + +#ifdef	__masix__ +#define i_reserved1	osd1.masix1.m_i_reserved1 +#define i_frag		osd2.masix2.m_i_frag +#define i_fsize		osd2.masix2.m_i_fsize +#define i_reserved2	osd2.masix2.m_i_reserved2 +#endif + +/* + * File system states + */ +#define	EXT2_VALID_FS			0x0001	/* Unmounted cleanly */ +#define	EXT2_ERROR_FS			0x0002	/* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK		0x000001  /* Do mount-time checks */ +#define EXT2_MOUNT_OLDALLOC		0x000002  /* Don't use the new Orlov allocator */ +#define EXT2_MOUNT_GRPID		0x000004  /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG		0x000008  /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT		0x000010  /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO		0x000020  /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC		0x000040  /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF		0x000080  /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NOBH			0x000100  /* No buffer_heads */ +#define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */ +#define EXT2_MOUNT_XATTR_USER		0x004000  /* Extended user attributes */ +#define EXT2_MOUNT_POSIX_ACL		0x008000  /* POSIX Access Control Lists */ +#define EXT2_MOUNT_XIP			0x010000  /* Execute in place */ +#define EXT2_MOUNT_USRQUOTA		0x020000  /* user quota */ +#define EXT2_MOUNT_GRPQUOTA		0x040000  /* group quota */ +#define EXT2_MOUNT_RESERVATION		0x080000  /* Preallocation */ + + +#define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt)			o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt)		(EXT2_SB(sb)->s_mount_opt & \ +					 EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE		1	/* Continue execution */ +#define EXT2_ERRORS_RO			2	/* Remount fs read-only */ +#define EXT2_ERRORS_PANIC		3	/* Panic */ +#define EXT2_ERRORS_DEFAULT		EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext2_super_block { +	uint32_t	s_inodes_count;		/* Inodes count */ +	uint32_t	s_blocks_count;		/* Blocks count */ +	uint32_t	s_r_blocks_count;	/* Reserved blocks count */ +	uint32_t	s_free_blocks_count;	/* Free blocks count */ +	uint32_t	s_free_inodes_count;	/* Free inodes count */ +	uint32_t	s_first_data_block;	/* First Data Block */ +	uint32_t	s_log_block_size;	/* Block size */ +	uint32_t	s_log_frag_size;	/* Fragment size */ +	uint32_t	s_blocks_per_group;	/* # Blocks per group */ +	uint32_t	s_frags_per_group;	/* # Fragments per group */ +	uint32_t	s_inodes_per_group;	/* # Inodes per group */ +	uint32_t	s_mtime;		/* Mount time */ +	uint32_t	s_wtime;		/* Write time */ +	uint16_t	s_mnt_count;		/* Mount count */ +	uint16_t	s_max_mnt_count;	/* Maximal mount count */ +	uint16_t	s_magic;		/* Magic signature */ +	uint16_t	s_state;		/* File system state */ +	uint16_t	s_errors;		/* Behaviour when detecting errors */ +	uint16_t	s_minor_rev_level; 	/* minor revision level */ +	uint32_t	s_lastcheck;		/* time of last check */ +	uint32_t	s_checkinterval;	/* max. time between checks */ +	uint32_t	s_creator_os;		/* OS */ +	uint32_t	s_rev_level;		/* Revision level */ +	uint16_t	s_def_resuid;		/* Default uid for reserved blocks */ +	uint16_t	s_def_resgid;		/* Default gid for reserved blocks */ +	/* +	 * These fields are for EXT2_DYNAMIC_REV superblocks only. +	 * +	 * Note: the difference between the compatible feature set and +	 * the incompatible feature set is that if there is a bit set +	 * in the incompatible feature set that the kernel doesn't +	 * know about, it should refuse to mount the filesystem. +	 * +	 * e2fsck's requirements are more strict; if it doesn't know +	 * about a feature in either the compatible or incompatible +	 * feature set, it must abort and not try to meddle with +	 * things it doesn't understand... +	 */ +	uint32_t	s_first_ino; 		/* First non-reserved inode */ +	uint16_t   s_inode_size; 		/* size of inode structure */ +	uint16_t	s_block_group_nr; 	/* block group # of this superblock */ +	uint32_t	s_feature_compat; 	/* compatible feature set */ +	uint32_t	s_feature_incompat; 	/* incompatible feature set */ +	uint32_t	s_feature_ro_compat; 	/* readonly-compatible feature set */ +	uint8_t	s_uuid[16];		/* 128-bit uuid for volume */ +	char	s_volume_name[16]; 	/* volume name */ +	char	s_last_mounted[64]; 	/* directory where last mounted */ +	uint32_t	s_algorithm_usage_bitmap; /* For compression */ +	/* +	 * Performance hints.  Directory preallocation should only +	 * happen if the EXT2_COMPAT_PREALLOC flag is on. +	 */ +	uint8_t	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/ +	uint8_t	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */ +	uint16_t	s_padding1; +	/* +	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. +	 */ +	uint8_t	s_journal_uuid[16];	/* uuid of journal superblock */ +	uint32_t	s_journal_inum;		/* inode number of journal file */ +	uint32_t	s_journal_dev;		/* device number of journal file */ +	uint32_t	s_last_orphan;		/* start of list of inodes to delete */ +	uint32_t	s_hash_seed[4];		/* HTREE hash seed */ +	uint8_t	s_def_hash_version;	/* Default hash version to use */ +	uint8_t	s_reserved_char_pad; +	uint16_t	s_reserved_word_pad; +	uint32_t	s_default_mount_opts; + 	uint32_t	s_first_meta_bg; 	/* First metablock block group */ +	uint32_t	s_reserved[190];	/* Padding to the end of the block */ +}; + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX		0 +#define EXT2_OS_HURD		1 +#define EXT2_OS_MASIX		2 +#define EXT2_OS_FREEBSD		3 +#define EXT2_OS_LITES		4 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV	0	/* The good old (original) format */ +#define EXT2_DYNAMIC_REV	1 	/* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\ +	( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\ +	( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\ +	( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT2_SET_COMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)			\ +	EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INO		0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020 +#define EXT2_FEATURE_COMPAT_ANY			0xffffffff + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004 +#define EXT2_FEATURE_RO_COMPAT_ANY		0xffffffff + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010 +#define EXT2_FEATURE_INCOMPAT_ANY		0xffffffff + +#define EXT2_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \ +					 EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ +					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ +					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT2_FEATURE_RO_COMPAT_SUPP +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED	~EXT2_FEATURE_INCOMPAT_SUPP + +/* + * Default values for user and/or group using reserved blocks + */ +#define	EXT2_DEF_RESUID		0 +#define	EXT2_DEF_RESGID		0 + +/* + * Default mount options + */ +#define EXT2_DEFM_DEBUG		0x0001 +#define EXT2_DEFM_BSDGROUPS	0x0002 +#define EXT2_DEFM_XATTR_USER	0x0004 +#define EXT2_DEFM_ACL		0x0008 +#define EXT2_DEFM_UID16		0x0010 +    /* Not used by ext2, but reserved for use by ext3 */ +#define EXT3_DEFM_JMODE		0x0060 +#define EXT3_DEFM_JMODE_DATA	0x0020 +#define EXT3_DEFM_JMODE_ORDERED	0x0040 +#define EXT3_DEFM_JMODE_WBACK	0x0060 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { +	uint32_t	inode;			/* Inode number */ +	uint16_t	rec_len;		/* Directory entry length */ +	uint16_t	name_len;		/* Name length */ +	char	name[EXT2_NAME_LEN];	/* File name */ +}; + +/* + * The new version of the directory entry.  Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext2_dir_entry_2 { +	uint32_t	inode;			/* Inode number */ +	uint16_t	rec_len;		/* Directory entry length */ +	uint8_t	name_len;		/* Name length */ +	uint8_t	file_type; +	char	name[EXT2_NAME_LEN];	/* File name */ +}; + +/* + * Ext2 directory file types.  Only the low 3 bits are used.  The + * other bits are reserved for now. + */ +enum { +	EXT2_FT_UNKNOWN, +	EXT2_FT_REG_FILE, +	EXT2_FT_DIR, +	EXT2_FT_CHRDEV, +	EXT2_FT_BLKDEV, +	EXT2_FT_FIFO, +	EXT2_FT_SOCK, +	EXT2_FT_SYMLINK, +	EXT2_FT_MAX +}; + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD		 	4 +#define EXT2_DIR_ROUND 			(EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \ +					 ~EXT2_DIR_ROUND) +#define EXT2_MAX_REC_LEN		((1<<16)-1) + +#endif	/* _EXT2_FS_H */ diff --git a/roms/openbios/fs/ext2/ext2_lseek.c b/roms/openbios/fs/ext2/ext2_lseek.c new file mode 100644 index 00000000..e837d89b --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_lseek.c @@ -0,0 +1,38 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" + +int ext2_lseek(ext2_FILE *file, long offset, int whence) +{ +	long new_offset; + +	switch(whence) +	{ +	case SEEK_SET: +		new_offset = offset; +		break; +	case SEEK_CUR: +		new_offset = file->offset + offset; +		break; +	case SEEK_END: +		new_offset = file->inode->i_size + offset; +		break; +	default: +		return -1; +	} + +	if ( (new_offset < 0) || +	     (new_offset > file->inode->i_size) ) +		return -1; + +	file->offset = new_offset; + +	return new_offset; +} diff --git a/roms/openbios/fs/ext2/ext2_mount.c b/roms/openbios/fs/ext2/ext2_mount.c new file mode 100644 index 00000000..06b63dec --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_mount.c @@ -0,0 +1,62 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" +#include "ext2_utils.h" + +#define SB_OFFSET (2) + +ext2_VOLUME* ext2_mount(int fd) +{ +	ext2_VOLUME *volume; +	struct ext2_super_block *super; +	char *buffer; + +	super = (struct ext2_super_block*)malloc(sizeof(struct ext2_super_block)); +	if (super == NULL) +		return NULL; + +	ext2_get_super(fd, super); +	if (super->s_magic != EXT2_SUPER_MAGIC) { +		free(super); +		return NULL; +	} + +	buffer = (char*)malloc(EXT2_BLOCK_SIZE(super)); +	if (buffer == NULL) { +		free(super); +		return NULL; +	} + +	volume = (ext2_VOLUME*)malloc(sizeof(ext2_VOLUME)); +	if (volume == NULL) { +		free(super); +		free(buffer); +		return NULL; +	} + +	volume->buffer = buffer; +	volume->fd = fd; +	volume->super = super; + +	volume->current = -1; +	ext2_read_block(volume, 0); + +	return volume; +} + +int ext2_umount(ext2_VOLUME* volume) +{ +	if (volume == NULL) +		return -1; +	free(volume->super); +	free(volume->buffer); +	free(volume); +	return 0; +} diff --git a/roms/openbios/fs/ext2/ext2_open.c b/roms/openbios/fs/ext2/ext2_open.c new file mode 100644 index 00000000..03a89bbd --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_open.c @@ -0,0 +1,65 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" +#include "ext2_utils.h" + +ext2_FILE* ext2_open(ext2_VOLUME *volume, const char* pathname) +{ +	ext2_FILE *file; +	struct ext2_inode *inode; +	int ino; +	int ret; + +	ino = ext2_seek_name(volume, pathname); +	if (ino == 0) +		return NULL; + +	inode = (struct ext2_inode*)malloc(sizeof(struct ext2_inode)); +	if (inode == NULL) +		return NULL; + +	ret = ext2_get_inode(volume, ino, inode); +	if (ret == -1) { +		free(inode); +		return NULL; +	} +	if (S_ISLNK(inode->i_mode)) { +		static char buffer[1024]; +		int i, last = 0; +		strcpy(buffer, pathname); +		for (i = 0; buffer[i]; i++) +			if (buffer[i] == '\\') +				last = i; +		buffer[last] = '\\'; +		strcpy(buffer + last + 1, (char*)inode->i_block); +		ino = ext2_seek_name((ext2_VOLUME*)volume, buffer); +		if (ino == 0) { +			free(inode); +			return NULL; +		} +		ret = ext2_get_inode((ext2_VOLUME*)volume, ino, inode); +		if (ret == -1) { +			free(inode); +			return NULL; +		} +	} + +	file = (ext2_FILE*)malloc(sizeof(ext2_FILE)); +	if (file == NULL) { +		free(inode); +		return NULL; +	} +	file->volume = volume; +	file->inode = inode; +	file->offset = 0; +	file->path = strdup(pathname); + +	return file; +} diff --git a/roms/openbios/fs/ext2/ext2_opendir.c b/roms/openbios/fs/ext2/ext2_opendir.c new file mode 100644 index 00000000..3363e0b3 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_opendir.c @@ -0,0 +1,49 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" +#include "ext2_utils.h" + +ext2_DIR* ext2_opendir(ext2_VOLUME *volume, const char *name) +{ +	ext2_DIR* dir; +	int ino; +	struct ext2_inode *inode; +	int ret; + +	ino = ext2_seek_name(volume, name); +	if (ino == 0) +		return NULL; + +	inode = (struct ext2_inode*)malloc(sizeof(struct ext2_inode)); +	if (inode == NULL) +		return NULL; + +	ret = ext2_get_inode(volume, ino, inode); +	if (ret == -1) { +		free(inode); +		return NULL; +	} + +	if (!S_ISDIR(inode->i_mode)) { +		free(inode); +		return NULL; +	} + +	dir = (ext2_DIR*)malloc(sizeof(ext2_DIR)); +	if (dir == NULL) { +		free(inode); +		return NULL; +	} +	dir->volume = (ext2_VOLUME*)volume; +	dir->inode = inode; +	dir->index = 0; + +	return dir; +} diff --git a/roms/openbios/fs/ext2/ext2_read.c b/roms/openbios/fs/ext2/ext2_read.c new file mode 100644 index 00000000..975b3675 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_read.c @@ -0,0 +1,23 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2.h" +#include "ext2_utils.h" + +size_t ext2_read(ext2_FILE *file, void *buf, size_t count) +{ +	int ret; + +	ret = ext2_read_data(file->volume, file->inode, file->offset, +			     buf, count); +	if (ret == -1) +		return -1; +	file->offset += ret; +	return ret; +} diff --git a/roms/openbios/fs/ext2/ext2_readdir.c b/roms/openbios/fs/ext2/ext2_readdir.c new file mode 100644 index 00000000..09ba95c9 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_readdir.c @@ -0,0 +1,25 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2_utils.h" + +static struct ext2_dir_entry_2 entry; + +struct ext2_dir_entry_2 *ext2_readdir(ext2_DIR *dir) +{ +	int ret; + +	ret = ext2_dir_entry(dir->volume, dir->inode, dir->index, &entry); +	if (ret == -1) +		return NULL; +	dir->index = ret; + +	entry.name[entry.name_len] = 0; +	return &entry; +} diff --git a/roms/openbios/fs/ext2/ext2_utils.c b/roms/openbios/fs/ext2/ext2_utils.c new file mode 100644 index 00000000..64563c82 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_utils.c @@ -0,0 +1,332 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libext2.h" +#include "ext2_utils.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" +#include "libc/byteorder.h" + +int ext2_probe(int fd, long long offset) +{ +	struct ext2_super_block *super; + +	super = (struct ext2_super_block*)malloc(sizeof(struct ext2_super_block)); +	seek_io(fd, 2 * 512 + offset); +	read_io(fd, super, sizeof (*super)); + +	if (__le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) { +		free(super); +		return 0; +	} + +	free(super); +	return -1; +} + +void ext2_get_super(int fd, struct ext2_super_block *super) +{ +	seek_io(fd, 2 * 512); +	read_io(fd, super, sizeof (*super)); + +	super->s_inodes_count = __le32_to_cpu(super->s_inodes_count); +	super->s_blocks_count = __le32_to_cpu(super->s_blocks_count); +	super->s_r_blocks_count = __le32_to_cpu(super->s_r_blocks_count); +	super->s_free_blocks_count = __le32_to_cpu(super->s_free_blocks_count); +	super->s_free_inodes_count = __le32_to_cpu(super->s_free_inodes_count); +	super->s_first_data_block = __le32_to_cpu(super->s_first_data_block); +	super->s_log_block_size = __le32_to_cpu(super->s_log_block_size); +	super->s_log_frag_size = __le32_to_cpu(super->s_log_frag_size); +	super->s_blocks_per_group = __le32_to_cpu(super->s_blocks_per_group); +	super->s_frags_per_group = __le32_to_cpu(super->s_frags_per_group); +	super->s_inodes_per_group = __le32_to_cpu(super->s_inodes_per_group); +	super->s_mtime = __le32_to_cpu(super->s_mtime); +	super->s_wtime = __le32_to_cpu(super->s_wtime); +	super->s_mnt_count = __le16_to_cpu(super->s_mnt_count); +	super->s_max_mnt_count = __le16_to_cpu(super->s_max_mnt_count); +	super->s_magic = __le16_to_cpu(super->s_magic); +	super->s_state = __le16_to_cpu(super->s_state); +	super->s_errors = __le16_to_cpu(super->s_errors); +	super->s_minor_rev_level = __le16_to_cpu(super->s_minor_rev_level); +	super->s_lastcheck = __le32_to_cpu(super->s_lastcheck); +	super->s_checkinterval = __le32_to_cpu(super->s_checkinterval); +	super->s_creator_os = __le32_to_cpu(super->s_creator_os); +	super->s_rev_level = __le32_to_cpu(super->s_rev_level); +	super->s_def_resuid = __le16_to_cpu(super->s_def_resuid); +	super->s_def_resgid = __le16_to_cpu(super->s_def_resgid); +	super->s_first_ino = __le32_to_cpu(super->s_first_ino); +	super->s_inode_size = __le16_to_cpu(super->s_inode_size); +	super->s_block_group_nr = __le16_to_cpu(super->s_block_group_nr); +	super->s_feature_compat = __le32_to_cpu(super->s_feature_compat); +	super->s_feature_incompat = __le32_to_cpu(super->s_feature_incompat); +	super->s_feature_ro_compat = __le32_to_cpu(super->s_feature_ro_compat); +	super->s_algorithm_usage_bitmap = +				__le32_to_cpu(super->s_algorithm_usage_bitmap); +	super->s_journal_inum = __le32_to_cpu(super->s_journal_inum); +	super->s_journal_dev = __le32_to_cpu(super->s_journal_dev); +	super->s_last_orphan = __le32_to_cpu(super->s_last_orphan); +	super->s_hash_seed[0] = __le32_to_cpu(super->s_hash_seed[0]); +	super->s_hash_seed[1] = __le32_to_cpu(super->s_hash_seed[1]); +	super->s_hash_seed[2] = __le32_to_cpu(super->s_hash_seed[2]); +	super->s_hash_seed[3] = __le32_to_cpu(super->s_hash_seed[3]); +	super->s_default_mount_opts = +				__le32_to_cpu(super->s_default_mount_opts); +	super->s_first_meta_bg = __le32_to_cpu(super->s_first_meta_bg); +} + +void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock) +{ +	long long offset; + +	if (fsblock == volume->current) +		return; + +	volume->current = fsblock; +	offset = fsblock * EXT2_BLOCK_SIZE(volume->super); + +	seek_io(volume->fd, offset); +	read_io(volume->fd, volume->buffer, EXT2_BLOCK_SIZE(volume->super)); +} + +void ext2_get_group_desc(ext2_VOLUME* volume, +		   int group_id, struct ext2_group_desc *gdp) +{ +	unsigned int block, offset; +	struct ext2_group_desc *le_gdp; + +	block = 1 + volume->super->s_first_data_block; +	block += group_id / EXT2_DESC_PER_BLOCK(volume->super); +	ext2_read_block(volume,  block); + +	offset = group_id % EXT2_DESC_PER_BLOCK(volume->super); +	offset *= sizeof(*gdp); + +	le_gdp = (struct ext2_group_desc *)(volume->buffer + offset); + +	gdp->bg_block_bitmap = __le32_to_cpu(le_gdp->bg_block_bitmap); +	gdp->bg_inode_bitmap = __le32_to_cpu(le_gdp->bg_inode_bitmap); +	gdp->bg_inode_table = __le32_to_cpu(le_gdp->bg_inode_table); +	gdp->bg_free_blocks_count = __le16_to_cpu(le_gdp->bg_free_blocks_count); +	gdp->bg_free_inodes_count = __le16_to_cpu(le_gdp->bg_free_inodes_count); +	gdp->bg_used_dirs_count = __le16_to_cpu(le_gdp->bg_used_dirs_count); +} + +int ext2_get_inode(ext2_VOLUME* volume, +		    unsigned int ino, struct ext2_inode *inode) +{ +	struct ext2_group_desc desc; +	unsigned int block; +	unsigned int group_id; +	unsigned int offset; +	struct ext2_inode *le_inode; +	int i; + +	ino--; + +	group_id = ino / EXT2_INODES_PER_GROUP(volume->super); +	ext2_get_group_desc(volume, group_id, &desc); + +	ino %= EXT2_INODES_PER_GROUP(volume->super); + +	block = desc.bg_inode_table; +	block += ino / (EXT2_BLOCK_SIZE(volume->super) / +			EXT2_INODE_SIZE(volume->super)); +	ext2_read_block(volume, block); + +	offset = ino % (EXT2_BLOCK_SIZE(volume->super) / +			EXT2_INODE_SIZE(volume->super)); +	offset *= EXT2_INODE_SIZE(volume->super); + +	le_inode = (struct ext2_inode *)(volume->buffer + offset); + +	inode->i_mode = __le16_to_cpu(le_inode->i_mode); +	inode->i_uid = __le16_to_cpu(le_inode->i_uid); +	inode->i_size = __le32_to_cpu(le_inode->i_size); +	inode->i_atime = __le32_to_cpu(le_inode->i_atime); +	inode->i_ctime = __le32_to_cpu(le_inode->i_ctime); +	inode->i_mtime = __le32_to_cpu(le_inode->i_mtime); +	inode->i_dtime = __le32_to_cpu(le_inode->i_dtime); +	inode->i_gid = __le16_to_cpu(le_inode->i_gid); +	inode->i_links_count = __le16_to_cpu(le_inode->i_links_count); +	inode->i_blocks = __le32_to_cpu(le_inode->i_blocks); +	inode->i_flags = __le32_to_cpu(le_inode->i_flags); +	if (S_ISLNK(inode->i_mode)) { +		memcpy(inode->i_block, le_inode->i_block, EXT2_N_BLOCKS * 4); +	} else { +		for (i = 0; i < EXT2_N_BLOCKS; i++) +			inode->i_block[i] = __le32_to_cpu(le_inode->i_block[i]); +        } +	inode->i_generation = __le32_to_cpu(le_inode->i_generation); +	inode->i_file_acl = __le32_to_cpu(le_inode->i_file_acl); +	inode->i_dir_acl = __le32_to_cpu(le_inode->i_dir_acl); +	inode->i_faddr = __le32_to_cpu(le_inode->i_faddr); +	inode->osd2.linux2.l_i_frag = le_inode->osd2.linux2.l_i_frag; +	inode->osd2.linux2.l_i_fsize = le_inode->osd2.linux2.l_i_fsize; +	inode->osd2.linux2.l_i_uid_high = +			__le16_to_cpu(le_inode->osd2.linux2.l_i_uid_high); +	inode->osd2.linux2.l_i_gid_high = +			__le16_to_cpu(le_inode->osd2.linux2.l_i_gid_high); +	return 0; +} + +unsigned int ext2_get_block_addr(ext2_VOLUME* volume, struct ext2_inode *inode, +				 unsigned int logical) +{ +	unsigned int physical; +	unsigned int addr_per_block; + +	/* direct */ + +	if (logical < EXT2_NDIR_BLOCKS) { +		physical = inode->i_block[logical]; +		return physical; +	} + +	/* indirect */ + +	logical -= EXT2_NDIR_BLOCKS; + +	addr_per_block = EXT2_ADDR_PER_BLOCK (volume->super); +	if (logical < addr_per_block) { +		ext2_read_block(volume, inode->i_block[EXT2_IND_BLOCK]); +		physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical]); +		return physical; +	} + +	/* double indirect */ + +	logical -=  addr_per_block; + +	if (logical < addr_per_block * addr_per_block) { +		ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]); +		physical = __le32_to_cpu(((unsigned int *)volume->buffer) +						[logical / addr_per_block]); +		ext2_read_block(volume, physical); +		physical = __le32_to_cpu(((unsigned int *)volume->buffer) +						[logical % addr_per_block]); +		return physical; +	} + +	/* triple indirect */ + +	logical -= addr_per_block * addr_per_block; +	ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]); +	physical = __le32_to_cpu(((unsigned int *)volume->buffer) +				[logical / (addr_per_block * addr_per_block)]); +	ext2_read_block(volume, physical); +	logical = logical % (addr_per_block * addr_per_block); +	physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical / addr_per_block]); +	ext2_read_block(volume, physical); +	physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical % addr_per_block]); +	return physical; +} + +int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode, +		   off_t offset, char *buffer, size_t length) +{ +	unsigned int logical, physical; +	int blocksize = EXT2_BLOCK_SIZE(volume->super); +	int shift; +	size_t read; + +	if (offset >= inode->i_size) +		return -1; + +	if (offset + length >= inode->i_size) +		length = inode->i_size - offset; + +	read = 0; +	logical = offset / blocksize; +	shift = offset % blocksize; + +	if (shift) { +		physical = ext2_get_block_addr(volume, inode, logical); +		ext2_read_block(volume, physical); + +		if (length < blocksize - shift) { +			memcpy(buffer, volume->buffer + shift, length); +			return length; +		} +		read += blocksize - shift; +		memcpy(buffer, volume->buffer + shift, read); + +		buffer += read; +		length -= read; +		logical++; +	} + +	while (length) { +		physical = ext2_get_block_addr(volume, inode, logical); +		ext2_read_block(volume, physical); + +		if (length < blocksize) { +			memcpy(buffer, volume->buffer, length); +			read += length; +			return read; +		} +		memcpy(buffer, volume->buffer, blocksize); + +		buffer += blocksize; +		length -= blocksize; +		read += blocksize; +		logical++; +	} + +	return read; +} + +off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode, +		     off_t index, struct ext2_dir_entry_2 *entry) +{ +	int ret; + +	ret = ext2_read_data(volume, inode, index, +			     (char*)entry, sizeof(*entry)); +	if (ret == -1) +		return -1; + +        entry->inode = __le32_to_cpu(entry->inode); +        entry->rec_len = __le16_to_cpu(entry->rec_len); +	return index + entry->rec_len; +} + +unsigned int ext2_seek_name(ext2_VOLUME *volume, const char *name) +{ +	struct ext2_inode inode; +	int ret; +	unsigned int ino; +	off_t index; +	struct ext2_dir_entry_2 entry; + +	ino = EXT2_ROOT_INO; +	while(1) { +		while (*name == '\\') +			name++; +		if (!*name) +		    break; +		ret = ext2_get_inode(volume, ino, &inode); +		if (ret == -1) +			return 0; +		index = 0; +		while (1) { +			index = ext2_dir_entry(volume, &inode, index, &entry); +			if (index == -1) +				return 0; +			ret = strncmp(name, entry.name, entry.name_len); +			if (ret == 0  && +			    (name[entry.name_len] == 0 || +			     name[entry.name_len] == '\\')) { +			     	ino = entry.inode; +				break; +			} +		} +		name += entry.name_len; +	} + +	return ino; +} diff --git a/roms/openbios/fs/ext2/ext2_utils.h b/roms/openbios/fs/ext2/ext2_utils.h new file mode 100644 index 00000000..43544d87 --- /dev/null +++ b/roms/openbios/fs/ext2/ext2_utils.h @@ -0,0 +1,54 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#ifndef __EXT2_UTILS_H__ +#define __EXT2_UTILS_H__ + +#include "ext2_fs.h" +#include "ext2.h" + +/* from linux/stat.h */ + +#define S_IFMT  00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK	 0120000 +#define S_IFREG  0100000 +#define S_IFBLK  0060000 +#define S_IFDIR  0040000 +#define S_IFCHR  0020000 +#define S_IFIFO  0010000 +#define S_ISUID  0004000 +#define S_ISGID  0002000 +#define S_ISVTX  0001000 + +#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK) + +/* utilities */ + +extern int ext2_probe(int fd, long long offset); +extern void ext2_get_super(int fd, struct ext2_super_block *super); +extern void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock); +extern void ext2_get_group_desc(ext2_VOLUME* volume, +				int group_id, struct ext2_group_desc *gdp); +extern int ext2_get_inode(ext2_VOLUME* volume, +			  unsigned int ino, struct ext2_inode *inode); +extern unsigned int ext2_get_block_addr(ext2_VOLUME* volume, +					struct ext2_inode *inode, +					unsigned int logical); +extern int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode, +			  off_t offset, char *buffer, size_t length); +extern off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode, +			    off_t offset, struct ext2_dir_entry_2 *entry); +extern unsigned int ext2_seek_name(ext2_VOLUME *volume, const char *name); +#endif /* __EXT2_UTILS_H__ */ diff --git a/roms/openbios/fs/ext2/libext2.h b/roms/openbios/fs/ext2/libext2.h new file mode 100644 index 00000000..12d22a44 --- /dev/null +++ b/roms/openbios/fs/ext2/libext2.h @@ -0,0 +1,25 @@ +/* + * + * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#ifndef __LIBEXT2_H__ +#define __LIBEXT2_H__ + +#include "config.h" +#include "ext2.h" + +extern ext2_VOLUME* ext2_mount(int fd); +extern int ext2_umount(ext2_VOLUME *volume); +extern ext2_DIR* ext2_opendir(ext2_VOLUME *, const char *name); +extern struct ext2_dir_entry_2* ext2_readdir(ext2_DIR* dir); +extern void ext2_closedir(ext2_DIR *dir); +extern ext2_FILE* ext2_open(ext2_VOLUME *, const char* pathname); +extern size_t ext2_read(ext2_FILE *file, void *buf, size_t count); +extern void ext2_close(ext2_FILE *file); +extern int ext2_lseek(ext2_FILE *file, long offset, int whence); + +#endif /* __LIBEXT2_H__ */ diff --git a/roms/openbios/fs/grubfs/Kconfig b/roms/openbios/fs/grubfs/Kconfig new file mode 100644 index 00000000..55fec8b7 --- /dev/null +++ b/roms/openbios/fs/grubfs/Kconfig @@ -0,0 +1,83 @@ +config FSYS_EXT2FS +	depends on GRUBFS +	bool "EXT2 support" +	default n +	help +	  Include EXT2 filesystem support + +config FSYS_FAT +	depends on GRUBFS +	bool "(V)FAT support" +	default n +	help +	  Include VFAT/FAT (MSDOS / Windows95) filesystem support + +config FSYS_JFS +	depends on GRUBFS +	bool "JFS support" +	default n +	help +	  Include JFS support + +config FSYS_MINIX +	depends on GRUBFS +	bool "Minix filesystem support" +	default n +	help +	  Include Minix filesystem support + +config FSYS_REISERFS +	depends on GRUBFS +	bool "Reiser filesystem support" +	default n +	help +	  Include Reiser filesystem support +	   +config FSYS_XFS +	depends on GRUBFS +	bool "XFS support" +	default n +	help +	  Include XFS support + +config FSYS_UFS +	depends on GRUBFS +	bool "UFS/UFS2 support" +	default n +	help +	  Include UFS/UFS2 support + +config FSYS_ISO9660 +	depends on GRUBFS +	bool "ISO 9660 support" +	default n +	help +	  Include ISO9660 (cdrom) filesystem support + +config FSYS_FFS +	depends on GRUBFS +	bool "FreeBSD FFS support" +	default n +	help +	  Include FreeBSD FFS filesystem support + +config FSYS_VSTAFS +	depends on GRUBFS +	bool "VSTA filesystem support" +	default n +	help +	  Include VSTA filesystem support + +config FSYS_NTFS +	depends on GRUBFS +	bool "NT filesystem support" +	default n +	help +	  Include NTFS filesystem support + +config FSYS_AFFS +	depends on GRUBFS +	bool "Amiga fast filesystem support" +	default n +	help +	  Include Amiga FFS filesystem support diff --git a/roms/openbios/fs/grubfs/build.xml b/roms/openbios/fs/grubfs/build.xml new file mode 100644 index 00000000..e5fb64a5 --- /dev/null +++ b/roms/openbios/fs/grubfs/build.xml @@ -0,0 +1,17 @@ +<build> + <library name="fs" type="static" target="target"> +  <object source="grubfs_fs.c"/> +  <object source="fsys_ext2fs.c" condition="FSYS_EXT2FS" flags="-DFSYS_EXT2FS -fno-strict-aliasing"/> +  <object source="fsys_fat.c" condition="FSYS_FAT" flags="-DFSYS_FAT -fno-strict-aliasing"/> +  <object source="fsys_jfs.c" condition="FSYS_JFS" flags="-DFSYS_JFS -fno-strict-aliasing"/> +  <object source="fsys_minix.c" condition="FSYS_MINIX" flags="-DFSYS_MINIX -fno-strict-aliasing"/> +  <object source="fsys_reiserfs.c" condition="FSYS_REISERFS" flags="-DFSYS_REISERFS -fno-strict-aliasing"/> +  <object source="fsys_xfs.c" condition="FSYS_XFS" flags="-DFSYS_XFS -fno-strict-aliasing"/> +  <object source="fsys_ufs.c" condition="FSYS_UFS" flags="-DFSYS_UFS -fno-strict-aliasing"/> +  <object source="fsys_ffs.c" condition="FSYS_FFS" flags="-DFSYS_FFS -fno-strict-aliasing"/> +  <object source="fsys_vstafs.c" condition="FSYS_VSTAFS" flags="-DFSYS_VSTAFS -fno-strict-aliasing"/> +  <object source="fsys_iso9660.c" condition="FSYS_ISO9660" flags="-DFSYS_ISO9660 -fno-strict-aliasing"/> +  <object source="fsys_ntfs.c" condition="FSYS_NTFS" flags="-DFSYS_NTFS -fno-strict-aliasing"/> +  <object source="fsys_affs.c" condition="FSYS_AFFS" flags="-DFSYS_AFFS -fno-strict-aliasing"/> + </library> +</build> diff --git a/roms/openbios/fs/grubfs/debug.h b/roms/openbios/fs/grubfs/debug.h new file mode 100644 index 00000000..7494d316 --- /dev/null +++ b/roms/openbios/fs/grubfs/debug.h @@ -0,0 +1 @@ +/* for grub compatibility */ diff --git a/roms/openbios/fs/grubfs/defs.h b/roms/openbios/fs/grubfs/defs.h new file mode 100644 index 00000000..3a3128ce --- /dev/null +++ b/roms/openbios/fs/grubfs/defs.h @@ -0,0 +1,86 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Common definitions for Berkeley Fast File System. + */ + +/* + * Compatibility definitions for disk IO. + */ + +/* + * Disk devices do all IO in 512-byte blocks. + */ +#define	DEV_BSIZE	512 + +/* + * Conversion between bytes and disk blocks. + */ +#define	btodb(byte_offset)	((byte_offset) >> 9) +#define	dbtob(block_number)	((block_number) << 9) + +typedef struct _quad_ +  { +    unsigned int val[2];	/* 2 int values make... */ +  } +quad;				/* an 8-byte item */ + +typedef unsigned int mach_time_t;	/* an unsigned int */ +typedef unsigned int mach_daddr_t;	/* an unsigned int */ +typedef unsigned int mach_off_t;	/* another unsigned int */ + +typedef unsigned short mach_uid_t; +typedef unsigned short mach_gid_t; +typedef unsigned int mach_ino_t; + +#define	NBBY	8 + +/* + * The file system is made out of blocks of at most MAXBSIZE units, + * with smaller units (fragments) only in the last direct block. + * MAXBSIZE primarily determines the size of buffers in the buffer + * pool.  It may be made larger without any effect on existing + * file systems; however, making it smaller may make some file + * systems unmountable. + * + * Note that the disk devices are assumed to have DEV_BSIZE "sectors" + * and that fragments must be some multiple of this size. + */ +#define	MAXBSIZE	8192 +#define	MAXFRAG		8 + +/* + * MAXPATHLEN defines the longest permissible path length + * after expanding symbolic links. + * + * MAXSYMLINKS defines the maximum number of symbolic links + * that may be expanded in a path name.  It should be set + * high enough to allow all legitimate uses, but halt infinite + * loops reasonably quickly. + */ + +#define	MAXPATHLEN	1024 +#define	MAXSYMLINKS	8 diff --git a/roms/openbios/fs/grubfs/dir.h b/roms/openbios/fs/grubfs/dir.h new file mode 100644 index 00000000..a775cab8 --- /dev/null +++ b/roms/openbios/fs/grubfs/dir.h @@ -0,0 +1,141 @@ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + *	@(#)dir.h	7.6 (Berkeley) 5/9/89 + */ + +#ifndef _BOOT_UFS_DIR_H_ +#define	_BOOT_UFS_DIR_H_ + +/* + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length.  Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry.  These are followed by the name padded to a 4 byte boundary + * with null bytes.  All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(dp) gives the amount of space required to represent + * a directory entry.  Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries.  This + * usually results in the last entry in a directory having a large + * dp->d_reclen.  When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen.  If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#define DIRBLKSIZ	DEV_BSIZE +#define	MAXNAMLEN	255 + +struct direct +  { +    unsigned int d_ino;		/* inode number of entry */ +    unsigned short d_reclen;	/* length of this record */ +    unsigned short d_namlen;	/* length of string in d_name */ +    char d_name[MAXNAMLEN + 1];	/* name with length <= MAXNAMLEN */ +  }; + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry.  This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ +    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) + +#ifdef KERNEL +/* + * Template for manipulating directories. + * Should use struct direct's, but the name field + * is MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate +  { +    unsigned int dot_ino; +    short dot_reclen; +    short dot_namlen; +    char dot_name[4];		/* must be multiple of 4 */ +    unsigned int dotdot_ino; +    short dotdot_reclen; +    short dotdot_namlen; +    char dotdot_name[4];	/* ditto */ +  }; +#endif + +/* + * The following information should be obtained from <dirent.h> + * and is provided solely (and temporarily) for backward compatibility. + */ +#ifndef KERNEL +#define d_fileno d_ino		/* compatibility with POSIX */ +#ifndef DEV_BSIZE +#define	DEV_BSIZE	512 +#endif +/* + * Definitions for library routines operating on directories. + */ +typedef struct _dirdesc +  { +    int dd_fd; +    int dd_loc; +    int dd_size; +    char dd_buf[DIRBLKSIZ]; +  } +DIR; + +#define dirfd(dirp)	((dirp)->dd_fd) + +#ifndef NULL +#define NULL 0 +#endif +#endif /* not KERNEL */ +#endif /* _BOOT_UFS_DIR_H_ */ diff --git a/roms/openbios/fs/grubfs/disk_inode.h b/roms/openbios/fs/grubfs/disk_inode.h new file mode 100644 index 00000000..68a61c7a --- /dev/null +++ b/roms/openbios/fs/grubfs/disk_inode.h @@ -0,0 +1,110 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + *	@(#)inode.h	7.5 (Berkeley) 7/3/89 + */ + +#ifndef	_BOOT_UFS_DISK_INODE_H_ +#define	_BOOT_UFS_DISK_INODE_H_ + +/* + * The I node is the focus of all file activity in the BSD Fast File System. + * There is a unique inode allocated for each active file, + * each current directory, each mounted-on file, text file, and the root. + * An inode is 'named' by its dev/inumber pair. (iget/iget.c) + * Data in icommon is read in from permanent inode on volume. + */ + +#define	FFS_NDADDR	12	/* direct addresses in inode */ +#define	FFS_NIADDR	3	/* indirect addresses in inode */ + +#define	FFS_MAX_FASTLINK_SIZE	((FFS_NDADDR + FFS_NIADDR) \ +				 * sizeof (mach_daddr_t)) + +struct icommon +  { +    unsigned short ic_mode;	/*  0: mode and type of file */ +    short ic_nlink;		/*  2: number of links to file */ +    mach_uid_t ic_uid;		/*  4: owner's user id */ +    mach_gid_t ic_gid;		/*  6: owner's group id */ +    quad ic_size;		/*  8: number of bytes in file */ +    mach_time_t ic_atime;	/* 16: time last accessed */ +    int ic_atspare; +    mach_time_t ic_mtime;	/* 24: time last modified */ +    int ic_mtspare; +    mach_time_t ic_ctime;	/* 32: last time inode changed */ +    int ic_ctspare; +    union +      { +	struct +	  { +	    mach_daddr_t Mb_db[FFS_NDADDR];	/* 40: disk block addresses */ +	    mach_daddr_t Mb_ib[FFS_NIADDR];	/* 88: indirect blocks */ +	  } +	ic_Mb; +	char ic_Msymlink[FFS_MAX_FASTLINK_SIZE]; +	/* 40: symbolic link name */ +      } +    ic_Mun; +#define	ic_db		ic_Mun.ic_Mb.Mb_db +#define	ic_ib		ic_Mun.ic_Mb.Mb_ib +#define	ic_symlink	ic_Mun.ic_Msymlink +    int ic_flags;		/* 100: status, currently unused */ +    int ic_blocks;		/* 104: blocks actually held */ +    int ic_gen;			/* 108: generation number */ +    int ic_spare[4];		/* 112: reserved, currently unused */ +  }; + +/* + *	Same structure, but on disk. + */ +struct dinode +  { +    union +      { +	struct icommon di_com; +	char di_char[128]; +      } +    di_un; +  }; +#define	di_ic	di_un.di_com + +#endif /* _BOOT_UFS_DISK_INODE_H_ */ diff --git a/roms/openbios/fs/grubfs/disk_inode_ffs.h b/roms/openbios/fs/grubfs/disk_inode_ffs.h new file mode 100644 index 00000000..3a2cfc6d --- /dev/null +++ b/roms/openbios/fs/grubfs/disk_inode_ffs.h @@ -0,0 +1,101 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + *	@(#)inode.h	7.5 (Berkeley) 7/3/89 + */ + +#ifndef	_BOOT_UFS_DISK_INODE_FFS_H_ +#define	_BOOT_UFS_DISK_INODE_FFS_H_ + +#define	NDADDR	FFS_NDADDR +#define	NIADDR	FFS_NIADDR + +#define	MAX_FASTLINK_SIZE	FFS_MAX_FASTLINK_SIZE + +#define	IC_FASTLINK	0x0001	/* Symbolic link in inode */ + +#define	i_mode		ic_mode +#define	i_nlink		ic_nlink +#define	i_uid		ic_uid +#define	i_gid		ic_gid +#if	defined(BYTE_MSF) && BYTE_MSF +#define	i_size		ic_size.val[1] +#else /* BYTE_LSF */ +#define	i_size		ic_size.val[0] +#endif +#define	i_db		ic_db +#define	i_ib		ic_ib +#define	i_atime		ic_atime +#define	i_mtime		ic_mtime +#define	i_ctime		ic_ctime +#define i_blocks	ic_blocks +#define	i_rdev		ic_db[0] +#define	i_symlink	ic_symlink +#define i_flags		ic_flags +#define i_gen		ic_gen + +/* modes */ +#define	IFMT	0xf000		/* type of file */ +#define	IFCHR	0x2000		/* character special */ +#define	IFDIR	0x4000		/* directory */ +#define	IFBLK	0x6000		/* block special */ +#define	IFREG	0x8000		/* regular */ +#define	IFLNK	0xa000		/* symbolic link */ +#define	IFSOCK	0xc000		/* socket */ + + +#define	ISUID		0x0800	/* set user id on execution */ +#define	ISGID		0x0400	/* set group id on execution */ +#define	ISVTX		0x0200	/* save swapped text even after use */ +#define	IREAD		0x0100	/* read, write, execute permissions */ +#define	IWRITE		0x0080 +#define	IEXEC		0x0040 + +#ifdef EEK +#define f_fs		u.ffs.ffs_fs +#define i_ic		u.ffs.ffs_ic +#define f_nindir	u.ffs.ffs_nindir +#define f_blk		u.ffs.ffs_blk +#define f_blksize	u.ffs.ffs_blksize +#define f_blkno		u.ffs.ffs_blkno +#endif /* EEK */ + +#endif	/* _BOOT_UFS_DISK_INODE_FFS_H_ */ diff --git a/roms/openbios/fs/grubfs/fat.h b/roms/openbios/fs/grubfs/fat.h new file mode 100644 index 00000000..43d38aef --- /dev/null +++ b/roms/openbios/fs/grubfs/fat.h @@ -0,0 +1,99 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2001  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + + +/* + *  Defines for the FAT BIOS Parameter Block (embedded in the first block + *  of the partition. + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* Note that some shorts are not aligned, and must therefore + * be declared as array of two bytes. + */ +struct fat_bpb { +	__s8	ignored[3];	/* Boot strap short or near jump */ +	__s8	system_id[8];	/* Name - can be used to special case +				   partition manager volumes */ +	__u16	bytes_per_sect;	/* bytes per logical sector */ +	__u8	sects_per_clust;/* sectors/cluster */ +	__u16	reserved_sects;	/* reserved sectors */ +	__u8	num_fats;	/* number of FATs */ +	__u16	dir_entries;	/* root directory entries */ +	__u16	short_sectors;	/* number of sectors */ +	__u8	media;		/* media code (unused) */ +	__u16	fat_length;	/* sectors/FAT */ +	__u16	secs_track;	/* sectors per track */ +	__u16	heads;		/* number of heads */ +	__u32	hidden;		/* hidden sectors (unused) */ +	__u32	long_sectors;	/* number of sectors (if short_sectors == 0) */ + +	/* The following fields are only used by FAT32 */ +	__u32	fat32_length;	/* sectors/FAT */ +	__u16	flags;		/* bit 8: fat mirroring, low 4: active fat */ +	__u16	version;	/* major, minor filesystem version */ +	__u32	root_cluster;	/* first cluster in root directory */ +	__u16	info_sector;	/* filesystem info sector */ +	__u16	backup_boot;	/* backup boot sector */ +	__u16	reserved2[6];	/* Unused */ +} __attribute__ ((packed)); + +/* + *  Defines how to differentiate a 12-bit and 16-bit FAT. + */ + +#define FAT_MAX_12BIT_CLUST       4087	/* 4085 + 2 */ + +/* + *  Defines for the file "attribute" byte + */ + +#define FAT_ATTRIB_OK_MASK        0x37 +#define FAT_ATTRIB_NOT_OK_MASK    0xC8 +#define FAT_ATTRIB_DIR            0x10 +#define FAT_ATTRIB_LONGNAME       0x0F + +/* + *  Defines for FAT directory entries + */ + +#define FAT_DIRENTRY_LENGTH       32 + +#define FAT_DIRENTRY_ATTRIB(entry) \ +  (*((unsigned char *) (entry+11))) +#define FAT_DIRENTRY_VALID(entry) \ +  ( ((*((unsigned char *) entry)) != 0) \ +    && ((*((unsigned char *) entry)) != 0xE5) \ +    && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) ) +#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \ +  ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16)) +#define FAT_DIRENTRY_FILELENGTH(entry) \ +  (*((unsigned long *) (entry+28))) + +#define FAT_LONGDIR_ID(entry) \ +  (*((unsigned char *) (entry))) +#define FAT_LONGDIR_ALIASCHECKSUM(entry) \ +  (*((unsigned char *) (entry+13))) diff --git a/roms/openbios/fs/grubfs/filesys.h b/roms/openbios/fs/grubfs/filesys.h new file mode 100644 index 00000000..6b6f9760 --- /dev/null +++ b/roms/openbios/fs/grubfs/filesys.h @@ -0,0 +1,303 @@ +/* GRUB compatibility header + * + * taken from filo and grub. + */ + +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 1999,2000,2001,2003   Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +/* This disables some portion of code */ +#define STAGE1_5 1 + +#if defined CONFIG_X86 +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static __inline__ unsigned int +ffz (unsigned int word) +{ +	__asm__ ("bsfl %1,%0" +	  : "=r" (word) +	  : "r" (~word)); +	return word; +} + +static __inline__ unsigned int +log2 (unsigned int word) +{ +	__asm__ ("bsfl %1,%0" +	  : "=r" (word) +	  : "r" (word)); +	return word; +} + +#elif defined (CONFIG_PPC) +static __inline__ unsigned long + __ilog2(unsigned long x) +{ +	unsigned long lz; + +	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); +	return 31 - lz; +} + +static __inline__ unsigned long +ffz(unsigned long x) +{ +	if ((x = ~x) == 0) +		return 32; + +	return __ilog2(x & -x); +} + +#define log2(n) ffz(~(n)) + +#else + +static __inline__ unsigned int log2(unsigned int word) +{ +	/* assume 8 bits per byte. */ +	unsigned int i = 1 << (sizeof(word)*8 - 1); +	unsigned int pow = sizeof(word) * 8 - 1; + +	if (! word) { +		/* invalid parameter */ +		return -1; +	} +	for(; i > word; i >>= 1, pow--) ; + +        return pow; +} + +#define ffz(n) log2(~(n)) + +#endif + +static inline int +substring (const char *s1, const char *s2) +{ +  while (*s1 == *s2) +    { +      /* The strings match exactly. */ +      if (! *(s1++)) +	return 0; +      s2 ++; +    } + +  /* S1 is a substring of S2. */ +  if (*s1 == 0) +    return -1; + +  /* S1 isn't a substring. */ +  return 1; +} + +#define grub_memmove memmove +#define grub_strcmp strcmp + +#define MAXINT 0x7fffffff + +/* This is only used by fsys_* to determine if it's hard disk. If it is, + * they try to guess filesystem type by partition type. I guess it is + * not necessory, so hardcoded to 0 (first floppy) --ts1 */ +#define current_drive 0 +#define current_slice 0 +#define current_partition 0 + +/* we fake this for now, assuming that the filesystem is not corrupt */ +#define part_length -1 +extern int filepos; +extern int filemax; +extern int fsmax; + +/* Error codes (descriptions are in common.c) */ +typedef enum +{ +  ERR_NONE = 0, +  ERR_BAD_FILENAME, +  ERR_BAD_FILETYPE, +  ERR_BAD_GZIP_DATA, +  ERR_BAD_GZIP_HEADER, +  ERR_BAD_PART_TABLE, +  ERR_BAD_VERSION, +  ERR_BELOW_1MB, +  ERR_BOOT_COMMAND, +  ERR_BOOT_FAILURE, +  ERR_BOOT_FEATURES, +  ERR_DEV_FORMAT, +  ERR_DEV_VALUES, +  ERR_EXEC_FORMAT, +  ERR_FILELENGTH, +  ERR_FILE_NOT_FOUND, +  ERR_FSYS_CORRUPT, +  ERR_FSYS_MOUNT, +  ERR_GEOM, +  ERR_NEED_LX_KERNEL, +  ERR_NEED_MB_KERNEL, +  ERR_NO_DISK, +  ERR_NO_PART, +  ERR_NUMBER_PARSING, +  ERR_OUTSIDE_PART, +  ERR_READ, +  ERR_SYMLINK_LOOP, +  ERR_UNRECOGNIZED, +  ERR_WONT_FIT, +  ERR_WRITE, +  ERR_BAD_ARGUMENT, +  ERR_UNALIGNED, +  ERR_PRIVILEGED, +  ERR_DEV_NEED_INIT, +  ERR_NO_DISK_SPACE, +  ERR_NUMBER_OVERFLOW, + +  MAX_ERR_NUM +} grub_error_t; + +extern grub_error_t errnum; + +#define grub_open file_open +#define grub_read file_read +#define grub_seek file_seek +#define grub_close file_close + +/* instrumentation variables */ +/* (Not used in FILO) */ +extern void (*disk_read_hook) (int, int, int); +extern void (*disk_read_func) (int, int, int); + +#define FSYS_BUFLEN 0x8000 +extern char FSYS_BUF[FSYS_BUFLEN]; + +#define print_possibilities 0 + +#define SECTOR_SIZE 512 +#define SECTOR_BITS 9 + +#ifdef CONFIG_FSYS_FAT +int fat_mount (void); +int fat_read (char *buf, int len); +int fat_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_EXT2FS +int ext2fs_mount (void); +int ext2fs_read (char *buf, int len); +int ext2fs_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_MINIX +int minix_mount (void); +int minix_read (char *buf, int len); +int minix_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_REISERFS +int reiserfs_mount (void); +int reiserfs_read (char *buf, int len); +int reiserfs_dir (char *dirname); +int reiserfs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_JFS +int jfs_mount (void); +int jfs_read (char *buf, int len); +int jfs_dir (char *dirname); +int jfs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_XFS +int xfs_mount (void); +int xfs_read (char *buf, int len); +int xfs_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_UFS +int ufs_mount (void); +int ufs_read (char *buf, int len); +int ufs_dir (char *dirname); +int ufs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_ISO9660 +int iso9660_mount (void); +int iso9660_read (char *buf, int len); +int iso9660_dir (char *dirname); +#endif + +/* This is not a flag actually, but used as if it were a flag.  */ +#define PC_SLICE_TYPE_HIDDEN_FLAG	0x10 + +#define PC_SLICE_TYPE_NONE         	0 +#define PC_SLICE_TYPE_FAT12        	1 +#define PC_SLICE_TYPE_FAT16_LT32M  	4 +#define PC_SLICE_TYPE_EXTENDED     	5 +#define PC_SLICE_TYPE_FAT16_GT32M  	6 +#define PC_SLICE_TYPE_FAT32		0xb +#define PC_SLICE_TYPE_FAT32_LBA		0xc +#define PC_SLICE_TYPE_FAT16_LBA		0xe +#define PC_SLICE_TYPE_WIN95_EXTENDED	0xf +#define PC_SLICE_TYPE_EZD        	0x55 +#define PC_SLICE_TYPE_MINIX		0x80 +#define PC_SLICE_TYPE_LINUX_MINIX	0x81 +#define PC_SLICE_TYPE_EXT2FS       	0x83 +#define PC_SLICE_TYPE_LINUX_EXTENDED	0x85 +#define PC_SLICE_TYPE_VSTAFS		0x9e +#define PC_SLICE_TYPE_DELL_UTIL		0xde +#define PC_SLICE_TYPE_LINUX_RAID	0xfd + +/* For convinience.  */ +/* Check if TYPE is a FAT partition type. Clear the hidden flag before +   the check, to allow the user to mount a hidden partition in GRUB.  */ +#define IS_PC_SLICE_TYPE_FAT(type)	\ +  ({ int _type = (type) & ~PC_SLICE_TYPE_HIDDEN_FLAG; \ +     _type == PC_SLICE_TYPE_FAT12 \ +     || _type == PC_SLICE_TYPE_FAT16_LT32M \ +     || _type == PC_SLICE_TYPE_FAT16_GT32M \ +     || _type == PC_SLICE_TYPE_FAT16_LBA \ +     || _type == PC_SLICE_TYPE_FAT32 \ +     || _type == PC_SLICE_TYPE_FAT32_LBA \ +     || _type == PC_SLICE_TYPE_DELL_UTIL; }) + +#define IS_PC_SLICE_TYPE_MINIX(type) \ +  (((type) == PC_SLICE_TYPE_MINIX)	\ +   || ((type) == PC_SLICE_TYPE_LINUX_MINIX)) + +#define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0 + +/* possible values for the *BSD-style partition type */ +#define	FS_UNUSED	0	/* unused */ +#define	FS_SWAP		1	/* swap */ +#define	FS_V6		2	/* Sixth Edition */ +#define	FS_V7		3	/* Seventh Edition */ +#define	FS_SYSV		4	/* System V */ +#define	FS_V71K		5	/* V7 with 1K blocks (4.1, 2.9) */ +#define	FS_V8		6	/* Eighth Edition, 4K blocks */ +#define	FS_BSDFFS	7	/* 4.2BSD fast file system */ +#define	FS_MSDOS	8	/* MSDOS file system */ +#define	FS_BSDLFS	9	/* 4.4BSD log-structured file system */ +#define	FS_OTHER	10	/* in use, but unknown/unsupported */ +#define	FS_HPFS		11	/* OS/2 high-performance file system */ +#define	FS_ISO9660	12	/* ISO 9660, normally CD-ROM */ +#define	FS_BOOT		13	/* partition contains bootstrap */ +#define	FS_ADOS		14	/* AmigaDOS fast file system */ +#define	FS_HFS		15	/* Macintosh HFS */ +#define	FS_FILECORE	16	/* Acorn Filecore Filing System */ +#define	FS_EXT2FS	17	/* Linux Extended 2 file system */ diff --git a/roms/openbios/fs/grubfs/fs.h b/roms/openbios/fs/grubfs/fs.h new file mode 100644 index 00000000..260e9264 --- /dev/null +++ b/roms/openbios/fs/grubfs/fs.h @@ -0,0 +1,457 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + *	@(#)fs.h	7.7 (Berkeley) 5/9/89 + */ + +/* + * Each disk drive contains some number of file systems. + * A file system consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A file system is described by its super-block, which in turn + * describes the cylinder groups.  The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss.  This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For file system fs, the offsets of the various blocks of interest + * are given in the super block as: + *	[fs->fs_sblkno]		Super-block + *	[fs->fs_cblkno]		Cylinder group block + *	[fs->fs_iblkno]		Inode blocks + *	[fs->fs_dblkno]		Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * The first boot and super blocks are given in absolute disk addresses. + * The byte-offset forms are preferred, as they don't imply a sector size. + */ +#define BBSIZE		8192 +#define SBSIZE		8192 +#define	BBOFF		((mach_off_t)(0)) +#define	SBOFF		((mach_off_t)(BBOFF + BBSIZE)) +#define	BBLOCK		((mach_daddr_t)(0)) +#define	SBLOCK		((mach_daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressible; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks.  To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary.  The file system format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided.  The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The file system records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + * + * The root inode is the root of the file system. + * Inode 0 can't be used for normal purposes and + * historically bad blocks were linked to inode 1, + * thus the root inode is 2. (inode 1 is no longer used for + * this purpose, however numerous dump tapes make this + * assumption, so we are stuck with it) + */ +#define	ROOTINO		((mach_ino_t)2)	/* i number of all roots */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE	4096 + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + * The limit on the amount of summary information per file system + * is defined by MAXCSBUFS. It is currently parameterized for a + * maximum of two million cylinders. + */ +#define MAXMNTLEN 512 +#define MAXCSBUFS 32 + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks.  These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + * + * N.B. sizeof(struct csum) must be a power of two in order for + * the ``fs_cs'' macro to work (see below). + */ +struct csum +  { +    int cs_ndir;		/* number of directories */ +    int cs_nbfree;		/* number of free blocks */ +    int cs_nifree;		/* number of free inodes */ +    int cs_nffree;		/* number of free frags */ +  }; + +/* + * Super block for a file system. + */ +#define	FS_MAGIC	0x011954 +struct fs +  { +    int xxx1;			/* struct       fs *fs_link; */ +    int xxx2;			/* struct       fs *fs_rlink; */ +    mach_daddr_t fs_sblkno;	/* addr of super-block in filesys */ +    mach_daddr_t fs_cblkno;	/* offset of cyl-block in filesys */ +    mach_daddr_t fs_iblkno;	/* offset of inode-blocks in filesys */ +    mach_daddr_t fs_dblkno;	/* offset of first data after cg */ +    int fs_cgoffset;		/* cylinder group offset in cylinder */ +    int fs_cgmask;		/* used to calc mod fs_ntrak */ +    mach_time_t fs_time;	/* last time written */ +    int fs_size;		/* number of blocks in fs */ +    int fs_dsize;		/* number of data blocks in fs */ +    int fs_ncg;			/* number of cylinder groups */ +    int fs_bsize;		/* size of basic blocks in fs */ +    int fs_fsize;		/* size of frag blocks in fs */ +    int fs_frag;		/* number of frags in a block in fs */ +/* these are configuration parameters */ +    int fs_minfree;		/* minimum percentage of free blocks */ +    int fs_rotdelay;		/* num of ms for optimal next block */ +    int fs_rps;			/* disk revolutions per second */ +/* these fields can be computed from the others */ +    int fs_bmask;		/* ``blkoff'' calc of blk offsets */ +    int fs_fmask;		/* ``fragoff'' calc of frag offsets */ +    int fs_bshift;		/* ``lblkno'' calc of logical blkno */ +    int fs_fshift;		/* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ +    int fs_maxcontig;		/* max number of contiguous blks */ +    int fs_maxbpg;		/* max number of blks per cyl group */ +/* these fields can be computed from the others */ +    int fs_fragshift;		/* block to frag shift */ +    int fs_fsbtodb;		/* fsbtodb and dbtofsb shift constant */ +    int fs_sbsize;		/* actual size of super block */ +    int fs_csmask;		/* csum block offset */ +    int fs_csshift;		/* csum block number */ +    int fs_nindir;		/* value of NINDIR */ +    int fs_inopb;		/* value of INOPB */ +    int fs_nspf;		/* value of NSPF */ +/* yet another configuration parameter */ +    int fs_optim;		/* optimization preference, see below */ +/* these fields are derived from the hardware */ +    int fs_npsect;		/* # sectors/track including spares */ +    int fs_interleave;		/* hardware sector interleave */ +    int fs_trackskew;		/* sector 0 skew, per track */ +    int fs_headswitch;		/* head switch time, usec */ +    int fs_trkseek;		/* track-to-track seek, usec */ +/* sizes determined by number of cylinder groups and their sizes */ +    mach_daddr_t fs_csaddr;	/* blk addr of cyl grp summary area */ +    int fs_cssize;		/* size of cyl grp summary area */ +    int fs_cgsize;		/* cylinder group size */ +/* these fields are derived from the hardware */ +    int fs_ntrak;		/* tracks per cylinder */ +    int fs_nsect;		/* sectors per track */ +    int fs_spc;			/* sectors per cylinder */ +/* this comes from the disk driver partitioning */ +    int fs_ncyl;		/* cylinders in file system */ +/* these fields can be computed from the others */ +    int fs_cpg;			/* cylinders per group */ +    int fs_ipg;			/* inodes per group */ +    int fs_fpg;			/* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ +    struct csum fs_cstotal;	/* cylinder summary information */ +/* these fields are cleared at mount time */ +    char fs_fmod;		/* super block modified flag */ +    char fs_clean;		/* file system is clean flag */ +    char fs_ronly;		/* mounted read-only flag */ +    char fs_flags;		/* currently unused flag */ +    char fs_fsmnt[MAXMNTLEN];	/* name mounted on */ +/* these fields retain the current block allocation info */ +    int fs_cgrotor;		/* last cg searched */ +#if 1 +    int was_fs_csp[MAXCSBUFS]; +#else +    struct csum *fs_csp[MAXCSBUFS];	/* list of fs_cs info buffers */ +#endif +    int fs_cpc;			/* cyl per cycle in postbl */ +    short fs_opostbl[16][8];	/* old rotation block list head */ +    long fs_sparecon[50];	/* reserved for future constants */ +    long fs_contigsumsize;	/* size of cluster summary array */ +    long fs_maxsymlinklen;	/* max length of an internal symlink */ +    long fs_inodefmt;		/* format of on-disk inodes */ +    quad fs_maxfilesize;	/* maximum representable file size */ +    quad fs_qbmask;		/* ~fs_bmask - for use with quad size */ +    quad fs_qfmask;		/* ~fs_fmask - for use with quad size */ +    long fs_state;		/* validate fs_clean field */ +    int fs_postblformat;	/* format of positional layout tables */ +    int fs_nrpos;		/* number of rotaional positions */ +    int fs_postbloff;		/* (short) rotation block list head */ +    int fs_rotbloff;		/* (char) blocks for each rotation */ +    int fs_magic;		/* magic number */ +    unsigned char fs_space[1];	/* list of blocks for each rotation */ +/* actually longer */ +  }; +/* + * Preference for optimization. + */ +#define FS_OPTTIME	0	/* minimize allocation time */ +#define FS_OPTSPACE	1	/* minimize disk fragmentation */ + +/* + * Rotational layout table format types + */ +#define FS_42POSTBLFMT		-1	/* 4.2BSD rotational table format */ +#define FS_DYNAMICPOSTBLFMT	1	/* dynamic rotational table format */ +/* + * Macros for access to superblock array structures + */ +#define fs_postbl(fs, cylno) \ +    (((fs)->fs_postblformat == FS_42POSTBLFMT) \ +    ? ((fs)->fs_opostbl[cylno]) \ +    : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) +#define fs_rotbl(fs) \ +    (((fs)->fs_postblformat == FS_42POSTBLFMT) \ +    ? ((fs)->fs_space) \ +    : ((unsigned char *)((char *)(fs) + (fs)->fs_rotbloff))) + +/* + * Convert cylinder group to base address of its global summary info. + * + * N.B. This macro assumes that sizeof(struct csum) is a power of two. + */ +#define fs_cs(fs, indx) \ +	fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask] + +/* + * Cylinder group block for a file system. + */ +#define	CG_MAGIC	0x090255 +struct cg +  { +    int xxx1;			/* struct       cg *cg_link; */ +    int cg_magic;		/* magic number */ +    mach_time_t cg_time;		/* time last written */ +    int cg_cgx;			/* we are the cgx'th cylinder group */ +    short cg_ncyl;		/* number of cyl's this cg */ +    short cg_niblk;		/* number of inode blocks this cg */ +    int cg_ndblk;		/* number of data blocks this cg */ +    struct csum cg_cs;		/* cylinder summary information */ +    int cg_rotor;		/* position of last used block */ +    int cg_frotor;		/* position of last used frag */ +    int cg_irotor;		/* position of last used inode */ +    int cg_frsum[MAXFRAG];	/* counts of available frags */ +    int cg_btotoff;		/* (long) block totals per cylinder */ +    int cg_boff;		/* (short) free block positions */ +    int cg_iusedoff;		/* (char) used inode map */ +    int cg_freeoff;		/* (char) free block map */ +    int cg_nextfreeoff;		/* (char) next available space */ +    int cg_sparecon[16];	/* reserved for future use */ +    unsigned char cg_space[1];	       /* space for cylinder group maps */ +/* actually longer */ +  }; +/* + * Macros for access to cylinder group array structures + */ +#define cg_blktot(cgp) \ +    (((cgp)->cg_magic != CG_MAGIC) \ +    ? (((struct ocg *)(cgp))->cg_btot) \ +    : ((int *)((char *)(cgp) + (cgp)->cg_btotoff))) +#define cg_blks(fs, cgp, cylno) \ +    (((cgp)->cg_magic != CG_MAGIC) \ +    ? (((struct ocg *)(cgp))->cg_b[cylno]) \ +    : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) +#define cg_inosused(cgp) \ +    (((cgp)->cg_magic != CG_MAGIC) \ +    ? (((struct ocg *)(cgp))->cg_iused) \ +    : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff))) +#define cg_blksfree(cgp) \ +    (((cgp)->cg_magic != CG_MAGIC) \ +    ? (((struct ocg *)(cgp))->cg_free) \ +    : ((unsigned char *)((char *)(cgp) + (cgp)->cg_freeoff))) +#define cg_chkmagic(cgp) \ +    ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) + +/* + * The following structure is defined + * for compatibility with old file systems. + */ +struct ocg +  { +    int xxx1;			/* struct       ocg *cg_link; */ +    int xxx2;			/* struct       ocg *cg_rlink; */ +    mach_time_t cg_time;	/* time last written */ +    int cg_cgx;			/* we are the cgx'th cylinder group */ +    short cg_ncyl;		/* number of cyl's this cg */ +    short cg_niblk;		/* number of inode blocks this cg */ +    int cg_ndblk;		/* number of data blocks this cg */ +    struct csum cg_cs;		/* cylinder summary information */ +    int cg_rotor;		/* position of last used block */ +    int cg_frotor;		/* position of last used frag */ +    int cg_irotor;		/* position of last used inode */ +    int cg_frsum[8];		/* counts of available frags */ +    int cg_btot[32];		/* block totals per cylinder */ +    short cg_b[32][8];		/* positions of free blocks */ +    char cg_iused[256];		/* used inode map */ +    int cg_magic;		/* magic number */ +    unsigned char cg_free[1];	/* free block map */ +/* actually longer */ +  }; + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define fsbtodb(fs, b)	((b) << (fs)->fs_fsbtodb) +#define	dbtofsb(fs, b)	((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc file system addresses of cylinder group data structures. + */ +#define	cgbase(fs, c)	((mach_daddr_t)((fs)->fs_fpg * (c))) +#define cgstart(fs, c) \ +	(cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) +#define	cgsblock(fs, c)	(cgstart(fs, c) + (fs)->fs_sblkno)	/* super blk */ +#define	cgtod(fs, c)	(cgstart(fs, c) + (fs)->fs_cblkno)	/* cg block */ +#define	cgimin(fs, c)	(cgstart(fs, c) + (fs)->fs_iblkno)	/* inode blk */ +#define	cgdmin(fs, c)	(cgstart(fs, c) + (fs)->fs_dblkno)	/* 1st data */ + +/* + * Macros for handling inode numbers: + *     inode number to file system block offset. + *     inode number to cylinder group number. + *     inode number to file system block address. + */ +#define	itoo(fs, x)	((x) % INOPB(fs)) +#define	itog(fs, x)	((x) / (fs)->fs_ipg) +#define	itod(fs, x) \ +	((mach_daddr_t)(cgimin(fs, itog(fs, x)) + \ +	(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +#define	dtog(fs, d)	((d) / (fs)->fs_fpg) +#define	dtogd(fs, d)	((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ +    (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) +#define cbtocylno(fs, bno) \ +    ((bno) * NSPF(fs) / (fs)->fs_spc) +#define cbtorpos(fs, bno) \ +    (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \ +     (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \ +     (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc)		/* calculates (loc % fs->fs_bsize) */ \ +	((loc) & ~(fs)->fs_bmask) +#define fragoff(fs, loc)	/* calculates (loc % fs->fs_fsize) */ \ +	((loc) & ~(fs)->fs_fmask) +#define lblkno(fs, loc)		/* calculates (loc / fs->fs_bsize) */ \ +	((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc)	/* calculates (loc / fs->fs_fsize) */ \ +	((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size)	/* calculates roundup(size, fs->fs_bsize) */ \ +	(((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask) +#define fragroundup(fs, size)	/* calculates roundup(size, fs->fs_fsize) */ \ +	(((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask) +#define fragstoblks(fs, frags)	/* calculates (frags / fs->fs_frag) */ \ +	((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks)	/* calculates (blks * fs->fs_frag) */ \ +	((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb)	/* calculates (fsb % fs->fs_frag) */ \ +	((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb)		/* calculates rounddown(fsb, fs->fs_frag) */ \ +	((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve + */ +#define freespace(fs, percentreserved) \ +	(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ +	(fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the file system. + */ +#define blksize(fs, ip, lbn) \ +	(((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \ +	    ? (fs)->fs_bsize \ +	    : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define dblksize(fs, dip, lbn) \ +	(((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \ +	    ? (fs)->fs_bsize \ +	    : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +/* + * Number of disk sectors per block; assumes DEV_BSIZE byte sector size. + */ +#define	NSPB(fs)	((fs)->fs_nspf << (fs)->fs_fragshift) +#define	NSPF(fs)	((fs)->fs_nspf) + +/* + * INOPB is the number of inodes in a secondary storage block. + */ +#define	INOPB(fs)	((fs)->fs_inopb) +#define	INOPF(fs)	((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * NINDIR is the number of indirects in a file system block. + */ +#define	NINDIR(fs)	((fs)->fs_nindir) diff --git a/roms/openbios/fs/grubfs/fsys_affs.c b/roms/openbios/fs/grubfs/fsys_affs.c new file mode 100644 index 00000000..c4a76322 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_affs.c @@ -0,0 +1,712 @@ +#ifdef FSYS_AFFS +#include "shared.h" +#include "filesys.h" + +/******************************** RDB definitions */ +#define RDB_LOCATION_LIMIT 16 +#define IDNAME_RIGIDDISK   0x5244534B  /* 'RDSK' */ + +struct RigidDiskBlock +{ +    unsigned long   rdb_ID; +    unsigned long   rdb_SummedLongs; +    long            rdb_ChkSum; +    unsigned long   rdb_HostID; +    unsigned long   rdb_BlockBytes; +    unsigned long   rdb_Flags; +    unsigned long   rdb_BadBlockList; +    unsigned long   rdb_PartitionList; +    unsigned long   rdb_FileSysHeaderList; +    unsigned long   rdb_DriveInit; +    unsigned long   rdb_Reserved1[6]; +    unsigned long   rdb_Cylinders; +    unsigned long   rdb_Sectors; +    unsigned long   rdb_Heads; +    unsigned long   rdb_Interleave; +    unsigned long   rdb_Park; +    unsigned long   rdb_Reserved2[3]; +    unsigned long   rdb_WritePreComp; +    unsigned long   rdb_ReducedWrite; +    unsigned long   rdb_StepRate; +    unsigned long   rdb_Reserved3[5]; +    unsigned long   rdb_RDBBlocksLo; +    unsigned long   rdb_RDBBlocksHi; +    unsigned long   rdb_LoCylinder; +    unsigned long   rdb_HiCylinder; +    unsigned long   rdb_CylBlocks; +    unsigned long   rdb_AutoParkSeconds; +    unsigned long   rdb_HighRDSKBlock; +    unsigned long   rdb_Reserved4; +    char    rdb_DiskVendor[8]; +    char    rdb_DiskProduct[16]; +    char    rdb_DiskRevision[4]; +    char    rdb_ControllerVendor[8]; +    char    rdb_ControllerProduct[16]; +    char    rdb_ControllerRevision[4]; +    char    rdb_DriveInitName[40]; +}; + +struct PartitionBlock +{ +    unsigned long   pb_ID; +    unsigned long   pb_SummedLongs; +    long            pb_ChkSum; +    unsigned long   pb_HostID; +    unsigned long   pb_Next; +    unsigned long   pb_Flags; +    unsigned long   pb_Reserved1[2]; +    unsigned long   pb_DevFlags; +    char            pb_DriveName[32]; +    unsigned long   pb_Reserved2[15]; +    unsigned long   pb_Environment[20]; +    unsigned long   pb_EReserved[12]; +}; + +#define DE_TABLESIZE    0 +#define DE_SIZEBLOCK    1 +#define DE_BLOCKSIZE    2 +#define DE_NUMHEADS     3 +#define DE_SECSPERBLOCK 4 +#define DE_BLKSPERTRACK 5 +#define DE_RESERVEDBLKS 6 +#define DE_PREFAC       7 +#define DE_INTERLEAVE   8 +#define DE_LOWCYL       9 +#define DE_HIGHCYL      10 +#define DE_UPPERCYL     DE_HIGHCYL +#define DE_NUMBUFFERS   11 +#define DE_BUFMEMTYPE   12 +#define DE_MEMBUFTYPE   DE_BUFMEMTYPE +#define DE_MAXTRANSFER  13 +#define DE_MASK         14 +#define DE_BOOTPRI      15 +#define DE_DOSTYPE      16 +#define DE_BAUD         17 +#define DE_CONTROL      18 +#define DE_BOOTBLOCKS   19 + + +/******************************** AFFS definitions */ +#define T_SHORT		2 +#define T_LIST			16 + +#define ST_FILE		-3 +#define ST_ROOT		1 +#define ST_USERDIR	2 + +struct BootBlock{ +	int id; +	int chksum; +	int rootblock; +	int data[127]; +}; + +struct RootBlock{ +	int p_type;					//0 +	int n1[2];					//1-2 +	int hashtable_size;		//3 +	int n2;						//4 +	int checksum;				//5 +	int hashtable[72];		//6-77 +	int bitmap_valid_flag;	//78 +	int bitmap_ptrs[25];		//79-103 +	int bitmap_extension;	//104 +	int root_days;				//105 +	int root_mins;				//106 +	int root_ticks;			//107; +	char diskname[32];		//108-115 +	int n3[2];					//116-117 +	int volume_days;			//118 +	int volume_mins;			//119 +	int volume_ticks;			//120 +	int creation_days;		//121 +	int creation_mins;		//122 +	int creation_ticks;		//123 +	int n4[3];					//124-126 +	int s_type;					//127 +}; + +struct DirHeader { +	int p_type;					//0 +	int own_key;				//1 +	int n1[3];					//2-4 +	int checksum;				//5 +	int hashtable[72];		//6-77 +	int n2;						//78 +	int owner;					//79 +	int protection;			//80 +	int n3;						//81 +	char comment[92];			//82-104 +	int days;					//105 +	int mins;					//106 +	int ticks;					//107 +	char name[32];				//108-115 +	int n4[2];					//116-117 +	int linkchain;				//118 +	int n5[5];					//119-123 +	int hashchain;				//124 +	int parent;					//125 +	int n6;						//126 +	int s_type;					//127 +}; + +struct FileHeader { +	int p_type;					//0 +	int own_key;				//1 +	int n1[3];					//2-4 +	int checksum;				//5 +	int filekey_table[72];	//6-77 +	int n2;						//78 +	int owner;					//79 +	int protection;			//80 +	int bytesize;				//81 +	char comment[92];			//82-104 +	int days;					//105 +	int mins;					//106 +	int ticks;					//107 +	char name[32];				//108-115 +	int n3[2];					//116-117 +	int linkchain;				//118 +	int n4[5];					//119-123 +	int hashchain;				//124 +	int parent;					//125 +	int extension;				//126 +	int s_type;					//127 +}; + +struct FileKeyExtension{ +	int p_type;					//0 +	int own_key;				//1 +	int table_size;			//2 +	int n1[2];					//3-4 +	int checksum;				//5 +	int filekey_table[72];	//6-77 +	int info[46];				//78-123 +	int n2;						//124 +	int parent;					//125 +	int extension;				//126 +	int s_type;					//127 +}; + +struct Position { +	unsigned int block; +	short filekey; +	unsigned short byte; +	unsigned int offset; +}; + +struct ReadData { +	unsigned int header_block; +	struct Position current; +	unsigned int filesize; +}; + +//#warning "Big vs. little endian for configure needed" +#define AROS_BE2LONG(l)	\ +	(                                  \ +	    ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \ +	    ((((unsigned long)(l)) >>  8) & 0x0000FF00UL) | \ +	    ((((unsigned long)(l)) <<  8) & 0x00FF0000UL) | \ +	    ((((unsigned long)(l)) << 24) & 0xFF000000UL)   \ +	) + +struct CacheBlock { +	int blocknum; +	unsigned short flags; +	unsigned short access_count; +	unsigned int blockbuffer[128]; +}; +#define LockBuffer(x) (((struct CacheBlock *)(x))->flags |= 0x0001) +#define UnLockBuffer(x) (((struct CacheBlock *)(x))->flags &= ~0x0001) + +#define MAX_CACHE_BLOCKS 10 + +struct FSysBuffer { +	struct ReadData file; +	struct CacheBlock blocks[MAX_CACHE_BLOCKS]; +}; + +#define bootBlock(x) ((struct BootBlock *)(x)->blockbuffer) +#define rootBlock(x) ((struct RootBlock *)(x)->blockbuffer) +#define dirHeader(x) ((struct DirHeader *)(x)->blockbuffer) +#define fileHeader(x) ((struct FileHeader *)(x)->blockbuffer) +#define extensionBlock(x) ((struct FileKeyExtension *)(x)->blockbuffer) + +#define rdsk(x) ((struct RigidDiskBlock *)(x)->blockbuffer) +#define part(x) ((struct PartitionBlock *)(x)->blockbuffer) + +static struct FSysBuffer *fsysb; +static int blockoffset; /* offset if there is an embedded RDB partition */ +static int rootb;       /* block number of root block */ +static int rdbb;        /* block number of rdb block */ + +static void initCache(void) +{ +int i; + +	for (i=0;i<MAX_CACHE_BLOCKS;i++) +	{ +		fsysb->blocks[i].blocknum = -1; +		fsysb->blocks[i].flags = 0; +		fsysb->blocks[i].access_count = 0; +	} +} + +static struct CacheBlock *getBlock(unsigned int block) +{ +struct CacheBlock *freeblock; +int i; + +	/* get first unlocked block */ +	i = 0; +	do +	{ +		freeblock = &fsysb->blocks[i++]; +	} while (freeblock->flags & 0x0001); +	/* search through list if block is already loaded in */ +	for (i=0;i<MAX_CACHE_BLOCKS;i++) +	{ +		if (fsysb->blocks[i].blocknum == block) +		{ +			fsysb->blocks[i].access_count++; +			return &fsysb->blocks[i]; +		} +		if (!(fsysb->blocks[i].flags & 0x0001)) +			if (freeblock->access_count>fsysb->blocks[i].access_count) +				freeblock = &fsysb->blocks[i]; +	} +	freeblock->blocknum = block; +	devread(block+blockoffset, 0, 512, (char *)freeblock->blockbuffer); +	return freeblock; +} + +static unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer) +{ +unsigned int sum=0,count=0; + +	for (count=0;count<SizeBlock;count++) +		sum += AROS_BE2LONG(buffer[count]); +	return sum; +} + +int affs_mount(void) { +struct CacheBlock *cblock; +int i; + +	if ( +			(current_drive & 0x80) && +			(current_partition != 0xFFFFFF) && +			(current_slice != 0x30) +		) +		return 0; +	fsysb = (struct FSysBuffer *)FSYS_BUF; +	blockoffset = 0; +	initCache(); +	/* check for rdb partitiontable */ +	for (i=0;i<RDB_LOCATION_LIMIT;i++) +	{ +		cblock = getBlock(i); +		if ( +				( +					((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFFFFFF00)==0x444F5300) && +					((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFF)>0) +				) || +				(AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) +			) +			break; +	} +	if (i == RDB_LOCATION_LIMIT) +		return 0; +	if (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) +	{ +		/* we have an RDB partition table within a MBR-Partition */ +		rdbb = i; +	} +	else if (i<2) +	{ +		/* partition type is 0x30 = AROS and AFFS formatted */ +		rdbb = RDB_LOCATION_LIMIT; +		rootb = (part_length-1+2)/2; +		cblock = getBlock(rootb); +		if ( +				(AROS_BE2LONG(rootBlock(cblock)->p_type) != T_SHORT) || +				(AROS_BE2LONG(rootBlock(cblock)->s_type) != ST_ROOT) || +				calcChkSum(128, cblock->blockbuffer) +			) +			return 0; +	} +	else +		return 0; +	return 1; +} + +static int seek(unsigned long offset) +{ +struct CacheBlock *cblock; +unsigned long block; +unsigned long togo; + +	block = fsysb->file.header_block; + +	togo = offset / 512; +	fsysb->file.current.filekey = 71-(togo % 72); +	togo /= 72; +	fsysb->file.current.byte = offset % 512; +	fsysb->file.current.offset = offset; +	while ((togo) && (block)) +	{ +		disk_read_func = disk_read_hook; +		cblock = getBlock(block); +                disk_read_func = NULL; +		block = AROS_BE2LONG(extensionBlock(cblock)->extension); +		togo--; +	} +	if (togo) +		return 1; +	fsysb->file.current.block = block; +	return 0; +} + +int affs_read(char *buf, int len) { +struct CacheBlock *cblock; +unsigned short size; +unsigned int readbytes = 0; + +	if (fsysb->file.current.offset != filepos) +	{ +		if (seek(filepos)) +			return ERR_FILELENGTH; +	} +	if (fsysb->file.current.block == 0) +		return 0; +	if (len>(fsysb->file.filesize-fsysb->file.current.offset)) +		len=fsysb->file.filesize-fsysb->file.current.offset; +	disk_read_func = disk_read_hook; +	cblock = getBlock(fsysb->file.current.block); +        disk_read_func = NULL; +	while (len) +	{ +		disk_read_func = disk_read_hook; +		if (fsysb->file.current.filekey<0) +		{ +			fsysb->file.current.filekey = 71; +			fsysb->file.current.block = AROS_BE2LONG(extensionBlock(cblock)->extension); +			if (fsysb->file.current.block) +			{ +				cblock = getBlock(fsysb->file.current.block); +			} +                        //#warning "else shouldn't occour" +		} +		size = 512; +		size -= fsysb->file.current.byte; +		if (size>len) +		{ +			size = len; +			devread +				( +					AROS_BE2LONG +					( +						extensionBlock(cblock)->filekey_table +							[fsysb->file.current.filekey] +					)+blockoffset, +					fsysb->file.current.byte, size, (char *)((long)buf+readbytes) +				); +			fsysb->file.current.byte += size; +		} +		else +		{ +			devread +				( +					AROS_BE2LONG +					( +						extensionBlock(cblock)->filekey_table +							[fsysb->file.current.filekey] +					)+blockoffset, +					fsysb->file.current.byte, size, (char *)((long)buf+readbytes) +				); +			fsysb->file.current.byte = 0; +			fsysb->file.current.filekey--; +		} +                disk_read_func = NULL; +		len -= size; +		readbytes += size; +	} +	fsysb->file.current.offset += readbytes; +	filepos = fsysb->file.current.offset; +	return readbytes; +} + +static unsigned char capitalch(unsigned char ch, unsigned char flags) +{ + +	if ((flags==0) || (flags==1)) +		return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch); +	else		// DOS\(>=2) +		return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) || +				 ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch); +} + +// str2 is a BCPL string +static int noCaseStrCmp(char *str1, char *str2, unsigned char flags) +{ +unsigned char length; + +	length=str2++[0]; +	do { +		if ((*str1==0) && (length==0)) +			return 0; +		length--; +//		if ((*str1==0) && (*str2==0)) return 1; +	} while (capitalch(*str1++,flags)==capitalch(*str2++,flags)); +	str1--; +	return (*str1) ? 1 : -1; +} + +static unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags) +{ +unsigned int length; + +	length=0; +	while (name[length] != 0) +	    length++; +	while (*name!=0) +		length=(length * 13 +capitalch(*name++,flags)) & 0x7FF; +	return length%tablesize; +} + +static grub_error_t getHeaderBlock(char *name, struct CacheBlock **dirh) +{ +int key; + +	key = getHashKey(name, 72, 1); +	if (!dirHeader(*dirh)->hashtable[key]) +		return ERR_FILE_NOT_FOUND; +	*dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashtable[key])); +	if (calcChkSum(128, (*dirh)->blockbuffer)) +	{ +#ifdef DEBUG_AFFS +printf("ghb: %d\n", (*dirh)->blocknum); +#endif +		return ERR_FSYS_CORRUPT; +	} +	if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) +		return ERR_BAD_FILETYPE; +	while (noCaseStrCmp(name,dirHeader(*dirh)->name,1) != 0) +	{ +		if (!dirHeader(*dirh)->hashchain) +			return ERR_FILE_NOT_FOUND; +		*dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashchain)); +		if (calcChkSum(128, (*dirh)->blockbuffer)) +		{ +#ifdef DEBUG_AFFS +printf("ghb2: %d\n", (*dirh)->blocknum); +#endif +			return ERR_FSYS_CORRUPT; +		} +		if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) +			return ERR_BAD_FILETYPE; +	} +	return 0; +} + +static char *copyPart(char *src, char *dst) +{ +	while ((*src != '/') && (*src)) +		*dst++ = *src++; +	if (*src == '/') +		src++; +	*dst-- = 0; +	/* cut off spaces at the end */ +	while (*dst == ' ') +		*dst-- = 0; +	return src; +} + +static grub_error_t findBlock(char *name, struct CacheBlock **dirh) +{ +char dname[32]; +int block; + +	name++;	/* skip "/" */ +	/* partition table part */ +	if (rdbb < RDB_LOCATION_LIMIT) +	{ +	int bpc; + +		blockoffset = 0; +		*dirh = getBlock(rdbb); +		if (*name==0) +			return 0; +		name = copyPart(name, dname); +		bpc = AROS_BE2LONG(rdsk(*dirh)->rdb_Sectors)*AROS_BE2LONG(rdsk(*dirh)->rdb_Heads); +		block = AROS_BE2LONG(rdsk(*dirh)->rdb_PartitionList); +		while (block != -1) +		{ +			*dirh = getBlock(block); +			if (noCaseStrCmp(dname, part(*dirh)->pb_DriveName, 1) == 0) +				break; +			block = AROS_BE2LONG(part(*dirh)->pb_Next); +		} +		if (block == -1) +			return ERR_FILE_NOT_FOUND; +		if	( +				((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFFFFFF00)!=0x444F5300) || +				((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFF)==0) +			) +			return ERR_BAD_FILETYPE; +		blockoffset = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_LOWCYL]); +		rootb = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_HIGHCYL]); +		rootb = rootb-blockoffset+1; /* highcyl-lowcyl+1 */ +		rootb *= bpc; +		rootb = rootb-1+AROS_BE2LONG(part(*dirh)->pb_Environment[DE_RESERVEDBLKS]); +		rootb /= 2; +		blockoffset *= bpc; +	} + +	/* filesystem part */ +	*dirh = getBlock(rootb); +	while (*name) +	{ +		if ( +				(AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_ROOT) && +				(AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_USERDIR) +			) +			return ERR_BAD_FILETYPE; +		name = copyPart(name, dname); +		errnum = getHeaderBlock(dname, dirh); +		if (errnum) +			return errnum; +	} +	return 0; +} + +#ifndef STAGE1_5 +static void checkPossibility(char *filename, char *bstr) +{ +	char cstr[32]; + +	if (noCaseStrCmp(filename, bstr, 1)<=0) +	{ +		if (print_possibilities>0) +			print_possibilities = -print_possibilities; +		memcpy(cstr, bstr+1, bstr[0]); +		cstr[bstr[0]]=0; +		print_a_completion(cstr); +	} +} +#else +#define checkPossibility(a, b) do { } while(0) +#endif + +int affs_dir(char *dirname) +{ +    struct CacheBlock *buffer1; +    struct CacheBlock *buffer2; +    char *current = dirname; +    char filename[128]; +    char *fname = filename; +    int i,block; + +    if (print_possibilities) +    { +	while (*current) +	    current++; +	while (*current != '/') +	    current--; +	current++; +	while (*current) +	{ +	    *fname++ = *current; +	    *current++ = 0; +	} +	*fname=0; +	errnum = findBlock(dirname, &buffer1); +	if (errnum) +	    return 0; +	if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == IDNAME_RIGIDDISK) +	{ +	    block = AROS_BE2LONG(rdsk(buffer1)->rdb_PartitionList); +	    while (block != -1) +	    { +		buffer1 = getBlock(block); +		checkPossibility(filename, part(buffer1)->pb_DriveName); +		block = AROS_BE2LONG(part(buffer1)->pb_Next); +	    } +#ifndef STAGE1_5 +	    if (*filename == 0) +		if (print_possibilities>0) +		    print_possibilities = -print_possibilities; +#endif +	} +	else if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == T_SHORT) +	{ +	    LockBuffer(buffer1); +	    for (i=0;i<72;i++) +	    { +		block = dirHeader(buffer1)->hashtable[i]; +		while (block) +		{ +		    buffer2 = getBlock(AROS_BE2LONG(block)); +		    if (calcChkSum(128, buffer2->blockbuffer)) +		    { +			errnum = ERR_FSYS_CORRUPT; +			return 0; +		    } +		    if (AROS_BE2LONG(dirHeader(buffer2)->p_type) != T_SHORT) +		    { +			errnum = ERR_BAD_FILETYPE; +			return 0; +		    } +		    checkPossibility(filename, dirHeader(buffer2)->name); +		    block = dirHeader(buffer2)->hashchain; +		} +	    } +	    UnLockBuffer(buffer1); +#ifndef STAGE1_5 +	    if (*filename == 0) +		if (print_possibilities>0) +		    print_possibilities = -print_possibilities; +#endif +	} +	else +	{ +	    errnum = ERR_BAD_FILETYPE; +	    return 0; +	} +	while (*current != '/') +	    current--; +	current++; +	fname = filename; +	while (*fname) +	    *current++ = *fname++; +        //#warning "TODO: add some more chars until possibilities differ" +	if (print_possibilities>0) +	    errnum = ERR_FILE_NOT_FOUND; +	return (print_possibilities<0); +    } +    else +    { +	while (*current && !isspace(*current)) +	    *fname++ = *current++; +	*fname = 0; + +	errnum = findBlock(filename, &buffer2); +	if (errnum) +	    return 0; +	if (AROS_BE2LONG(fileHeader(buffer2)->s_type)!=ST_FILE) +	{ +	    errnum = ERR_BAD_FILETYPE; +	    return 0; +	} +	fsysb->file.header_block = AROS_BE2LONG(fileHeader(buffer2)->own_key); +	fsysb->file.current.block = AROS_BE2LONG(fileHeader(buffer2)->own_key); +	fsysb->file.current.filekey = 71; +	fsysb->file.current.byte = 0; +	fsysb->file.current.offset = 0; +	fsysb->file.filesize = AROS_BE2LONG(fileHeader(buffer2)->bytesize); +	filepos = 0; +	filemax = fsysb->file.filesize; +	return 1; +    } +} +#endif diff --git a/roms/openbios/fs/grubfs/fsys_ext2fs.c b/roms/openbios/fs/grubfs/fsys_ext2fs.c new file mode 100644 index 00000000..05425bbd --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_ext2fs.c @@ -0,0 +1,794 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 1999, 2001  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_EXT2FS + +#include "config.h" +#include "shared.h" +#include "filesys.h" +#include "libc/byteorder.h" + +#ifdef CONFIG_DEBUG_EXT2FS +#define E2DEBUG +#endif + +static int mapblock1, mapblock2; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE 1024		/* initial block size for superblock read */ +/* made up, defaults to 1 but can be passed via mount_opts */ +#define WHICH_SUPER 1 +/* kind of from fs/ext2/super.c */ +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */ + +/* include/asm-i386/types.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* + * Constants relative to the data blocks, from ext2_fs.h + */ +#define EXT2_NDIR_BLOCKS                12 +#define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1) + +/* include/linux/ext2_fs.h */ +struct ext2_super_block +  { +    __u32 s_inodes_count;	/* Inodes count */ +    __u32 s_blocks_count;	/* Blocks count */ +    __u32 s_r_blocks_count;	/* Reserved blocks count */ +    __u32 s_free_blocks_count;	/* Free blocks count */ +    __u32 s_free_inodes_count;	/* Free inodes count */ +    __u32 s_first_data_block;	/* First Data Block */ +    __u32 s_log_block_size;	/* Block size */ +    __s32 s_log_frag_size;	/* Fragment size */ +    __u32 s_blocks_per_group;	/* # Blocks per group */ +    __u32 s_frags_per_group;	/* # Fragments per group */ +    __u32 s_inodes_per_group;	/* # Inodes per group */ +    __u32 s_mtime;		/* Mount time */ +    __u32 s_wtime;		/* Write time */ +    __u16 s_mnt_count;		/* Mount count */ +    __s16 s_max_mnt_count;	/* Maximal mount count */ +    __u16 s_magic;		/* Magic signature */ +    __u16 s_state;		/* File system state */ +    __u16 s_errors;		/* Behaviour when detecting errors */ +    __u16 s_pad; +    __u32 s_lastcheck;		/* time of last check */ +    __u32 s_checkinterval;	/* max. time between checks */ +    __u32 s_creator_os;		/* OS */ +    __u32 s_rev_level;		/* Revision level */ +    __u16 s_def_resuid;		/* Default uid for reserved blocks */ +    __u16 s_def_resgid;		/* Default gid for reserved blocks */ +    __u32 s_reserved[235];	/* Padding to the end of the block */ +  }; + +struct ext2_group_desc +  { +    __u32 bg_block_bitmap;	/* Blocks bitmap block */ +    __u32 bg_inode_bitmap;	/* Inodes bitmap block */ +    __u32 bg_inode_table;	/* Inodes table block */ +    __u16 bg_free_blocks_count;	/* Free blocks count */ +    __u16 bg_free_inodes_count;	/* Free inodes count */ +    __u16 bg_used_dirs_count;	/* Directories count */ +    __u16 bg_pad; +    __u32 bg_reserved[3]; +  }; + +struct ext2_inode +  { +    __u16 i_mode;		/* File mode */ +    __u16 i_uid;		/* Owner Uid */ +    __u32 i_size;		/* 4: Size in bytes */ +    __u32 i_atime;		/* Access time */ +    __u32 i_ctime;		/* 12: Creation time */ +    __u32 i_mtime;		/* Modification time */ +    __u32 i_dtime;		/* 20: Deletion Time */ +    __u16 i_gid;		/* Group Id */ +    __u16 i_links_count;	/* 24: Links count */ +    __u32 i_blocks;		/* Blocks count */ +    __u32 i_flags;		/* 32: File flags */ +    union +      { +	struct +	  { +	    __u32 l_i_reserved1; +	  } +	linux1; +	struct +	  { +	    __u32 h_i_translator; +	  } +	hurd1; +	struct +	  { +	    __u32 m_i_reserved1; +	  } +	masix1; +      } +    osd1;			/* OS dependent 1 */ +    __u32 i_block[EXT2_N_BLOCKS];	/* 40: Pointers to blocks */ +    __u32 i_version;		/* File version (for NFS) */ +    __u32 i_file_acl;		/* File ACL */ +    __u32 i_dir_acl;		/* Directory ACL */ +    __u32 i_faddr;		/* Fragment address */ +    union +      { +	struct +	  { +	    __u8 l_i_frag;	/* Fragment number */ +	    __u8 l_i_fsize;	/* Fragment size */ +	    __u16 i_pad1; +	    __u32 l_i_reserved2[2]; +	  } +	linux2; +	struct +	  { +	    __u8 h_i_frag;	/* Fragment number */ +	    __u8 h_i_fsize;	/* Fragment size */ +	    __u16 h_i_mode_high; +	    __u16 h_i_uid_high; +	    __u16 h_i_gid_high; +	    __u32 h_i_author; +	  } +	hurd2; +	struct +	  { +	    __u8 m_i_frag;	/* Fragment number */ +	    __u8 m_i_fsize;	/* Fragment size */ +	    __u16 m_pad1; +	    __u32 m_i_reserved2[2]; +	  } +	masix2; +      } +    osd2;			/* OS dependent 2 */ +  }; + +/* linux/posix_type.h */ +typedef long linux_off_t; + +/* linux/ext2fs.h */ +#define EXT2_NAME_LEN 255 +struct ext2_dir_entry +  { +    __u32 inode;		/* Inode number */ +    __u16 rec_len;		/* Directory entry length */ +    __u8 name_len;		/* Name length */ +    __u8 file_type; +    char name[EXT2_NAME_LEN];	/* File name */ +  }; + +/* ext2/super.c */ +#define EXT2_SUPER_MAGIC      0xEF53	/* include/linux/ext2_fs.h */ +#define EXT2_ROOT_INO              2	/* include/linux/ext2_fs.h */ +#define PATH_MAX                1024	/* include/linux/limits.h */ +#define MAX_LINK_COUNT             5	/* number of symbolic links to follow */ + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ +    ((struct ext2_super_block *)(FSYS_BUF)) +#define GROUP_DESC \ +    ((struct ext2_group_desc *) \ +     ((char *)SUPERBLOCK + sizeof(struct ext2_super_block))) +#define INODE \ +    ((struct ext2_inode *)((char *)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK))) +#define DATABLOCK1 \ +    ((char *)((char *)INODE + sizeof(struct ext2_inode))) +#define DATABLOCK2 \ +    ((char *)((char *)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK))) + +/* linux/ext2_fs.h */ +#define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT2_ADDR_PER_BLOCK_BITS(s)	(log2(EXT2_ADDR_PER_BLOCK(s))) + +/* linux/ext2_fs.h */ +#define EXT2_BLOCK_SIZE_BITS(s)        (__le32_to_cpu((s)->s_log_block_size) + 10) +/* kind of from ext2/super.c */ +#define EXT2_BLOCK_SIZE(s)	(1 << EXT2_BLOCK_SIZE_BITS(s)) +/* linux/ext2fs.h */ +#define EXT2_DESC_PER_BLOCK(s) \ +     (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +/* linux/stat.h */ +#define S_IFMT  00170000 +#define S_IFLNK  0120000 +#define S_IFREG  0100000 +#define S_IFDIR  0040000 +#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR) + +#ifdef E2DEBUG +void +dump_super(struct ext2_super_block *s) +{ +    printf(" superblock 0x%x:\n", s); +    printf("  inodes=%d\n", __le32_to_cpu(s->s_inodes_count)); +    printf("  blocks=%d\n", __le32_to_cpu(s->s_blocks_count)); +    printf("  reserved=%d\n", __le32_to_cpu(s->s_r_blocks_count)); +    printf("  i_free=%d\n", __le32_to_cpu(s->s_free_inodes_count)); +    printf("  b_free=%d\n", __le32_to_cpu(s->s_free_blocks_count)); +    printf("  first=%d\n", __le32_to_cpu(s->s_first_data_block)); +    printf("  log_b_size=%d, b_size=%d\n", __le32_to_cpu(s->s_log_block_size), EXT2_BLOCK_SIZE(s)); +    printf("  log_f_size=%d\n", __le32_to_cpu(s->s_log_frag_size)); +    printf("  bpg=%d\n", __le32_to_cpu(s->s_blocks_per_group)); +    printf("  fpg=%d\n", __le32_to_cpu(s->s_frags_per_group)); +    printf("  ipg=%d\n", __le32_to_cpu(s->s_inodes_per_group)); +} + +void +dump_group_desc(struct ext2_group_desc *g) +{ +    printf(" group_desc 0x%x:\n", g); +    printf("  b_bmap block=%d\n", __le32_to_cpu(g->bg_block_bitmap)); +    printf("  i_bmap block=%d\n", __le32_to_cpu(g->bg_inode_bitmap)); +    printf("  i_tab block=%d\n", __le32_to_cpu(g->bg_inode_table)); +    printf("  free_blks=%d\n", __le16_to_cpu(g->bg_free_blocks_count)); +    printf("  free_inodes=%d\n", __le16_to_cpu(g->bg_free_inodes_count)); +    printf("  used_dirs=%d\n", __le16_to_cpu(g->bg_used_dirs_count)); +} + +void +dump_inode(struct ext2_inode *i) +{ +    printf(" inode 0x%x:\n", i); +    printf("  mode=%o\n", __le16_to_cpu(i->i_mode)); +    printf("  uid=%d\n", __le16_to_cpu(i->i_uid)); +    printf("  gid=%d\n", __le16_to_cpu(i->i_gid)); +    printf("  size=%d\n", __le32_to_cpu(i->i_size)); +    printf("  atime=%d\n", __le32_to_cpu(i->i_atime)); +    printf("  ctime=%d\n", __le32_to_cpu(i->i_ctime)); +    printf("  mtime=%d\n", __le32_to_cpu(i->i_mtime)); +    printf("  dtime=%d\n", __le32_to_cpu(i->i_dtime)); +    printf("  links=%d\n", __le16_to_cpu(i->i_links_count)); +    printf("  blocks=%d\n", __le32_to_cpu(i->i_blocks)); +    printf("  flags=%d\n", __le32_to_cpu(i->i_flags)); +} + +void +dump_inode_data(unsigned char *inode, int len) +{ +  static char hexdigit[] = "0123456789abcdef"; +  unsigned char *i; +  for (i = inode; +       i < (inode + len); +       i++) +    { +      printf ("%c", hexdigit[*i >> 4]); +      printf ("%c", hexdigit[*i % 16]); +      if (!((i + 1 - inode) % 16)) +	{ +	  printf ("\n"); +	} +      else +	{ +	  printf (" "); +	} +    } +} +#endif + +/* check filesystem types and read superblock into memory buffer */ +int +ext2fs_mount (void) +{ +  int retval = 1; + +  if ((((current_drive & 0x80) || (current_slice != 0)) +       && (current_slice != PC_SLICE_TYPE_EXT2FS) +       && (current_slice != PC_SLICE_TYPE_LINUX_RAID) +       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) +       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) +      || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE)) +      || !devread (SBLOCK, 0, sizeof (struct ext2_super_block), +		   (char *) SUPERBLOCK) +      || __le16_to_cpu(SUPERBLOCK->s_magic) != EXT2_SUPER_MAGIC) +      retval = 0; + +  return retval; +} + +/* Takes a file system block number and reads it into BUFFER. */ +static int +ext2_rdfsb (int fsblock, char * buffer) +{ +#ifdef E2DEBUG +  printf ("ext2_rdfsb: fsblock %d, devblock %d, size %d\n", fsblock, +	  fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), +	  EXT2_BLOCK_SIZE (SUPERBLOCK)); +#endif /* E2DEBUG */ +  return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0, +		  EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer); +} + +/* from +  ext2/inode.c:ext2_bmap() +*/ +/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into +   a physical block (the location in the file system) via an inode. */ +static int +ext2fs_block_map (int logical_block) +{ + +#ifdef E2DEBUG +  printf ("ext2fs_block_map(%d)\n", logical_block); +#endif /* E2DEBUG */ + +  /* if it is directly pointed to by the inode, return that physical addr */ +  if (logical_block < EXT2_NDIR_BLOCKS) +    { +#ifdef E2DEBUG +      printf ("ext2fs_block_map: returning %d\n", __le32_to_cpu(INODE->i_block[logical_block])); +#endif /* E2DEBUG */ +      return __le32_to_cpu(INODE->i_block[logical_block]); +    } +  /* else */ +  logical_block -= EXT2_NDIR_BLOCKS; +  /* try the indirect block */ +  if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK)) +    { +      if (mapblock1 != 1 +	  && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_IND_BLOCK]), DATABLOCK1)) +	{ +	  errnum = ERR_FSYS_CORRUPT; +	  return -1; +	} +      mapblock1 = 1; +      return __le32_to_cpu(((__u32 *) DATABLOCK1)[logical_block]); +    } +  /* else */ +  logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK); +  /* now try the double indirect block */ +  if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2))) +    { +      int bnum; +      if (mapblock1 != 2 +	  && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_DIND_BLOCK]), DATABLOCK1)) +	{ +	  errnum = ERR_FSYS_CORRUPT; +	  return -1; +	} +      mapblock1 = 2; +      if ((bnum = __le32_to_cpu(((__u32 *) DATABLOCK1) +		   [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)])) +	  != mapblock2 +	  && !ext2_rdfsb (bnum, DATABLOCK2)) +	{ +	  errnum = ERR_FSYS_CORRUPT; +	  return -1; +	} +      mapblock2 = bnum; +      return __le32_to_cpu(((__u32 *) DATABLOCK2) +	[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); +    } +  /* else */ +  mapblock2 = -1; +  logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)); +  if (mapblock1 != 3 +      && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_TIND_BLOCK]), DATABLOCK1)) +    { +      errnum = ERR_FSYS_CORRUPT; +      return -1; +    } +  mapblock1 = 3; +  if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK1) +		   [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) +				      * 2)]), +		   DATABLOCK2)) +    { +      errnum = ERR_FSYS_CORRUPT; +      return -1; +    } +  if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK2) +		   [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)) +		    & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]), +		   DATABLOCK2)) +    { +      errnum = ERR_FSYS_CORRUPT; +      return -1; +    } +  return __le32_to_cpu(((__u32 *) DATABLOCK2) +    [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); +} + +/* preconditions: all preconds of ext2fs_block_map */ +int +ext2fs_read (char *buf, int len) +{ +  int logical_block; +  int offset; +  int map; +  int ret = 0; +  int size = 0; + +#ifdef E2DEBUG +  printf("ext2fs_read(0x%x, %d)\n", buf, len); +  dump_inode(INODE); +  dump_inode_data((unsigned char *)INODE, sizeof (struct ext2_inode)); +#endif /* E2DEBUG */ +  while (len > 0) +    { +      /* find the (logical) block component of our location */ +      logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); +      offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); +      map = ext2fs_block_map (logical_block); +#ifdef E2DEBUG +      printf ("map=%d\n", map); +#endif /* E2DEBUG */ +      if (map < 0) +	break; + +      size = EXT2_BLOCK_SIZE (SUPERBLOCK); +      size -= offset; +      if (size > len) +	size = len; + +      disk_read_func = disk_read_hook; + +      devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), +	       offset, size, buf); + +      disk_read_func = NULL; + +      buf += size; +      len -= size; +      filepos += size; +      ret += size; +    } + +  if (errnum) +    ret = 0; + +  return ret; +} + + +/* Based on: +   def_blk_fops points to +   blkdev_open, which calls (I think): +   sys_open() +   do_open() +   open_namei() +   dir_namei() which accesses current->fs->root +     fs->root was set during original mount: +     (something)... which calls (I think): +     ext2_read_super() +     iget() +     __iget() +     read_inode() +     ext2_read_inode() +       uses desc_per_block_bits, which is set in ext2_read_super() +       also uses group descriptors loaded during ext2_read_super() +   lookup() +   ext2_lookup() +   ext2_find_entry() +   ext2_getblk() + +*/ + +/* preconditions: ext2fs_mount already executed, therefore supblk in buffer + *   known as SUPERBLOCK + * returns: 0 if error, nonzero iff we were able to find the file successfully + * postconditions: on a nonzero return, buffer known as INODE contains the + *   inode of the file we were trying to look up + * side effects: messes up GROUP_DESC buffer area + */ +int +ext2fs_dir (char *dirname) +{ +  int current_ino = EXT2_ROOT_INO;	/* start at the root */ +  int updir_ino = current_ino;	/* the parent of the current directory */ +  int group_id;			/* which group the inode is in */ +  int group_desc;		/* fs pointer to that group */ +  int desc;			/* index within that group */ +  int ino_blk;			/* fs pointer of the inode's information */ +  int str_chk = 0;		/* used to hold the results of a string compare */ +  struct ext2_group_desc *gdp; +  struct ext2_inode *raw_inode;	/* inode info corresponding to current_ino */ + +  char linkbuf[PATH_MAX];	/* buffer for following symbolic links */ +  int link_count = 0; + +  char *rest; +  char ch;			/* temp char holder */ + +  int off;			/* offset within block of directory entry (off mod blocksize) */ +  int loc;			/* location within a directory */ +  int blk;			/* which data blk within dir entry (off div blocksize) */ +  long map;			/* fs pointer of a particular block from dir entry */ +  struct ext2_dir_entry *dp;	/* pointer to directory entry */ + +  /* loop invariants: +     current_ino = inode to lookup +     dirname = pointer to filename component we are cur looking up within +     the directory known pointed to by current_ino (if any) +   */ + +#ifdef E2DEBUG +  printf("****** ext2fs_dir(%s)\n", dirname); +  dump_super(SUPERBLOCK); +#endif /* E2DEBUG */ + +  while (1) +    { +#ifdef E2DEBUG +      printf ("ext2fs_dir: inode %d\n", current_ino); +      printf ("ext2fs_dir: dirname=%s\n", dirname); +#endif /* E2DEBUG */ + +      /* look up an inode */ +      group_id = (current_ino - 1) / __le32_to_cpu(SUPERBLOCK->s_inodes_per_group); +      group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); +      desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1); +#ifdef E2DEBUG +      printf ("ext2fs_dir: ipg=%d, dpb=%d\n", __le32_to_cpu(SUPERBLOCK->s_inodes_per_group), +	      EXT2_DESC_PER_BLOCK (SUPERBLOCK)); +      printf ("ext2fs_dir: group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc); +#endif /* E2DEBUG */ +      if (!ext2_rdfsb ( +			(WHICH_SUPER + group_desc + __le32_to_cpu(SUPERBLOCK->s_first_data_block)), +			(char*) GROUP_DESC)) +	{ +	  return 0; +	} + +#ifdef E2DEBUG +      dump_group_desc(GROUP_DESC); +#endif /* E2DEBUG */ + +      gdp = GROUP_DESC; +      ino_blk = __le32_to_cpu(gdp[desc].bg_inode_table) + +	(((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)) +	 >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); +#ifdef E2DEBUG +      printf ("ext2fs_dir: itab_blk=%d, i_in_grp=%d, log2=%d\n", +	 __le32_to_cpu(gdp[desc].bg_inode_table), +	 ((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)), +	 log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); +      printf ("ext2fs_dir: inode table fsblock=%d\n", ino_blk); +#endif /* E2DEBUG */ +      if (!ext2_rdfsb (ino_blk, (char *)INODE)) +	{ +	  return 0; +	} + +      /* reset indirect blocks! */ +      mapblock2 = mapblock1 = -1; + +      raw_inode = INODE + +	((current_ino - 1) +	 & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1)); +#ifdef E2DEBUG +      printf ("ext2fs_dir: ipb=%d, sizeof(inode)=%d\n", +	      (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)), +	      sizeof (struct ext2_inode)); +      printf ("ext2fs_dir: inode=%x, raw_inode=%x\n", INODE, raw_inode); +      printf ("ext2fs_dir: offset into inode table block=%d\n", (int) raw_inode - (int) INODE); +      dump_inode(raw_inode); +      dump_inode_data((unsigned char *)INODE, EXT2_BLOCK_SIZE(SUPERBLOCK)); +      printf ("ext2fs_dir: first word=%x\n", *((int *) raw_inode)); +#endif /* E2DEBUG */ + +      /* copy inode to fixed location */ +      memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode)); + +#ifdef E2DEBUG +      dump_inode(INODE); +      printf ("ext2fs_dir: first word=%x\n", *((int *) INODE)); +#endif /* E2DEBUG */ + +      /* If we've got a symbolic link, then chase it. */ +      if (S_ISLNK (__le16_to_cpu(INODE->i_mode))) +	{ +	  int len; +	  if (++link_count > MAX_LINK_COUNT) +	    { +	      errnum = ERR_SYMLINK_LOOP; +	      return 0; +	    } + +	  /* Find out how long our remaining name is. */ +	  len = 0; +	  while (dirname[len] && !isspace (dirname[len])) +	    len++; + +	  /* Get the symlink size. */ +	  filemax = __le32_to_cpu(INODE->i_size); +	  if (filemax + len > sizeof (linkbuf) - 2) +	    { +	      errnum = ERR_FILELENGTH; +	      return 0; +	    } + +	  if (len) +	    { +	      /* Copy the remaining name to the end of the symlink data. +	         Note that DIRNAME and LINKBUF may overlap! */ +	      memmove (linkbuf + filemax, dirname, len); +	    } +	  linkbuf[filemax + len] = '\0'; + +	  /* Read the symlink data. */ +	  if (__le32_to_cpu(INODE->i_blocks)) +	    { +	      /* Read the necessary blocks, and reset the file pointer. */ +	      len = file_read (linkbuf, filemax); +	      filepos = 0; +	      if (!len) +		return 0; +	    } +	  else +	    { +	      /* Copy the data directly from the inode. */ +	      len = filemax; +	      memmove (linkbuf, (char *) INODE->i_block, len); +	    } + +#ifdef E2DEBUG +	  printf ("ext2fs_dir: symlink=%s\n", linkbuf); +#endif + +	  dirname = linkbuf; +	  if (*dirname == '/') +	    { +	      /* It's an absolute link, so look it up in root. */ +	      current_ino = EXT2_ROOT_INO; +	      updir_ino = current_ino; +	    } +	  else +	    { +	      /* Relative, so look it up in our parent directory. */ +	      current_ino = updir_ino; +	    } + +	  /* Try again using the new name. */ +	  continue; +	} + +      /* if end of filename, INODE points to the file's inode */ +      if (!*dirname || isspace (*dirname)) +	{ +	  if (!S_ISREG (__le16_to_cpu(INODE->i_mode))) +	    { +	      errnum = ERR_BAD_FILETYPE; +	      return 0; +	    } + +	  filemax = __le32_to_cpu(INODE->i_size); +	  return 1; +	} + +      /* else we have to traverse a directory */ +      updir_ino = current_ino; + +      /* skip over slashes */ +      while (*dirname == '/') +	dirname++; + +      /* if this isn't a directory of sufficient size to hold our file, abort */ +      if (!(__le32_to_cpu(INODE->i_size)) || !S_ISDIR (__le16_to_cpu(INODE->i_mode))) +	{ +	  errnum = ERR_BAD_FILETYPE; +	  return 0; +	} + +      /* skip to next slash or end of filename (space) */ +      for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; +	   rest++); + +      /* look through this directory and find the next filename component */ +      /* invariant: rest points to slash after the next filename component */ +      *rest = 0; +      loc = 0; + +      do +	{ + +#ifdef E2DEBUG +	  printf ("ext2fs_dir: dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc); +#endif /* E2DEBUG */ + +	  /* if our location/byte offset into the directory exceeds the size, +	     give up */ +	  if (loc >= __le32_to_cpu(INODE->i_size)) +	    { +	      if (print_possibilities < 0) +		{ +# if 0 +		  putchar ('\n'); +# endif +		} +	      else +		{ +		  errnum = ERR_FILE_NOT_FOUND; +		  *rest = ch; +		} +	      return (print_possibilities < 0); +	    } + +	  /* else, find the (logical) block component of our location */ +	  blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + +	  /* we know which logical block of the directory entry we are looking +	     for, now we have to translate that to the physical (fs) block on +	     the disk */ +	  map = ext2fs_block_map (blk); +#ifdef E2DEBUG +	  printf ("ext2fs_dir: fs block=%d\n", map); +#endif /* E2DEBUG */ +	  mapblock2 = -1; +	  if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) +	    { +	      errnum = ERR_FSYS_CORRUPT; +	      *rest = ch; +	      return 0; +	    } +	  off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); +	  dp = (struct ext2_dir_entry *) (DATABLOCK2 + off); +	  /* advance loc prematurely to next on-disk directory entry  */ +	  loc += __le16_to_cpu(dp->rec_len); + +	  /* NOTE: ext2fs filenames are NOT null-terminated */ + +#ifdef E2DEBUG +	  printf ("ext2fs_dir: directory entry ino=%d\n", __le32_to_cpu(dp->inode)); +	  if (__le32_to_cpu(dp->inode)) +	    printf ("entry=%s\n", dp->name); +#endif /* E2DEBUG */ + +	  if (__le32_to_cpu(dp->inode)) +	    { +	      int saved_c = dp->name[dp->name_len]; + +	      dp->name[dp->name_len] = 0; +	      str_chk = substring (dirname, dp->name); + +# ifndef STAGE1_5 +	      if (print_possibilities && ch != '/' +		  && (!*dirname || str_chk <= 0)) +		{ +		  if (print_possibilities > 0) +		    print_possibilities = -print_possibilities; +		  print_a_completion (dp->name); +		} +# endif + +	      dp->name[dp->name_len] = saved_c; +	    } + +	} +      while (!__le32_to_cpu(dp->inode) || (str_chk || (print_possibilities && ch != '/'))); + +      current_ino = __le32_to_cpu(dp->inode); +      *(dirname = rest) = ch; +    } +  /* never get here */ +} + +#endif /* FSYS_EXT2_FS */ diff --git a/roms/openbios/fs/grubfs/fsys_fat.c b/roms/openbios/fs/grubfs/fsys_fat.c new file mode 100644 index 00000000..a7e160d1 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_fat.c @@ -0,0 +1,477 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2000, 2001   Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_FAT + +#include "shared.h" +#include "filesys.h" +#include "fat.h" + +struct fat_superblock +{ +  int fat_offset; +  int fat_length; +  int fat_size; +  int root_offset; +  int root_max; +  int data_offset; + +  int num_sectors; +  int num_clust; +  int clust_eof_marker; +  int sects_per_clust; +  int sectsize_bits; +  int clustsize_bits; +  int root_cluster; + +  int cached_fat; +  int file_cluster; +  int current_cluster_num; +  int current_cluster; +}; + +/* pointer(s) into filesystem info buffer for DOS stuff */ +#define FAT_SUPER ( (struct fat_superblock *) \ + 		    ( FSYS_BUF + 32256) )/* 512 bytes long */ +#define FAT_BUF   ( FSYS_BUF + 30208 )	/* 4 sector FAT buffer */ +#define NAME_BUF  ( FSYS_BUF + 29184 )	/* Filename buffer (833 bytes) */ + +#define FAT_CACHE_SIZE 2048 + +int +fat_mount (void) +{ +  struct fat_bpb bpb; +  __u32 magic, first_fat; + +  /* Check partition type for harddisk */ +  if (((current_drive & 0x80) || (current_slice != 0)) +      && ! IS_PC_SLICE_TYPE_FAT (current_slice) +      && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS))) +    return 0; + +  /* Read bpb */ +  if (! devread (0, 0, sizeof (bpb), (char *) &bpb)) +    return 0; + +  /* Check if the number of sectors per cluster is zero here, to avoid +     zero division.  */ +  if (bpb.sects_per_clust == 0) +    return 0; + +  FAT_SUPER->sectsize_bits = log2 (bpb.bytes_per_sect); +  FAT_SUPER->clustsize_bits +    = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust); + +  /* Fill in info about super block */ +  FAT_SUPER->num_sectors = bpb.short_sectors +    ? bpb.short_sectors : bpb.long_sectors; + +  /* FAT offset and length */ +  FAT_SUPER->fat_offset = bpb.reserved_sects; +  FAT_SUPER->fat_length = +    bpb.fat_length ? bpb.fat_length : bpb.fat32_length; + +  /* Rootdir offset and length for FAT12/16 */ +  FAT_SUPER->root_offset = +    FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length; +  FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * bpb.dir_entries; + +  /* Data offset and number of clusters */ +  FAT_SUPER->data_offset = +    FAT_SUPER->root_offset +    + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1; +  FAT_SUPER->num_clust = +    2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset) +	 / bpb.sects_per_clust); +  FAT_SUPER->sects_per_clust = bpb.sects_per_clust; + +  if (!bpb.fat_length) +    { +      /* This is a FAT32 */ +      if (bpb.dir_entries) + 	return 0; + +      if (bpb.flags & 0x0080) +	{ +	  /* FAT mirroring is disabled, get active FAT */ +	  int active_fat = bpb.flags & 0x000f; +	  if (active_fat >= bpb.num_fats) +	    return 0; +	  FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length; +	} + +      FAT_SUPER->fat_size = 8; +      FAT_SUPER->root_cluster = bpb.root_cluster; + +      /* Yes the following is correct.  FAT32 should be called FAT28 :) */ +      FAT_SUPER->clust_eof_marker = 0xffffff8; +    } +  else +    { +      if (!FAT_SUPER->root_max) + 	return 0; + +      FAT_SUPER->root_cluster = -1; +      if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST) +	{ +	  FAT_SUPER->fat_size = 4; +	  FAT_SUPER->clust_eof_marker = 0xfff8; +	} +      else +	{ +	  FAT_SUPER->fat_size = 3; +	  FAT_SUPER->clust_eof_marker = 0xff8; +	} +    } + + +  /* Now do some sanity checks */ + +  if (bpb.bytes_per_sect != (1 << FAT_SUPER->sectsize_bits) +      || bpb.bytes_per_sect != SECTOR_SIZE +      || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits + 				       - FAT_SUPER->sectsize_bits)) +      || FAT_SUPER->num_clust <= 2 +      || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE) + 	  > FAT_SUPER->fat_length)) +    return 0; + +  /* kbs: Media check on first FAT entry [ported from PUPA] */ + +  if (!devread(FAT_SUPER->fat_offset, 0, +               sizeof(first_fat), (char *)&first_fat)) +    return 0; + +  if (FAT_SUPER->fat_size == 8) +    { +      first_fat &= 0x0fffffff; +      magic = 0x0fffff00; +    } +  else if (FAT_SUPER->fat_size == 4) +    { +      first_fat &= 0x0000ffff; +      magic = 0xff00; +    } +  else +    { +      first_fat &= 0x00000fff; +      magic = 0x0f00; +    } + +  if (first_fat != (magic | bpb.media)) +    return 0; + +  FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE; +  return 1; +} + +int +fat_read (char *buf, int len) +{ +  int logical_clust; +  int offset; +  int ret = 0; +  int size; + +  if (FAT_SUPER->file_cluster < 0) +    { +      /* root directory for fat16 */ +      size = FAT_SUPER->root_max - filepos; +      if (size > len) + 	size = len; +      if (!devread(FAT_SUPER->root_offset, filepos, size, buf)) + 	return 0; +      filepos += size; +      return size; +    } + +  logical_clust = filepos >> FAT_SUPER->clustsize_bits; +  offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1)); +  if (logical_clust < FAT_SUPER->current_cluster_num) +    { +      FAT_SUPER->current_cluster_num = 0; +      FAT_SUPER->current_cluster = FAT_SUPER->file_cluster; +    } + +  while (len > 0) +    { +      int sector; +      while (logical_clust > FAT_SUPER->current_cluster_num) +	{ +	  /* calculate next cluster */ +	  int fat_entry = +	    FAT_SUPER->current_cluster * FAT_SUPER->fat_size; +	  int next_cluster; +	  int cached_pos = (fat_entry - FAT_SUPER->cached_fat); + +	  if (cached_pos < 0 || +	      (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE) +	    { +	      FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1)); +	      cached_pos = (fat_entry - FAT_SUPER->cached_fat); +	      sector = FAT_SUPER->fat_offset +		+ FAT_SUPER->cached_fat / (2*SECTOR_SIZE); +	      if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF)) +		return 0; +	    } +	  next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1)); +	  if (FAT_SUPER->fat_size == 3) +	    { +	      if (cached_pos & 1) +		next_cluster >>= 4; +	      next_cluster &= 0xFFF; +	    } +	  else if (FAT_SUPER->fat_size == 4) +	    next_cluster &= 0xFFFF; + +	  if (next_cluster >= FAT_SUPER->clust_eof_marker) +	    return ret; +	  if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust) +	    { +	      errnum = ERR_FSYS_CORRUPT; +	      return 0; +	    } + +	  FAT_SUPER->current_cluster = next_cluster; +	  FAT_SUPER->current_cluster_num++; +	} + +      sector = FAT_SUPER->data_offset + +	((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits + 					      - FAT_SUPER->sectsize_bits)); +      size = (1 << FAT_SUPER->clustsize_bits) - offset; +      if (size > len) +	size = len; + +      disk_read_func = disk_read_hook; + +      devread(sector, offset, size, buf); + +      disk_read_func = NULL; + +      len -= size; +      buf += size; +      ret += size; +      filepos += size; +      logical_clust++; +      offset = 0; +    } +  return errnum ? 0 : ret; +} + +int +fat_dir (char *dirname) +{ +  char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH]; +  char *filename = (char *) NAME_BUF; +  int attrib = FAT_ATTRIB_DIR; +#ifndef STAGE1_5 +  int do_possibilities = 0; +#endif + +  /* XXX I18N: +   * the positions 2,4,6 etc are high bytes of a 16 bit unicode char +   */ +  static unsigned char longdir_pos[] = +  { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; +  int slot = -2; +  int alias_checksum = -1; + +  FAT_SUPER->file_cluster = FAT_SUPER->root_cluster; +  filepos = 0; +  FAT_SUPER->current_cluster_num = MAXINT; + +  /* main loop to find desired directory entry */ + loop: + +  /* if we have a real file (and we're not just printing possibilities), +     then this is where we want to exit */ + +  if (!*dirname || isspace (*dirname)) +    { +      if (attrib & FAT_ATTRIB_DIR) +	{ +	  errnum = ERR_BAD_FILETYPE; +	  return 0; +	} + +      return 1; +    } + +  /* continue with the file/directory name interpretation */ + +  while (*dirname == '/') +    dirname++; + +  if (!(attrib & FAT_ATTRIB_DIR)) +    { +      errnum = ERR_BAD_FILETYPE; +      return 0; +    } +  /* Directories don't have a file size */ +  filemax = MAXINT; + +  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + +  *rest = 0; + +# ifndef STAGE1_5 +  if (print_possibilities && ch != '/') +    do_possibilities = 1; +# endif + +  while (1) +    { +      if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH +	  || dir_buf[0] == 0) +	{ +	  if (!errnum) +	    { +# ifndef STAGE1_5 +	      if (print_possibilities < 0) +		{ +#if 0 +		  putchar ('\n'); +#endif +		  return 1; +		} +# endif /* STAGE1_5 */ + +	      errnum = ERR_FILE_NOT_FOUND; +	      *rest = ch; +	    } + +	  return 0; +	} + +      if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME) +	{ +	  /* This is a long filename.  The filename is build from back +	   * to front and may span multiple entries.  To bind these +	   * entries together they all contain the same checksum over +	   * the short alias. +	   * +	   * The id field tells if this is the first entry (the last +	   * part) of the long filename, and also at which offset this +	   * belongs. +	   * +	   * We just write the part of the long filename this entry +	   * describes and continue with the next dir entry. +	   */ +	  int i, offset; +	  unsigned char id = FAT_LONGDIR_ID(dir_buf); + +	  if ((id & 0x40)) +	    { +	      id &= 0x3f; +	      slot = id; +	      filename[slot * 13] = 0; +	      alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf); +	    } + +	  if (id != slot || slot == 0 +	      || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf)) +	    { +	      alias_checksum = -1; +	      continue; +	    } + +	  slot--; +	  offset = slot * 13; + +	  for (i=0; i < 13; i++) +	    filename[offset+i] = dir_buf[longdir_pos[i]]; +	  continue; +	} + +      if (!FAT_DIRENTRY_VALID (dir_buf)) +	continue; + +      if (alias_checksum != -1 && slot == 0) +	{ +	  int i; +	  unsigned char sum; + +	  slot = -2; +	  for (sum = 0, i = 0; i< 11; i++) +	    sum = ((sum >> 1) | (sum << 7)) + dir_buf[i]; + +	  if (sum == alias_checksum) +	    { +# ifndef STAGE1_5 +	      if (do_possibilities) +		goto print_filename; +# endif /* STAGE1_5 */ + +	      if (substring (dirname, filename) == 0) +		break; +	    } +	} + +      /* XXX convert to 8.3 filename format here */ +      { +	int i, j, c; + +	for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i])) +	       && !isspace (c); i++); + +	filename[i++] = '.'; + +	for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j])) +	       && !isspace (c); j++); + +	if (j == 0) +	  i--; + +	filename[i + j] = 0; +      } + +# ifndef STAGE1_5 +      if (do_possibilities) +	{ +	print_filename: +	  if (substring (dirname, filename) <= 0) +	    { +	      if (print_possibilities > 0) +		print_possibilities = -print_possibilities; +	      print_a_completion (filename); +	    } +	  continue; +	} +# endif /* STAGE1_5 */ + +      if (substring (dirname, filename) == 0) +	break; +    } + +  *(dirname = rest) = ch; + +  attrib = FAT_DIRENTRY_ATTRIB (dir_buf); +  filemax = FAT_DIRENTRY_FILELENGTH (dir_buf); +  filepos = 0; +  FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf); +  FAT_SUPER->current_cluster_num = MAXINT; + +  /* go back to main loop at top of function */ +  goto loop; +} + +#endif /* FSYS_FAT */ diff --git a/roms/openbios/fs/grubfs/fsys_ffs.c b/roms/openbios/fs/grubfs/fsys_ffs.c new file mode 100644 index 00000000..c6804b8b --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_ffs.c @@ -0,0 +1,311 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2000, 2001  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +/* + * Elements of this file were originally from the FreeBSD "biosboot" + * bootloader file "disk.c" dated 4/12/95. + * + * The license and header comments from that file are included here. + */ + +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU + *  School of Computer Science + *  Carnegie Mellon University + *  Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + *	from: Mach, Revision 2.2  92/04/04  11:35:49  rpd + *	$Id: fsys_ffs.c,v 1.10 2001/11/12 06:57:29 okuji Exp $ + */ + +#ifdef FSYS_FFS + +#include "shared.h" + +#include "filesys.h" + +#include "defs.h" +#include "disk_inode.h" +#include "disk_inode_ffs.h" +#include "dir.h" +#include "fs.h" + +/* used for filesystem map blocks */ +static int mapblock; +static int mapblock_offset; +static int mapblock_bsize; + +/* pointer to superblock */ +#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 )) +#define INODE ((struct icommon *) ( FSYS_BUF + 16384 )) +#define MAPBUF ( FSYS_BUF + 24576 ) +#define MAPBUF_LEN 8192 + + +int +ffs_mount (void) +{ +  int retval = 1; + +  if ((((current_drive & 0x80) || (current_slice != 0)) +       && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_BSDFFS)) +      || part_length < (SBLOCK + (SBSIZE / DEV_BSIZE)) +      || !devread (SBLOCK, 0, SBSIZE, (char *) SUPERBLOCK) +      || SUPERBLOCK->fs_magic != FS_MAGIC) +    retval = 0; + +  mapblock = -1; +  mapblock_offset = -1; + +  return retval; +} + +static int +block_map (int file_block) +{ +  int bnum, offset, bsize; + +  if (file_block < NDADDR) +    return (INODE->i_db[file_block]); + +  /* If the blockmap loaded does not include FILE_BLOCK, +     load a new blockmap.  */ +  if ((bnum = fsbtodb (SUPERBLOCK, INODE->i_ib[0])) != mapblock +      || (mapblock_offset <= bnum && bnum <= mapblock_offset + mapblock_bsize)) +    { +      if (MAPBUF_LEN < SUPERBLOCK->fs_bsize) +	{ +	  offset = ((file_block - NDADDR) % NINDIR (SUPERBLOCK)); +	  bsize = MAPBUF_LEN; + +	  if (offset + MAPBUF_LEN > SUPERBLOCK->fs_bsize) +	    offset = (SUPERBLOCK->fs_bsize - MAPBUF_LEN) / sizeof (int); +	} +      else +	{ +	  bsize = SUPERBLOCK->fs_bsize; +	  offset = 0; +	} + +      if (! devread (bnum, offset * sizeof (int), bsize, (char *) MAPBUF)) +	{ +	  mapblock = -1; +	  mapblock_bsize = -1; +	  mapblock_offset = -1; +	  errnum = ERR_FSYS_CORRUPT; +	  return -1; +	} + +      mapblock = bnum; +      mapblock_bsize = bsize; +      mapblock_offset = offset; +    } + +  return (((int *) MAPBUF)[((file_block - NDADDR) % NINDIR (SUPERBLOCK)) +			  - mapblock_offset]); +} + + +int +ffs_read (char *buf, int len) +{ +  int logno, off, size, map, ret = 0; + +  while (len && !errnum) +    { +      off = blkoff (SUPERBLOCK, filepos); +      logno = lblkno (SUPERBLOCK, filepos); +      size = blksize (SUPERBLOCK, INODE, logno); + +      if ((map = block_map (logno)) < 0) +	break; + +      size -= off; + +      if (size > len) +	size = len; + +      disk_read_func = disk_read_hook; + +      devread (fsbtodb (SUPERBLOCK, map), off, size, buf); + +      disk_read_func = NULL; + +      buf += size; +      len -= size; +      filepos += size; +      ret += size; +    } + +  if (errnum) +    ret = 0; + +  return ret; +} + + +int +ffs_dir (char *dirname) +{ +  char *rest, ch; +  int block, off, loc, map, ino = ROOTINO; +  struct direct *dp; + +/* main loop to find destination inode */ +loop: + +  /* load current inode (defaults to the root inode) */ + +	if (!devread (fsbtodb (SUPERBLOCK, itod (SUPERBLOCK, ino)), +								ino % (SUPERBLOCK->fs_inopb) * sizeof (struct dinode), +								sizeof (struct dinode), (char *) INODE)) +			return 0;			/* XXX what return value? */ + +  /* if we have a real file (and we're not just printing possibilities), +     then this is where we want to exit */ + +  if (!*dirname || isspace (*dirname)) +    { +      if ((INODE->i_mode & IFMT) != IFREG) +	{ +	  errnum = ERR_BAD_FILETYPE; +	  return 0; +	} + +      filemax = INODE->i_size; + +      /* incomplete implementation requires this! */ +      fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize; +      return 1; +    } + +  /* continue with file/directory name interpretation */ + +  while (*dirname == '/') +    dirname++; + +  if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR)) +    { +      errnum = ERR_BAD_FILETYPE; +      return 0; +    } + +  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + +  *rest = 0; +  loc = 0; + +  /* loop for reading a the entries in a directory */ + +  do +    { +      if (loc >= INODE->i_size) +	{ +#if 0 +	  putchar ('\n'); +#endif + +	  if (print_possibilities < 0) +	    return 1; + +	  errnum = ERR_FILE_NOT_FOUND; +	  *rest = ch; +	  return 0; +	} + +      if (!(off = blkoff (SUPERBLOCK, loc))) +	{ +	  block = lblkno (SUPERBLOCK, loc); + +	  if ((map = block_map (block)) < 0 +	      || !devread (fsbtodb (SUPERBLOCK, map), 0, +			   blksize (SUPERBLOCK, INODE, block), +			   (char *) FSYS_BUF)) +	    { +	      errnum = ERR_FSYS_CORRUPT; +	      *rest = ch; +	      return 0; +	    } +	} + +      dp = (struct direct *) (FSYS_BUF + off); +      loc += dp->d_reclen; + +#ifndef STAGE1_5 +      if (dp->d_ino && print_possibilities && ch != '/' +	  && (!*dirname || substring (dirname, dp->d_name) <= 0)) +	{ +	  if (print_possibilities > 0) +	    print_possibilities = -print_possibilities; + +	  print_a_completion (dp->d_name); +	} +#endif /* STAGE1_5 */ +    } +  while (!dp->d_ino || (substring (dirname, dp->d_name) != 0 +			|| (print_possibilities && ch != '/'))); + +  /* only get here if we have a matching directory entry */ + +  ino = dp->d_ino; +  *(dirname = rest) = ch; + +  /* go back to main loop at top of function */ +  goto loop; +} + +int +ffs_embed (int *start_sector, int needed_sectors) +{ +  /* XXX: I don't know if this is really correct. Someone who is +     familiar with BSD should check for this.  */ +  if (needed_sectors > 14) +    return 0; + +  *start_sector = 1; +#if 1 +  /* FIXME: Disable the embedding in FFS until someone checks if +     the code above is correct.  */ +  return 0; +#else +  return 1; +#endif +} + +#endif /* FSYS_FFS */ diff --git a/roms/openbios/fs/grubfs/fsys_iso9660.c b/roms/openbios/fs/grubfs/fsys_iso9660.c new file mode 100644 index 00000000..12f94b73 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_iso9660.c @@ -0,0 +1,342 @@ +/* + *  ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + *  including Rock Ridge Extensions support + * + *  Copyright (C) 1998, 1999  Kousuke Takai  <tak@kmc.kyoto-u.ac.jp> + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ +/* + *  References: + *	linux/fs/isofs/rock.[ch] + *	mkisofs-1.11.1/diag/isoinfo.c + *	mkisofs-1.11.1/iso9660.h + *		(all are written by Eric Youngdale) + * + *  Modifications by: + *	Leonid Lisovskiy   <lly@pisem.net>	2003 + */ + +/* + * Modified to make it work with FILO + * 2003-10 by SONE Takeshi + */ + +#ifdef FSYS_ISO9660 + +#include "shared.h" +#include "filesys.h" +#include "iso9660.h" +#include "debug.h" + +#if defined(__sparc__) || defined(__PPC__) +#define ENDIAN b +#else +#define ENDIAN l +#endif + +struct iso_superblock { +    unsigned long vol_sector; + +    unsigned long file_start; +}; + +#define ISO_SUPER	((struct iso_superblock *)(FSYS_BUF)) +#define PRIMDESC        ((struct iso_primary_descriptor *)(FSYS_BUF + 2048)) +#define DIRREC          ((struct iso_directory_record *)(FSYS_BUF + 4096)) +#define RRCONT_BUF      ((unsigned char *)(FSYS_BUF + 6144)) +#define NAME_BUF        ((unsigned char *)(FSYS_BUF + 8192)) + +static int +iso9660_devread (int sector, int byte_offset, int byte_len, char *buf) +{ +  /* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte +   * CD-ROM sector */ +  return devread(sector<<2, byte_offset, byte_len, buf); +} + +int +iso9660_mount (void) +{ +  unsigned int sector; + +  /* +   *  Because there is no defined slice type ID for ISO-9660 filesystem, +   *  this test will pass only either (1) if entire disk is used, or +   *  (2) if current partition is BSD style sub-partition whose ID is +   *  ISO-9660. +   */ +  /*if ((current_partition != 0xFFFFFF) +      && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660)) +    return 0;*/ + +  /* +   *  Currently, only FIRST session of MultiSession disks are supported !!! +   */ +  for (sector = 16 ; sector < 32 ; sector++) +    { +      if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC)) +	break; +      /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */ +      if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0') +	  && CHECK2(PRIMDESC->id + 3, '0', '1')) +	{ +	  ISO_SUPER->vol_sector = sector; +	  ISO_SUPER->file_start = 0; +          fsmax = PRIMDESC->volume_space_size.ENDIAN; +	  return 1; +	} +    } + +  return 0; +} + +int +iso9660_dir (char *dirname) +{ +  struct iso_directory_record *idr; +  RR_ptr_t rr_ptr; +  struct rock_ridge *ce_ptr; +  unsigned int pathlen; +  int size; +  unsigned int extent; +  unsigned int rr_len; +  unsigned char file_type; +  unsigned char rr_flag; + +  idr = &PRIMDESC->root_directory_record; +  ISO_SUPER->file_start = 0; + +  do +  { +      while (*dirname == '/')	/* skip leading slashes */ +	  dirname++; +      /* pathlen = strcspn(dirname, "/\n\t "); */ +      for (pathlen = 0 ; +	  dirname[pathlen] +	     && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ; +	  pathlen++) +	; + +      size = idr->size.ENDIAN; +      extent = idr->extent.ENDIAN; + +      while (size > 0) +      { +	  if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC)) +	  { +	      errnum = ERR_FSYS_CORRUPT; +	      return 0; +	  } +	  extent++; + +	  idr = (struct iso_directory_record *)DIRREC; +	  for (; idr->length.ENDIAN > 0; +                 idr = (struct iso_directory_record *)((char *)idr + idr->length.ENDIAN) ) +	  { +              const char *name = (char *)idr->name; +              unsigned int name_len = idr->name_len.ENDIAN; + +              file_type = (idr->flags.ENDIAN & 2) ? ISO_DIRECTORY : ISO_REGULAR; +	      if (name_len == 1) +	      { +		  if ((name[0] == 0) ||	/* self */ +		      (name[0] == 1)) 	/* parent */ +		    continue; +	      } +	      if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1')) +	      { +		  name_len -= 2;	/* truncate trailing file version */ +		  if (name_len > 1 && name[name_len - 1] == '.') +		    name_len--;		/* truncate trailing dot */ +	      } + +	      /* +	       *  Parse Rock-Ridge extension +	       */ +              rr_len = (idr->length.ENDIAN - idr->name_len.ENDIAN +			- (unsigned char)sizeof(struct iso_directory_record) +			+ (unsigned char)sizeof(idr->name)); +              rr_ptr.ptr = ((char *)idr + idr->name_len.ENDIAN +			    + sizeof(struct iso_directory_record) +			    - sizeof(idr->name)); +	      if (rr_len & 1) +		rr_ptr.ptr++, rr_len--; +	      ce_ptr = NULL; +	      rr_flag = RR_FLAG_NM | RR_FLAG_PX; + +	      while (rr_len >= 4) +	      { +		  if (rr_ptr.rr->version != 1) +		  { +#ifndef STAGE1_5 +		    if (debug) +		      printf( +			    "Non-supported version (%d) RockRidge chunk " +			    "`%c%c'\n", rr_ptr.rr->version, +			    rr_ptr.rr->signature & 0xFF, +			    rr_ptr.rr->signature >> 8); +#endif +		  } +                  else if (CHECK2(&rr_ptr.rr->signature, 'R', 'R') +			   && rr_ptr.rr->len >= 5) +                      rr_flag &= rr_ptr.rr->u.rr.flags.ENDIAN; +                  else if (CHECK2(&rr_ptr.rr->signature, 'N', 'M')) +		  { +		      name = (char *)rr_ptr.rr->u.nm.name; +		      name_len = rr_ptr.rr->len - 5; +		      rr_flag &= ~RR_FLAG_NM; +		  } +                  else if (CHECK2(&rr_ptr.rr->signature, 'P', 'X') +			   && rr_ptr.rr->len >= 36) +		  { +                      file_type = ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT) +				   == POSIX_S_IFREG +				   ? ISO_REGULAR +                                   : ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT) +				      == POSIX_S_IFDIR +				      ? ISO_DIRECTORY : ISO_OTHER)); +		      rr_flag &= ~RR_FLAG_PX; +		  } +                  else if (CHECK2(&rr_ptr.rr->signature, 'C', 'E') +			   && rr_ptr.rr->len >= 28) +		    ce_ptr = rr_ptr.rr; +		  if (!rr_flag) +		    /* +		     * There is no more extension we expects... +		     */ +		    break; +		  rr_len -= rr_ptr.rr->len; +		  rr_ptr.ptr += rr_ptr.rr->len; +		  if (rr_len < 4 && ce_ptr != NULL) +		  { +		      /* preserve name before loading new extent. */ +		      if( RRCONT_BUF <= (unsigned char *)name +			  && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE ) +		      { +			  memcpy(NAME_BUF, name, name_len); +			  name = (char *)NAME_BUF; +		      } +                      rr_ptr.ptr = (char *)(RRCONT_BUF + ce_ptr->u.ce.offset.ENDIAN); +                      rr_len = ce_ptr->u.ce.size.ENDIAN; +                      if (!iso9660_devread(ce_ptr->u.ce.extent.ENDIAN, 0, +                                           ISO_SECTOR_SIZE, (char *)RRCONT_BUF)) +		      { +			  errnum = 0;	/* this is not fatal. */ +			  break; +		      } +		      ce_ptr = NULL; +		   } +	      } /* rr_len >= 4 */ + +	      filemax = MAXINT; +	      if (name_len >= pathlen +                  && !strnicmp(name, dirname, pathlen)) +	      { +                if (dirname[pathlen] == '/' || !print_possibilities) +		{ +		  /* +		   *  DIRNAME is directory component of pathname, +		   *  or we are to open a file. +		   */ +		  if (pathlen == name_len) +		  { +		      if (dirname[pathlen] == '/') +		      { +		          if (file_type != ISO_DIRECTORY) +		          { +			      errnum = ERR_BAD_FILETYPE; +			      return 0; +			  } +                          goto next_dir_level; +		      } +		      if (file_type != ISO_REGULAR) +		      { +		          errnum = ERR_BAD_FILETYPE; +		          return 0; +		      } +                      ISO_SUPER->file_start = idr->extent.ENDIAN; +		      filepos = 0; +                      filemax = idr->size.ENDIAN; +		      return 1; +		  } +		} +	        else	/* Completion */ +	        { +#ifndef STAGE1_5 + 		  if (print_possibilities > 0) +		      print_possibilities = -print_possibilities; +		  memcpy(NAME_BUF, name, name_len); +		  NAME_BUF[name_len] = '\0'; +            	  print_a_completion (NAME_BUF); +#endif +	        } +	      } +	  } /* for */ + +	  size -= ISO_SECTOR_SIZE; +      } /* size>0 */ + +      if (dirname[pathlen] == '/' || print_possibilities >= 0) +      { +	  errnum = ERR_FILE_NOT_FOUND; +	  return 0; +      } + +next_dir_level: +      dirname += pathlen; + +  } while (*dirname == '/'); + +  return 1; +} + +int +iso9660_read (char *buf, int len) +{ +  int sector, blkoffset, size, ret; + +  if (ISO_SUPER->file_start == 0) +    return 0; + +  ret = 0; +  blkoffset = filepos & (ISO_SECTOR_SIZE - 1); +  sector = filepos >> ISO_SECTOR_BITS; +  while (len > 0) +  { +    size = ISO_SECTOR_SIZE - blkoffset; +    if (size > len) +        size = len; + +    disk_read_func = disk_read_hook; + +    if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf)) +	return 0; + +    disk_read_func = NULL; + +    len -= size; +    buf += size; +    ret += size; +    filepos += size; +    sector++; +    blkoffset = 0; +  } + +  return ret; +} + +#endif /* FSYS_ISO9660 */ diff --git a/roms/openbios/fs/grubfs/fsys_jfs.c b/roms/openbios/fs/grubfs/fsys_jfs.c new file mode 100644 index 00000000..66469e68 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_jfs.c @@ -0,0 +1,404 @@ +/* fsys_jfs.c - an implementation for the IBM JFS file system */ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2001,2002  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_JFS + +#include "shared.h" +#include "filesys.h" +#include "jfs.h" + +#define MAX_LINK_COUNT	8 + +#define DTTYPE_INLINE	0 +#define DTTYPE_PAGE	1 + +struct jfs_info +{ +	int bsize; +	int l2bsize; +	int bdlog; +	int xindex; +	int xlastindex; +	int sindex; +	int slastindex; +	int de_index; +	int dttype; +	xad_t *xad; +	ldtentry_t *de; +}; + +static struct jfs_info jfs; + +#define xtpage		((xtpage_t *)FSYS_BUF) +#define dtpage		((dtpage_t *)((char *)FSYS_BUF + 4096)) +#define fileset		((dinode_t *)((char *)FSYS_BUF + 8192)) +#define inode		((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t))) +#define dtroot		((dtroot_t *)(&inode->di_btroot)) + +static ldtentry_t de_always[2] = { +    {1, -1, 2, {'.', '.'}, 0}, +    {1, -1, 1, {'.'}, 0} +}; + +static int +isinxt (s64 key, s64 offset, s64 len) +{ +	return (key >= offset) ? (key < offset + len ? 1 : 0) : 0; +} + +static xad_t * +first_extent (dinode_t *di) +{ +	xtpage_t *xtp; + +	jfs.xindex = 2; +	xtp = (xtpage_t *)&di->di_btroot; +	jfs.xad = &xtp->xad[2]; +	if (xtp->header.flag & BT_LEAF) { +	    	jfs.xlastindex = xtp->header.nextindex; +	} else { +		do { +			devread (addressXAD (jfs.xad) << jfs.bdlog, 0, +				 sizeof(xtpage_t), (char *)xtpage); +			jfs.xad = &xtpage->xad[2]; +		} while (!(xtpage->header.flag & BT_LEAF)); +		jfs.xlastindex = xtpage->header.nextindex; +	} + +	return jfs.xad; +} + +static xad_t * +next_extent (void) +{ +	if (++jfs.xindex < jfs.xlastindex) { +	} else if (xtpage->header.next) { +		devread (xtpage->header.next << jfs.bdlog, 0, +			 sizeof(xtpage_t), (char *)xtpage); +		jfs.xlastindex = xtpage->header.nextindex; +		jfs.xindex = XTENTRYSTART; +		jfs.xad = &xtpage->xad[XTENTRYSTART]; +	} else { +		return NULL; +	} +	return ++jfs.xad; +} + + +static void +di_read (u32 inum, dinode_t *di) +{ +	s64 key; +	u32 xd, ioffset; +	s64 offset; +	xad_t *xad; +	pxd_t pxd; + +	key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize; +	xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT; +	ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE; +	xad = first_extent (fileset); +	do { +		offset = offsetXAD (xad); +		if (isinxt (key, offset, lengthXAD (xad))) { +			devread ((addressXAD (xad) + key - offset) << jfs.bdlog, +				 3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd); +			devread (addressPXD (&pxd) << jfs.bdlog, +				 ioffset, DISIZE, (char *)di); +			break; +		} +	} while ((xad = next_extent ())); +} + +static ldtentry_t * +next_dentry (void) +{ +	ldtentry_t *de; +	s8 *stbl; + +	if (jfs.dttype == DTTYPE_INLINE) { +		if (jfs.sindex < jfs.slastindex) { +			return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]]; +		} +	} else { +		de = (ldtentry_t *)dtpage->slot; +		stbl = (s8 *)&de[(int)dtpage->header.stblindex]; +		if (jfs.sindex < jfs.slastindex) { +			return &de[(int)stbl[jfs.sindex++]]; +		} else if (dtpage->header.next) { +			devread (dtpage->header.next << jfs.bdlog, 0, +				 sizeof(dtpage_t), (char *)dtpage); +			jfs.slastindex = dtpage->header.nextindex; +			jfs.sindex = 1; +			return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]]; +		} +	} + +	return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL; +} + +static ldtentry_t * +first_dentry (void) +{ +	dtroot_t *dtr; +	pxd_t *xd; +	idtentry_t *de; + +	dtr = (dtroot_t *)&inode->di_btroot; +	jfs.sindex = 0; +	jfs.de_index = 0; + +	de_always[0].inumber = inode->di_parent; +	de_always[1].inumber = inode->di_number; +	if (dtr->header.flag & BT_LEAF) { +		jfs.dttype = DTTYPE_INLINE; +		jfs.slastindex = dtr->header.nextindex; +	} else { +		de = (idtentry_t *)dtpage->slot; +		jfs.dttype = DTTYPE_PAGE; +		xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd; +		for (;;) { +			devread (addressPXD (xd) << jfs.bdlog, 0, +				 sizeof(dtpage_t), (char *)dtpage); +			if (dtpage->header.flag & BT_LEAF) +				break; +			xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd; +		} +		jfs.slastindex = dtpage->header.nextindex; +	} + +	return next_dentry (); +} + + +static dtslot_t * +next_dslot (int next) +{ +	return (jfs.dttype == DTTYPE_INLINE) +		? (dtslot_t *)&dtroot->slot[next] +		: &((dtslot_t *)dtpage->slot)[next]; +} + +static void +uni2ansi (UniChar *uni, char *ansi, int len) +{ +	for (; len; len--, uni++) +		*ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni; +} + +int +jfs_mount (void) +{ +	struct jfs_superblock super; + +	if (part_length < MINJFS >> SECTOR_BITS +	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0, +			 sizeof(struct jfs_superblock), (char *)&super) +	    || (super.s_magic != JFS_MAGIC) +	    || !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I, +			 0, DISIZE, (char*)fileset)) { +		return 0; +	} + +	jfs.bsize = super.s_bsize; +	jfs.l2bsize = super.s_l2bsize; +	jfs.bdlog = jfs.l2bsize - SECTOR_BITS; + +	return 1; +} + +int +jfs_read (char *buf, int len) +{ +	xad_t *xad; +	s64 endofprev, endofcur; +	s64 offset, xadlen; +	int toread, startpos, endpos; + +	startpos = filepos; +	endpos = filepos + len; +	endofprev = (1ULL << 62) - 1; +	xad = first_extent (inode); +	do { +		offset = offsetXAD (xad); +		xadlen = lengthXAD (xad); +		if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) { +			endofcur = (offset + xadlen) << jfs.l2bsize; +			toread = (endofcur >= endpos) +				  ? len : (endofcur - filepos); + +			disk_read_func = disk_read_hook; +			devread (addressXAD (xad) << jfs.bdlog, +				 filepos - (offset << jfs.l2bsize), toread, buf); +			disk_read_func = NULL; + +			buf += toread; +			len -= toread; +			filepos += toread; +		} else if (offset > endofprev) { +			toread = ((offset << jfs.l2bsize) >= endpos) +				  ? len : ((offset - endofprev) << jfs.l2bsize); +			len -= toread; +			filepos += toread; +			for (; toread; toread--) { +				*buf++ = 0; +			} +			continue; +		} +		endofprev = offset + xadlen; +		xad = next_extent (); +	} while (len > 0 && xad); + +	return filepos - startpos; +} + +int +jfs_dir (char *dirname) +{ +	char *ptr, *rest, ch; +	ldtentry_t *de; +	dtslot_t *ds; +	u32 inum, parent_inum; +	s64 di_size; +	u32 di_mode; +	int namlen, cmp, n, link_count; +	char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX]; + +	parent_inum = inum = ROOT_I; +	link_count = 0; +	for (;;) { +		di_read (inum, inode); +		di_size = inode->di_size; +		di_mode = inode->di_mode; + +		if ((di_mode & IFMT) == IFLNK) { +			if (++link_count > MAX_LINK_COUNT) { +				errnum = ERR_SYMLINK_LOOP; +				return 0; +			} +			if (di_size < (di_mode & INLINEEA ? 256 : 128)) { +				grub_memmove (linkbuf, inode->di_fastsymlink, di_size); +				n = di_size; +			} else if (di_size < JFS_PATH_MAX - 1) { +				filepos = 0; +				filemax = di_size; +				n = jfs_read (linkbuf, filemax); +			} else { +				errnum = ERR_FILELENGTH; +				return 0; +			} + +			inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum; +			while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++)); +			linkbuf[n] = 0; +			dirname = linkbuf; +			continue; +		} + +		if (!*dirname || isspace (*dirname)) { +			if ((di_mode & IFMT) != IFREG) { +				errnum = ERR_BAD_FILETYPE; +				return 0; +			} +			filepos = 0; +			filemax = di_size; +			return 1; +		} + +		if ((di_mode & IFMT) != IFDIR) { +			errnum = ERR_BAD_FILETYPE; +			return 0; +		} + +		for (; *dirname == '/'; dirname++); + +		for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); +		*rest = 0; + +		de = first_dentry (); +		for (;;) { +			namlen = de->namlen; +			if (de->next == -1) { +				uni2ansi (de->name, namebuf, namlen); +				namebuf[namlen] = 0; +			} else { +				uni2ansi (de->name, namebuf, DTLHDRDATALEN); +				ptr = namebuf; +				ptr += DTLHDRDATALEN; +				namlen -= DTLHDRDATALEN; +				ds = next_dslot (de->next); +				while (ds->next != -1) { +					uni2ansi (ds->name, ptr, DTSLOTDATALEN); +					ptr += DTSLOTDATALEN; +					namlen -= DTSLOTDATALEN; +					ds = next_dslot (ds->next); +				} +				uni2ansi (ds->name, ptr, namlen); +				ptr += namlen; +				*ptr = 0; +			} + +			cmp = (!*dirname) ? -1 : substring (dirname, namebuf); +#ifndef STAGE1_5 +			if (print_possibilities && ch != '/' +			    && cmp <= 0) { +				if (print_possibilities > 0) +					print_possibilities = -print_possibilities; +				print_a_completion (namebuf); +			} else +#endif +			if (cmp == 0) { +				parent_inum = inum; +				inum = de->inumber; +		        	*(dirname = rest) = ch; +				break; +			} +			de = next_dentry (); +			if (de == NULL) { +				if (print_possibilities < 0) +					return 1; + +				errnum = ERR_FILE_NOT_FOUND; +				*rest = ch; +				return 0; +			} +		} +	} +} + +int +jfs_embed (int *start_sector, int needed_sectors) +{ +	struct jfs_superblock super; + +	if (needed_sectors > 63 +	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0, +			 sizeof (struct jfs_superblock), +			 (char *)&super) +	    || (super.s_magic != JFS_MAGIC)) { +		return 0; +	} + +	*start_sector = 1; +	return 1; +} + +#endif /* FSYS_JFS */ diff --git a/roms/openbios/fs/grubfs/fsys_minix.c b/roms/openbios/fs/grubfs/fsys_minix.c new file mode 100644 index 00000000..d16b58c8 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_minix.c @@ -0,0 +1,535 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +/* Restrictions: +   This is MINIX V1 only (yet) +   Disk creation is like: +   mkfs.minix -c DEVICE +*/ + +#ifdef FSYS_MINIX + +#include "shared.h" +#include "filesys.h" + +/* #define DEBUG_MINIX */ + +/* indirect blocks */ +static int mapblock1, mapblock2, namelen; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE 	(1<<BLOCK_SIZE_BITS) + +/* made up, defaults to 1 but can be passed via mount_opts */ +#define WHICH_SUPER 1 +/* kind of from fs/ext2/super.c (is OK for minix) */ +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */ + +/* include/asm-i386/type.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* include/linux/minix_fs.h */ +#define MINIX_ROOT_INO 1 + +/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */ +#define MINIX_LINK_MAX  250 +#define MINIX2_LINK_MAX 65530 + +#define MINIX_I_MAP_SLOTS       8 +#define MINIX_Z_MAP_SLOTS       64 +#define MINIX_SUPER_MAGIC       0x137F          /* original minix fs */ +#define MINIX_SUPER_MAGIC2      0x138F          /* minix fs, 30 char names */ +#define MINIX2_SUPER_MAGIC      0x2468          /* minix V2 fs */ +#define MINIX2_SUPER_MAGIC2     0x2478          /* minix V2 fs, 30 char names */ +#define MINIX_VALID_FS          0x0001          /* Clean fs. */ +#define MINIX_ERROR_FS          0x0002          /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +#define MINIX_V1                0x0001          /* original minix fs */ +#define MINIX_V2                0x0002          /* minix V2 fs */ + +/* originally this is : +#define INODE_VERSION(inode)    inode->i_sb->u.minix_sb.s_version +   here we have */ +#define INODE_VERSION(inode)	(SUPERBLOCK->s_version) + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { +	__u16 i_mode; +	__u16 i_uid; +	__u32 i_size; +	__u32 i_time; +	__u8  i_gid; +	__u8  i_nlinks; +	__u16 i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { +	__u16 i_mode; +	__u16 i_nlinks; +	__u16 i_uid; +	__u16 i_gid; +	__u32 i_size; +	__u32 i_atime; +	__u32 i_mtime; +	__u32 i_ctime; +	__u32 i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { +        __u16 s_ninodes; +        __u16 s_nzones; +        __u16 s_imap_blocks; +        __u16 s_zmap_blocks; +        __u16 s_firstdatazone; +        __u16 s_log_zone_size; +        __u32 s_max_size; +        __u16 s_magic; +        __u16 s_state; +        __u32 s_zones; +}; + +struct minix_dir_entry { +        __u16 inode; +        char name[0]; +}; + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ +    ((struct minix_super_block *)(FSYS_BUF)) +#define INODE \ +    ((struct minix_inode *)((char *) SUPERBLOCK + BLOCK_SIZE)) +#define DATABLOCK1 \ +    ((char *)((char *)INODE + sizeof(struct minix_inode))) +#define DATABLOCK2 \ +    ((char *)((char *)DATABLOCK1 + BLOCK_SIZE)) + +/* linux/stat.h */ +#define S_IFMT  00170000 +#define S_IFLNK  0120000 +#define S_IFREG  0100000 +#define S_IFDIR  0040000 +#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR) + +#define PATH_MAX                1024	/* include/linux/limits.h */ +#define MAX_LINK_COUNT             5	/* number of symbolic links to follow */ + +/* check filesystem types and read superblock into memory buffer */ +int +minix_mount (void) +{ +  if (((current_drive & 0x80) || current_slice != 0) +      && ! IS_PC_SLICE_TYPE_MINIX (current_slice) +      && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)) +    return 0;			/* The partition is not of MINIX type */ + +  if (part_length < (SBLOCK + +		     (sizeof (struct minix_super_block) / DEV_BSIZE))) +    return 0;			/* The partition is too short */ + +  if (!devread (SBLOCK, 0, sizeof (struct minix_super_block), +		(char *) SUPERBLOCK)) +    return 0;			/* Cannot read superblock */ + +  switch (SUPERBLOCK->s_magic) +    { +    case MINIX_SUPER_MAGIC: +      namelen = 14; +      break; +    case MINIX_SUPER_MAGIC2: +      namelen = 30; +      break; +    default: +      return 0;			/* Unsupported type */ +    } + +  return 1; +} + +/* Takes a file system block number and reads it into BUFFER. */ +static int +minix_rdfsb (int fsblock, char *buffer) +{ +  return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0, +		  BLOCK_SIZE, buffer); +} + +/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into +   a physical block (the location in the file system) via an inode. */ +static int +minix_block_map (int logical_block) +{ +  int i; + +  if (logical_block < 7) +    return INODE->i_zone[logical_block]; + +  logical_block -= 7; +  if (logical_block < 512) +    { +      i = INODE->i_zone[7]; + +      if (!i || ((mapblock1 != 1) +		 && !minix_rdfsb (i, DATABLOCK1))) +	{ +	  errnum = ERR_FSYS_CORRUPT; +	  return -1; +	} +      mapblock1 = 1; +      return ((__u16 *) DATABLOCK1) [logical_block]; +    } + +  logical_block -= 512; +  i = INODE->i_zone[8]; +  if (!i || ((mapblock1 != 2) +	     && !minix_rdfsb (i, DATABLOCK1))) +    { +      errnum = ERR_FSYS_CORRUPT; +      return -1; +    } +  mapblock1 = 2; +  i = ((__u16 *) DATABLOCK1)[logical_block >> 9]; +  if (!i || ((mapblock2 != i) +	     && !minix_rdfsb (i, DATABLOCK2))) +    { +      errnum = ERR_FSYS_CORRUPT; +      return -1; +    } +  mapblock2 = i; +  return ((__u16 *) DATABLOCK2)[logical_block & 511]; +} + +/* read from INODE into BUF */ +int +minix_read (char *buf, int len) +{ +  int logical_block; +  int offset; +  int map; +  int ret = 0; +  int size = 0; + +  while (len > 0) +    { +      /* find the (logical) block component of our location */ +      logical_block = filepos >> BLOCK_SIZE_BITS; +      offset = filepos & (BLOCK_SIZE - 1); +      map = minix_block_map (logical_block); +#ifdef DEBUG_MINIX +      printf ("map=%d\n", map); +#endif +      if (map < 0) +	break; + +      size = BLOCK_SIZE; +      size -= offset; +      if (size > len) +	size = len; + +      disk_read_func = disk_read_hook; + +      devread (map * (BLOCK_SIZE / DEV_BSIZE), +	       offset, size, buf); + +      disk_read_func = NULL; + +      buf += size; +      len -= size; +      filepos += size; +      ret += size; +    } + +  if (errnum) +    ret = 0; + +  return ret; +} + +/* preconditions: minix_mount already executed, therefore supblk in buffer +     known as SUPERBLOCK +   returns: 0 if error, nonzero iff we were able to find the file successfully +   postconditions: on a nonzero return, buffer known as INODE contains the +     inode of the file we were trying to look up +   side effects: none yet  */ +int +minix_dir (char *dirname) +{ +  int current_ino = MINIX_ROOT_INO;  /* start at the root */ +  int updir_ino = current_ino;	     /* the parent of the current directory */ +  int ino_blk;			     /* fs pointer of the inode's info */ + +  int str_chk = 0;		     /* used ot hold the results of a string +				        compare */ + +  struct minix_inode * raw_inode;    /* inode info for current_ino */ + +  char linkbuf[PATH_MAX];	     /* buffer for following sym-links */ +  int link_count = 0; + +  char * rest; +  char ch; + +  int off;			     /* offset within block of directory +					entry */ +  int loc;			     /* location within a directory */ +  int blk;			     /* which data blk within dir entry */ +  long map;			     /* fs pointer of a particular block from +					dir entry */ +  struct minix_dir_entry * dp;	     /* pointer to directory entry */ + +  /* loop invariants: +     current_ino = inode to lookup +     dirname = pointer to filename component we are cur looking up within +     the directory known pointed to by current_ino (if any) */ + +#ifdef DEBUG_MINIX +  printf ("\n"); +#endif + +  while (1) +    { +#ifdef DEBUG_MINIX +      printf ("inode %d, dirname %s\n", current_ino, dirname); +#endif + +      ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks +		 + (current_ino - 1) / MINIX_INODES_PER_BLOCK); +      if (! minix_rdfsb (ino_blk, (char *) INODE)) +	return 0; + +      /* reset indirect blocks! */ +      mapblock2 = mapblock1 = -1; + +      raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK); + +      /* copy inode to fixed location */ +      memmove ((void *) INODE, (void *) raw_inode, +	       sizeof (struct minix_inode)); + +      /* If we've got a symbolic link, then chase it. */ +      if (S_ISLNK (INODE->i_mode)) +	{ +	  int len; + +	  if (++link_count > MAX_LINK_COUNT) +	    { +	      errnum = ERR_SYMLINK_LOOP; +	      return 0; +	    } +#ifdef DEBUG_MINIX +	  printf ("S_ISLNK (%s)\n", dirname); +#endif + +	  /* Find out how long our remaining name is. */ +	  len = 0; +	  while (dirname[len] && !isspace (dirname[len])) +	    len++; + +	  /* Get the symlink size. */ +	  filemax = (INODE->i_size); +	  if (filemax + len > sizeof (linkbuf) - 2) +	    { +	      errnum = ERR_FILELENGTH; +	      return 0; +	    } + +	  if (len) +	    { +	      /* Copy the remaining name to the end of the symlink data. +	         Note that DIRNAME and LINKBUF may overlap! */ +	      memmove (linkbuf + filemax, dirname, len); +	    } +	  linkbuf[filemax + len] = '\0'; + +	  /* Read the necessary blocks, and reset the file pointer. */ +	  len = grub_read (linkbuf, filemax); +	  filepos = 0; +	  if (!len) +	    return 0; + +#ifdef DEBUG_MINIX +	  printf ("symlink=%s\n", linkbuf); +#endif + +	  dirname = linkbuf; +	  if (*dirname == '/') +	    { +	      /* It's an absolute link, so look it up in root. */ +	      current_ino = MINIX_ROOT_INO; +	      updir_ino = current_ino; +	    } +	  else +	    { +	      /* Relative, so look it up in our parent directory. */ +	      current_ino = updir_ino; +	    } + +	  /* Try again using the new name. */ +	  continue; +	} + +      /* If end of filename, INODE points to the file's inode */ +      if (!*dirname || isspace (*dirname)) +	{ +	  if (!S_ISREG (INODE->i_mode)) +	    { +	      errnum = ERR_BAD_FILETYPE; +	      return 0; +	    } + +	  filemax = (INODE->i_size); +	  return 1; +	} + +      /* else we have to traverse a directory */ +      updir_ino = current_ino; + +      /* skip over slashes */ +      while (*dirname == '/') +	dirname++; + +      /* if this isn't a directory of sufficient size to hold our file, +	 abort */ +      if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode)) +	{ +	  errnum = ERR_BAD_FILETYPE; +	  return 0; +	} + +      /* skip to next slash or end of filename (space) */ +      for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; +	   rest++); + +      /* look through this directory and find the next filename component */ +      /* invariant: rest points to slash after the next filename component */ +      *rest = 0; +      loc = 0; + +      do +	{ +#ifdef DEBUG_MINIX +	  printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc); +#endif + +	  /* if our location/byte offset into the directory exceeds the size, +	     give up */ +	  if (loc >= INODE->i_size) +	    { +	      if (print_possibilities < 0) +		{ +#if 0 +		  putchar ('\n'); +#endif +		} +	      else +		{ +		  errnum = ERR_FILE_NOT_FOUND; +		  *rest = ch; +		} +	      return (print_possibilities < 0); +	    } + +	  /* else, find the (logical) block component of our location */ +	  blk = loc >> BLOCK_SIZE_BITS; + +	  /* we know which logical block of the directory entry we are looking +	     for, now we have to translate that to the physical (fs) block on +	     the disk */ +	  map = minix_block_map (blk); +#ifdef DEBUG_MINIX +	  printf ("fs block=%d\n", map); +#endif +	  mapblock2 = -1; +	  if ((map < 0) || !minix_rdfsb (map, DATABLOCK2)) +	    { +	      errnum = ERR_FSYS_CORRUPT; +	      *rest = ch; +	      return 0; +	    } +	  off = loc & (BLOCK_SIZE - 1); +	  dp = (struct minix_dir_entry *) (DATABLOCK2 + off); +	  /* advance loc prematurely to next on-disk directory entry  */ +	  loc += sizeof (dp->inode) + namelen; + +	  /* NOTE: minix filenames are NULL terminated if < NAMELEN +	     else exact */ + +#ifdef DEBUG_MINIX +	  printf ("directory entry ino=%d\n", dp->inode); +	  if (dp->inode) +	    printf ("entry=%s\n", dp->name); +#endif + +	  if (dp->inode) +	    { +	      int saved_c = dp->name[namelen]; + +	      dp->name[namelen] = 0; +	      str_chk = substring (dirname, dp->name); + +# ifndef STAGE1_5 +	      if (print_possibilities && ch != '/' +		  && (!*dirname || str_chk <= 0)) +		{ +		  if (print_possibilities > 0) +		    print_possibilities = -print_possibilities; +		  print_a_completion (dp->name); +		} +# endif + +	      dp->name[namelen] = saved_c; +	    } + +	} +      while (!dp->inode || (str_chk || (print_possibilities && ch != '/'))); + +      current_ino = dp->inode; +      *(dirname = rest) = ch; +    } +  /* never get here */ +} + +#endif /* FSYS_MINIX */ diff --git a/roms/openbios/fs/grubfs/fsys_ntfs.c b/roms/openbios/fs/grubfs/fsys_ntfs.c new file mode 100644 index 00000000..a244f5c6 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_ntfs.c @@ -0,0 +1,1255 @@ +/* vim: set sw=4 :*/ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 1999  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +/* + * Samuel Leo <samuel@_.remove.me._szonline.net> + * Limitations: + * 1. Only 32 bit size support + * 2. don't support >1k MFT record size, >16k INDEX record size + * 3. don't support recursive at_attribute_list + * 4. don't support compressed attribute other than Datastream + * 5. all MFT's at_attribute_list must resident at first run list + * 6. don't support journaling + * 7. don't support EFS encryption + * 8. don't support mount point and junction + */ +#ifdef FSYS_NTFS + +//#define DEBUG_NTFS 1 + +/* +#define NO_ATTRIBUTE_LIST 1 +   totally disable at_attribute_list support, +   if no compressed/fragment file and MFT, +   not recommended +#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1 +   disable non-resident at_attribute_list support, +   if no huge compressed/fragment file and MFT +#define NO_NTFS_DECOMPRESSION 1 +   disable ntfs compressed file support +#define NO_ALTERNATE_DATASTREAM 1 +   disable ntfs alternate datastream support +*/ + +#include "shared.h" +#include "filesys.h" + +#ifdef STAGE1_5 +/* safe turn off non-resident attribute list if MFT fragments < 4000 */ +//#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1 +#define NO_NTFS_DECOMPRESSION 1 +#endif + +#define MAX_MFT_RECORD_SIZE 1024 +#define MAX_INDEX_RECORD_SIZE 16384 +#define MAX_INDEX_BITMAP_SIZE 4096 +#define DECOMP_DEST_BUFFER_SIZE 16384 +#define DECOMP_SOURCE_BUFFER_SIZE (8192+2) +#define MAX_DIR_DEPTH 64 + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE 	512 + +#define WHICH_SUPER 1 +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */ + +/* include/asm-i386/type.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + +#define FILE_MFT      0 +#define FILE_MFTMIRR  1 +#define FILE_LOGFILE  2 +#define FILE_VOLUME   3 +#define FILE_ATTRDEF  4 +#define FILE_ROOT     5 +#define FILE_BITMAP   6 +#define FILE_BOOT     7 +#define FILE_BADCLUS  8 +#define FILE_QUOTA    9 +#define FILE_UPCASE  10 + +#define at_standard_information 0x10 +#define at_attribute_list 	0x20 +#define at_filename		0x30 +#define at_security_descriptor	0x50 +#define at_data			0x80 +#define at_index_root		0x90 +#define at_index_allocation	0xa0 +#define at_bitmap		0xb0 +#define at_symlink		0xc0 + +#define NONAME	"" +#define ATTR_NORMAL	0 +#define ATTR_COMPRESSED	1 +#define ATTR_RESIDENT	2 +#define ATTR_ENCRYPTED	16384 +#define ATTR_SPARSE	32768 + +typedef struct run_list { +	char *start; +	char *ptr; +	int svcn; +	int evcn; +	int vcn; +	int cnum0; +	int cnum; +	int clen; +} RUNL; + +typedef struct ntfs_mft_record { +	char mft[MAX_MFT_RECORD_SIZE]; +	char mft2[MAX_MFT_RECORD_SIZE]; +	int attr_type; +	char *attr_name; +	int attr_flag; +	int attr_size; +	char *attr; +	int attr_len; +	RUNL runl; +	char *attr_list; +	int attr_list_len; +	int attr_list_size; +	int attr_list_off; +	int attr_inited; +	char attr_list_buf[2*BLOCK_SIZE]; +	RUNL attr_list_runl; +} MFTR; + + +#define index_data	((char *)FSYS_BUF) +#define bitmap_data	((__u8 *)(FSYS_BUF+MAX_INDEX_RECORD_SIZE)) +#define dcdbuf	((__u8 *)index_data) +#define dcsbuf	(bitmap_data) +#define dcend	(dcsbuf+DECOMP_SOURCE_BUFFER_SIZE) +#define fnbuf ((char *)(bitmap_data+MAX_INDEX_BITMAP_SIZE)) +#define mmft	((MFTR *)dcend) +#define cmft	((MFTR *)(dcend+sizeof(MFTR))) +#define mft_run	((RUNL *)(dcend+2*sizeof(MFTR))) +#define path_ino ((int *)(dcend+2*sizeof(MFTR)+sizeof(RUNL))) +#define cluster16 (path_ino+MAX_DIR_DEPTH) +#define index16 cluster16[16] +#define blocksize cluster16[17] +#define clustersize cluster16[18] +#define mft_record_size cluster16[19] +#define index_record_size cluster16[20] +#define dcvcn cluster16[21] +#define dcoff cluster16[22] +#define dclen cluster16[23] +#define dcrem cluster16[24] +#define dcslen cluster16[25] +#define dcsptr ((__u8 *)cluster16[26]) +#define is_ads_completion cluster16[27] + +static int read_mft_record(int mftno, char *mft, int self); +static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl); +static int get_next_run(RUNL *runl); + +static inline int +nsubstring (char *s1, char *s2) +{ +    while (tolower(*s1) == tolower(*s2)) +    { +	/* The strings match exactly. */ +	if (! *(s1++)) +	    return 0; +	s2 ++; +    } + +    /* S1 is a substring of S2. */ +    if (*s1 == 0) +	return -1; + +    /* S1 isn't a substring. */ +    return 1; +} + +static int fixup_record(char *record, char *magic, int size) +{ +    int start, count, offset; +    __u16 fixup; + +    if(*(int *)record != *(int *)magic) +	return 0; +    start=*(__u16 *)(record+4); +    count=*(__u16 *)(record+6); +    count--; +    if(size && blocksize*count != size) +	return 0; +    fixup = *(__u16 *)(record+start); +    start+=2; +    offset=blocksize-2; +    while(count--){ +	if(*(__u16 *)(record+offset)!=fixup) +	    return 0; +	*(__u16 *)(record+offset) = *(__u16 *)(record+start); +	start+=2; +	offset+=blocksize; +    } +    return 1; +} + +static void rewind_run_list( RUNL *runl) { +    runl->vcn = runl->svcn; +    runl->ptr = runl->start; +    runl->cnum0 = 0; +    runl->cnum = 0; +    runl->clen = 0; +} + +static int get_next_run(RUNL *runl){ +    int t, n, v; + +#ifdef DEBUG_NTFS +    printf("get_next_run: s=%d e=%d c=%d start=%x ptr=%x\n", +	   runl->svcn, runl->evcn, runl->vcn, runl->start, runl->ptr); +#endif + +    runl->vcn += runl->clen; +    if(runl->vcn > runl->evcn) { +    	return 0; +    } + +    t = *(runl->ptr)++; +    n = t&0xf; +    runl->clen = 0; v = 1; +    while(n--) { +	runl->clen += v * *((__u8 *)runl->ptr)++; +	v <<= 8; +    } +    n = (t>>4)&0xf; +    if(n==0) +	runl->cnum = 0; +    else { +	int c = 0; +	v = 1; +	while(n--) { +	    c += v * *((__u8 *)runl->ptr)++; +	    v <<= 8; +	} +	if(c & (v>>1)) c -= v; +	runl->cnum0 += c; +	runl->cnum = runl->cnum0; +    } +#ifdef DEBUG_NTFS +    printf("got_next_run: t=%x cluster %x len %x vcn=%x ecn=%x\n", +    	t, runl->cnum, runl->clen, runl->vcn, runl->evcn); +#endif +    return 1; +} + +#ifndef NO_ATTRIBUTE_LIST +static void init_run_list(char *attr, int len, RUNL *runl, __u32 *initp) { +    int allocated; + +    runl->svcn = *(__u32 *)(attr+0x10); /* only support 32 bit */ +    runl->evcn = *(__u32 *)(attr+0x18); /* only support 32 bit */ +    runl->start = attr + *(__u16 *)(attr+0x20); +    allocated = *(__u32 *)(attr+0x28); +    if(initp) *initp = *(__u32 *)(attr+0x38); +    if(!runl->evcn) runl->evcn = (allocated - 1) / clustersize; +#ifdef DEBUG_NTFS +    printf("size %d allocated=%d inited=%d cegin=%x csize=%d vcn=%d-%d\n", +	    /*attr_size*/ *(__u32 *)(attr+0x30), +	    /*allocated*/ *(__u32 *)(attr+0x28), +	    /*attr_inited*/ *(__u32 *)(attr+0x38), +	    /*cengin*/ *(__u16 *)(attr+0x22), +	    /*csize*/ *(__u16 *)(attr+0x40), +	    runl->svcn, runl->evcn); +#endif +    rewind_run_list(runl); +} +#endif + + +static int find_attribute(char *mft, int type, char *name, char **attr, int *size, int *len, int *flag) { +    int t, l, r, n, i, namelen; +    unsigned short *attr_name; + +    n = strlen(name); +    r = mft_record_size - *(__u16 *)(mft+0x14); +    mft += *(__u16 *)(mft+0x14); +    while( (t = *(__s32 *)mft) != -1 ) { +	l = *(__u32 *)(mft+4); +	if(l>r) break; +#ifdef DEBUG_NTFS +	printf("type = %x len = %d namelen=%d resident=%d compresed=%d attrno=%d\n", +		t, l, +		/*namelen*/ *(mft+9), +		//name = (__u16 *)(mft + *(__u16 *)(mft+10)), +		/*resident */ (*(mft+8) == 0), +		/*compressed*/ *(__u16 *)(mft+12), +		/*attrno*/ *(__u16 *)(mft+14)); +#endif +	namelen = *(mft+9); +	if(t == type) { +#ifndef STAGE1_5 +#ifndef NO_ALTERNATE_DATASTREAM +	    if(is_ads_completion && type == at_data) { +		if(namelen && namelen >= n && +		   (!*(mft+8)/*resident*/ || !*(__u32 *)(attr+0x10)/*svcn==0*/)) +		{ +		    for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i < n; i++) +			if(tolower(name[i]) != tolower(attr_name[i])) +			    break; +		    if(i >= n) { +			for(; i < namelen; i++) +			    name[i] = attr_name[i]; +			name[i] = '\0'; +			if(print_possibilities > 0) +			    print_possibilities = -print_possibilities; +			print_a_completion(fnbuf); +			name[n] = '\0'; +		    } +		} +	    } else +#endif +#endif +		if(namelen == n) { + +		for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i<n; i++) +		    if(tolower(name[i]) != tolower(attr_name[i])) +			break; +		if(i>=n) { +		    if(flag) *flag = *(__u16 *)(mft+12); +		    if(*(mft+8) == 0) { +			if(flag) *flag |= ATTR_RESIDENT; +#ifdef DEBUG_NTFS +			printf("resident data at %x size %x indexed=%d\n", +			       /*data*/ *(__u16 *)(mft+0x14), +			       /*attr_size*/ *(__u16 *)(mft+0x10), +			       /*indexed*/ *(__u16 *)(mft+0x16)); +#endif +			if(attr) *attr = mft + *(__u16 *)(mft+0x14); +			if(size) *size = *(__u16 *)(mft+0x10); +			if(len) *len = *(__u16 *)(mft+0x10); +		    } else { +			if(attr) *attr = mft; +			if(size) *size = *(__u32 *)(mft+0x30); +			if(len) *len = l; +		    } +		    return 1; +		} +	    } +	} +	mft += l; +	r -= l; +    } +    return 0; +} + +#ifndef NO_ATTRIBUTE_LIST +static __u32 get_next_attribute_list(MFTR *mftr, int *size) { +    int l, t, mftno; +#ifdef DEBUG_NTFS +    printf("get_next_attribute_list: type=%x\n",mftr->attr_type); +#endif +again: +    while(mftr->attr_list_len>0x14) { +	t = *(__u32 *)(mftr->attr_list + 0); +	l = *(__u16 *)(mftr->attr_list + 4); +#ifdef DEBUG_NTFS +	printf("attr_list type=%x len=%x remain=%x\n", t, l, mftr->attr_list_len); +#endif +	if(l==0 || l>mftr->attr_list_len) return 0; +	mftno = *(__u32 *)(mftr->attr_list + 0x10); +	mftr->attr_list_len -= l; +	mftr->attr_list += l; +	if(t==mftr->attr_type) +	{ +#ifdef DEBUG_NTFS +	printf("attr_list mftno=%x\n", mftno); +#endif +	    if(read_mft_record(mftno, mftr->mft2, (mftr==mmft))==0) +		break; +	    if(find_attribute(mftr->mft2, mftr->attr_type, mftr->attr_name, +			&mftr->attr, size, &mftr->attr_len, &mftr->attr_flag)) +		return 1; +	} +    } +#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST +    if(mftr->attr_list_off < mftr->attr_list_size) { +	int len = mftr->attr_list_size - mftr->attr_list_off; +	if(len > BLOCK_SIZE) len = BLOCK_SIZE; + +	if(mftr->attr_list_len) +	    memmove(mftr->attr_list_buf, mftr->attr_list, mftr->attr_list_len); +	mftr->attr_list = mftr->attr_list_buf; + +	if(read_attribute( NULL, mftr->attr_list_off, +			mftr->attr_list_buf + mftr->attr_list_len, +			len, &mftr->attr_list_runl) != len) +	{ +#ifdef DEBUG_NTFS +	    printf("CORRUPT NON-RESIDENT ATTRIBUTE_LIST\n"); +#endif +	    /* corrupt */ +	    errnum = ERR_FSYS_CORRUPT; +	    mftr->attr_list_size = 0; +	    mftr->attr_len = 0; +	    mftr->attr_list = NULL; +	    return 0; +	} + +	mftr->attr_list_len += len; +	mftr->attr_list_off += len; +	goto again; +    } +#endif +    mftr->attr_list = NULL; +    return 0; +} +#endif + +static int search_attribute( MFTR *mftr, int type, char *name) +{ +#ifdef DEBUG_NTFS +    printf("searching attribute %x <%s>\n", type, name); +#endif + +    mftr->attr_type = type; +    mftr->attr_name = name; +    mftr->attr_list = NULL; +    mftr->attr_list_len = 0; +    mftr->attr_list_size = 0; +    mftr->attr_list_off = 0; +    dcrem = dclen = 0; + +#ifndef NO_ATTRIBUTE_LIST +    if(find_attribute(mftr->mft, at_attribute_list, NONAME, +		      &mftr->attr_list, &mftr->attr_list_size, +		      &mftr->attr_list_len, &mftr->attr_list_off)) { +	if(mftr->attr_list_off&ATTR_RESIDENT) { +	    /* resident at_attribute_list */ +	    mftr->attr_list_size = 0; +#ifdef DEBUG_NTFS +	    printf("resident attribute_list len=%x\n", mftr->attr_list_len); +#endif +	} else { +#ifdef DEBUG_NTFS +	    printf("non-resident attribute_list len=%x size=%x\n", +		   mftr->attr_list_len, mftr->attr_list_size); +#endif +#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST +	    init_run_list(mftr->attr_list, mftr->attr_list_len, &mftr->attr_list_runl, NULL); +	    if(get_next_run(&mftr->attr_list_runl)==0 || +	       mftr->attr_list_runl.cnum==0) +		mftr->attr_list_size = 0; +#endif +	    mftr->attr_list = NULL; +	    mftr->attr_list_len = 0; +	} +    } +#endif + +    if(find_attribute(mftr->mft, type, name, +		      &mftr->attr, &mftr->attr_size, &mftr->attr_len, +		      &mftr->attr_flag) +#ifndef NO_ATTRIBUTE_LIST +       || get_next_attribute_list(mftr, &mftr->attr_size) +#endif +       ) +    { +#ifndef NO_ATTRIBUTE_LIST +	if(!(mftr->attr_flag&ATTR_RESIDENT)){ +	    init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, &mftr->attr_inited); +	    if(mftr->attr_inited > mftr->attr_size) +	    	mftr->attr_inited = mftr->attr_size; +	    if(get_next_run(&mftr->runl)==0) { +		mftr->attr_flag |= ATTR_RESIDENT; +		mftr->attr_len = 0; +	    } +	} else +	    mftr->attr_inited = mftr->attr_size; +#endif + +	return 1; +    } + +    mftr->attr_type = 0; +    return 0; +} + +static int get_run( RUNL *rl, int vcn, int *clp, int *lenp) { +    if(rl->evcn < vcn) +	return 0; + +    if(rl->vcn > vcn) { +    	rewind_run_list(rl); +	get_next_run(rl); +    } + +    while(rl->vcn+rl->clen <= vcn) +    { +	if(get_next_run(rl)==0) +	    return 0; +    } + +    if(clp) *clp = rl->cnum == 0 ? 0 : rl->cnum + vcn - rl->vcn; +    if(lenp) *lenp = rl->clen - vcn + rl->vcn; +    return 1; +} + +static int search_run(MFTR *mftr, int vcn) { + +    if( mftr->attr==NULL && !search_attribute(mftr, mftr->attr_type, mftr->attr_name)) +	return 0; + +    if(mftr->runl.svcn > vcn) +	search_attribute(mftr, mftr->attr_type, mftr->attr_name); + +#ifdef NO_ATTRIBUTE_LIST +    if(mftr->runl.evcn < vcn) +	return 0; +#else +    while(mftr->runl.evcn < vcn) { +	if(get_next_attribute_list(mftr, NULL)==0) { +	    mftr->attr = NULL; +	    return 0; +	} +	init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, NULL); +	if(get_next_run(&mftr->runl)==0) { +	    mftr->attr = NULL; +	    return 0; +	} +    } +#endif + +    return 1; +} + +static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl) { +    int vcn; +    int cnum, clen; +    int done = 0; +    int n; +    RUNL *rl; + +    if(!from_rl && (mftr->attr_flag & ATTR_RESIDENT)) { +	/* resident attribute */ +	if(offset > mftr->attr_len) +	    return 0; +	if(offset+len > mftr->attr_len) +	    len = mftr->attr_len - offset; +	memmove( buf, mftr->attr + offset, len); +	return len; +    } + +    vcn = offset / clustersize; +    offset %= clustersize; + +    while(len>0) { +	if(from_rl) +	    rl = from_rl; +	else if(search_run(mftr, vcn) == 0) +	    break; +	else +	    rl = &mftr->runl; +	if(get_run(rl, vcn, &cnum, &clen) == 0) +	    break; +	if(cnum==0 && from_rl) +	    break; +	n = clen * clustersize - offset; +	if(n > len) n = len; +	if(cnum==0) { +	    memset( buf, 0, n); +	} else if(!devread(cnum*(clustersize>>9)+(offset>>9), offset&0x1ff, n, buf)) +	    break; + +	buf += n; +	vcn += (offset+n)/clustersize; +	done += n; +	offset = 0; +	len -= n; +    } +    return done; +} + +static int read_mft_record(int mftno, char *mft, int self){ +#ifdef DEBUG_NTFS +    printf("Reading MFT record: mftno=%d\n", mftno); +#endif +    if( read_attribute( mmft, mftno * mft_record_size, +	    mft, mft_record_size, self?mft_run:NULL) != mft_record_size) +	return 0; +    if(!fixup_record( mft, "FILE", mft_record_size)) +	return 0; +    return 1; +} + +#ifndef NO_NTFS_DECOMPRESSION +static int get_16_cluster(MFTR *mftr, int vcn) { +    int n = 0, cnum, clen; +    while(n < 16 && search_run(mftr, vcn) && get_run(&mftr->runl, vcn, &cnum, &clen) && cnum) { +	if(clen > 16 - n) +	    clen = 16 - n; +	vcn += clen; +	while(clen--) +	    cluster16[n++] = cnum++; +    } +    cluster16[n] = 0; +    return n; +} + +static inline int compressed_block_size( unsigned char *src ) { +    return 3 + (*(__u16 *)src & 0xfff); +} + +static int decompress_block(unsigned char *dest, unsigned char *src) { +    int head; +    int copied=0; +    unsigned char *last; +    int bits; +    int tag=0; + +    /* high bit indicates that compression was performed */ +    if(!(*(__u16 *)src & 0x8000)) { +	memmove(dest,src+2,0x1000); +	return 0x1000; +    } + +    if((head = *(__u16 *)src & 0xFFF)==0) +	/* block is not used */ +	return 0; + +    src += 2; +    last = src+head; +    bits = 0; + +    while(src<=last) +    { +	if(copied>4096) +	{ +#ifdef DEBUG_NTFS +	    printf("decompress error 1\n"); +#endif +	    errnum = ERR_FSYS_CORRUPT; +	    return 0; +	} +	if(!bits){ +	    tag=*(__u8 *)src; +	    bits=8; +	    src++; +	    if(src>last) +		break; +	} +	if(tag & 1){ +	    int i,len,delta,code,lmask,dshift; +	    code = *(__u16 *)src; +	    src+=2; +	    if(!copied) +	    { +#ifdef DEBUG_NTFS +		printf("decompress error 2\n"); +#endif +		errnum = ERR_FSYS_CORRUPT; +		return 0; +	    } +	    for(i=copied-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1) +	    { +		lmask >>= 1; +		dshift--; +	    } +	    delta = code >> dshift; +	    len = (code & lmask) + 3; +	    for(i=0; i<len; i++) +	    { +		dest[copied]=dest[copied-delta-1]; +		copied++; +	    } +	} else +	    dest[copied++]=*(__u8 *)src++; +	tag>>=1; +	bits--; +    } + +    return copied; +} +#endif + +int ntfs_read(char *buf, int len){ +    int ret; +#ifdef STAGE1_5 +/* stage2 can't be resident/compressed/encrypted files, + * but does sparse flag, cause stage2 never sparsed + */ +    if((cmft->attr_flag&~ATTR_SPARSE) != ATTR_NORMAL) +	return 0; +    disk_read_func = disk_read_hook; +    ret = read_attribute(cmft, filepos, buf, len, 0); +    disk_read_func = NULL; +    filepos += ret; +#else + +#ifndef NO_NTFS_DECOMPRESSION +    int off; +    int vcn; +    int size; +    int len0; +#endif + +    if(len<=0 || filepos >= cmft->attr_size || (cmft->attr_flag&ATTR_ENCRYPTED)) +	return 0; + +    if(filepos+len > cmft->attr_size) +	len = cmft->attr_size - filepos; +    if(filepos >= cmft->attr_inited) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 1\n"); +#endif +    	memset(buf, 0, len); +	return len; +    } else if(filepos+len > cmft->attr_inited) { +    	len0 = len; +	len = cmft->attr_inited - filepos; +	len0 -= len; +    } else +    	len0 = 0; +#ifdef DEBUG_NTFS +printf("read filepos=%x filemax=%x inited=%x len=%x len0=%x\n",filepos,filemax,cmft->attr_inited,len,len0); +#endif + +    if((cmft->attr_flag&(ATTR_COMPRESSED|ATTR_RESIDENT)) != ATTR_COMPRESSED) { +	if(cmft->attr_flag==ATTR_NORMAL) +	    disk_read_func = disk_read_hook; +	ret = read_attribute(cmft, filepos, buf, len, 0); +	if(cmft->attr_flag==ATTR_NORMAL) +	    disk_read_func = NULL; +	filepos += ret; +	if(ret==len && len0) { +		memset(buf+len, 0, len0); +		filepos += len0; +		ret += len0; +	} +	return ret; +    } + +    ret = 0; + +#ifndef NO_NTFS_DECOMPRESSION +    /* NTFS don't support compression if cluster size > 4k */ +    if(clustersize > 4096) { +	errnum = ERR_FSYS_CORRUPT; +	return 0; +    } + +    while(len > 0){ +#ifdef DEBUG_NTFS +printf("Reading filepos=%x len=%x\n", filepos, len); +#endif +	if(filepos >= dcoff && filepos < (dcoff+dclen)) { +#ifdef DEBUG_NTFS +printf("decompress cache %x+%x\n", dcoff, dclen); +#endif +	    size = dcoff + dclen - filepos; +	    if(size > len) size = len; +	    memmove( buf, dcdbuf + filepos - dcoff, size); +	    filepos += size; +	    len -= size; +	    ret += size; +	    buf += size; +	    if(len==0) { +		if(len0) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 2\n"); +#endif +		    memset(buf, 0, len0); +		    filepos += len0; +		    ret += len0; +		} +		return ret; +	    } +	} + +	vcn = filepos / clustersize / 16; +	vcn *= 16; +	off = filepos % (16 * clustersize); +	if( dcvcn != vcn || filepos < dcoff) +	    dcrem = 0; + +#ifdef DEBUG_NTFS +printf("vcn %x off %x dcrem %x\n", vcn, off, dcrem); +#endif +	if(dcrem) { +	    int head; + +	    /* reading source */ +	    if(dcslen < 2 || compressed_block_size(dcsptr) > dcslen) { +		if(cluster16[index16]==0) { +		    errnum = ERR_FSYS_CORRUPT; +		    return ret; +		} +		if(dcslen) +		    memmove(dcsbuf, dcsptr, dcslen); +		dcsptr = dcsbuf; +		while((dcslen+clustersize) < DECOMP_SOURCE_BUFFER_SIZE) { +		    if(cluster16[index16]==0) +			break; +#ifdef DEBUG_NTFS +printf("reading dcslen=%x cluster %x\n", dcslen, cluster16[index16]); +#endif +		    if(!devread(cluster16[index16]*(clustersize>>9), 0, clustersize, dcsbuf+dcslen)) +			return ret; +		    dcslen += clustersize; +		    index16++; +		} +	    } +	    /* flush destination */ +	    dcoff += dclen; +	    dclen = 0; + +	    while(dcrem && dclen < DECOMP_DEST_BUFFER_SIZE && +		  dcslen >= 2 && (head=compressed_block_size(dcsptr)) <= dcslen) { +		size = decompress_block(dcdbuf+dclen, dcsptr); +		if(dcrem>=0x1000 && size!=0x1000) { +		    errnum = ERR_FSYS_CORRUPT; +		    return ret; +		} +		dcrem -= size; +		dclen += size; +		dcsptr += head; +		dcslen -= head; +	    } +	    continue; +	} +	dclen = dcrem = 0; +#ifdef DEBUG_NTFS +printf("get next 16 clusters\n"); +#endif +	switch(get_16_cluster(cmft, vcn)) { +	case 0: +#ifdef DEBUG_NTFS +printf("sparse\n"); +#endif +	    /* sparse */ +	    size = 16 * clustersize - off; +	    if( len < size ) +		size = len; +#ifndef STAGE1_5 +	    memset( buf, 0, size); +#endif +	    filepos += size; +	    len -= size; +	    ret += size; +	    buf += size; +	    break; + +	case 16: +#ifdef DEBUG_NTFS +printf("uncompressed\n"); +#endif +	    /* uncompressed */ +	    index16 = off / clustersize; +	    off %= clustersize; +	    while(index16 < 16) { +		size = clustersize - off; +		if( len < size ) +		    size = len; +		if(!devread(cluster16[index16]*(clustersize>>9)+(off>>9), off&0x1ff, size, buf)) +		    return ret; +		filepos += size; +		len -= size; +		ret += size; +		if(len==0) +		    return ret; +		off = 0; +		buf += size; +		index16++; +	    } +	    break; + +	default: +#ifdef DEBUG_NTFS +printf("compressed\n"); +#endif +	    index16 = 0; +	    dcvcn = vcn; +	    dcoff = vcn * clustersize; +	    dcrem = cmft->attr_inited - dcoff; +	    if(dcrem > 16 * clustersize) +		dcrem = 16 * clustersize; +	    dcsptr = dcsbuf; +	    dcslen = 0; +	} +    } +    if(len0) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 3\n"); +#endif +	memset(buf, 0, len0); +	filepos += len0; +	ret += len0; +    } +#else +    errnum = FSYS_CORRUPT; +#endif /*NO_NTFS_DECOMPRESSION*/ +#endif /*STAGE1_5*/ +    return ret; +} + +int ntfs_mount (void) +{ +    char *sb = (char *)FSYS_BUF; +    int mft_record; +    int spc; + +  if (((current_drive & 0x80) || (current_slice != 0)) +       && (current_slice != /*PC_SLICE_TYPE_NTFS*/7) +       && (current_slice != /*PC_SLICE_TYPE_NTFS*/0x17)) +      return 0; + +    if (!devread (0, 0, 512, (char *) FSYS_BUF)) +	return 0;			/* Cannot read superblock */ + +    if(sb[3]!='N' || sb[4]!='T' || sb[5]!='F' || sb[6]!='S') +	return 0; +    blocksize = *(__u16 *)(sb+0xb); +    spc = *(unsigned char *)(sb+0xd); +    clustersize = spc * blocksize; +    mft_record_size = *(char *)(sb+0x40); +    index_record_size = *(char *)(sb+0x44); +    if(mft_record_size>0) +	mft_record_size *= clustersize; +    else +	mft_record_size = 1 << (-mft_record_size); + +    index_record_size *= clustersize; +    mft_record = *(__u32 *)(sb+0x30); /* only support 32 bit */ +    spc = clustersize / 512; + +    if(mft_record_size > MAX_MFT_RECORD_SIZE || index_record_size > MAX_INDEX_RECORD_SIZE) { +	/* only support 1k MFT record, 4k INDEX record */ +	return 0; +    } + +#ifdef DEBUG_NTFS +    printf("spc=%x mft_record=%x:%x\n", spc, *(__s64 *)(sb+0x30)); +#endif + +    if (!devread (mft_record*spc, 0, mft_record_size, mmft->mft)) +	return 0;			/* Cannot read superblock */ + +    if(!fixup_record( mmft->mft, "FILE", mft_record_size)) +	return 0; + +#ifndef NO_ALTERNATE_DATASTREAM +    is_ads_completion = 0; +#endif +    if(!search_attribute(mmft, at_data, NONAME)) return 0; + +    *mft_run = mmft->runl; + +    *path_ino = FILE_ROOT; + +    return 1; +} + +int +ntfs_dir (char *dirname) +{ +    char *rest, ch; +    int namelen; +    int depth = 0; +    int chk_sfn = 1; +    int flag = 0; +    int record_offset; +    int my_index_record_size; +    unsigned char *index_entry = 0, *entry, *index_end; +    int i; + +    /* main loop to find desired directory entry */ +loop: + +#ifdef DEBUG_NTFS +    printf("dirname=%s\n", dirname); +#endif +    if(!read_mft_record(path_ino[depth], cmft->mft, 0)) +    { +#ifdef DEBUG_NTFS +	printf("MFT error 1\n"); +#endif +	errnum = ERR_FSYS_CORRUPT; +	return 0; +    } + +    /* if we have a real file (and we're not just printing possibilities), +       then this is where we want to exit */ + +    if (!*dirname || isspace (*dirname) || *dirname==':') +    { +#ifndef STAGE1_5 +#ifndef NO_ALTERNATE_DATASTREAM +	if (*dirname==':' && print_possibilities) { +	    char *tmp; + +	    /* preparing ADS name completion */ +	    for(tmp = dirname; *tmp != '/'; tmp--); +	    for(tmp++, rest=fnbuf; *tmp && !isspace(*tmp); *rest++ = *tmp++) +		if(*tmp==':') dirname = rest; +	    *rest++ = '\0'; + +	    is_ads_completion = 1; +	    search_attribute(cmft, at_data, dirname+1); +	    is_ads_completion = 0; + +	    if(errnum==0) { +		if(print_possibilities < 0) +		    return 1; +		errnum = ERR_FILE_NOT_FOUND; +	    } +	    return 0; +	} +#endif +#endif + +	if (*dirname==':') dirname++; +	for (rest = dirname; (ch = *rest) && !isspace (ch); rest++); +	*rest = 0; + +#ifdef DEBUG_NTFS +	printf("got file: search at_data\n"); +#endif + +	if (!search_attribute(cmft, at_data, dirname)) { +	    errnum = *(dirname-1)==':'?ERR_FILE_NOT_FOUND:ERR_BAD_FILETYPE; +	    *rest = ch; +	    return 0; +	} +	*rest = ch; + +	filemax = cmft->attr_size; +#ifdef DEBUG_NTFS +	printf("filemax=%x\n", filemax); +#endif +	return 1; +    } + +    if(depth >= (MAX_DIR_DEPTH-1)) { +	errnum = ERR_FSYS_CORRUPT; +	return 0; +    } + +    /* continue with the file/directory name interpretation */ + +    while (*dirname == '/') +	dirname++; + +    for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/' && ch != ':'; rest++); + +    *rest = 0; + +    if (!search_attribute(cmft, at_index_root, "$I30")) +    { +	errnum = ERR_BAD_FILETYPE; +	return 0; +    } + +    read_attribute(cmft, 0, fnbuf, 16, 0); +    my_index_record_size = *(__u32 *)(fnbuf+8); + +    if(my_index_record_size > MAX_INDEX_RECORD_SIZE) { +	errnum = ERR_FSYS_CORRUPT; +	return 0; +    } + +#ifdef DEBUG_NTFS +    printf("index_record_size=%x\n", my_index_record_size); +#endif + +    if(cmft->attr_size > MAX_INDEX_RECORD_SIZE) { +	errnum = ERR_FSYS_CORRUPT; +	return 0; +    } +    read_attribute(cmft, 0, index_data, cmft->attr_size, 0); +    index_end = index_data + cmft->attr_size; +    index_entry = index_data + 0x20; +    record_offset = -1; + +#ifndef STAGE1_5 +    if (print_possibilities && ch != '/' && ch != ':' && !*dirname) +    { +	print_possibilities = -print_possibilities; +	/* fake '.' for empty directory */ +	print_a_completion ("."); +    } +#endif + +    if (search_attribute(cmft, at_bitmap, "$I30")) { +	if(cmft->attr_size > MAX_INDEX_BITMAP_SIZE) { +	    errnum = ERR_FSYS_CORRUPT; +	    return 0; +	} + +	read_attribute(cmft, 0, bitmap_data, cmft->attr_size, 0); + +	if (search_attribute(cmft, at_index_allocation, "$I30")==0) { +	    errnum = ERR_FSYS_CORRUPT; +	    return 0; +	} + +	for(record_offset = 0; record_offset*my_index_record_size<cmft->attr_size; record_offset++){ +	    int bit = 1 << (record_offset&3); +	    int byte = record_offset>>3; +#ifdef DEBUG_NTFS +	    printf("record_offset=%x\n", record_offset); +#endif +	    if((bitmap_data[byte]&bit)) +		break; +	} + +	if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1; +    } + +    do +    { +	entry = index_entry; index_entry += *(__u16 *)(entry+8); +	if(entry+0x50>=index_entry||entry>=index_end|| +	   index_entry>=index_end||(entry[0x12]&2)){ +	    if(record_offset < 0 || +	       !read_attribute(cmft, record_offset*my_index_record_size, index_data, my_index_record_size, 0)){ +		if (!errnum) +		{ +		    if (print_possibilities < 0) +		    { +#if 0 +			putchar ('\n'); +#endif +			return 1; +		    } + +		    errnum = ERR_FILE_NOT_FOUND; +		    *rest = ch; +		} + +		return 0; +	    } +	    if(!fixup_record( index_data, "INDX", my_index_record_size)) +	    { +#ifdef DEBUG_NTFS +		printf("index error\n"); +#endif +		errnum = ERR_FSYS_CORRUPT; +		return 0; +	    } +	    entry = index_data + 0x18 + *(__u16 *)(index_data+0x18); +	    index_entry = entry + *(__u16 *)(entry+8); +	    index_end = index_data + my_index_record_size - 0x52; +	    for(record_offset++; record_offset*my_index_record_size<cmft->attr_size; record_offset++){ +		int bit = 1 << (record_offset&3); +		int byte = record_offset>>3; +		if((bitmap_data[byte]&bit)) break; +	    } +	    if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1; +#ifdef DEBUG_NTFS +	    printf("record_offset=%x\n", record_offset); +#endif +	} +	flag = entry[0x51]; +	path_ino[depth+1] = *(__u32 *)entry; +	if(path_ino[depth+1] < 16) +	    continue; +	namelen = entry[0x50]; +	//if(index_data[0x48]&2) printf("hidden file\n"); +#ifndef STAGE1_5 +	/* skip short file name */ +	if( flag == 2 && print_possibilities && ch != '/' && ch != ':' ) +	    continue; +#endif + +	for( i = 0, entry+=0x52; i < namelen; i++, entry+=2 ) +	{ +	    int c = *(__u16 *)entry; +	    if(c==' '||c>=0x100) +		fnbuf[i] = '_'; +	    else +		fnbuf[i] = c; +	} +	fnbuf[namelen] = 0; +#ifdef DEBUG_NTFS +	printf("FLAG: %d  NAME: %s  inum=%d\n", flag,fnbuf,path_ino[depth+1]); +#endif + +	//uncntrl(fnbuf); + +	chk_sfn = nsubstring(dirname,fnbuf); +#ifndef STAGE1_5 +	if (print_possibilities && ch != '/' && ch != ':' +	    && (!*dirname || chk_sfn <= 0)) +	{ +	    if (print_possibilities > 0) +		print_possibilities = -print_possibilities; +	    print_a_completion (fnbuf); +	} +#endif /* STAGE1_5 */ +    } +    while (chk_sfn != 0 || +	   (print_possibilities && ch != '/' && ch != ':')); + +    *(dirname = rest) = ch; + +    depth++; + +    /* go back to main loop at top of function */ +    goto loop; +} + +#ifdef DEBUG_NTFS +int dump_block(char *msg, char *buf, int size){ +    int l = (size+15)/16; +    int off; +    int i, j; +    int c; +    printf("----- %s -----\n", msg); +    for( i = 0, off = 0; i < l; i++, off+=16) +    { +	if(off<16) +	    printf("000%x:", off); +	else if(off<256) +	    printf("00%x:", off); +	else +	    printf("0%x:", off); +	for(j=0;j<16;j++) +	{ +	    c = buf[off+j]&0xff; +	    if( c >= 16 ) +		printf("%c%x",j==8?'-':' ',c); +	    else +		printf("%c0%x",j==8?'-':' ',c); +	} +	printf("  "); +	for(j=0;j<16;j++) { +	    char c = buf[off+j]; +	    printf("%c",c<' '||c>='\x7f'?'.':c); +	} +	printf("\n"); +    } +} +#endif +#endif /* FSYS_NTFS */ diff --git a/roms/openbios/fs/grubfs/fsys_reiserfs.c b/roms/openbios/fs/grubfs/fsys_reiserfs.c new file mode 100644 index 00000000..b94a3352 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_reiserfs.c @@ -0,0 +1,1220 @@ +/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2000, 2001  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_REISERFS +#include "shared.h" +#include "filesys.h" + +#undef REISERDEBUG + +/* Some parts of this code (mainly the structures and defines) are + * from the original reiser fs code, as found in the linux kernel. + */ + +/* include/asm-i386/types.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; +typedef unsigned long long __u64; + +/* linux/posix_type.h */ +typedef long linux_off_t; + +#include "libc/byteorder.h" + +/* include/linux/reiser_fs.h */ +/* This is the new super block of a journaling reiserfs system */ +struct reiserfs_super_block +{ +  __u32 s_block_count;			/* blocks count         */ +  __u32 s_free_blocks;                  /* free blocks count    */ +  __u32 s_root_block;           	/* root block number    */ +  __u32 s_journal_block;           	/* journal block number    */ +  __u32 s_journal_dev;           	/* journal device number  */ +  __u32 s_journal_size; 		/* size of the journal on FS creation.  used to make sure they don't overflow it */ +  __u32 s_journal_trans_max;            /* max number of blocks in a transaction.  */ +  __u32 s_journal_magic;                /* random value made on fs creation */ +  __u32 s_journal_max_batch;            /* max number of blocks to batch into a trans */ +  __u32 s_journal_max_commit_age;       /* in seconds, how old can an async commit be */ +  __u32 s_journal_max_trans_age;        /* in seconds, how old can a transaction be */ +  __u16 s_blocksize;                   	/* block size           */ +  __u16 s_oid_maxsize;			/* max size of object id array  */ +  __u16 s_oid_cursize;			/* current size of object id array */ +  __u16 s_state;                       	/* valid or error       */ +  char s_magic[16];                     /* reiserfs magic string indicates that file system is reiserfs */ +  __u16 s_tree_height;                  /* height of disk tree */ +  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */ +  __u16 s_version; +  char s_unused[128];			/* zero filled by mkreiserfs */ +}; + +#define REISERFS_MAX_SUPPORTED_VERSION 2 +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" +#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" + +#define MAX_HEIGHT 7 + +/* must be correct to keep the desc and commit structs at 4k */ +#define JOURNAL_TRANS_HALF 1018 + +/* first block written in a commit.  */ +struct reiserfs_journal_desc { +  __u32 j_trans_id;			/* id of commit */ +  __u32 j_len;				/* length of commit. len +1 is the commit block */ +  __u32 j_mount_id;			/* mount id of this trans*/ +  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */ +  char j_magic[12]; +}; + +/* last block written in a commit */ +struct reiserfs_journal_commit { +  __u32 j_trans_id;			/* must match j_trans_id from the desc block */ +  __u32 j_len;			/* ditto */ +  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */ +  char j_digest[16];			/* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ +}; + +/* this header block gets written whenever a transaction is considered +   fully flushed, and is more recent than the last fully flushed +   transaction. +   fully flushed means all the log blocks and all the real blocks are +   on disk, and this transaction does not need to be replayed. +*/ +struct reiserfs_journal_header { +  /* id of last fully flushed transaction */ +  __u32 j_last_flush_trans_id; +  /* offset in the log of where to start replay after a crash */ +  __u32 j_first_unflushed_offset; +  /* mount id to detect very old transactions */ +  __u32 j_mount_id; +}; + +/* magic string to find desc blocks in the journal */ +#define JOURNAL_DESC_MAGIC "ReIsErLB" + + +/* + * directories use this key as well as old files + */ +struct offset_v1 +{ +  /* +   * for regular files this is the offset to the first byte of the +   * body, contained in the object-item, as measured from the start of +   * the entire body of the object. +   * +   * for directory entries, k_offset consists of hash derived from +   * hashing the name and using few bits (23 or more) of the resulting +   * hash, and generation number that allows distinguishing names with +   * hash collisions. If number of collisions overflows generation +   * number, we return EEXIST.  High order bit is 0 always +   */ +  __u32 k_offset; +  __u32 k_uniqueness; +}; + +struct offset_v2 +{ +  /* +   * for regular files this is the offset to the first byte of the +   * body, contained in the object-item, as measured from the start of +   * the entire body of the object. +   * +   * for directory entries, k_offset consists of hash derived from +   * hashing the name and using few bits (23 or more) of the resulting +   * hash, and generation number that allows distinguishing names with +   * hash collisions. If number of collisions overflows generation +   * number, we return EEXIST.  High order bit is 0 always +   */ +  __u64 k_offset:60; +  __u64 k_type: 4; +}; + + +struct key +{ +  /* packing locality: by default parent directory object id */ +  __u32 k_dir_id; +  /* object identifier */ +  __u32 k_objectid; +  /* the offset and node type (old and new form) */ +  union +  { +    struct offset_v1 v1; +    struct offset_v2 v2; +  } +  u; +}; + +#define KEY_SIZE (sizeof (struct key)) + +/* Header of a disk block.  More precisely, header of a formatted leaf +   or internal node, and not the header of an unformatted node. */ +struct block_head +{ +  __u16 blk_level;        /* Level of a block in the tree. */ +  __u16 blk_nr_item;      /* Number of keys/items in a block. */ +  __u16 blk_free_space;   /* Block free space in bytes. */ +  struct key  blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes +				      only) */ +}; +#define BLKH_SIZE (sizeof (struct block_head)) +#define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.                       */ + +struct item_head +{ +  struct key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/ + +  union +  { +    __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this +			    is an indirect item.  This equals 0xFFFF iff this is a direct item or +			    stat data item. Note that the key, not this field, is used to determine +			    the item type, and thus which field this union contains. */ +    __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory +			     entries in the directory item. */ +  } +  u; +  __u16 ih_item_len;           /* total size of the item body                  */ +  __u16 ih_item_location;      /* an offset to the item body within the block  */ +  __u16 ih_version;	       /* ITEM_VERSION_1 for all old items, +				  ITEM_VERSION_2 for new ones. +				  Highest bit is set by fsck +                                  temporary, cleaned after all done */ +}; +/* size of item header     */ +#define IH_SIZE (sizeof (struct item_head)) + +#define ITEM_VERSION_1 0 +#define ITEM_VERSION_2 1 +#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \ +			   ? (ih)->ih_key.u.v1.k_offset \ +			   : (ih)->ih_key.u.v2.k_offset) + +#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \ +				 ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \ +				 : (ih)->ih_key.u.v2.k_type == V2_##type) + +/* FIXME these types look wrong. */ +struct disk_child +{ +  unsigned long       dc_block_number;              /* Disk child's block number. */ +  unsigned short      dc_size;		            /* Disk child's used space.   */ +}; + +#define DC_SIZE (sizeof (struct disk_child)) + +/* Stat Data on disk. + * + * Note that reiserfs has two different forms of stat data.  Luckily + * the fields needed by grub are at the same position. + */ +struct stat_data +{ +  __u16 sd_mode;	/* file type, permissions */ +  __u16 sd_notused1[3]; /* fields not needed by reiserfs */ +  __u32 sd_size;	/* file size */ +  __u32 sd_size_hi;	/* file size high 32 bits (since version 2) */ +}; + +struct reiserfs_de_head +{ +  __u32 deh_offset;  /* third component of the directory entry key */ +  __u32 deh_dir_id;  /* objectid of the parent directory of the +			object, that is referenced by directory entry */ +  __u32 deh_objectid;/* objectid of the object, that is referenced by +                        directory entry */ +  __u16 deh_location;/* offset of name in the whole item */ +  __u16 deh_state;   /* whether 1) entry contains stat data (for +			future), and 2) whether entry is hidden +			(unlinked) */ +}; + +#define DEH_SIZE (sizeof (struct reiserfs_de_head)) + +#define DEH_Statdata (1 << 0)			/* not used now */ +#define DEH_Visible  (1 << 2) + +#define SD_OFFSET  0 +#define SD_UNIQUENESS 0 +#define DOT_OFFSET 1 +#define DOT_DOT_OFFSET 2 +#define DIRENTRY_UNIQUENESS 500 + +#define V1_TYPE_STAT_DATA 0x0 +#define V1_TYPE_DIRECT 0xffffffff +#define V1_TYPE_INDIRECT 0xfffffffe +#define V1_TYPE_DIRECTORY_MAX 0xfffffffd +#define V2_TYPE_STAT_DATA 0 +#define V2_TYPE_INDIRECT 1 +#define V2_TYPE_DIRECT 2 +#define V2_TYPE_DIRENTRY 3 + +#define REISERFS_ROOT_OBJECTID 2 +#define REISERFS_ROOT_PARENT_OBJECTID 1 +#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) +/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */ +#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) +#define REISERFS_OLD_BLOCKSIZE 4096 + +#define S_ISREG(mode) (((mode) & 0170000) == 0100000) +#define S_ISDIR(mode) (((mode) & 0170000) == 0040000) +#define S_ISLNK(mode) (((mode) & 0170000) == 0120000) + +#define PATH_MAX       1024	/* include/linux/limits.h */ +#define MAX_LINK_COUNT    5	/* number of symbolic links to follow */ + +/* The size of the node cache */ +#define FSYSREISER_CACHE_SIZE 24*1024 +#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE +#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3 + +/* Info about currently opened file */ +struct fsys_reiser_fileinfo +{ +  __u32 k_dir_id; +  __u32 k_objectid; +}; + +/* In memory info about the currently mounted filesystem */ +struct fsys_reiser_info +{ +  /* The last read item head */ +  struct item_head *current_ih; +  /* The last read item */ +  char *current_item; +  /* The information for the currently opened file */ +  struct fsys_reiser_fileinfo fileinfo; +  /* The start of the journal */ +  __u32 journal_block; +  /* The size of the journal */ +  __u32 journal_block_count; +  /* The first valid descriptor block in journal +     (relative to journal_block) */ +  __u32 journal_first_desc; + +  /* The ReiserFS version. */ +  __u16 version; +  /* The current depth of the reiser tree. */ +  __u16 tree_depth; +  /* SECTOR_SIZE << blocksize_shift == blocksize. */ +  __u8  blocksize_shift; +  /* 1 << full_blocksize_shift == blocksize. */ +  __u8  fullblocksize_shift; +  /* The reiserfs block size  (must be a power of 2) */ +  __u16 blocksize; +  /* The number of cached tree nodes */ +  __u16 cached_slots; +  /* The number of valid transactions in journal */ +  __u16 journal_transactions; + +  unsigned int blocks[MAX_HEIGHT]; +  unsigned int next_key_nr[MAX_HEIGHT]; +}; + +/* The cached s+tree blocks in FSYS_BUF,  see below + * for a more detailed description. + */ +#define ROOT     ((char *)FSYS_BUF) +#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift)) +#define LEAF     CACHE (DISK_LEAF_NODE_LEVEL) + +#define BLOCKHEAD(cache) ((struct block_head *) cache) +#define ITEMHEAD         ((struct item_head  *) ((char *) LEAF + BLKH_SIZE)) +#define KEY(cache)       ((struct key        *) ((char *) cache + BLKH_SIZE)) +#define DC(cache)        ((struct disk_child *) \ +			  ((char *) cache + BLKH_SIZE + KEY_SIZE * nr_item)) +/* The fsys_reiser_info block. + */ +#define INFO \ +    ((struct fsys_reiser_info *) ((char *) FSYS_BUF + FSYSREISER_CACHE_SIZE)) +/* + * The journal cache.  For each transaction it contains the number of + * blocks followed by the real block numbers of this transaction. + * + * If the block numbers of some transaction won't fit in this space, + * this list is stopped with a 0xffffffff marker and the remaining + * uncommitted transactions aren't cached. + */ +#define JOURNAL_START    ((__u32 *) (INFO + 1)) +#define JOURNAL_END      ((__u32 *) (FSYS_BUF + FSYS_BUFLEN)) + +static __inline__ int +is_power_of_two (unsigned long word) +{ +  return (word & -word) == word; +} + +static int +journal_read (int block, int len, char *buffer) +{ +  return devread ((INFO->journal_block + block) << INFO->blocksize_shift, +		  0, len, buffer); +} + +/* Read a block from ReiserFS file system, taking the journal into + * account.  If the block nr is in the journal, the block from the + * journal taken. + */ +static int +block_read (int blockNr, int start, int len, char *buffer) +{ +  int transactions = INFO->journal_transactions; +  int desc_block = INFO->journal_first_desc; +  int journal_mask = INFO->journal_block_count - 1; +  int translatedNr = blockNr; +  __u32 *journal_table = JOURNAL_START; +  while (transactions-- > 0) +    { +      int i = 0; +      int j_len; +      if (*journal_table != 0xffffffff) +	{ +	  /* Search for the blockNr in cached journal */ +	  j_len = *journal_table++; +	  while (i++ < j_len) +	    { +	      if (*journal_table++ == blockNr) +		{ +		  journal_table += j_len - i; +		  goto found; +		} +	    } +	} +      else +	{ +	  /* This is the end of cached journal marker.  The remaining +	   * transactions are still on disk. +	   */ +	  struct reiserfs_journal_desc   desc; +	  struct reiserfs_journal_commit commit; + +	  if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) +	    return 0; + +	  j_len = desc.j_len; +	  while (i < j_len && i < JOURNAL_TRANS_HALF) +	    if (desc.j_realblock[i++] == blockNr) +	      goto found; + +	  if (j_len >= JOURNAL_TRANS_HALF) +	    { +	      int commit_block = (desc_block + 1 + j_len) & journal_mask; +	      if (! journal_read (commit_block, +				  sizeof (commit), (char *) &commit)) +		return 0; +	      while (i < j_len) +		if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr) +		  goto found; +	    } +	} +      goto not_found; + +    found: +      translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); +#ifdef REISERDEBUG +      printf ("block_read: block %d is mapped to journal block %d.\n", +	      blockNr, translatedNr - INFO->journal_block); +#endif +      /* We must continue the search, as this block may be overwritten +       * in later transactions. +       */ +    not_found: +      desc_block = (desc_block + 2 + j_len) & journal_mask; +    } +  return devread (translatedNr << INFO->blocksize_shift, start, len, buffer); +} + +/* Init the journal data structure.  We try to cache as much as + * possible in the JOURNAL_START-JOURNAL_END space, but if it is full + * we can still read the rest from the disk on demand. + * + * The first number of valid transactions and the descriptor block of the + * first valid transaction are held in INFO.  The transactions are all + * adjacent, but we must take care of the journal wrap around. + */ +static int +journal_init (void) +{ +  unsigned int block_count = INFO->journal_block_count; +  unsigned int desc_block; +  unsigned int commit_block; +  unsigned int next_trans_id; +  struct reiserfs_journal_header header; +  struct reiserfs_journal_desc   desc; +  struct reiserfs_journal_commit commit; +  __u32 *journal_table = JOURNAL_START; + +  journal_read (block_count, sizeof (header), (char *) &header); +  desc_block = header.j_first_unflushed_offset; +  if (desc_block >= block_count) +    return 0; + +  INFO->journal_first_desc = desc_block; +  next_trans_id = header.j_last_flush_trans_id + 1; + +#ifdef REISERDEBUG +  printf ("journal_init: last flushed %d\n", +	  header.j_last_flush_trans_id); +#endif + +  while (1) +    { +      journal_read (desc_block, sizeof (desc), (char *) &desc); +      if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0 +	  || desc.j_trans_id != next_trans_id +	  || desc.j_mount_id != header.j_mount_id) +	/* no more valid transactions */ +	break; + +      commit_block = (desc_block + desc.j_len + 1) & (block_count - 1); +      journal_read (commit_block, sizeof (commit), (char *) &commit); +      if (desc.j_trans_id != commit.j_trans_id +	  || desc.j_len != commit.j_len) +	/* no more valid transactions */ +	break; + +#ifdef REISERDEBUG +      printf ("Found valid transaction %d/%d at %d.\n", +	      desc.j_trans_id, desc.j_mount_id, desc_block); +#endif + +      next_trans_id++; +      if (journal_table < JOURNAL_END) +	{ +	  if ((journal_table + 1 + desc.j_len) >= JOURNAL_END) +	    { +	      /* The table is almost full; mark the end of the cached +	       * journal.*/ +	      *journal_table = 0xffffffff; +	      journal_table = JOURNAL_END; +	    } +	  else +	    { +	      int i; +	      /* Cache the length and the realblock numbers in the table. +	       * The block number of descriptor can easily be computed. +	       * and need not to be stored here. +	       */ +	      *journal_table++ = desc.j_len; +	      for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++) +		{ +		  *journal_table++ = desc.j_realblock[i]; +#ifdef REISERDEBUG +		  printf ("block %d is in journal %d.\n", +			  desc.j_realblock[i], desc_block); +#endif +		} +	      for (     ; i < desc.j_len; i++) +		{ +		  *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; +#ifdef REISERDEBUG +		  printf ("block %d is in journal %d.\n", +			  commit.j_realblock[i-JOURNAL_TRANS_HALF], +			  desc_block); +#endif +		} +	    } +	} +      desc_block = (commit_block + 1) & (block_count - 1); +    } +#ifdef REISERDEBUG +  printf ("Transaction %d/%d at %d isn't valid.\n", +	  desc.j_trans_id, desc.j_mount_id, desc_block); +#endif + +  INFO->journal_transactions +    = next_trans_id - header.j_last_flush_trans_id - 1; +  return errnum == 0; +} + +/* check filesystem types and read superblock into memory buffer */ +int +reiserfs_mount (void) +{ +  struct reiserfs_super_block super; +  int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; + +  if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) +      || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), +		(char *) &super) +      || (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 +	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) +      || (/* check that this is not a copy inside the journal log */ +	  super.s_journal_block * super.s_blocksize +	  <= REISERFS_DISK_OFFSET_IN_BYTES)) +    { +      /* Try old super block position */ +      superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; +      if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) +	  || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), +			(char *) &super)) +	return 0; + +      if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 +	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) +	{ +	  /* pre journaling super block ? */ +	  if (substring (REISERFS_SUPER_MAGIC_STRING, +			 (char*) ((char *) &super + 20)) > 0) +	    return 0; + +	  super.s_blocksize = REISERFS_OLD_BLOCKSIZE; +	  super.s_journal_block = 0; +	  super.s_version = 0; +	} +    } + +  /* check the version number.  */ +  if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION) +    return 0; + +  INFO->version = super.s_version; +  INFO->blocksize = super.s_blocksize; +  INFO->fullblocksize_shift = log2 (super.s_blocksize); +  INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; +  INFO->cached_slots = +    (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; + +#ifdef REISERDEBUG +  printf ("reiserfs_mount: version=%d, blocksize=%d\n", +	  INFO->version, INFO->blocksize); +#endif /* REISERDEBUG */ + +  /* Clear node cache. */ +  memset (INFO->blocks, 0, sizeof (INFO->blocks)); + +  if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE +      || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE +      || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize) +    return 0; + +  /* Initialize journal code.  If something fails we end with zero +   * journal_transactions, so we don't access the journal at all. +   */ +  INFO->journal_transactions = 0; +  if (super.s_journal_block != 0 && super.s_journal_dev == 0) +    { +      INFO->journal_block = super.s_journal_block; +      INFO->journal_block_count = super.s_journal_size; +      if (is_power_of_two (INFO->journal_block_count)) +	journal_init (); + +      /* Read in super block again, maybe it is in the journal */ +      block_read (superblock >> INFO->blocksize_shift, +		  0, sizeof (struct reiserfs_super_block), (char *) &super); +    } + +  if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT)) +    return 0; + +  INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level; + +#ifdef REISERDEBUG +  printf ("root read_in: block=%d, depth=%d\n", +	  super.s_root_block, INFO->tree_depth); +#endif /* REISERDEBUG */ + +  if (INFO->tree_depth >= MAX_HEIGHT) +    return 0; +  if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) +    { +      /* There is only one node in the whole filesystem, +       * which is simultanously leaf and root */ +      memcpy (LEAF, ROOT, INFO->blocksize); +    } +  return 1; +} + +/***************** TREE ACCESSING METHODS *****************************/ + +/* I assume you are familiar with the ReiserFS tree, if not go to + * http://www.namesys.com/content_table.html + * + * My tree node cache is organized as following + *   0   ROOT node + *   1   LEAF node  (if the ROOT is also a LEAF it is copied here + *   2-n other nodes on current path from bottom to top. + *       if there is not enough space in the cache, the top most are + *       omitted. + * + * I have only two methods to find a key in the tree: + *   search_stat(dir_id, objectid) searches for the stat entry (always + *       the first entry) of an object. + *   next_key() gets the next key in tree order. + * + * This means, that I can only sequential reads of files are + * efficient, but this really doesn't hurt for grub. + */ + +/* Read in the node at the current path and depth into the node cache. + * You must set INFO->blocks[depth] before. + */ +static char * +read_tree_node (unsigned int blockNr, int depth) +{ +  char* cache = CACHE(depth); +  int num_cached = INFO->cached_slots; +  if (depth < num_cached) +    { +      /* This is the cached part of the path.  Check if same block is +       * needed. +       */ +      if (blockNr == INFO->blocks[depth]) +	return cache; +    } +  else +    cache = CACHE(num_cached); + +#ifdef REISERDEBUG +  printf ("  next read_in: block=%d (depth=%d)\n", +	  blockNr, depth); +#endif /* REISERDEBUG */ +  if (! block_read (blockNr, 0, INFO->blocksize, cache)) +      return NULL; +  /* Make sure it has the right node level */ +  if (BLOCKHEAD (cache)->blk_level != depth) +    { +      errnum = ERR_FSYS_CORRUPT; +      return NULL; +    } + +  INFO->blocks[depth] = blockNr; +  return cache; +} + +/* Get the next key, i.e. the key following the last retrieved key in + * tree order.  INFO->current_ih and + * INFO->current_info are adapted accordingly.  */ +static int +next_key (void) +{ +  int depth; +  struct item_head *ih = INFO->current_ih + 1; +  char *cache; + +#ifdef REISERDEBUG +  printf ("next_key:\n  old ih: key %d:%d:%d:%d version:%d\n", +	  INFO->current_ih->ih_key.k_dir_id, +	  INFO->current_ih->ih_key.k_objectid, +	  INFO->current_ih->ih_key.u.v1.k_offset, +	  INFO->current_ih->ih_key.u.v1.k_uniqueness, +	  INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ + +  if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item]) +    { +      depth = DISK_LEAF_NODE_LEVEL; +      /* The last item, was the last in the leaf node. +       * Read in the next block +       */ +      do +	{ +	  if (depth == INFO->tree_depth) +	    { +	      /* There are no more keys at all. +	       * Return a dummy item with MAX_KEY */ +	      ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; +	      goto found; +	    } +	  depth++; +#ifdef REISERDEBUG +	  printf ("  depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); +#endif /* REISERDEBUG */ +	} +      while (INFO->next_key_nr[depth] == 0); + +      if (depth == INFO->tree_depth) +	cache = ROOT; +      else if (depth <= INFO->cached_slots) +	cache = CACHE (depth); +      else +	{ +	  cache = read_tree_node (INFO->blocks[depth], depth); +	  if (! cache) +	    return 0; +	} + +      do +	{ +	  int nr_item = BLOCKHEAD (cache)->blk_nr_item; +	  int key_nr = INFO->next_key_nr[depth]++; +#ifdef REISERDEBUG +	  printf ("  depth=%d, i=%d/%d\n", depth, key_nr, nr_item); +#endif /* REISERDEBUG */ +	  if (key_nr == nr_item) +	    /* This is the last item in this block, set the next_key_nr to 0 */ +	    INFO->next_key_nr[depth] = 0; + +	  cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth); +	  if (! cache) +	    return 0; +	} +      while (depth > DISK_LEAF_NODE_LEVEL); + +      ih = ITEMHEAD; +    } + found: +  INFO->current_ih   = ih; +  INFO->current_item = &LEAF[ih->ih_item_location]; +#ifdef REISERDEBUG +  printf ("  new ih: key %d:%d:%d:%d version:%d\n", +	  INFO->current_ih->ih_key.k_dir_id, +	  INFO->current_ih->ih_key.k_objectid, +	  INFO->current_ih->ih_key.u.v1.k_offset, +	  INFO->current_ih->ih_key.u.v1.k_uniqueness, +	  INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ +  return 1; +} + +/* preconditions: reiserfs_mount already executed, therefore + *   INFO block is valid + * returns: 0 if error (errnum is set), + *   nonzero iff we were able to find the key successfully. + * postconditions: on a nonzero return, the current_ih and + *   current_item fields describe the key that equals the + *   searched key.  INFO->next_key contains the next key after + *   the searched key. + * side effects: messes around with the cache. + */ +static int +search_stat (__u32 dir_id, __u32 objectid) +{ +  char *cache; +  int depth; +  int nr_item; +  int i; +  struct item_head *ih; +#ifdef REISERDEBUG +  printf ("search_stat:\n  key %d:%d:0:0\n", dir_id, objectid); +#endif /* REISERDEBUG */ + +  depth = INFO->tree_depth; +  cache = ROOT; + +  while (depth > DISK_LEAF_NODE_LEVEL) +    { +      struct key *key; +      nr_item = BLOCKHEAD (cache)->blk_nr_item; + +      key = KEY (cache); + +      for (i = 0; i < nr_item; i++) +	{ +	  if (key->k_dir_id > dir_id +	      || (key->k_dir_id == dir_id +		  && (key->k_objectid > objectid +		      || (key->k_objectid == objectid +			  && (key->u.v1.k_offset +			      | key->u.v1.k_uniqueness) > 0)))) +	    break; +	  key++; +	} + +#ifdef REISERDEBUG +      printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item); +#endif /* REISERDEBUG */ +      INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; +      cache = read_tree_node (DC (cache)[i].dc_block_number, --depth); +      if (! cache) +	return 0; +    } + +  /* cache == LEAF */ +  nr_item = BLOCKHEAD (LEAF)->blk_nr_item; +  ih = ITEMHEAD; +  for (i = 0; i < nr_item; i++) +    { +      if (ih->ih_key.k_dir_id == dir_id +	  && ih->ih_key.k_objectid == objectid +	  && ih->ih_key.u.v1.k_offset == 0 +	  && ih->ih_key.u.v1.k_uniqueness == 0) +	{ +#ifdef REISERDEBUG +	  printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item); +#endif /* REISERDEBUG */ +	  INFO->current_ih   = ih; +	  INFO->current_item = &LEAF[ih->ih_item_location]; +	  return 1; +	} +      ih++; +    } +  errnum = ERR_FSYS_CORRUPT; +  return 0; +} + +int +reiserfs_read (char *buf, int len) +{ +  unsigned int blocksize; +  unsigned int offset; +  unsigned int to_read; +  char *prev_buf = buf; + +#ifdef REISERDEBUG +  printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n", +	  filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1); +#endif /* REISERDEBUG */ + +  if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid +      || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1) +    { +      search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid); +      goto get_next_key; +    } + +  while (! errnum) +    { +      if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid) +	break; + +      offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1; +      blocksize = INFO->current_ih->ih_item_len; + +#ifdef REISERDEBUG +      printf ("  loop: filepos=%d len=%d, offset=%d blocksize=%d\n", +	      filepos, len, offset, blocksize); +#endif /* REISERDEBUG */ + +      if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT) +	  && offset < blocksize) +	{ +#ifdef REISERDEBUG +	  printf ("direct_read: offset=%d, blocksize=%d\n", +		  offset, blocksize); +#endif /* REISERDEBUG */ +	  to_read = blocksize - offset; +	  if (to_read > len) +	    to_read = len; + +	  if (disk_read_hook != NULL) +	    { +	      disk_read_func = disk_read_hook; + +	      block_read (INFO->blocks[DISK_LEAF_NODE_LEVEL], +			  (INFO->current_item - LEAF + offset), to_read, buf); + +	      disk_read_func = NULL; +	    } +	  else +	    memcpy (buf, INFO->current_item + offset, to_read); +	  goto update_buf_len; +	} +      else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT)) +	{ +	  blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; +#ifdef REISERDEBUG +	  printf ("indirect_read: offset=%d, blocksize=%d\n", +		  offset, blocksize); +#endif /* REISERDEBUG */ + +	  while (offset < blocksize) +	    { +	      __u32 blocknr = ((__u32 *) INFO->current_item) +		[offset >> INFO->fullblocksize_shift]; +	      int blk_offset = offset & (INFO->blocksize-1); + +	      to_read = INFO->blocksize - blk_offset; +	      if (to_read > len) +		to_read = len; + +	      disk_read_func = disk_read_hook; + +	      /* Journal is only for meta data.  Data blocks can be read +	       * directly without using block_read +	       */ +	      devread (blocknr << INFO->blocksize_shift, +		       blk_offset, to_read, buf); + +	      disk_read_func = NULL; +	    update_buf_len: +	      len -= to_read; +	      buf += to_read; +	      offset += to_read; +	      filepos += to_read; +	      if (len == 0) +		goto done; +	    } +	} +    get_next_key: +      next_key (); +    } + done: +  return errnum ? 0 : buf - prev_buf; +} + + +/* preconditions: reiserfs_mount already executed, therefore + *   INFO block is valid + * returns: 0 if error, nonzero iff we were able to find the file successfully + * postconditions: on a nonzero return, INFO->fileinfo contains the info + *   of the file we were trying to look up, filepos is 0 and filemax is + *   the size of the file. + */ +int +reiserfs_dir (char *dirname) +{ +  struct reiserfs_de_head *de_head; +  char *rest, ch; +  __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; +#ifndef STAGE1_5 +  int do_possibilities = 0; +#endif /* ! STAGE1_5 */ +  char linkbuf[PATH_MAX];	/* buffer for following symbolic links */ +  int link_count = 0; +  int mode; + +  dir_id = REISERFS_ROOT_PARENT_OBJECTID; +  objectid = REISERFS_ROOT_OBJECTID; + +  while (1) +    { +#ifdef REISERDEBUG +      printf ("dirname=%s\n", dirname); +#endif /* REISERDEBUG */ + +      /* Search for the stat info first. */ +      if (! search_stat (dir_id, objectid)) +	return 0; + +#ifdef REISERDEBUG +      printf ("sd_mode=%x sd_size=%d\n", +	      ((struct stat_data *) INFO->current_item)->sd_mode, +	      ((struct stat_data *) INFO->current_item)->sd_size); +#endif /* REISERDEBUG */ + +      mode = ((struct stat_data *) INFO->current_item)->sd_mode; + +      /* If we've got a symbolic link, then chase it. */ +      if (S_ISLNK (mode)) +	{ +	  int len; +	  if (++link_count > MAX_LINK_COUNT) +	    { +	      errnum = ERR_SYMLINK_LOOP; +	      return 0; +	    } + +	  /* Get the symlink size. */ +	  filemax = ((struct stat_data *) INFO->current_item)->sd_size; + +	  /* Find out how long our remaining name is. */ +	  len = 0; +	  while (dirname[len] && !isspace (dirname[len])) +	    len++; + +	  if (filemax + len > sizeof (linkbuf) - 1) +	    { +	      errnum = ERR_FILELENGTH; +	      return 0; +	    } + +	  /* Copy the remaining name to the end of the symlink data. +	     Note that DIRNAME and LINKBUF may overlap! */ +	  grub_memmove (linkbuf + filemax, dirname, len+1); + +	  INFO->fileinfo.k_dir_id = dir_id; +	  INFO->fileinfo.k_objectid = objectid; +  	  filepos = 0; +	  if (! next_key () +	      || reiserfs_read (linkbuf, filemax) != filemax) +	    { +	      if (! errnum) +		errnum = ERR_FSYS_CORRUPT; +	      return 0; +	    } + +#ifdef REISERDEBUG +	  printf ("symlink=%s\n", linkbuf); +#endif /* REISERDEBUG */ + +	  dirname = linkbuf; +	  if (*dirname == '/') +	    { +	      /* It's an absolute link, so look it up in root. */ +	      dir_id = REISERFS_ROOT_PARENT_OBJECTID; +	      objectid = REISERFS_ROOT_OBJECTID; +	    } +	  else +	    { +	      /* Relative, so look it up in our parent directory. */ +	      dir_id   = parent_dir_id; +	      objectid = parent_objectid; +	    } + +	  /* Now lookup the new name. */ +	  continue; +	} + +      /* if we have a real file (and we're not just printing possibilities), +	 then this is where we want to exit */ + +      if (! *dirname || isspace (*dirname)) +	{ +	  if (! S_ISREG (mode)) +	    { +	      errnum = ERR_BAD_FILETYPE; +	      return 0; +	    } + +	  filepos = 0; +	  filemax = ((struct stat_data *) INFO->current_item)->sd_size; + +	  /* If this is a new stat data and size is > 4GB set filemax to +	   * maximum +	   */ +	  if (INFO->current_ih->ih_version == ITEM_VERSION_2 +	      && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0) +	    filemax = 0xffffffff; + +	  INFO->fileinfo.k_dir_id = dir_id; +	  INFO->fileinfo.k_objectid = objectid; +	  return next_key (); +	} + +      /* continue with the file/directory name interpretation */ +      while (*dirname == '/') +	dirname++; +      if (! S_ISDIR (mode)) +	{ +	  errnum = ERR_BAD_FILETYPE; +	  return 0; +	} +      for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++); +      *rest = 0; + +# ifndef STAGE1_5 +      if (print_possibilities && ch != '/') +	do_possibilities = 1; +# endif /* ! STAGE1_5 */ + +      while (1) +	{ +	  char *name_end; +	  int num_entries; + +	  if (! next_key ()) +	    return 0; +#ifdef REISERDEBUG +	  printf ("ih: key %d:%d:%d:%d version:%d\n", +		  INFO->current_ih->ih_key.k_dir_id, +		  INFO->current_ih->ih_key.k_objectid, +		  INFO->current_ih->ih_key.u.v1.k_offset, +		  INFO->current_ih->ih_key.u.v1.k_uniqueness, +		  INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ + +	  if (INFO->current_ih->ih_key.k_objectid != objectid) +	    break; + +	  name_end = INFO->current_item + INFO->current_ih->ih_item_len; +	  de_head = (struct reiserfs_de_head *) INFO->current_item; +	  num_entries = INFO->current_ih->u.ih_entry_count; +	  while (num_entries > 0) +	    { +	      char *filename = INFO->current_item + de_head->deh_location; +	      char  tmp = *name_end; +	      if ((de_head->deh_state & DEH_Visible)) +		{ +		  int cmp; +		  /* Directory names in ReiserFS are not null +		   * terminated.  We write a temporary 0 behind it. +		   * NOTE: that this may overwrite the first block in +		   * the tree cache.  That doesn't hurt as long as we +		   * don't call next_key () in between. +		   */ +		  *name_end = 0; +		  cmp = substring (dirname, filename); +		  *name_end = tmp; +# ifndef STAGE1_5 +		  if (do_possibilities) +		    { +		      if (cmp <= 0) +			{ +			  if (print_possibilities > 0) +			    print_possibilities = -print_possibilities; +			  *name_end = 0; +			  print_a_completion (filename); +			  *name_end = tmp; +			} +		    } +		  else +# endif /* ! STAGE1_5 */ +		    if (cmp == 0) +		      goto found; +		} +	      /* The beginning of this name marks the end of the next name. +	       */ +	      name_end = filename; +	      de_head++; +	      num_entries--; +	    } +	} + +# ifndef STAGE1_5 +      if (print_possibilities < 0) +	return 1; +# endif /* ! STAGE1_5 */ + +      errnum = ERR_FILE_NOT_FOUND; +      *rest = ch; +      return 0; + +    found: + +      *rest = ch; +      dirname = rest; + +      parent_dir_id = dir_id; +      parent_objectid = objectid; +      dir_id = de_head->deh_dir_id; +      objectid = de_head->deh_objectid; +    } +} + +int +reiserfs_embed (int *start_sector, int needed_sectors) +{ +  struct reiserfs_super_block super; +  int num_sectors; + +  if (! devread (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0, +		 sizeof (struct reiserfs_super_block), (char *) &super)) +    return 0; + +  *start_sector = 1; /* reserve first sector for stage1 */ +  if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0 +       || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0) +      && (/* check that this is not a super block copy inside +	   * the journal log */ +	  super.s_journal_block * super.s_blocksize +	  > REISERFS_DISK_OFFSET_IN_BYTES)) +    num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1; +  else +    num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1; + +  return (needed_sectors <= num_sectors); +} +#endif /* FSYS_REISERFS */ diff --git a/roms/openbios/fs/grubfs/fsys_ufs.c b/roms/openbios/fs/grubfs/fsys_ufs.c new file mode 100644 index 00000000..8e0a0f77 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_ufs.c @@ -0,0 +1,391 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (c) 2000, 2001  Free Software Foundation, Inc. + *  Copyright (c) 2005  Rink Springer + * + *  This file is based on FreeBSD 5.4-RELEASE's /sys/boot/common/ufsread.c, + *  and has some minor patches so it'll work with Cromwell/GRUB. + * + */ +/*- + * Copyright (c) 2002 McAfee, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and McAfee Research,, the Security Research Division of + * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as + * part of the DARPA CHATS research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ +#ifdef FSYS_UFS + +#include "asm/types.h" + +#include "shared.h" +#include "filesys.h" + +#include "ufs_dinode.h" +#include "ufs_fs.h" + +#ifdef __i386__ +/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase +   (see sys/ufs/ffs/fs.h rev 1.39) so that i386 boot loader (boot2) can +   support both UFS1 and UFS2 again. */ +#undef cgbase +#define cgbase(fs, c)   ((ufs2_daddr_t)((fs)->fs_fpg * (c))) +#endif + +/* + * We use 4k `virtual' blocks for filesystem data, whatever the actual + * filesystem block size. FFS blocks are always a multiple of 4k. + */ +#define VBLKSHIFT	12 +#define VBLKSIZE	(1 << VBLKSHIFT) +#define VBLKMASK	(VBLKSIZE - 1) +#define DBPERVBLK	(VBLKSIZE / DEV_BSIZE) +#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define IPERVBLK(fs)	(INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define INO_TO_VBA(fs, ipervblk, x) \ +    (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ +    (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) +#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) +#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ +    ((off) / VBLKSIZE) * DBPERVBLK) +#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) + +/* Buffers that must not span a 64k boundary. */ +struct dmadat { +	char blkbuf[VBLKSIZE];	/* filesystem blocks */ +	char indbuf[VBLKSIZE];	/* indir blocks */ +	char sbbuf[SBLOCKSIZE];	/* superblock */ +	char secbuf[DEV_BSIZE];	/* for MBR/disklabel */ +}; +static struct dmadat *dmadat = (struct dmadat*)FSYS_BUF; + +#define SUPERBLOCK ((struct fs*)dmadat->sbbuf) + +ino_t lookup(const char *); +ssize_t fsread(ino_t, void *, size_t); + +static int dsk_meta; +static uint32_t fs_off; +static ino_t cur_ino = 0; + +static inline int +dskread (void* buf, unsigned lba, unsigned nblk) +{ +	return !devread (lba, 0, nblk * DEV_BSIZE, buf) ? -1 : 0; +} + +#if defined(UFS2_ONLY) +#define DIP(field) dp2.field +#elif defined(UFS1_ONLY) +#define DIP(field) dp1.field +#else +#define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field +#endif + +static __inline int +fsfind(const char *name, ino_t * ino) +{ +	char buf[DEV_BSIZE]; +	struct ufs_dirent *d; +	char *s; +	ssize_t n; +#ifndef UFS2_ONLY +	static struct ufs1_dinode dp1; +#endif +#ifndef UFS1_ONLY +	static struct ufs2_dinode dp2; +#endif +	char* blkbuf = dmadat->blkbuf; +	struct fs* fs = (struct fs *)dmadat->sbbuf; + +	fs_off = 0; +	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) +		for (s = buf; s < buf + DEV_BSIZE;) { +			d = (void *)s; +			if (!strcmp(name, d->d_name)) { +				*ino = d->d_fileno; + +				/* below is for grub, which wants the file size +				 */ +				n = IPERVBLK(fs); +				if (dskread(blkbuf, INO_TO_VBA(fs, n, (*ino)), DBPERVBLK)) +					return -1; +				n = INO_TO_VBO(n, (*ino)); +#if defined(UFS1_ONLY) +				dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +#elif defined(UFS2_ONLY) +				dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#else +				if (fs->fs_magic == FS_UFS1_MAGIC) +					dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +				else +					dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#endif + +				filemax = DIP(di_size); +				return d->d_type; +			} +			s += d->d_reclen; +		} +	return 0; +} + +ino_t +lookup(const char *path) +{ +	char name[MAXNAMLEN + 1]; +	const char *s; +	ino_t ino; +	ssize_t n; +	int dt; + +	ino = ROOTINO; +	dt = DT_DIR; +	name[0] = '/'; +	name[1] = '\0'; +	for (;;) { +		if (*path == '/') +			path++; +		if (!*path) +			break; +		for (s = path; *s && *s != '/'; s++); +		if ((n = s - path) > MAXNAMLEN) +			return 0; +		memcpy(name, path, n); +		name[n] = 0; +		if (dt != DT_DIR) { +			printk("%s: not a directory.\n", name); +			return (0); +		} +		if ((dt = fsfind(name, &ino)) <= 0) +			break; +		path = s; +	} +	return dt == DT_REG ? ino : 0; +} + +/* + * Possible superblock locations ordered from most to least likely. + */ +static const int sblock_try[] = SBLOCKSEARCH; + +ssize_t +fsread(ino_t inode, void *buf, size_t nbyte) +{ +#ifndef UFS2_ONLY +	static struct ufs1_dinode dp1; +#endif +#ifndef UFS1_ONLY +	static struct ufs2_dinode dp2; +#endif +	static ino_t inomap; +	char *blkbuf; +	void *indbuf; +	struct fs *fs; +	char *s; +	size_t n, nb, size, off, vboff; +	ufs_lbn_t lbn; +	ufs2_daddr_t addr, vbaddr; +	static ufs2_daddr_t blkmap, indmap; +	unsigned int u; + + +	blkbuf = dmadat->blkbuf; +	indbuf = dmadat->indbuf; +	fs = (struct fs *)dmadat->sbbuf; +	if (!dsk_meta) { +		inomap = 0; +		for (n = 0; sblock_try[n] != -1; n++) { +			if (dskread(fs, sblock_try[n] / DEV_BSIZE, +			    SBLOCKSIZE / DEV_BSIZE)) +				return -1; +			if (( +#if defined(UFS1_ONLY) +			     fs->fs_magic == FS_UFS1_MAGIC +#elif defined(UFS2_ONLY) +			    (fs->fs_magic == FS_UFS2_MAGIC && +			    fs->fs_sblockloc == sblock_try[n]) +#else +			     fs->fs_magic == FS_UFS1_MAGIC || +			    (fs->fs_magic == FS_UFS2_MAGIC && +			    fs->fs_sblockloc == sblock_try[n]) +#endif +			    ) && +			    fs->fs_bsize <= MAXBSIZE && +			    fs->fs_bsize >= sizeof(struct fs)) +				break; +		} +		if (sblock_try[n] == -1) { +			printk("Not ufs\n"); +			return -1; +		} +		dsk_meta++; +	} +	if (!inode) +		return 0; +	if (inomap != inode) { +		n = IPERVBLK(fs); +		if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK)) +			return -1; +		n = INO_TO_VBO(n, inode); +#if defined(UFS1_ONLY) +		dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +#elif defined(UFS2_ONLY) +		dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#else +		if (fs->fs_magic == FS_UFS1_MAGIC) +			dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +		else +			dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#endif +		inomap = inode; +		fs_off = 0; +		blkmap = indmap = 0; +	} +	s = buf; +	size = DIP(di_size); +	n = size - fs_off; +	if (nbyte > n) +		nbyte = n; +	nb = nbyte; +	while (nb) { +		lbn = lblkno(fs, fs_off); +		off = blkoff(fs, fs_off); +		if (lbn < NDADDR) { +			addr = DIP(di_db[lbn]); +		} else if (lbn < NDADDR + NINDIR(fs)) { +			n = INDIRPERVBLK(fs); +			addr = DIP(di_ib[0]); +			u = (unsigned int)(lbn - NDADDR) / (n * DBPERVBLK); +			vbaddr = fsbtodb(fs, addr) + u; +			if (indmap != vbaddr) { +				if (dskread(indbuf, vbaddr, DBPERVBLK)) +					return -1; +				indmap = vbaddr; +			} +			n = (lbn - NDADDR) & (n - 1); +#if defined(UFS1_ONLY) +			addr = ((ufs1_daddr_t *)indbuf)[n]; +#elif defined(UFS2_ONLY) +			addr = ((ufs2_daddr_t *)indbuf)[n]; +#else +			if (fs->fs_magic == FS_UFS1_MAGIC) +				addr = ((ufs1_daddr_t *)indbuf)[n]; +			else +				addr = ((ufs2_daddr_t *)indbuf)[n]; +#endif +		} else { +			return -1; +		} +		vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK; +		vboff = off & VBLKMASK; +		n = sblksize(fs, size, lbn) - (off & ~VBLKMASK); +		if (n > VBLKSIZE) +			n = VBLKSIZE; +		if (blkmap != vbaddr) { +			if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) +				return -1; +			blkmap = vbaddr; +		} +		n -= vboff; +		if (n > nb) +			n = nb; +		memcpy(s, blkbuf + vboff, n); +		s += n; +		fs_off += n; +		nb -= n; +	} +	return nbyte; +} + +int +ufs_mount (void) +{ +  int i, retval = 0; + +  /* +   * We don't care about stuff being in disklabels or not. If the magic +   * matches, we're good to go. +   */ +  for (i = 0; sblock_try[i] != -1; ++i) +  { +	if (! (part_length < (sblock_try[i] + (SBLOCKSIZE / DEV_BSIZE)) +		 || ! devread (0, sblock_try[i], SBLOCKSIZE, (char *) SUPERBLOCK))) +	    { +		if ( +#if defined(UFS1_ONLY) +		     SUPERBLOCK->fs_magic == FS_UFS1_MAGIC +#elif defined(UFS2_ONLY) +		    (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC && +		     SUPERBLOCK->fs_sblockloc == sblock_try[i]) +#else +		     SUPERBLOCK->fs_magic == FS_UFS1_MAGIC || +		    (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC && +		     SUPERBLOCK->fs_sblockloc == sblock_try[i]) +#endif +		) { +			retval = 1; break; +		} +	    } +  } +  return retval; +} + +int +ufs_read (char *buf, int len) +{ +	return fsread(cur_ino, buf, len); +} + +int +ufs_dir (char *dirname) +{ +	cur_ino = lookup(dirname); +	return cur_ino & 0xffffffff; +} + +int +ufs_embed (int* start_sector, int needed_sectors) +{ +	/* TODO; unused by Cromwell */ +	return 0; +} + +#endif /* FSYS_UFS */ diff --git a/roms/openbios/fs/grubfs/fsys_vstafs.c b/roms/openbios/fs/grubfs/fsys_vstafs.c new file mode 100644 index 00000000..e06d3e73 --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_vstafs.c @@ -0,0 +1,254 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2001   Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_VSTAFS + +#include "shared.h" +#include "filesys.h" +#include "vstafs.h" + + +static void get_file_info (int sector); +static struct dir_entry *vstafs_readdir (long sector); +static struct dir_entry *vstafs_nextdir (void); + + +#define FIRST_SECTOR	((struct first_sector *) FSYS_BUF) +#define FILE_INFO       ((struct fs_file *) (long) FIRST_SECTOR + 8192) +#define DIRECTORY_BUF   ((struct dir_entry *) (long) FILE_INFO + 512) + +#define ROOT_SECTOR	1 + +/* + * In f_sector we store the sector number in which the information about + * the found file is. + */ +static int f_sector; + +int +vstafs_mount (void) +{ +  int retval = 1; + +  if( (((current_drive & 0x80) || (current_slice != 0)) +       && current_slice != PC_SLICE_TYPE_VSTAFS) +      ||  ! devread (0, 0, BLOCK_SIZE, (char *) FSYS_BUF) +      ||  FIRST_SECTOR->fs_magic != 0xDEADFACE) +    retval = 0; + +  return retval; +} + +static void +get_file_info (int sector) +{ +  devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO); +} + +static int curr_ext, current_direntry, current_blockpos; +static struct alloc *a1; + +static struct dir_entry * +vstafs_readdir (long sector) +{ +  /* +   * Get some information from the current directory +   */ +  get_file_info (sector); +  if (FILE_INFO->type != 2) +    { +      errnum = ERR_FILE_NOT_FOUND; +      return NULL; +    } + +  a1 = FILE_INFO->blocks; +  curr_ext = 0; +  devread (a1[curr_ext].a_start, 0, 512, (char *) DIRECTORY_BUF); +  current_direntry = 11; +  current_blockpos = 0; + +  return &DIRECTORY_BUF[10]; +} + +static struct dir_entry * +vstafs_nextdir (void) +{ +  if (current_direntry > 15) +    { +      current_direntry = 0; +      if (++current_blockpos > (a1[curr_ext].a_len - 1)) +	{ +	  current_blockpos = 0; +	  curr_ext++; +	} + +      if (curr_ext < FILE_INFO->extents) +	{ +            devread (a1[curr_ext].a_start + current_blockpos, 0, +                     512, (char *) DIRECTORY_BUF); +	} +      else +	{ +            /* errnum =ERR_FILE_NOT_FOUND; */ +            return NULL; +	} +    } + +  return &DIRECTORY_BUF[current_direntry++]; +} + +int +vstafs_dir (char *dirname) +{ +  char *fn, ch; +  struct dir_entry *d; +  /* int l, i, s; */ + +  /* +   * Read in the entries of the current directory. +   */ +  f_sector = ROOT_SECTOR; +  do +    { +      if (! (d = vstafs_readdir (f_sector))) +	{ +	  return 0; +	} + +      /* +       * Find the file in the path +       */ +      while (*dirname == '/') dirname++; +      fn = dirname; +      while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++; +      *fn = 0; + +      do +	{ +	  if (d->name[0] == 0 || d->name[0] & 0x80) +	    continue; + +#ifndef STAGE1_5 +	  if (print_possibilities && ch != '/' +	      && (! *dirname || strcmp (dirname, d->name) <= 0)) +	    { +	      if (print_possibilities > 0) +		print_possibilities = -print_possibilities; + +	      printf ("  %s", d->name); +	    } +#endif +	  if (! grub_strcmp (dirname, d->name)) +	    { +	      f_sector = d->start; +	      get_file_info (f_sector); +	      filemax = FILE_INFO->len; +	      break; +	    } +	} +      while ((d =vstafs_nextdir ())); + +      *(dirname = fn) = ch; +      if (! d) +	{ +	  if (print_possibilities < 0) +	    { +#ifndef STAGE1_5 +	      putchar ('\n'); +#endif +	      return 1; +	    } + +	  errnum = ERR_FILE_NOT_FOUND; +	  return 0; +	} +    } +  while (*dirname && ! isspace (ch)); + +  return 1; +} + +int +vstafs_read (char *addr, int len) +{ +  struct alloc *a2; +  int size, ret = 0, offset, curr_len = 0; +  int curr_ext2; +  char extent; +  int ext_size; +  char *curr_pos; + +  get_file_info (f_sector); +  size = FILE_INFO->len-VSTAFS_START_DATA; +  a2 = FILE_INFO->blocks; + +  if (filepos > 0) +    { +      if (filepos < a2[0].a_len * 512 - VSTAFS_START_DATA) +	{ +	  offset = filepos + VSTAFS_START_DATA; +	  extent = 0; +          curr_len = a2[0].a_len * 512 - offset - filepos; +	} +      else +	{ +          ext_size = a2[0].a_len * 512 - VSTAFS_START_DATA; +	  offset = filepos - ext_size; +	  extent = 1; +	  do +	    { +	      curr_len -= ext_size; +	      offset -= ext_size; +              ext_size = a2[extent+1].a_len * 512; +	    } +	  while (extent < FILE_INFO->extents && offset>ext_size); +	} +    } +  else +    { +      offset = VSTAFS_START_DATA; +      extent = 0; +      curr_len = a2[0].a_len * 512 - offset; +    } + +  curr_pos = addr; +  if (curr_len > len) +    curr_len = len; + +  for (curr_ext2=extent; +       curr_ext2 < FILE_INFO->extents; +       curr_len = a2[curr_ext].a_len * 512, curr_pos += curr_len, curr_ext2++) +    { +      ret += curr_len; +      size -= curr_len; +      if (size < 0) +	{ +	  ret += size; +	  curr_len += size; +	} + +      devread (a2[curr_ext2].a_start,offset, curr_len, curr_pos); +      offset = 0; +    } + +  return ret; +} + +#endif /* FSYS_VSTAFS */ diff --git a/roms/openbios/fs/grubfs/fsys_xfs.c b/roms/openbios/fs/grubfs/fsys_xfs.c new file mode 100644 index 00000000..b082621c --- /dev/null +++ b/roms/openbios/fs/grubfs/fsys_xfs.c @@ -0,0 +1,639 @@ +/* fsys_xfs.c - an implementation for the SGI XFS file system */ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2001,2002  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifdef FSYS_XFS + +#include "shared.h" +#include "filesys.h" +#include "xfs.h" + +#define MAX_LINK_COUNT	8 + +typedef struct xad { +	xfs_fileoff_t offset; +	xfs_fsblock_t start; +	xfs_filblks_t len; +} xad_t; + +struct xfs_info { +	int bsize; +	int dirbsize; +	int isize; +	unsigned int agblocks; +	int bdlog; +	int blklog; +	int inopblog; +	int agblklog; +	int agnolog; +	unsigned int nextents; +	xfs_daddr_t next; +	xfs_daddr_t daddr; +	xfs_dablk_t forw; +	xfs_dablk_t dablk; +	xfs_bmbt_rec_32_t *xt; +	xfs_bmbt_ptr_t ptr0; +	int btnode_ptr0_off; +	int i8param; +	int dirpos; +	int dirmax; +	int blkoff; +	int fpos; +	xfs_ino_t rootino; +}; + +static struct xfs_info xfs; + +#define dirbuf		((char *)FSYS_BUF) +#define filebuf		((char *)FSYS_BUF + 4096) +#define inode		((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) +#define icore		(inode->di_core) + +#define	mask32lo(n)	(((__uint32_t)1 << (n)) - 1) + +#define	XFS_INO_MASK(k)		((__uint32_t)((1ULL << (k)) - 1)) +#define	XFS_INO_OFFSET_BITS	xfs.inopblog +#define	XFS_INO_AGBNO_BITS	xfs.agblklog +#define	XFS_INO_AGINO_BITS	(xfs.agblklog + xfs.inopblog) +#define	XFS_INO_AGNO_BITS	xfs.agnolog + +static inline xfs_agblock_t +agino2agbno (xfs_agino_t agino) +{ +	return agino >> XFS_INO_OFFSET_BITS; +} + +static inline xfs_agnumber_t +ino2agno (xfs_ino_t ino) +{ +	return ino >> XFS_INO_AGINO_BITS; +} + +static inline xfs_agino_t +ino2agino (xfs_ino_t ino) +{ +	return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS); +} + +static inline int +ino2offset (xfs_ino_t ino) +{ +	return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS); +} + +static inline __uint16_t +le16 (__uint16_t x) +{ +#ifdef __i386__ +	__asm__("xchgb %b0,%h0"	\ +		: "=q" (x) \ +		:  "0" (x)); \ +		return x; +#else +	return __be16_to_cpu(x); +#endif +} + +static inline __uint32_t +le32 (__uint32_t x) +{ +#ifdef __i386__ +#if 1 +        /* 386 doesn't have bswap. So what. */ +	__asm__("bswap %0" : "=r" (x) : "0" (x)); +#else +	/* This is slower but this works on all x86 architectures.  */ +	__asm__("xchgb %b0, %h0" \ +		"\n\troll $16, %0" \ +		"\n\txchgb %b0, %h0" \ +		: "=q" (x) : "0" (x)); +#endif +	return x; +#else +	return __be32_to_cpu(x); +#endif +} + +static inline __uint64_t +le64 (__uint64_t x) +{ +	__uint32_t h = x >> 32; +        __uint32_t l = x & ((1ULL<<32)-1); +        return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h))); +} + + +static xfs_fsblock_t +xt_start (xfs_bmbt_rec_32_t *r) +{ +	return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) | +	       (((xfs_fsblock_t)le32 (r->l2)) << 11) | +	       (((xfs_fsblock_t)le32 (r->l3)) >> 21); +} + +static xfs_fileoff_t +xt_offset (xfs_bmbt_rec_32_t *r) +{ +	return (((xfs_fileoff_t)le32 (r->l0) & +		mask32lo(31)) << 23) | +		(((xfs_fileoff_t)le32 (r->l1)) >> 9); +} + +static xfs_filblks_t +xt_len (xfs_bmbt_rec_32_t *r) +{ +	return le32(r->l3) & mask32lo(21); +} + +static inline int +xfs_highbit32(__uint32_t v) +{ +	int i; + +	if (--v) { +		for (i = 0; i < 31; i++, v >>= 1) { +			if (v == 0) +				return i; +		} +	} +	return 0; +} + +static int +isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) +{ +	return (key >= offset) ? (key < offset + len ? 1 : 0) : 0; +} + +static xfs_daddr_t +agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno) +{ +	return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog; +} + +static xfs_daddr_t +fsb2daddr (xfs_fsblock_t fsbno) +{ +	return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog), +			 (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog))); +} + +#undef offsetof +#define offsetof(t,m)	((long)&(((t *)0)->m)) + +static inline int +btroot_maxrecs (void) +{ +	int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize; + +	return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) / +		(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)); +} + +static int +di_read (xfs_ino_t ino) +{ +	xfs_agino_t agino; +	xfs_agnumber_t agno; +	xfs_agblock_t agbno; +	xfs_daddr_t daddr; +	int offset; + +	agno = ino2agno (ino); +	agino = ino2agino (ino); +	agbno = agino2agbno (agino); +	offset = ino2offset (ino); +	daddr = agb2daddr (agno, agbno); + +	devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode); + +	xfs.ptr0 = *(xfs_bmbt_ptr_t *) +		    (inode->di_u.di_c + sizeof(xfs_bmdr_block_t) +		    + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t)); + +	return 1; +} + +static void +init_extents (void) +{ +	xfs_bmbt_ptr_t ptr0; +	xfs_btree_lblock_t h; + +	switch (icore.di_format) { +	case XFS_DINODE_FMT_EXTENTS: +		xfs.xt = inode->di_u.di_bmx; +		xfs.nextents = le32 (icore.di_nextents); +		break; +	case XFS_DINODE_FMT_BTREE: +		ptr0 = xfs.ptr0; +		for (;;) { +			xfs.daddr = fsb2daddr (le64(ptr0)); +			devread (xfs.daddr, 0, +				 sizeof(xfs_btree_lblock_t), (char *)&h); +			if (!h.bb_level) { +				xfs.nextents = le16(h.bb_numrecs); +				xfs.next = fsb2daddr (le64(h.bb_rightsib)); +				xfs.fpos = sizeof(xfs_btree_block_t); +				return; +			} +			devread (xfs.daddr, xfs.btnode_ptr0_off, +				 sizeof(xfs_bmbt_ptr_t), (char *)&ptr0); +		} +	} +} + +static xad_t * +next_extent (void) +{ +	static xad_t xad; + +	switch (icore.di_format) { +	case XFS_DINODE_FMT_EXTENTS: +		if (xfs.nextents == 0) +			return NULL; +		break; +	case XFS_DINODE_FMT_BTREE: +		if (xfs.nextents == 0) { +			xfs_btree_lblock_t h; +			if (xfs.next == 0) +				return NULL; +			xfs.daddr = xfs.next; +			devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h); +			xfs.nextents = le16(h.bb_numrecs); +			xfs.next = fsb2daddr (le64(h.bb_rightsib)); +			xfs.fpos = sizeof(xfs_btree_block_t); +		} +		/* Yeah, I know that's slow, but I really don't care */ +		devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf); +		xfs.xt = (xfs_bmbt_rec_32_t *)filebuf; +		xfs.fpos += sizeof(xfs_bmbt_rec_32_t); +	} +	xad.offset = xt_offset (xfs.xt); +	xad.start = xt_start (xfs.xt); +	xad.len = xt_len (xfs.xt); +	++xfs.xt; +	--xfs.nextents; + +	return &xad; +} + +/* + * Name lies - the function reads only first 100 bytes + */ +static void +xfs_dabread (void) +{ +	xad_t *xad; +	xfs_fileoff_t offset;; + +	init_extents (); +	while ((xad = next_extent ())) { +		offset = xad->offset; +		if (isinxt (xfs.dablk, offset, xad->len)) { +			devread (fsb2daddr (xad->start + xfs.dablk - offset), +				 0, 100, dirbuf); +			break; +		} +	} +} + +static inline xfs_ino_t +sf_ino (char *sfe, int namelen) +{ +	void *p = sfe + namelen + 3; + +	return (xfs.i8param == 0) +		? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p); +} + +static inline xfs_ino_t +sf_parent_ino (void) +{ +	return (xfs.i8param == 0) +		? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent)) +		: le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent)); +} + +static inline int +roundup8 (int n) +{ +	return ((n+7)&~7); +} + +static char * +next_dentry (xfs_ino_t *ino) +{ +	int namelen = 1; +	int toread; +        static char *usual[2]; +	static xfs_dir2_sf_entry_t *sfe; +        char *name; + +        if (!usual[0]) { +            usual[0] = strdup("."); +            usual[1] = strdup(".."); +        } +        name = usual[0]; + +	if (xfs.dirpos >= xfs.dirmax) { +		if (xfs.forw == 0) +			return NULL; +		xfs.dablk = xfs.forw; +		xfs_dabread (); +#define h	((xfs_dir2_leaf_hdr_t *)dirbuf) +		xfs.dirmax = le16 (h->count) - le16 (h->stale); +		xfs.forw = le32 (h->info.forw); +#undef h +		xfs.dirpos = 0; +	} + +	switch (icore.di_format) { +	case XFS_DINODE_FMT_LOCAL: +		switch (xfs.dirpos) { +		case -2: +			*ino = 0; +			break; +		case -1: +			*ino = sf_parent_ino (); +			++name; +			++namelen; +			sfe = (xfs_dir2_sf_entry_t *) +				(inode->di_u.di_c +				 + sizeof(xfs_dir2_sf_hdr_t) +				 - xfs.i8param); +			break; +		default: +			namelen = sfe->namelen; +			*ino = sf_ino ((char *)sfe, namelen); +			name = (char *)sfe->name; +			sfe = (xfs_dir2_sf_entry_t *) +				  ((char *)sfe + namelen + 11 - xfs.i8param); +		} +		break; +	case XFS_DINODE_FMT_BTREE: +	case XFS_DINODE_FMT_EXTENTS: +#define dau	((xfs_dir2_data_union_t *)dirbuf) +		for (;;) { +			if (xfs.blkoff >= xfs.dirbsize) { +				xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); +				filepos &= ~(xfs.dirbsize - 1); +				filepos |= xfs.blkoff; +			} +			xfs_read (dirbuf, 4); +			xfs.blkoff += 4; +			if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) { +				toread = roundup8 (le16(dau->unused.length)) - 4; +				xfs.blkoff += toread; +				filepos += toread; +				continue; +			} +			break; +		} +		xfs_read ((char *)dirbuf + 4, 5); +		*ino = le64 (dau->entry.inumber); +		namelen = dau->entry.namelen; +#undef dau +		toread = roundup8 (namelen + 11) - 9; +		xfs_read (dirbuf, toread); +		name = (char *)dirbuf; +		xfs.blkoff += toread + 5; +	} +	++xfs.dirpos; +	name[namelen] = 0; + +	return name; +} + +static char * +first_dentry (xfs_ino_t *ino) +{ +	xfs.forw = 0; +	switch (icore.di_format) { +	case XFS_DINODE_FMT_LOCAL: +		xfs.dirmax = inode->di_u.di_dir2sf.hdr.count; +		xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4; +		xfs.dirpos = -2; +		break; +	case XFS_DINODE_FMT_EXTENTS: +	case XFS_DINODE_FMT_BTREE: +		filepos = 0; +		xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t)); +		if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) { +#define tail		((xfs_dir2_block_tail_t *)dirbuf) +			filepos = xfs.dirbsize - sizeof(*tail); +			xfs_read (dirbuf, sizeof(*tail)); +			xfs.dirmax = le32 (tail->count) - le32 (tail->stale); +#undef tail +		} else { +			xfs.dablk = (1ULL << 35) >> xfs.blklog; +#define h		((xfs_dir2_leaf_hdr_t *)dirbuf) +#define n		((xfs_da_intnode_t *)dirbuf) +			for (;;) { +				xfs_dabread (); +				if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC)) +				    || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) { +					xfs.dirmax = le16 (h->count) - le16 (h->stale); +					xfs.forw = le32 (h->info.forw); +					break; +				} +				xfs.dablk = le32 (n->btree[0].before); +			} +#undef n +#undef h +		} +		xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); +		filepos = xfs.blkoff; +		xfs.dirpos = 0; +	} +	return next_dentry (ino); +} + +int +xfs_mount (void) +{ +	xfs_sb_t super; + +	if (!devread (0, 0, sizeof(super), (char *)&super) +	    || (le32(super.sb_magicnum) != XFS_SB_MAGIC) +	    || ((le16(super.sb_versionnum) +		& XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) { +		return 0; +	} + +	xfs.bsize = le32 (super.sb_blocksize); +	xfs.blklog = super.sb_blocklog; +	xfs.bdlog = xfs.blklog - SECTOR_BITS; +	xfs.rootino = le64 (super.sb_rootino); +	xfs.isize = le16 (super.sb_inodesize); +	xfs.agblocks = le32 (super.sb_agblocks); +	xfs.dirbsize = xfs.bsize << super.sb_dirblklog; + +	xfs.inopblog = super.sb_inopblog; +	xfs.agblklog = super.sb_agblklog; +	xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); + +	xfs.btnode_ptr0_off = +		((xfs.bsize - sizeof(xfs_btree_block_t)) / +		(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) +		 * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t); + +	return 1; +} + +int +xfs_read (char *buf, int len) +{ +	xad_t *xad; +	xfs_fileoff_t endofprev, endofcur, offset; +	xfs_filblks_t xadlen; +	int toread, startpos, endpos; + +	if (icore.di_format == XFS_DINODE_FMT_LOCAL) { +		grub_memmove (buf, inode->di_u.di_c + filepos, len); +		filepos += len; +		return len; +	} + +	startpos = filepos; +	endpos = filepos + len; +	endofprev = (xfs_fileoff_t)-1; +	init_extents (); +	while (len > 0 && (xad = next_extent ())) { +		offset = xad->offset; +		xadlen = xad->len; +		if (isinxt (filepos >> xfs.blklog, offset, xadlen)) { +			endofcur = (offset + xadlen) << xfs.blklog; +			toread = (endofcur >= endpos) +				  ? len : (endofcur - filepos); + +			disk_read_func = disk_read_hook; +			devread (fsb2daddr (xad->start), +				 filepos - (offset << xfs.blklog), toread, buf); +			disk_read_func = NULL; + +			buf += toread; +			len -= toread; +			filepos += toread; +		} else if (offset > endofprev) { +			toread = ((offset << xfs.blklog) >= endpos) +				  ? len : ((offset - endofprev) << xfs.blklog); +			len -= toread; +			filepos += toread; +			for (; toread; toread--) { +				*buf++ = 0; +			} +			continue; +		} +		endofprev = offset + xadlen; +	} + +	return filepos - startpos; +} + +int +xfs_dir (char *dirname) +{ +	xfs_ino_t ino, parent_ino, new_ino; +	xfs_fsize_t di_size; +	int di_mode; +	int cmp, n, link_count; +	char linkbuf[xfs.bsize]; +	char *rest, *name, ch; + +	parent_ino = ino = xfs.rootino; +	link_count = 0; +	for (;;) { +		di_read (ino); +		di_size = le64 (icore.di_size); +		di_mode = le16 (icore.di_mode); + +		if ((di_mode & IFMT) == IFLNK) { +			if (++link_count > MAX_LINK_COUNT) { +				errnum = ERR_SYMLINK_LOOP; +				return 0; +			} +			if (di_size < xfs.bsize - 1) { +				filepos = 0; +				filemax = di_size; +				n = xfs_read (linkbuf, filemax); +			} else { +				errnum = ERR_FILELENGTH; +				return 0; +			} + +			ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino; +			while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++)); +			linkbuf[n] = 0; +			dirname = linkbuf; +			continue; +		} + +		if (!*dirname || isspace (*dirname)) { +			if ((di_mode & IFMT) != IFREG) { +				errnum = ERR_BAD_FILETYPE; +				return 0; +			} +			filepos = 0; +			filemax = di_size; +			return 1; +		} + +		if ((di_mode & IFMT) != IFDIR) { +			errnum = ERR_BAD_FILETYPE; +			return 0; +		} + +		for (; *dirname == '/'; dirname++); + +		for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); +		*rest = 0; + +		name = first_dentry (&new_ino); +		for (;;) { +			cmp = (!*dirname) ? -1 : substring (dirname, name); +#ifndef STAGE1_5 +			if (print_possibilities && ch != '/' && cmp <= 0) { +				if (print_possibilities > 0) +					print_possibilities = -print_possibilities; +				print_a_completion (name); +			} else +#endif +			if (cmp == 0) { +				parent_ino = ino; +				if (new_ino) +					ino = new_ino; +		        	*(dirname = rest) = ch; +				break; +			} +			name = next_dentry (&new_ino); +			if (name == NULL) { +				if (print_possibilities < 0) +					return 1; + +				errnum = ERR_FILE_NOT_FOUND; +				*rest = ch; +				return 0; +			} +		} +	} +} + +#endif /* FSYS_XFS */ diff --git a/roms/openbios/fs/grubfs/glue.h b/roms/openbios/fs/grubfs/glue.h new file mode 100644 index 00000000..7f212937 --- /dev/null +++ b/roms/openbios/fs/grubfs/glue.h @@ -0,0 +1,48 @@ +#ifndef __GLUE_H +#define __GLUE_H + +#include "asm/types.h" +#include "config.h" +#include "libc/byteorder.h" + +typedef uint64_t sector_t; + +int devopen(void); + +int devread(unsigned long sector, unsigned long byte_offset, +	unsigned long byte_len, void *buf); + +int file_open(const char *filename); +int file_read(void *buf, unsigned long len); +int file_seek(unsigned long offset); +unsigned long file_size(void); +void file_close(void); + +int mount_fs(void); + +extern int using_devsize; + +/* + * some of the filesystem drivers don't correctly provide their + * prototypes. we fix this here so we can leave them untouched. + */ + +int ffs_mount (void); +int ffs_read (char *buf, int len); +int ffs_dir (char *dirname); +int ffs_embed (int *start_sector, int needed_sectors); + +int vstafs_mount (void); +int vstafs_dir (char *dirname); +int vstafs_read (char *addr, int len); + +int ntfs_mount (void); +int ntfs_dir (char *dirname); +int ntfs_read (char *addr, int len); + +int affs_mount (void); +int affs_dir (char *dirname); +int affs_read (char *addr, int len); + + +#endif /* FS_H */ diff --git a/roms/openbios/fs/grubfs/grubfs_fs.c b/roms/openbios/fs/grubfs/grubfs_fs.c new file mode 100644 index 00000000..acd2a644 --- /dev/null +++ b/roms/openbios/fs/grubfs/grubfs_fs.c @@ -0,0 +1,398 @@ +/* + *	/packages/grubfs-files + * + *	grub vfs + * + *   Copyright (C) 2004 Stefan Reinauer + *   Copyright (C) 2004 Samuel Rydh + *   Copyright (C) 2010 Mark Cave-Ayland + * + *   inspired by HFS code from Samuel Rydh + * + *   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 "filesys.h" +#include "glue.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" + +extern void     grubfs_init( void ); + +/************************************************************************/ +/* 	grub GLOBALS (horrible... but difficult to fix)			*/ +/************************************************************************/ + +/* the grub drivers want these: */ +int		filepos; +int		filemax; +grub_error_t	errnum; +char		FSYS_BUF[FSYS_BUFLEN]; + +/* these are not even used by us, instead + * the grub fs drivers want them: + */ +int		fsmax; +void		(*disk_read_hook) (int, int, int); +void		(*disk_read_func) (int, int, int); + + +/************************************************************************/ +/*	filsystem table							*/ +/************************************************************************/ + +typedef struct fsys_entry { +        const char *name; +	int	(*mount_func) (void); +	int	(*read_func) (char *buf, int len); +	int	(*dir_func) (char *dirname); +	void	(*close_func) (void); +	int	(*embed_func) (int *start_sector, int needed_sectors); +} fsys_entry_t; + +static const struct fsys_entry fsys_table[] = { +# ifdef CONFIG_FSYS_FAT +    {"fat", fat_mount, fat_read, fat_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_EXT2FS +    {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_MINIX +    {"minix", minix_mount, minix_read, minix_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_REISERFS +    {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, NULL, reiserfs_embed}, +# endif +# ifdef CONFIG_FSYS_JFS +    {"jfs", jfs_mount, jfs_read, jfs_dir, NULL, jfs_embed}, +# endif +# ifdef CONFIG_FSYS_XFS +    {"xfs", xfs_mount, xfs_read, xfs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_UFS +    {"ufs", ufs_mount, ufs_read, ufs_dir, NULL, ufs_embed}, +# endif +# ifdef CONFIG_FSYS_ISO9660 +    {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_NTFS +    {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_AFFS +    {"affs", affs_mount, affs_read, affs_dir, NULL, NULL}, +# endif +}; + +/* We don't provide a file search mechanism (yet) */ +typedef struct { +	unsigned long	pos; +	unsigned long	len; +	const char	*path; +} grubfile_t; + +typedef struct { +	const struct fsys_entry *fsys; +	grubfile_t *fd; +	int dev_fd; +	long long offset;	/* Offset added onto each device read; should only ever be non-zero +				when probing a partition for a filesystem */ +} grubfs_t; + +typedef struct { +	grubfs_t *gfs; +} grubfs_info_t; + +/* Static block and global pointer required for I/O glue */ +static grubfs_t dummy_fs; +static grubfs_t *curfs = &dummy_fs; + +DECLARE_NODE( grubfs, 0, sizeof(grubfs_info_t), "+/packages/grubfs-files" ); + + +/************************************************************************/ +/*	I/O glue (called by grub source)				*/ +/************************************************************************/ + +int +devread( unsigned long sector, unsigned long byte_offset, +	 unsigned long byte_len, void *buf ) +{ +	long long offs = (long long)sector * 512 + byte_offset; + +#ifdef CONFIG_DEBUG_FS +	//printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd); +#endif + +	if( !curfs ) { +#ifdef CONFIG_DEBUG_FS +		printk("devread: fsys == NULL!\n"); +#endif +		return -1; +	} + +	if( seek_io(curfs->dev_fd, offs + curfs->offset) ) { +#ifdef CONFIG_DEBUG_FS +		printk("seek failure\n"); +#endif +		return -1; +	} +	return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0; +} + +int +file_read( void *buf, unsigned long len ) +{ +	if (filepos < 0 || filepos > filemax) +		filepos = filemax; +	if (len > filemax-filepos) +		len = filemax - filepos; +	errnum = 0; +	return curfs->fsys->read_func( buf, len ); +} + + +/************************************************************************/ +/*	Standard package methods					*/ +/************************************************************************/ + +/* ( -- success? ) */ +static void +grubfs_files_open( grubfs_info_t *mi ) +{ +	int fd, i; +	char *path = my_args_copy(); +	char *s; + +	fd = open_ih( my_parent() ); +	if ( fd == -1 ) { +		free( path ); +		RET( 0 ); +	} + +	mi->gfs = &dummy_fs; + +	for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) { +#ifdef CONFIG_DEBUG_FS +		printk("Trying %s\n", fsys_table[i].name); +#endif +		if (fsys_table[i].mount_func()) { +			const fsys_entry_t *fsys = &fsys_table[i]; +#ifdef CONFIG_DEBUG_FS +			printk("Mounted %s\n", fsys->name); +#endif +			mi->gfs = malloc(sizeof(grubfs_t)); +			mi->gfs->fsys = fsys; +			mi->gfs->dev_fd = fd; +			mi->gfs->offset = 0; + +			s = path; +			while (*s) { +				if(*s=='\\') *s='/'; +				s++; +			} +#ifdef CONFIG_DEBUG_FS +			printk("Path=%s\n",path); +#endif +			if (!mi->gfs->fsys->dir_func((char *) path)) { +				forth_printf("File not found\n"); +				RET( 0 ); +			} + +			mi->gfs->fd = malloc(sizeof(grubfile_t)); +			mi->gfs->fd->pos = filepos; +			mi->gfs->fd->len = filemax; +			mi->gfs->fd->path = strdup(path); + +			RET( -1 ); +		} +	} +#ifdef CONFIG_DEBUG_FS +	printk("Unknown filesystem type\n"); +#endif + +	RET( 0 ); +} + +/* ( -- ) */ +static void +grubfs_files_close( grubfs_info_t *mi ) +{ +	grubfile_t *gf = mi->gfs->fd; + +	if (gf->path) +		free((void *)(gf->path)); +	free(gf); + +	filepos = 0; +	filemax = 0; +} + +/* ( buf len -- actlen ) */ +static void +grubfs_files_read( grubfs_info_t *mi ) +{ +	int count = POP(); +	char *buf = (char *)cell2pointer(POP()); + +	grubfile_t *file = mi->gfs->fd; +        int ret; + +	filepos = file->pos; +	filemax = file->len; + +	if (count > filemax - filepos) +		count = filemax - filepos; + +	ret = mi->gfs->fsys->read_func(buf, count); + +	file->pos = filepos; + +	RET( ret ); +} + +/* ( pos.d -- status ) */ +static void +grubfs_files_seek( grubfs_info_t *mi ) +{ +	long long pos = DPOP(); +	int offs = (int)pos; +	int whence = SEEK_SET; + +	grubfile_t *file = mi->gfs->fd; +	unsigned long newpos; + +	switch( whence ) { +	case SEEK_END: +		if (offs < 0 && (unsigned long) -offs > file->len) +			newpos = 0; +		else +			newpos = file->len + offs; +		break; +	default: +	case SEEK_SET: +		newpos = (offs < 0) ? 0 : offs; +		break; +	} + +	if (newpos > file->len) +		newpos = file->len; + +	file->pos = newpos; + +	if (newpos) +		RET( -1 ); +	else +		RET( 0 ); +} + +/* ( addr -- size ) */ +static void +grubfs_files_load( grubfs_info_t *mi ) +{ +	char *buf = (char *)cell2pointer(POP()); +	int count, ret; + +	grubfile_t *file = mi->gfs->fd; +	count = file->len; + +	ret = mi->gfs->fsys->read_func(buf, count); +	file->pos = filepos; + +	RET( ret ); +} + +/* ( -- cstr ) */ +static void +grubfs_files_get_path( grubfs_info_t *mi ) +{ +	grubfile_t *file = mi->gfs->fd; +	const char *path = file->path; + +	RET( pointer2cell(strdup(path)) ); +} + +/* ( -- cstr ) */ +static void +grubfs_files_get_fstype( grubfs_info_t *mi ) +{ +	grubfs_t *gfs = mi->gfs; + +	PUSH( pointer2cell(strdup(gfs->fsys->name)) ); +} + + +/* static method, ( pos.d ih -- flag? ) */ +static void +grubfs_files_probe( grubfs_info_t *dummy ) +{ +	ihandle_t ih = POP_ih(); +	long long offs = DPOP(); +	int i; + +	curfs->dev_fd = open_ih(ih); +        if (curfs->dev_fd == -1) { +                RET( -1 ); +        } +	curfs->offset = offs; + +	for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) { +#ifdef CONFIG_DEBUG_FS +		printk("Probing for %s\n", fsys_table[i].name); +#endif +		if (fsys_table[i].mount_func()) { +			RET( -1 ); +		} +	} + +#ifdef CONFIG_DEBUG_FS +	printk("Unknown filesystem type\n"); +#endif + +	close_io(curfs->dev_fd); + +	RET ( 0 ); +} + +/* static method, ( pathstr len ihandle -- ) */ +static void +grubfs_files_dir( grubfs_info_t *dummy ) +{ +	forth_printf("dir method not implemented for grubfs filesystem\n"); +	POP(); +	POP(); +	POP(); +} + +static void +grubfs_initializer( grubfs_info_t *dummy ) +{ +	fword("register-fs-package"); +} + +NODE_METHODS( grubfs ) = { +	{ "probe",	grubfs_files_probe	}, +	{ "open",	grubfs_files_open	}, +	{ "close",	grubfs_files_close 	}, +	{ "read",	grubfs_files_read	}, +	{ "seek",	grubfs_files_seek	}, +	{ "load",	grubfs_files_load	}, +	{ "dir",	grubfs_files_dir	}, + +	/* special */ +	{ "get-path",	grubfs_files_get_path	}, +	{ "get-fstype",	grubfs_files_get_fstype	}, + +	{ NULL,		grubfs_initializer	}, +}; + +void +grubfs_init( void ) +{ +	REGISTER_NODE( grubfs ); +} diff --git a/roms/openbios/fs/grubfs/iso9660.h b/roms/openbios/fs/grubfs/iso9660.h new file mode 100644 index 00000000..6423a8f6 --- /dev/null +++ b/roms/openbios/fs/grubfs/iso9660.h @@ -0,0 +1,167 @@ +/* + *  ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + *  including Rock Ridge Extensions support + * + *  Copyright (C) 1998, 1999  Kousuke Takai  <tak@kmc.kyoto-u.ac.jp> + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ +/* + *  References: + *	linux/fs/isofs/rock.[ch] + *	mkisofs-1.11.1/diag/isoinfo.c + *	mkisofs-1.11.1/iso9660.h + *		(all are written by Eric Youngdale) + */ + +/* + * Modified by SONE Takeshi to work with FILO + */ + +#ifndef _ISO9660_H_ +#define _ISO9660_H_ + +#define ISO_SECTOR_BITS              (11) +#define ISO_SECTOR_SIZE              (1<<ISO_SECTOR_BITS) + +#define	ISO_REGULAR	1	/* regular file	*/ +#define	ISO_DIRECTORY	2	/* directory	*/ +#define	ISO_OTHER	0	/* other file (with Rock Ridge) */ + +#define	RR_FLAG_PX	0x01	/* have POSIX file attributes */ +#define	RR_FLAG_NM	0x08	/* have alternate file name   */ + +/* POSIX file attributes for Rock Ridge extensions */ +#define	POSIX_S_IFMT	0xF000 +#define	POSIX_S_IFREG	0x8000 +#define	POSIX_S_IFDIR	0x4000 + +/* volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +#ifndef ASM_FILE + +typedef	union { +	uint8_t l,b; +}	iso_8bit_t; + +typedef	struct __iso_16bit { +	uint16_t l, b; +} iso_16bit_t; + +typedef	struct __iso_32bit { +	uint32_t l, b; +} iso_32bit_t; + +typedef uint8_t		iso_date_t[7]; + +struct iso_directory_record { +	iso_8bit_t	length; +	iso_8bit_t	ext_attr_length; +	iso_32bit_t	extent; +	iso_32bit_t	size; +	iso_date_t	date; +	iso_8bit_t	flags; +	iso_8bit_t	file_unit_size; +	iso_8bit_t	interleave; +	iso_16bit_t	volume_seq_number; +	iso_8bit_t	name_len; +	uint8_t	name[1]; +} __attribute__ ((packed)); + +struct iso_primary_descriptor { +	iso_8bit_t	type; +	uint8_t		id[5]; +	iso_8bit_t	version; +	uint8_t		_unused1[1]; +	uint8_t		system_id[32]; +	uint8_t		volume_id[32]; +	uint8_t		_unused2[8]; +	iso_32bit_t	volume_space_size; +	uint8_t		_unused3[32]; +	iso_16bit_t	volume_set_size; +	iso_16bit_t	volume_seq_number; +	iso_16bit_t	logical_block_size; +	iso_32bit_t	path_table_size; +	uint8_t		type_l_path_table[4]; +	uint8_t		opt_type_l_path_table[4]; +	uint8_t		type_m_path_table[4]; +	uint8_t		opt_type_m_path_table[4]; +	struct iso_directory_record root_directory_record; +	uint8_t		volume_set_id[128]; +	uint8_t		publisher_id[128]; +	uint8_t		preparer_id[128]; +	uint8_t		application_id[128]; +	uint8_t		copyright_file_id[37]; +	uint8_t		abstract_file_id[37]; +	uint8_t		bibliographic_file_id[37]; +	uint8_t		creation_date[17]; +	uint8_t		modification_date[17]; +	uint8_t		expiration_date[17]; +	uint8_t		effective_date[17]; +	iso_8bit_t	file_structure_version; +	uint8_t		_unused4[1]; +	uint8_t		application_data[512]; +	uint8_t		_unused5[653]; +} __attribute__ ((packed)); + +struct rock_ridge { +	uint16_t	signature; +	uint8_t		len; +	uint8_t		version; +	union { +	  struct CE { +	    iso_32bit_t	extent; +	    iso_32bit_t	offset; +	    iso_32bit_t	size; +	  } ce; +	  struct NM { +	    iso_8bit_t	flags; +	    uint8_t	name[0]; +	  } nm; +	  struct PX { +	    iso_32bit_t	mode; +	    iso_32bit_t	nlink; +	    iso_32bit_t	uid; +	    iso_32bit_t	gid; +	  } px; +	  struct RR { +	    iso_8bit_t	flags; +	  } rr; +	} u; +} __attribute__ ((packed)); + +typedef	union RR_ptr { +	struct rock_ridge *rr; +	char		  *ptr; +	int		   i; +} RR_ptr_t; + +#define CHECK2(ptr, c1, c2)                                             \ +    (*(unsigned char *)(ptr) == (c1) &&                                 \ +     *((unsigned char *)(ptr) + 1) == (c2)) +#define	CHECK4(ptr, c1, c2, c3, c4)                                     \ +    (*(unsigned char *)(ptr) == (c1) &&                                 \ +     *((unsigned char *)(ptr) + 1) == (c2) &&                           \ +     *((unsigned char *)(ptr) + 2) == (c3) &&                           \ +     *((unsigned char *)(ptr) + 3) == (c4)) + +#endif /* !ASM_FILE */ + +#endif /* _ISO9660_H_ */ diff --git a/roms/openbios/fs/grubfs/jfs.h b/roms/openbios/fs/grubfs/jfs.h new file mode 100644 index 00000000..afe7263d --- /dev/null +++ b/roms/openbios/fs/grubfs/jfs.h @@ -0,0 +1,604 @@ +/* jfs.h - an extractions from linux/include/linux/jfs/jfs* into one file */ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2000  International Business Machines  Corp. + *  Copyright (C) 2001  Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY;  without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See + *  the GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program;  if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + +#ifndef _JFS_H_ +#define _JFS_H_ + +/* those are from jfs_filsys.h */ + +/* + *	 file system option (superblock flag) + */ +/* platform option (conditional compilation) */ +#define JFS_AIX		0x80000000	/* AIX support */ +/*	POSIX name/directory  support */ + +#define JFS_OS2		0x40000000	/* OS/2 support */ +/*	case-insensitive name/directory support */ + +#define JFS_LINUX      	0x10000000	/* Linux support */ +/*	case-sensitive name/directory support */ + +/* directory option */ +#define JFS_UNICODE	0x00000001	/* unicode name */ + +/* bba */ +#define	JFS_SWAP_BYTES		0x00100000	/* running on big endian computer */ + + +/* + *	buffer cache configuration + */ +/* page size */ +#ifdef PSIZE +#undef PSIZE +#endif +#define	PSIZE		4096	/* page size (in byte) */ + +/* + *	fs fundamental size + * + * PSIZE >= file system block size >= PBSIZE >= DISIZE + */ +#define	PBSIZE		512	/* physical block size (in byte) */ +#define DISIZE		512	/* on-disk inode size (in byte) */ +#define L2DISIZE	9 +#define	INOSPERIAG	4096	/* number of disk inodes per iag */ +#define	L2INOSPERIAG	12 +#define INOSPEREXT	32	/* number of disk inode per extent */ +#define L2INOSPEREXT	5 + +/* Minimum number of bytes supported for a JFS partition */ +#define MINJFS			(0x1000000) + +/* + * fixed byte offset address + */ +#define SUPER1_OFF	0x8000	/* primary superblock */ + +#define AITBL_OFF	(SUPER1_OFF + PSIZE + (PSIZE << 1)) + +/* + *	fixed reserved inode number + */ +/* aggregate inode */ +#define	AGGREGATE_I	1	/* aggregate inode map inode */ +#define	FILESYSTEM_I	16	/* 1st/only fileset inode in ait: +				 * fileset inode map inode +				 */ + +/* per fileset inode */ +#define	ROOT_I		2	/* fileset root inode */ + +/* + *	directory configuration + */ +#define JFS_NAME_MAX	255 +#define JFS_PATH_MAX	PSIZE + +#if 0 +typedef unsigned char u8; +typedef char s8; +typedef unsigned short u16; +typedef short s16; +typedef unsigned int u32; +typedef int s32; +typedef unsigned long long u64; +typedef long long s64; +#endif + +typedef u16 UniChar; + +/* these from jfs_btree.h */ + +/* btpaget_t flag */ +#define BT_TYPE		0x07	/* B+-tree index */ +#define	BT_ROOT		0x01	/* root page */ +#define	BT_LEAF		0x02	/* leaf page */ +#define	BT_INTERNAL	0x04	/* internal page */ +#define	BT_RIGHTMOST	0x10	/* rightmost page */ +#define	BT_LEFTMOST	0x20	/* leftmost page */ + +/* those are from jfs_types.h */ + +struct timestruc_t { +	u32 tv_sec; +	u32 tv_nsec; +}; + +/* + *	physical xd (pxd) + */ +typedef struct { +	unsigned len:24; +	unsigned addr1:8; +	u32 addr2; +} pxd_t; + +/* xd_t field extraction */ +#define	lengthPXD(pxd)	((pxd)->len) +#define	addressPXD(pxd)	(((s64)((pxd)->addr1)) << 32 | ((pxd)->addr2)) + +/* + *	data extent descriptor (dxd) + */ +typedef struct { +	unsigned flag:8;	/* 1: flags */ +	unsigned rsrvd:24;	/* 3: */ +	u32 size;		/* 4: size in byte */ +	unsigned len:24;	/* 3: length in unit of fsblksize */ +	unsigned addr1:8;	/* 1: address in unit of fsblksize */ +	u32 addr2;		/* 4: address in unit of fsblksize */ +} dxd_t;			/* - 16 - */ + +/* + *	DASD limit information - stored in directory inode + */ +typedef struct dasd { +	u8 thresh;		/* Alert Threshold (in percent) */ +	u8 delta;		/* Alert Threshold delta (in percent)   */ +	u8 rsrvd1; +	u8 limit_hi;		/* DASD limit (in logical blocks)       */ +	u32 limit_lo;		/* DASD limit (in logical blocks)       */ +	u8 rsrvd2[3]; +	u8 used_hi;		/* DASD usage (in logical blocks)       */ +	u32 used_lo;		/* DASD usage (in logical blocks)       */ +} dasd_t; + + +/* from jfs_superblock.h */ + +#define JFS_MAGIC 	0x3153464A	/* "JFS1" */ + +struct jfs_superblock +{ +	u32 s_magic;		/* 4: magic number */ +	u32 s_version;		/* 4: version number */ + +	s64 s_size;		/* 8: aggregate size in hardware/LVM blocks; +				 * VFS: number of blocks +				 */ +	s32 s_bsize;		/* 4: aggregate block size in bytes; +				 * VFS: fragment size +				 */ +	s16 s_l2bsize;		/* 2: log2 of s_bsize */ +	s16 s_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */ +	s32 s_pbsize;		/* 4: hardware/LVM block size in bytes */ +	s16 s_l2pbsize;		/* 2: log2 of s_pbsize */ +	s16 pad;		/* 2: padding necessary for alignment */ + +	u32 s_agsize;		/* 4: allocation group size in aggr. blocks */ + +	u32 s_flag;		/* 4: aggregate attributes: +				 *    see jfs_filsys.h +				 */ +	u32 s_state;		/* 4: mount/unmount/recovery state: +				 *    see jfs_filsys.h +				 */ +	s32 s_compress;		/* 4: > 0 if data compression */ + +	pxd_t s_ait2;		/* 8: first extent of secondary +				 *    aggregate inode table +				 */ + +	pxd_t s_aim2;		/* 8: first extent of secondary +				 *    aggregate inode map +				 */ +	u32 s_logdev;		/* 4: device address of log */ +	s32 s_logserial;	/* 4: log serial number at aggregate mount */ +	pxd_t s_logpxd;		/* 8: inline log extent */ + +	pxd_t s_fsckpxd;	/* 8: inline fsck work space extent */ + +	struct timestruc_t s_time;	/* 8: time last updated */ + +	s32 s_fsckloglen;	/* 4: Number of filesystem blocks reserved for +				 *    the fsck service log. +				 *    N.B. These blocks are divided among the +				 *         versions kept.  This is not a per +				 *         version size. +				 *    N.B. These blocks are included in the +				 *         length field of s_fsckpxd. +				 */ +	s8 s_fscklog;		/* 1: which fsck service log is most recent +				 *    0 => no service log data yet +				 *    1 => the first one +				 *    2 => the 2nd one +				 */ +	char s_fpack[11];	/* 11: file system volume name +				 *     N.B. This must be 11 bytes to +				 *          conform with the OS/2 BootSector +				 *          requirements +				 */ + +	/* extendfs() parameter under s_state & FM_EXTENDFS */ +	s64 s_xsize;		/* 8: extendfs s_size */ +	pxd_t s_xfsckpxd;	/* 8: extendfs fsckpxd */ +	pxd_t s_xlogpxd;	/* 8: extendfs logpxd */ +	/* - 128 byte boundary - */ + +	/* +	 *      DFS VFS support (preliminary) +	 */ +	char s_attach;		/* 1: VFS: flag: set when aggregate is attached +				 */ +	u8 rsrvd4[7];		/* 7: reserved - set to 0 */ + +	u64 totalUsable;	/* 8: VFS: total of 1K blocks which are +				 * available to "normal" (non-root) users. +				 */ +	u64 minFree;		/* 8: VFS: # of 1K blocks held in reserve for +				 * exclusive use of root.  This value can be 0, +				 * and if it is then totalUsable will be equal +				 * to # of blocks in aggregate.  I believe this +				 * means that minFree + totalUsable = # blocks. +				 * In that case, we don't need to store both +				 * totalUsable and minFree since we can compute +				 * one from the other.  I would guess minFree +				 * would be the one we should store, and +				 * totalUsable would be the one we should +				 * compute.  (Just a guess...) +				 */ + +	u64 realFree;		/* 8: VFS: # of free 1K blocks can be used by +				 * "normal" users.  It may be this is something +				 * we should compute when asked for instead of +				 * storing in the superblock.  I don't know how +				 * often this information is needed. +				 */ +	/* +	 *      graffiti area +	 */ +}; + +/* from jfs_dtree.h */ + +/* + *      entry segment/slot + * + * an entry consists of type dependent head/only segment/slot and + * additional segments/slots linked vi next field; + * N.B. last/only segment of entry is terminated by next = -1; + */ +/* + *	directory page slot + */ +typedef struct { +	s8 next;		/* 1: */ +	s8 cnt;			/* 1: */ +	UniChar name[15];	/* 30: */ +} dtslot_t;			/* (32) */ + +#define DTSLOTDATALEN	15 + +/* + *	 internal node entry head/only segment + */ +typedef struct { +	pxd_t xd;		/* 8: child extent descriptor */ + +	s8 next;		/* 1: */ +	u8 namlen;		/* 1: */ +	UniChar name[11];	/* 22: 2-byte aligned */ +} idtentry_t;			/* (32) */ + +/* + *	leaf node entry head/only segment + * + * 	For legacy filesystems, name contains 13 unichars -- no index field + */ +typedef struct { +	u32 inumber;		/* 4: 4-byte aligned */ +	s8 next;		/* 1: */ +	u8 namlen;		/* 1: */ +	UniChar name[11];	/* 22: 2-byte aligned */ +	u32 index;		/* 4: index into dir_table */ +} ldtentry_t;			/* (32) */ + +#define DTLHDRDATALEN	11 + +/* + * dir_table used for directory traversal during readdir +*/ + +/* + * Maximum entry in inline directory table + */ + +typedef struct dir_table_slot { +	u8 rsrvd;	/* 1: */ +	u8 flag;	/* 1: 0 if free */ +	u8 slot;	/* 1: slot within leaf page of entry */ +	u8 addr1;	/* 1: upper 8 bits of leaf page address */ +	u32 addr2;	/* 4: lower 32 bits of leaf page address -OR- +			      index of next entry when this entry was deleted */ +} dir_table_slot_t;	/* (8) */ + +/* + *	directory root page (in-line in on-disk inode): + * + * cf. dtpage_t below. + */ +typedef union { +	struct { +		dasd_t DASD;	/* 16: DASD limit/usage info  F226941 */ + +		u8 flag;	/* 1: */ +		s8 nextindex;	/* 1: next free entry in stbl */ +		s8 freecnt;	/* 1: free count */ +		s8 freelist;	/* 1: freelist header */ + +		u32 idotdot;	/* 4: parent inode number */ + +		s8 stbl[8];	/* 8: sorted entry index table */ +	} header;		/* (32) */ + +	dtslot_t slot[9]; +} dtroot_t; + +/* + *	directory regular page: + * + *	entry slot array of 32 byte slot + * + * sorted entry slot index table (stbl): + * contiguous slots at slot specified by stblindex, + * 1-byte per entry + *   512 byte block:  16 entry tbl (1 slot) + *  1024 byte block:  32 entry tbl (1 slot) + *  2048 byte block:  64 entry tbl (2 slot) + *  4096 byte block: 128 entry tbl (4 slot) + * + * data area: + *   512 byte block:  16 - 2 =  14 slot + *  1024 byte block:  32 - 2 =  30 slot + *  2048 byte block:  64 - 3 =  61 slot + *  4096 byte block: 128 - 5 = 123 slot + * + * N.B. index is 0-based; index fields refer to slot index + * except nextindex which refers to entry index in stbl; + * end of entry stot list or freelist is marked with -1. + */ +typedef union { +	struct { +		s64 next;	/* 8: next sibling */ +		s64 prev;	/* 8: previous sibling */ + +		u8 flag;	/* 1: */ +		s8 nextindex;	/* 1: next entry index in stbl */ +		s8 freecnt;	/* 1: */ +		s8 freelist;	/* 1: slot index of head of freelist */ + +		u8 maxslot;	/* 1: number of slots in page slot[] */ +		s8 stblindex;	/* 1: slot index of start of stbl */ +		u8 rsrvd[2];	/* 2: */ + +		pxd_t self;	/* 8: self pxd */ +	} header;		/* (32) */ + +	dtslot_t slot[128]; +} dtpage_t; + +/* from jfs_xtree.h */ + +/* + *      extent allocation descriptor (xad) + */ +typedef struct xad { +	unsigned flag:8;	/* 1: flag */ +	unsigned rsvrd:16;	/* 2: reserved */ +	unsigned off1:8;	/* 1: offset in unit of fsblksize */ +	u32 off2;		/* 4: offset in unit of fsblksize */ +	unsigned len:24;	/* 3: length in unit of fsblksize */ +	unsigned addr1:8;	/* 1: address in unit of fsblksize */ +	u32 addr2;		/* 4: address in unit of fsblksize */ +} xad_t;			/* (16) */ + +/* xad_t field extraction */ +#define offsetXAD(xad)	(((s64)((xad)->off1)) << 32 | ((xad)->off2)) +#define addressXAD(xad)	(((s64)((xad)->addr1)) << 32 | ((xad)->addr2)) +#define lengthXAD(xad)	((xad)->len) + +/* possible values for maxentry */ +#define XTPAGEMAXSLOT   256 +#define XTENTRYSTART    2 + +/* + *      xtree page: + */ +typedef union { +	struct xtheader { +		s64 next;	/* 8: */ +		s64 prev;	/* 8: */ + +		u8 flag;	/* 1: */ +		u8 rsrvd1;	/* 1: */ +		s16 nextindex;	/* 2: next index = number of entries */ +		s16 maxentry;	/* 2: max number of entries */ +		s16 rsrvd2;	/* 2: */ + +		pxd_t self;	/* 8: self */ +	} header;		/* (32) */ + +	xad_t xad[XTPAGEMAXSLOT];	/* 16 * maxentry: xad array */ +} xtpage_t; + +/* from jfs_dinode.h */ + +struct dinode { +	/* +	 *      I. base area (128 bytes) +	 *      ------------------------ +	 * +	 * define generic/POSIX attributes +	 */ +	u32 di_inostamp;	/* 4: stamp to show inode belongs to fileset */ +	s32 di_fileset;		/* 4: fileset number */ +	u32 di_number;		/* 4: inode number, aka file serial number */ +	u32 di_gen;		/* 4: inode generation number */ + +	pxd_t di_ixpxd;		/* 8: inode extent descriptor */ + +	s64 di_size;		/* 8: size */ +	s64 di_nblocks;		/* 8: number of blocks allocated */ + +	u32 di_nlink;		/* 4: number of links to the object */ + +	u32 di_uid;		/* 4: user id of owner */ +	u32 di_gid;		/* 4: group id of owner */ + +	u32 di_mode;		/* 4: attribute, format and permission */ + +	struct timestruc_t di_atime;	/* 8: time last data accessed */ +	struct timestruc_t di_ctime;	/* 8: time last status changed */ +	struct timestruc_t di_mtime;	/* 8: time last data modified */ +	struct timestruc_t di_otime;	/* 8: time created */ + +	dxd_t di_acl;		/* 16: acl descriptor */ + +	dxd_t di_ea;		/* 16: ea descriptor */ + +	s32 di_next_index;  /* 4: Next available dir_table index */ + +	s32 di_acltype;		/* 4: Type of ACL */ + +	/* +	 * 	Extension Areas. +	 * +	 *	Historically, the inode was partitioned into 4 128-byte areas, +	 *	the last 3 being defined as unions which could have multiple +	 *	uses.  The first 96 bytes had been completely unused until +	 *	an index table was added to the directory.  It is now more +	 *	useful to describe the last 3/4 of the inode as a single +	 *	union.  We would probably be better off redesigning the +	 *	entire structure from scratch, but we don't want to break +	 *	commonality with OS/2's JFS at this time. +	 */ +	union { +		struct { +			/* +			 * This table contains the information needed to +			 * find a directory entry from a 32-bit index. +			 * If the index is small enough, the table is inline, +			 * otherwise, an x-tree root overlays this table +			 */ +			dir_table_slot_t _table[12];	/* 96: inline */ + +			dtroot_t _dtroot;		/* 288: dtree root */ +		} _dir;					/* (384) */ +#define di_dirtable	u._dir._table +#define di_dtroot	u._dir._dtroot +#define di_parent       di_dtroot.header.idotdot +#define di_DASD		di_dtroot.header.DASD + +		struct { +			union { +				u8 _data[96];		/* 96: unused */ +				struct { +					void *_imap;	/* 4: unused */ +					u32 _gengen;	/* 4: generator */ +				} _imap; +			} _u1;				/* 96: */ +#define di_gengen	u._file._u1._imap._gengen + +			union { +				xtpage_t _xtroot; +				struct { +					u8 unused[16];	/* 16: */ +					dxd_t _dxd;	/* 16: */ +					union { +						u32 _rdev;	/* 4: */ +						u8 _fastsymlink[128]; +					} _u; +					u8 _inlineea[128]; +				} _special; +			} _u2; +		} _file; +#define di_xtroot	u._file._u2._xtroot +#define di_dxd		u._file._u2._special._dxd +#define di_btroot	di_xtroot +#define di_inlinedata	u._file._u2._special._u +#define di_rdev		u._file._u2._special._u._rdev +#define di_fastsymlink	u._file._u2._special._u._fastsymlink +#define di_inlineea     u._file._u2._special._inlineea +	} u; +}; + +typedef struct dinode dinode_t; + +/* di_mode */ +#define IFMT	0xF000		/* S_IFMT - mask of file type */ +#define IFDIR	0x4000		/* S_IFDIR - directory */ +#define IFREG	0x8000		/* S_IFREG - regular file */ +#define IFLNK	0xA000		/* S_IFLNK - symbolic link */ + +/* extended mode bits (on-disk inode di_mode) */ +#define INLINEEA        0x00040000	/* inline EA area free */ + +/* from jfs_imap.h */ + +#define	EXTSPERIAG	128	/* number of disk inode extent per iag  */ +#define SMAPSZ		4	/* number of words per summary map      */ +#define	MAXAG		128	/* maximum number of allocation groups  */ + +/* + *	inode allocation map: + * + * inode allocation map consists of + * . the inode map control page and + * . inode allocation group pages (per 4096 inodes) + * which are addressed by standard JFS xtree. + */ +/* + *	inode allocation group page (per 4096 inodes of an AG) + */ +typedef struct { +	s64 agstart;		/* 8: starting block of ag              */ +	s32 iagnum;		/* 4: inode allocation group number     */ +	s32 inofreefwd;		/* 4: ag inode free list forward        */ +	s32 inofreeback;	/* 4: ag inode free list back           */ +	s32 extfreefwd;		/* 4: ag inode extent free list forward */ +	s32 extfreeback;	/* 4: ag inode extent free list back    */ +	s32 iagfree;		/* 4: iag free list                     */ + +	/* summary map: 1 bit per inode extent */ +	s32 inosmap[SMAPSZ];	/* 16: sum map of mapwords w/ free inodes; +				 *      note: this indicates free and backed +				 *      inodes, if the extent is not backed the +				 *      value will be 1.  if the extent is +				 *      backed but all inodes are being used the +				 *      value will be 1.  if the extent is +				 *      backed but at least one of the inodes is +				 *      free the value will be 0. +				 */ +	s32 extsmap[SMAPSZ];	/* 16: sum map of mapwords w/ free extents */ +	s32 nfreeinos;		/* 4: number of free inodes             */ +	s32 nfreeexts;		/* 4: number of free extents            */ +	/* (72) */ +	u8 pad[1976];		/* 1976: pad to 2048 bytes */ +	/* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */ +	u32 wmap[EXTSPERIAG];	/* 512: working allocation map  */ +	u32 pmap[EXTSPERIAG];	/* 512: persistent allocation map */ +	pxd_t inoext[EXTSPERIAG];	/* 1024: inode extent addresses */ +} iag_t;			/* (4096) */ + +#endif /* _JFS_H_ */ diff --git a/roms/openbios/fs/grubfs/shared.h b/roms/openbios/fs/grubfs/shared.h new file mode 100644 index 00000000..b3034e03 --- /dev/null +++ b/roms/openbios/fs/grubfs/shared.h @@ -0,0 +1,3 @@ +/* Sorry, nothing is shared here ;) Just for GRUB compatibility. */ + +#include "glue.h" diff --git a/roms/openbios/fs/grubfs/ufs_dinode.h b/roms/openbios/fs/grubfs/ufs_dinode.h new file mode 100644 index 00000000..f3f7fca0 --- /dev/null +++ b/roms/openbios/fs/grubfs/ufs_dinode.h @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1989, 1993 + *	The Regents of the University of California.  All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + *    products derived from this software without specific prior written + *    permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *	@(#)dinode.h	8.3 (Berkeley) 1/21/94 + * $FreeBSD: src/sys/ufs/ufs/dinode.h,v 1.13.2.1 2005/01/31 23:27:01 imp Exp $ + */ + +#ifndef _UFS_UFS_DINODE_H_ +#define	_UFS_UFS_DINODE_H_ + +/* + * The root inode is the root of the filesystem.  Inode 0 can't be used for + * normal purposes and historically bad blocks were linked to inode 1, thus + * the root inode is 2.  (Inode 1 is no longer used for this purpose, however + * numerous dump tapes make this assumption, so we are stuck with it). + */ +#define	ROOTINO	((ino_t)2) + +/* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file.  It is used as a place holder + * in the directory entry which has been tagged as a DT_W entry. + * See the comments about ROOTINO above. + */ +#define	WINO	((ino_t)1) + +/* + * The size of physical and logical block numbers and time fields in UFS. + */ +typedef	int32_t	ufs1_daddr_t; +typedef	int64_t	ufs2_daddr_t; +typedef int64_t ufs_lbn_t; +typedef int64_t ufs_time_t; + +/* File permissions. */ +#define	IEXEC		0000100		/* Executable. */ +#define	IWRITE		0000200		/* Writeable. */ +#define	IREAD		0000400		/* Readable. */ +#define	ISVTX		0001000		/* Sticky bit. */ +#define	ISGID		0002000		/* Set-gid. */ +#define	ISUID		0004000		/* Set-uid. */ + +/* File types. */ +#define	IFMT		0170000		/* Mask of file type. */ +#define	IFIFO		0010000		/* Named pipe (fifo). */ +#define	IFCHR		0020000		/* Character device. */ +#define	IFDIR		0040000		/* Directory file. */ +#define	IFBLK		0060000		/* Block device. */ +#define	IFREG		0100000		/* Regular file. */ +#define	IFLNK		0120000		/* Symbolic link. */ +#define	IFSOCK		0140000		/* UNIX domain socket. */ +#define	IFWHT		0160000		/* Whiteout. */ + +/* + * A dinode contains all the meta-data associated with a UFS2 file. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ + +#define	NXADDR	2			/* External addresses in inode. */ +#define	NDADDR	12			/* Direct addresses in inode. */ +#define	NIADDR	3			/* Indirect addresses in inode. */ + +struct ufs2_dinode { +	uint16_t	di_mode;	/*   0: IFMT, permissions; see below. */ +	int16_t		di_nlink;	/*   2: File link count. */ +	uint32_t	di_uid;		/*   4: File owner. */ +	uint32_t	di_gid;		/*   8: File group. */ +	uint32_t	di_blksize;	/*  12: Inode blocksize. */ +	uint64_t	di_size;	/*  16: File byte count. */ +	uint64_t	di_blocks;	/*  24: Bytes actually held. */ +	ufs_time_t	di_atime;	/*  32: Last access time. */ +	ufs_time_t	di_mtime;	/*  40: Last modified time. */ +	ufs_time_t	di_ctime;	/*  48: Last inode change time. */ +	ufs_time_t	di_birthtime;	/*  56: Inode creation time. */ +	int32_t		di_mtimensec;	/*  64: Last modified time. */ +	int32_t		di_atimensec;	/*  68: Last access time. */ +	int32_t		di_ctimensec;	/*  72: Last inode change time. */ +	int32_t		di_birthnsec;	/*  76: Inode creation time. */ +	int32_t		di_gen;		/*  80: Generation number. */ +	uint32_t	di_kernflags;	/*  84: Kernel flags. */ +	uint32_t	di_flags;	/*  88: Status flags (chflags). */ +	int32_t		di_extsize;	/*  92: External attributes block. */ +	ufs2_daddr_t	di_extb[NXADDR];/*  96: External attributes block. */ +	ufs2_daddr_t	di_db[NDADDR];	/* 112: Direct disk blocks. */ +	ufs2_daddr_t	di_ib[NIADDR];	/* 208: Indirect disk blocks. */ +	int64_t		di_spare[3];	/* 232: Reserved; currently unused */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define	di_rdev di_db[0] + +/* + * A UFS1 dinode contains all the meta-data associated with a UFS1 file. + * This structure defines the on-disk format of a UFS1 dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ +struct ufs1_dinode { +	uint16_t	di_mode;	/*   0: IFMT, permissions; see below. */ +	int16_t		di_nlink;	/*   2: File link count. */ +	union { +		uint16_t oldids[2];	/*   4: Ffs: old user and group ids. */ +	} di_u; +	uint64_t	di_size;	/*   8: File byte count. */ +	int32_t		di_atime;	/*  16: Last access time. */ +	int32_t		di_atimensec;	/*  20: Last access time. */ +	int32_t		di_mtime;	/*  24: Last modified time. */ +	int32_t		di_mtimensec;	/*  28: Last modified time. */ +	int32_t		di_ctime;	/*  32: Last inode change time. */ +	int32_t		di_ctimensec;	/*  36: Last inode change time. */ +	ufs1_daddr_t	di_db[NDADDR];	/*  40: Direct disk blocks. */ +	ufs1_daddr_t	di_ib[NIADDR];	/*  88: Indirect disk blocks. */ +	uint32_t	di_flags;	/* 100: Status flags (chflags). */ +	int32_t		di_blocks;	/* 104: Blocks actually held. */ +	int32_t		di_gen;		/* 108: Generation number. */ +	uint32_t	di_uid;		/* 112: File owner. */ +	uint32_t	di_gid;		/* 116: File group. */ +	int32_t		di_spare[2];	/* 120: Reserved; currently unused */ +}; +#define	di_ogid		di_u.oldids[1] +#define	di_ouid		di_u.oldids[0] + +#endif /* _UFS_UFS_DINODE_H_ */ diff --git a/roms/openbios/fs/grubfs/ufs_fs.h b/roms/openbios/fs/grubfs/ufs_fs.h new file mode 100644 index 00000000..bd11cc96 --- /dev/null +++ b/roms/openbios/fs/grubfs/ufs_fs.h @@ -0,0 +1,635 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *	@(#)fs.h	8.13 (Berkeley) 3/21/95 + * $FreeBSD: src/sys/ufs/ffs/fs.h,v 1.43.2.3 2005/02/28 16:04:53 delphij Exp $ + */ + +#ifndef _UFS_FFS_FS_H_ +#define _UFS_FFS_FS_H_ + +/* + * Each disk drive contains some number of filesystems. + * A filesystem consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A filesystem is described by its super-block, which in turn + * describes the cylinder groups.  The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss.  This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For filesystem fs, the offsets of the various blocks of interest + * are given in the super block as: + *	[fs->fs_sblkno]		Super-block + *	[fs->fs_cblkno]		Cylinder group block + *	[fs->fs_iblkno]		Inode blocks + *	[fs->fs_dblkno]		Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY	     0 +#define SBLOCK_UFS1	  8192 +#define SBLOCK_UFS2	 65536 +#define SBLOCK_PIGGY	262144 +#define SBLOCKSIZE	  8192 +#define SBLOCKSEARCH \ +	{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } + +/* + * Max number of fragments per block. This value is NOT tweakable. + */ +#define MAXFRAG 	8 + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressable; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks.  To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary.  The filesystem format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided.  The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The filesystem records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE	4096 + +/* + * The path name on which the filesystem is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN	468 + +/* + * The volume name for this filesystem is maintained in fs_volname. + * MAXVOLLEN defines the length of the buffer allocated. + */ +#define MAXVOLLEN	32 + +/* + * There is a 128-byte region in the superblock reserved for in-core + * pointers to summary information. Originally this included an array + * of pointers to blocks of struct csum; now there are just a few + * pointers and the remaining space is padded with fs_ocsp[]. + * + * NOCSPTRS determines the size of this padding. One pointer (fs_csp) + * is taken away to point to a contiguous array of struct csum for + * all cylinder groups; a second (fs_maxcluster) points to an array + * of cluster sizes that is computed as cylinder groups are inspected, + * and the third points to an array that tracks the creation of new + * directories. A fourth pointer, fs_active, is used when creating + * snapshots; it points to a bitmap of cylinder groups for which the + * free-block bitmap has changed since the snapshot operation began. + */ +#define	NOCSPTRS	((128 / sizeof(void *)) - 4) + +/* + * A summary of contiguous blocks of various sizes is maintained + * in each cylinder group. Normally this is set by the initial + * value of fs_maxcontig. To conserve space, a maximum summary size + * is set by FS_MAXCONTIG. + */ +#define FS_MAXCONTIG	16 + +/* + * MINFREE gives the minimum acceptable percentage of filesystem + * blocks which may be free. If the freelist drops below this level + * only the superuser may continue to allocate blocks. This may + * be set to 0 if no reserve of free blocks is deemed necessary, + * however throughput drops by fifty percent if the filesystem + * is run at between 95% and 100% full; thus the minimum default + * value of fs_minfree is 5%. However, to get good clustering + * performance, 10% is a better choice. hence we use 10% as our + * default value. With 10% free space, fragmentation is not a + * problem, so we choose to optimize for time. + */ +#define MINFREE		8 +#define DEFAULTOPT	FS_OPTTIME + +/* + * Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine + * tune the layout preferences for directories within a filesystem. + * His algorithm can be tuned by adjusting the following parameters + * which tell the system the average file size and the average number + * of files per directory. These defaults are well selected for typical + * filesystems, but may need to be tuned for odd cases like filesystems + * being used for squid caches or news spools. + */ +#define AVFILESIZ	16384	/* expected average file size */ +#define AFPDIR		64	/* expected number of files per directory */ + +/* + * The maximum number of snapshot nodes that can be associated + * with each filesystem. This limit affects only the number of + * snapshot files that can be recorded within the superblock so + * that they can be found when the filesystem is mounted. However, + * maintaining too many will slow the filesystem performance, so + * having this limit is a good idea. + */ +#define FSMAXSNAP 20 + +/* + * Used to identify special blocks in snapshots: + * + * BLK_NOCOPY - A block that was unallocated at the time the snapshot + *	was taken, hence does not need to be copied when written. + * BLK_SNAP - A block held by another snapshot that is not needed by this + *	snapshot. When the other snapshot is freed, the BLK_SNAP entries + *	are converted to BLK_NOCOPY. These are needed to allow fsck to + *	identify blocks that are in use by other snapshots (which are + *	expunged from this snapshot). + */ +#define BLK_NOCOPY ((ufs2_daddr_t)(1)) +#define BLK_SNAP ((ufs2_daddr_t)(2)) + +/* + * Sysctl values for the fast filesystem. + */ +#define	FFS_ADJ_REFCNT		 1	/* adjust inode reference count */ +#define	FFS_ADJ_BLKCNT		 2	/* adjust inode used block count */ +#define	FFS_BLK_FREE		 3	/* free range of blocks in map */ +#define	FFS_DIR_FREE		 4	/* free specified dir inodes in map */ +#define	FFS_FILE_FREE		 5	/* free specified file inodes in map */ +#define	FFS_SET_FLAGS		 6	/* set filesystem flags */ +#define	FFS_ADJ_NDIR		 7	/* adjust number of directories */ +#define	FFS_ADJ_NBFREE		 8	/* adjust number of free blocks */ +#define	FFS_ADJ_NIFREE		 9	/* adjust number of free inodes */ +#define	FFS_ADJ_NFFREE		10 	/* adjust number of free frags */ +#define	FFS_ADJ_NUMCLUSTERS	11	/* adjust number of free clusters */ +#define	FFS_MAXID		12	/* number of valid ffs ids */ + +/* + * Command structure passed in to the filesystem to adjust filesystem values. + */ +#define	FFS_CMD_VERSION		0x19790518	/* version ID */ +struct fsck_cmd { +	int32_t	version;	/* version of command structure */ +	int32_t	handle;		/* reference to filesystem to be changed */ +	int64_t	value;		/* inode or block number to be affected */ +	int64_t	size;		/* amount or range to be adjusted */ +	int64_t	spare;		/* reserved for future use */ +}; + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks.  These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + */ +struct csum { +	int32_t	cs_ndir;		/* number of directories */ +	int32_t	cs_nbfree;		/* number of free blocks */ +	int32_t	cs_nifree;		/* number of free inodes */ +	int32_t	cs_nffree;		/* number of free frags */ +}; +struct csum_total { +	int64_t	cs_ndir;		/* number of directories */ +	int64_t	cs_nbfree;		/* number of free blocks */ +	int64_t	cs_nifree;		/* number of free inodes */ +	int64_t	cs_nffree;		/* number of free frags */ +	int64_t	cs_numclusters;		/* number of free clusters */ +	int64_t	cs_spare[3];		/* future expansion */ +}; + +/* + * Super block for an FFS filesystem. + */ +struct fs { +	int32_t	 fs_firstfield;		/* historic filesystem linked list, */ +	int32_t	 fs_unused_1;		/*     used for incore super blocks */ +	int32_t	 fs_sblkno;		/* offset of super-block in filesys */ +	int32_t	 fs_cblkno;		/* offset of cyl-block in filesys */ +	int32_t	 fs_iblkno;		/* offset of inode-blocks in filesys */ +	int32_t	 fs_dblkno;		/* offset of first data after cg */ +	int32_t	 fs_old_cgoffset;	/* cylinder group offset in cylinder */ +	int32_t	 fs_old_cgmask;		/* used to calc mod fs_ntrak */ +	int32_t  fs_old_time;		/* last time written */ +	int32_t	 fs_old_size;		/* number of blocks in fs */ +	int32_t	 fs_old_dsize;		/* number of data blocks in fs */ +	int32_t	 fs_ncg;		/* number of cylinder groups */ +	int32_t	 fs_bsize;		/* size of basic blocks in fs */ +	int32_t	 fs_fsize;		/* size of frag blocks in fs */ +	int32_t	 fs_frag;		/* number of frags in a block in fs */ +/* these are configuration parameters */ +	int32_t	 fs_minfree;		/* minimum percentage of free blocks */ +	int32_t	 fs_old_rotdelay;	/* num of ms for optimal next block */ +	int32_t	 fs_old_rps;		/* disk revolutions per second */ +/* these fields can be computed from the others */ +	int32_t	 fs_bmask;		/* ``blkoff'' calc of blk offsets */ +	int32_t	 fs_fmask;		/* ``fragoff'' calc of frag offsets */ +	int32_t	 fs_bshift;		/* ``lblkno'' calc of logical blkno */ +	int32_t	 fs_fshift;		/* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ +	int32_t	 fs_maxcontig;		/* max number of contiguous blks */ +	int32_t	 fs_maxbpg;		/* max number of blks per cyl group */ +/* these fields can be computed from the others */ +	int32_t	 fs_fragshift;		/* block to frag shift */ +	int32_t	 fs_fsbtodb;		/* fsbtodb and dbtofsb shift constant */ +	int32_t	 fs_sbsize;		/* actual size of super block */ +	int32_t	 fs_spare1[2];		/* old fs_csmask */ +					/* old fs_csshift */ +	int32_t	 fs_nindir;		/* value of NINDIR */ +	int32_t	 fs_inopb;		/* value of INOPB */ +	int32_t	 fs_old_nspf;		/* value of NSPF */ +/* yet another configuration parameter */ +	int32_t	 fs_optim;		/* optimization preference, see below */ +	int32_t	 fs_old_npsect;		/* # sectors/track including spares */ +	int32_t	 fs_old_interleave;	/* hardware sector interleave */ +	int32_t	 fs_old_trackskew;	/* sector 0 skew, per track */ +	int32_t	 fs_id[2];		/* unique filesystem id */ +/* sizes determined by number of cylinder groups and their sizes */ +	int32_t	 fs_old_csaddr;		/* blk addr of cyl grp summary area */ +	int32_t	 fs_cssize;		/* size of cyl grp summary area */ +	int32_t	 fs_cgsize;		/* cylinder group size */ +	int32_t	 fs_spare2;		/* old fs_ntrak */ +	int32_t	 fs_old_nsect;		/* sectors per track */ +	int32_t  fs_old_spc;		/* sectors per cylinder */ +	int32_t	 fs_old_ncyl;		/* cylinders in filesystem */ +	int32_t	 fs_old_cpg;		/* cylinders per group */ +	int32_t	 fs_ipg;		/* inodes per group */ +	int32_t	 fs_fpg;		/* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ +	struct	csum fs_old_cstotal;	/* cylinder summary information */ +/* these fields are cleared at mount time */ +	int8_t   fs_fmod;		/* super block modified flag */ +	int8_t   fs_clean;		/* filesystem is clean flag */ +	int8_t 	 fs_ronly;		/* mounted read-only flag */ +	int8_t   fs_old_flags;		/* old FS_ flags */ +	char	 fs_fsmnt[MAXMNTLEN];	/* name mounted on */ +	char	 fs_volname[MAXVOLLEN];	/* volume name */ +	uint64_t fs_swuid;		/* system-wide uid */ +	int32_t  fs_pad;		/* due to alignment of fs_swuid */ +/* these fields retain the current block allocation info */ +	int32_t	 fs_cgrotor;		/* last cg searched */ +	void 	*fs_ocsp[NOCSPTRS];	/* padding; was list of fs_cs buffers */ +	uint8_t *fs_contigdirs;	/* # of contiguously allocated dirs */ +	struct	csum *fs_csp;		/* cg summary info buffer for fs_cs */ +	int32_t	*fs_maxcluster;		/* max cluster in each cyl group */ +	unsigned int *fs_active;	/* used by snapshots to track fs */ +	int32_t	 fs_old_cpc;		/* cyl per cycle in postbl */ +	int32_t	 fs_maxbsize;		/* maximum blocking factor permitted */ +	int64_t	 fs_sparecon64[17];	/* old rotation block list head */ +	int64_t	 fs_sblockloc;		/* byte offset of standard superblock */ +	struct	csum_total fs_cstotal;	/* cylinder summary information */ +	ufs_time_t fs_time;		/* last time written */ +	int64_t	 fs_size;		/* number of blocks in fs */ +	int64_t	 fs_dsize;		/* number of data blocks in fs */ +	ufs2_daddr_t fs_csaddr;		/* blk addr of cyl grp summary area */ +	int64_t	 fs_pendingblocks;	/* blocks in process of being freed */ +	int32_t	 fs_pendinginodes;	/* inodes in process of being freed */ +	int32_t	 fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ +	int32_t	 fs_avgfilesize;	/* expected average file size */ +	int32_t	 fs_avgfpdir;		/* expected # of files per directory */ +	int32_t	 fs_save_cgsize;	/* save real cg size to use fs_bsize */ +	int32_t	 fs_sparecon32[26];	/* reserved for future constants */ +	int32_t  fs_flags;		/* see FS_ flags below */ +	int32_t	 fs_contigsumsize;	/* size of cluster summary array */ +	int32_t	 fs_maxsymlinklen;	/* max length of an internal symlink */ +	int32_t	 fs_old_inodefmt;	/* format of on-disk inodes */ +	uint64_t fs_maxfilesize;	/* maximum representable file size */ +	int64_t	 fs_qbmask;		/* ~fs_bmask for use with 64-bit size */ +	int64_t	 fs_qfmask;		/* ~fs_fmask for use with 64-bit size */ +	int32_t	 fs_state;		/* validate fs_clean field */ +	int32_t	 fs_old_postblformat;	/* format of positional layout tables */ +	int32_t	 fs_old_nrpos;		/* number of rotational positions */ +	int32_t	 fs_spare5[2];		/* old fs_postbloff */ +					/* old fs_rotbloff */ +	int32_t	 fs_magic;		/* magic number */ +}; + +/* Sanity checking. */ +#ifdef CTASSERT +CTASSERT(sizeof(struct fs) == 1376); +#endif + +/* + * Filesystem identification + */ +#define	FS_UFS1_MAGIC	0x011954	/* UFS1 fast filesystem magic number */ +#define	FS_UFS2_MAGIC	0x19540119	/* UFS2 fast filesystem magic number */ +#define	FS_BAD_MAGIC	0x19960408	/* UFS incomplete newfs magic number */ +#define	FS_OKAY		0x7c269d38	/* superblock checksum */ +#define FS_42INODEFMT	-1		/* 4.2BSD inode format */ +#define FS_44INODEFMT	2		/* 4.4BSD inode format */ + +/* + * Preference for optimization. + */ +#define FS_OPTTIME	0	/* minimize allocation time */ +#define FS_OPTSPACE	1	/* minimize disk fragmentation */ + +/* + * Filesystem flags. + * + * The FS_UNCLEAN flag is set by the kernel when the filesystem was + * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates + * that the filesystem should be managed by the soft updates code. + * Note that the FS_NEEDSFSCK flag is set and cleared only by the + * fsck utility. It is set when background fsck finds an unexpected + * inconsistency which requires a traditional foreground fsck to be + * run. Such inconsistencies should only be found after an uncorrectable + * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when + * it has successfully cleaned up the filesystem. The kernel uses this + * flag to enforce that inconsistent filesystems be mounted read-only. + * The FS_INDEXDIRS flag when set indicates that the kernel maintains + * on-disk auxiliary indexes (such as B-trees) for speeding directory + * accesses. Kernels that do not support auxiliary indicies clear the + * flag to indicate that the indicies need to be rebuilt (by fsck) before + * they can be used. + * + * FS_ACLS indicates that ACLs are administratively enabled for the + * file system, so they should be loaded from extended attributes, + * observed for access control purposes, and be administered by object + * owners.  FS_MULTILABEL indicates that the TrustedBSD MAC Framework + * should attempt to back MAC labels into extended attributes on the + * file system rather than maintain a single mount label for all + * objects. + */ +#define FS_UNCLEAN    0x01	/* filesystem not clean at mount */ +#define FS_DOSOFTDEP  0x02	/* filesystem using soft dependencies */ +#define FS_NEEDSFSCK  0x04	/* filesystem needs sync fsck before mount */ +#define FS_INDEXDIRS  0x08	/* kernel supports indexed directories */ +#define FS_ACLS       0x10	/* file system has ACLs enabled */ +#define FS_MULTILABEL 0x20	/* file system is MAC multi-label */ +#define FS_FLAGS_UPDATED 0x80	/* flags have been moved to new location */ + +/* + * Macros to access bits in the fs_active array. + */ +#define	ACTIVECGNUM(fs, cg)	((fs)->fs_active[(cg) / (NBBY * sizeof(int))]) +#define	ACTIVECGOFF(cg)		(1 << ((cg) % (NBBY * sizeof(int)))) + +/* + * The size of a cylinder group is calculated by CGSIZE. The maximum size + * is limited by the fact that cylinder groups are at most one block. + * Its size is derived from the size of the maps maintained in the + * cylinder group and the (struct cg) size. + */ +#define CGSIZE(fs) \ +    /* base cg */	(sizeof(struct cg) + sizeof(int32_t) + \ +    /* old btotoff */	(fs)->fs_old_cpg * sizeof(int32_t) + \ +    /* old boff */	(fs)->fs_old_cpg * sizeof(uint16_t) + \ +    /* inode map */	howmany((fs)->fs_ipg, NBBY) + \ +    /* block map */	howmany((fs)->fs_fpg, NBBY) +\ +    /* if present */	((fs)->fs_contigsumsize <= 0 ? 0 : \ +    /* cluster sum */	(fs)->fs_contigsumsize * sizeof(int32_t) + \ +    /* cluster map */	howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) + +/* + * The minimal number of cylinder groups that should be created. + */ +#define MINCYLGRPS	4 + +/* + * Convert cylinder group to base address of its global summary info. + */ +#define fs_cs(fs, indx) fs_csp[indx] + +/* + * Cylinder group block for a filesystem. + */ +#define	CG_MAGIC	0x090255 +struct cg { +	int32_t	 cg_firstfield;		/* historic cyl groups linked list */ +	int32_t	 cg_magic;		/* magic number */ +	int32_t  cg_old_time;		/* time last written */ +	int32_t	 cg_cgx;		/* we are the cgx'th cylinder group */ +	int16_t	 cg_old_ncyl;		/* number of cyl's this cg */ +	int16_t  cg_old_niblk;		/* number of inode blocks this cg */ +	int32_t	 cg_ndblk;		/* number of data blocks this cg */ +	struct	csum cg_cs;		/* cylinder summary information */ +	int32_t	 cg_rotor;		/* position of last used block */ +	int32_t	 cg_frotor;		/* position of last used frag */ +	int32_t	 cg_irotor;		/* position of last used inode */ +	int32_t	 cg_frsum[MAXFRAG];	/* counts of available frags */ +	int32_t	 cg_old_btotoff;	/* (int32) block totals per cylinder */ +	int32_t	 cg_old_boff;		/* (uint16) free block positions */ +	int32_t	 cg_iusedoff;		/* (uint8) used inode map */ +	int32_t	 cg_freeoff;		/* (uint8) free block map */ +	int32_t	 cg_nextfreeoff;	/* (uint8) next available space */ +	int32_t	 cg_clustersumoff;	/* (uint32) counts of avail clusters */ +	int32_t	 cg_clusteroff;		/* (uint8) free cluster map */ +	int32_t	 cg_nclusterblks;	/* number of clusters this cg */ +	int32_t  cg_niblk;		/* number of inode blocks this cg */ +	int32_t	 cg_initediblk;		/* last initialized inode */ +	int32_t	 cg_sparecon32[3];	/* reserved for future use */ +	ufs_time_t cg_time;		/* time last written */ +	int64_t	 cg_sparecon64[3];	/* reserved for future use */ +	uint8_t cg_space[1];		/* space for cylinder group maps */ +/* actually longer */ +}; + +/* + * Macros for access to cylinder group array structures + */ +#define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) +#define cg_inosused(cgp) \ +    ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_iusedoff)) +#define cg_blksfree(cgp) \ +    ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_freeoff)) +#define cg_clustersfree(cgp) \ +    ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_clusteroff)) +#define cg_clustersum(cgp) \ +    ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff)) + +/* + * Turn filesystem block numbers into disk block addresses. + * This maps filesystem blocks to device size blocks. + */ +#define fsbtodb(fs, b)	((b) << (fs)->fs_fsbtodb) +#define	dbtofsb(fs, b)	((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc filesystem addresses of cylinder group data structures. + */ +#define	cgbase(fs, c)	(((ufs2_daddr_t)(fs)->fs_fpg) * (c)) +#define	cgdmin(fs, c)	(cgstart(fs, c) + (fs)->fs_dblkno)	/* 1st data */ +#define	cgimin(fs, c)	(cgstart(fs, c) + (fs)->fs_iblkno)	/* inode blk */ +#define	cgsblock(fs, c)	(cgstart(fs, c) + (fs)->fs_sblkno)	/* super blk */ +#define	cgtod(fs, c)	(cgstart(fs, c) + (fs)->fs_cblkno)	/* cg block */ +#define cgstart(fs, c)							\ +       ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) :		\ +       (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) + +/* + * Macros for handling inode numbers: + *     inode number to filesystem block offset. + *     inode number to cylinder group number. + *     inode number to filesystem block address. + */ +#define	ino_to_cg(fs, x)	((x) / (fs)->fs_ipg) +#define	ino_to_fsba(fs, x)						\ +	((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) +			\ +	    (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) +#define	ino_to_fsbo(fs, x)	((x) % INOPB(fs)) + +/* + * Give cylinder group number for a filesystem block. + * Give cylinder group block number for a filesystem block. + */ +#define	dtog(fs, d)	((d) / (fs)->fs_fpg) +#define	dtogd(fs, d)	((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ +    (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc)		/* calculates (loc % fs->fs_bsize) */ \ +	((loc) & (fs)->fs_qbmask) +#define fragoff(fs, loc)	/* calculates (loc % fs->fs_fsize) */ \ +	((loc) & (fs)->fs_qfmask) +#define lfragtosize(fs, frag)	/* calculates ((off_t)frag * fs->fs_fsize) */ \ +	(((off_t)(frag)) << (fs)->fs_fshift) +#define lblktosize(fs, blk)	/* calculates ((off_t)blk * fs->fs_bsize) */ \ +	(((off_t)(blk)) << (fs)->fs_bshift) +/* Use this only when `blk' is known to be small, e.g., < NDADDR. */ +#define smalllblktosize(fs, blk)    /* calculates (blk * fs->fs_bsize) */ \ +	((blk) << (fs)->fs_bshift) +#define lblkno(fs, loc)		/* calculates (loc / fs->fs_bsize) */ \ +	((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc)	/* calculates (loc / fs->fs_fsize) */ \ +	((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size)	/* calculates roundup(size, fs->fs_bsize) */ \ +	(((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) +#define fragroundup(fs, size)	/* calculates roundup(size, fs->fs_fsize) */ \ +	(((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) +#define fragstoblks(fs, frags)	/* calculates (frags / fs->fs_frag) */ \ +	((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks)	/* calculates (blks * fs->fs_frag) */ \ +	((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb)	/* calculates (fsb % fs->fs_frag) */ \ +	((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb)		/* calculates rounddown(fsb, fs->fs_frag) */ \ +	((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve. + */ +#define freespace(fs, percentreserved) \ +	(blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ +	(fs)->fs_cstotal.cs_nffree - \ +	(((off_t)((fs)->fs_dsize)) * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the filesystem. + */ +#define blksize(fs, ip, lbn) \ +	(((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ +	    ? (fs)->fs_bsize \ +	    : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define sblksize(fs, size, lbn) \ +	(((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ +	  ? (fs)->fs_bsize \ +	  : (fragroundup(fs, blkoff(fs, (size))))) + + +/* + * Number of inodes in a secondary storage block/fragment. + */ +#define	INOPB(fs)	((fs)->fs_inopb) +#define	INOPF(fs)	((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * Number of indirects in a filesystem block. + */ +#define	NINDIR(fs)	((fs)->fs_nindir) + +extern int inside[], around[]; +extern char *fragtbl[]; + +struct ufs_dirent { +	uint32_t d_fileno;		/* file number of entry */ +	uint16_t d_reclen;		/* length of this record */ +	uint8_t  d_type; 		/* file type, see below */ +	uint8_t  d_namlen;		/* length of string in d_name */ +#define	MAXNAMLEN	255 +	char	d_name[MAXNAMLEN + 1];	/* name must be no longer than this */ +}; + +/* + * File types + */ +#define	DT_UNKNOWN	 0 +#define	DT_FIFO		 1 +#define	DT_CHR		 2 +#define	DT_DIR		 4 +#define	DT_BLK		 6 +#define	DT_REG		 8 +#define	DT_LNK		10 +#define	DT_SOCK		12 +#define	DT_WHT		14 + +/* XXX: We hardcode BSIZE and BSIZE_SHIFT here. fsys_ffs seems to do the same, + *      so we should get away with it :-) */ +#define DEV_BSIZE	512 +#define DEV_BSHIFT 	9		/* 2**9 = 512 */ +#define MAXBSIZE	8192 + +typedef unsigned int ino_t; + +#endif diff --git a/roms/openbios/fs/grubfs/vstafs.h b/roms/openbios/fs/grubfs/vstafs.h new file mode 100644 index 00000000..f240ffc4 --- /dev/null +++ b/roms/openbios/fs/grubfs/vstafs.h @@ -0,0 +1,89 @@ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2001   Free Software Foundation, Inc. + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + *  MA 02110-1301, USA. + */ + + +#ifndef VSTAFS_H +#define VSTAFS_H	1 + + +#define LINE			16 +#define BLOCK_SIZE		512 +#define VSTAFS_START_DATA	320 + +struct bootrecord +{ +  unsigned char flag; +  unsigned char s_sector; +  unsigned char s_head; +  unsigned char s_cylinder; +  unsigned char p_type; +  unsigned char e_sector; +  unsigned char e_head; +  unsigned char e_cylinder; +  unsigned long start_lba; +  unsigned long nr_sector_lba; +}; + +struct alloc +{ +  unsigned long a_start; +  unsigned long a_len; +}; + +struct first_sector +{ +  unsigned long fs_magic; +  unsigned long fs_size; +  unsigned long fs_extsize; +  unsigned long fs_free; +  struct  alloc fs_freesecs[0]; +}; + +struct prot +{ +  unsigned char len; +  unsigned char pdefault; +  unsigned char id[7]; +  unsigned char bits[7]; +}; + +struct fs_file +{ +  unsigned long prev; +  unsigned long rev; +  unsigned long len; +  unsigned short type; +  unsigned short nlink; +  struct prot pprot; +  unsigned int owner; +  unsigned int extents; +  struct alloc blocks[32]; +  long fs_ctime, fs_mtime; /* it is not lon but time_t */ +  char pad[16]; +  char data[0]; +}; + +struct dir_entry +{ +  char name[28]; +  unsigned long start; +}; + +#endif /* ! VSTAFS_H */ diff --git a/roms/openbios/fs/grubfs/xfs.h b/roms/openbios/fs/grubfs/xfs.h new file mode 100644 index 00000000..0ed07042 --- /dev/null +++ b/roms/openbios/fs/grubfs/xfs.h @@ -0,0 +1,546 @@ +/* xfs.h - an extraction from xfsprogs-1.3.5/include/xfs* into one file */ +/* + *  GRUB  --  GRand Unified Bootloader + *  Copyright (C) 2000  Silicon Graphics, Inc.  All Rights Reserved. + *  Copyright (C) 2001  Free Software Foundation, Inc. + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of version 2 of the GNU General Public License as + *  published by the Free Software Foundation. + * + *  This program is distributed in the hope that it would be useful, but + *  WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + *  Further, this software is distributed without any warranty that it is + *  free of the rightful claim of any third person regarding infringement + *  or the like.  Any license provided herein, whether implied or + *  otherwise, applies only to this software file.  Patent licenses, if + *  any, provided herein do not apply to combinations of this program with + *  other software, or any other product whatsoever. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write the Free Software Foundation, Inc., + *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + *  Mountain View, CA  94043, or: + * + *  http://www.sgi.com + * + *  For further information regarding this notice, see: + * + *  http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _BITS_TYPES_H +typedef signed char	__int8_t; +typedef unsigned char	__uint8_t; +typedef short		__int16_t; +typedef unsigned short	__uint16_t; +typedef int		__int32_t; +typedef unsigned int	__uint32_t; +typedef long long	__int64_t; +typedef unsigned long long __uint64_t; +#endif + +typedef __uint64_t	xfs_ino_t; +typedef	__uint32_t	xfs_agino_t; +typedef __int64_t	xfs_daddr_t; +typedef __int64_t	xfs_off_t; +typedef __uint8_t	uuid_t[16]; + + +/* those are from xfs_types.h */ + +typedef __uint32_t	xfs_agblock_t;	/* blockno in alloc. group */ +typedef	__uint32_t	xfs_extlen_t;	/* extent length in blocks */ +typedef	__uint32_t	xfs_agnumber_t;	/* allocation group number */ +typedef __int32_t	xfs_extnum_t;	/* # of extents in a file */ +typedef __int16_t	xfs_aextnum_t;	/* # extents in an attribute fork */ +typedef	__int64_t	xfs_fsize_t;	/* bytes in a file */ + +typedef	__uint32_t	xfs_dablk_t;	/* dir/attr block number (in file) */ +typedef	__uint32_t	xfs_dahash_t;	/* dir/attr hash value */ + +/* + * Disk based types: + */ +typedef __uint64_t	xfs_dfsbno_t;	/* blockno in filesystem (agno|agbno) */ +typedef __uint64_t	xfs_drfsbno_t;	/* blockno in filesystem (raw) */ +typedef	__uint64_t	xfs_drtbno_t;	/* extent (block) in realtime area */ +typedef	__uint64_t	xfs_dfiloff_t;	/* block number in a file */ + +typedef	__uint64_t	xfs_fsblock_t;	/* blockno in filesystem (agno|agbno) */ +typedef	__uint64_t	xfs_fileoff_t;	/* block number in a file */ +typedef	__uint64_t	xfs_filblks_t;	/* number of blocks in a file */ + + +/* those are from xfs_sb.h */ + +#define	XFS_SB_MAGIC		0x58465342	/* 'XFSB'*/ +#define	XFS_SB_VERSION_4	4		/* 6.2+ - bitmask version */ +#define	XFS_SB_VERSION_NUMBITS	0x000f + +typedef struct xfs_sb +{ +	__uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */ +	__uint32_t	sb_blocksize;	/* logical block size, bytes */ +	xfs_drfsbno_t	sb_dblocks;	/* number of data blocks */ +	xfs_drfsbno_t	sb_rblocks;	/* number of realtime blocks */ +	xfs_drtbno_t	sb_rextents;	/* number of realtime extents */ +	uuid_t		sb_uuid;	/* file system unique id */ +	xfs_dfsbno_t	sb_logstart;	/* starting block of log if internal */ +	xfs_ino_t	sb_rootino;	/* root inode number */ +	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */ +	xfs_ino_t	sb_rsumino;	/* summary inode for rt bitmap */ +	xfs_agblock_t	sb_rextsize;	/* realtime extent size, blocks */ +	xfs_agblock_t	sb_agblocks;	/* size of an allocation group */ +	xfs_agnumber_t	sb_agcount;	/* number of allocation groups */ +	xfs_extlen_t	sb_rbmblocks;	/* number of rt bitmap blocks */ +	xfs_extlen_t	sb_logblocks;	/* number of log blocks */ +	__uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */ +	__uint16_t	sb_sectsize;	/* volume sector size, bytes */ +	__uint16_t	sb_inodesize;	/* inode size, bytes */ +	__uint16_t	sb_inopblock;	/* inodes per block */ +	char		sb_fname[12];	/* file system name */ +	__uint8_t	sb_blocklog;	/* log2 of sb_blocksize */ +	__uint8_t	sb_sectlog;	/* log2 of sb_sectsize */ +	__uint8_t	sb_inodelog;	/* log2 of sb_inodesize */ +	__uint8_t	sb_inopblog;	/* log2 of sb_inopblock */ +	__uint8_t	sb_agblklog;	/* log2 of sb_agblocks (rounded up) */ +	__uint8_t	sb_rextslog;	/* log2 of sb_rextents */ +	__uint8_t	sb_inprogress;	/* mkfs is in progress, don't mount */ +	__uint8_t	sb_imax_pct;	/* max % of fs for inode space */ +					/* statistics */ +	/* +	 * These fields must remain contiguous.  If you really +	 * want to change their layout, make sure you fix the +	 * code in xfs_trans_apply_sb_deltas(). +	 */ +	__uint64_t	sb_icount;	/* allocated inodes */ +	__uint64_t	sb_ifree;	/* free inodes */ +	__uint64_t	sb_fdblocks;	/* free data blocks */ +	__uint64_t	sb_frextents;	/* free realtime extents */ +	/* +	 * End contiguous fields. +	 */ +	xfs_ino_t	sb_uquotino;	/* user quota inode */ +	xfs_ino_t	sb_gquotino;	/* group quota inode */ +	__uint16_t	sb_qflags;	/* quota flags */ +	__uint8_t	sb_flags;	/* misc. flags */ +	__uint8_t	sb_shared_vn;	/* shared version number */ +	xfs_extlen_t	sb_inoalignmt;	/* inode chunk alignment, fsblocks */ +	__uint32_t	sb_unit;	/* stripe or raid unit */ +	__uint32_t	sb_width;	/* stripe or raid width */ +	__uint8_t	sb_dirblklog;	/* log2 of dir block size (fsbs) */ +        __uint8_t       sb_dummy[7];    /* padding */ +} xfs_sb_t; + + +/* those are from xfs_btree.h */ + +/* + * Long form header: bmap btrees. + */ +typedef struct xfs_btree_lblock +{ +	__uint32_t	bb_magic;	/* magic number for block type */ +	__uint16_t	bb_level;	/* 0 is a leaf */ +	__uint16_t	bb_numrecs;	/* current # of data records */ +	xfs_dfsbno_t	bb_leftsib;	/* left sibling block or NULLDFSBNO */ +	xfs_dfsbno_t	bb_rightsib;	/* right sibling block or NULLDFSBNO */ +} xfs_btree_lblock_t; + +/* + * Combined header and structure, used by common code. + */ +typedef struct xfs_btree_hdr +{ +	__uint32_t	bb_magic;	/* magic number for block type */ +	__uint16_t	bb_level;	/* 0 is a leaf */ +	__uint16_t	bb_numrecs;	/* current # of data records */ +} xfs_btree_hdr_t; + +typedef struct xfs_btree_block +{ +	xfs_btree_hdr_t	bb_h;		/* header */ +	union		{ +		struct	{ +			xfs_agblock_t	bb_leftsib; +			xfs_agblock_t	bb_rightsib; +		}	s;		/* short form pointers */ +		struct	{ +			xfs_dfsbno_t	bb_leftsib; +			xfs_dfsbno_t	bb_rightsib; +		}	l;		/* long form pointers */ +	}		bb_u;		/* rest */ +} xfs_btree_block_t; + +/* those are from xfs_bmap_btree.h */ + +/* + * Bmap root header, on-disk form only. + */ +typedef struct xfs_bmdr_block +{ +	__uint16_t	bb_level;	/* 0 is a leaf */ +	__uint16_t	bb_numrecs;	/* current # of data records */ +} xfs_bmdr_block_t; + +/* + * Bmap btree record and extent descriptor. + * For 32-bit kernels, + *  l0:31 is an extent flag (value 1 indicates non-normal). + *  l0:0-30 and l1:9-31 are startoff. + *  l1:0-8, l2:0-31, and l3:21-31 are startblock. + *  l3:0-20 are blockcount. + * For 64-bit kernels, + *  l0:63 is an extent flag (value 1 indicates non-normal). + *  l0:9-62 are startoff. + *  l0:0-8 and l1:21-63 are startblock. + *  l1:0-20 are blockcount. + */ + +#define	BMBT_USE_64	1 + +typedef struct xfs_bmbt_rec_32 +{ +	__uint32_t		l0, l1, l2, l3; +} xfs_bmbt_rec_32_t; +typedef struct xfs_bmbt_rec_64 +{ +	__uint64_t		l0, l1; +} xfs_bmbt_rec_64_t; + +#if BMBT_USE_64 +typedef	__uint64_t	xfs_bmbt_rec_base_t;	/* use this for casts */ +typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#else	/* !BMBT_USE_64 */ +typedef	__uint32_t	xfs_bmbt_rec_base_t;	/* use this for casts */ +typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#endif	/* BMBT_USE_64 */ + +/* + * Key structure for non-leaf levels of the tree. + */ +typedef struct xfs_bmbt_key +{ +	xfs_dfiloff_t	br_startoff;	/* starting file offset */ +} xfs_bmbt_key_t, xfs_bmdr_key_t; + +typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;	/* btree pointer type */ +					/* btree block header type */ +typedef	struct xfs_btree_lblock xfs_bmbt_block_t; + + +/* those are from xfs_dir2.h */ +/* + * Directory version 2. + * There are 4 possible formats: + *	shortform + *	single block - data with embedded leaf at the end + *	multiple data blocks, single leaf+freeindex block + *	data blocks, node&leaf blocks (btree), freeindex blocks + * + *	The shortform format is in xfs_dir2_sf.h. + *	The single block format is in xfs_dir2_block.h. + *	The data block format is in xfs_dir2_data.h. + *	The leaf and freeindex block formats are in xfs_dir2_leaf.h. + *	Node blocks are the same as the other version, in xfs_da_btree.h. + */ + +/* + * Byte offset in data block and shortform entry. + */ +typedef	__uint16_t	xfs_dir2_data_off_t; + +/* + * Byte offset in a directory. + */ +typedef	xfs_off_t		xfs_dir2_off_t; + +/* those are from xfs_da_btree.h */ +/*======================================================================== + * Directory Structure when greater than XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This structure is common to both leaf nodes and non-leaf nodes in the Btree. + * + * Is is used to manage a doubly linked list of all blocks at the same + * level in the Btree, and to identify which type of block this is. + */ +#define	XFS_DIR2_LEAF1_MAGIC	0xd2f1	/* magic number: v2 dirlf single blks */ +#define	XFS_DIR2_LEAFN_MAGIC	0xd2ff	/* magic number: v2 dirlf multi blks */ + +typedef struct xfs_da_blkinfo { +	xfs_dablk_t forw;			/* previous block in list */ +	xfs_dablk_t back;			/* following block in list */ +	__uint16_t magic;			/* validity check on block */ +	__uint16_t pad;				/* unused */ +} xfs_da_blkinfo_t; + +/* + * This is the structure of the root and intermediate nodes in the Btree. + * The leaf nodes are defined above. + * + * Entries are not packed. + * + * Since we have duplicate keys, use a binary search but always follow + * all match in the block, not just the first match found. + */ + +typedef struct xfs_da_intnode { +	struct xfs_da_node_hdr {	/* constant-structure header block */ +		xfs_da_blkinfo_t info;	/* block type, links, etc. */ +		__uint16_t count;	/* count of active entries */ +		__uint16_t level;	/* level above leaves (leaf == 0) */ +	} hdr; +	struct xfs_da_node_entry { +		xfs_dahash_t hashval;	/* hash value for this descendant */ +		xfs_dablk_t before;	/* Btree block before this key */ +	} btree[1];			/* variable sized array of keys */ +} xfs_da_intnode_t; + + +/* those are from xfs_dir2_data.h */ +/* + * Directory format 2, data block structures. + */ + +/* + * Constants. + */ +#define	XFS_DIR2_DATA_FREE_TAG	0xffff +#define	XFS_DIR2_DATA_FD_COUNT	3 + +/* + * Structures. + */ + +/* + * Describe a free area in the data block. + * The freespace will be formatted as a xfs_dir2_data_unused_t. + */ +typedef struct xfs_dir2_data_free { +	xfs_dir2_data_off_t	offset;		/* start of freespace */ +	xfs_dir2_data_off_t	length;		/* length of freespace */ +} xfs_dir2_data_free_t; + +/* + * Header for the data blocks. + * Always at the beginning of a directory-sized block. + * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. + */ +typedef struct xfs_dir2_data_hdr { +	__uint32_t		magic;		/* XFS_DIR2_DATA_MAGIC */ +						/* or XFS_DIR2_BLOCK_MAGIC */ +	xfs_dir2_data_free_t	bestfree[XFS_DIR2_DATA_FD_COUNT]; +} xfs_dir2_data_hdr_t; + +/* + * Active entry in a data block.  Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_entry { +	xfs_ino_t		inumber;	/* inode number */ +	__uint8_t		namelen;	/* name length */ +	__uint8_t		name[1];	/* name bytes, no null */ +						/* variable offset */ +	xfs_dir2_data_off_t	tag;		/* starting offset of us */ +} xfs_dir2_data_entry_t; + +/* + * Unused entry in a data block.  Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_unused { +	__uint16_t		freetag;	/* XFS_DIR2_DATA_FREE_TAG */ +	xfs_dir2_data_off_t	length;		/* total free length */ +						/* variable offset */ +	xfs_dir2_data_off_t	tag;		/* starting offset of us */ +} xfs_dir2_data_unused_t; + +typedef union { +	xfs_dir2_data_entry_t	entry; +	xfs_dir2_data_unused_t	unused; +} xfs_dir2_data_union_t; + + +/* those are from xfs_dir2_leaf.h */ +/* + * Directory version 2, leaf block structures. + */ + +/* + * Leaf block header. + */ +typedef struct xfs_dir2_leaf_hdr { +	xfs_da_blkinfo_t	info;		/* header for da routines */ +	__uint16_t		count;		/* count of entries */ +	__uint16_t		stale;		/* count of stale entries */ +} xfs_dir2_leaf_hdr_t; + + +/* those are from xfs_dir2_block.h */ +/* + * xfs_dir2_block.h + * Directory version 2, single block format structures + */ + +/* + * The single block format is as follows: + * xfs_dir2_data_hdr_t structure + * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures + * xfs_dir2_leaf_entry_t structures + * xfs_dir2_block_tail_t structure + */ + +#define	XFS_DIR2_BLOCK_MAGIC	0x58443242	/* XD2B: for one block dirs */ + +typedef struct xfs_dir2_block_tail { +	__uint32_t	count;			/* count of leaf entries */ +	__uint32_t	stale;			/* count of stale lf entries */ +} xfs_dir2_block_tail_t; + + +/* those are from xfs_dir2_sf.h */ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +/* + * Inode number stored as 8 8-bit values. + */ +typedef	struct { __uint8_t i[8]; } xfs_dir2_ino8_t; + +/* + * Inode number stored as 4 8-bit values. + * Works a lot of the time, when all the inode numbers in a directory + * fit in 32 bits. + */ +typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; + +typedef union { +	xfs_dir2_ino8_t	i8; +	xfs_dir2_ino4_t	i4; +} xfs_dir2_inou_t; + +/* + * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. + * Only need 16 bits, this is the byte offset into the single block form. + */ +typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tightly as possible.  The header + * and the elements must be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir2_sf_hdr { +	__uint8_t		count;		/* count of entries */ +	__uint8_t		i8count;	/* count of 8-byte inode #s */ +	xfs_dir2_inou_t		parent;		/* parent dir inode number */ +} xfs_dir2_sf_hdr_t; + +typedef struct xfs_dir2_sf_entry { +	__uint8_t		namelen;	/* actual name length */ +	xfs_dir2_sf_off_t	offset;		/* saved offset */ +	__uint8_t		name[1];	/* name, variable size */ +	xfs_dir2_inou_t		inumber;	/* inode number, var. offset */ +} xfs_dir2_sf_entry_t; + +typedef struct xfs_dir2_sf { +	xfs_dir2_sf_hdr_t	hdr;		/* shortform header */ +	xfs_dir2_sf_entry_t	list[1];	/* shortform entries */ +} xfs_dir2_sf_t; + +/* those are from xfs_dinode.h */ + +#define	XFS_DINODE_VERSION_1	1 +#define	XFS_DINODE_VERSION_2	2 +#define	XFS_DINODE_MAGIC	0x494e	/* 'IN' */ + +/* + * Disk inode structure. + * This is just the header; the inode is expanded to fill a variable size + * with the last field expanding.  It is split into the core and "other" + * because we only need the core part in the in-core inode. + */ +typedef struct xfs_timestamp { +	__int32_t	t_sec;		/* timestamp seconds */ +	__int32_t	t_nsec;		/* timestamp nanoseconds */ +} xfs_timestamp_t; + +/* + * Note: Coordinate changes to this structure with the XFS_DI_* #defines + * below and the offsets table in xfs_ialloc_log_di(). + */ +typedef struct xfs_dinode_core +{ +	__uint16_t	di_magic;	/* inode magic # = XFS_DINODE_MAGIC */ +	__uint16_t	di_mode;	/* mode and type of file */ +	__int8_t	di_version;	/* inode version */ +	__int8_t	di_format;	/* format of di_c data */ +	__uint16_t	di_onlink;	/* old number of links to file */ +	__uint32_t	di_uid;		/* owner's user id */ +	__uint32_t	di_gid;		/* owner's group id */ +	__uint32_t	di_nlink;	/* number of links to file */ +	__uint16_t	di_projid;	/* owner's project id */ +	__uint8_t	di_pad[10];	/* unused, zeroed space */ +	xfs_timestamp_t	di_atime;	/* time last accessed */ +	xfs_timestamp_t	di_mtime;	/* time last modified */ +	xfs_timestamp_t	di_ctime;	/* time created/inode modified */ +	xfs_fsize_t	di_size;	/* number of bytes in file */ +	xfs_drfsbno_t	di_nblocks;	/* # of direct & btree blocks used */ +	xfs_extlen_t	di_extsize;	/* basic/minimum extent size for file */ +	xfs_extnum_t	di_nextents;	/* number of extents in data fork */ +	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/ +	__uint8_t	di_forkoff;	/* attr fork offs, <<3 for 64b align */ +	__int8_t	di_aformat;	/* format of attr fork's data */ +	__uint32_t	di_dmevmask;	/* DMIG event mask */ +	__uint16_t	di_dmstate;	/* DMIG state info */ +	__uint16_t	di_flags;	/* random flags, XFS_DIFLAG_... */ +	__uint32_t	di_gen;		/* generation number */ +} xfs_dinode_core_t; + +typedef struct xfs_dinode +{ +	xfs_dinode_core_t	di_core; +	xfs_agino_t		di_next_unlinked;/* agi unlinked list ptr */ +	union { +		xfs_bmdr_block_t di_bmbt;	/* btree root block */ +		xfs_bmbt_rec_32_t di_bmx[1];	/* extent list */ +		xfs_dir2_sf_t	di_dir2sf;	/* shortform directory v2 */ +		char		di_c[1];	/* local contents */ +	} di_u; +} xfs_dinode_t; + +/* + * Values for di_format + */ +typedef enum xfs_dinode_fmt +{ +	XFS_DINODE_FMT_DEV,		/* CHR, BLK: di_dev */ +	XFS_DINODE_FMT_LOCAL,		/* DIR, REG: di_c */ +					/* LNK: di_symlink */ +	XFS_DINODE_FMT_EXTENTS,		/* DIR, REG, LNK: di_bmx */ +	XFS_DINODE_FMT_BTREE,		/* DIR, REG, LNK: di_bmbt */ +	XFS_DINODE_FMT_UUID 		/* MNT: di_uuid */ +} xfs_dinode_fmt_t; + +/* + * File types (mode field) + */ +#define	IFMT		0170000		/* type of file */ +#define	IFDIR		0040000		/* directory */ +#define	IFREG		0100000		/* regular */ +#define	IFLNK		0120000		/* symbolic link */ diff --git a/roms/openbios/fs/hfs/block.c b/roms/openbios/fs/hfs/block.c new file mode 100644 index 00000000..0b65a1f3 --- /dev/null +++ b/roms/openbios/fs/hfs/block.c @@ -0,0 +1,612 @@ +/* +* libhfs - library for reading and writing Macintosh HFS volumes +* Copyright (C) 1996-1998 Robert Leslie +* +* 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; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +* MA 02110-1301, USA. +* +* $Id: block.c,v 1.11 1998/11/02 22:08:52 rob Exp $ +*/ + +#include "config.h" + +#include "libhfs.h" +#include "volume.h" +#include "block.h" +#include "os.h" + +#define INUSE(b)	((b)->flags & HFS_BUCKET_INUSE) +#define DIRTY(b)	((b)->flags & HFS_BUCKET_DIRTY) + +/* + * NAME:	block->init() + * DESCRIPTION:	initialize a volume's block cache + */ +int b_init(hfsvol *vol) +{ +  bcache *cache; +  int i; + +  ASSERT(vol->cache == 0); + +  cache = ALLOC(bcache, 1); +  if (cache == NULL) +    ERROR(ENOMEM, NULL); + +  vol->cache = cache; + +  cache->vol    = vol; +  cache->tail   = &cache->chain[HFS_CACHESZ - 1]; + +  cache->hits   = 0; +  cache->misses = 0; + +  for (i = 0; i < HFS_CACHESZ; ++i) +    { +      bucket *b = &cache->chain[i]; + +      b->flags = 0; +      b->count = 0; + +      b->bnum  = 0; +      b->data  = &cache->pool[i]; + +      b->cnext = b + 1; +      b->cprev = b - 1; + +      b->hnext = NULL; +      b->hprev = NULL; +    } + +  cache->chain[0].cprev = cache->tail; +  cache->tail->cnext    = &cache->chain[0]; + +  for (i = 0; i < HFS_HASHSZ; ++i) +    cache->hash[i] = NULL; + +  return 0; + +fail: +  return -1; +} + +# ifdef DEBUG +/* + * NAME:	block->showstats() + * DESCRIPTION:	output cache hit/miss ratio + */ +void b_showstats(const bcache *cache) +{ +  fprintf(stderr, "BLOCK: CACHE vol 0x%lx \"%s\" hit/miss ratio = %.3f\n", +	  (unsigned long) cache->vol, cache->vol->mdb.drVN, +	  (float) cache->hits / (float) cache->misses); +} + +/* + * NAME:	block->dumpcache() + * DESCRIPTION:	dump the cache tables for a volume + */ +void b_dumpcache(const bcache *cache) +{ +  const bucket *b; +  int i; + +  fprintf(stderr, "BLOCK CACHE DUMP:\n"); + +  for (i = 0, b = cache->tail->cnext; i < HFS_CACHESZ; ++i, b = b->cnext) +    { +      if (INUSE(b)) +	{ +	  fprintf(stderr, "\t %lu", b->bnum); +	  if (DIRTY(b)) +	    fprintf(stderr, "*"); + +	  fprintf(stderr, ":%u", b->count); +	} +    } + +  fprintf(stderr, "\n"); + +  fprintf(stderr, "BLOCK HASH DUMP:\n"); + +  for (i = 0; i < HFS_HASHSZ; ++i) +    { +      int seen = 0; + +      for (b = cache->hash[i]; b; b = b->hnext) +	{ +	  if (! seen) +	    fprintf(stderr, "  %d:", i); + +	  if (INUSE(b)) +	    { +	      fprintf(stderr, " %lu", b->bnum); +	      if (DIRTY(b)) +		fprintf(stderr, "*"); + +	      fprintf(stderr, ":%u", b->count); +	    } + +	  seen = 1; +	} + +      if (seen) +	fprintf(stderr, "\n"); +    } +} +# endif + +/* + * NAME:	fillchain() + * DESCRIPTION:	fill a chain of bucket buffers with a single read + */ +static +int fillchain(hfsvol *vol, bucket **bptr, unsigned int *count) +{ +  bucket *blist[HFS_BLOCKBUFSZ], **start = bptr; +  unsigned long bnum=-2;	// XXX +  unsigned int len, i; + +  for (len = 0; len < HFS_BLOCKBUFSZ && +	 (unsigned int) (bptr - start) < *count; ++bptr) +    { +      if (INUSE(*bptr)) +	continue; + +      if (len > 0 && (*bptr)->bnum != bnum) +	break; + +      blist[len++] = *bptr; +      bnum = (*bptr)->bnum + 1; +    } + +  *count = bptr - start; + +  if (len == 0) +    goto done; +  else if (len == 1) +    { +      if (b_readpb(vol, vol->vstart + blist[0]->bnum, +		   blist[0]->data, 1) == -1) +	goto fail; +    } +  else +    { +      block buffer[HFS_BLOCKBUFSZ]; + +      if (b_readpb(vol, vol->vstart + blist[0]->bnum, buffer, len) == -1) +	goto fail; + +      for (i = 0; i < len; ++i) +	memcpy(blist[i]->data, buffer[i], HFS_BLOCKSZ); +    } + +  for (i = 0; i < len; ++i) +    { +      blist[i]->flags |=  HFS_BUCKET_INUSE; +      blist[i]->flags &= ~HFS_BUCKET_DIRTY; +    } + +done: +  return 0; + +fail: +  return -1; +} + + +/* + * NAME:	compare() + * DESCRIPTION:	comparison function for qsort of cache bucket pointers + */ +static +int compare(const bucket **b1, const bucket **b2) +{ +  long diff; + +  diff = (*b1)->bnum - (*b2)->bnum; + +  if (diff < 0) +    return -1; +  else if (diff > 0) +    return 1; +  else +    return 0; +} + +/* + * NAME:	dobuckets() + * DESCRIPTION:	fill or flush an array of cache buckets to a volume + */ +static +int dobuckets(hfsvol *vol, bucket **chain, unsigned int len, +	      int (*func)(hfsvol *, bucket **, unsigned int *)) +{ +  unsigned int count, i; +  int result = 0; + +  qsort(chain, len, sizeof(*chain), +	(int (*)(const void *, const void *)) compare); + +  for (i = 0; i < len; i += count) +    { +      count = len - i; +      if (func(vol, chain + i, &count) == -1) +	result = -1; +    } + +  return result; +} + +# define fillbuckets(vol, chain, len)	dobuckets(vol, chain, len, fillchain) + +/* + * NAME:	block->finish() + * DESCRIPTION:	commit and free a volume's block cache + */ +int b_finish(hfsvol *vol) +{ +  int result = 0; + +  if (vol->cache == NULL) +    goto done; + +# ifdef DEBUG +  b_dumpcache(vol->cache); +# endif + +  FREE(vol->cache); +  vol->cache = NULL; + +done: +  return result; +} + +/* + * NAME:	findbucket() + * DESCRIPTION:	locate a bucket in the cache, and/or its hash slot + */ +static +bucket *findbucket(bcache *cache, unsigned long bnum, bucket ***hslot) +{ +  bucket *b; + +  *hslot = &cache->hash[bnum & (HFS_HASHSZ - 1)]; + +  for (b = **hslot; b; b = b->hnext) +    { +      if (INUSE(b) && b->bnum == bnum) +	break; +    } + +  return b; +} + +/* + * NAME:	reuse() + * DESCRIPTION:	free a bucket for reuse, flushing if necessary + */ +static +int reuse(bcache *cache, bucket *b, unsigned long bnum) +{ +  bucket *bptr; +  int i; + +# ifdef DEBUG +  if (INUSE(b)) +    fprintf(stderr, "BLOCK: CACHE reusing bucket containing " +	    "vol 0x%lx block %lu:%u\n", +	    (unsigned long) cache->vol, b->bnum, b->count); +# endif + +  if (INUSE(b) && DIRTY(b)) +    { +      /* flush most recently unused buckets */ + +      for (bptr = b, i = 0; i < HFS_BLOCKBUFSZ; ++i) +	{ +	  bptr = bptr->cprev; +	} +    } + +  b->flags &= ~HFS_BUCKET_INUSE; +  b->count  = 1; +  b->bnum   = bnum; + +  return 0; +} + +/* + * NAME:	cplace() + * DESCRIPTION:	move a bucket to an appropriate place near head of the chain + */ +static +void cplace(bcache *cache, bucket *b) +{ +  bucket *p; + +  for (p = cache->tail->cnext; p->count > 1; p = p->cnext) +    --p->count; + +  b->cnext->cprev = b->cprev; +  b->cprev->cnext = b->cnext; + +  if (cache->tail == b) +    cache->tail = b->cprev; + +  b->cprev = p->cprev; +  b->cnext = p; + +  p->cprev->cnext = b; +  p->cprev = b; +} + +/* + * NAME:	hplace() + * DESCRIPTION:	move a bucket to the head of its hash slot + */ +static +void hplace(bucket **hslot, bucket *b) +{ +  if (*hslot != b) +    { +      if (b->hprev) +	*b->hprev = b->hnext; +      if (b->hnext) +	b->hnext->hprev = b->hprev; + +      b->hprev = hslot; +      b->hnext = *hslot; + +      if (*hslot) +	(*hslot)->hprev = &b->hnext; + +      *hslot = b; +    } +} + +/* + * NAME:	getbucket() + * DESCRIPTION:	fetch a bucket from the cache, or an empty one to be filled + */ +static +bucket *getbucket(bcache *cache, unsigned long bnum, int fill) +{ +  bucket **hslot, *b, *p, *bptr, +    *chain[HFS_BLOCKBUFSZ], **slots[HFS_BLOCKBUFSZ]; + +  b = findbucket(cache, bnum, &hslot); + +  if (b) +    { +      /* cache hit; move towards head of cache chain */ + +      ++cache->hits; + +      if (++b->count > b->cprev->count && +	  b != cache->tail->cnext) +	{ +	  p = b->cprev; + +	  p->cprev->cnext = b; +	  b->cnext->cprev = p; + +	  p->cnext = b->cnext; +	  b->cprev = p->cprev; + +	  p->cprev = b; +	  b->cnext = p; + +	  if (cache->tail == b) +	    cache->tail = p; +	} +    } +  else +    { +      /* cache miss; reuse least-used cache bucket */ + +      ++cache->misses; + +      b = cache->tail; + +      if (reuse(cache, b, bnum) == -1) +	goto fail; + +      if (fill) +	{ +	  unsigned int len = 0; + +	  chain[len]   = b; +	  slots[len++] = hslot; + +	  for (bptr = b->cprev; +	       len < (HFS_BLOCKBUFSZ >> 1) && ++bnum < cache->vol->vlen; +	       bptr = bptr->cprev) +	    { +	      if (findbucket(cache, bnum, &hslot)) +		break; + +	      if (reuse(cache, bptr, bnum) == -1) +		goto fail; + +	      chain[len]   = bptr; +	      slots[len++] = hslot; +	    } + +	  if (fillbuckets(cache->vol, chain, len) == -1) +	    goto fail; + +	  while (--len) +	    { +	      cplace(cache, chain[len]); +	      hplace(slots[len], chain[len]); +	    } + +	  hslot = slots[0]; +	} + +      /* move bucket to appropriate place in chain */ + +      cplace(cache, b); +    } + +  /* insert at front of hash chain */ + +  hplace(hslot, b); + +  return b; + +fail: +  return NULL; +} + +/* + * NAME:	block->readpb() + * DESCRIPTION:	read blocks from the physical medium (bypassing cache) + */ +int b_readpb(hfsvol *vol, unsigned long bnum, block *bp, unsigned int blen) +{ +  unsigned long nblocks; + +# ifdef DEBUG +  fprintf(stderr, "BLOCK: READ vol 0x%lx block %lu", +	  (unsigned long) vol, bnum); +  if (blen > 1) +    fprintf(stderr, "+%u[..%lu]\n", blen - 1, bnum + blen - 1); +  else +    fprintf(stderr, "\n"); +# endif + +  nblocks = os_seek(vol->os_fd, bnum, HFS_BLOCKSZ_BITS ); +  if (nblocks == (unsigned long) -1) +    goto fail; + +  if (nblocks != bnum) +    ERROR(EIO, "block seek failed for read"); + +  nblocks = os_read(vol->os_fd, bp, blen, HFS_BLOCKSZ_BITS); +  if (nblocks == (unsigned long) -1) +    goto fail; + +  if (nblocks != blen) +    ERROR(EIO, "incomplete block read"); + +  return 0; + +fail: +  return -1; +} + + +/* + * NAME:	block->readlb() + * DESCRIPTION:	read a logical block from a volume (or from the cache) + */ +int b_readlb(hfsvol *vol, unsigned long bnum, block *bp) +{ +  if (vol->vlen > 0 && bnum >= vol->vlen) +    ERROR(EIO, "read nonexistent logical block"); + +  if (vol->cache) +    { +      bucket *b; + +      b = getbucket(vol->cache, bnum, 1); +      if (b == NULL) +	goto fail; + +      memcpy(bp, b->data, HFS_BLOCKSZ); +    } +  else +    { +      if (b_readpb(vol, vol->vstart + bnum, bp, 1) == -1) +	goto fail; +    } + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	block->readab() + * DESCRIPTION:	read a block from an allocation block from a volume + */ +int b_readab(hfsvol *vol, unsigned int anum, unsigned int index, block *bp) +{ +  /* verify the allocation block exists and is marked as in-use */ + +  if (anum >= vol->mdb.drNmAlBlks) +    ERROR(EIO, "read nonexistent allocation block"); +  else if (vol->vbm && ! BMTST(vol->vbm, anum)) +    ERROR(EIO, "read unallocated block"); + +  return b_readlb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + index, bp); + +fail: +  return -1; +} + + +/* + * NAME:	block->size() + * DESCRIPTION:	return the number of physical blocks on a volume's medium + */ +unsigned long b_size(hfsvol *vol) +{ +  unsigned long low, high, mid; +  block b; + +  high = os_seek(vol->os_fd, -1, HFS_BLOCKSZ_BITS); + +  if (high != (unsigned long) -1 && high > 0) +    return high; + +  /* manual size detection: first check there is at least 1 block in medium */ + +  if (b_readpb(vol, 0, &b, 1) == -1) +    ERROR(EIO, "size of medium indeterminable or empty"); + +  for (low = 0, high = 2880; +       high > 0 && b_readpb(vol, high - 1, &b, 1) != -1; +       high <<= 1) +    low = high - 1; + +  if (high == 0) +    ERROR(EIO, "size of medium indeterminable or too large"); + +  /* common case: 1440K floppy */ + +  if (low == 2879 && b_readpb(vol, 2880, &b, 1) == -1) +    return 2880; + +  /* binary search for other sizes */ + +  while (low < high - 1) +    { +      mid = (low + high) >> 1; + +      if (b_readpb(vol, mid, &b, 1) == -1) +	high = mid; +      else +	low = mid; +    } + +  return low + 1; + +fail: +  return 0; +} diff --git a/roms/openbios/fs/hfs/btree.c b/roms/openbios/fs/hfs/btree.c new file mode 100644 index 00000000..cd5c8534 --- /dev/null +++ b/roms/openbios/fs/hfs/btree.c @@ -0,0 +1,230 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: btree.c,v 1.10 1998/11/02 22:08:54 rob Exp $ + */ + +#include "config.h" + +#include "libhfs.h" +#include "btree.h" +#include "data.h" +#include "file.h" +#include "block.h" +#include "node.h" + +/* + * NAME:	btree->getnode() + * DESCRIPTION:	retrieve a numbered node from a B*-tree file + */ +int bt_getnode(node *np, btree *bt, unsigned long nnum) +{ +  block *bp = &np->data; +  const byte *ptr; +  int i; + +  np->bt   = bt; +  np->nnum = nnum; + +# if 0 +  fprintf(stderr, "BTREE: GET vol \"%s\" btree \"%s\" node %lu\n", +	  bt->f.vol->mdb.drVN, bt->f.name, np->nnum); +# endif + +  /* verify the node exists and is marked as in-use */ + +  if (nnum > 0 && nnum >= bt->hdr.bthNNodes) +    ERROR(EIO, "read nonexistent b*-tree node"); +  else if (bt->map && ! BMTST(bt->map, nnum)) +    ERROR(EIO, "read unallocated b*-tree node"); + +  if (f_getblock(&bt->f, nnum, bp) == -1) +    goto fail; + +  ptr = *bp; + +  d_fetchul(&ptr, &np->nd.ndFLink); +  d_fetchul(&ptr, &np->nd.ndBLink); +  d_fetchsb(&ptr, &np->nd.ndType); +  d_fetchsb(&ptr, &np->nd.ndNHeight); +  d_fetchuw(&ptr, &np->nd.ndNRecs); +  d_fetchsw(&ptr, &np->nd.ndResv2); + +  if (np->nd.ndNRecs > HFS_MAX_NRECS) +    ERROR(EIO, "too many b*-tree node records"); + +  i = np->nd.ndNRecs + 1; + +  ptr = *bp + HFS_BLOCKSZ - (2 * i); + +  while (i--) +    d_fetchuw(&ptr, &np->roff[i]); + +  return 0; + +fail: +  return -1; +} + + +/* + * NAME:	btree->readhdr() + * DESCRIPTION:	read the header node of a B*-tree + */ +int bt_readhdr(btree *bt) +{ +  const byte *ptr; +  byte *map = NULL; +  int i; +  unsigned long nnum; + +  if (bt_getnode(&bt->hdrnd, bt, 0) == -1) +    goto fail; + +  if (bt->hdrnd.nd.ndType != ndHdrNode || +      bt->hdrnd.nd.ndNRecs != 3 || +      bt->hdrnd.roff[0] != 0x00e || +      bt->hdrnd.roff[1] != 0x078 || +      bt->hdrnd.roff[2] != 0x0f8 || +      bt->hdrnd.roff[3] != 0x1f8) +    ERROR(EIO, "malformed b*-tree header node"); + +  /* read header record */ + +  ptr = HFS_NODEREC(bt->hdrnd, 0); + +  d_fetchuw(&ptr, &bt->hdr.bthDepth); +  d_fetchul(&ptr, &bt->hdr.bthRoot); +  d_fetchul(&ptr, &bt->hdr.bthNRecs); +  d_fetchul(&ptr, &bt->hdr.bthFNode); +  d_fetchul(&ptr, &bt->hdr.bthLNode); +  d_fetchuw(&ptr, &bt->hdr.bthNodeSize); +  d_fetchuw(&ptr, &bt->hdr.bthKeyLen); +  d_fetchul(&ptr, &bt->hdr.bthNNodes); +  d_fetchul(&ptr, &bt->hdr.bthFree); + +  for (i = 0; i < 76; ++i) +    d_fetchsb(&ptr, &bt->hdr.bthResv[i]); + +  if (bt->hdr.bthNodeSize != HFS_BLOCKSZ) +    ERROR(EINVAL, "unsupported b*-tree node size"); + +  /* read map record; construct btree bitmap */ +  /* don't set bt->map until we're done, since getnode() checks it */ + +  map = ALLOC(byte, HFS_MAP1SZ); +  if (map == NULL) +    ERROR(ENOMEM, NULL); + +  memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ); +  bt->mapsz = HFS_MAP1SZ; + +  /* read continuation map records, if any */ + +  nnum = bt->hdrnd.nd.ndFLink; + +  while (nnum) +    { +      node n; +      byte *newmap; + +      if (bt_getnode(&n, bt, nnum) == -1) +	goto fail; + +      if (n.nd.ndType != ndMapNode || +	  n.nd.ndNRecs != 1 || +	  n.roff[0] != 0x00e || +	  n.roff[1] != 0x1fa) +	ERROR(EIO, "malformed b*-tree map node"); + +      newmap = REALLOC(map, byte, bt->mapsz + HFS_MAPXSZ); +      if (newmap == NULL) +	ERROR(ENOMEM, NULL); + +      map = newmap; + +      memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ); +      bt->mapsz += HFS_MAPXSZ; + +      nnum = n.nd.ndFLink; +    } + +  bt->map = map; + +  return 0; + +fail: +  FREE(map); +  return -1; +} + + +/* + * NAME:	btree->search() + * DESCRIPTION:	locate a data record given a search key + */ +int bt_search(btree *bt, const byte *key, node *np) +{ +  int found = 0; +  unsigned long nnum; + +  nnum = bt->hdr.bthRoot; + +  if (nnum == 0) +    ERROR(ENOENT, NULL); + +  while (1) +    { +      const byte *rec; + +      if (bt_getnode(np, bt, nnum) == -1) +	{ +	  found = -1; +	  goto fail; +	} + +      found = n_search(np, key); + +      switch (np->nd.ndType) +	{ +	case ndIndxNode: +	  if (np->rnum == -1) +            ERROR(ENOENT, NULL); + +	  rec  = HFS_NODEREC(*np, np->rnum); +	  nnum = d_getul(HFS_RECDATA(rec)); + +	  break; + +	case ndLeafNode: +	  if (! found) +            ERROR(ENOENT, NULL); + +	  goto done; + +	default: +	  found = -1; +	  ERROR(EIO, "unexpected b*-tree node"); +	} +    } + +done: +fail: +  return found; +} diff --git a/roms/openbios/fs/hfs/build.xml b/roms/openbios/fs/hfs/build.xml new file mode 100644 index 00000000..2ac6fdbb --- /dev/null +++ b/roms/openbios/fs/hfs/build.xml @@ -0,0 +1,15 @@ +<build> + <library name="fs" type="static" target="target"> +  <object source="block.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="btree.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="data.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="file.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="hfs.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="low.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="medium.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="node.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="record.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="volume.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> +  <object source="hfs_fs.c" flags="-I$(SRCDIR)/fs/hfs/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFS"/> + </library> +</build> diff --git a/roms/openbios/fs/hfs/data.c b/roms/openbios/fs/hfs/data.c new file mode 100644 index 00000000..a0e4a8ea --- /dev/null +++ b/roms/openbios/fs/hfs/data.c @@ -0,0 +1,476 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: data.c,v 1.7 1998/11/02 22:08:57 rob Exp $ + */ + +#include "config.h" +#include "data.h" + +#define TIMEDIFF  2082844800UL + +static +time_t tzdiff = -1; + +static const +unsigned char hfs_charorder[256] = { +  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, +  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + +  0x20, 0x22, 0x23, 0x28, 0x29, 0x2a, 0x2b, 0x2c, +  0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +  0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, +  0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + +  0x47, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69, +  0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f, +  0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1, +  0xa3, 0xa5, 0xa8, 0xaa, 0xab, 0xac, 0xad, 0xae, + +  0x54, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69, +  0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f, +  0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1, +  0xa3, 0xa5, 0xa8, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + +  0x4c, 0x50, 0x5c, 0x62, 0x7d, 0x81, 0x9a, 0x55, +  0x4a, 0x56, 0x4c, 0x4e, 0x50, 0x5c, 0x62, 0x64, +  0x65, 0x66, 0x6f, 0x70, 0x71, 0x72, 0x7d, 0x89, +  0x8a, 0x8b, 0x81, 0x83, 0x9c, 0x9d, 0x9e, 0x9a, + +  0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0x95, +  0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0x52, 0x85, +  0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, +  0xc9, 0xca, 0xcb, 0x57, 0x8c, 0xcc, 0x52, 0x85, + +  0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0x26, +  0x27, 0xd4, 0x20, 0x4a, 0x4e, 0x83, 0x87, 0x87, +  0xd5, 0xd6, 0x24, 0x25, 0x2d, 0x2e, 0xd7, 0xd8, +  0xa7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + +  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, +  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, +  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, +  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +/* + * NAME:	data->getsb() + * DESCRIPTION:	marshal 1 signed byte into local host format + */ +signed char d_getsb(register const unsigned char *ptr) +{ +  return ptr[0]; +} + +/* + * NAME:	data->getub() + * DESCRIPTION:	marshal 1 unsigned byte into local host format + */ +unsigned char d_getub(register const unsigned char *ptr) +{ +  return ptr[0]; +} + +/* + * NAME:	data->getsw() + * DESCRIPTION:	marshal 2 signed bytes into local host format + */ +signed short d_getsw(register const unsigned char *ptr) +{ +  return +    (((  signed short) ptr[0] << 8) | +     ((unsigned short) ptr[1] << 0)); +} + +/* + * NAME:	data->getuw() + * DESCRIPTION:	marshal 2 unsigned bytes into local host format + */ +unsigned short d_getuw(register const unsigned char *ptr) +{ +  return +    (((unsigned short) ptr[0] << 8) | +     ((unsigned short) ptr[1] << 0)); +} + +/* + * NAME:	data->getsl() + * DESCRIPTION:	marshal 4 signed bytes into local host format + */ +signed long d_getsl(register const unsigned char *ptr) +{ +  return +    (((  signed long) ptr[0] << 24) | +     ((unsigned long) ptr[1] << 16) | +     ((unsigned long) ptr[2] <<  8) | +     ((unsigned long) ptr[3] <<  0)); +} + +/* + * NAME:	data->getul() + * DESCRIPTION:	marshal 4 unsigned bytes into local host format + */ +unsigned long d_getul(register const unsigned char *ptr) +{ +  return +    (((unsigned long) ptr[0] << 24) | +     ((unsigned long) ptr[1] << 16) | +     ((unsigned long) ptr[2] <<  8) | +     ((unsigned long) ptr[3] <<  0)); +} + +/* + * NAME:	data->putsb() + * DESCRIPTION:	marshal 1 signed byte out in big-endian format + */ +void d_putsb(register unsigned char *ptr, +	     register signed char data) +{ +  *ptr = data; +} + +/* + * NAME:	data->putub() + * DESCRIPTION:	marshal 1 unsigned byte out in big-endian format + */ +void d_putub(register unsigned char *ptr, +	     register unsigned char data) +{ +  *ptr = data; +} + +/* + * NAME:	data->putsw() + * DESCRIPTION:	marshal 2 signed bytes out in big-endian format + */ +void d_putsw(register unsigned char *ptr, +	     register signed short data) +{ +  *ptr++ = ((unsigned short) data & 0xff00) >> 8; +  *ptr   = ((unsigned short) data & 0x00ff) >> 0; +} + +/* + * NAME:	data->putuw() + * DESCRIPTION:	marshal 2 unsigned bytes out in big-endian format + */ +void d_putuw(register unsigned char *ptr, +	     register unsigned short data) +{ +  *ptr++ = (data & 0xff00) >> 8; +  *ptr   = (data & 0x00ff) >> 0; +} + +/* + * NAME:	data->putsl() + * DESCRIPTION:	marshal 4 signed bytes out in big-endian format + */ +void d_putsl(register unsigned char *ptr, +	     register signed long data) +{ +  *ptr++ = ((unsigned long) data & 0xff000000UL) >> 24; +  *ptr++ = ((unsigned long) data & 0x00ff0000UL) >> 16; +  *ptr++ = ((unsigned long) data & 0x0000ff00UL) >>  8; +  *ptr   = ((unsigned long) data & 0x000000ffUL) >>  0; +} + +/* + * NAME:	data->putul() + * DESCRIPTION:	marshal 4 unsigned bytes out in big-endian format + */ +void d_putul(register unsigned char *ptr, +	     register unsigned long data) +{ +  *ptr++ = (data & 0xff000000UL) >> 24; +  *ptr++ = (data & 0x00ff0000UL) >> 16; +  *ptr++ = (data & 0x0000ff00UL) >>  8; +  *ptr   = (data & 0x000000ffUL) >>  0; +} + +/* + * NAME:	data->fetchsb() + * DESCRIPTION:	incrementally retrieve a signed byte of data + */ +void d_fetchsb(register const unsigned char **ptr, +	       register signed char *dest) +{ +  *dest = *(*ptr)++; +} + +/* + * NAME:	data->fetchub() + * DESCRIPTION:	incrementally retrieve an unsigned byte of data + */ +void d_fetchub(register const unsigned char **ptr, +	       register unsigned char *dest) +{ +  *dest = *(*ptr)++; +} + +/* + * NAME:	data->fetchsw() + * DESCRIPTION:	incrementally retrieve a signed word of data + */ +void d_fetchsw(register const unsigned char **ptr, +	       register signed short *dest) +{ +  *dest = +    (((  signed short) (*ptr)[0] << 8) | +     ((unsigned short) (*ptr)[1] << 0)); +  *ptr += 2; +} + +/* + * NAME:	data->fetchuw() + * DESCRIPTION:	incrementally retrieve an unsigned word of data + */ +void d_fetchuw(register const unsigned char **ptr, +	       register unsigned short *dest) +{ +  *dest = +    (((unsigned short) (*ptr)[0] << 8) | +     ((unsigned short) (*ptr)[1] << 0)); +  *ptr += 2; +} + +/* + * NAME:	data->fetchsl() + * DESCRIPTION:	incrementally retrieve a signed long word of data + */ +void d_fetchsl(register const unsigned char **ptr, +	       register signed long *dest) +{ +  *dest = +    (((  signed long) (*ptr)[0] << 24) | +     ((unsigned long) (*ptr)[1] << 16) | +     ((unsigned long) (*ptr)[2] <<  8) | +     ((unsigned long) (*ptr)[3] <<  0)); +  *ptr += 4; +} + +/* + * NAME:	data->fetchul() + * DESCRIPTION:	incrementally retrieve an unsigned long word of data + */ +void d_fetchul(register const unsigned char **ptr, +	       register unsigned long *dest) +{ +  *dest = +    (((unsigned long) (*ptr)[0] << 24) | +     ((unsigned long) (*ptr)[1] << 16) | +     ((unsigned long) (*ptr)[2] <<  8) | +     ((unsigned long) (*ptr)[3] <<  0)); +  *ptr += 4; +} + +/* + * NAME:	data->storesb() + * DESCRIPTION:	incrementally store a signed byte of data + */ +void d_storesb(register unsigned char **ptr, +	       register signed char data) +{ +  *(*ptr)++ = data; +} + +/* + * NAME:	data->storeub() + * DESCRIPTION:	incrementally store an unsigned byte of data + */ +void d_storeub(register unsigned char **ptr, +	       register unsigned char data) +{ +  *(*ptr)++ = data; +} + +/* + * NAME:	data->storesw() + * DESCRIPTION:	incrementally store a signed word of data + */ +void d_storesw(register unsigned char **ptr, +	       register signed short data) +{ +  *(*ptr)++ = ((unsigned short) data & 0xff00) >> 8; +  *(*ptr)++ = ((unsigned short) data & 0x00ff) >> 0; +} + +/* + * NAME:	data->storeuw() + * DESCRIPTION:	incrementally store an unsigned word of data + */ +void d_storeuw(register unsigned char **ptr, +	       register unsigned short data) +{ +  *(*ptr)++ = (data & 0xff00) >> 8; +  *(*ptr)++ = (data & 0x00ff) >> 0; +} + +/* + * NAME:	data->storesl() + * DESCRIPTION:	incrementally store a signed long word of data + */ +void d_storesl(register unsigned char **ptr, +	       register signed long data) +{ +  *(*ptr)++ = ((unsigned long) data & 0xff000000UL) >> 24; +  *(*ptr)++ = ((unsigned long) data & 0x00ff0000UL) >> 16; +  *(*ptr)++ = ((unsigned long) data & 0x0000ff00UL) >>  8; +  *(*ptr)++ = ((unsigned long) data & 0x000000ffUL) >>  0; +} + +/* + * NAME:	data->storeul() + * DESCRIPTION:	incrementally store an unsigned long word of data + */ +void d_storeul(register unsigned char **ptr, +	       register unsigned long data) +{ +  *(*ptr)++ = (data & 0xff000000UL) >> 24; +  *(*ptr)++ = (data & 0x00ff0000UL) >> 16; +  *(*ptr)++ = (data & 0x0000ff00UL) >>  8; +  *(*ptr)++ = (data & 0x000000ffUL) >>  0; +} + +/* + * NAME:	data->fetchstr() + * DESCRIPTION:	incrementally retrieve a string + */ +void d_fetchstr(const unsigned char **ptr, char *dest, unsigned size) +{ +  unsigned len; + +  len = d_getub(*ptr); + +  if (len > 0 && len < size) +    memcpy(dest, *ptr + 1, len); +  else +    len = 0; + +  dest[len] = 0; + +  *ptr += size; +} + +/* + * NAME:	data->storestr() + * DESCRIPTION:	incrementally store a string + */ +void d_storestr(unsigned char **ptr, const char *src, unsigned size) +{ +  unsigned len; + +  len = strlen(src); +  if (len > --size) +    len = 0; + +  d_storeub(ptr, len); + +  memcpy(*ptr, src, len); +  memset(*ptr + len, 0, size - len); + +  *ptr += size; +} + +/* + * NAME:	data->relstring() + * DESCRIPTION:	compare two strings as per MacOS for HFS + */ +int d_relstring(const char *str1, const char *str2) +{ +  register int diff; + +  while (*str1 && *str2) +    { +      diff = hfs_charorder[(unsigned char) *str1] - +	     hfs_charorder[(unsigned char) *str2]; + +      if (diff) +	return diff; + +      ++str1, ++str2; +    } + +  if (! *str1 && *str2) +    return -1; +  else if (*str1 && ! *str2) +    return 1; + +  return 0; +} + +/* + * NAME:	calctzdiff() + * DESCRIPTION:	calculate the timezone difference between local time and UTC + */ +static +void calctzdiff(void) +{ +# ifdef HAVE_MKTIME + +  time_t t; +  int isdst; +  struct tm tm; +  const struct tm *tmp; + +  time(&t); +  isdst = localtime(&t)->tm_isdst; + +  tmp = gmtime(&t); +  if (tmp) +    { +      tm = *tmp; +      tm.tm_isdst = isdst; + +      tzdiff = t - mktime(&tm); +    } +  else +    tzdiff = 0; + +# else + +  tzdiff = 0; + +# endif +} + +/* + * NAME:	data->ltime() + * DESCRIPTION:	convert MacOS time to local time + */ +time_t d_ltime(unsigned long mtime) +{ +  if (tzdiff == -1) +    calctzdiff(); + +  return (time_t) (mtime - TIMEDIFF) - tzdiff; +} + +/* + * NAME:	data->mtime() + * DESCRIPTION:	convert local time to MacOS time + */ +unsigned long d_mtime(time_t ltime) +{ +  if (tzdiff == -1) +    calctzdiff(); + +  return (unsigned long) (ltime + tzdiff) + TIMEDIFF; +} diff --git a/roms/openbios/fs/hfs/file.c b/roms/openbios/fs/hfs/file.c new file mode 100644 index 00000000..a6ddb893 --- /dev/null +++ b/roms/openbios/fs/hfs/file.c @@ -0,0 +1,191 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: file.c,v 1.9 1998/11/02 22:08:59 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "file.h" +#include "btree.h" +#include "record.h" +#include "volume.h" + +/* + * NAME:	file->init() + * DESCRIPTION:	initialize file structure + */ +void f_init(hfsfile *file, hfsvol *vol, long cnid, const char *name) +{ +  int i; + +  file->vol   = vol; +  file->parid = 0; + +  strcpy(file->name, name); + +  file->cat.cdrType          = cdrFilRec; +  file->cat.cdrResrv2        = 0; + +  file->cat.u.fil.filFlags   = 0; +  file->cat.u.fil.filTyp     = 0; + +  file->cat.u.fil.filUsrWds.fdType       = 0; +  file->cat.u.fil.filUsrWds.fdCreator    = 0; +  file->cat.u.fil.filUsrWds.fdFlags      = 0; +  file->cat.u.fil.filUsrWds.fdLocation.v = 0; +  file->cat.u.fil.filUsrWds.fdLocation.h = 0; +  file->cat.u.fil.filUsrWds.fdFldr       = 0; + +  file->cat.u.fil.filFlNum   = cnid; +  file->cat.u.fil.filStBlk   = 0; +  file->cat.u.fil.filLgLen   = 0; +  file->cat.u.fil.filPyLen   = 0; +  file->cat.u.fil.filRStBlk  = 0; +  file->cat.u.fil.filRLgLen  = 0; +  file->cat.u.fil.filRPyLen  = 0; +  file->cat.u.fil.filCrDat   = 0; +  file->cat.u.fil.filMdDat   = 0; +  file->cat.u.fil.filBkDat   = 0; + +  file->cat.u.fil.filFndrInfo.fdIconID = 0; +  for (i = 0; i < 4; ++i) +    file->cat.u.fil.filFndrInfo.fdUnused[i] = 0; +  file->cat.u.fil.filFndrInfo.fdComment = 0; +  file->cat.u.fil.filFndrInfo.fdPutAway = 0; + +  file->cat.u.fil.filClpSize = 0; + +  for (i = 0; i < 3; ++i) +    { +      file->cat.u.fil.filExtRec[i].xdrStABN     = 0; +      file->cat.u.fil.filExtRec[i].xdrNumABlks  = 0; + +      file->cat.u.fil.filRExtRec[i].xdrStABN    = 0; +      file->cat.u.fil.filRExtRec[i].xdrNumABlks = 0; +    } + +  file->cat.u.fil.filResrv   = 0; + +  f_selectfork(file, fkData); + +  file->flags = 0; + +  file->prev  = NULL; +  file->next  = NULL; +} + +/* + * NAME:	file->selectfork() + * DESCRIPTION:	choose a fork for file operations + */ +void f_selectfork(hfsfile *file, int fork) +{ +  file->fork = fork; + +  memcpy(&file->ext, fork == fkData ? +	 &file->cat.u.fil.filExtRec : &file->cat.u.fil.filRExtRec, +	 sizeof(ExtDataRec)); + +  file->fabn = 0; +  file->pos  = 0; +} + +/* + * NAME:	file->getptrs() + * DESCRIPTION:	make pointers to the current fork's lengths and extents + */ +void f_getptrs(hfsfile *file, ExtDataRec **extrec, +	       unsigned long **lglen, unsigned long **pylen) +{ +  if (file->fork == fkData) +    { +      if (extrec) +	*extrec = &file->cat.u.fil.filExtRec; +      if (lglen) +	*lglen  = &file->cat.u.fil.filLgLen; +      if (pylen) +	*pylen  = &file->cat.u.fil.filPyLen; +    } +  else +    { +      if (extrec) +	*extrec = &file->cat.u.fil.filRExtRec; +      if (lglen) +	*lglen  = &file->cat.u.fil.filRLgLen; +      if (pylen) +	*pylen  = &file->cat.u.fil.filRPyLen; +    } +} + +/* + * NAME:	file->doblock() + * DESCRIPTION:	read or write a numbered block from a file + */ +int f_doblock(hfsfile *file, unsigned long num, block *bp, +	      int (*func)(hfsvol *, unsigned int, unsigned int, block *)) +{ +  unsigned int abnum; +  unsigned int blnum; +  unsigned int fabn; +  int i; + +  abnum = num / file->vol->lpa; +  blnum = num % file->vol->lpa; + +  /* locate the appropriate extent record */ + +  fabn = file->fabn; + +  if (abnum < fabn) +    { +      ExtDataRec *extrec; + +      f_getptrs(file, &extrec, NULL, NULL); + +      fabn = file->fabn = 0; +      memcpy(&file->ext, extrec, sizeof(ExtDataRec)); +    } +  else +    abnum -= fabn; + +  while (1) +    { +      unsigned int n; + +      for (i = 0; i < 3; ++i) +	{ +	  n = file->ext[i].xdrNumABlks; + +	  if (abnum < n) +	    return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp); + +	  fabn  += n; +	  abnum -= n; +	} + +      if (v_extsearch(file, fabn, &file->ext, NULL) <= 0) +	goto fail; + +      file->fabn = fabn; +    } + +fail: +  return -1; +} diff --git a/roms/openbios/fs/hfs/hfs.c b/roms/openbios/fs/hfs/hfs.c new file mode 100644 index 00000000..0c5fefb4 --- /dev/null +++ b/roms/openbios/fs/hfs/hfs.c @@ -0,0 +1,747 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "data.h" +#include "block.h" +#include "medium.h" +#include "file.h" +#include "btree.h" +#include "node.h" +#include "record.h" +#include "volume.h" + +const char *hfs_error = "no error";	/* static error string */ + +hfsvol *hfs_mounts;			/* linked list of mounted volumes */ + +static +hfsvol *curvol;				/* current volume */ + + +/* + * NAME:	getvol() + * DESCRIPTION:	validate a volume reference + */ +static +int getvol(hfsvol **vol) +{ +  if (*vol == NULL) +    { +      if (curvol == NULL) +	ERROR(EINVAL, "no volume is current"); + +      *vol = curvol; +    } + +  return 0; + +fail: +  return -1; +} + +/* High-Level Volume Routines ============================================== */ + +/* + * NAME:	hfs->mount() + * DESCRIPTION:	open an HFS volume; return volume descriptor or 0 (error) + */ +hfsvol *hfs_mount( int os_fd, int pnum) +{ +  hfsvol *vol, *check; +  int mode = HFS_MODE_RDONLY; + +  /* see if the volume is already mounted */ +  for (check = hfs_mounts; check; check = check->next) +    { +      if (check->pnum == pnum && v_same(check, os_fd) == 1) +	{ +	    vol = check; +	    goto done; +	} +    } + +  vol = ALLOC(hfsvol, 1); +  if (vol == NULL) +    ERROR(ENOMEM, NULL); + +  v_init(vol, mode); + +  vol->flags |= HFS_VOL_READONLY; +  if( v_open(vol, os_fd) == -1 ) +	  goto fail; + +  /* mount the volume */ + +  if (v_geometry(vol, pnum) == -1 || +      v_mount(vol) == -1) +    goto fail; + +  /* add to linked list of volumes */ + +  vol->prev = NULL; +  vol->next = hfs_mounts; + +  if (hfs_mounts) +    hfs_mounts->prev = vol; + +  hfs_mounts = vol; + +done: +  ++vol->refs; +  curvol = vol; + +  return vol; + +fail: +  if (vol) +    { +      v_close(vol); +      FREE(vol); +    } + +  return NULL; +} + + +/* + * NAME:	hfs->umount() + * DESCRIPTION:	close an HFS volume + */ +int hfs_umount(hfsvol *vol) +{ +  int result = 0; + +  if (getvol(&vol) == -1) +    goto fail; + +  if (--vol->refs) +    { +      goto done; +    } + +  /* close all open files and directories */ + +  while (vol->files) +    { +      if (hfs_close(vol->files) == -1) +	result = -1; +    } + +  while (vol->dirs) +    { +      if (hfs_closedir(vol->dirs) == -1) +	result = -1; +    } + +  /* close medium */ + +  if (v_close(vol) == -1) +    result = -1; + +  /* remove from linked list of volumes */ + +  if (vol->prev) +    vol->prev->next = vol->next; +  if (vol->next) +    vol->next->prev = vol->prev; + +  if (vol == hfs_mounts) +    hfs_mounts = vol->next; +  if (vol == curvol) +    curvol = NULL; + +  FREE(vol); + +done: +  return result; + +fail: +  return -1; +} + +/* + * NAME:	hfs->umountall() + * DESCRIPTION:	unmount all mounted volumes + */ +void hfs_umountall(void) +{ +  while (hfs_mounts) +    hfs_umount(hfs_mounts); +} + +/* + * NAME:	hfs->getvol() + * DESCRIPTION:	return a pointer to a mounted volume + */ +hfsvol *hfs_getvol(const char *name) +{ +  hfsvol *vol; + +  if (name == NULL) +    return curvol; + +  for (vol = hfs_mounts; vol; vol = vol->next) +    { +      if (d_relstring(name, vol->mdb.drVN) == 0) +	return vol; +    } + +  return NULL; +} + +/* + * NAME:	hfs->setvol() + * DESCRIPTION:	change the current volume + */ +void hfs_setvol(hfsvol *vol) +{ +  curvol = vol; +} + +/* + * NAME:	hfs->vstat() + * DESCRIPTION:	return volume statistics + */ +int hfs_vstat(hfsvol *vol, hfsvolent *ent) +{ +  if (getvol(&vol) == -1) +    goto fail; + +  strcpy(ent->name, vol->mdb.drVN); + +  ent->flags     = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0; + +  ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz; +  ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz; + +  ent->alblocksz = vol->mdb.drAlBlkSiz; +  ent->clumpsz   = vol->mdb.drClpSiz; + +  ent->numfiles  = vol->mdb.drFilCnt; +  ent->numdirs   = vol->mdb.drDirCnt; + +  ent->crdate    = d_ltime(vol->mdb.drCrDate); +  ent->mddate    = d_ltime(vol->mdb.drLsMod); +  ent->bkdate    = d_ltime(vol->mdb.drVolBkUp); + +  ent->blessed   = vol->mdb.drFndrInfo[0]; + +  return 0; + +fail: +  return -1; +} + + +/* High-Level Directory Routines =========================================== */ + +/* + * NAME:	hfs->chdir() + * DESCRIPTION:	change current HFS directory + */ +int hfs_chdir(hfsvol *vol, const char *path) +{ +  CatDataRec data; + +  if (getvol(&vol) == -1 || +      v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0) +    goto fail; + +  if (data.cdrType != cdrDirRec) +    ERROR(ENOTDIR, NULL); + +  vol->cwd = data.u.dir.dirDirID; + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	hfs->getcwd() + * DESCRIPTION:	return the current working directory ID + */ +unsigned long hfs_getcwd(hfsvol *vol) +{ +  if (getvol(&vol) == -1) +    return 0; + +  return vol->cwd; +} + +/* + * NAME:	hfs->setcwd() + * DESCRIPTION:	set the current working directory ID + */ +int hfs_setcwd(hfsvol *vol, unsigned long id) +{ +  if (getvol(&vol) == -1) +    goto fail; + +  if (id == vol->cwd) +    goto done; + +  /* make sure the directory exists */ + +  if (v_getdthread(vol, id, NULL, NULL) <= 0) +    goto fail; + +  vol->cwd = id; + +done: +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	hfs->dirinfo() + * DESCRIPTION:	given a directory ID, return its (name and) parent ID + */ +int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name) +{ +  CatDataRec thread; + +  if (getvol(&vol) == -1 || +      v_getdthread(vol, *id, &thread, NULL) <= 0) +    goto fail; + +  *id = thread.u.dthd.thdParID; + +  if (name) +    strcpy(name, thread.u.dthd.thdCName); + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	hfs->opendir() + * DESCRIPTION:	prepare to read the contents of a directory + */ +hfsdir *hfs_opendir(hfsvol *vol, const char *path) +{ +  hfsdir *dir = NULL; +  CatKeyRec key; +  CatDataRec data; +  byte pkey[HFS_CATKEYLEN]; + +  if (getvol(&vol) == -1) +    goto fail; + +  dir = ALLOC(hfsdir, 1); +  if (dir == NULL) +    ERROR(ENOMEM, NULL); + +  dir->vol = vol; + +  if (*path == 0) +    { +      /* meta-directory containing root dirs from all mounted volumes */ + +      dir->dirid = 0; +      dir->vptr  = hfs_mounts; +    } +  else +    { +      if (v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0) +	goto fail; + +      if (data.cdrType != cdrDirRec) +        ERROR(ENOTDIR, NULL); + +      dir->dirid = data.u.dir.dirDirID; +      dir->vptr  = NULL; + +      r_makecatkey(&key, dir->dirid, ""); +      r_packcatkey(&key, pkey, NULL); + +      if (bt_search(&vol->cat, pkey, &dir->n) <= 0) +	goto fail; +    } + +  dir->prev = NULL; +  dir->next = vol->dirs; + +  if (vol->dirs) +    vol->dirs->prev = dir; + +  vol->dirs = dir; + +  return dir; + +fail: +  FREE(dir); +  return NULL; +} + +/* + * NAME:	hfs->readdir() + * DESCRIPTION:	return the next entry in the directory + */ +int hfs_readdir(hfsdir *dir, hfsdirent *ent) +{ +  CatKeyRec key; +  CatDataRec data; +  const byte *ptr; + +  if (dir->dirid == 0) +    { +      hfsvol *vol; +      char cname[HFS_MAX_FLEN + 1]; + +      for (vol = hfs_mounts; vol; vol = vol->next) +	{ +	  if (vol == dir->vptr) +	    break; +	} + +      if (vol == NULL) +	ERROR(ENOENT, "no more entries"); + +      if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, NULL) <= 0 || +	  v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName, +                      &data, cname, NULL) <= 0) +	goto fail; + +      r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent); + +      dir->vptr = vol->next; + +      goto done; +    } + +  if (dir->n.rnum == -1) +    ERROR(ENOENT, "no more entries"); + +  while (1) +    { +      ++dir->n.rnum; + +      while (dir->n.rnum >= dir->n.nd.ndNRecs) +	{ +	  if (dir->n.nd.ndFLink == 0) +	    { +	      dir->n.rnum = -1; +	      ERROR(ENOENT, "no more entries"); +	    } + +	  if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1) +	    { +	      dir->n.rnum = -1; +	      goto fail; +	    } + +	  dir->n.rnum = 0; +	} + +      ptr = HFS_NODEREC(dir->n, dir->n.rnum); + +      r_unpackcatkey(ptr, &key); + +      if (key.ckrParID != dir->dirid) +	{ +	  dir->n.rnum = -1; +	  ERROR(ENOENT, "no more entries"); +	} + +      r_unpackcatdata(HFS_RECDATA(ptr), &data); + +      switch (data.cdrType) +	{ +	case cdrDirRec: +	case cdrFilRec: +	  r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent); +	  goto done; + +	case cdrThdRec: +	case cdrFThdRec: +	  break; + +	default: +	  dir->n.rnum = -1; +	  ERROR(EIO, "unexpected directory entry found"); +	} +    } + +done: +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	hfs->closedir() + * DESCRIPTION:	stop reading a directory + */ +int hfs_closedir(hfsdir *dir) +{ +  hfsvol *vol = dir->vol; + +  if (dir->prev) +    dir->prev->next = dir->next; +  if (dir->next) +    dir->next->prev = dir->prev; +  if (dir == vol->dirs) +    vol->dirs = dir->next; + +  FREE(dir); + +  return 0; +} + +/* High-Level File Routines ================================================ */ + +/* + * NAME:	hfs->open() + * DESCRIPTION:	prepare a file for I/O + */ +hfsfile *hfs_open(hfsvol *vol, const char *path) +{ +  hfsfile *file = NULL; + +  if (getvol(&vol) == -1) +    goto fail; + +  file = ALLOC(hfsfile, 1); +  if (file == NULL) +    ERROR(ENOMEM, NULL); + +  if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, NULL) <= 0) +    goto fail; + +  if (file->cat.cdrType != cdrFilRec) +    ERROR(EISDIR, NULL); + +  /* package file handle for user */ + +  file->vol   = vol; +  file->flags = 0; + +  f_selectfork(file, fkData); + +  file->prev = NULL; +  file->next = vol->files; + +  if (vol->files) +    vol->files->prev = file; + +  vol->files = file; + +  return file; + +fail: +  FREE(file); +  return NULL; +} + +/* + * NAME:	hfs->setfork() + * DESCRIPTION:	select file fork for I/O operations + */ +int hfs_setfork(hfsfile *file, int fork) +{ +  int result = 0; + +  f_selectfork(file, fork ? fkRsrc : fkData); + +  return result; +} + +/* + * NAME:	hfs->getfork() + * DESCRIPTION:	return the current fork for I/O operations + */ +int hfs_getfork(hfsfile *file) +{ +  return file->fork != fkData; +} + +/* + * NAME:	hfs->read() + * DESCRIPTION:	read from an open file + */ +unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len) +{ +  unsigned long *lglen, count; +  byte *ptr = buf; + +  f_getptrs(file, NULL, &lglen, NULL); + +  if (file->pos + len > *lglen) +    len = *lglen - file->pos; + +  count = len; +  while (count) +    { +      unsigned long bnum, offs, chunk; + +      bnum  = file->pos >> HFS_BLOCKSZ_BITS; +      offs  = file->pos & (HFS_BLOCKSZ - 1); + +      chunk = HFS_BLOCKSZ - offs; +      if (chunk > count) +	chunk = count; + +      if (offs == 0 && chunk == HFS_BLOCKSZ) +	{ +	  if (f_getblock(file, bnum, (block *) ptr) == -1) +	    goto fail; +	} +      else +	{ +	  block b; + +	  if (f_getblock(file, bnum, &b) == -1) +	    goto fail; + +	  memcpy(ptr, b + offs, chunk); +	} + +      ptr += chunk; + +      file->pos += chunk; +      count     -= chunk; +    } + +  return len; + +fail: +  return -1; +} + +/* + * NAME:	hfs->seek() + * DESCRIPTION:	change file seek pointer + */ +unsigned long hfs_seek(hfsfile *file, long offset, int from) +{ +  unsigned long *lglen, newpos; + +  f_getptrs(file, NULL, &lglen, NULL); + +  switch (from) +    { +    case HFS_SEEK_SET: +      newpos = (offset < 0) ? 0 : offset; +      break; + +    case HFS_SEEK_CUR: +      if (offset < 0 && (unsigned long) -offset > file->pos) +	newpos = 0; +      else +	newpos = file->pos + offset; +      break; + +    case HFS_SEEK_END: +      if (offset < 0 && (unsigned long) -offset > *lglen) +	newpos = 0; +      else +	newpos = *lglen + offset; +      break; + +    default: +      ERROR(EINVAL, NULL); +    } + +  if (newpos > *lglen) +    newpos = *lglen; + +  file->pos = newpos; + +  return newpos; + +fail: +  return -1; +} + +/* + * NAME:	hfs->close() + * DESCRIPTION:	close a file + */ +int hfs_close(hfsfile *file) +{ +  hfsvol *vol = file->vol; +  int result = 0; + +  if (file->prev) +    file->prev->next = file->next; +  if (file->next) +    file->next->prev = file->prev; +  if (file == vol->files) +    vol->files = file->next; + +  FREE(file); + +  return result; +} + +/* High-Level Catalog Routines ============================================= */ + +/* + * NAME:	hfs->stat() + * DESCRIPTION:	return catalog information for an arbitrary path + */ +int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent) +{ +  CatDataRec data; +  unsigned long parid; +  char name[HFS_MAX_FLEN + 1]; + +  if (getvol(&vol) == -1 || +      v_resolve(&vol, path, &data, &parid, name, NULL) <= 0) +    goto fail; + +  r_unpackdirent(parid, name, &data, ent); + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	hfs->fstat() + * DESCRIPTION:	return catalog information for an open file + */ +int hfs_fstat(hfsfile *file, hfsdirent *ent) +{ +  r_unpackdirent(file->parid, file->name, &file->cat, ent); + +  return 0; +} + +/* + * NAME:	hfs->probe() + * DESCRIPTION:	return whether a HFS filesystem is present at the given offset + */ +int hfs_probe(int fd, long long offset) +{ +  return v_probe(fd, offset); +} diff --git a/roms/openbios/fs/hfs/hfs_fs.c b/roms/openbios/fs/hfs/hfs_fs.c new file mode 100644 index 00000000..2d62ec0c --- /dev/null +++ b/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 ); +} diff --git a/roms/openbios/fs/hfs/include/apple.h b/roms/openbios/fs/hfs/include/apple.h new file mode 100644 index 00000000..3de581d8 --- /dev/null +++ b/roms/openbios/fs/hfs/include/apple.h @@ -0,0 +1,273 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: apple.h,v 1.1 1998/04/11 08:27:11 rob Exp $ + */ + +typedef signed char	Char; +typedef unsigned char	UChar; +typedef signed char	SignedByte; +typedef signed short	Integer; +typedef unsigned short	UInteger; +typedef signed long	LongInt; +typedef unsigned long	ULongInt; +typedef char		Str15[16]; +typedef char		Str31[32]; +typedef long		OSType; + +typedef struct { +  Integer	sbSig;		/* device signature (should be 0x4552) */ +  Integer	sbBlkSize;	/* block size of the device (in bytes) */ +  LongInt	sbBlkCount;	/* number of blocks on the device */ +  Integer	sbDevType;	/* reserved */ +  Integer	sbDevId;	/* reserved */ +  LongInt	sbData;		/* reserved */ +  Integer	sbDrvrCount;	/* number of driver descriptor entries */ +  LongInt	ddBlock;	/* first driver's starting block */ +  Integer	ddSize;		/* size of the driver, in 512-byte blocks */ +  Integer	ddType;		/* driver operating system type (MacOS = 1) */ +  Integer	ddPad[243];	/* additional drivers, if any */ +} Block0; + +typedef struct { +  Integer	pmSig;		/* partition signature (0x504d or 0x5453) */ +  Integer	pmSigPad;	/* reserved */ +  LongInt	pmMapBlkCnt;	/* number of blocks in partition map */ +  LongInt	pmPyPartStart;	/* first physical block of partition */ +  LongInt	pmPartBlkCnt;	/* number of blocks in partition */ +  Char		pmPartName[33];	/* partition name */ +  Char		pmParType[33];	/* partition type */ +  LongInt	pmLgDataStart;	/* first logical block of data area */ +  LongInt	pmDataCnt;	/* number of blocks in data area */ +  LongInt	pmPartStatus;	/* partition status information */ +  LongInt	pmLgBootStart;	/* first logical block of boot code */ +  LongInt	pmBootSize;	/* size of boot code, in bytes */ +  LongInt	pmBootAddr;	/* boot code load address */ +  LongInt	pmBootAddr2;	/* reserved */ +  LongInt	pmBootEntry;	/* boot code entry point */ +  LongInt	pmBootEntry2;	/* reserved */ +  LongInt	pmBootCksum;	/* boot code checksum */ +  Char		pmProcessor[17];/* processor type */ +  Integer	pmPad[188];	/* reserved */ +} Partition; + +typedef struct { +  Integer	bbID;		/* boot blocks signature */ +  LongInt	bbEntry;	/* entry point to boot code */ +  Integer	bbVersion;	/* boot blocks version number */ +  Integer	bbPageFlags;	/* used internally */ +  Str15		bbSysName;	/* System filename */ +  Str15		bbShellName;	/* Finder filename */ +  Str15		bbDbg1Name;	/* debugger filename */ +  Str15		bbDbg2Name;	/* debugger filename */ +  Str15		bbScreenName;	/* name of startup screen */ +  Str15		bbHelloName;	/* name of startup program */ +  Str15		bbScrapName;	/* name of system scrap file */ +  Integer	bbCntFCBs;	/* number of FCBs to allocate */ +  Integer	bbCntEvts;	/* number of event queue elements */ +  LongInt	bb128KSHeap;	/* system heap size on 128K Mac */ +  LongInt	bb256KSHeap;	/* used internally */ +  LongInt	bbSysHeapSize;	/* system heap size on all machines */ +  Integer	filler;		/* reserved */ +  LongInt	bbSysHeapExtra;	/* additional system heap space */ +  LongInt	bbSysHeapFract;	/* fraction of RAM for system heap */ +} BootBlkHdr; + +typedef struct { +  UInteger	xdrStABN;	/* first allocation block */ +  UInteger	xdrNumABlks;	/* number of allocation blocks */ +} ExtDescriptor; + +typedef ExtDescriptor ExtDataRec[3]; + +typedef struct { +  SignedByte	xkrKeyLen;	/* key length */ +  SignedByte	xkrFkType;	/* fork type (0x00/0xff == data/resource */ +  ULongInt	xkrFNum;	/* file number */ +  UInteger	xkrFABN;	/* starting file allocation block */ +} ExtKeyRec; + +typedef struct { +  SignedByte	ckrKeyLen;	/* key length */ +  SignedByte	ckrResrv1;	/* reserved */ +  ULongInt	ckrParID;	/* parent directory ID */ +  Str31		ckrCName;	/* catalog node name */ +} CatKeyRec; + +typedef struct { +  Integer	v;		/* vertical coordinate */ +  Integer	h;		/* horizontal coordinate */ +} Point; + +typedef struct { +  Integer	top;		/* top edge of rectangle */ +  Integer	left;		/* left edge */ +  Integer	bottom;		/* bottom edge */ +  Integer	right;		/* right edge */ +} Rect; + +typedef struct { +  Rect		frRect;		/* folder's rectangle */ +  Integer	frFlags;	/* flags */ +  Point		frLocation;	/* folder's location */ +  Integer	frView;		/* folder's view */ +} DInfo; + +typedef struct { +  Point		frScroll;	/* scroll position */ +  LongInt	frOpenChain;	/* directory ID chain of open folders */ +  Integer	frUnused;	/* reserved */ +  Integer	frComment;	/* comment ID */ +  LongInt	frPutAway;	/* directory ID */ +} DXInfo; + +typedef struct { +  OSType	fdType;		/* file type */ +  OSType	fdCreator;	/* file's creator */ +  Integer	fdFlags;	/* flags */ +  Point		fdLocation;	/* file's location */ +  Integer	fdFldr;		/* file's window */ +} FInfo; + +typedef struct { +  Integer	fdIconID;	/* icon ID */ +  Integer	fdUnused[4];	/* reserved */ +  Integer	fdComment;	/* comment ID */ +  LongInt	fdPutAway;	/* home directory ID */ +} FXInfo; + +typedef struct { +  Integer	drSigWord;	/* volume signature (0x4244 for HFS) */ +  LongInt	drCrDate;	/* date and time of volume creation */ +  LongInt	drLsMod;	/* date and time of last modification */ +  Integer	drAtrb;		/* volume attributes */ +  UInteger	drNmFls;	/* number of files in root directory */ +  UInteger	drVBMSt;	/* first block of volume bit map (always 3) */ +  UInteger	drAllocPtr;	/* start of next allocation search */ +  UInteger	drNmAlBlks;	/* number of allocation blocks in volume */ +  ULongInt	drAlBlkSiz;	/* size (in bytes) of allocation blocks */ +  ULongInt	drClpSiz;	/* default clump size */ +  UInteger	drAlBlSt;	/* first allocation block in volume */ +  LongInt	drNxtCNID;	/* next unused catalog node ID (dir/file ID) */ +  UInteger	drFreeBks;	/* number of unused allocation blocks */ +  char		drVN[28];	/* volume name (1-27 chars) */ +  LongInt	drVolBkUp;	/* date and time of last backup */ +  Integer	drVSeqNum;	/* volume backup sequence number */ +  ULongInt	drWrCnt;	/* volume write count */ +  ULongInt	drXTClpSiz;	/* clump size for extents overflow file */ +  ULongInt	drCTClpSiz;	/* clump size for catalog file */ +  UInteger	drNmRtDirs;	/* number of directories in root directory */ +  ULongInt	drFilCnt;	/* number of files in volume */ +  ULongInt	drDirCnt;	/* number of directories in volume */ +  LongInt	drFndrInfo[8];	/* information used by the Finder */ +  UInteger	drEmbedSigWord;	/* type of embedded volume */ +  ExtDescriptor	drEmbedExtent;	/* location of embedded volume */ +  ULongInt	drXTFlSize;	/* size (in bytes) of extents overflow file */ +  ExtDataRec	drXTExtRec;	/* first extent record for extents file */ +  ULongInt	drCTFlSize;	/* size (in bytes) of catalog file */ +  ExtDataRec	drCTExtRec;	/* first extent record for catalog file */ +} MDB; + +typedef enum { +  cdrDirRec  = 1, +  cdrFilRec  = 2, +  cdrThdRec  = 3, +  cdrFThdRec = 4 +} CatDataType; + +typedef struct { +  SignedByte	cdrType;	/* record type */ +  SignedByte	cdrResrv2;	/* reserved */ +  union { +    struct {  /* cdrDirRec */ +      Integer	dirFlags;	/* directory flags */ +      UInteger	dirVal;		/* directory valence */ +      ULongInt	dirDirID;	/* directory ID */ +      LongInt	dirCrDat;	/* date and time of creation */ +      LongInt	dirMdDat;	/* date and time of last modification */ +      LongInt	dirBkDat;	/* date and time of last backup */ +      DInfo	dirUsrInfo;	/* Finder information */ +      DXInfo	dirFndrInfo;	/* additional Finder information */ +      LongInt	dirResrv[4];	/* reserved */ +    } dir; +    struct {  /* cdrFilRec */ +      SignedByte +		filFlags;	/* file flags */ +      SignedByte +		filTyp;		/* file type */ +      FInfo	filUsrWds;	/* Finder information */ +      ULongInt	filFlNum;	/* file ID */ +      UInteger	filStBlk;	/* first alloc block of data fork */ +      ULongInt	filLgLen;	/* logical EOF of data fork */ +      ULongInt	filPyLen;	/* physical EOF of data fork */ +      UInteger	filRStBlk;	/* first alloc block of resource fork */ +      ULongInt	filRLgLen;	/* logical EOF of resource fork */ +      ULongInt	filRPyLen;	/* physical EOF of resource fork */ +      LongInt	filCrDat;	/* date and time of creation */ +      LongInt	filMdDat;	/* date and time of last modification */ +      LongInt	filBkDat;	/* date and time of last backup */ +      FXInfo	filFndrInfo;	/* additional Finder information */ +      UInteger	filClpSize;	/* file clump size */ +      ExtDataRec +		filExtRec;	/* first data fork extent record */ +      ExtDataRec +		filRExtRec;	/* first resource fork extent record */ +      LongInt	filResrv;	/* reserved */ +    } fil; +    struct {  /* cdrThdRec */ +      LongInt	thdResrv[2];	/* reserved */ +      ULongInt	thdParID;	/* parent ID for this directory */ +      Str31	thdCName;	/* name of this directory */ +    } dthd; +    struct {  /* cdrFThdRec */ +      LongInt	fthdResrv[2];	/* reserved */ +      ULongInt	fthdParID;	/* parent ID for this file */ +      Str31	fthdCName;	/* name of this file */ +    } fthd; +  } u; +} CatDataRec; + +typedef struct { +  ULongInt	ndFLink;	/* forward link */ +  ULongInt	ndBLink;	/* backward link */ +  SignedByte	ndType;		/* node type */ +  SignedByte	ndNHeight;	/* node level */ +  UInteger	ndNRecs;	/* number of records in node */ +  Integer	ndResv2;	/* reserved */ +} NodeDescriptor; + +enum { +  ndIndxNode = (SignedByte) 0x00, +  ndHdrNode  = (SignedByte) 0x01, +  ndMapNode  = (SignedByte) 0x02, +  ndLeafNode = (SignedByte) 0xff +}; + +typedef struct { +  UInteger	bthDepth;	/* current depth of tree */ +  ULongInt	bthRoot;	/* number of root node */ +  ULongInt	bthNRecs;	/* number of leaf records in tree */ +  ULongInt	bthFNode;	/* number of first leaf node */ +  ULongInt	bthLNode;	/* number of last leaf node */ +  UInteger	bthNodeSize;	/* size of a node */ +  UInteger	bthKeyLen;	/* maximum length of a key */ +  ULongInt	bthNNodes;	/* total number of nodes in tree */ +  ULongInt	bthFree;	/* number of free nodes */ +  SignedByte	bthResv[76];	/* reserved */ +} BTHdrRec; diff --git a/roms/openbios/fs/hfs/include/block.h b/roms/openbios/fs/hfs/include/block.h new file mode 100644 index 00000000..d7e76451 --- /dev/null +++ b/roms/openbios/fs/hfs/include/block.h @@ -0,0 +1,41 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: block.h,v 1.10 1998/11/02 22:08:53 rob Exp $ + */ + +int b_init(hfsvol *); +int b_flush(hfsvol *); +int b_finish(hfsvol *); + +int b_readpb(hfsvol *, unsigned long, block *, unsigned int); +int b_writepb(hfsvol *, unsigned long, const block *, unsigned int); + +int b_readlb(hfsvol *, unsigned long, block *); +int b_writelb(hfsvol *, unsigned long, const block *); + +int b_readab(hfsvol *, unsigned int, unsigned int, block *); +int b_writeab(hfsvol *, unsigned int, unsigned int, const block *); + +unsigned long b_size(hfsvol *); + +# ifdef DEBUG +void b_showstats(const bcache *); +void b_dumpcache(const bcache *); +# endif diff --git a/roms/openbios/fs/hfs/include/btree.h b/roms/openbios/fs/hfs/include/btree.h new file mode 100644 index 00000000..36660f53 --- /dev/null +++ b/roms/openbios/fs/hfs/include/btree.h @@ -0,0 +1,34 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: btree.h,v 1.8 1998/11/02 22:08:55 rob Exp $ + */ + +int bt_getnode(node *, btree *, unsigned long); +int bt_putnode(node *); + +int bt_readhdr(btree *); +int bt_writehdr(btree *); + +int bt_space(btree *, unsigned int); + +int bt_insert(btree *, const byte *, unsigned int); +int bt_delete(btree *, const byte *); + +int bt_search(btree *, const byte *, node *); diff --git a/roms/openbios/fs/hfs/include/data.h b/roms/openbios/fs/hfs/include/data.h new file mode 100644 index 00000000..f3e20008 --- /dev/null +++ b/roms/openbios/fs/hfs/include/data.h @@ -0,0 +1,57 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: data.h,v 1.7 1998/11/02 22:08:58 rob Exp $ + */ + +  signed  char d_getsb(register const unsigned char *); +unsigned  char d_getub(register const unsigned char *); +  signed short d_getsw(register const unsigned char *); +unsigned short d_getuw(register const unsigned char *); +  signed  long d_getsl(register const unsigned char *); +unsigned  long d_getul(register const unsigned char *); + +void d_putsb(register unsigned char *, register   signed  char); +void d_putub(register unsigned char *, register unsigned  char); +void d_putsw(register unsigned char *, register   signed short); +void d_putuw(register unsigned char *, register unsigned short); +void d_putsl(register unsigned char *, register   signed  long); +void d_putul(register unsigned char *, register unsigned  long); + +void d_fetchsb(register const unsigned char **, register   signed  char *); +void d_fetchub(register const unsigned char **, register unsigned  char *); +void d_fetchsw(register const unsigned char **, register   signed short *); +void d_fetchuw(register const unsigned char **, register unsigned short *); +void d_fetchsl(register const unsigned char **, register   signed  long *); +void d_fetchul(register const unsigned char **, register unsigned  long *); + +void d_storesb(register unsigned char **, register   signed  char); +void d_storeub(register unsigned char **, register unsigned  char); +void d_storesw(register unsigned char **, register   signed short); +void d_storeuw(register unsigned char **, register unsigned short); +void d_storesl(register unsigned char **, register   signed  long); +void d_storeul(register unsigned char **, register unsigned  long); + +void d_fetchstr(const unsigned char **, char *, unsigned); +void d_storestr(unsigned char **, const char *, unsigned); + +int d_relstring(const char *, const char *); + +time_t d_ltime(unsigned long); +unsigned long d_mtime(time_t); diff --git a/roms/openbios/fs/hfs/include/file.h b/roms/openbios/fs/hfs/include/file.h new file mode 100644 index 00000000..dacdc480 --- /dev/null +++ b/roms/openbios/fs/hfs/include/file.h @@ -0,0 +1,46 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: file.h,v 1.6 1998/04/11 08:27:12 rob Exp $ + */ + +enum { +  fkData = 0x00, +  fkRsrc = 0xff +}; + +void f_init(hfsfile *, hfsvol *, long, const char *); +void f_selectfork(hfsfile *, int); +void f_getptrs(hfsfile *, ExtDataRec **, unsigned long **, unsigned long **); + +int f_doblock(hfsfile *, unsigned long, block *, +	      int (*)(hfsvol *, unsigned int, unsigned int, block *)); + +# define f_getblock(file, num, bp)  \ +    f_doblock((file), (num), (bp), b_readab) +# define f_putblock(file, num, bp)  \ +    f_doblock((file), (num), (bp),  \ +	      (int (*)(hfsvol *, unsigned int, unsigned int, block *))  \ +	      b_writeab) + +int f_addextent(hfsfile *, ExtDescriptor *); +long f_alloc(hfsfile *); + +int f_trunc(hfsfile *); +int f_flush(hfsfile *); diff --git a/roms/openbios/fs/hfs/include/hfs.h b/roms/openbios/fs/hfs/include/hfs.h new file mode 100644 index 00000000..9996cc8d --- /dev/null +++ b/roms/openbios/fs/hfs/include/hfs.h @@ -0,0 +1,180 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: hfs.h,v 1.11 1998/11/02 22:09:01 rob Exp $ + */ + +# define HFS_BLOCKSZ		512 +# define HFS_BLOCKSZ_BITS	9 + +# define HFS_MAX_FLEN		31 +# define HFS_MAX_VLEN		27 + +typedef struct _hfsvol_  hfsvol; +typedef struct _hfsfile_ hfsfile; +typedef struct _hfsdir_  hfsdir; + +typedef struct { +  char name[HFS_MAX_VLEN + 1];	/* name of volume (MacOS Standard Roman) */ +  int flags;			/* volume flags */ + +  unsigned long totbytes;	/* total bytes on volume */ +  unsigned long freebytes;	/* free bytes on volume */ + +  unsigned long alblocksz;	/* volume allocation block size */ +  unsigned long clumpsz;	/* default file clump size */ + +  unsigned long numfiles;	/* number of files in volume */ +  unsigned long numdirs;	/* number of directories in volume */ + +  time_t crdate;		/* volume creation date */ +  time_t mddate;		/* last volume modification date */ +  time_t bkdate;		/* last volume backup date */ + +  unsigned long blessed;	/* CNID of MacOS System Folder */ +} hfsvolent; + +typedef struct { +  char name[HFS_MAX_FLEN + 1];	/* catalog name (MacOS Standard Roman) */ +  int flags;			/* bit flags */ +  unsigned long cnid;		/* catalog node id (CNID) */ +  unsigned long parid;		/* CNID of parent directory */ + +  time_t crdate;		/* date of creation */ +  time_t mddate;		/* date of last modification */ +  time_t bkdate;		/* date of last backup */ + +  short fdflags;		/* Macintosh Finder flags */ + +  struct { +    signed short v;		/* Finder icon vertical coordinate */ +    signed short h;		/* horizontal coordinate */ +  } fdlocation; + +  union { +    struct { +      unsigned long dsize;	/* size of data fork */ +      unsigned long rsize;	/* size of resource fork */ + +      char type[5];		/* file type code (plus null) */ +      char creator[5];		/* file creator code (plus null) */ +    } file; + +    struct { +      unsigned short valence;	/* number of items in directory */ + +      struct { +	signed short top;	/* top edge of folder's rectangle */ +	signed short left;	/* left edge */ +	signed short bottom;	/* bottom edge */ +	signed short right;	/* right edge */ +      } rect; +    } dir; +  } u; +} hfsdirent; + +# define HFS_ISDIR		0x0001 +# define HFS_ISLOCKED		0x0002 + +# define HFS_CNID_ROOTPAR	1 +# define HFS_CNID_ROOTDIR	2 +# define HFS_CNID_EXT		3 +# define HFS_CNID_CAT		4 +# define HFS_CNID_BADALLOC	5 + +# define HFS_FNDR_ISONDESK		(1 <<  0) +# define HFS_FNDR_COLOR			0x0e +# define HFS_FNDR_COLORRESERVED		(1 <<  4) +# define HFS_FNDR_REQUIRESSWITCHLAUNCH	(1 <<  5) +# define HFS_FNDR_ISSHARED		(1 <<  6) +# define HFS_FNDR_HASNOINITS		(1 <<  7) +# define HFS_FNDR_HASBEENINITED		(1 <<  8) +# define HFS_FNDR_RESERVED		(1 <<  9) +# define HFS_FNDR_HASCUSTOMICON		(1 << 10) +# define HFS_FNDR_ISSTATIONERY		(1 << 11) +# define HFS_FNDR_NAMELOCKED		(1 << 12) +# define HFS_FNDR_HASBUNDLE		(1 << 13) +# define HFS_FNDR_ISINVISIBLE		(1 << 14) +# define HFS_FNDR_ISALIAS		(1 << 15) + +extern const char *hfs_error; +extern const unsigned char hfs_charorder[]; + +# define HFS_MODE_RDONLY	0 +# define HFS_MODE_RDWR		1 +# define HFS_MODE_ANY		2 + +# define HFS_MODE_MASK		0x0003 + +# define HFS_OPT_NOCACHE	0x0100 +# define HFS_OPT_2048		0x0200 +# define HFS_OPT_ZERO		0x0400 + +# define HFS_SEEK_SET		0 +# define HFS_SEEK_CUR		1 +# define HFS_SEEK_END		2 + +hfsvol *hfs_mount( int os_fd, int); +int hfs_flush(hfsvol *); +void hfs_flushall(void); +int hfs_umount(hfsvol *); +void hfs_umountall(void); +hfsvol *hfs_getvol(const char *); +void hfs_setvol(hfsvol *); + +int hfs_vstat(hfsvol *, hfsvolent *); +int hfs_vsetattr(hfsvol *, hfsvolent *); + +int hfs_chdir(hfsvol *, const char *); +unsigned long hfs_getcwd(hfsvol *); +int hfs_setcwd(hfsvol *, unsigned long); +int hfs_dirinfo(hfsvol *, unsigned long *, char *); + +hfsdir *hfs_opendir(hfsvol *, const char *); +int hfs_readdir(hfsdir *, hfsdirent *); +int hfs_closedir(hfsdir *); + +hfsfile *hfs_create(hfsvol *, const char *, const char *, const char *); +hfsfile *hfs_open(hfsvol *, const char *); +int hfs_setfork(hfsfile *, int); +int hfs_getfork(hfsfile *); +unsigned long hfs_read(hfsfile *, void *, unsigned long); +unsigned long hfs_write(hfsfile *, const void *, unsigned long); +int hfs_truncate(hfsfile *, unsigned long); +unsigned long hfs_seek(hfsfile *, long, int); +int hfs_close(hfsfile *); + +int hfs_stat(hfsvol *, const char *, hfsdirent *); +int hfs_fstat(hfsfile *, hfsdirent *); +int hfs_setattr(hfsvol *, const char *, const hfsdirent *); +int hfs_fsetattr(hfsfile *, const hfsdirent *); + +int hfs_mkdir(hfsvol *, const char *); +int hfs_rmdir(hfsvol *, const char *); + +int hfs_delete(hfsvol *, const char *); +int hfs_rename(hfsvol *, const char *, const char *); + +int hfs_zero(const char *, unsigned int, unsigned long *); +int hfs_mkpart(const char *, unsigned long); +int hfs_nparts(const char *); + +int hfs_format(const char *, int, int, +	       const char *, unsigned int, const unsigned long []); +int hfs_probe(int fd, long long offset); diff --git a/roms/openbios/fs/hfs/include/libhfs.h b/roms/openbios/fs/hfs/include/libhfs.h new file mode 100644 index 00000000..f46f4383 --- /dev/null +++ b/roms/openbios/fs/hfs/include/libhfs.h @@ -0,0 +1,225 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: libhfs.h,v 1.7 1998/11/02 22:09:02 rob Exp $ + */ + +# include "hfs.h" +# include "apple.h" + +# define ERROR(code, str)  \ +    do { hfs_error = (str), errno = (code); goto fail; } while (0) + +# ifdef DEBUG +#  define ASSERT(cond)	do { if (! (cond)) abort(); } while (0) +# else +#  define ASSERT(cond)	/* nothing */ +# endif + +# define SIZE(type, n)		((size_t) (sizeof(type) * (n))) +# define ALLOC(type, n)		((type *) malloc(SIZE(type, n))) +# define ALLOCX(type, n)	((n) ? ALLOC(type, n) : (type *) 0) +# define FREE(ptr)		((ptr) ? (void) free((void *) ptr) : (void) 0) + +# define REALLOC(ptr, type, n)  \ +    ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n)))) +# define REALLOCX(ptr, type, n)  \ +    ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0)) + +# define BMTST(bm, num)  \ +    (((const byte *) (bm))[(num) >> 3]  &  (0x80 >> ((num) & 0x07))) +# define BMSET(bm, num)  \ +          (((byte *) (bm))[(num) >> 3] |=  (0x80 >> ((num) & 0x07))) +# define BMCLR(bm, num)  \ +          (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07))) + +# define STRINGIZE(x)		#x +# define STR(x)			STRINGIZE(x) + +typedef unsigned char byte; +typedef byte block[HFS_BLOCKSZ]; + +typedef struct _bucket_ { +  int flags;			/* bit flags */ +  unsigned int count;		/* number of times this block is requested */ + +  unsigned long bnum;		/* logical block number */ +  block *data;			/* pointer to block contents */ + +  struct _bucket_ *cnext;	/* next bucket in cache chain */ +  struct _bucket_ *cprev;	/* previous bucket in cache chain */ + +  struct _bucket_ *hnext;	/* next bucket in hash chain */ +  struct _bucket_ **hprev;	/* previous bucket's pointer to this bucket */ +} bucket; + +# define HFS_BUCKET_INUSE	0x01 +# define HFS_BUCKET_DIRTY	0x02 + +# define HFS_CACHESZ		128 +# define HFS_HASHSZ		32 +# define HFS_BLOCKBUFSZ		16 + +typedef struct { +  struct _hfsvol_ *vol;		/* volume to which cache belongs */ +  bucket *tail;			/* end of bucket chain */ + +  unsigned int hits;		/* number of cache hits */ +  unsigned int misses;		/* number of cache misses */ + +  bucket chain[HFS_CACHESZ];	/* cache bucket chain */ +  bucket *hash[HFS_HASHSZ];	/* hash table for bucket chain */ + +  block pool[HFS_CACHESZ];	/* physical blocks in cache */ +} bcache; + +# define HFS_MAP1SZ  256 +# define HFS_MAPXSZ  492 + +# define HFS_NODEREC(nd, rnum)	((nd).data + (nd).roff[rnum]) +# define HFS_RECLEN(nd, rnum)	((nd).roff[(rnum) + 1] - (nd).roff[rnum]) + +# define HFS_RECKEYLEN(ptr)	(*(const byte *) (ptr)) +# define HFS_RECKEYSKIP(ptr)	((size_t) ((1 + HFS_RECKEYLEN(ptr) + 1) & ~1)) +# define HFS_RECDATA(ptr)	((ptr) + HFS_RECKEYSKIP(ptr)) + +# define HFS_SETKEYLEN(ptr, x)	(*(byte *) (ptr) = (x)) + +# define HFS_CATDATALEN		sizeof(CatDataRec) +# define HFS_EXTDATALEN		sizeof(ExtDataRec) +# define HFS_MAX_DATALEN	(HFS_CATDATALEN > HFS_EXTDATALEN ?  \ +				 HFS_CATDATALEN : HFS_EXTDATALEN) + +# define HFS_CATKEYLEN		sizeof(CatKeyRec) +# define HFS_EXTKEYLEN		sizeof(ExtKeyRec) +# define HFS_MAX_KEYLEN		(HFS_CATKEYLEN > HFS_EXTKEYLEN ?  \ +				 HFS_CATKEYLEN : HFS_EXTKEYLEN) + +# define HFS_MAX_CATRECLEN	(HFS_CATKEYLEN + HFS_CATDATALEN) +# define HFS_MAX_EXTRECLEN	(HFS_EXTKEYLEN + HFS_EXTDATALEN) +# define HFS_MAX_RECLEN		(HFS_MAX_KEYLEN + HFS_MAX_DATALEN) + +# define HFS_SIGWORD		0x4244 +# define HFS_SIGWORD_MFS	((Integer) 0xd2d7) + +# define HFS_ATRB_BUSY		(1 <<  6) +# define HFS_ATRB_HLOCKED	(1 <<  7) +# define HFS_ATRB_UMOUNTED	(1 <<  8) +# define HFS_ATRB_BBSPARED	(1 <<  9) +# define HFS_ATRB_BVINCONSIS	(1 << 11) +# define HFS_ATRB_COPYPROT	(1 << 14) +# define HFS_ATRB_SLOCKED	(1 << 15) + +struct _hfsfile_ { +  struct _hfsvol_ *vol;		/* pointer to volume descriptor */ +  unsigned long parid;		/* parent directory ID of this file */ +  char name[HFS_MAX_FLEN + 1];	/* catalog name of this file */ +  CatDataRec cat;		/* catalog information */ +  ExtDataRec ext;		/* current extent record */ +  unsigned int fabn;		/* starting file allocation block number */ +  int fork;			/* current selected fork for I/O */ +  unsigned long pos;		/* current file seek pointer */ +  int flags;			/* bit flags */ + +  struct _hfsfile_ *prev; +  struct _hfsfile_ *next; +}; + +# define HFS_FILE_UPDATE_CATREC	0x01 + +# define HFS_MAX_NRECS	35	/* maximum based on minimum record size */ + +typedef struct _node_ { +  struct _btree_ *bt;		/* btree to which this node belongs */ +  unsigned long nnum;		/* node index */ +  NodeDescriptor nd;		/* node descriptor */ +  int rnum;			/* current record index */ +  UInteger roff[HFS_MAX_NRECS + 1]; +				/* record offsets */ +  block data;			/* raw contents of node */ +} node; + +struct _hfsdir_ { +  struct _hfsvol_ *vol;		/* associated volume */ +  unsigned long dirid;		/* directory ID of interest (or 0) */ + +  node n;			/* current B*-tree node */ +  struct _hfsvol_ *vptr;	/* current volume pointer */ + +  struct _hfsdir_ *prev; +  struct _hfsdir_ *next; +}; + +typedef void (*keyunpackfunc)(const byte *, void *); +typedef int (*keycomparefunc)(const void *, const void *); + +typedef struct _btree_ { +  hfsfile f;			/* subset file information */ +  node hdrnd;			/* header node */ +  BTHdrRec hdr;			/* header record */ +  byte *map;			/* usage bitmap */ +  unsigned long mapsz;		/* number of bytes in bitmap */ +  int flags;			/* bit flags */ + +  keyunpackfunc keyunpack;	/* key unpacking function */ +  keycomparefunc keycompare;	/* key comparison function */ +} btree; + +# define HFS_BT_UPDATE_HDR	0x01 + +struct _hfsvol_ { +  int os_fd;		/* OS-dependent private descriptor data */ +  int flags;		/* bit flags */ + +  int pnum;		/* ordinal HFS partition number */ +  unsigned long vstart;	/* logical block offset to start of volume */ +  unsigned long vlen;	/* number of logical blocks in volume */ +  unsigned int lpa;	/* number of logical blocks per allocation block */ + +  bcache *cache;	/* cache of recently used blocks */ + +  MDB mdb;		/* master directory block */ +  block *vbm;		/* volume bitmap */ +  unsigned short vbmsz;	/* number of blocks in bitmap */ + +  btree ext;		/* B*-tree control block for extents overflow file */ +  btree cat;		/* B*-tree control block for catalog file */ + +  unsigned long cwd;	/* directory id of current working directory */ + +  int refs;		/* number of external references to this volume */ +  hfsfile *files;	/* list of open files */ +  hfsdir *dirs;		/* list of open directories */ + +  struct _hfsvol_ *prev; +  struct _hfsvol_ *next; +}; + +# define HFS_VOL_OPEN		0x0001 +# define HFS_VOL_MOUNTED	0x0002 +# define HFS_VOL_READONLY	0x0004 +# define HFS_VOL_USINGCACHE	0x0008 + +# define HFS_VOL_UPDATE_MDB	0x0010 +# define HFS_VOL_UPDATE_ALTMDB	0x0020 +# define HFS_VOL_UPDATE_VBM	0x0040 + +# define HFS_VOL_OPT_MASK	0xff00 + +extern hfsvol *hfs_mounts; diff --git a/roms/openbios/fs/hfs/include/low.h b/roms/openbios/fs/hfs/include/low.h new file mode 100644 index 00000000..56d049a8 --- /dev/null +++ b/roms/openbios/fs/hfs/include/low.h @@ -0,0 +1,45 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: low.h,v 1.6 1998/04/11 08:27:13 rob Exp $ + */ + +# define HFS_DDR_SIGWORD	0x4552 + +# define HFS_PM_SIGWORD		0x504d +# define HFS_PM_SIGWORD_OLD	0x5453 + +# define HFS_BB_SIGWORD		0x4c4b + +# define HFS_BOOTCODE1LEN	(HFS_BLOCKSZ - 148) +# define HFS_BOOTCODE2LEN	HFS_BLOCKSZ + +# define HFS_BOOTCODELEN	(HFS_BOOTCODE1LEN + HFS_BOOTCODE2LEN) + +int l_getddr(hfsvol *, Block0 *); +int l_putddr(hfsvol *, const Block0 *); + +int l_getpmentry(hfsvol *, Partition *, unsigned long); +int l_putpmentry(hfsvol *, const Partition *, unsigned long); + +int l_getbb(hfsvol *, BootBlkHdr *, byte *); +int l_putbb(hfsvol *, const BootBlkHdr *, const byte *); + +int l_getmdb(hfsvol *, MDB *, int); +int l_putmdb(hfsvol *, const MDB *, int); diff --git a/roms/openbios/fs/hfs/include/medium.h b/roms/openbios/fs/hfs/include/medium.h new file mode 100644 index 00000000..29d97a4e --- /dev/null +++ b/roms/openbios/fs/hfs/include/medium.h @@ -0,0 +1,43 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: medium.h,v 1.3 1998/04/11 08:27:13 rob Exp $ + */ + +/* + * Partition Types: + * + * "Apple_partition_map"	partition map + * "Apple_Driver"		device driver + * "Apple_Driver43"		SCSI Manager 4.3 device driver + * "Apple_MFS"			Macintosh 64K ROM filesystem + * "Apple_HFS"			Macintosh hierarchical filesystem + * "Apple_Unix_SVR2"		Unix filesystem + * "Apple_PRODOS"		ProDOS filesystem + * "Apple_Free"			unused + * "Apple_Scratch"		empty + */ + +int m_zeroddr(hfsvol *); + +int m_zeropm(hfsvol *, unsigned int); +int m_findpmentry(hfsvol *, const char *, Partition *, unsigned long *); +int m_mkpart(hfsvol *, const char *, const char *, unsigned long); + +int m_zerobb(hfsvol *); diff --git a/roms/openbios/fs/hfs/include/node.h b/roms/openbios/fs/hfs/include/node.h new file mode 100644 index 00000000..d7367fd5 --- /dev/null +++ b/roms/openbios/fs/hfs/include/node.h @@ -0,0 +1,35 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: node.h,v 1.7 1998/11/02 22:09:06 rob Exp $ + */ + +void n_init(node *, btree *, int, int); + +int n_new(node *); +int n_free(node *); + +int n_search(node *, const byte *); + +void n_index(const node *, byte *, unsigned int *); + +void n_insertx(node *, const byte *, unsigned int); +int n_insert(node *, byte *, unsigned int *); + +int n_delete(node *, byte *, int *); diff --git a/roms/openbios/fs/hfs/include/record.h b/roms/openbios/fs/hfs/include/record.h new file mode 100644 index 00000000..283e809f --- /dev/null +++ b/roms/openbios/fs/hfs/include/record.h @@ -0,0 +1,48 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: record.h,v 1.7 1998/11/02 22:09:08 rob Exp $ + */ + +void r_packcatkey(const CatKeyRec *, byte *, unsigned int *); +void r_unpackcatkey(const byte *, CatKeyRec *); + +void r_packextkey(const ExtKeyRec *, byte *, unsigned int *); +void r_unpackextkey(const byte *, ExtKeyRec *); + +int r_comparecatkeys(const CatKeyRec *, const CatKeyRec *); +int r_compareextkeys(const ExtKeyRec *, const ExtKeyRec *); + +void r_packcatdata(const CatDataRec *, byte *, unsigned int *); +void r_unpackcatdata(const byte *, CatDataRec *); + +void r_packextdata(const ExtDataRec *, byte *, unsigned int *); +void r_unpackextdata(const byte *, ExtDataRec *); + +void r_makecatkey(CatKeyRec *, unsigned long, const char *); +void r_makeextkey(ExtKeyRec *, int, unsigned long, unsigned int); + +void r_packcatrec(const CatKeyRec *, const CatDataRec *, +		  byte *, unsigned int *); +void r_packextrec(const ExtKeyRec *, const ExtDataRec *, +		  byte *, unsigned int *); + +void r_packdirent(CatDataRec *, const hfsdirent *); +void r_unpackdirent(unsigned long, const char *, +		    const CatDataRec *, hfsdirent *); diff --git a/roms/openbios/fs/hfs/include/volume.h b/roms/openbios/fs/hfs/include/volume.h new file mode 100644 index 00000000..562c2d19 --- /dev/null +++ b/roms/openbios/fs/hfs/include/volume.h @@ -0,0 +1,71 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: volume.h,v 1.7 1998/11/02 22:09:12 rob Exp $ + */ + +#ifndef _H_VOLUME +#define _H_VOLUME + +void v_init(hfsvol *, int); + +int v_open(hfsvol *, int os_fd); +int v_flush(hfsvol *); +int v_close(hfsvol *); + +int v_same(hfsvol *, int os_fd); +int v_geometry(hfsvol *, int); + +int v_readmdb(hfsvol *); +int v_writemdb(hfsvol *); + +int v_readvbm(hfsvol *); +int v_writevbm(hfsvol *); + +int v_mount(hfsvol *); +int v_dirty(hfsvol *); + +int v_catsearch(hfsvol *, unsigned long, const char *, +		CatDataRec *, char *, node *); +int v_extsearch(hfsfile *, unsigned int, ExtDataRec *, node *); + +int v_getthread(hfsvol *, unsigned long, CatDataRec *, node *, int); + +# define v_getdthread(vol, id, thread, np)  \ +    v_getthread(vol, id, thread, np, cdrThdRec) +# define v_getfthread(vol, id, thread, np)  \ +    v_getthread(vol, id, thread, np, cdrFThdRec) + +int v_putcatrec(const CatDataRec *, node *); +int v_putextrec(const ExtDataRec *, node *); + +int v_allocblocks(hfsvol *, ExtDescriptor *); +int v_freeblocks(hfsvol *, const ExtDescriptor *); + +int v_resolve(hfsvol **vol, const char *path, +              CatDataRec *data, unsigned long *parid, char *fname, node *np); + +int v_adjvalence(hfsvol *, unsigned long, int, int); +int v_mkdir(hfsvol *, unsigned long, const char *); + +int v_scavenge(hfsvol *); + +int v_probe(int fd, long long offset); + +#endif   /* _H_VOLUME */ diff --git a/roms/openbios/fs/hfs/low.c b/roms/openbios/fs/hfs/low.c new file mode 100644 index 00000000..e0f7cb0e --- /dev/null +++ b/roms/openbios/fs/hfs/low.c @@ -0,0 +1,157 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998, 2001 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: low.c,v 1.8 1998/11/02 22:09:03 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "low.h" +#include "data.h" +#include "block.h" +#include "file.h" + +/* + * NAME:	low->getpmentry() + * DESCRIPTION:	read a partition map entry + */ +int l_getpmentry(hfsvol *vol, Partition *map, unsigned long bnum) +{ +  block b; +  const byte *ptr = b; +  int i; + +  if (b_readpb(vol, bnum, &b, 1) == -1) +    goto fail; + +  d_fetchsw(&ptr, &map->pmSig); +  d_fetchsw(&ptr, &map->pmSigPad); +  d_fetchsl(&ptr, &map->pmMapBlkCnt); +  d_fetchsl(&ptr, &map->pmPyPartStart); +  d_fetchsl(&ptr, &map->pmPartBlkCnt); + +  strncpy((char *) map->pmPartName, (const char *) ptr, 32); +  map->pmPartName[32] = 0; +  ptr += 32; + +  strncpy((char *) map->pmParType, (const char *) ptr, 32); +  map->pmParType[32] = 0; +  ptr += 32; + +  d_fetchsl(&ptr, &map->pmLgDataStart); +  d_fetchsl(&ptr, &map->pmDataCnt); +  d_fetchsl(&ptr, &map->pmPartStatus); +  d_fetchsl(&ptr, &map->pmLgBootStart); +  d_fetchsl(&ptr, &map->pmBootSize); +  d_fetchsl(&ptr, &map->pmBootAddr); +  d_fetchsl(&ptr, &map->pmBootAddr2); +  d_fetchsl(&ptr, &map->pmBootEntry); +  d_fetchsl(&ptr, &map->pmBootEntry2); +  d_fetchsl(&ptr, &map->pmBootCksum); + +  strncpy((char *) map->pmProcessor, (const char *) ptr, 16); +  map->pmProcessor[16] = 0; +  ptr += 16; + +  for (i = 0; i < 188; ++i) +    d_fetchsw(&ptr, &map->pmPad[i]); + +  ASSERT(ptr - b == HFS_BLOCKSZ); + +  return 0; + +fail: +  return -1; +} + + +/* + * NAME:	low->getmdb() + * DESCRIPTION:	read a master directory block + */ +int l_getmdb(hfsvol *vol, MDB *mdb, int backup) +{ +  block b; +  const byte *ptr = b; +  int i; + +  if (b_readlb(vol, backup ? vol->vlen - 2 : 2, &b) == -1) +    goto fail; + +  d_fetchsw(&ptr, &mdb->drSigWord); +  d_fetchsl(&ptr, &mdb->drCrDate); +  d_fetchsl(&ptr, &mdb->drLsMod); +  d_fetchsw(&ptr, &mdb->drAtrb); +  d_fetchuw(&ptr, &mdb->drNmFls); +  d_fetchuw(&ptr, &mdb->drVBMSt); +  d_fetchuw(&ptr, &mdb->drAllocPtr); +  d_fetchuw(&ptr, &mdb->drNmAlBlks); +  d_fetchul(&ptr, &mdb->drAlBlkSiz); +  d_fetchul(&ptr, &mdb->drClpSiz); +  d_fetchuw(&ptr, &mdb->drAlBlSt); +  d_fetchsl(&ptr, &mdb->drNxtCNID); +  d_fetchuw(&ptr, &mdb->drFreeBks); + +  d_fetchstr(&ptr, mdb->drVN, sizeof(mdb->drVN)); + +  ASSERT(ptr - b == 64); + +  d_fetchsl(&ptr, &mdb->drVolBkUp); +  d_fetchsw(&ptr, &mdb->drVSeqNum); +  d_fetchul(&ptr, &mdb->drWrCnt); +  d_fetchul(&ptr, &mdb->drXTClpSiz); +  d_fetchul(&ptr, &mdb->drCTClpSiz); +  d_fetchuw(&ptr, &mdb->drNmRtDirs); +  d_fetchul(&ptr, &mdb->drFilCnt); +  d_fetchul(&ptr, &mdb->drDirCnt); + +  for (i = 0; i < 8; ++i) +    d_fetchsl(&ptr, &mdb->drFndrInfo[i]); + +  ASSERT(ptr - b == 124); + +  d_fetchuw(&ptr, &mdb->drEmbedSigWord); +  d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrStABN); +  d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrNumABlks); + +  d_fetchul(&ptr, &mdb->drXTFlSize); + +  for (i = 0; i < 3; ++i) +    { +      d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrStABN); +      d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrNumABlks); +    } + +  ASSERT(ptr - b == 146); + +  d_fetchul(&ptr, &mdb->drCTFlSize); + +  for (i = 0; i < 3; ++i) +    { +      d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrStABN); +      d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrNumABlks); +    } + +  ASSERT(ptr - b == 162); + +  return 0; + +fail: +  return -1; +} diff --git a/roms/openbios/fs/hfs/medium.c b/roms/openbios/fs/hfs/medium.c new file mode 100644 index 00000000..171ba80d --- /dev/null +++ b/roms/openbios/fs/hfs/medium.c @@ -0,0 +1,84 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: medium.c,v 1.4 1998/11/02 22:09:04 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "block.h" +#include "low.h" +#include "medium.h" + + +/* + * NAME:	medium->findpmentry() + * DESCRIPTION:	locate a partition map entry + */ +int m_findpmentry(hfsvol *vol, const char *type, +		  Partition *map, unsigned long *start) +{ +  unsigned long bnum; +  int found = 0; + +  if (start && *start > 0) +    { +      bnum = *start; + +      if (bnum++ >= (unsigned long) map->pmMapBlkCnt) +	ERROR(EINVAL, "partition not found"); +    } +  else +    bnum = 1; + +  while (1) +    { +      if (l_getpmentry(vol, map, bnum) == -1) +	{ +	  found = -1; +	  goto fail; +	} + +      if (map->pmSig != HFS_PM_SIGWORD) +	{ +	  found = -1; + +	  if (map->pmSig == HFS_PM_SIGWORD_OLD) +	    ERROR(EINVAL, "old partition map format not supported"); +	  else +	    ERROR(EINVAL, "invalid partition map"); +	} + +      if (strcmp((char *) map->pmParType, type) == 0) +	{ +	  found = 1; +	  goto done; +	} + +      if (bnum++ >= (unsigned long) map->pmMapBlkCnt) +	ERROR(EINVAL, "partition not found"); +    } + +done: +  if (start) +    *start = bnum; + +fail: +  return found; +} diff --git a/roms/openbios/fs/hfs/node.c b/roms/openbios/fs/hfs/node.c new file mode 100644 index 00000000..1670f038 --- /dev/null +++ b/roms/openbios/fs/hfs/node.c @@ -0,0 +1,60 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: node.c,v 1.9 1998/11/02 22:09:05 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "node.h" +#include "data.h" +#include "btree.h" + +/* + * NAME:	node->search() + * DESCRIPTION:	locate a record in a node, or the record it should follow + */ +int n_search(node *np, const byte *pkey) +{ +  const btree *bt = np->bt; +  byte key1[HFS_MAX_KEYLEN], key2[HFS_MAX_KEYLEN]; +  int i, comp = -1; + +  bt->keyunpack(pkey, key2); + +  for (i = np->nd.ndNRecs; i--; ) +    { +      const byte *rec; + +      rec = HFS_NODEREC(*np, i); + +      if (HFS_RECKEYLEN(rec) == 0) +	continue;  /* deleted record */ + +      bt->keyunpack(rec, key1); +      comp = bt->keycompare(key1, key2); + +      if (comp <= 0) +	break; +    } + +  np->rnum = i; + +  return comp == 0; +} diff --git a/roms/openbios/fs/hfs/record.c b/roms/openbios/fs/hfs/record.c new file mode 100644 index 00000000..92a3addd --- /dev/null +++ b/roms/openbios/fs/hfs/record.c @@ -0,0 +1,553 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: record.c,v 1.9 1998/11/02 22:09:07 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "record.h" +#include "data.h" + +/* + * NAME:	record->packcatkey() + * DESCRIPTION:	pack a catalog record key + */ +void r_packcatkey(const CatKeyRec *key, byte *pkey, unsigned int *len) +{ +  const byte *start = pkey; + +  d_storesb(&pkey, key->ckrKeyLen); +  d_storesb(&pkey, key->ckrResrv1); +  d_storeul(&pkey, key->ckrParID); + +  d_storestr(&pkey, key->ckrCName, sizeof(key->ckrCName)); + +  if (len) +    *len = HFS_RECKEYSKIP(start); +} + +/* + * NAME:	record->unpackcatkey() + * DESCRIPTION:	unpack a catalog record key + */ +void r_unpackcatkey(const byte *pkey, CatKeyRec *key) +{ +  d_fetchsb(&pkey, &key->ckrKeyLen); +  d_fetchsb(&pkey, &key->ckrResrv1); +  d_fetchul(&pkey, &key->ckrParID); + +  d_fetchstr(&pkey, key->ckrCName, sizeof(key->ckrCName)); +} + +/* + * NAME:	record->packextkey() + * DESCRIPTION:	pack an extents record key + */ +void r_packextkey(const ExtKeyRec *key, byte *pkey, unsigned int *len) +{ +  const byte *start = pkey; + +  d_storesb(&pkey, key->xkrKeyLen); +  d_storesb(&pkey, key->xkrFkType); +  d_storeul(&pkey, key->xkrFNum); +  d_storeuw(&pkey, key->xkrFABN); + +  if (len) +    *len = HFS_RECKEYSKIP(start); +} + +/* + * NAME:	record->unpackextkey() + * DESCRIPTION:	unpack an extents record key + */ +void r_unpackextkey(const byte *pkey, ExtKeyRec *key) +{ +  d_fetchsb(&pkey, &key->xkrKeyLen); +  d_fetchsb(&pkey, &key->xkrFkType); +  d_fetchul(&pkey, &key->xkrFNum); +  d_fetchuw(&pkey, &key->xkrFABN); +} + +/* + * NAME:	record->comparecatkeys() + * DESCRIPTION:	compare two (packed) catalog record keys + */ +int r_comparecatkeys(const CatKeyRec *key1, const CatKeyRec *key2) +{ +  int diff; + +  diff = key1->ckrParID - key2->ckrParID; +  if (diff) +    return diff; + +  return d_relstring(key1->ckrCName, key2->ckrCName); +} + +/* + * NAME:	record->compareextkeys() + * DESCRIPTION:	compare two (packed) extents record keys + */ +int r_compareextkeys(const ExtKeyRec *key1, const ExtKeyRec *key2) +{ +  int diff; + +  diff = key1->xkrFNum - key2->xkrFNum; +  if (diff) +    return diff; + +  diff = (unsigned char) key1->xkrFkType - +         (unsigned char) key2->xkrFkType; +  if (diff) +    return diff; + +  return key1->xkrFABN - key2->xkrFABN; +} + +/* + * NAME:	record->packcatdata() + * DESCRIPTION:	pack catalog record data + */ +void r_packcatdata(const CatDataRec *data, byte *pdata, unsigned int *len) +{ +  const byte *start = pdata; +  int i; + +  d_storesb(&pdata, data->cdrType); +  d_storesb(&pdata, data->cdrResrv2); + +  switch (data->cdrType) +    { +    case cdrDirRec: +      d_storesw(&pdata, data->u.dir.dirFlags); +      d_storeuw(&pdata, data->u.dir.dirVal); +      d_storeul(&pdata, data->u.dir.dirDirID); +      d_storesl(&pdata, data->u.dir.dirCrDat); +      d_storesl(&pdata, data->u.dir.dirMdDat); +      d_storesl(&pdata, data->u.dir.dirBkDat); + +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.top); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.left); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.bottom); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.right); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frFlags); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.v); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.h); +      d_storesw(&pdata, data->u.dir.dirUsrInfo.frView); + +      d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.v); +      d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.h); +      d_storesl(&pdata, data->u.dir.dirFndrInfo.frOpenChain); +      d_storesw(&pdata, data->u.dir.dirFndrInfo.frUnused); +      d_storesw(&pdata, data->u.dir.dirFndrInfo.frComment); +      d_storesl(&pdata, data->u.dir.dirFndrInfo.frPutAway); + +      for (i = 0; i < 4; ++i) +	d_storesl(&pdata, data->u.dir.dirResrv[i]); + +      break; + +    case cdrFilRec: +      d_storesb(&pdata, data->u.fil.filFlags); +      d_storesb(&pdata, data->u.fil.filTyp); + +      d_storesl(&pdata, data->u.fil.filUsrWds.fdType); +      d_storesl(&pdata, data->u.fil.filUsrWds.fdCreator); +      d_storesw(&pdata, data->u.fil.filUsrWds.fdFlags); +      d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.v); +      d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.h); +      d_storesw(&pdata, data->u.fil.filUsrWds.fdFldr); + +      d_storeul(&pdata, data->u.fil.filFlNum); + +      d_storeuw(&pdata, data->u.fil.filStBlk); +      d_storeul(&pdata, data->u.fil.filLgLen); +      d_storeul(&pdata, data->u.fil.filPyLen); + +      d_storeuw(&pdata, data->u.fil.filRStBlk); +      d_storeul(&pdata, data->u.fil.filRLgLen); +      d_storeul(&pdata, data->u.fil.filRPyLen); + +      d_storesl(&pdata, data->u.fil.filCrDat); +      d_storesl(&pdata, data->u.fil.filMdDat); +      d_storesl(&pdata, data->u.fil.filBkDat); + +      d_storesw(&pdata, data->u.fil.filFndrInfo.fdIconID); +      for (i = 0; i < 4; ++i) +	d_storesw(&pdata, data->u.fil.filFndrInfo.fdUnused[i]); +      d_storesw(&pdata, data->u.fil.filFndrInfo.fdComment); +      d_storesl(&pdata, data->u.fil.filFndrInfo.fdPutAway); + +      d_storeuw(&pdata, data->u.fil.filClpSize); + +      for (i = 0; i < 3; ++i) +	{ +	  d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrStABN); +	  d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrNumABlks); +	} + +      for (i = 0; i < 3; ++i) +	{ +	  d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrStABN); +	  d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks); +	} + +      d_storesl(&pdata, data->u.fil.filResrv); + +      break; + +    case cdrThdRec: +      for (i = 0; i < 2; ++i) +	d_storesl(&pdata, data->u.dthd.thdResrv[i]); + +      d_storeul(&pdata, data->u.dthd.thdParID); + +      d_storestr(&pdata, data->u.dthd.thdCName, +		 sizeof(data->u.dthd.thdCName)); + +      break; + +    case cdrFThdRec: +      for (i = 0; i < 2; ++i) +	d_storesl(&pdata, data->u.fthd.fthdResrv[i]); + +      d_storeul(&pdata, data->u.fthd.fthdParID); + +      d_storestr(&pdata, data->u.fthd.fthdCName, +		 sizeof(data->u.fthd.fthdCName)); + +      break; + +    default: +      ASSERT(0); +    } + +  if (len) +    *len += pdata - start; +} + +/* + * NAME:	record->unpackcatdata() + * DESCRIPTION:	unpack catalog record data + */ +void r_unpackcatdata(const byte *pdata, CatDataRec *data) +{ +  int i; + +  d_fetchsb(&pdata, &data->cdrType); +  d_fetchsb(&pdata, &data->cdrResrv2); + +  switch (data->cdrType) +    { +    case cdrDirRec: +      d_fetchsw(&pdata, &data->u.dir.dirFlags); +      d_fetchuw(&pdata, &data->u.dir.dirVal); +      d_fetchul(&pdata, &data->u.dir.dirDirID); +      d_fetchsl(&pdata, &data->u.dir.dirCrDat); +      d_fetchsl(&pdata, &data->u.dir.dirMdDat); +      d_fetchsl(&pdata, &data->u.dir.dirBkDat); + +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.top); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.left); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.right); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frFlags); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h); +      d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frView); + +      d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v); +      d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h); +      d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain); +      d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frUnused); +      d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frComment); +      d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frPutAway); + +      for (i = 0; i < 4; ++i) +	d_fetchsl(&pdata, &data->u.dir.dirResrv[i]); + +      break; + +    case cdrFilRec: +      d_fetchsb(&pdata, &data->u.fil.filFlags); +      d_fetchsb(&pdata, &data->u.fil.filTyp); + +      d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdType); +      d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdCreator); +      d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFlags); +      d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.v); +      d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.h); +      d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFldr); + +      d_fetchul(&pdata, &data->u.fil.filFlNum); + +      d_fetchuw(&pdata, &data->u.fil.filStBlk); +      d_fetchul(&pdata, &data->u.fil.filLgLen); +      d_fetchul(&pdata, &data->u.fil.filPyLen); + +      d_fetchuw(&pdata, &data->u.fil.filRStBlk); +      d_fetchul(&pdata, &data->u.fil.filRLgLen); +      d_fetchul(&pdata, &data->u.fil.filRPyLen); + +      d_fetchsl(&pdata, &data->u.fil.filCrDat); +      d_fetchsl(&pdata, &data->u.fil.filMdDat); +      d_fetchsl(&pdata, &data->u.fil.filBkDat); + +      d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdIconID); +      for (i = 0; i < 4; ++i) +	d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]); +      d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdComment); +      d_fetchsl(&pdata, &data->u.fil.filFndrInfo.fdPutAway); + +      d_fetchuw(&pdata, &data->u.fil.filClpSize); + +      for (i = 0; i < 3; ++i) +	{ +	  d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrStABN); +	  d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrNumABlks); +	} + +      for (i = 0; i < 3; ++i) +	{ +	  d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrStABN); +	  d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrNumABlks); +	} + +      d_fetchsl(&pdata, &data->u.fil.filResrv); + +      break; + +    case cdrThdRec: +      for (i = 0; i < 2; ++i) +	d_fetchsl(&pdata, &data->u.dthd.thdResrv[i]); + +      d_fetchul(&pdata, &data->u.dthd.thdParID); + +      d_fetchstr(&pdata, data->u.dthd.thdCName, +		 sizeof(data->u.dthd.thdCName)); + +      break; + +    case cdrFThdRec: +      for (i = 0; i < 2; ++i) +	d_fetchsl(&pdata, &data->u.fthd.fthdResrv[i]); + +      d_fetchul(&pdata, &data->u.fthd.fthdParID); + +      d_fetchstr(&pdata, data->u.fthd.fthdCName, +		 sizeof(data->u.fthd.fthdCName)); + +      break; + +    default: +      ASSERT(0); +    } +} + +/* + * NAME:	record->packextdata() + * DESCRIPTION:	pack extent record data + */ +void r_packextdata(const ExtDataRec *data, byte *pdata, unsigned int *len) +{ +  const byte *start = pdata; +  int i; + +  for (i = 0; i < 3; ++i) +    { +      d_storeuw(&pdata, (*data)[i].xdrStABN); +      d_storeuw(&pdata, (*data)[i].xdrNumABlks); +    } + +  if (len) +    *len += pdata - start; +} + +/* + * NAME:	record->unpackextdata() + * DESCRIPTION:	unpack extent record data + */ +void r_unpackextdata(const byte *pdata, ExtDataRec *data) +{ +  int i; + +  for (i = 0; i < 3; ++i) +    { +      d_fetchuw(&pdata, &(*data)[i].xdrStABN); +      d_fetchuw(&pdata, &(*data)[i].xdrNumABlks); +    } +} + +/* + * NAME:	record->makecatkey() + * DESCRIPTION:	construct a catalog record key + */ +void r_makecatkey(CatKeyRec *key, unsigned long parid, const char *name) +{ +  int len; + +  len = strlen(name) + 1; + +  key->ckrKeyLen = 0x05 + len + (len & 1); +  key->ckrResrv1 = 0; +  key->ckrParID  = parid; + +  strcpy(key->ckrCName, name); +} + +/* + * NAME:	record->makeextkey() + * DESCRIPTION:	construct an extents record key + */ +void r_makeextkey(ExtKeyRec *key, +		  int fork, unsigned long fnum, unsigned int fabn) +{ +  key->xkrKeyLen = 0x07; +  key->xkrFkType = fork; +  key->xkrFNum   = fnum; +  key->xkrFABN   = fabn; +} + +/* + * NAME:	record->packcatrec() + * DESCRIPTION:	create a packed catalog record + */ +void r_packcatrec(const CatKeyRec *key, const CatDataRec *data, +		  byte *precord, unsigned int *len) +{ +  r_packcatkey(key, precord, len); +  r_packcatdata(data, HFS_RECDATA(precord), len); +} + +/* + * NAME:	record->packextrec() + * DESCRIPTION:	create a packed extents record + */ +void r_packextrec(const ExtKeyRec *key, const ExtDataRec *data, +		  byte *precord, unsigned int *len) +{ +  r_packextkey(key, precord, len); +  r_packextdata(data, HFS_RECDATA(precord), len); +} + +/* + * NAME:	record->packdirent() + * DESCRIPTION:	make changes to a catalog record + */ +void r_packdirent(CatDataRec *data, const hfsdirent *ent) +{ +  switch (data->cdrType) +    { +    case cdrDirRec: +      data->u.dir.dirCrDat = d_mtime(ent->crdate); +      data->u.dir.dirMdDat = d_mtime(ent->mddate); +      data->u.dir.dirBkDat = d_mtime(ent->bkdate); + +      data->u.dir.dirUsrInfo.frFlags      = ent->fdflags; +      data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v; +      data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h; + +      data->u.dir.dirUsrInfo.frRect.top    = ent->u.dir.rect.top; +      data->u.dir.dirUsrInfo.frRect.left   = ent->u.dir.rect.left; +      data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom; +      data->u.dir.dirUsrInfo.frRect.right  = ent->u.dir.rect.right; + +      break; + +    case cdrFilRec: +      if (ent->flags & HFS_ISLOCKED) +	data->u.fil.filFlags |=  (1 << 0); +      else +	data->u.fil.filFlags &= ~(1 << 0); + +      data->u.fil.filCrDat = d_mtime(ent->crdate); +      data->u.fil.filMdDat = d_mtime(ent->mddate); +      data->u.fil.filBkDat = d_mtime(ent->bkdate); + +      data->u.fil.filUsrWds.fdFlags      = ent->fdflags; +      data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v; +      data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h; + +      data->u.fil.filUsrWds.fdType = +	d_getsl((const unsigned char *) ent->u.file.type); +      data->u.fil.filUsrWds.fdCreator = +	d_getsl((const unsigned char *) ent->u.file.creator); + +      break; +    } +} + +/* + * NAME:	record->unpackdirent() + * DESCRIPTION:	unpack catalog information into hfsdirent structure + */ +void r_unpackdirent(unsigned long parid, const char *name, +		    const CatDataRec *data, hfsdirent *ent) +{ +  strcpy(ent->name, name); +  ent->parid = parid; + +  switch (data->cdrType) +    { +    case cdrDirRec: +      ent->flags = HFS_ISDIR; +      ent->cnid  = data->u.dir.dirDirID; + +      ent->crdate = d_ltime(data->u.dir.dirCrDat); +      ent->mddate = d_ltime(data->u.dir.dirMdDat); +      ent->bkdate = d_ltime(data->u.dir.dirBkDat); + +      ent->fdflags      = data->u.dir.dirUsrInfo.frFlags; +      ent->fdlocation.v = data->u.dir.dirUsrInfo.frLocation.v; +      ent->fdlocation.h = data->u.dir.dirUsrInfo.frLocation.h; + +      ent->u.dir.valence = data->u.dir.dirVal; + +      ent->u.dir.rect.top    = data->u.dir.dirUsrInfo.frRect.top; +      ent->u.dir.rect.left   = data->u.dir.dirUsrInfo.frRect.left; +      ent->u.dir.rect.bottom = data->u.dir.dirUsrInfo.frRect.bottom; +      ent->u.dir.rect.right  = data->u.dir.dirUsrInfo.frRect.right; + +      break; + +    case cdrFilRec: +      ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0; +      ent->cnid  = data->u.fil.filFlNum; + +      ent->crdate = d_ltime(data->u.fil.filCrDat); +      ent->mddate = d_ltime(data->u.fil.filMdDat); +      ent->bkdate = d_ltime(data->u.fil.filBkDat); + +      ent->fdflags      = data->u.fil.filUsrWds.fdFlags; +      ent->fdlocation.v = data->u.fil.filUsrWds.fdLocation.v; +      ent->fdlocation.h = data->u.fil.filUsrWds.fdLocation.h; + +      ent->u.file.dsize = data->u.fil.filLgLen; +      ent->u.file.rsize = data->u.fil.filRLgLen; + +      d_putsl((unsigned char *) ent->u.file.type, +	      data->u.fil.filUsrWds.fdType); +      d_putsl((unsigned char *) ent->u.file.creator, +	     data->u.fil.filUsrWds.fdCreator); + +      ent->u.file.type[4] = ent->u.file.creator[4] = 0; + +      break; +    } +} diff --git a/roms/openbios/fs/hfs/volume.c b/roms/openbios/fs/hfs/volume.c new file mode 100644 index 00000000..4faf7e6c --- /dev/null +++ b/roms/openbios/fs/hfs/volume.c @@ -0,0 +1,612 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: volume.c,v 1.12 1998/11/02 22:09:10 rob Exp $ + */ + +#include "config.h" +#include "libhfs.h" +#include "volume.h" +#include "data.h" +#include "block.h" +#include "low.h" +#include "medium.h" +#include "file.h" +#include "btree.h" +#include "record.h" +#include "os.h" + +#include "libc/byteorder.h" + +/* + * NAME:	vol->init() + * DESCRIPTION:	initialize volume structure + */ +void v_init(hfsvol *vol, int flags) +{ +  btree *ext = &vol->ext; +  btree *cat = &vol->cat; + +  vol->os_fd       = 0; +  vol->flags      = flags & HFS_VOL_OPT_MASK; + +  vol->pnum       = -1; +  vol->vstart     = 0; +  vol->vlen       = 0; +  vol->lpa        = 0; + +  vol->cache      = NULL; + +  vol->vbm        = NULL; +  vol->vbmsz      = 0; + +  f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow"); + +  ext->map        = NULL; +  ext->mapsz      = 0; +  ext->flags      = 0; + +  ext->keyunpack  = (keyunpackfunc)  r_unpackextkey; +  ext->keycompare = (keycomparefunc) r_compareextkeys; + +  f_init(&cat->f, vol, HFS_CNID_CAT, "catalog"); + +  cat->map        = NULL; +  cat->mapsz      = 0; +  cat->flags      = 0; + +  cat->keyunpack  = (keyunpackfunc)  r_unpackcatkey; +  cat->keycompare = (keycomparefunc) r_comparecatkeys; + +  vol->cwd        = HFS_CNID_ROOTDIR; + +  vol->refs       = 0; +  vol->files      = NULL; +  vol->dirs       = NULL; + +  vol->prev       = NULL; +  vol->next       = NULL; +} + +/* + * NAME:	vol->open() + * DESCRIPTION:	open volume source and lock against concurrent updates + */ +int v_open(hfsvol *vol, int os_fd ) +{ +  if (vol->flags & HFS_VOL_OPEN) +    ERROR(EINVAL, "volume already open"); + +  vol->flags |= HFS_VOL_OPEN; +  vol->os_fd = os_fd; + +  /* initialize volume block cache (OK to fail) */ + +  if (! (vol->flags & HFS_OPT_NOCACHE) && +      b_init(vol) != -1) +    vol->flags |= HFS_VOL_USINGCACHE; + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	vol->close() + * DESCRIPTION:	close access path to volume source + */ +int v_close(hfsvol *vol) +{ +  int result = 0; + +  if (! (vol->flags & HFS_VOL_OPEN)) +    goto done; + +  if ((vol->flags & HFS_VOL_USINGCACHE) && +      b_finish(vol) == -1) +    result = -1; + +  vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE); + +  /* free dynamically allocated structures */ + +  FREE(vol->vbm); + +  vol->vbm   = NULL; +  vol->vbmsz = 0; + +  FREE(vol->ext.map); +  FREE(vol->cat.map); + +  vol->ext.map = NULL; +  vol->cat.map = NULL; + +done: +  return result; +} + +/* + * NAME:	vol->same() + * DESCRIPTION:	return 1 iff path is same as open volume + */ +int v_same(hfsvol *vol, int os_fd ) +{ +  return vol->os_fd == os_fd; +} + +/* + * NAME:	vol->geometry() + * DESCRIPTION:	determine volume location and size (possibly in a partition) + */ +int v_geometry(hfsvol *vol, int pnum) +{ +  Partition map; +  unsigned long bnum = 0; +  int found; + +  vol->pnum = pnum; + +  if (pnum == 0) +    { +      vol->vstart = 0; +      vol->vlen   = b_size(vol); + +      if (vol->vlen == 0) +	goto fail; +    } +  else +    { +      while (pnum--) +	{ +	  found = m_findpmentry(vol, "Apple_HFS", &map, &bnum); +	  if (found == -1 || ! found) +	    goto fail; +	} + +      vol->vstart = map.pmPyPartStart; +      vol->vlen   = map.pmPartBlkCnt; + +      if (map.pmDataCnt) +	{ +	  if ((unsigned long) map.pmLgDataStart + +	      (unsigned long) map.pmDataCnt > vol->vlen) +	    ERROR(EINVAL, "partition data overflows partition"); + +	  vol->vstart += (unsigned long) map.pmLgDataStart; +	  vol->vlen    = map.pmDataCnt; +	} + +      if (vol->vlen == 0) +	ERROR(EINVAL, "volume partition is empty"); +    } + +  if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS)) +    ERROR(EINVAL, "volume is smaller than 800K"); + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	vol->readmdb() + * DESCRIPTION:	load Master Directory Block into memory + */ +int v_readmdb(hfsvol *vol) +{ +  if (l_getmdb(vol, &vol->mdb, 0) == -1) +    goto fail; + +  if (vol->mdb.drSigWord != HFS_SIGWORD) +    { +      if (vol->mdb.drSigWord == HFS_SIGWORD_MFS) +	ERROR(EINVAL, "MFS volume format not supported"); +      else +	ERROR(EINVAL, "not a Macintosh HFS volume"); +    } + +  if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0) +    ERROR(EINVAL, "bad volume allocation block size"); + +  vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS; + +  /* extents pseudo-file structs */ + +  vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN; +  vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize; +  vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize; + +  vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; +  vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; + +  memcpy(&vol->ext.f.cat.u.fil.filExtRec, +	 &vol->mdb.drXTExtRec, sizeof(ExtDataRec)); + +  f_selectfork(&vol->ext.f, fkData); + +  /* catalog pseudo-file structs */ + +  vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN; +  vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize; +  vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize; + +  vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; +  vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; + +  memcpy(&vol->cat.f.cat.u.fil.filExtRec, +	 &vol->mdb.drCTExtRec, sizeof(ExtDataRec)); + +  f_selectfork(&vol->cat.f, fkData); + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	vol->readvbm() + * DESCRIPTION:	read volume bitmap into memory + */ +int v_readvbm(hfsvol *vol) +{ +  unsigned int vbmst = vol->mdb.drVBMSt; +  unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12; +  block *bp; + +  ASSERT(vol->vbm == 0); + +  if (vol->mdb.drAlBlSt - vbmst < vbmsz) +    ERROR(EIO, "volume bitmap collides with volume data"); + +  vol->vbm = ALLOC(block, vbmsz); +  if (vol->vbm == NULL) +    ERROR(ENOMEM, NULL); + +  vol->vbmsz = vbmsz; + +  for (bp = vol->vbm; vbmsz--; ++bp) +    { +      if (b_readlb(vol, vbmst++, bp) == -1) +	goto fail; +    } + +  return 0; + +fail: +  FREE(vol->vbm); + +  vol->vbm   = NULL; +  vol->vbmsz = 0; + +  return -1; +} + +/* + * NAME:	vol->mount() + * DESCRIPTION:	load volume information into memory + */ +int v_mount(hfsvol *vol) +{ +  /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */ + +  if (v_readmdb(vol) == -1 || +      v_readvbm(vol) == -1 || +      bt_readhdr(&vol->ext) == -1 || +      bt_readhdr(&vol->cat) == -1) +    goto fail; + +  if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED) +    vol->flags |= HFS_VOL_READONLY; +  else if (vol->flags & HFS_VOL_READONLY) +    vol->mdb.drAtrb |= HFS_ATRB_HLOCKED; +  else +    vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED; + +  vol->flags |= HFS_VOL_MOUNTED; + +  return 0; + +fail: +  return -1; +} + +/* + * NAME:	vol->catsearch() + * DESCRIPTION:	search catalog tree + */ +int v_catsearch(hfsvol *vol, unsigned long parid, const char *name, +		CatDataRec *data, char *cname, node *np) +{ +  CatKeyRec key; +  byte pkey[HFS_CATKEYLEN]; +  const byte *ptr; +  node n; +  int found; + +  if (np == NULL) +    np = &n; + +  r_makecatkey(&key, parid, name); +  r_packcatkey(&key, pkey, NULL); + +  found = bt_search(&vol->cat, pkey, np); +  if (found <= 0) +    return found; + +  ptr = HFS_NODEREC(*np, np->rnum); + +  if (cname) +    { +      r_unpackcatkey(ptr, &key); +      strcpy(cname, key.ckrCName); +    } + +  if (data) +    r_unpackcatdata(HFS_RECDATA(ptr), data); + +  return 1; +} + +/* + * NAME:	vol->extsearch() + * DESCRIPTION:	search extents tree + */ +int v_extsearch(hfsfile *file, unsigned int fabn, +		ExtDataRec *data, node *np) +{ +  ExtKeyRec key; +  ExtDataRec extsave; +  unsigned int fabnsave; +  byte pkey[HFS_EXTKEYLEN]; +  const byte *ptr; +  node n; +  int found; + +  if (np == NULL) +    np = &n; + +  r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn); +  r_packextkey(&key, pkey, NULL); + +  /* in case bt_search() clobbers these */ + +  memcpy(&extsave, &file->ext, sizeof(ExtDataRec)); +  fabnsave = file->fabn; + +  found = bt_search(&file->vol->ext, pkey, np); + +  memcpy(&file->ext, &extsave, sizeof(ExtDataRec)); +  file->fabn = fabnsave; + +  if (found <= 0) +    return found; + +  if (data) +    { +      ptr = HFS_NODEREC(*np, np->rnum); +      r_unpackextdata(HFS_RECDATA(ptr), data); +    } + +  return 1; +} + +/* + * NAME:	vol->getthread() + * DESCRIPTION:	retrieve catalog thread information for a file or directory + */ +int v_getthread(hfsvol *vol, unsigned long id, +		CatDataRec *thread, node *np, int type) +{ +  CatDataRec rec; +  int found; + +  if (thread == NULL) +    thread = &rec; + +  found = v_catsearch(vol, id, "", thread, NULL, np); +  if (found == 1 && thread->cdrType != type) +    ERROR(EIO, "bad thread record"); + +  return found; + +fail: +  return -1; +} + + +/* + * NAME:	vol->resolve() + * DESCRIPTION:	translate a pathname; return catalog information + */ +int v_resolve(hfsvol **vol, const char *path, +              CatDataRec *data, unsigned long *parid, char *fname, node *np) +{ +  unsigned long dirid; +  char name[HFS_MAX_FLEN + 1], *nptr; +  int found = 0; + +  if (*path == 0) +    ERROR(ENOENT, "empty path"); + +  if (parid) +    *parid = 0; + +  nptr = strchr(path, ':'); + +  if (*path == ':' || nptr == NULL) +    { +      dirid = (*vol)->cwd;  /* relative path */ + +      if (*path == ':') +	++path; + +      if (*path == 0) +	{ +          found = v_getdthread(*vol, dirid, data, NULL); +	  if (found == -1) +	    goto fail; + +	  if (found) +	    { +	      if (parid) +		*parid = data->u.dthd.thdParID; + +	      found = v_catsearch(*vol, data->u.dthd.thdParID, +				  data->u.dthd.thdCName, data, fname, np); +	      if (found == -1) +		goto fail; +	    } + +	  goto done; +	} +    } +  else +    { +      hfsvol *check; + +      dirid = HFS_CNID_ROOTPAR;  /* absolute path */ + +      if (nptr - path > HFS_MAX_VLEN) +        ERROR(ENAMETOOLONG, NULL); + +      strncpy(name, path, nptr - path); +      name[nptr - path] = 0; + +      for (check = hfs_mounts; check; check = check->next) +	{ +	  if (d_relstring(check->mdb.drVN, name) == 0) +	    { +	      *vol = check; +	      break; +	    } +	} +    } + +  while (1) +    { +      while (*path == ':') +	{ +	  ++path; + +          found = v_getdthread(*vol, dirid, data, NULL); +	  if (found == -1) +	    goto fail; +	  else if (! found) +	    goto done; + +	  dirid = data->u.dthd.thdParID; +	} + +      if (*path == 0) +	{ +          found = v_getdthread(*vol, dirid, data, NULL); +	  if (found == -1) +	    goto fail; + +	  if (found) +	    { +	      if (parid) +		*parid = data->u.dthd.thdParID; + +	      found = v_catsearch(*vol, data->u.dthd.thdParID, +				  data->u.dthd.thdCName, data, fname, np); +	      if (found == -1) +		goto fail; +	    } + +	  goto done; +	} + +      nptr = name; +      while (nptr < name + sizeof(name) - 1 && *path && *path != ':') +	*nptr++ = *path++; + +      if (*path && *path != ':') +        ERROR(ENAMETOOLONG, NULL); + +      *nptr = 0; +      if (*path == ':') +	++path; + +      if (parid) +	*parid = dirid; + +      found = v_catsearch(*vol, dirid, name, data, fname, np); +      if (found == -1) +	goto fail; + +      if (! found) +	{ +	  if (*path && parid) +	    *parid = 0; + +	  if (*path == 0 && fname) +	    strcpy(fname, name); + +	  goto done; +	} + +      switch (data->cdrType) +	{ +	case cdrDirRec: +	  if (*path == 0) +	    goto done; + +	  dirid = data->u.dir.dirDirID; +	  break; + +	case cdrFilRec: +	  if (*path == 0) +	    goto done; + +	  ERROR(ENOTDIR, "invalid pathname"); + +	default: +	  ERROR(EIO, "unexpected catalog record"); +	} +    } + +done: +  return found; + +fail: +  return -1; +} + +/* Determine whether the volume is a HFS volume */ +int +v_probe(int fd, long long offset) +{ +	MDB *mdb; + +	mdb = (MDB*)malloc(2 * 512); +	os_seek_offset( fd, 2 * 512 + offset ); +	os_read(fd, mdb, 2, 9); + +	if (__be16_to_cpu(mdb->drSigWord) != HFS_SIGWORD) { +		free(mdb); +		return 0; +	} + +	free(mdb); +	return -1; +} diff --git a/roms/openbios/fs/hfs_mdb.h b/roms/openbios/fs/hfs_mdb.h new file mode 100644 index 00000000..652525d9 --- /dev/null +++ b/roms/openbios/fs/hfs_mdb.h @@ -0,0 +1,118 @@ +/* + *   Creation Date: <2000/09/03 23:04:27 samuel> + *   Time-stamp: <2000/09/04 01:23:55 samuel> + * + *	<hfs_mdb.h> + * + *	HFS Master Directory Block (MDB) + * + *   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 + * + */ + +#ifndef _H_HFS_MDB +#define _H_HFS_MDB + +#include "libc/byteorder.h" + +typedef unsigned char hfs_char_t; +typedef unsigned char hfs_ushort_t[2]; +typedef unsigned char hfs_uint_t[4]; + +static inline unsigned short hfs_get_ushort(hfs_ushort_t addr) +{ +	return __be16_to_cpu(*((unsigned short *)(addr))); +} + +static inline unsigned int hfs_get_uint(hfs_uint_t addr) +{ +	return __be32_to_cpu(*((unsigned int *)(addr))); +} + +/* + * The HFS Master Directory Block (MDB). + * + * Also known as the Volume Information Block (VIB), this structure is + * the HFS equivalent of a superblock. + * + * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62 + * + * modified for HFS Extended + */ + +typedef struct hfs_mdb { +	hfs_ushort_t	drSigWord;	/* Signature word indicating fs type */ +	hfs_uint_t	drCrDate;	/* fs creation date/time */ +	hfs_uint_t	drLsMod;	/* fs modification date/time */ +	hfs_ushort_t	drAtrb;		/* fs attributes */ +	hfs_ushort_t	drNmFls;	/* number of files in root directory */ +	hfs_ushort_t	drVBMSt;	/* location (in 512-byte blocks) +					   of the volume bitmap */ +	hfs_ushort_t	drAllocPtr;	/* location (in allocation blocks) +					   to begin next allocation search */ +	hfs_ushort_t	drNmAlBlks;	/* number of allocation blocks */ +	hfs_uint_t	drAlBlkSiz;	/* bytes in an allocation block */ +	hfs_uint_t	drClpSiz;	/* clumpsize, the number of bytes to +					   allocate when extending a file */ +	hfs_ushort_t	drAlBlSt;	/* location (in 512-byte blocks) +					   of the first allocation block */ +	hfs_uint_t	drNxtCNID;	/* CNID to assign to the next +					   file or directory created */ +	hfs_ushort_t	drFreeBks;	/* number of free allocation blocks */ +	hfs_char_t	drVN[28];	/* the volume label */ +	hfs_uint_t	drVolBkUp;	/* fs backup date/time */ +	hfs_ushort_t	drVSeqNum;	/* backup sequence number */ +	hfs_uint_t	drWrCnt;	/* fs write count */ +	hfs_uint_t	drXTClpSiz;	/* clumpsize for the extents B-tree */ +	hfs_uint_t	drCTClpSiz;	/* clumpsize for the catalog B-tree */ +	hfs_ushort_t	drNmRtDirs;	/* number of directories in +					   the root directory */ +	hfs_uint_t	drFilCnt;	/* number of files in the fs */ +	hfs_uint_t	drDirCnt;	/* number of directories in the fs */ +	hfs_char_t	drFndrInfo[32];	/* data used by the Finder */ +	hfs_ushort_t	drEmbedSigWord;	/* embedded volume signature */ +	hfs_uint_t	drEmbedExtent;  /* starting block number (xdrStABN) +					   and number of allocation blocks +					   (xdrNumABlks) occupied by embedded +					   volume */ +	hfs_uint_t	drXTFlSize;	/* bytes in the extents B-tree */ +	hfs_char_t	drXTExtRec[12];	/* extents B-tree's first 3 extents */ +	hfs_uint_t	drCTFlSize;	/* bytes in the catalog B-tree */ +	hfs_char_t	drCTExtRec[12];	/* catalog B-tree's first 3 extents */ +} hfs_mdb_t; + +#define HFS_PLUS_SIGNATURE	0x482b		/* 'H+' */ +#define HFS_SIGNATURE		0x4244		/* HFS / embedded HFS+ */ + + +typedef struct hfs_plus_mdb +{ +	unsigned short	signature; +	unsigned short	version; +	unsigned int	attributes; +	unsigned int	lastMountedVersion; +	unsigned int	reserved; + +	unsigned int	createDate; +	unsigned int	modifyDate; +	unsigned int	backupDate; +	unsigned int	checkedDate; + +	unsigned int	fileCount; +	unsigned int	folderCount; + +	unsigned int	blockSize; +	unsigned int	totalBlocks; +	unsigned int	freeBlocks; + +	unsigned int	nextAllocation; +	unsigned int	rsrcClumpSize; +	unsigned int	dataClumpSize; + +	/* ... there are more fields here ... */ +} hfs_plus_mdb_t; + + +#endif   /* _H_HFS_MDB */ diff --git a/roms/openbios/fs/hfsplus/build.xml b/roms/openbios/fs/hfsplus/build.xml new file mode 100644 index 00000000..5f4c2886 --- /dev/null +++ b/roms/openbios/fs/hfsplus/build.xml @@ -0,0 +1,11 @@ +<build> + <library name="fs" type="static" target="target"> +  <object source="hfsp_blockiter.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="hfsp_btree.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="libhfsp.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="hfsp_record.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="hfsp_unicode.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="hfsp_volume.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> +  <object source="hfsp_fs.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> + </library> +</build> diff --git a/roms/openbios/fs/hfsplus/hfsp_blockiter.c b/roms/openbios/fs/hfsplus/hfsp_blockiter.c new file mode 100644 index 00000000..e9100922 --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_blockiter.c @@ -0,0 +1,141 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * The iterator shown here iterates over the blocks of a fork. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original work by 1996-1998 Robert Leslie <rob@mars.org> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: blockiter.c,v 1.2 2000/10/17 05:58:46 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "blockiter.h" +#include "volume.h" +#include "record.h" +#include "btree.h" +#include "os.h" +#include "swab.h" +#include "hfstime.h" + +/* Initialize iterator for a given fork */ +void +blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f, +		    UInt8 forktype, UInt32 fileId) +{ +    b->vol	    = vol; +    b->curr_block   = 0; +    b->block	    = 0; +    b->max_block    = f->total_blocks; +    b->fileId	    = fileId; +    b->index	    = 0; +    b->file	    = f->extents; +    b->e	    = f->extents; +    b->forktype	    = forktype; +    b->in_extent    = 0; +} + +/* get next extent record when needed */ +static int +blockiter_next_extent(blockiter *b) +{ +    btree*  extents_tree = volume_get_extents_tree(b->vol); +    int	    err; + +    b->index = 0; +    if (b->in_extent) // already using extents record ? +    { +	err = record_next_extent(&b->er); +	// Hope there is no need to check this ... +	// if (b->er.key.start_block != b->curr_block) +	//     HFSP_ERROR(ENOENT, +	//	"Extents record inconistent"); +    } +    else +    { +	err = record_init_file(&b->er, extents_tree, b->forktype, +		b->fileId, b->curr_block); +	b->in_extent = -1;  // true +    } +    b->e = b->er.extent; +    return err; +} + +/* find next block of the fork iterating over */ +int +blockiter_next(blockiter *b) +{ +    b->curr_block ++; +    b->block ++; +    if (b->curr_block >= b->max_block) +	return -1; // end of Blocks, but no error +    // in current part of extent ? +    if (b->block >= b->e->block_count) +    { +	b->index++; +	b->block = 0;		// reset relative position +	b->e++; +	if (b -> index >= 8)	// need to fetch another extent +	{ +	    if (blockiter_next_extent(b)) +		HFSP_ERROR(ENOENT, "Extends record not found."); +	} +    } +    return 0; + +  fail: +    return -1; +} + +/* skip the indicated number of blocks */ +int +blockiter_skip(blockiter *b, UInt32 skip) +{ +    while (skip > 0) +    { +	// Skip to skip or end of current extent +	UInt32 diff = b->e->block_count - b->block; +	if (skip < diff) +	{ +	    diff = skip; +	    skip = 0; +	} +	else +	    skip -= diff; +	b->curr_block += diff; +	b->block      += diff; +	if (b->curr_block >= b->max_block) +	    return -1;	// end of Blocks, but no error +	if (b->block >= b->e->block_count) +	{ +	    b->index++; +	    b->block = 0;		// reset relative position +	    b->e++; +	    if (b -> index >= 8)	// need to fetch another extent +	    { +		if (blockiter_next_extent(b)) +		    HFSP_ERROR(ENOENT, "Extends record not found."); +	    } +	} +    } // we are here when skip was null, thats ok +    return 0; +  fail: +    return -1; +} diff --git a/roms/openbios/fs/hfsplus/hfsp_btree.c b/roms/openbios/fs/hfsplus/hfsp_btree.c new file mode 100644 index 00000000..24eca924 --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_btree.c @@ -0,0 +1,372 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original 1996-1998 Robert Leslie <rob@mars.org> + * Additional work by  Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "volume.h" +#include "btree.h" +#include "record.h" +#include "swab.h" + +/* Read the node from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readnode(btree_node_desc* node, void *p) +{ +    node->next	    = bswabU32_inc(p); +    node->prev	    = bswabU32_inc(p); +    node->kind	    = bswabU8_inc(p); +    node->height    = bswabU8_inc(p); +    node->num_rec   = bswabU16_inc(p); +    node->reserved  = bswabU16_inc(p); +    return p; +} + +/* read a btree header from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readhead(btree_head* head, void *p) +{ +	UInt32 *q; +        head->depth	    = bswabU16_inc(p); +        head->root	    = bswabU32_inc(p); +        head->leaf_count    = bswabU32_inc(p); +        head->leaf_head	    = bswabU32_inc(p); +        head->leaf_tail	    = bswabU32_inc(p); +        head->node_size	    = bswabU16_inc(p); +        head->max_key_len   = bswabU16_inc(p); +        head->node_count    = bswabU32_inc(p); +        head->free_nodes    = bswabU32_inc(p); +        head->reserved1	    = bswabU16_inc(p); +        head->clump_size    = bswabU32_inc(p); +        head->btree_type    = bswabU8_inc(p); +        head->reserved2	    = bswabU8_inc(p); +        head->attributes    = bswabU32_inc(p); +	    // skip reserved bytes +	q=((UInt32*) p); +	// ((UInt32*) p) += 16; +	q+=16; +	return q; +} + +/* Priority of the depth of the node compared to LRU value. + * Should be the average number of keys per node but these vary. */ +#define DEPTH_FACTOR	1000 + +/* Cache size is height of tree + this value + * Really big numbers wont help in case of ls -R + */ +#define EXTRA_CACHESIZE	3 + +/* Not in use by now ... */ +#define CACHE_DIRTY 0x0001 + +/* Intialize cache with default cache Size, + * must call node_cache_close to deallocate memory */ +static int node_cache_init(node_cache* cache, btree* tree, int size) +{ +    int nodebufsize; +    char * buf; + +    cache->size		= size; +    cache->currindex	= 0; +    nodebufsize = tree->head.node_size + sizeof(node_buf); +    buf = malloc(size *(sizeof(node_entry) + nodebufsize)); +    if (!buf) +	return -1; +    cache -> nodebufsize = nodebufsize; +    cache -> entries = (node_entry*) buf; +    cache -> buffers = (char*) &cache->entries[size]; +    bzero(cache->entries, size*sizeof(node_entry)); +    return 0; +} + +/* Like cache->buffers[i], since size of node_buf is variable */ +static inline node_buf* node_buf_get(node_cache* cache, int i) +{ +    return (node_buf*) (cache->buffers + (i * cache->nodebufsize)); +} + +/* flush the node at index */ +static void node_cache_flush_node(node_cache* cache, int index) +{ +    // NYI +    cache -> entries[index].index = 0;	// invalidate entry +} + +static void node_cache_close(node_cache* cache) +{ +    if (!cache->entries) // not (fully) intialized ? +	return; +    free(cache->entries); +} + +/* Load the cach node indentified by index with + * the node identified by node_index */ + +static node_buf* node_cache_load_buf +    (btree* bt, node_cache* cache, int index, UInt16 node_index) +{ +    node_buf	*result	    = node_buf_get(cache ,index); +    UInt32	blkpernode  = bt->blkpernode; +    UInt32	block	    = node_index * blkpernode; +    void*	p	    = volume_readfromfork(bt->vol, result->node, bt->fork, +			     block, blkpernode, HFSP_EXTENT_DATA, bt->cnid); +    node_entry	*e	    = &cache->entries[index]; + +    if (!p) +	return NULL;	// evil ... + +    result->index   = node_index; +    btree_readnode(&result->desc, p); + +    e -> priority   = result->desc.height * DEPTH_FACTOR; +    e -> index	    = node_index; +    return result; +} + +/* Read node at given index, using cache. + */ +node_buf* btree_node_by_index(btree* bt, UInt16 index) +{ +    node_cache*	cache = &bt->cache; +    int		oldindex, lruindex; +    int		currindex = cache->currindex; +    UInt32	prio; +    node_entry	*e; + +    // Shortcut acces to current node, will not change priorities +    if (cache->entries[currindex].index == index) +	return node_buf_get(cache ,currindex); +    oldindex = currindex; +    if (currindex == 0) +	currindex = cache->size; +    currindex--; +    lruindex = oldindex;	    // entry to be flushed when needed +    prio     = 0;		    // current priority +    while (currindex != oldindex)   // round robin +    { +	e = &cache->entries[currindex]; +	if (e->index == index)	    // got it +	{ +	    if (e->priority != 0)   // already top, uuh +		e->priority--; +	    cache->currindex = currindex; +	    return node_buf_get(cache ,currindex); +	} +	else +	{ +	    if (!e->index) +	    { +		lruindex = currindex; +		break;	// empty entry, load it +	    } +	    if (e->priority != UINT_MAX) // already least, uuh +		e->priority++; +	} +	if (prio < e->priority) +	{ +	    lruindex = currindex; +	    prio = e->priority; +	} +	if (currindex == 0) +	    currindex = cache->size; +	currindex--; +    } +    e = &cache->entries[lruindex]; +    cache->currindex = lruindex; +    if (e->flags & CACHE_DIRTY) +           node_cache_flush_node(    cache, lruindex); +    return node_cache_load_buf  (bt, cache, lruindex, index); +} + +/** intialize the btree with the first entry in the fork */ +static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ +    void	    *p; +    char	    buf[vol->blksize]; +    UInt16	    node_size; +    btree_node_desc node; + +    bt->vol	= vol; +    bt->fork	= fork; +    p	= volume_readfromfork(vol, buf, fork, 0, 1, +		 HFSP_EXTENT_DATA, bt->cnid); +    if (!p) +	return -1; +    p = btree_readnode(&node, p); +    if (node.kind != HFSP_NODE_HEAD) +	return -1;   // should not happen ? +    btree_readhead(&bt->head, p); + +    node_size = bt->head.node_size; +    bt->blkpernode = node_size / vol->blksize; + +    if (bt->blkpernode == 0 || vol->blksize * +	    bt->blkpernode != node_size) +	return -1;  // should never happen ... + +    node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE); + +    // Allocate buffer +    // bt->buf = malloc(node_size); +    // if (!bt->buf) +    //	return ENOMEM; + +    return 0; +} + +/** Intialize catalog btree, so that btree_close can safely be called. */ +void btree_reset(btree* bt) +{ +    bt->cache.entries = NULL; +} + +/** Intialize catalog btree */ +int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ +    int result = btree_init(bt,vol,fork);	// super (...) +    bt->cnid  = HFSP_CAT_CNID; +    bt->kcomp = record_key_compare; +    bt->kread = record_readkey; +    return result; +} + +/** Intialize catalog btree */ +int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ +    int result = btree_init(bt,vol,fork);	// super (...) +    bt->cnid  = HFSP_EXT_CNID; +    bt->kcomp = record_extent_key_compare; +    bt->kread = record_extent_readkey; +    return result; +} + +/** close the btree and free any resources */ +void btree_close(btree* bt) +{ +    node_cache_close(&bt->cache); +    // free(bt->buf); +} + +/* returns pointer to key given by index in current node. + * + * Assumes that current node is not NODE_HEAD ... + */ +void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index) +{ +    UInt16  node_size	    = bt->head.node_size; +	// The offsets are found at the end of the node ... +    UInt16  off_pos	    = node_size - (index +1) * sizeof(btree_record_offset); +	// position of offset at end of node +    btree_record_offset* offset = +	(btree_record_offset*) (buf->node + off_pos); + +    // now we have the offset and can read the key ... +#ifdef CONFIG_LITTLE_ENDIAN +    return buf->node + bswabU16(*offset); +#else +    return buf->node + *offset; +#endif +} + + +#ifdef DEBUG + +/* print btree header node information */ +void btree_printhead(btree_head* head) +{ +    UInt32 attr; +    printf("  depth       : %#X\n",  head->depth); +    printf("  root        : %#lX\n", head->root); +    printf("  leaf_count  : %#lX\n", head->leaf_count); +    printf("  leaf_head   : %#lX\n", head->leaf_head); +    printf("  leaf_tail   : %#lX\n", head->leaf_tail); +    printf("  node_size   : %#X\n",  head->node_size); +    printf("  max_key_len : %#X\n",  head->max_key_len); +    printf("  node_count  : %#lX\n", head->node_count); +    printf("  free_nodes  : %#lX\n", head->free_nodes); +    printf("  reserved1   : %#X\n",  head->reserved1); +    printf("  clump_size  : %#lX\n", head->clump_size); +    printf("  btree_type  : %#X\n",  head->btree_type); +    attr = head->attributes; +    printf("  reserved2   : %#X\n",  head->reserved2); +    if (attr & HFSPLUS_BAD_CLOSE) +        printf(" HFSPLUS_BAD_CLOSE *** "); +    else +        printf(" !HFSPLUS_BAD_CLOSE"); +    if (attr & HFSPLUS_TREE_BIGKEYS) +        printf(" HFSPLUS_TREE_BIGKEYS "); +    else +        printf("  !HFSPLUS_TREE_BIGKEYS"); +    if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE) +        printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE"); +    else +        printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE"); +    if (attr & HFSPLUS_TREE_UNUSED) +        printf(" HFSPLUS_TREE_UNUSED ***\n"); +    printf("\n"); +} + +/* Dump all the node information to stdout */ +void btree_print(btree* bt) +{ +    btree_node_desc* node; + +    btree_printhead(&bt->head); + +    node = &bt->node; +    printf("next     : %#lX\n", node->next); +    printf("prev     : %#lX\n", node->prev); +    printf("height   : %#X\n",  node->height); +    printf("num_rec  : %#X\n",  node->num_rec); +    printf("reserved : %#X\n",  node->reserved); +    printf("height   : %#X\n",  node->height);                                      switch(node->kind) +    { +	case HFSP_NODE_NDX  : +	    printf("HFSP_NODE_NDX\n"); +	    break; +	case HFSP_NODE_HEAD : +	    printf("HFSP_NODE_HEAD\n"); +	    break; +	case HFSP_NODE_MAP  : +	    printf("HFSP_NODE_MAP\n"); +	    break; +	case HFSP_NODE_LEAF : +	    printf("HFSP_NODE_LEAF\n"); +	    break; +	default: +	    printf("*** Unknown Node type ***\n"); +    } +} + +#endif diff --git a/roms/openbios/fs/hfsplus/hfsp_fs.c b/roms/openbios/fs/hfsplus/hfsp_fs.c new file mode 100644 index 00000000..df234bb0 --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_fs.c @@ -0,0 +1,632 @@ +/* + *   Creation Date: <2001/05/05 23:33:49 samuel> + *   Time-stamp: <2004/01/12 10:25:39 samuel> + * + *	/package/hfsplus-files + * + *	HFS+ file system interface (and ROM lookup support) + * + *   Copyright (C) 2001, 2002, 2003, 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 "libhfsp.h" +#include "volume.h" +#include "record.h" +#include "unicode.h" +#include "blockiter.h" +#include "libc/diskio.h" +#include "libc/vsprintf.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     hfsp_init( void ); + +typedef struct { +	record		rec; +	char		*path; +	off_t		pos; +} hfsp_file_t; + +typedef struct { +	volume *vol; +	hfsp_file_t *hfspfile; +} hfsp_info_t; + +DECLARE_NODE( hfsp, 0, sizeof(hfsp_info_t), "+/packages/hfsplus-files" ); + + +/************************************************************************/ +/*	Search implementation						*/ +/************************************************************************/ + +typedef int (*match_proc_t)( record *r, record *parent, const void *match_data, hfsp_file_t *pt ); + +static int +search_files( record *par, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt ) +{ +	hfsp_file_t t; +	record r; +	int ret = 1; + +	t.path = NULL; + +	record_init_parent( &r, par ); +	do{ +		if( r.record.type == HFSP_FOLDER || r.record.type == HFSP_FILE ) +			ret = (*proc)( &r, par, match_data, &t ); + +		if( ret && r.record.type == HFSP_FOLDER && recursive ) +			ret = search_files( &r, 1, proc, match_data, &t ); + +	} while( ret && !record_next(&r) ); + +	if( !ret && pt ) { +                char name[256]; +                const char *s2 = t.path ? t.path : ""; + +		unicode_uni2asc( name, &r.key.name, sizeof(name)); + +		pt->rec = t.rec; +		pt->path = malloc( strlen(name) + strlen(s2) + 2 ); +		strcpy( pt->path, name ); +		if( strlen(s2) ) { +			strcat( pt->path, "\\" ); +			strcat( pt->path, s2 ); +		} +	} + +	if( t.path ) +		free( t.path ); + +	return ret; +} + +static int +root_search_files( volume *vol, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt ) +{ +	record r; + +	record_init_root( &r, &vol->catalog ); +	return search_files( &r, recursive, proc, match_data, pt ); +} + +static int +match_file( record *r, record *parent, const void *match_data, hfsp_file_t *pt ) +{ +        const char *p = (const char*)match_data; +	char name[256]; +	int ret=1; + +	if( r->record.type != HFSP_FILE ) +		return 1; + +	(void) unicode_uni2asc(name, &r->key.name, sizeof(name)); +	if( !(ret=strcasecmp(p, name)) && pt ) +		pt->rec = *r; + +	return ret; +} + +static int +match_rom( record *r, record *par, const void *match_data, hfsp_file_t *pt ) +{ +	hfsp_cat_file *file = &r->record.u.file; +	FInfo *fi = &file->user_info; +	int ret = 1; +	char buf[256]; + +	if( r->record.type == HFSP_FILE && fi->fdCreator == MAC_OS_ROM_CREATOR && fi->fdType == MAC_OS_ROM_TYPE ) { +		ret = search_files( par, 0, match_file, "System", NULL ) +			|| search_files( par, 0, match_file, "Finder", NULL ); + +		(void) unicode_uni2asc(buf, &r->key.name, sizeof(buf)); +		if( !strcasecmp("BootX", buf) ) +			return 1; + +		if( !ret && pt ) +			pt->rec = *r; +	} +	return ret; +} + +static int +match_path( record *r, record *par, const void *match_data, hfsp_file_t *pt ) +{ +	char name[256], *s, *next, *org; +	int ret=1; + + 	next = org = strdup( (char*)match_data ); +	while( (s=strsep( &next, "\\/" )) && !strlen(s) ) +		; +	if( !s ) { +		free( org ); +		return 1; +	} + +	if( *s == ':' && strlen(s) == 5 ) { +		if( r->record.type == HFSP_FILE && !next ) { +			/* match type */ +			hfsp_cat_file *file = &r->record.u.file; +			FInfo *fi = &file->user_info; +			int i, type=0; +			for( i=1; s[i] && i<=4; i++ ) +				type = (type << 8) | s[i]; +			/* printk("fi->fdType: %s / %s\n", s+1, b ); */ +			if( fi->fdType == type ) { +				if( pt ) +					pt->rec = *r; +				ret = 0; +			} +		} +	} else { +		(void) unicode_uni2asc(name, &r->key.name, sizeof(name)); + +		if( !strcasecmp(s, name) ) { +			if( r->record.type == HFSP_FILE && !next ) { +				if( pt ) +					pt->rec = *r; +				ret = 0; +			} else /* must be a directory */ +				ret = search_files( r, 0, match_path, next, pt ); +		} +	} +	free( org ); +	return ret; +} + + +/************************************************************************/ +/*	Standard package methods						*/ +/************************************************************************/ + +/* ( -- success? ) */ +static void +hfsp_files_open( hfsp_info_t *mi ) +{ +	int fd; +	char *path = my_args_copy(); + +	if ( ! path ) +		RET( 0 ); + +	fd = open_ih( my_parent() ); +	if ( fd == -1 ) { +		free( path ); +		RET( 0 ); +	} + +	mi->vol = malloc( sizeof(volume) ); +	if (volume_open(mi->vol, fd)) { +		free( path ); +		close_io( fd ); +		RET( 0 ); +	} + +	mi->hfspfile = malloc( sizeof(hfsp_file_t) ); +	 +	/* Leading \\ means system folder. The finder info block has +	 * the following meaning. +	 * +	 *  [0] Prefered boot directory ID +	 *  [3] MacOS 9 boot directory ID +	 *  [5] MacOS X boot directory ID +	 */ +	if( !strncmp(path, "\\\\", 2) ) { +		int *p = (int*)&(mi->vol)->vol.finder_info[0]; +		int cnid = p[0]; +		/* printk(" p[0] = %x, p[3] = %x, p[5] = %x\n", p[0], p[3], p[5] ); */ +		if( p[0] == p[5] && p[3] ) +			cnid = p[3]; +		if( record_init_cnid(&(mi->hfspfile->rec), &(mi->vol)->catalog, cnid) ) +			RET ( 0 ); +		path += 2; +	} else { +		record_init_root( &(mi->hfspfile->rec), &(mi->vol)->catalog ); +	} + +	if( !search_files(&(mi->hfspfile->rec), 0, match_path, path, mi->hfspfile ) ) +		RET ( -1 ); +	 +	RET ( -1 ); +} + +/* ( -- ) */ +static void +hfsp_files_close( hfsp_info_t *mi ) +{ +	volume_close(mi->vol); + +	if( mi->hfspfile->path ) +		free( mi->hfspfile->path ); +	free( mi->hfspfile ); +} + +/* ( buf len -- actlen ) */ +static void +hfsp_files_read( hfsp_info_t *mi ) +{ +	int count = POP(); +	char *buf = (char *)cell2pointer(POP()); + +	hfsp_file_t *t = mi->hfspfile; +	volume *vol = t->rec.tree->vol; +	UInt32 blksize = vol->blksize; +	hfsp_cat_file *file = &t->rec.record.u.file; +	blockiter iter; +	char buf2[blksize]; +	int act_count, curpos=0; + +	blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id ); +	while( curpos + blksize < t->pos ) { +		if( blockiter_next( &iter ) ) { +			RET ( -1 ); +			return; +		} +		curpos += blksize; +	} +	act_count = 0; + +	while( act_count < count ){ +		UInt32 block = blockiter_curr(&iter); +		int max = blksize, add = 0, size; + +		if( volume_readinbuf( vol, buf2, block ) ) +			break; + +		if( curpos < t->pos ){ +			add += t->pos - curpos; +			max -= t->pos - curpos; +		} +		size = (count-act_count > max)? max : count-act_count; +		memcpy( (char *)buf + act_count, &buf2[add], size ); + +		curpos += blksize; +		act_count += size; + +		if( blockiter_next( &iter ) ) +			break; +	} + +	t->pos += act_count; + +	RET ( act_count ); +} + +/* ( pos.d -- status ) */ +static void +hfsp_files_seek( hfsp_info_t *mi ) +{ +	long long pos = DPOP(); +	int offs = (int)pos; +	int whence = SEEK_SET; + +	hfsp_file_t *t = mi->hfspfile; +	hfsp_cat_file *file = &t->rec.record.u.file; +	int total = file->data_fork.total_size; + +	if( offs == -1 ) { +		offs = 0; +		whence = SEEK_END; +	} + +	switch( whence ){ +	case SEEK_END: +		t->pos = total + offs; +		break; +	default: +	case SEEK_SET: +		t->pos = offs; +		break; +	} + +	if( t->pos < 0 ) +		t->pos = 0; + +	if( t->pos > total ) +		t->pos = total; + +	RET ( 0 ); +} + +/* ( addr -- size ) */ +static void +hfsp_files_load( hfsp_info_t *mi ) +{ +	char *buf = (char *)cell2pointer(POP()); + +	hfsp_file_t *t = mi->hfspfile; +	volume *vol = t->rec.tree->vol; +	UInt32 blksize = vol->blksize; +	hfsp_cat_file *file = &t->rec.record.u.file; +	int total = file->data_fork.total_size; +	blockiter iter; +	char buf2[blksize]; +	int act_count; + +	blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id ); + +	act_count = 0; + +	while( act_count < total ){ +		UInt32 block = blockiter_curr(&iter); +		int max = blksize, size; + +		if( volume_readinbuf( vol, buf2, block ) ) +			break; + +		size = (total-act_count > max)? max : total-act_count; +		memcpy( (char *)buf + act_count, &buf2, size ); + +		act_count += size; + +		if( blockiter_next( &iter ) ) +			break; +	} + +	RET ( act_count ); +} + +/* ( -- cstr ) */ +static void +hfsp_files_get_fstype( hfsp_info_t *mi ) +{ +	PUSH( pointer2cell(strdup("HFS+")) ); +} + +/* ( -- cstr ) */ +static void +hfsp_files_get_path( hfsp_info_t *mi ) +{ +	char *buf; +	hfsp_file_t *t = mi->hfspfile; + +	if( !t->path ) +		RET ( 0 ); + +	buf = malloc(strlen(t->path) + 1); +	strncpy( buf, t->path, strlen(t->path) ); +	buf[strlen(t->path)] = 0; + +	PUSH(pointer2cell(buf)); +} + +/* ( -- success? ) */ +static void +hfsp_files_open_nwrom( hfsp_info_t *mi ) +{ +	/* Switch to an existing ROM image file on the fs! */ +	if( !root_search_files(mi->vol, 1, match_rom, NULL, mi->hfspfile) ) +		RET ( -1 ); + +	RET ( 0 ); +} + +/* ( -- cstr|0 ) */ +static void +hfsp_files_volume_name( hfsp_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 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(uint32_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 += 1904; + +	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 method, ( pathstr len ihandle -- ) */ +static void +hfsp_files_dir( hfsp_info_t *dummy ) +{ +	ihandle_t ih = POP_ih(); +	char *path = pop_fstr_copy(); +	int fd, found; +	volume *vol; +	record rec, r, folrec; +	char name[256], *curfol, *tmppath; +	 +	fd = open_ih(ih); +	if ( fd == -1 ) { +		free( path ); +		RET( 0 ); +	} + +	vol = malloc( sizeof(volume) ); +	if (volume_open(vol, fd)) { +		free( path ); +		close_io( fd ); +		RET( 0 ); +	} +	 +	/* First move to the specified folder */ +	tmppath = strdup(path); +	record_init_root( &rec, &vol->catalog ); +	record_init_parent( &r, &rec ); +	 +	/* Remove initial \ or / */ +	curfol = strsep(&tmppath, "\\//"); +	curfol = strsep(&tmppath, "\\//"); +	forth_printf("\n"); +	 +	while (curfol && strlen(curfol)) {	     +	    found = 0; +	    do { +		if (r.record.type == HFSP_FOLDER) { +		    unicode_uni2asc(name, &r.key.name, sizeof(name)); +		     +		    if (!strcmp(name, curfol)) { +			folrec = r; +			found = -1; +		    } +		} +	    } while ( !record_next(&r) ); +	     +	    if (!found) { +		forth_printf("Unable to locate path %s on filesystem\n", path); +		goto done; +	    } else { +		record_init_parent( &r, &folrec ); +	    } +	     +	    curfol = strsep(&tmppath, "\\//"); +	} +	 +	/* Output the directory contents */ +	found = 0; +	do { +	    unicode_uni2asc(name, &r.key.name, sizeof(name)); +	     +	    if (r.record.type == HFSP_FILE) { +		/* Grab the file entry */ +		hfsp_cat_file *file = &r.record.u.file; +		forth_printf("% 10lld ", file->data_fork.total_size); +		print_date(file->create_date); +		forth_printf(" %s\n", name); +		found = -1; +	    } +	     +	    if (r.record.type == HFSP_FOLDER) { +		/* Grab the directory entry */ +		hfsp_cat_folder *folder = &r.record.u.folder; +		forth_printf("         0 "); +		print_date(folder->create_date); +		forth_printf(" %s\\\n", name); +		found = -1; +	    } +	     +	} while ( !record_next(&r) ); +	 +	if (!found) { +	    forth_printf("  (Empty folder)\n"); +	} +	 +done: +	volume_close(vol); +	free(vol); +	free(path); +	if (tmppath) +	    free(tmppath); +} + +/* static method, ( pos.d ih -- flag? ) */ +static void +hfsp_files_probe( hfsp_info_t *dummy ) +{ +	ihandle_t ih = POP_ih(); +	long long offs = DPOP(); +	int fd, ret = 0; + +	fd = open_ih(ih); +        if (fd >= 0) { +                if (volume_probe(fd, offs)) { +                        ret = -1; +                } +                close_io(fd); +        } else { +                ret = -1; +        } + +	RET (ret); +} + +static void +hfsp_initializer( hfsp_info_t *dummy ) +{ +	fword("register-fs-package"); +} + +NODE_METHODS( hfsp ) = { +	{ "probe",	hfsp_files_probe	}, +	{ "open",	hfsp_files_open		}, +	{ "close",	hfsp_files_close	}, +	{ "read",	hfsp_files_read		}, +	{ "seek",	hfsp_files_seek		}, +	{ "load",	hfsp_files_load		}, +	{ "dir",	hfsp_files_dir		}, + +	/* special */ +	{ "open-nwrom",	 	hfsp_files_open_nwrom 	}, +	{ "get-path",		hfsp_files_get_path	}, +	{ "get-fstype",		hfsp_files_get_fstype	}, +	{ "volume-name",	hfsp_files_volume_name	}, + +	{ NULL,		hfsp_initializer	}, +}; + +void +hfsp_init( void ) +{ +	REGISTER_NODE( hfsp ); +} diff --git a/roms/openbios/fs/hfsplus/hfsp_record.c b/roms/openbios/fs/hfsplus/hfsp_record.c new file mode 100644 index 00000000..d4e7af1b --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_record.c @@ -0,0 +1,759 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes. + * + * a record contains a key and a folder or file and is part + * of a btree. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original 1996-1998 Robert Leslie <rob@mars.org> + * Additional work by  Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "hfstime.h" +#include "record.h" +#include "volume.h" +#include "btree.h" +#include "unicode.h" +#include "swab.h" + +/* read a hfsp_cat_key from memory */ +void* record_readkey(void* p, void* buf) +{ +    hfsp_cat_key*   key = (hfsp_cat_key*) buf; +    const void*	    check; +    UInt16	    key_length, len,i; +    UInt16*	    cp; + +    key->key_length = key_length    = bswabU16_inc(p); +    check = p; +    key->parent_cnid		    = bswabU32_inc(p); +    key->name.strlen = len	    = bswabU16_inc(p); +    cp = key->name.name; +    for (i=0; i < len; i++, cp++) +	*cp			    = bswabU16_inc(p); +	/* check if keylenght was correct */ +    if (key_length != ((char*) p) - ((char*) check)) +	 HFSP_ERROR(EINVAL, "Invalid key length in record_readkey"); +    return p; +  fail: +    return NULL; +} + +/* read a hfsp_extent_key from memory */ +void* record_extent_readkey(void* p, void* buf) +{ +    hfsp_extent_key* key = (hfsp_extent_key*) buf; +    UInt16  key_length; + +    key->key_length = key_length    = bswabU16_inc(p); +    key->fork_type		    = bswabU8_inc(p); +    key->filler			    = bswabU8_inc(p); +    if (key_length != 10) +	HFSP_ERROR(-1, "Invalid key length in record_extent_readkey"); +    key->file_id		    = bswabU32_inc(p); +    key->start_block		    = bswabU32_inc(p); +    return p; +  fail: +    return NULL; +} + + +/* read posix permission from memory */ +static inline void* record_readperm(void *p, hfsp_perm* perm) +{ +    perm->owner= bswabU32_inc(p); +    perm->group= bswabU32_inc(p); +    perm->mode = bswabU32_inc(p); +    perm->dev  = bswabU32_inc(p); +    return p; +} + +/* read directory info */ +static inline void* record_readDInfo(void *p, DInfo* info) +{ +    info->frRect.top	= bswabU16_inc(p); +    info->frRect.left	= bswabU16_inc(p); +    info->frRect.bottom	= bswabU16_inc(p); +    info->frRect.right	= bswabU16_inc(p); +    info->frFlags	= bswabU16_inc(p); +    info->frLocation.v	= bswabU16_inc(p); +    info->frLocation.h	= bswabU16_inc(p); +    info->frView	= bswabU16_inc(p); +    return p; +} + +/* read extra Directory info */ +static inline void* record_readDXInfo(void *p, DXInfo* xinfo) +{ +    xinfo->frScroll.v  = bswabU16_inc(p); +    xinfo->frScroll.h  = bswabU16_inc(p); +    xinfo->frOpenChain = bswabU32_inc(p); +    xinfo->frUnused    = bswabU16_inc(p); +    xinfo->frComment   = bswabU16_inc(p); +    xinfo->frPutAway   = bswabU32_inc(p); +    return p; +} + +/* read a hfsp_cat_folder from memory */ +static void* record_readfolder(void *p, hfsp_cat_folder* folder) +{ +    folder->flags		= bswabU16_inc(p); +    folder->valence		= bswabU32_inc(p); +    folder->id			= bswabU32_inc(p); +    folder->create_date		= bswabU32_inc(p); +    folder->content_mod_date    = bswabU32_inc(p); +    folder->attribute_mod_date	= bswabU32_inc(p); +    folder->access_date		= bswabU32_inc(p); +    folder->backup_date		= bswabU32_inc(p); +    p = record_readperm	    (p, &folder->permissions); +    p = record_readDInfo    (p, &folder->user_info); +    p = record_readDXInfo   (p, &folder->finder_info); +    folder->text_encoding	= bswabU32_inc(p); +    folder->reserved		= bswabU32_inc(p); +    return p; +} + +/* read file info */ +static inline void* record_readFInfo(void *p, FInfo* info) +{ +    info->fdType	= bswabU32_inc(p); +    info->fdCreator	= bswabU32_inc(p); +    info->fdFlags	= bswabU16_inc(p); +    info->fdLocation.v	= bswabU16_inc(p); +    info->fdLocation.h	= bswabU16_inc(p); +    info->fdFldr	= bswabU16_inc(p); +    return p; +} + +/* read extra File info */ +static inline void* record_readFXInfo(void *p, FXInfo* xinfo) +{ +    SInt16 *q; +    xinfo->fdIconID	= bswabU16_inc(p); +    q=(SInt16*) p; +    q+=4; // skip unused +    p=(void *)q; +    xinfo->fdComment	= bswabU16_inc(p); +    xinfo->fdPutAway	= bswabU32_inc(p); +    return p; +} + +/* read a hfsp_cat_file from memory */ +static void* record_readfile(void *p, hfsp_cat_file* file) +{ +    file->flags			= bswabU16_inc(p); +    file->reserved1		= bswabU32_inc(p); +    file->id			= bswabU32_inc(p); +    file->create_date		= bswabU32_inc(p); +    file->content_mod_date	= bswabU32_inc(p); +    file->attribute_mod_date	= bswabU32_inc(p); +    file->access_date		= bswabU32_inc(p); +    file->backup_date		= bswabU32_inc(p); +    p = record_readperm	    (p, &file->permissions); +    p = record_readFInfo    (p, &file->user_info); +    p = record_readFXInfo   (p, &file->finder_info); +    file->text_encoding		= bswabU32_inc(p); +    file->reserved2		= bswabU32_inc(p); +    p =	    volume_readfork (p, &file->data_fork); +    return  volume_readfork (p, &file->res_fork); +} + +/* read a hfsp_cat_thread from memory */ +static void* record_readthread(void *p, hfsp_cat_thread* entry) +{ +    int	    i; +    UInt16  len; +    UInt16* cp; + +    entry->         reserved	= bswabU16_inc(p); +    entry->	    parentID	= bswabU32_inc(p); +    entry->nodeName.strlen = len= bswabU16_inc(p); +    cp = entry->nodeName.name; +    if (len > 255) +        HFSP_ERROR(-1, "Invalid key length in record thread"); +    for (i=0; i < len; i++, cp++) +	*cp			 = bswabU16_inc(p); +    return p; + fail: +    return NULL; +} + +/* read a hfsp_cat_entry from memory */ +static void* record_readentry(void *p, hfsp_cat_entry* entry) +{ +    UInt16 type = bswabU16_inc(p); +    entry->type = type; +    switch (type) +    { +	case HFSP_FOLDER: +	    return record_readfolder(p, &entry->u.folder); +	case HFSP_FILE: +	    return record_readfile  (p, &entry->u.file); +	case HFSP_FOLDER_THREAD: +	case HFSP_FILE_THREAD: +	    return record_readthread(p, &entry->u.thread); +	default: +	    HFSP_ERROR(-1, "Unexpected record type in record_readentry"); +    } ; +  fail: +    return NULL; +} + + +/* Most of the functions here will not change the node in the btree, +   But this must be changed in the future ... */ + + +/* intialize the record with the given index entry in the btree. */ +static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index) +{ +    void *p; +    r-> tree   = bt; +    p = btree_key_by_index(bt,buf,index); +    if (!p) +	return -1; +    p = record_readkey  (p, &r->key); +    if (!p) +	return -1; +    p = record_readentry(p, &r->record); +    if (!p) +	return -1; +    r->node_index = buf->index; +    r-> keyind    = index; + +    return 0; +} + +/* intialize the record with the given index entry in the btree. */ +static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index) +{ +    void *p; +    r-> tree   = bt; +    p = btree_key_by_index(bt, buf,index); +    if (!p) +	return -1; +    p = record_extent_readkey(p, &r->key); +    if (!p) +	return -1; +    p = volume_readextent(p, r->extent); +    if (!p) +	return -1; +    r->node_index = buf->index; +    r-> keyind    = index; + +    return 0; +} + +/* intialize the record to the first record of the tree + * which is (per design) the root node. + */ +int record_init_root(record* r, btree* tree) +{ +    // Position to first leaf node ... +    UInt32 leaf_head = tree->head.leaf_head; +    node_buf* buf = btree_node_by_index(tree, leaf_head); +    if (!buf) +	return -1; +    return record_init(r, tree, buf, 0); +} + +/* Compare two cat_keys ... */ +int record_key_compare(void* k1, void* k2) +{ +    hfsp_cat_key* key1 = (hfsp_cat_key*) k1; +    hfsp_cat_key* key2 = (hfsp_cat_key*) k2; +    int diff = key2->parent_cnid - key1->parent_cnid; +    if (!diff) // same parent +	diff = fast_unicode_compare(&key1->name, &key2->name); +    return diff; +} + +/* Compare two extent_keys ... */ +int record_extent_key_compare(void* k1, void* k2) +{ +    hfsp_extent_key* key1 = (hfsp_extent_key*) k1; +    hfsp_extent_key* key2 = (hfsp_extent_key*) k2; +    int diff = key2->fork_type - key1->fork_type; +    if (!diff) // same type +    { +	diff = key2->file_id - key1->file_id; +	if (!diff) // same file +	    diff = key2->start_block - key1->start_block; +    } +    return diff; +} + +/* Position node in btree so that key might be inside */ +static node_buf* record_find_node(btree* tree, void *key) +{ +    int			start, end, mid, comp;  // components of a binary search +    void		*p = NULL; +    char		curr_key[tree->head.max_key_len]; +		    // The current key under examination +    hfsp_key_read	readkey	    = tree->kread; +    hfsp_key_compare	key_compare = tree->kcomp; +    UInt32		index; +    node_buf*		node = btree_node_by_index(tree, tree->head.root); +    if (!node) +	HFSP_ERROR(-1, "record_find_node: Cant position to root node"); +    while (node->desc.kind == HFSP_NODE_NDX) +    { +	mid = start = 0; +	end  = node->desc.num_rec; +	comp = -1; +	while (start < end) +	{ +	    mid = (start + end) >> 1; +	    p = btree_key_by_index(tree, node, mid); +	    if (!p) +		HFSP_ERROR(-1, "record_find_node: unexpected error"); +	    p = readkey  (p, curr_key); +	    if (!p) +		HFSP_ERROR(-1, "record_find_node: unexpected error"); +	    comp = key_compare(curr_key, key); +	    if (comp > 0) +		start = mid + 1; +	    else if (comp < 0) +		end = mid; +	    else +		break; +	} +	if (!p) // Empty tree, fascinating ... +	    HFSP_ERROR(-1, "record_find_node: unexpected empty node"); +	if (comp < 0)	// mmh interesting key is before this key ... +	{ +	    if (mid == 0) +		return NULL;  // nothing before this key .. +	    p = btree_key_by_index(tree, node, mid-1); +	    if (!p) +		HFSP_ERROR(-1, "record_find_node: unexpected error"); +	    p = readkey  (p, curr_key); +	    if (!p) +		HFSP_ERROR(-1, "record_find_node: unexpected error"); +	} + +	index = bswabU32_inc(p); +	node = btree_node_by_index(tree, index); +    } +    return node;	// go on and use the found node +  fail: +    return NULL; +} + +/* search for the given key in the btree. + * + * returns pointer to memory just after key or NULL + * In any case *keyind recives the index where the + * key was found (or could be inserted.) + */ +static void * +record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index) +{ +    node_buf* buf = record_find_node(tree, key); +    if (buf) +    { +	int		    comp  = -1; +	int		    start = 0; // components of a binary search +	int		    end   = buf->desc.num_rec; +	int		    mid   = -1; +	void		    *p    = NULL; +	char		    curr_key[tree->head.max_key_len]; +	hfsp_key_read	    readkey	= tree->kread; +	hfsp_key_compare    key_compare = tree->kcomp; +	while (start < end) +	{ +	    mid = (start + end) >> 1; +	    p = btree_key_by_index(tree, buf, mid); +	    if (!p) +		HFSP_ERROR(-1, "record_init_key: unexpected error"); +	    p = readkey  (p, curr_key); +	    if (!p) +		HFSP_ERROR(-1, "record_init_cat_key: unexpected error"); +	    comp = key_compare(curr_key, key); +	    if (comp > 0) +		start = mid + 1; +	    else if (comp < 0) +		end = mid; +	    else +		break; +	} +	if (!p) // Empty tree, fascinating ... +	    HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node"); +	*keyind = mid; +	*node_index = buf->index; +	if (!comp)	// found something ... +	    return p; +    } +    HFSP_ERROR(ENOENT, NULL); +  fail: +    return NULL; +} + +/* intialize the record by searching for the given key in the btree. + * + * r is umodified on error. + */ +static int +record_init_key(record* r, btree* tree, hfsp_cat_key* key) +{ +    int	    keyind; +    UInt16  node_index; +    void    *p = record_find_key(tree, key, &keyind, &node_index); + +    if (p) +    { +	r -> tree      = tree; +	r -> node_index= node_index; +	r -> keyind    = keyind; +	r -> key       = *key; // Better use a record_key_copy ... +	p = record_readentry(p, &r->record); +	if (!p) +	    HFSP_ERROR(-1, "record_init_key: unexpected error"); +	return 0; +    } +  fail: +    return -1; +} + +/* intialize the extent_record to the extent identified by the + * (first) blockindex. + * + * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC + */ +int record_init_file(extent_record* r, btree* tree, +		    UInt8 forktype, UInt32 fileId, UInt32 blockindex) +{ +    int		    keyind; +    UInt16	    node_index; +    hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex }; +    void	    *p = record_find_key(tree, &key, &keyind, &node_index); + +    if (p) +    { +	r -> tree      = tree; +	r -> node_index= node_index; +	r -> keyind    = keyind; +	r -> key       = key; // Better use a record_key_copy ... +	p =  volume_readextent(p, r->extent); +	if (!p) +	    HFSP_ERROR(-1, "record_init_file: unexpected error"); +	return 0; +    } +  fail: +    return -1; +} + +/* intialize the record to the folder identified by cnid + */ +int record_init_cnid(record* r, btree* tree, UInt32 cnid) +{ +    hfsp_cat_key    thread_key;	    // the thread is the first record + +    thread_key.key_length = 6;	    // null name (like '.' in unix ) +    thread_key.parent_cnid = cnid; +    thread_key.name.strlen = 0; + +    return record_init_key(r, tree, &thread_key); +} + +/* intialize the record to the first record of the parent. + */ +int record_init_parent(record* r, record* parent) +{ +    if (parent->record.type == HFSP_FOLDER) +	return record_init_cnid(r, parent->tree, parent->record.u.folder.id); +    else if(parent->record.type == HFSP_FOLDER_THREAD) +    { +	if (r != parent) +	    *r = *parent; // The folder thread is in fact the first entry, like '.' +	return 0; +    } +    HFSP_ERROR(EINVAL, +	"record_init_parent: parent is neither folder nor folder thread."); + +  fail: +    return EINVAL; +} + + +/* find correct node record for given node and *pindex. + * + * index of record in this (or next) node + * */ +static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex) +{ +    node_buf*	     buf    = btree_node_by_index(tree, node_index); +    btree_node_desc* desc   = &buf->desc; +    UInt32	     numrec = desc->num_rec; +    if (*pindex >= numrec) // move on to next node +    { +	UInt16 next = desc->next; +	*pindex = 0; +	if (!next   /* is there a next node ? */ +	||  !( buf = btree_node_by_index(tree, next))) +	    return NULL; +    } +    return buf; +} +/* move record foreward to next entry. + * + * In case of an error the value of *r is undefined ! + */ +int record_next(record* r) +{ +    btree*	tree	= r->tree; +    UInt16	index	= r->keyind +1; +    UInt32	parent; +    node_buf*	buf	= prepare_next(tree, r->node_index, &index); + +    if (!buf) +	return ENOENT;	// No (more) such file or directory + +    parent = r->key.parent_cnid; + +    if (record_init(r, tree, buf, index)) +	return -1; + +    if (r->key.parent_cnid != parent || // end of current directory +	index != r->keyind)		// internal error ? +	return ENOENT;	// No (more) such file or directory + +    return 0; +} + +/* move record foreward to next extent record. + * + * In case of an error the value of *r is undefined ! + */ +int record_next_extent(extent_record* r) +{ +    btree*	tree   = r->tree; +    UInt16	index  = r->keyind +1; +    UInt32	file_id; +    UInt8	fork_type; +    node_buf*	buf	= prepare_next(tree, r->node_index, &index); + +    if (!buf) +	return ENOENT;	// No (more) such file or directory + +    file_id	= r->key.file_id; +    fork_type	= r->key.fork_type; + +    if (record_init_extent(r, tree, buf, index)) +	return -1; + +    if (r->key.file_id	 != file_id ||	    // end of current file +	r->key.fork_type != fork_type ||    // end of current fork +	index != r->keyind)		    // internal error ? +	return ENOENT;	// No (more) such file or directory + +    return 0; +} + +/* intialize the record by searching for the given string in the given folder. + * + * parent and r may be the same. + */ +int record_init_string_parent(record* r, record* parent, char* name) +{ +    hfsp_cat_key key; + +    if (parent->record.type == HFSP_FOLDER) +	key.parent_cnid = parent->record.u.folder.id; +    else if(parent->record.type == HFSP_FOLDER_THREAD) +	key.parent_cnid = parent->key.parent_cnid; +    else +	HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder."); + +    key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size +    return record_init_key(r, parent->tree, &key); + +  fail: +    return -1; +} + +/* move record up in folder hierarchy (if possible) */ +int record_up(record* r) +{ +    if (r->record.type == HFSP_FOLDER) +    { +	// locate folder thread +	if (record_init_cnid(r, r->tree, r->record.u.folder.id)) +	    return -1; +    } +    else if(r->record.type == HFSP_FOLDER_THREAD) +    { +	// do nothing were are already where we want to be +    } +    else +	HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread."); + +    if(r->record.type != HFSP_FOLDER_THREAD) +	HFSP_ERROR(-1, "record_up: unable to locate parent"); +    return record_init_cnid(r, r->tree, r->record.u.thread.parentID); + +  fail: +    return -1; +} + +#ifdef DEBUG + +/* print Quickdraw Point */ +static void record_print_Point(Point* p) +{ +    printf("[ v=%d, h=%d ]", p->v, p->h); +} + +/* print Quickdraw Rect */ +static void record_print_Rect(Rect* r) +{ +    printf("[ top=%d, left=%d, bottom=%d, right=%d  ]", +	     r->top, r->left, r->bottom, r->right); +} + +/* print the key of a record */ +static void record_print_key(hfsp_cat_key* key) +{ +    char buf[255]; // mh this _might_ overflow +    unicode_uni2asc(buf, &key->name, 255); +    printf("parent cnid :    %ld\n",   key->parent_cnid); +    printf("name        :    %s\n", buf); +} + +/* print permissions */ +static void record_print_perm(hfsp_perm* perm) +{ +    printf("owner               :\t%ld\n",  perm->owner); +    printf("group               :\t%ld\n",  perm->group); +    printf("perm                :\t0x%lX\n",perm->mode); +    printf("dev                 :\t%ld\n",  perm->dev); +} + +/* print Directory info */ +static void record_print_DInfo(DInfo* dinfo) +{ +    printf(  "frRect              :\t");    record_print_Rect(&dinfo->frRect); +    printf("\nfrFlags             :\t0X%X\n",    dinfo->frFlags); +    printf(  "frLocation          :\t");    record_print_Point(&dinfo->frLocation); +    printf("\nfrView              :\t0X%X\n",    dinfo->frView); +} + +/* print extended Directory info */ +static void record_print_DXInfo(DXInfo* xinfo) +{ +    printf(  "frScroll            :\t");    record_print_Point(&xinfo->frScroll); +    printf("\nfrOpenChain         :\t%ld\n",  xinfo->frOpenChain); +    printf(  "frUnused            :\t%d\n",   xinfo->frUnused); +    printf(  "frComment           :\t%d\n",   xinfo->frComment); +    printf(  "frPutAway           :\t%ld\n",  xinfo->frPutAway); +} + +static void record_print_folder(hfsp_cat_folder* folder) +{ +    printf("flags               :\t0x%X\n",	folder->flags); +    printf("valence             :\t0x%lX\n",	folder->valence); +    printf("id                  :\t%ld\n",	folder->id); +    record_print_perm	(&folder->permissions); +    record_print_DInfo	(&folder->user_info); +    record_print_DXInfo	(&folder->finder_info); +    printf("text_encoding       :\t0x%lX\n",	folder->text_encoding); +    printf("reserved            :\t0x%lX\n",	folder->reserved); +} + +/* print File info */ +static void record_print_FInfo(FInfo* finfo) +{ +    printf(  "fdType              :\t%4.4s\n", (char*) &finfo->fdType); +    printf(  "fdCreator           :\t%4.4s\n", (char*) &finfo->fdCreator); +    printf(  "fdFlags             :\t0X%X\n", finfo->fdFlags); +    printf(  "fdLocation          :\t");     record_print_Point(&finfo->fdLocation); +    printf("\nfdFldr              :\t%d\n",  finfo->fdFldr); +} + +/* print extended File info */ +static void record_print_FXInfo(FXInfo* xinfo) +{ +    printf(  "fdIconID            :\t%d\n",   xinfo->fdIconID); +    // xinfo -> fdUnused; +    printf(  "fdComment           :\t%d\n",   xinfo->fdComment); +    printf(  "fdPutAway           :\t%ld\n",  xinfo->fdPutAway); +} + +/* print folder entry */ + +/* print file entry */ +static void record_print_file(hfsp_cat_file* file) +{ +    printf("flags               :\t0x%X\n",	file->flags); +    printf("reserved1           :\t0x%lX\n",	file->reserved1); +    printf("id                  :\t%ld\n",	file->id); +    record_print_perm	(&file->permissions); +    record_print_FInfo	(&file->user_info); +    record_print_FXInfo	(&file->finder_info); +    printf("text_encoding       :\t0x%lX\n",	file->text_encoding); +    printf("reserved            :\t0x%lX\n",	file->reserved2); +    printf("Datafork:\n"); +    volume_print_fork (&file->data_fork); +    printf("Rsrcfork:\n"); +    volume_print_fork (&file->res_fork); +} + +/* print info for a file or folder thread */ +static void record_print_thread(hfsp_cat_thread* entry) +{ +    char buf[255]; // mh this _might_ overflow +    unicode_uni2asc(buf, &entry->nodeName, 255); +    printf("parent cnid :\t%ld\n", entry->parentID); +    printf("name        :\t%s\n" , buf); +} + +/* print the information for a record */ +static void record_print_entry(hfsp_cat_entry* entry) +{ +    switch (entry->type) +    { +	case HFSP_FOLDER: +	    printf("=== Folder ===\n"); +	    return record_print_folder(&entry->u.folder); +	case HFSP_FILE: +	    printf("=== File ===\n"); +	    return record_print_file  (&entry->u.file); +	case HFSP_FOLDER_THREAD: +	    printf("=== Folder Thread ===\n"); +	    return record_print_thread(&entry->u.thread); +	case HFSP_FILE_THREAD: +	    printf("=== File Thread ==\n"); +	    return record_print_thread(&entry->u.thread); +	default: +	    printf("=== Unknown Record Type ===\n"); +    } ; +} + +    /* Dump all the record information to stdout */ +void record_print(record* r) +{ +    printf ("keyind      :    %u\n", r->keyind); +    record_print_key  (&r->key); +    record_print_entry(&r->record); +} + +#endif diff --git a/roms/openbios/fs/hfsplus/hfsp_unicode.c b/roms/openbios/fs/hfsplus/hfsp_unicode.c new file mode 100644 index 00000000..7a34affa --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_unicode.c @@ -0,0 +1,511 @@ +/* + *  linux/fs/hfsplus/unicode.c + * + * Copyright (C) 1999-2000  Brad Boyer (flar@pants.nu) + * This file may be distributed under the terms of the GNU Public License. + * + * The routines found here convert hfs-unicode string into ascii Strings + * and vice versa.  And the correct comparison between Strings. + */ + + +#include "config.h" +#include "libhfsp.h" +#include "unicode.h" + +/* ISO-8859-1 -> unicode */ +static int +asc2uni( unsigned char *ustr, const char *astr, int maxlen ) +{ +	int len; + +	if( maxlen <= 0 ) +		return 0; + +	for( len=0; *astr && len < maxlen-1 ; astr++, len++ ) { +		*ustr++ = 0; +		*ustr++ = *astr; +	} +	ustr[0] = ustr[1] = 0; +	return len; +} + +/* unicode -> ISO-8859-1 */ +static int +uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ) +{ +	int len; + +	if( maxlen <= 0 ) +		return 0; + +	for( len=0; ustrlen-- > 0 && len < maxlen-1 ; ustr += 2 ) { +		/* might be unrepresentable (or too complicated for us) */ +		if( ustr[0] || !ustr[1] ) +			continue; +		if( ustr[1] < 0x20 || ustr[1] >= 0x7f ) +		    *astr++ = '?'; +		else +		    *astr++ = ustr[1]; +		len++; +	} +	*astr = 0; +	return len; +} + +int +unicode_asc2uni( hfsp_unistr255 *ustr, const char* astr ) +{ +	return ustr->strlen = asc2uni( (u8*)ustr->name, astr, 255 ); +} + +int +unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen) +{ +	return uni2asc( astr, (u8*)ustr->name, ustr->strlen, maxlen ); +} + +/* The following code is almost as published by Apple, only +   small modifications where made to match some linux styles ... + +fastUnicodeCompare - Compare two Unicode strings; produce a relative ordering +*/ + +static const UInt16 gLowerCaseTable[]; + +SInt32 fast_unicode_compare ( const hfsp_unistr255 *ustr1, +			      const hfsp_unistr255 *ustr2) +{ +    register UInt16     c1,c2; +    register SInt32	diff; +    register UInt16     temp; +    register UInt16	length1 = ustr1->strlen; +    register UInt16	length2 = ustr2->strlen; +    register const UInt16* lowerCaseTable = gLowerCaseTable; +    register const UInt16* str1 = ustr1->name; +    register const UInt16* str2 = ustr2->name; + +    while (1) { +        //  Set default values for c1, c2 in case there are no more valid chars +        c1 = c2 = 0; +        //  Find next non-ignorable char from str1, or zero if no more +        while (length1 && c1 == 0) { +            c1 = *(str1++); +            --length1; +            if ((temp = lowerCaseTable[c1>>8]) != 0)        //  is there a subtable +                                                            //  for this upper byte? +                c1 = lowerCaseTable[temp + (c1 & 0x00FF)];  //  yes, so fold the char +        } +        //  Find next non-ignorable char from str2, or zero if no more +        while (length2 && c2 == 0) { +            c2 = *(str2++); +            --length2; +            if ((temp = lowerCaseTable[c2>>8]) != 0)        //  is there a subtable +                                                            //  for this upper byte? +                c2 = lowerCaseTable[temp + (c2 & 0x00FF)];  //  yes, so fold the char +        } +	diff = c2-c1; +        if (diff)       //  found a difference, so stop looping +            break; +        if (c1 == 0)        //  did we reach the end of both strings at the same time? +            return 0;       //  yes, so strings are equal +    } +    return diff; +} + + +/*  The lower case table consists of a 256-entry high-byte table followed by +    some number of 256-entry subtables. The high-byte table contains either an +    offset to the subtable for characters with that high byte or zero, which +    means that there are no case mappings or ignored characters in that block. +    Ignored characters are mapped to zero. + */ + +static const UInt16 gLowerCaseTable[] = { + +    // High-byte indices ( == 0 iff no case mapping and no ignorables ) + + +    /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00, + +    // Table 1 (for high byte 0x00) + +    /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, +            0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, +    /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, +            0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, +    /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, +            0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, +    /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, +            0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, +    /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, +            0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, +    /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, +            0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, +    /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, +            0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, +    /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, +            0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, +    /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, +            0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, +    /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, +            0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, +    /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, +            0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, +    /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, +            0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, +    /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, +            0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, +    /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, +            0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF, +    /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, +            0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, +    /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, +            0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + +    // Table 2 (for high byte 0x01) + +    /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, +            0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, +    /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, +            0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, +    /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, +            0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, +    /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, +            0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140, +    /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, +            0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, +    /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, +            0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F, +    /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, +            0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F, +    /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, +            0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, +    /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, +            0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259, +    /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, +            0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275, +    /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, +            0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF, +    /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, +            0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF, +    /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, +            0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF, +    /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, +            0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF, +    /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, +            0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF, +    /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, +            0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, + +    // Table 3 (for high byte 0x03) + +    /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, +            0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, +    /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, +            0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, +    /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, +            0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, +    /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, +            0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, +    /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, +            0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, +    /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, +            0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, +    /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, +            0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, +    /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, +            0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F, +    /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, +            0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F, +    /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, +            0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, +    /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, +            0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, +    /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, +            0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, +    /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, +            0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF, +    /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, +            0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF, +    /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, +            0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF, +    /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, +            0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF, + +    // Table 4 (for high byte 0x04) + +    /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, +            0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F, +    /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, +            0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, +    /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, +            0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, +    /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, +            0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, +    /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, +            0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, +    /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, +            0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F, +    /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, +            0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F, +    /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, +            0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F, +    /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, +            0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F, +    /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, +            0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F, +    /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, +            0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF, +    /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, +            0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF, +    /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, +            0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF, +    /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, +            0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF, +    /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, +            0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF, +    /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, +            0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, + +    // Table 5 (for high byte 0x05) + +    /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, +            0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F, +    /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, +            0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F, +    /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, +            0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F, +    /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, +            0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, +    /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, +            0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, +    /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, +            0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F, +    /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, +            0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, +    /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, +            0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, +    /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, +            0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F, +    /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, +            0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F, +    /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, +            0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF, +    /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, +            0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, +    /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, +            0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF, +    /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, +            0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, +    /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, +            0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF, +    /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, +            0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF, + +    // Table 6 (for high byte 0x10) + +    /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, +            0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, +    /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, +            0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F, +    /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, +            0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F, +    /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, +            0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F, +    /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, +            0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, +    /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, +            0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F, +    /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, +            0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F, +    /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, +            0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F, +    /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, +            0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, +    /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, +            0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F, +    /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, +            0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, +    /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, +            0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, +    /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, +            0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF, +    /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, +            0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, +    /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, +            0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, +    /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, +            0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF, + +    // Table 7 (for high byte 0x20) + +    /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, +            0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, +            0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, +    /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, +            0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F, +    /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, +            0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F, +    /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, +            0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F, +    /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, +            0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F, +    /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, +            0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +    /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, +            0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, +    /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, +            0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F, +    /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, +            0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F, +    /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, +            0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF, +    /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, +            0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF, +    /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, +            0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, +    /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, +            0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF, +    /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, +            0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF, +    /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, +            0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF, + +    // Table 8 (for high byte 0x21) + +    /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, +            0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F, +    /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, +            0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F, +    /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, +            0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, +    /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, +            0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F, +    /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, +            0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F, +    /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, +            0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F, +    /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, +            0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, +    /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, +            0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, +    /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, +            0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F, +    /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, +            0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F, +    /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, +            0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF, +    /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, +            0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF, +    /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, +            0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF, +    /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, +            0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF, +    /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, +            0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF, +    /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, +            0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF, + +    // Table 9 (for high byte 0xFE) + +    /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, +            0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, +    /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, +            0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F, +    /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, +            0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F, +    /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, +            0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F, +    /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, +            0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, +    /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, +            0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F, +    /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, +            0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F, +    /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, +            0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, +    /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, +            0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F, +    /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, +            0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F, +    /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, +            0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, +    /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, +            0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, +    /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, +            0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF, +    /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, +            0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF, +    /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, +            0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, +    /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, +            0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000, + +    // Table 10 (for high byte 0xFF) + +    /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, +            0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, +    /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, +            0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F, +    /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, +            0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, +    /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, +            0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, +    /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, +            0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, +    /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, +            0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F, +    /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, +            0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, +    /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, +            0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, +    /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, +            0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, +    /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, +            0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, +    /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, +            0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF, +    /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, +            0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF, +    /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, +            0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF, +    /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, +            0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF, +    /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, +            0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF, +    /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, +            0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, +}; diff --git a/roms/openbios/fs/hfsplus/hfsp_volume.c b/roms/openbios/fs/hfsplus/hfsp_volume.c new file mode 100644 index 00000000..2d624e23 --- /dev/null +++ b/roms/openbios/fs/hfsplus/hfsp_volume.c @@ -0,0 +1,323 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * Code to acces the basic volume information of a HFS+ volume. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original work by 1996-1998 Robert Leslie <rob@mars.org> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "volume.h" +#include "record.h" +#include "btree.h" +#include "blockiter.h" +#include "os.h" +#include "swab.h" +#include "hfstime.h" + + +/* Fill a given buffer with the given block in volume. + */ +int +volume_readinbuf(volume * vol,void* buf, long block) +{ +	UInt16 blksize_bits; +	ASSERT( block < vol->maxblocks); + +	blksize_bits = vol->blksize_bits; +	block	+= vol->startblock; +	if( os_seek(vol->os_fd, block, blksize_bits) == block) +		if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits)) +			return 0; +	return -1; +} + +/* read multiple blocks into given memory. + * + * returns given pinter or NULL on failure. + */ +void* +volume_readfromfork(volume* vol, void* buf, +		hfsp_fork_raw* f, UInt32 block, +		UInt32 count, UInt8 forktype, UInt32 fileId) +{ +	blockiter iter; +	char *cbuf = buf; + +	blockiter_init(&iter, vol, f, forktype, fileId); +	if( blockiter_skip(&iter, block)) +		return NULL; + +	while( count > 0) { +		--count; +		if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter))) +			return NULL; +		cbuf += vol->blksize; +		if( count > 0 && blockiter_next(&iter)) +			return NULL; +	} +	return buf; +} + + +/* Read a raw hfsp_extent_rec from memory. + * + * return pointer right after the structure. + */ +void* +volume_readextent(void *p, hfsp_extent_rec er) +{ +	int 		i; +	hfsp_extent	*e; + +	for( i=0; i < 8; i++) { +		e = &er[i]; +		e->start_block = bswabU32_inc(p); +		e->block_count = bswabU32_inc(p); +	} +	return p; +} + +/* Read a raw hfsp_fork from memory. + * + * return pointer right after the structure. + */ +void* +volume_readfork(void *p, hfsp_fork_raw* f) +{ +	f->total_size   = bswabU64_inc(p); +	f->clump_size   = bswabU32_inc(p); +	f->total_blocks = bswabU32_inc(p); + +	return volume_readextent(p, f->extents); +} + +/* Read the volume from the given buffer and swap the bytes. + * + * ToDo: add more consitency checks. + */ +static int +volume_readbuf(hfsp_vh* vh, char * p) +{ +	if(  (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG) +		HFSP_ERROR(-1, "This is not a HFS+ volume"); + +	vh->version		= bswabU16_inc(p); +	vh->attributes   	= bswabU32_inc(p); +	vh->last_mount_vers	= bswabU32_inc(p); +	vh->reserved		= bswabU32_inc(p); +	vh->create_date		= bswabU32_inc(p); +	vh->modify_date		= bswabU32_inc(p); +	vh->backup_date		= bswabU32_inc(p); +	vh->checked_date	= bswabU32_inc(p); +	vh->file_count		= bswabU32_inc(p); +	vh->folder_count	= bswabU32_inc(p); +	vh->blocksize		= bswabU32_inc(p); +	vh->total_blocks	= bswabU32_inc(p); +	vh->free_blocks		= bswabU32_inc(p); +	vh->next_alloc		= bswabU32_inc(p); +	vh->rsrc_clump_sz	= bswabU32_inc(p); +	vh->data_clump_sz	= bswabU32_inc(p); +	vh->next_cnid		= bswabU32_inc(p); +	vh->write_count		= bswabU32_inc(p); +	vh->encodings_bmp	= bswabU64_inc(p); +	memcpy(vh->finder_info, p, 32); +	p += 32; // So finderinfo must be swapped later, *** +	p = volume_readfork(p, &vh->alloc_file ); +	p = volume_readfork(p, &vh->ext_file   ); +	p = volume_readfork(p, &vh->cat_file   ); +	p = volume_readfork(p, &vh->attr_file  ); +        volume_readfork(p, &vh->start_file ); +	return 0; +  fail: +	return -1; +} + +/* Read the volume from the given block */ +static int +volume_read(volume * vol, hfsp_vh* vh, UInt32 block) +{ +	char buf[vol->blksize]; + +	if( volume_readinbuf(vol, buf, block)) +		return -1; +        return volume_readbuf(vh, buf); +} + +/* Find out wether the volume is wrapped and unwrap it eventually */ +static int +volume_read_wrapper(volume * vol, hfsp_vh* vh) +{ +	UInt16  signature; +	char	buf[vol->blksize]; +        char    *p = buf; +	int	ret; +	UInt64	vol_size; +	 +	if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here +		return -1; + +	signature = bswabU16_inc(p); +	if( signature == HFS_VOLHEAD_SIG) {		/* Wrapper */ +		UInt32  drAlBlkSiz;			/* size (in bytes) of allocation blocks */ +		UInt32	sect_per_block;			/* how may block build an hfs sector */ +		UInt16  drAlBlSt;			/* first allocation block in volume */ +		UInt16	embeds, embedl;			/* Start/lenght of embedded area in blocks */ + +		p += 0x12;			/* skip unneded HFS vol fields */ +		drAlBlkSiz = bswabU32_inc(p);		/* offset 0x14 */ +		p += 0x4;			/* skip unneded HFS vol fields */ +		drAlBlSt = bswabU16_inc(p);		/* offset 0x1C */ + +		p += 0x5E;			/* skip unneded HFS vol fields */ +		signature = bswabU16_inc(p);		/* offset 0x7C, drEmbedSigWord */ +		if( signature != HFSP_VOLHEAD_SIG) +			HFSP_ERROR(-1, "This looks like a normal HFS volume"); +		embeds = bswabU16_inc(p); +		embedl = bswabU16_inc(p); +		sect_per_block =  (drAlBlkSiz / HFSP_BLOCKSZ); +		// end is absolute (not relative to HFS+ start) +		vol->maxblocks = embedl * sect_per_block; +		vol->startblock = drAlBlSt + embeds * sect_per_block; +		/* Now we can try to read the embedded HFS+ volume header */ +		return volume_read(vol,vh,2); +	} +	else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ +		p = buf; // Restore to begin of block +                ret = volume_readbuf(vh, p); +		if( !ret ) { +		    /* When reading the initial partition we must use 512 byte blocks */ +		    vol_size = (uint64_t)vh->blocksize * vh->total_blocks; +		    vol->maxblocks = vol_size / HFSP_BLOCKSZ; +		} +		 +		return ret; +	} else +		 HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); +fail: +	return -1; +} + + +/* Open the device, read and verify the volume header +   (and its backup) */ +int +volume_open( volume* vol, int os_fd ) +{ +	hfsp_vh backup;	/* backup volume found at second to last block */ +	long	sect_per_block; +	int	shift; + +	vol->blksize_bits	= HFSP_BLOCKSZ_BITS; +	vol->blksize		= HFSP_BLOCKSZ; +	vol->startblock		= 0; +	vol->maxblocks		= 3; +		/* this should be enough until we find the volume descriptor */ +	vol->extents		= NULL; /* Thanks to Jeremias Sauceda */ + +	btree_reset(&vol->catalog); +	vol->os_fd = os_fd; + +	// vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS); +	// This wont work for /dev/... but we do not really need it + +	if( volume_read_wrapper(vol, &vol->vol)) +		return -1; +	if( volume_read(vol, &backup, vol->maxblocks - 2)) +		return -1; + +	/* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header +	   and adjust depend values accordingly, after that a block always +	   means a HFS+ allocation size */ + +	/* Usually 4096 / 512  == 8 */ +	sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ; +	shift = 0; +	if( sect_per_block > 1) { +		shift = 1; +		while( sect_per_block > 2) { +			sect_per_block >>=1; +			shift++; +		}		/* shift = 3 */ +	} +	vol -> blksize_bits += shift; +	vol -> blksize = 1 << vol->blksize_bits; +	vol -> startblock >>= shift; +	vol -> maxblocks = vol->vol.total_blocks;	/* cant calculate via shift ? */ + +	if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file)) +		return -1; + +	return 0; +} + +/* Write back all data eventually cached and close the device */ +int +volume_close(volume* vol) +{ +	btree_close(&vol->catalog); +	if( vol->extents) { +		btree_close(vol->extents); +		FREE(vol->extents); +	} +	return 0; +} + +/* internal fucntion used to create the extents btree, +   is called by inline function when needed */ +void +volume_create_extents_tree(volume* vol) +{ +	btree* result = (btree*) ALLOC(btree*, sizeof(btree)); +	if( !result) +		HFSP_ERROR(ENOMEM, "No memory for extents btree"); +	if( !btree_init_extent(result, vol, &vol->vol.ext_file)) { +		vol->extents = result; +		return; +	} +  fail: +	vol->extents = NULL; +} + +/* Determine whether the volume is a HFS-plus volume */ +int +volume_probe(int fd, long long offset) +{ +	UInt16 *vol; +	int ret = 0; + +	vol = (UInt16 *)malloc(2 * 1 << HFSP_BLOCKSZ_BITS); +	os_seek_offset( fd, 2 * (1 << HFSP_BLOCKSZ_BITS) + offset ); +	os_read(fd, vol, 2, HFSP_BLOCKSZ_BITS); + +	if (__be16_to_cpu(vol[0]) == HFS_VOLHEAD_SIG && +		__be16_to_cpu(vol[0x3e]) == HFSP_VOLHEAD_SIG) { +		ret = -1; +	} else if (__be16_to_cpu(vol[0]) == HFSP_VOLHEAD_SIG) { +		ret = -1; +	} + +	free(vol); +	return ret; +} + diff --git a/roms/openbios/fs/hfsplus/include/apple.h b/roms/openbios/fs/hfsplus/include/apple.h new file mode 100644 index 00000000..7ba836db --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/apple.h @@ -0,0 +1,111 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file contains defintions that are special for Apple. + * The names match the defintions found in Apple Header files. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original code 1996-1998 by Robert Leslie <rob@mars.rog> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: apple.h,v 1.2 2000/09/08 14:55:08 hasi Exp $ + */ + +typedef signed char	    Char; +typedef unsigned char	    UChar; +typedef signed char	    SInt8; +typedef unsigned char	    UInt8; +typedef signed short	    SInt16; +typedef unsigned short	    UInt16; +typedef signed long	    SInt32; +typedef unsigned long	    UInt32; +typedef unsigned long	    OSType; +typedef unsigned long long  UInt64; + +/* A point, normally used by Quickdraw, + * but found in Finderinformation, too + */ +typedef struct { +  SInt16	v;		/* vertical coordinate */ +  SInt16	h;		/* horizontal coordinate */ +} Point; + +/* A rectancle, normally used by Quickdraw, + * but found in Finderinformation, too. + */ +typedef struct { +  SInt16	top;		/* top edge of rectangle */ +  SInt16	left;		/* left edge */ +  SInt16	bottom;		/* bottom edge */ +  SInt16	right;		/* right edge */ +} Rect; + +/* Information about the location and size of a folder + * used by the Finder. + */ +typedef struct { +  Rect		frRect;		/* folder's rectangle */ +  SInt16	frFlags;	/* flags */ +  Point		frLocation;	/* folder's location */ +  SInt16	frView;		/* folder's view */ +} DInfo; + +/* Extended folder information used by the Finder ... + */ +typedef struct { +  Point		frScroll;	/* scroll position */ +  SInt32	frOpenChain;	/* directory ID chain of open folders */ +  SInt16	frUnused;	/* reserved */ +  SInt16	frComment;	/* comment ID */ +  SInt32	frPutAway;	/* directory ID */ +} DXInfo; + +/* Finder information for a File + */ +typedef struct { +  OSType	fdType;		/* file type */ +  OSType	fdCreator;	/* file's creator */ +  SInt16	fdFlags;	/* flags */ +  Point		fdLocation;	/* file's location */ +  SInt16	fdFldr;		/* file's window */ +} FInfo; + +/* Extendend Finder Information for a file + */ +typedef struct { +  SInt16	fdIconID;	/* icon ID */ +  SInt16	fdUnused[4];	/* reserved */ +  SInt16	fdComment;	/* comment ID */ +  SInt32	fdPutAway;	/* home directory ID */ +} FXInfo; + +/* Flagvalues for FInfo and DInfo */ +# define HFS_FNDR_ISONDESK              (1 <<  0) +# define HFS_FNDR_COLOR                 0x0e +# define HFS_FNDR_COLORRESERVED         (1 <<  4) +# define HFS_FNDR_REQUIRESSWITCHLAUNCH  (1 <<  5) +# define HFS_FNDR_ISSHARED              (1 <<  6) +# define HFS_FNDR_HASNOINITS            (1 <<  7) +# define HFS_FNDR_HASBEENINITED         (1 <<  8) +# define HFS_FNDR_RESERVED              (1 <<  9) +# define HFS_FNDR_HASCUSTOMICON         (1 << 10) +# define HFS_FNDR_ISSTATIONERY          (1 << 11) +# define HFS_FNDR_NAMELOCKED            (1 << 12) +# define HFS_FNDR_HASBUNDLE             (1 << 13) +# define HFS_FNDR_ISINVISIBLE           (1 << 14) +# define HFS_FNDR_ISALIAS               (1 << 15) diff --git a/roms/openbios/fs/hfsplus/include/blockiter.h b/roms/openbios/fs/hfsplus/include/blockiter.h new file mode 100644 index 00000000..da3e480f --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/blockiter.h @@ -0,0 +1,59 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * The iterator shown here iterates over the blocks of a fork. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original work by 1996-1998 Robert Leslie <rob@mars.org> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: blockiter.h,v 1.1 2000/10/10 11:14:05 hasi Exp $ + */ + +/*  Structure of the blockiterator */ +typedef struct +{ +    volume*	    vol;	// volume we iterate over +    UInt32	    curr_block;	// current, absolute block +    UInt32	    block;	// relative block in current extent +    UInt32	    max_block;	// Maximum allowed block +    UInt32	    fileId;	// id of file we iterate over +    int		    index;	// 0 .. 7 in current extent +    hfsp_extent*    file;	// original extent record from file +    hfsp_extent*    e;		// current extentent under examination +    UInt8	    forktype;	// type of fork we iterate over +    UInt8	    in_extent;	// boolean  0 - in file extent +				//	    1 - in extents file +    extent_record   er;		// record to iterate in extents file. +} blockiter; + +/* Initialize iterator for a given fork */ +extern void blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f, +			    UInt8 forktype, UInt32 fileId); + +/* find next block of the fork iterating over */ +extern int blockiter_next(blockiter *b); + +/* skip the indicated number of blocks */ +extern int blockiter_skip(blockiter *b, UInt32 skip); + +/* return current block */ +static inline UInt32 blockiter_curr(blockiter *b) +{ +    return b->e->start_block + b->block; +} diff --git a/roms/openbios/fs/hfsplus/include/btree.h b/roms/openbios/fs/hfsplus/include/btree.h new file mode 100644 index 00000000..46ac8501 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/btree.h @@ -0,0 +1,50 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes. + * + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original 1996-1998 Robert Leslie <rob@mars.org> + * Additional work by  Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: btree.h,v 1.10 2000/10/25 05:43:04 hasi Exp $ + */ + +/** Intialize catalog btree, so that btree_close can safely be called. */ +extern void btree_reset(btree* bt); + +/** Intialize catalog btree */ +extern int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork); + +/** Intialize extents btree */ +extern int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork); + +/** close the btree and free any resources */ +extern void btree_close(btree* bt); + +/* Read node at given index */ +extern node_buf* btree_node_by_index(btree* bt, UInt16 index); + +/* returns pointer to key given by index in current node */ +extern void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index); + +#ifdef DEBUG +    /* Dump all the btree information to stdout */ +  extern void btree_print(btree* bt); +#endif diff --git a/roms/openbios/fs/hfsplus/include/hfs.h b/roms/openbios/fs/hfsplus/include/hfs.h new file mode 100644 index 00000000..5b0cbb49 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/hfs.h @@ -0,0 +1,32 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file includes definitions for access to old HFS structures. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original code 1996-1998 by Robert Leslie <rob@mars.rog> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: hfs.h,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + + +#define HFS_BLOCKSZ		512 +	/* A sector for Apple is always 512 bytes */ +#define HFS_BLOCKSZ_BITS	9	/* 1<<9 == 512  */ +#define	HFS_VOLHEAD_SIG		0x4244	/* 'BD'	*/ diff --git a/roms/openbios/fs/hfsplus/include/hfsp.h b/roms/openbios/fs/hfsplus/include/hfsp.h new file mode 100644 index 00000000..e916473c --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/hfsp.h @@ -0,0 +1,305 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file includes definitions for the structures found on + * HFS+ Volumes. The structures are further wrapped by struct + * found in libhfsp.h. fucntions on those enhanced structures + * are found in files mentioned in comments below. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original code 1996-1998 by Robert Leslie <rob@mars.rog> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: hfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $ + */ + +#define HFSP_BLOCKSZ            512	/* A sector for Apple is always 512 bytes */ +#define HFSP_BLOCKSZ_BITS       9	/* 1<<9 == 512  */ +#define	HFSP_VOLHEAD_SIG	0x482B	/* 'H+'	*/ + +/* HFS+ includes POSIX permissions , although marked as reserved they will be + * used as such. Is ignored by MacOS 8-9 but probably not by MacOS X. + */ +typedef struct { +        UInt32         owner; +        UInt32         group; +        UInt32         mode; +        UInt32         dev; +} hfsp_perm; + +/* A single contiguous area (fragment) of a file */ +typedef struct { +        UInt32         start_block; +        UInt32         block_count; +} hfsp_extent; + +/* A file may contain up to 8 normale extents, all other +   are found in some extra extent area */ +typedef hfsp_extent hfsp_extent_rec[8]; + +/* Information for a "Fork" in a file + * Forks are the "usual" DATA and RSRC forks or special files + * (e.g. the Volume Bitmap) + */ +typedef struct { +        UInt64		total_size;  // logical size +        UInt32		clump_size;  // number of bytes to preallocate +        UInt32		total_blocks; +        hfsp_extent_rec extents;     // initial (8) extents +} hfsp_fork_raw; + +/* HFS+ Volume Header + * Always found at block 2 of the disk, a copy is stored + * at the second to last block of the disk. + */ +typedef struct hfsp_vh { +        UInt16         signature;   // must be HFSPLUS_VOLHEAD_SIG 'H+' +        UInt16         version;     // currently 4, ignored +        UInt32         attributes;  // See bit constants below +        UInt32         last_mount_vers; +                // Use a registered creator code here (what do we use ?) +		// Mac OS uses '8.10' well +        UInt32         reserved; + +        UInt32         create_date; // local time ! +        UInt32         modify_date; // GMT (?) +        UInt32         backup_date; // GMT (?) +        UInt32         checked_date; // GMT (?) fsck ? + +        UInt32         file_count; +         // not including special files but including DATA and RSRC forks +        UInt32         folder_count; // excluding the root folder + +        UInt32         blocksize; +         // must be multiple of HFSPLUS_SECTOR_SIZE, +         // should be a multiple of 4k for harddisk +        UInt32         total_blocks; +        UInt32         free_blocks; +         // The total number of unused allocation blocks on the disk. + +        UInt32         next_alloc; +         // hint wher to search for next allocation blocks +        UInt32         rsrc_clump_sz; +         // default clump size for rsrc forks +        UInt32         data_clump_sz; +         // default clump size for data forks +        UInt32	       next_cnid; +         // next unused catalog id +        UInt32         write_count; +         // increment on every mount (and write ?) +        UInt64        encodings_bmp; +                // for every encoding used on the disk a bit is set +                // ignored but eventually must be cared for +        Char          finder_info[32]; +	hfsp_fork_raw   alloc_file; +         // stores bitmap of use/free blocks +        hfsp_fork_raw   ext_file; +         // stores oferflow extents +        hfsp_fork_raw   cat_file; +	 // This contains the root directory +        hfsp_fork_raw   attr_file; +        hfsp_fork_raw   start_file; +         // a special startup file may be described here (used by ?) +} hfsp_vh; + +/* HFS+ volume attributes */ +/* 0-6 reserved, may be used in memory only */ +#define HFSPLUS_VOL_RESERVED1 0x000000FF +#define HFSPLUS_VOL_HARDLOCK  0x00000080 // Used in Memory by finder only +#define HFSPLUS_VOL_UNMNT     0x00000100 +        // clear this bit when mounting, set as last step of unmounting +        // This is checked by (slower) ROM code +#define HFSPLUS_VOL_SPARE_BLK 0x00000200 +#define HFSPLUS_VOL_NOCACHE   0x00000400 +        // in case of RAM or ROM disk (try a HFS+ Ramdisk :) +#define HFSPLUS_VOL_INCNSTNT  0x00000800 +        // Reverse meaning as of HFSPLUS_VOL_UNMNT +        // This is checked by (faster) Mac OS code +/* 12-14 reserved */ +#define HFSPLUS_VOL_RESERVED2 0x00007000 +#define HFSPLUS_VOL_SOFTLOCK  0x00008000 +#define HFSPLUS_VOL_RESERVED3 0xFFFF0000 + +/* HFS+ Btree node descriptor */ +typedef struct { +	UInt32	    next;   /* pointer to next node of this kind, or 0 */ +	UInt32	    prev;   /* pointer to previous node of this kind, or 0 */ +	UInt8	    kind;   /* see below */ +	UInt8	    height; /* root node starts with 0 */ +	UInt16	    num_rec;	/* number of records in this node */ +	UInt16	    reserved;	/* fill up to 4 byte alignment */ +} btree_node_desc; + +/* HFS+ Btree Node types */ +#define HFSP_NODE_NDX	0x00 +#define HFSP_NODE_HEAD	0x01 +#define HFSP_NODE_MAP	0x02 +#define HFSP_NODE_LEAF	0xFF + +#define HFSP_CATALOG_MIN_NODE_SIZE  0x1000 +#define HFSP_ATTRMIN_DOE_SIZE	    0x1000 + +/* The record offsets are found at the end of the fork + * containing the Btree */ + +typedef UInt16	btree_record_offset; + +typedef struct { +        UInt16         depth; +	    // equal to height of btree_node_desc +        UInt32         root; +	    // root node of the hierarchy +        UInt32         leaf_count; +        UInt32         leaf_head; +        UInt32         leaf_tail; +        UInt16         node_size; +	    // node size of _all_ nodes in this fork +        UInt16         max_key_len; +        UInt32         node_count; +	    // count of all (free and used) nodes in tree +        UInt32         free_nodes; +        UInt16         reserved1; +        UInt32         clump_size; +         // ignored my MacOS used by ? +        UInt8	       btree_type; +         // always 0 for HFS+ +        UInt8	       reserved2; +        UInt32         attributes; +	 // see below +        UInt32         reserved3[16]; +} btree_head; + +/* BTree attributes */ +#define HFSPLUS_BAD_CLOSE            0x01 +  // Btree was not properly closed and should be checked +  // not used for HFS+ but reserved +#define HFSPLUS_TREE_BIGKEYS         0x02 +  // always set for HFS+ +#define HFSPLUS_TREE_VAR_NDXKEY_SIZE 0x04 +  // use variable length index nodes, always set for catalog btree, +  // always cleared for extents btree. + +#define HFSPLUS_TREE_UNUSED          0xFFFFFFF8 + +/* Some special File ID numbers */ +#define HFSP_POR_CNID             1  /* Parent Of the Root */ +#define HFSP_ROOT_CNID            2  /* ROOT directory */ +#define HFSP_EXT_CNID             3  /* EXTents B-tree */ +#define HFSP_CAT_CNID             4  /* CATalog B-tree */ +#define HFSP_BAD_CNID             5  /* BAD blocks file */ +#define HFSP_ALLOC_CNID           6  /* ALLOCation file */ +#define HFSP_START_CNID           7  /* STARTup file */ +#define HFSP_ATTR_CNID            8  /* ATTRibutes file  */ +#define HFSP_EXCH_CNID           15  /* ExchangeFiles temp id */ +#define HFPS_MIN_CNID		 15  /* Minimum expected value */ + +/* Unicode String */ +typedef struct { +    UInt16		strlen; +    UInt16		name[255];	// unicode charcters +} hfsp_unistr255; + +/* HFS+ catalog entry key */ +typedef struct { +    UInt16		key_length;	/* excluding length */ +    UInt32		parent_cnid; +    hfsp_unistr255	name; +} hfsp_cat_key; + +/* HFS+ exnteds entry key */ +typedef struct { +    UInt16		key_length;	/* excluding length */ +    UInt8		fork_type;	/* Seee below */ +    UInt8		filler; +    UInt32		file_id; +    UInt32		start_block; +} hfsp_extent_key; + +#define HFSP_EXTENT_DATA    0x00 +#define HFSP_EXTENT_RSRC    0xFF + +/* The key is followed by a record, an index or some other data */ + +/* The types of these records are defined as follows */ + +#define HFSP_FOLDER         0x0001  // entry fo a Folder +#define HFSP_FILE           0x0002  // entry for a File +#define HFSP_FOLDER_THREAD  0x0003 +    // Like '.' in unix, identifies the folder by its id, only +#define HFSP_FILE_THREAD    0x0004 +    // Im unsure if this is used by HFS+, too + +/* HFS+ folder data (part of an hfsp_cat_entry) */ +typedef struct { +    UInt16          flags;		/* no flags defined yet */ +    UInt32	    valence;		/* Numer of files and folders contained in folder */ +    UInt32	    id; +    UInt32	    create_date;	// GMT +    UInt32	    content_mod_date;	// GMT +    UInt32	    attribute_mod_date;	// GMT +    UInt32	    access_date;	// GMT +    UInt32	    backup_date;	// GMT +    hfsp_perm	    permissions; +    DInfo	    user_info; +    DXInfo	    finder_info; +    UInt32	    text_encoding; +	 // hint fo the finder what encoding to use, unused here +    UInt32         reserved; +} hfsp_cat_folder; + +/* HFS+ file data (part of a cat_entry) */ +typedef struct { +    UInt16          flags;		/* See below */ +    UInt32	    reserved1; +    UInt32	    id; +    UInt32	    create_date; +    UInt32	    content_mod_date; +    UInt32	    attribute_mod_date; +    UInt32	    access_date; +    UInt32	    backup_date; +    hfsp_perm	    permissions; +    FInfo           user_info; +    FXInfo	    finder_info; +    UInt32	    text_encoding; +    UInt32	    reserved2; + +    hfsp_fork_raw   data_fork; +    hfsp_fork_raw   res_fork; +} hfsp_cat_file; + +/* File attribute bits */ +#define HFSP_FILE_LOCKED      0x0001 +#define HFSP_THREAD_EXISTS    0x0002 /* Always set in HFS+ */ + +/* HFS+ catalog thread (part of a cat_entry) */ +typedef struct { +    UInt16          reserved; +    UInt32	    parentID; +    hfsp_unistr255   nodeName; +} hfsp_cat_thread; + + +/* A data record in the catalog tree */ +typedef struct { +    UInt16	    type; +    union { +	hfsp_cat_folder folder; +	hfsp_cat_file   file; +	hfsp_cat_thread thread; +    } u; +} hfsp_cat_entry; diff --git a/roms/openbios/fs/hfsplus/include/hfstime.h b/roms/openbios/fs/hfsplus/include/hfstime.h new file mode 100644 index 00000000..bb6bd4a6 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/hfstime.h @@ -0,0 +1,34 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>^ + * Original 1996-1998 Robert Leslie <rob@mars.org> + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * The HFS+ dates are stored as UInt32 containing the number of seconds since + * midnight, January 1, 1904, GMT. This is slightly different from HFS, + * where the value represents local time. A notable exception is the + * creationdate !. Linux uses times in GMT starting at  January 1, 1970 + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: hfstime.h,v 1.2 2000/10/19 13:33:38 hasi Exp $ + */ + +    /* The number of seconds between 1.1.1904 and 1.1.1970 */ +#define HFSPTIMEDIFF 2082844800U + +   /* return the given apple time as UNIX time */ +extern char* get_atime(UInt32 atime); diff --git a/roms/openbios/fs/hfsplus/include/libhfsp.h b/roms/openbios/fs/hfsplus/include/libhfsp.h new file mode 100644 index 00000000..912cfbd0 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/libhfsp.h @@ -0,0 +1,201 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann (khalfmann@libra.de) + * Original work by 1996-1998 Robert Leslie (rob@mars.org) + * + * This file defines constants,structs etc needed for this library. + * Everything found here is usually not related to Apple defintions. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: libhfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $ + */ + +# include "apple.h" +# include "hfs.h" +# include "hfsp.h" + +/* Last error is eventually found here */ +extern const char *hfsp_error; + +# define HFSP_ERROR(code, str)  \ +    do { hfsp_error = (str), errno = (code); goto fail; } while (0) + +# ifdef DEBUG +#  define ASSERT(cond)	do { if (! (cond)) abort(); } while (0) +# else +#  define ASSERT(cond)	/* nothing */ +# endif + +# define SIZE(type, n)		((size_t) (sizeof(type) * (n))) +# define ALLOC(type, n)		((type *) malloc(SIZE(type, n))) +# define ALLOCX(type, n)	((n) ? ALLOC(type, n) : (type *) 0) +# define FREE(ptr)		((ptr) ? (void) free((void *) ptr) : (void) 0) + +# define REALLOC(ptr, type, n)  \ +    ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n)))) +# define REALLOCX(ptr, type, n)  \ +    ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0)) + +# define BMTST(bm, num)  \ +    (((const byte *) (bm))[(num) >> 3]  &  (0x80 >> ((num) & 0x07))) +# define BMSET(bm, num)  \ +          (((byte *) (bm))[(num) >> 3] |=  (0x80 >> ((num) & 0x07))) +# define BMCLR(bm, num)  \ +          (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07))) + +# define STRINGIZE(x)		#x +# define STR(x)			STRINGIZE(x) + +/* used by internal routines to specify the open modes */ +# define HFSP_MODE_RDONLY        0 +# define HFSP_MODE_RDWR          1 +# define HFSP_MODE_ANY           2 + +/* Signatures registered with Apple to identify this driver */ +    /* Identifies the userland implementation */ +# define HPLS_SIGNATURE 0x482B4C58	// 'H+LX' +    /* Identifies the kernel module by Brad Boyer (flar@pants.nu) */ +# define HPLS_SIGRES1	0x482B4C78	// 'H+Lx' +    /* not jet in use ... */ +# define HPLS_SIGRES2	0x482B6C78	// 'H+lx' +    /* Signature used by Apple */ +# define HPAPPLE_SIGNATURE  0x382e3130	// '8.10' + +/* Version used for this implementation of HFS+. This is not related + * to the VERSION file found at the top-level of this package, + * but designates the version of the low level code */ +#define HPLS_VERSION	1   /* must fit in a short */ + + +/* Othe Signatures may follow for informational purpos */ + +/* prototype for key comparing functions. */ +typedef int (*hfsp_key_compare) (void* key1, void* key2); + +/* prototype for key reading (necessary for byte swapping) */ +typedef void* (*hfsp_key_read) (void* p, void* key); + +struct volume; /* foreward declaration for btree needed */ + +/* Structures for a node cache. The cache is an array + * with linear search. (So making it to big may make + * things slower). It is searched in a round robin + * fashion. + */ + +typedef struct +{ +    UInt32		priority; +	// as lower this number as higher the priority. +	// decremetned on any sucessfull usage +	// incremented else, intial value height*DEPTHFACTOR +    UInt16		index;	// of node in fork +	// 0 means empty, since first node is node header +	// contents of node in original byte order +    UInt16		flags;	// like DIRTY etc. +} node_entry; + +typedef struct +{ +    UInt32		index;	    // duplicate of above +    btree_node_desc	desc;	    // header of node +    char		node[0];    // actual node_size +	// contents of node in original byte order +} node_buf; + +typedef struct +{ +    int		size;	     // number of nodes in the cache +    int		currindex;   // round robin index +    int		nodebufsize; // size of complete node_buf, including node +    node_entry	*entries; +    char	*buffers;   // actually *node_buf +} node_cache; + +typedef struct +{ +    struct volume*	vol;	/* pointer to volume this tree is part of */ +    hfsp_fork_raw*	fork;	/* pointer to fork this tree is part of */ +    UInt32		cnid;	/* (pseudo) file id for the fork */ +    hfsp_key_compare	kcomp; +	/* function used for key compare in _this_ btree */ +    hfsp_key_read	kread; +	/* fucntion used to read a key int _this_ btree */ +    btree_head		head; + +    UInt16		blkpernode; +	 /* Number of volume blocks per node (usually 1-4) */ +    node_cache		cache; +    /* Warning all functions of btrees and records may modify +       the following values ! */ +    // UInt16		node_index; /* index of node in fork */ +    // btree_node_desc	node;	/* current node under examination */ +    // char*		buf;	/* buf with size of a node */ +} btree; + +/* Function on btrees are defined in btree.h */ + +/* A Wrapper around the raw hfs+ volume header for additional information + * needed by this library. + */ + +typedef struct volume +{ +    int		os_fd;		/* OS dependend reference to device */ +    UInt16	blksize_bits;   /* blocksize of device = 1 << blksize_bits */ +    UInt16	filler; +    UInt32	blksize;	/* always 1 << blksize_bits */ +    UInt32	startblock; +	/* Offset from physical to logical blocks, +	   eventually intodruced by HFS wrapper */ +    UInt32  	maxblocks;	/* maximum number of blocks in device */ +    // UInt32	currblock;	/* value of current block, to cache blocks */ +    hfsp_vh	vol;		/* raw volume data */ +    // void*	blockbuf;	/* (single) buffer for fetching one block */ +     /* Buffer has double size of blksize to allow cross block reading */ + +    btree*	extents;	/* is NULL by default and intialized when needed */ +    btree	catalog;	/* This is always neeeded */ +} volume; + +/* Functions on volumes are defined in volume.h */ + +typedef struct {    // may not be used as found here +    btree*		tree;	// tree where this record is contained in. +    UInt16		node_index; /* index of record in btree */ +    UInt16		keyind;	/* index of current key in btree */ +    hfsp_cat_key	key;	/* current key */ +    UInt32		child;	/* child node belonging to this key */ +} index_record; + +typedef struct { +    btree*		tree;	// tree where this record is contained in. +    UInt16		node_index; /* index of record in btree */ +    UInt16		keyind;	/* index of current key in btree */ +    hfsp_extent_key	key;	/* current key */ +    hfsp_extent_rec	extent; /* The payload carried around */ +} extent_record; + +typedef struct { +    btree*		tree;	// tree where this record is contained in. +    UInt16		node_index; /* index of record in btree */ +    UInt16		keyind;	/* index of current key in btree */ +    hfsp_cat_key	key;	/* current key */ +    hfsp_cat_entry	record;	/* current record */ +} record; + +/* Functions on records are defined in record.h */ diff --git a/roms/openbios/fs/hfsplus/include/record.h b/roms/openbios/fs/hfsplus/include/record.h new file mode 100644 index 00000000..6454f552 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/record.h @@ -0,0 +1,80 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes. + * + * a record contains a key and a folder or file and is part + * of a btree. + * + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de> + * Original 1996-1998 Robert Leslie <rob@mars.org> + * Additional work by  Brad Boyer (flar@pants.nu) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: record.h,v 1.10 2000/10/01 17:08:05 hasi Exp $ + */ + +/* Compare two cat_keys ... */ +extern int record_key_compare(void* k1, void* k2); + +/* Compare two extent_keys ... */ +extern int record_extent_key_compare(void* k1, void* k2); + +/* read a catalog key into a given buffer */ +extern void* record_readkey(void* p, void* buf); + +/* read an extent key into a given buffer */ +extern void* record_extent_readkey(void* p, void* buf); + +/* intialize the record to the first record of the tree + * which is (per design) the root node. + */ +extern int record_init_root(record* r, btree* tree); + +/* intialize the record to the folder given by cnid. + */ +extern int record_init_cnid(record* r, btree* tree, UInt32 cnid); + +/* intialize the record to the first record of the parent. + */ +extern int record_init_parent(record* r, record* parent); + +/* intialize the record by searching for the given string in the given folder. + * + * parent and r may be the same. + */ +extern int record_init_string_parent(record* r, record* parent, char* key); + +/* move record up in folder hierarchy (if possible) */ +extern int record_up(record* r); + +/* move record foreward to next entry. + * + * In case of an error the value of *r is undefined ! + */ +extern int record_next(record* r); + +/* intialize the extent_record to the extent identified by + * a given file */ +extern int record_init_file(extent_record* r, btree* tree, +		    UInt8 forktype, UInt32 fileId, UInt32 blockindex); + +/* move foreward to next entent record. */ +extern int record_next_extent(extent_record *r); + +#ifdef DEBUG +    /* Dump all the record information to stdout */ +  extern void record_print(record* r); +#endif diff --git a/roms/openbios/fs/hfsplus/include/swab.h b/roms/openbios/fs/hfsplus/include/swab.h new file mode 100644 index 00000000..c424008e --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/swab.h @@ -0,0 +1,64 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * Copyright (C) 2000 Klaus Halfmann <klaus.halfmann@feri.de> + * Original work 1996-1998 Robert Leslie <rob@mars.org> + * + * This file defines some byte swapping function. I did not find this + * in any standard or linux way. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: swab.h,v 1.1.1.1 2002/03/05 19:50:29 klaus Exp $ + */ + +#include "config.h" +#include "libc/byteorder.h" + + /* basic fuction: +    value = swab_inc(ptr); +	ptr is afterwards incremented by sizeof(value) + */ + +#ifndef CONFIG_BIG_ENDIAN + +#define bswabU16(val) __bswap16(val) + +#define bswabU16_inc(ptr) (__extension__ ({ UInt16 v=__bswap16(*((UInt16*) (ptr))); ptr+=sizeof(UInt16);v;})) +#define bswabU32_inc(ptr) (__extension__ ({ UInt32 v=__bswap32(*((UInt32*) (ptr))); ptr+=sizeof(UInt32);v;})) +#define bswabU64_inc(ptr) (__extension__ ({ UInt64 v=__bswap64(*((UInt64*) (ptr))); ptr+=sizeof(UInt64);v;})) + +#define bstoreU16_inc(ptr, val) do {(*((UInt16*) (ptr))) = __bswap16(val); ptr+=sizeof(UInt16);} while (0) +#define bstoreU32_inc(ptr, val) do {(*((UInt32*) (ptr))) = __bswap32(val); ptr+=sizeof(UInt32);} while (0) +#define bstoreU64_inc(ptr, val) do {(*((UInt64*) (ptr))) = __bswap64(val); ptr+=sizeof(UInt64);} while (0) + +#else // BYTE_ORDER == BIG_ENDIAN + +#define bswabU16(val) val + +#define bswabU16_inc(ptr) (__extension__ ({ UInt16 v=(*((UInt16*) (ptr))); ptr+=sizeof(UInt16);v;})) +#define bswabU32_inc(ptr) (__extension__ ({ UInt32 v=(*((UInt32*) (ptr))); ptr+=sizeof(UInt32);v;})) +#define bswabU64_inc(ptr) (__extension__ ({ UInt64 v=(*((UInt64*) (ptr))); ptr+=sizeof(UInt64);v;})) + +#define bstoreU16_inc(ptr, val) do {(*((UInt16*) (ptr))) = val; ptr+=sizeof(UInt16);} while (0) +#define bstoreU32_inc(ptr, val) do {(*((UInt32*) (ptr))) = val; ptr+=sizeof(UInt32);} while (0) +#define bstoreU64_inc(ptr, val) do {(*((UInt64*) (ptr))) = val; ptr+=sizeof(UInt64);} while (0) + +#endif + +/* for the sake of compleetness and readability */ +#define bswabU8_inc(ptr)	(__extension__ ({ UInt8 v=(*((UInt8*) (ptr))); ptr+=sizeof(UInt8);v;})) +#define bstoreU8_inc(ptr,val)	do {(*((UInt8*) (ptr))) = val; ptr+=sizeof(UInt8);} while (0) diff --git a/roms/openbios/fs/hfsplus/include/unicode.h b/roms/openbios/fs/hfsplus/include/unicode.h new file mode 100644 index 00000000..e7c86f78 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/unicode.h @@ -0,0 +1,28 @@ +/* + *  linux/fs/hfsplus/unicode.c + * + * Copyright (C) 1999-2000  Brad Boyer (flar@pants.nu) + * This file may be distributed under the terms of the GNU Public License. + * + * The routines found here convert hfs-unicode string into ascii Strings + * and vice versa.  And the correct comparison between Strings. + */ + +/* convert the asci string astr into a unicode string given by ustr. + * + * returns actual length of convertet string. + */ + +int unicode_asc2uni(hfsp_unistr255 *ustr, const char *astr); + +/* Convert an unicode string ustr to a ascii string astr of given maximum len + * + * returns actual length of convertet string. + */ + +int unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen); + +/* similar to strcmp for unicode, pascal strings */ + +SInt32 fast_unicode_compare (const hfsp_unistr255 *ustr1, +			     const hfsp_unistr255 *ustr2); diff --git a/roms/openbios/fs/hfsplus/include/volume.h b/roms/openbios/fs/hfsplus/include/volume.h new file mode 100644 index 00000000..19be0550 --- /dev/null +++ b/roms/openbios/fs/hfsplus/include/volume.h @@ -0,0 +1,87 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>^ + * Original 1996-1998 Robert Leslie <rob@mars.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: volume.h,v 1.11 2000/10/17 05:58:46 hasi Exp $ + */ + +#ifndef _H_VOLUME +#define _H_VOLUME + +/* Open the device, read and verify the volume header +   (and its backup) */ +extern int volume_open(volume* vol, int os_fd); + +/* Write back all data eventually cached and close the device. */ +extern int volume_close(volume* vol); + +/* read multiple blocks into given memory. + * + * returns given pointer or NULL on failure. + */ +extern void* volume_readfromfork(volume* vol, void* buf, +	hfsp_fork_raw* f, UInt32 block, +	UInt32 count, UInt8 forktype, UInt32 fileId); + +/* Fill a given buffer with the given block in volume. + */ +int volume_readinbuf(volume * vol,void* buf, long block); + +/* invalidat cache hold in volume, will be removed when + * caching strategy is clear to me. */ +/* +extern inline void volume_invalidate_cache(volume* vol) +{ +    vol -> currblock = (UInt32) -1; +} +*/ + +/* Check in Allocation file if given block is allocated. */ +extern int volume_allocated(volume* v, UInt32 block); + +/* Read a raw hfsp_extent_rec from memory. */ +extern void* volume_readextent(void *p, hfsp_extent_rec er); + +/* Read fork information from raw memory */ +extern void* volume_readfork(void *p, hfsp_fork_raw* f); + +/* internal function used to create the extents btree, +   is called by following inline fucntion when needed */ +extern void volume_create_extents_tree(volume* vol); + +/* accessor for entends btree, is created on demand */ +static inline btree* volume_get_extents_tree(volume* vol) { +    if (!vol->extents) +	volume_create_extents_tree(vol); +    return vol->extents; +} + +/* Determine whether the volume is a HFS-plus volume */ +int volume_probe(int fd, long long offset); + +#ifdef DEBUG +    /* Print raw fork information to stdout */ +  void volume_print_fork(hfsp_fork_raw* f); +    /* Dump all the volume information to stdout */ +  void volume_print(hfsp_vh* vol); +#endif + + + +#endif   /* _H_VOLUME */ diff --git a/roms/openbios/fs/hfsplus/libhfsp.c b/roms/openbios/fs/hfsplus/libhfsp.c new file mode 100644 index 00000000..af1cde6a --- /dev/null +++ b/roms/openbios/fs/hfsplus/libhfsp.c @@ -0,0 +1,29 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * Thi file contains utitlity fucntions to manage the features of + * the hfs+ library. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: libhfsp.c,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + +#include "config.h" +#include "libhfsp.h" + +const char *hfsp_error = "no error";       /* static error string */ diff --git a/roms/openbios/fs/ioglue.c b/roms/openbios/fs/ioglue.c new file mode 100644 index 00000000..1d33d8fd --- /dev/null +++ b/roms/openbios/fs/ioglue.c @@ -0,0 +1,92 @@ +/* + *   Creation Date: <2001/05/06 22:27:09 samuel> + *   Time-stamp: <2003/12/12 02:24:56 samuel> + * + *	<fs.c> + * + *     	I/O API used by the filesystem code + * + *   Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + *   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/diskio.h" +#include "os.h" +#include "hfs_mdb.h" + +/************************************************************************/ +/*	functionsions used by the various filesystems			*/ +/************************************************************************/ + +char * +get_hfs_vol_name( int fd, char *buf, int size ) +{ +	char sect[512]; +	hfs_mdb_t *mdb = (hfs_mdb_t*)§ + +	seek_io( fd, 0x400 ); +	read_io( fd, sect, sizeof(sect) ); +	if( hfs_get_ushort(mdb->drSigWord) == HFS_SIGNATURE ) { +		unsigned int n = mdb->drVN[0]; +		if( n >= size ) +			n = size - 1; +		memcpy( buf, &mdb->drVN[1], n ); +		buf[n] = 0; +	} else if( hfs_get_ushort(mdb->drSigWord) == HFS_PLUS_SIGNATURE ) { +		strncpy( buf, "Unembedded HFS+", size ); +	} else { +		strncpy( buf, "Error", size ); +	} +	return buf; +} + +unsigned long +os_read( int fd, void *buf, unsigned long len, int blksize_bits ) +{ +	/* printk("os_read %d\n", (int)len); */ + +	int cnt = read_io( fd, buf, len << blksize_bits ); +	return (cnt > 0)? (cnt >> blksize_bits) : cnt; +} + +unsigned long +os_seek( int fd, unsigned long blknum, int blksize_bits ) +{ +	/* printk("os_seek %d\n", blknum ); */ +	long long offs = (long long)blknum << blksize_bits; + +	/* offset == -1 means seek to EOF */ +	if( (int)blknum == -1 ) +		offs = -1; + +	if( seek_io(fd, offs) ) { +		/* printk("os_seek failure\n"); */ +		return (unsigned long)-1; +	} + +	if( (int)blknum == -1 ) { +		if( (offs=tell(fd)) < 0 ) +			return -1; +		blknum = offs >> blksize_bits; +	} +	return blknum; +} + +void +os_seek_offset( int fd, long long offset ) +{ +	seek_io(fd, offset); +} + +int +os_same( int fd1, int fd2 ) +{ +	return fd1 == fd2; +} diff --git a/roms/openbios/fs/iso9660/build.xml b/roms/openbios/fs/iso9660/build.xml new file mode 100644 index 00000000..00d39021 --- /dev/null +++ b/roms/openbios/fs/iso9660/build.xml @@ -0,0 +1,13 @@ +<build> + <library name="fs" type="static" target="target"> +  <object source="iso9660_fs.c" condition="ISO9660"/> +  <object source="iso9660_close.c" condition="ISO9660"/> +  <object source="iso9660_closedir.c" condition="ISO9660"/> +  <object source="iso9660_lseek.c" condition="ISO9660"/> +  <object source="iso9660_mount.c" condition="ISO9660"/> +  <object source="iso9660_open.c" condition="ISO9660"/> +  <object source="iso9660_opendir.c" condition="ISO9660"/> +  <object source="iso9660_read.c" condition="ISO9660"/> +  <object source="iso9660_readdir.c" condition="ISO9660"/> + </library> +</build> diff --git a/roms/openbios/fs/iso9660/iso9660.h b/roms/openbios/fs/iso9660/iso9660.h new file mode 100644 index 00000000..ac6dcf09 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660.h @@ -0,0 +1,58 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#ifndef __ISO9660_H__ +#define __ISO9660_H__ + +#include "iso9660_fs.h" + +typedef struct iso9660_VOLUME { +	int ucs_level; +	struct iso_primary_descriptor *descriptor; +	int fd; +} iso9660_VOLUME; + +typedef struct iso9660_DIR { +	iso9660_VOLUME *volume; +	int extent; +	int len; +	int index; +	unsigned char buffer[ISOFS_BLOCK_SIZE]; +} iso9660_DIR; + +typedef struct iso9660_FILE { +	iso9660_VOLUME *volume; +	char *path; +	int base;			/* first extent of the file */ +	int size;			/* size of the file */ +	int offset; +	int current; +	unsigned char buffer[ISOFS_BLOCK_SIZE]; +} iso9660_FILE; + +static inline int isonum_721(char *p) +{ +        return ((p[0] & 0xff) +                | ((p[1] & 0xff) << 8)); +} + +static inline int isonum_723(char *p) +{ +        return (isonum_721(p)); +} + +static inline int isonum_733(char *p) +{ +	return ((p[0] & 0xff) | ((p[1] & 0xff) << 8) | +		((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24)); +} + +extern struct iso_directory_record *iso9660_get_root_node(iso9660_VOLUME* volume); +extern struct iso_directory_record* iso9660_get_node(iso9660_VOLUME *volume, struct iso_directory_record *dirnode, const char *path); + +#endif /* __ISO9660_H__ */ diff --git a/roms/openbios/fs/iso9660/iso9660_close.c b/roms/openbios/fs/iso9660/iso9660_close.c new file mode 100644 index 00000000..ce79c0fd --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_close.c @@ -0,0 +1,15 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE bootloader, http://emile.sf.net + * + */ + +#include "libiso9660.h" + +void iso9660_close(iso9660_FILE *file) +{ +	free(file->path); +	free(file); +} diff --git a/roms/openbios/fs/iso9660/iso9660_closedir.c b/roms/openbios/fs/iso9660/iso9660_closedir.c new file mode 100644 index 00000000..706cc222 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_closedir.c @@ -0,0 +1,19 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" + +int iso9660_closedir(iso9660_DIR *dir) +{ +	if (dir == NULL) +		return -1; + +	free(dir); + +	return 0; +} diff --git a/roms/openbios/fs/iso9660/iso9660_fs.c b/roms/openbios/fs/iso9660/iso9660_fs.c new file mode 100644 index 00000000..d6f547be --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_fs.c @@ -0,0 +1,263 @@ +/* + * /packages/iso9660-files filesystem handler + * + * (c) 2009 Laurent Vivier <Laurent@vivier.eu> + * (c) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk> + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "libiso9660.h" +#include "fs/fs.h" +#include "libc/vsprintf.h" +#include "libc/diskio.h" + +extern void     iso9660_init( void ); + +typedef struct { +	enum { FILE, DIR } type; +	union { +		iso9660_FILE *file; +		iso9660_DIR * dir; +	}; +} iso9660_COMMON; + +typedef struct { +	iso9660_VOLUME *volume; +	iso9660_COMMON *common; +} iso9660_info_t; + +DECLARE_NODE( iso9660, 0, sizeof(iso9660_info_t), "+/packages/iso9660-files" ); + +/* ( -- success? ) */ +static void +iso9660_files_open( iso9660_info_t *mi ) +{ +	int fd; +	char *path = my_args_copy(); + +	if ( ! path ) +		RET( 0 ); +  +	fd = open_ih( my_parent() ); +	if ( fd == -1 ) { +		free( path ); +		RET( 0 ); +	} +  +	mi->volume = iso9660_mount( fd ); +	if ( mi->volume == NULL ) { +		free( path ); +		close_io( fd ); +		RET( 0 ); +	} + +	mi->common->dir = iso9660_opendir( mi->volume, path ); +	if ( mi->common->dir == NULL ) { +		mi->common->file = iso9660_open( mi->volume, path ); +		if (mi->common->file == NULL) { +			iso9660_umount( mi->volume ); +			close_io( fd ); +			free( path ); +			RET( 0 ); +		} +		mi->common->type = FILE; +		free( path ); +		RET( -1 ); + 	} +	mi->common->type = DIR; +	free( path ); + +	RET( -1 ); +} + +/* ( -- ) */ +static void +iso9660_files_close( iso9660_info_t *mi ) +{ +	int fd = mi->volume->fd; +  +	if (mi->common->type == FILE ) +		iso9660_close( mi->common->file ); +	else if ( mi->common->type == DIR ) +		iso9660_closedir( mi->common->dir ); +	iso9660_umount( mi->volume ); +	close_io( fd ); +} + +/* ( buf len -- actlen ) */ +static void +iso9660_files_read( iso9660_info_t *mi ) +{ +	int count = POP(); +	char *buf = (char *)cell2pointer(POP()); +	int ret; +  +	if ( mi->common->type != FILE ) +		PUSH( 0 ); +  +	ret = iso9660_read( mi->common->file, buf, count ); +  +	PUSH( ret ); +} + +/* ( pos.d -- status ) */ +static void +iso9660_files_seek( iso9660_info_t *mi ) +{ +	long long pos = DPOP(); +	cell ret; +	int offs = (int)pos; +	int whence = SEEK_SET; + +	if (mi->common->type != FILE) +		PUSH( -1 ); + +	if( offs == -1 ) { +		offs = 0; +		whence = SEEK_END; +	} +  +	ret = iso9660_lseek(mi->common->file, offs, whence); +  +	PUSH( (ret < 0)? -1 : 0 ); +} + +/* ( -- filepos.d ) */ +static void +iso9660_files_offset( iso9660_info_t *mi ) +{ +	if ( mi->common->type != FILE ) +		DPUSH( -1 ); +  +	DPUSH( mi->common->file->offset ); +} + +/* ( addr -- size ) */ +static void +iso9660_files_load( iso9660_info_t *mi) +{ +	char *buf = (char*)cell2pointer(POP()); +	int ret, size; +  +	if ( mi->common->type != FILE ) +		PUSH( 0 ); +  +	size = 0; +	while(1) { +		ret = iso9660_read( mi->common->file, buf, 512 ); +		if (ret <= 0) +			break; +		buf += ret; +		size += ret; +		if (ret != 512) +			break; +	} +	PUSH( size ); +} + +/* static method, ( pathstr len ihandle -- ) */ +static void +iso9660_files_dir( iso9660_info_t *dummy ) +{ +	iso9660_VOLUME *volume; +	iso9660_COMMON *common; +	struct iso_directory_record *idr; +	char name_buf[256]; +	int fd; +  +	ihandle_t ih = POP(); +	char *path = pop_fstr_copy(); + +	fd = open_ih( ih ); +	if ( fd == -1 ) { +		free( path ); +		return; +	} +  +	volume = iso9660_mount( fd ); +	if ( volume == NULL ) { +		free ( path ); +		close_io( fd ); +		return; +	} + +	common = malloc(sizeof(iso9660_COMMON)); +	common->dir = iso9660_opendir( volume, path ); + +	forth_printf("\n"); +	while ( (idr = iso9660_readdir(common->dir)) ) { +  +		forth_printf("% 10d ", isonum_733(idr->size)); +		forth_printf("%d-%02d-%02d %02d:%02d:%02d ", +			     idr->date[0] + 1900, /* year */ +			     idr->date[1], /* month */ +                             idr->date[2], /* day */ +			     idr->date[3], idr->date[4], idr->date[5]); +		iso9660_name(common->dir->volume, idr, name_buf); +		if (idr->flags[0] & 2) +			forth_printf("%s\\\n", name_buf); +		else +			forth_printf("%s\n", name_buf); +	} + +	iso9660_closedir( common->dir ); +	iso9660_umount( volume ); + +	close_io( fd ); + +	free( common ); +	free( path ); +} + +/* static method, ( pos.d ih -- flag? ) */ +static void +iso9660_files_probe( iso9660_info_t *dummy ) +{ +	ihandle_t ih = POP_ih(); +	long long offs = DPOP(); +	int fd, ret = 0; + +	fd = open_ih(ih); +        if (fd >= 0) { +                if (iso9660_probe(fd, offs)) { +                        ret = -1; +                } +                close_io(fd); +        } else { +                ret = -1; +        } + +	RET (ret); +} + +static void +iso9660_files_block_size( iso9660_info_t *dummy ) +{ +	PUSH(2048); +} +  +static void +iso9660_initializer( iso9660_info_t *dummy ) +{ +	fword("register-fs-package"); +} +  +NODE_METHODS( iso9660 ) = { +	{ "probe",	iso9660_files_probe		}, +	{ "open",	iso9660_files_open		}, +	{ "close",	iso9660_files_close		}, +	{ "read",	iso9660_files_read		}, +	{ "seek",	iso9660_files_seek		}, +	{ "offset",	iso9660_files_offset		}, +	{ "load",	iso9660_files_load		}, +	{ "dir",	iso9660_files_dir		}, +	{ "block-size",	iso9660_files_block_size	}, +	{ NULL,		iso9660_initializer	}, +}; + +void +iso9660_init( void ) +{ +	REGISTER_NODE( iso9660 ); +} diff --git a/roms/openbios/fs/iso9660/iso9660_fs.h b/roms/openbios/fs/iso9660/iso9660_fs.h new file mode 100644 index 00000000..0de124da --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_fs.h @@ -0,0 +1,161 @@ +#ifndef _ISO9660_FS_H +#define _ISO9660_FS_H + +/* this file has been copied from linux 2.6.26 */ + +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { +	char type[ISODCL(1,1)]; /* 711 */ +	char id[ISODCL(2,6)]; +	char version[ISODCL(7,7)]; +	char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_SUPPLEMENTARY 2 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +struct iso_primary_descriptor { +	char type			[ISODCL (  1,   1)]; /* 711 */ +	char id				[ISODCL (  2,   6)]; +	char version			[ISODCL (  7,   7)]; /* 711 */ +	char unused1			[ISODCL (  8,   8)]; +	char system_id			[ISODCL (  9,  40)]; /* achars */ +	char volume_id			[ISODCL ( 41,  72)]; /* dchars */ +	char unused2			[ISODCL ( 73,  80)]; +	char volume_space_size		[ISODCL ( 81,  88)]; /* 733 */ +	char unused3			[ISODCL ( 89, 120)]; +	char volume_set_size		[ISODCL (121, 124)]; /* 723 */ +	char volume_sequence_number	[ISODCL (125, 128)]; /* 723 */ +	char logical_block_size		[ISODCL (129, 132)]; /* 723 */ +	char path_table_size		[ISODCL (133, 140)]; /* 733 */ +	char type_l_path_table		[ISODCL (141, 144)]; /* 731 */ +	char opt_type_l_path_table	[ISODCL (145, 148)]; /* 731 */ +	char type_m_path_table		[ISODCL (149, 152)]; /* 732 */ +	char opt_type_m_path_table	[ISODCL (153, 156)]; /* 732 */ +	char root_directory_record	[ISODCL (157, 190)]; /* 9.1 */ +	char volume_set_id		[ISODCL (191, 318)]; /* dchars */ +	char publisher_id		[ISODCL (319, 446)]; /* achars */ +	char preparer_id		[ISODCL (447, 574)]; /* achars */ +	char application_id		[ISODCL (575, 702)]; /* achars */ +	char copyright_file_id		[ISODCL (703, 739)]; /* 7.5 dchars */ +	char abstract_file_id		[ISODCL (740, 776)]; /* 7.5 dchars */ +	char bibliographic_file_id	[ISODCL (777, 813)]; /* 7.5 dchars */ +	char creation_date		[ISODCL (814, 830)]; /* 8.4.26.1 */ +	char modification_date		[ISODCL (831, 847)]; /* 8.4.26.1 */ +	char expiration_date		[ISODCL (848, 864)]; /* 8.4.26.1 */ +	char effective_date		[ISODCL (865, 881)]; /* 8.4.26.1 */ +	char file_structure_version	[ISODCL (882, 882)]; /* 711 */ +	char unused4			[ISODCL (883, 883)]; +	char application_data		[ISODCL (884, 1395)]; +	char unused5			[ISODCL (1396, 2048)]; +}; + +/* Almost the same as the primary descriptor but two fields are specified */ +struct iso_supplementary_descriptor { +	char type			[ISODCL (  1,   1)]; /* 711 */ +	char id				[ISODCL (  2,   6)]; +	char version			[ISODCL (  7,   7)]; /* 711 */ +	char flags			[ISODCL (  8,   8)]; /* 853 */ +	char system_id			[ISODCL (  9,  40)]; /* achars */ +	char volume_id			[ISODCL ( 41,  72)]; /* dchars */ +	char unused2			[ISODCL ( 73,  80)]; +	char volume_space_size		[ISODCL ( 81,  88)]; /* 733 */ +	char escape			[ISODCL ( 89, 120)]; /* 856 */ +	char volume_set_size		[ISODCL (121, 124)]; /* 723 */ +	char volume_sequence_number	[ISODCL (125, 128)]; /* 723 */ +	char logical_block_size		[ISODCL (129, 132)]; /* 723 */ +	char path_table_size		[ISODCL (133, 140)]; /* 733 */ +	char type_l_path_table		[ISODCL (141, 144)]; /* 731 */ +	char opt_type_l_path_table	[ISODCL (145, 148)]; /* 731 */ +	char type_m_path_table		[ISODCL (149, 152)]; /* 732 */ +	char opt_type_m_path_table	[ISODCL (153, 156)]; /* 732 */ +	char root_directory_record	[ISODCL (157, 190)]; /* 9.1 */ +	char volume_set_id		[ISODCL (191, 318)]; /* dchars */ +	char publisher_id		[ISODCL (319, 446)]; /* achars */ +	char preparer_id		[ISODCL (447, 574)]; /* achars */ +	char application_id		[ISODCL (575, 702)]; /* achars */ +	char copyright_file_id		[ISODCL (703, 739)]; /* 7.5 dchars */ +	char abstract_file_id		[ISODCL (740, 776)]; /* 7.5 dchars */ +	char bibliographic_file_id	[ISODCL (777, 813)]; /* 7.5 dchars */ +	char creation_date		[ISODCL (814, 830)]; /* 8.4.26.1 */ +	char modification_date		[ISODCL (831, 847)]; /* 8.4.26.1 */ +	char expiration_date		[ISODCL (848, 864)]; /* 8.4.26.1 */ +	char effective_date		[ISODCL (865, 881)]; /* 8.4.26.1 */ +	char file_structure_version	[ISODCL (882, 882)]; /* 711 */ +	char unused4			[ISODCL (883, 883)]; +	char application_data		[ISODCL (884, 1395)]; +	char unused5			[ISODCL (1396, 2048)]; +}; + + +#define HS_STANDARD_ID "CDROM" + +struct  hs_volume_descriptor { +	char foo			[ISODCL (  1,   8)]; /* 733 */ +	char type			[ISODCL (  9,   9)]; /* 711 */ +	char id				[ISODCL ( 10,  14)]; +	char version			[ISODCL ( 15,  15)]; /* 711 */ +	char data[ISODCL(16,2048)]; +}; + + +struct hs_primary_descriptor { +	char foo			[ISODCL (  1,   8)]; /* 733 */ +	char type			[ISODCL (  9,   9)]; /* 711 */ +	char id				[ISODCL ( 10,  14)]; +	char version			[ISODCL ( 15,  15)]; /* 711 */ +	char unused1			[ISODCL ( 16,  16)]; /* 711 */ +	char system_id			[ISODCL ( 17,  48)]; /* achars */ +	char volume_id			[ISODCL ( 49,  80)]; /* dchars */ +	char unused2			[ISODCL ( 81,  88)]; /* 733 */ +	char volume_space_size		[ISODCL ( 89,  96)]; /* 733 */ +	char unused3			[ISODCL ( 97, 128)]; /* 733 */ +	char volume_set_size		[ISODCL (129, 132)]; /* 723 */ +	char volume_sequence_number	[ISODCL (133, 136)]; /* 723 */ +	char logical_block_size		[ISODCL (137, 140)]; /* 723 */ +	char path_table_size		[ISODCL (141, 148)]; /* 733 */ +	char type_l_path_table		[ISODCL (149, 152)]; /* 731 */ +	char unused4			[ISODCL (153, 180)]; /* 733 */ +	char root_directory_record	[ISODCL (181, 214)]; /* 9.1 */ +}; + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ +	unsigned char  name_len[2];	/* 721 */ +	char extent[4];		/* 731 */ +	char  parent[2];	/* 721 */ +	char name[0]; +} __attribute__((packed)); + +/* high sierra is identical to iso, except that the date is only 6 bytes, and +   there is an extra reserved byte after the flags */ + +struct iso_directory_record { +	char length			[ISODCL (1, 1)]; /* 711 */ +	char ext_attr_length		[ISODCL (2, 2)]; /* 711 */ +	char extent			[ISODCL (3, 10)]; /* 733 */ +	char size			[ISODCL (11, 18)]; /* 733 */ +	char date			[ISODCL (19, 25)]; /* 7 by 711 */ +	char flags			[ISODCL (26, 26)]; +	char file_unit_size		[ISODCL (27, 27)]; /* 711 */ +	char interleave			[ISODCL (28, 28)]; /* 711 */ +	char volume_sequence_number	[ISODCL (29, 32)]; /* 723 */ +	unsigned char name_len		[ISODCL (33, 33)]; /* 711 */ +	char name			[0]; +} __attribute__((packed)); + +#define ISOFS_BLOCK_BITS 11 +#define ISOFS_BLOCK_SIZE (1 << ISOFS_BLOCK_BITS) + +#endif /* _ISO9660_FS_H */ diff --git a/roms/openbios/fs/iso9660/iso9660_lseek.c b/roms/openbios/fs/iso9660/iso9660_lseek.c new file mode 100644 index 00000000..62987583 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_lseek.c @@ -0,0 +1,37 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" + +int iso9660_lseek(iso9660_FILE *_file, long offset, int whence) +{ +	iso9660_FILE *file = (iso9660_FILE*)_file; +	long new_offset; + +	switch(whence) +	{ +	case SEEK_SET: +		new_offset = offset; +		break; +	case SEEK_CUR: +		new_offset = file->offset + offset; +		break; +	case SEEK_END: +		new_offset = file->size + offset; +		break; +	default: +		return -1; +	} + +	if ( (new_offset < 0) || (new_offset > file->size) ) +		return -1; + +	file->offset = new_offset; + +	return new_offset; +} diff --git a/roms/openbios/fs/iso9660/iso9660_mount.c b/roms/openbios/fs/iso9660/iso9660_mount.c new file mode 100644 index 00000000..a5817040 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_mount.c @@ -0,0 +1,210 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + * some parts from mkisofs (c) J. Schilling + * + */ + +#include "libiso9660.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" + +void iso9660_name(iso9660_VOLUME *volume, struct iso_directory_record *idr, char *buffer) +{ +	int	j; +        unsigned char ul, uc; + +	buffer[0] = 0; +	if (idr->name_len[0] == 1 && idr->name[0] == 0) +		strcpy(buffer, "."); +	else if (idr->name_len[0] == 1 && idr->name[0] == 1) +		strcpy(buffer, ".."); +	else { +		switch (volume->ucs_level) { +		case 3: +		case 2: +		case 1: +			/* +			 * Unicode name. +			 */ + +			for (j = 0; j < (int)idr->name_len[0] / 2; j++) { +				ul = idr->name[j*2+1]; + +				/* +				 * unicode convertion +				 * up = unls->unls_uni2cs[uh]; +				 * +				 * if (up == NULL) +				 *	uc = '\0'; +				 * else +				 *	uc = up[ul]; +				 * +				 * we use only low byte +				 */ + +				uc = ul; + +				buffer[j] = uc ? uc : '_'; +			} +			buffer[idr->name_len[0]/2] = '\0'; +			break; +		case 0: +			/* +			 * Normal non-Unicode name. +			 */ +			strncpy(buffer, idr->name, idr->name_len[0]); +			buffer[idr->name_len[0]] = 0; +			break; +		default: +			/* +			 * Don't know how to do these yet.  Maybe they are the same +			 * as one of the above. +			 */ +			break; +		} +	} +} + +iso9660_VOLUME *iso9660_mount(int fd) +{ +	iso9660_VOLUME* volume; +	struct iso_primary_descriptor *jpd; +	struct iso_primary_descriptor ipd; +	int	block; +	int ucs_level = 0; + +	/* read filesystem descriptor */ + +	seek_io(fd, 16 * ISOFS_BLOCK_SIZE); +	read_io(fd, &ipd, sizeof (ipd)); + +	/* +	 * High sierra: +	 * +	 *	DESC TYPE	== 1 (VD_SFS)	offset 8	len 1 +	 *	STR ID		== "CDROM"	offset 9	len 5 +	 *	STD_VER		== 1		offset 14	len 1 +	 */ + +	/* High Sierra format ? */ + +	if ((((char *)&ipd)[8] == 1) && +	    (strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) && +	    (((char *)&ipd)[14] == 1)) { +		printk("Incompatible format: High Sierra format\n"); +		return NULL; +	} + +	/* +	 * ISO 9660: +	 * +	 *	DESC TYPE	== 1 (VD_PVD)	offset 0	len 1 +	 *	STR ID		== "CD001"	offset 1	len 5 +	 *	STD_VER		== 1		offset 6	len 1 +	 */ + +	/* NOT ISO 9660 format ? */ + +	if ((ipd.type[0] != ISO_VD_PRIMARY) || +	    (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) || +	    (ipd.version[0] != 1)) { +		return NULL; +	} + +	/* UCS info */ + +	block = 16; + +	jpd = (struct iso_primary_descriptor *) +		malloc(sizeof(struct iso_primary_descriptor)); +	if (jpd == NULL) +		return NULL; + +	memcpy(jpd, &ipd, sizeof (ipd)); +	while ((uint8_t)jpd->type[0] != ISO_VD_END) { + +		/* +		 * If Joliet UCS escape sequence found, we may be wrong +		 */ + +		if (jpd->unused3[0] == '%' && +		    jpd->unused3[1] == '/' && +		    (jpd->unused3[3] == '\0' || +		    jpd->unused3[3] == ' ') && +		    (jpd->unused3[2] == '@' || +		    jpd->unused3[2] == 'C' || +		    jpd->unused3[2] == 'E')) { + +			if (jpd->version[0] != 1) +				break; +		} + +		block++; +		seek_io(fd, block * ISOFS_BLOCK_SIZE); +		read_io(fd, jpd, sizeof (*jpd)); +	} + +	ucs_level = 0; +	if (((unsigned char) jpd->type[0] == ISO_VD_END)) { +		memcpy(jpd, &ipd, sizeof (ipd)); +	} else { +		switch (jpd->unused3[2]) { +		case '@': +			ucs_level = 1; +			break; +		case 'C': +			ucs_level = 2; +			break; +		case 'E': +			ucs_level = 3; +			break; +		} + +		if (ucs_level && jpd->unused3[3] == ' ') +			printk("Warning: Joliet escape sequence uses illegal space at offset 3\n"); +	} + +	volume = (iso9660_VOLUME*)malloc(sizeof(iso9660_VOLUME)); +	if (volume == NULL) +		return NULL; + +	volume->descriptor = jpd; +	volume->ucs_level = ucs_level; +	volume->fd = fd; + +	return volume; +} + +int iso9660_umount(iso9660_VOLUME* volume) +{ +	if (volume == NULL) +		return -1; +	free(volume->descriptor); +	free(volume); +	return 0; +} + +int iso9660_probe(int fd, long long offset) +{ +	struct iso_primary_descriptor ipd; + +	seek_io(fd, 16 * ISOFS_BLOCK_SIZE + offset); +	read_io(fd, &ipd, sizeof (ipd)); + +	if ((ipd.type[0] != ISO_VD_PRIMARY) || +	    (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) || +	    (ipd.version[0] != 1)) { +		return 0; +	} + +	return -1; +} + +struct iso_directory_record *iso9660_get_root_node(iso9660_VOLUME* volume) +{ +	return (struct iso_directory_record *)volume->descriptor->root_directory_record; +} diff --git a/roms/openbios/fs/iso9660/iso9660_open.c b/roms/openbios/fs/iso9660/iso9660_open.c new file mode 100644 index 00000000..77c271f0 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_open.c @@ -0,0 +1,39 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" + +iso9660_FILE* iso9660_open(iso9660_VOLUME *volume, const char* pathname) +{ +	struct iso_directory_record *root; +	struct iso_directory_record *idr; +	iso9660_FILE *file; + +	root = iso9660_get_root_node(volume); +	if (root == NULL) +		return NULL; + +	idr = iso9660_get_node(volume, root, pathname); +	if (idr == NULL) +		return NULL; + +	file = (iso9660_FILE*)malloc(sizeof(iso9660_FILE)); +	if (file == NULL) +		return NULL; + +	file->base = isonum_733((char *)idr->extent); +	file->size = isonum_733((char *)idr->size); +	file->offset = 0; +	file->current = -1; +	file->volume = volume; +	file->path = strdup(pathname); + +	free(idr); + +	return file; +} diff --git a/roms/openbios/fs/iso9660/iso9660_opendir.c b/roms/openbios/fs/iso9660/iso9660_opendir.c new file mode 100644 index 00000000..49eab4b4 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_opendir.c @@ -0,0 +1,133 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" + +static inline int iso9660_is_directory(struct iso_directory_record * idr) +{ +	return ((idr->flags[0] & 2) != 0); +} + +static iso9660_DIR* iso9660_opendir_node(iso9660_VOLUME *volume, struct iso_directory_record *node) +{ +	iso9660_DIR *dir; + +	dir = (iso9660_DIR*)malloc(sizeof(iso9660_DIR)); +	if (dir == NULL) +		return NULL; + +	dir->extent = isonum_733((char *)node->extent); +	dir->len = isonum_733((char *)node->size); +	dir->index =  sizeof (dir->buffer); +	dir->volume = volume; + +	return dir; +} + +static struct iso_directory_record* idr_new(struct iso_directory_record* idr) +{ +	struct iso_directory_record* result; +	int size = sizeof(*idr) + (int)idr->name_len[0]; + +	result = (struct iso_directory_record*)malloc(size); +	memcpy(result, idr, size); + +	return result; +} + +static struct iso_directory_record * seek_name(iso9660_VOLUME *volume, +					       struct iso_directory_record *idr, +					       char *name) +{ +	struct iso_directory_record *result; +	char name_buf[256]; +	iso9660_DIR *dir; + +	dir = iso9660_opendir_node(volume, idr); +	if (dir == NULL) +		return NULL; + +	while ((idr = iso9660_readdir(dir)) != NULL) +	{ +		iso9660_name(volume, idr, name_buf); +		if (strcasecmp(name, name_buf) == 0) +		{ +			result = idr_new(idr); +			iso9660_closedir(dir); +			return result; +		} +	} +	iso9660_closedir(dir); +	return NULL; +} + +struct iso_directory_record* iso9660_get_node( +		iso9660_VOLUME *volume, +		struct iso_directory_record *dirnode, +		const char *path) +{ +	struct iso_directory_record* result; +	struct iso_directory_record* current; +	char name[256]; +	int i; + +	current = idr_new(dirnode); +	while(1) +	{ +		/* ignore head '\' */ + +		while (*path && *path == '\\') +			path++; + +		if (*path == 0) +			break; + +		/* extract first path component */ + +		i = 0; +		while (*path && *path != '\\') +			name[i++] = *path++; +		name[i] = 0; + +		/* seek first component in current directory */ + +		result = seek_name(volume, current, name); +		if (result == NULL) +			return NULL; + +		free(current); +		current = result; +	} +	return current; +} + +iso9660_DIR* iso9660_opendir(iso9660_VOLUME *volume, const char *name) +{ +	iso9660_DIR *dir; +	struct iso_directory_record *node; + +	node = iso9660_get_root_node((iso9660_VOLUME*)volume); +	if (node == NULL) +		return NULL; + +	node = iso9660_get_node((iso9660_VOLUME*)volume, node, name); +	if (node == NULL) +		return NULL; +	if (!iso9660_is_directory(node)) { +		free(node); +		return NULL; +	} + +	dir = iso9660_opendir_node((iso9660_VOLUME*)volume, node); + +	free(node); + +	dir->volume = (iso9660_VOLUME*)volume; + +	return dir; +} diff --git a/roms/openbios/fs/iso9660/iso9660_read.c b/roms/openbios/fs/iso9660/iso9660_read.c new file mode 100644 index 00000000..22cc463f --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_read.c @@ -0,0 +1,74 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" + +size_t iso9660_read(iso9660_FILE *_file, char *buf, size_t count) +{ +	iso9660_FILE *file = (iso9660_FILE*)_file; +	size_t read = 0; + +	if ( count > (file->size  - file->offset) ) +		count = file->size  - file->offset; + +	while (count > 0) +	{ +		size_t part; +		int offset_extent; +		int offset_index; + +		offset_extent = file->base + +				    (file->offset / ISOFS_BLOCK_SIZE); +		offset_index = file->offset % ISOFS_BLOCK_SIZE; + +		if (file->current != offset_extent) +		{ +			if ( (offset_index == 0) && +			     (count >= ISOFS_BLOCK_SIZE) ) +			{ +				/* direct i/o */ + +				int extents_nb; + +				extents_nb = count / ISOFS_BLOCK_SIZE; + +				part = extents_nb * ISOFS_BLOCK_SIZE; + +				seek_io(file->volume->fd, +					offset_extent * ISOFS_BLOCK_SIZE); +				read_io(file->volume->fd, buf + read, part); + +				file->offset += part; +				count -= part; +				read += part; + +				continue; +			} + +			file->current = offset_extent; +			seek_io(file->volume->fd, +				offset_extent * ISOFS_BLOCK_SIZE); +			read_io(file->volume->fd, file->buffer, +				ISOFS_BLOCK_SIZE); +		} + +		part = ISOFS_BLOCK_SIZE - offset_index; +		if (count < part) +			part = count; + +		memcpy(buf + read, file->buffer + offset_index, part); + +		file->offset += part; +		count -= part; +		read += part; +	} + +	return read; +} diff --git a/roms/openbios/fs/iso9660/iso9660_readdir.c b/roms/openbios/fs/iso9660/iso9660_readdir.c new file mode 100644 index 00000000..003ffb20 --- /dev/null +++ b/roms/openbios/fs/iso9660/iso9660_readdir.c @@ -0,0 +1,50 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#include "libiso9660.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" + +#define offsetof(t,m)	((long)&(((t *)0)->m)) + +static void read_extent(iso9660_DIR *dir) +{ +	seek_io(dir->volume->fd, dir->extent * ISOFS_BLOCK_SIZE); +	read_io(dir->volume->fd, dir->buffer, ISOFS_BLOCK_SIZE); + +	dir->len -= ISOFS_BLOCK_SIZE; +	dir->extent ++; +	dir->index = 0; +} + +struct iso_directory_record *iso9660_readdir(iso9660_DIR *dir) +{ +	struct iso_directory_record *idr; + +	if (dir->index > +	    ISOFS_BLOCK_SIZE - offsetof(struct iso_directory_record, name[0])) +	{ +		if (dir->len <= 0) +			return NULL; + +		read_extent(dir); +	} + +	idr = (struct iso_directory_record *) &dir->buffer[dir->index]; +	if (idr->length[0] == 0)  { +		if (dir->len <= 0) +			return NULL; + +		read_extent(dir); +		idr = (struct iso_directory_record *) &dir->buffer[dir->index]; +	} + +	dir->index += dir->buffer[dir->index]; + +	return idr; +} diff --git a/roms/openbios/fs/iso9660/libiso9660.h b/roms/openbios/fs/iso9660/libiso9660.h new file mode 100644 index 00000000..8a5b4801 --- /dev/null +++ b/roms/openbios/fs/iso9660/libiso9660.h @@ -0,0 +1,27 @@ +/* + * + * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu> + * + * This file has been copied from EMILE, http://emile.sf.net + * + */ + +#ifndef __LIBISO9660_H__ +#define __LIBISO9660_H__ + +#include "config.h" +#include "iso9660.h" + +extern iso9660_VOLUME* iso9660_mount(int fd); +extern int iso9660_umount(iso9660_VOLUME *volume); +extern int iso9660_probe(int fd, long long offs); +extern iso9660_DIR* iso9660_opendir(iso9660_VOLUME *, const char *name); +extern iso9660_FILE* iso9660_open(iso9660_VOLUME *, const char *pathname); +extern int iso9660_closedir(iso9660_DIR *dir); +extern struct iso_directory_record *iso9660_readdir(iso9660_DIR *dir); +extern size_t iso9660_read(iso9660_FILE *file, char *buf, size_t count); +extern void iso9660_close(iso9660_FILE *file); +extern int iso9660_lseek(iso9660_FILE *file, long offset, int whence); +extern void iso9660_name(iso9660_VOLUME *volume, struct iso_directory_record * idr, char *buffer); + +#endif /* __LIBISO9660_H__ */ diff --git a/roms/openbios/fs/os.h b/roms/openbios/fs/os.h new file mode 100644 index 00000000..b0375f7e --- /dev/null +++ b/roms/openbios/fs/os.h @@ -0,0 +1,57 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998, 2003 Robert Leslie + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: os.h,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + +#ifndef _H_OS +#define _H_OS + +/* + * NAME:	os->same() + * DESCRIPTION:	return 1 iff path is same as the open descriptor + */ +int os_same( int fd1, int fd2 ); + +/* + * NAME:	os->seek() + * DESCRIPTION:	set a descriptor's seek pointer (offset in blocks) + */ +unsigned long os_seek( int fd, unsigned long offset, int blksize_bits); + +/* + * NAME:	os->read() + * DESCRIPTION:	read blocks from an open descriptor + */ +unsigned long os_read( int fd, void *buf, unsigned long len, int blksize_bits); + +/* + * NAME:	os->write() + * DESCRIPTION:	write blocks to an open descriptor + */ +unsigned long os_write( int fd, const void *buf, unsigned long len, int blksize_bits); + +/* + * NAME:	os->seek_offset() + * DESCRIPTION:	set a descriptor's seek pointer (offset in bytes) + */ +void os_seek_offset( int fd, long long offset ); + + +#endif   /* _H_OS */  | 
