summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/fs
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/fs
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openbios/fs')
-rw-r--r--qemu/roms/openbios/fs/build.xml14
-rw-r--r--qemu/roms/openbios/fs/ext2/build.xml14
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2.h33
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_close.c18
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_closedir.c18
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_fs.c309
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_fs.h534
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_lseek.c38
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_mount.c62
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_open.c65
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_opendir.c49
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_read.c23
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_readdir.c25
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_utils.c332
-rw-r--r--qemu/roms/openbios/fs/ext2/ext2_utils.h54
-rw-r--r--qemu/roms/openbios/fs/ext2/libext2.h25
-rw-r--r--qemu/roms/openbios/fs/grubfs/Kconfig83
-rw-r--r--qemu/roms/openbios/fs/grubfs/build.xml17
-rw-r--r--qemu/roms/openbios/fs/grubfs/debug.h1
-rw-r--r--qemu/roms/openbios/fs/grubfs/defs.h86
-rw-r--r--qemu/roms/openbios/fs/grubfs/dir.h141
-rw-r--r--qemu/roms/openbios/fs/grubfs/disk_inode.h110
-rw-r--r--qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h101
-rw-r--r--qemu/roms/openbios/fs/grubfs/fat.h99
-rw-r--r--qemu/roms/openbios/fs/grubfs/filesys.h303
-rw-r--r--qemu/roms/openbios/fs/grubfs/fs.h457
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_affs.c712
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c794
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_fat.c477
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ffs.c311
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_iso9660.c342
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_jfs.c404
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_minix.c535
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ntfs.c1255
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c1220
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ufs.c391
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_vstafs.c254
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_xfs.c639
-rw-r--r--qemu/roms/openbios/fs/grubfs/glue.h48
-rw-r--r--qemu/roms/openbios/fs/grubfs/grubfs_fs.c398
-rw-r--r--qemu/roms/openbios/fs/grubfs/iso9660.h167
-rw-r--r--qemu/roms/openbios/fs/grubfs/jfs.h604
-rw-r--r--qemu/roms/openbios/fs/grubfs/shared.h3
-rw-r--r--qemu/roms/openbios/fs/grubfs/ufs_dinode.h191
-rw-r--r--qemu/roms/openbios/fs/grubfs/ufs_fs.h635
-rw-r--r--qemu/roms/openbios/fs/grubfs/vstafs.h89
-rw-r--r--qemu/roms/openbios/fs/grubfs/xfs.h546
-rw-r--r--qemu/roms/openbios/fs/hfs/block.c612
-rw-r--r--qemu/roms/openbios/fs/hfs/btree.c230
-rw-r--r--qemu/roms/openbios/fs/hfs/build.xml15
-rw-r--r--qemu/roms/openbios/fs/hfs/data.c476
-rw-r--r--qemu/roms/openbios/fs/hfs/file.c191
-rw-r--r--qemu/roms/openbios/fs/hfs/hfs.c747
-rw-r--r--qemu/roms/openbios/fs/hfs/hfs_fs.c593
-rw-r--r--qemu/roms/openbios/fs/hfs/include/apple.h273
-rw-r--r--qemu/roms/openbios/fs/hfs/include/block.h41
-rw-r--r--qemu/roms/openbios/fs/hfs/include/btree.h34
-rw-r--r--qemu/roms/openbios/fs/hfs/include/data.h57
-rw-r--r--qemu/roms/openbios/fs/hfs/include/file.h46
-rw-r--r--qemu/roms/openbios/fs/hfs/include/hfs.h180
-rw-r--r--qemu/roms/openbios/fs/hfs/include/libhfs.h225
-rw-r--r--qemu/roms/openbios/fs/hfs/include/low.h45
-rw-r--r--qemu/roms/openbios/fs/hfs/include/medium.h43
-rw-r--r--qemu/roms/openbios/fs/hfs/include/node.h35
-rw-r--r--qemu/roms/openbios/fs/hfs/include/record.h48
-rw-r--r--qemu/roms/openbios/fs/hfs/include/volume.h71
-rw-r--r--qemu/roms/openbios/fs/hfs/low.c157
-rw-r--r--qemu/roms/openbios/fs/hfs/medium.c84
-rw-r--r--qemu/roms/openbios/fs/hfs/node.c60
-rw-r--r--qemu/roms/openbios/fs/hfs/record.c553
-rw-r--r--qemu/roms/openbios/fs/hfs/volume.c612
-rw-r--r--qemu/roms/openbios/fs/hfs_mdb.h118
-rw-r--r--qemu/roms/openbios/fs/hfsplus/build.xml11
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c141
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_btree.c372
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_fs.c632
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_record.c759
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c511
-rw-r--r--qemu/roms/openbios/fs/hfsplus/hfsp_volume.c323
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/apple.h111
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/blockiter.h59
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/btree.h50
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/hfs.h32
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/hfsp.h305
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/hfstime.h34
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/libhfsp.h201
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/record.h80
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/swab.h64
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/unicode.h28
-rw-r--r--qemu/roms/openbios/fs/hfsplus/include/volume.h87
-rw-r--r--qemu/roms/openbios/fs/hfsplus/libhfsp.c29
-rw-r--r--qemu/roms/openbios/fs/ioglue.c92
-rw-r--r--qemu/roms/openbios/fs/iso9660/build.xml13
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660.h58
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_close.c15
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_closedir.c19
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_fs.c263
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_fs.h161
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_lseek.c37
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_mount.c210
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_open.c39
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_opendir.c133
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_read.c74
-rw-r--r--qemu/roms/openbios/fs/iso9660/iso9660_readdir.c50
-rw-r--r--qemu/roms/openbios/fs/iso9660/libiso9660.h27
-rw-r--r--qemu/roms/openbios/fs/os.h57
106 files changed, 23649 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/build.xml b/qemu/roms/openbios/fs/build.xml
new file mode 100644
index 000000000..9ecc00553
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/build.xml b/qemu/roms/openbios/fs/ext2/build.xml
new file mode 100644
index 000000000..98e9e0569
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2.h b/qemu/roms/openbios/fs/ext2/ext2.h
new file mode 100644
index 000000000..ad8589284
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_close.c b/qemu/roms/openbios/fs/ext2/ext2_close.c
new file mode 100644
index 000000000..f370e181e
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_closedir.c b/qemu/roms/openbios/fs/ext2/ext2_closedir.c
new file mode 100644
index 000000000..e9f06319c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_fs.c b/qemu/roms/openbios/fs/ext2/ext2_fs.c
new file mode 100644
index 000000000..66eb0b438
--- /dev/null
+++ b/qemu/roms/openbios/fs/ext2/ext2_fs.c
@@ -0,0 +1,309 @@
+/*
+ * /packages/ext2-files
+ *
+ * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info>
+ * (c) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
+ *
+ * This file has been copied from EMILE, http://emile.sf.net
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libext2.h"
+#include "ext2_utils.h"
+#include "fs/fs.h"
+#include "libc/vsprintf.h"
+#include "libc/diskio.h"
+
+extern void ext2_init( void );
+
+typedef struct {
+ enum { FILE, DIR } type;
+ union {
+ ext2_FILE *file;
+ ext2_DIR *dir;
+ };
+} ext2_COMMON;
+
+typedef struct {
+ ext2_VOLUME *volume;
+ ext2_COMMON *common;
+} ext2_info_t;
+
+DECLARE_NODE( ext2, 0, sizeof(ext2_info_t), "+/packages/ext2-files" );
+
+
+static const int days_month[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int days_month_leap[12] =
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static inline int is_leap(int year)
+{
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+}
+
+static void
+print_date(time_t sec)
+{
+ unsigned int second, minute, hour, month, day, year;
+ int current;
+ const int *days;
+
+ second = sec % 60;
+ sec /= 60;
+
+ minute = sec % 60;
+ sec /= 60;
+
+ hour = sec % 24;
+ sec /= 24;
+
+ year = sec * 100 / 36525;
+ sec -= year * 36525 / 100;
+ year += 1970;
+
+ days = is_leap(year) ? days_month_leap : days_month;
+
+ current = 0;
+ month = 0;
+ while (month < 12) {
+ if (sec <= current + days[month]) {
+ break;
+ }
+ current += days[month];
+ month++;
+ }
+ month++;
+
+ day = sec - current + 1;
+
+ forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
+ year, month, day, hour, minute, second);
+}
+
+
+/************************************************************************/
+/* Standard package methods */
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+ext2_files_open( ext2_info_t *mi )
+{
+ int fd;
+ char *path = my_args_copy();
+
+ fd = open_ih( my_parent() );
+ if ( fd == -1 ) {
+ free( path );
+ RET( 0 );
+ }
+
+ mi->volume = ext2_mount(fd);
+ if (!mi->volume) {
+ RET( 0 );
+ }
+
+ mi->common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON));
+ if (mi->common == NULL)
+ RET( 0 );
+
+ mi->common->dir = ext2_opendir(mi->volume, path);
+ if (mi->common->dir == NULL) {
+ mi->common->file = ext2_open(mi->volume, path);
+ if (mi->common->file == NULL) {
+ free(mi->common);
+ RET( 0 );
+ }
+ mi->common->type = FILE;
+ RET( -1 );
+ }
+ mi->common->type = DIR;
+ RET( -1 );
+}
+
+/* ( -- ) */
+static void
+ext2_files_close( ext2_info_t *mi )
+{
+ ext2_COMMON *common = mi->common;
+
+ if (common->type == FILE)
+ ext2_close(common->file);
+ else if (common->type == DIR)
+ ext2_closedir(common->dir);
+ free(common);
+
+ ext2_umount(mi->volume);
+}
+
+/* ( buf len -- actlen ) */
+static void
+ext2_files_read( ext2_info_t *mi )
+{
+ int count = POP();
+ char *buf = (char *)cell2pointer(POP());
+
+ ext2_COMMON *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ RET ( ext2_read( common->file, buf, count ) );
+}
+
+/* ( pos.d -- status ) */
+static void
+ext2_files_seek( ext2_info_t *mi )
+{
+ long long pos = DPOP();
+ int offs = (int)pos;
+ int whence = SEEK_SET;
+ int ret;
+ ext2_COMMON *common = mi->common;
+
+ if (common->type != FILE)
+ RET( -1 );
+
+ ret = ext2_lseek(common->file, offs, whence);
+ if (ret)
+ RET( -1 );
+ else
+ RET( 0 );
+}
+
+/* ( addr -- size ) */
+static void
+ext2_files_load( ext2_info_t *mi )
+{
+ char *buf = (char *)cell2pointer(POP());
+ int count;
+
+ ext2_COMMON *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ /* Seek to the end in order to get the file size */
+ ext2_lseek(common->file, 0, SEEK_END);
+ count = common->file->offset;
+ ext2_lseek(common->file, 0, SEEK_SET);
+
+ RET ( ext2_read( common->file, buf, count ) );
+}
+
+/* ( -- cstr ) */
+static void
+ext2_files_get_path( ext2_info_t *mi )
+{
+ ext2_COMMON *common = mi->common;
+
+ if (common->type != FILE)
+ RET( 0 );
+
+ RET( pointer2cell(strdup(common->file->path)) );
+}
+
+/* ( -- cstr ) */
+static void
+ext2_files_get_fstype( ext2_info_t *mi )
+{
+ PUSH( pointer2cell(strdup("ext2")) );
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+ext2_files_dir( ext2_info_t *dummy )
+{
+ ext2_COMMON *common;
+ ext2_VOLUME *volume;
+ struct ext2_dir_entry_2 *entry;
+ struct ext2_inode inode;
+ int fd;
+
+ ihandle_t ih = POP();
+ char *path = pop_fstr_copy();
+
+ fd = open_ih( ih );
+ if ( fd == -1 ) {
+ free( path );
+ return;
+ }
+
+ volume = ext2_mount(fd);
+ if (!volume) {
+ return;
+ }
+
+ common = (ext2_COMMON*)malloc(sizeof(ext2_COMMON));
+ common->dir = ext2_opendir(volume, path);
+
+ forth_printf("\n");
+ while ( (entry = ext2_readdir(common->dir)) ) {
+ ext2_get_inode(common->dir->volume, entry->inode, &inode);
+ forth_printf("% 10d ", inode.i_size);
+ print_date(inode.i_mtime);
+ if (S_ISDIR(inode.i_mode))
+ forth_printf("%s\\\n", entry->name);
+ else
+ forth_printf("%s\n", entry->name);
+ }
+
+ ext2_closedir( common->dir );
+ ext2_umount( volume );
+
+ close_io( fd );
+
+ free( common );
+ free( path );
+}
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+ext2_files_probe( ext2_info_t *dummy )
+{
+ ihandle_t ih = POP_ih();
+ long long offs = DPOP();
+ int fd, ret = 0;
+
+ fd = open_ih(ih);
+ if (fd >= 0) {
+ if (ext2_probe(fd, offs)) {
+ ret = -1;
+ }
+ close_io(fd);
+ } else {
+ ret = -1;
+ }
+
+ RET (ret);
+}
+
+
+static void
+ext2_initializer( ext2_info_t *dummy )
+{
+ fword("register-fs-package");
+}
+
+NODE_METHODS( ext2 ) = {
+ { "probe", ext2_files_probe },
+ { "open", ext2_files_open },
+ { "close", ext2_files_close },
+ { "read", ext2_files_read },
+ { "seek", ext2_files_seek },
+ { "load", ext2_files_load },
+ { "dir", ext2_files_dir },
+
+ /* special */
+ { "get-path", ext2_files_get_path },
+ { "get-fstype", ext2_files_get_fstype },
+
+ { NULL, ext2_initializer },
+};
+
+void
+ext2_init( void )
+{
+ REGISTER_NODE( ext2 );
+}
diff --git a/qemu/roms/openbios/fs/ext2/ext2_fs.h b/qemu/roms/openbios/fs/ext2/ext2_fs.h
new file mode 100644
index 000000000..4a7adff7d
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_lseek.c b/qemu/roms/openbios/fs/ext2/ext2_lseek.c
new file mode 100644
index 000000000..e837d89b4
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_mount.c b/qemu/roms/openbios/fs/ext2/ext2_mount.c
new file mode 100644
index 000000000..06b63deca
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_open.c b/qemu/roms/openbios/fs/ext2/ext2_open.c
new file mode 100644
index 000000000..03a89bbd0
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_opendir.c b/qemu/roms/openbios/fs/ext2/ext2_opendir.c
new file mode 100644
index 000000000..3363e0b3a
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_read.c b/qemu/roms/openbios/fs/ext2/ext2_read.c
new file mode 100644
index 000000000..975b3675b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_readdir.c b/qemu/roms/openbios/fs/ext2/ext2_readdir.c
new file mode 100644
index 000000000..09ba95c9d
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_utils.c b/qemu/roms/openbios/fs/ext2/ext2_utils.c
new file mode 100644
index 000000000..64563c826
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/ext2_utils.h b/qemu/roms/openbios/fs/ext2/ext2_utils.h
new file mode 100644
index 000000000..43544d870
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ext2/libext2.h b/qemu/roms/openbios/fs/ext2/libext2.h
new file mode 100644
index 000000000..12d22a44b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/Kconfig b/qemu/roms/openbios/fs/grubfs/Kconfig
new file mode 100644
index 000000000..55fec8b72
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/build.xml b/qemu/roms/openbios/fs/grubfs/build.xml
new file mode 100644
index 000000000..e5fb64a5f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/debug.h b/qemu/roms/openbios/fs/grubfs/debug.h
new file mode 100644
index 000000000..7494d3169
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/debug.h
@@ -0,0 +1 @@
+/* for grub compatibility */
diff --git a/qemu/roms/openbios/fs/grubfs/defs.h b/qemu/roms/openbios/fs/grubfs/defs.h
new file mode 100644
index 000000000..3a3128ce1
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/dir.h b/qemu/roms/openbios/fs/grubfs/dir.h
new file mode 100644
index 000000000..a775cab8c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/disk_inode.h b/qemu/roms/openbios/fs/grubfs/disk_inode.h
new file mode 100644
index 000000000..68a61c7a4
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h b/qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h
new file mode 100644
index 000000000..3a2cfc6d1
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fat.h b/qemu/roms/openbios/fs/grubfs/fat.h
new file mode 100644
index 000000000..43d38aefc
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/filesys.h b/qemu/roms/openbios/fs/grubfs/filesys.h
new file mode 100644
index 000000000..6b6f97603
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fs.h b/qemu/roms/openbios/fs/grubfs/fs.h
new file mode 100644
index 000000000..260e92647
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_affs.c b/qemu/roms/openbios/fs/grubfs/fsys_affs.c
new file mode 100644
index 000000000..c4a76322b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c b/qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c
new file mode 100644
index 000000000..05425bbd3
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_fat.c b/qemu/roms/openbios/fs/grubfs/fsys_fat.c
new file mode 100644
index 000000000..a7e160d1d
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_ffs.c b/qemu/roms/openbios/fs/grubfs/fsys_ffs.c
new file mode 100644
index 000000000..c6804b8ba
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_iso9660.c b/qemu/roms/openbios/fs/grubfs/fsys_iso9660.c
new file mode 100644
index 000000000..12f94b734
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_jfs.c b/qemu/roms/openbios/fs/grubfs/fsys_jfs.c
new file mode 100644
index 000000000..66469e686
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_minix.c b/qemu/roms/openbios/fs/grubfs/fsys_minix.c
new file mode 100644
index 000000000..d16b58c87
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_ntfs.c b/qemu/roms/openbios/fs/grubfs/fsys_ntfs.c
new file mode 100644
index 000000000..a244f5c6b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c b/qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c
new file mode 100644
index 000000000..b94a33529
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_ufs.c b/qemu/roms/openbios/fs/grubfs/fsys_ufs.c
new file mode 100644
index 000000000..8e0a0f776
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_vstafs.c b/qemu/roms/openbios/fs/grubfs/fsys_vstafs.c
new file mode 100644
index 000000000..e06d3e73e
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/fsys_xfs.c b/qemu/roms/openbios/fs/grubfs/fsys_xfs.c
new file mode 100644
index 000000000..b082621c7
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/glue.h b/qemu/roms/openbios/fs/grubfs/glue.h
new file mode 100644
index 000000000..7f2129372
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/grubfs_fs.c b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c
new file mode 100644
index 000000000..acd2a6441
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/iso9660.h b/qemu/roms/openbios/fs/grubfs/iso9660.h
new file mode 100644
index 000000000..6423a8f68
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/jfs.h b/qemu/roms/openbios/fs/grubfs/jfs.h
new file mode 100644
index 000000000..afe7263d2
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/shared.h b/qemu/roms/openbios/fs/grubfs/shared.h
new file mode 100644
index 000000000..b3034e03c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/ufs_dinode.h b/qemu/roms/openbios/fs/grubfs/ufs_dinode.h
new file mode 100644
index 000000000..f3f7fca02
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/ufs_fs.h b/qemu/roms/openbios/fs/grubfs/ufs_fs.h
new file mode 100644
index 000000000..bd11cc968
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/vstafs.h b/qemu/roms/openbios/fs/grubfs/vstafs.h
new file mode 100644
index 000000000..f240ffc4a
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/grubfs/xfs.h b/qemu/roms/openbios/fs/grubfs/xfs.h
new file mode 100644
index 000000000..0ed07042c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/block.c b/qemu/roms/openbios/fs/hfs/block.c
new file mode 100644
index 000000000..0b65a1f3b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/btree.c b/qemu/roms/openbios/fs/hfs/btree.c
new file mode 100644
index 000000000..cd5c85347
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/build.xml b/qemu/roms/openbios/fs/hfs/build.xml
new file mode 100644
index 000000000..2ac6fdbb3
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/data.c b/qemu/roms/openbios/fs/hfs/data.c
new file mode 100644
index 000000000..a0e4a8ea7
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/file.c b/qemu/roms/openbios/fs/hfs/file.c
new file mode 100644
index 000000000..a6ddb893a
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/hfs.c b/qemu/roms/openbios/fs/hfs/hfs.c
new file mode 100644
index 000000000..0c5fefb47
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/hfs_fs.c b/qemu/roms/openbios/fs/hfs/hfs_fs.c
new file mode 100644
index 000000000..2d62ec0c6
--- /dev/null
+++ b/qemu/roms/openbios/fs/hfs/hfs_fs.c
@@ -0,0 +1,593 @@
+/*
+ * Creation Date: <2001/05/06 22:47:23 samuel>
+ * Time-stamp: <2004/01/12 10:24:35 samuel>
+ *
+ * /packages/hfs-files
+ *
+ * HFS world interface
+ *
+ * Copyright (C) 2001-2004 Samuel Rydh (samuel@ibrium.se)
+ * Copyright (C) 2010 Mark Cave-Ayland (mark.cave-ayland@siriusit.co.uk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "fs/fs.h"
+#include "libc/vsprintf.h"
+#include "libc/diskio.h"
+#include "libhfs.h"
+
+#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */
+#define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */
+#define MAC_OS_ROM_NAME "Mac OS ROM"
+
+#define FINDER_TYPE 0x464E4452 /* 'FNDR' */
+#define FINDER_CREATOR 0x4D414353 /* 'MACS' */
+#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
+#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
+
+#define VOLNAME_SIZE 64
+
+extern void hfs_init( void );
+
+typedef struct {
+ enum { FILE, DIR } type;
+ union {
+ hfsdir *dir;
+ hfsfile *file;
+ };
+} hfscommon;
+
+typedef struct {
+ hfsvol *vol;
+ hfscommon *common;
+} hfs_info_t;
+
+DECLARE_NODE( hfs, 0, sizeof(hfs_info_t), "+/packages/hfs-files" );
+
+/************************************************************************/
+/* Search Functions */
+/************************************************************************/
+
+static int
+_find_file( hfsvol *vol, const char *path, unsigned long type, unsigned long creator )
+{
+ hfsdirent ent;
+ hfsdir *dir;
+ int ret=1;
+
+ if( !(dir=hfs_opendir(vol, path)) )
+ return 1;
+
+ while( ret && !hfs_readdir(dir, &ent) ) {
+ if( ent.flags & HFS_ISDIR )
+ continue;
+ ret = !(*(unsigned long*)ent.u.file.type == type && *(unsigned long*)ent.u.file.creator == creator );
+ }
+
+ hfs_closedir( dir );
+ return ret;
+}
+
+
+/* ret: 0=success, 1=not_found, 2=not_a_dir */
+static int
+_search( hfsvol *vol, const char *path, const char *sname, hfsfile **ret_fd )
+{
+ hfsdir *dir;
+ hfsdirent ent;
+ int topdir=0, status = 1;
+ char *p, buf[256];
+
+ strncpy( buf, path, sizeof(buf) );
+ if( buf[strlen(buf)-1] != ':' )
+ strncat( buf, ":", sizeof(buf) );
+ buf[sizeof(buf)-1] = 0;
+ p = buf + strlen( buf );
+
+ if( !(dir=hfs_opendir(vol, path)) )
+ return 2;
+
+ /* printk("DIRECTORY: %s\n", path ); */
+
+ while( status && !hfs_readdir(dir, &ent) ) {
+ unsigned long type, creator;
+
+ *p = 0;
+ topdir = 0;
+
+ strncat( buf, ent.name, sizeof(buf) );
+ if( (status=_search(vol, buf, sname, ret_fd)) != 2 )
+ continue;
+ topdir = 1;
+
+ /* name search? */
+ if( sname ) {
+ status = strcasecmp( ent.name, sname );
+ continue;
+ }
+
+ type = *(unsigned long*)ent.u.file.type;
+ creator = *(unsigned long*)ent.u.file.creator;
+
+ /* look for Mac OS ROM, System and Finder in the same directory */
+ if( type == MAC_OS_ROM_TYPE && creator == MAC_OS_ROM_CREATOR ) {
+ if( strcasecmp(ent.name, MAC_OS_ROM_NAME) )
+ continue;
+
+ status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR )
+ || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR );
+ }
+ }
+ if( !status && topdir && ret_fd && !(*ret_fd=hfs_open(vol, buf)) ) {
+ printk("Unexpected error: failed to open matched ROM\n");
+ status = 1;
+ }
+
+ hfs_closedir( dir );
+ return status;
+}
+
+static hfsfile *
+_do_search( hfs_info_t *mi, const char *sname )
+{
+ hfsvol *vol = hfs_getvol( NULL );
+
+ mi->common->type = FILE;
+ (void)_search( vol, ":", sname, &mi->common->file );
+
+ return mi->common->file;
+}
+
+
+static const int days_month[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static const int days_month_leap[12] =
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static inline int is_leap(int year)
+{
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
+}
+
+static void
+print_date(time_t sec)
+{
+ unsigned int second, minute, hour, month, day, year;
+ int current;
+ const int *days;
+
+ second = sec % 60;
+ sec /= 60;
+
+ minute = sec % 60;
+ sec /= 60;
+
+ hour = sec % 24;
+ sec /= 24;
+
+ year = sec * 100 / 36525;
+ sec -= year * 36525 / 100;
+ year += 1970;
+
+ days = is_leap(year) ? days_month_leap : days_month;
+
+ current = 0;
+ month = 0;
+ while (month < 12) {
+ if (sec <= current + days[month]) {
+ break;
+ }
+ current += days[month];
+ month++;
+ }
+ month++;
+
+ day = sec - current + 1;
+
+ forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
+ year, month, day, hour, minute, second);
+}
+
+/*
+static void
+dir_fs( file_desc_t *fd )
+{
+ hfscommon *common = (hfscommon*)fd;
+ hfsdirent ent;
+
+ if (common->type != DIR)
+ return;
+
+ forth_printf("\n");
+ while( !hfs_readdir(common->dir, &ent) ) {
+ forth_printf("% 10d ", ent.u.file.dsize);
+ print_date(ent.mddate);
+ if( ent.flags & HFS_ISDIR )
+ forth_printf("%s\\\n", ent.name);
+ else
+ forth_printf("%s\n", ent.name);
+ }
+}
+*/
+
+/************************************************************************/
+/* Standard package methods */
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+hfs_files_open( hfs_info_t *mi )
+{
+ int fd;
+ char *path = my_args_copy();
+
+ const char *s;
+ char buf[256];
+
+ fd = open_ih( my_parent() );
+ if ( fd == -1 ) {
+ free( path );
+ RET( 0 );
+ }
+
+ mi->vol = hfs_mount(fd, 0);
+ if (!mi->vol) {
+ RET( 0 );
+ }
+
+ if( !strncmp(path, "\\\\", 2) ) {
+ hfsvolent ent;
+
+ /* \\ is an alias for the (blessed) system folder */
+ if( hfs_vstat(mi->vol, &ent) < 0 || hfs_setcwd(mi->vol, ent.blessed) ) {
+ free(path);
+ RET( -1 );
+ }
+ path += 2;
+ } else {
+ hfs_chdir( mi->vol, ":" );
+ }
+
+ mi->common = malloc(sizeof(hfscommon));
+ if (!mi->common) {
+ free(path);
+ RET( 0 );
+ }
+
+ if (strcmp(path, "\\") == 0) {
+ /* root directory is in fact ":" */
+ mi->common->dir = hfs_opendir(mi->vol, ":");
+ mi->common->type = DIR;
+ free(path);
+ RET( -1 );
+ }
+
+ if (path[strlen(path) - 1] == '\\') {
+ path[strlen(path) - 1] = 0;
+ }
+
+ for( path-- ;; ) {
+ int n;
+
+ s = ++path;
+ path = strchr(s, '\\');
+ if( !path || !path[1])
+ break;
+ n = MIN( sizeof(buf)-1, (path-s) );
+ if( !n )
+ continue;
+
+ strncpy( buf, s, n );
+ buf[n] = 0;
+ if( hfs_chdir(mi->vol, buf) ) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ }
+
+ /* support the ':filetype' syntax */
+ if( *s == ':' ) {
+ unsigned long id, oldid = hfs_getcwd(mi->vol);
+ hfsdirent ent;
+ hfsdir *dir;
+
+ s++;
+ id = oldid;
+ hfs_dirinfo( mi->vol, &id, buf );
+ hfs_setcwd( mi->vol, id );
+
+ if( !(dir=hfs_opendir(mi->vol, buf)) ) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ hfs_setcwd( mi->vol, oldid );
+
+ while( !hfs_readdir(dir, &ent) ) {
+ if( ent.flags & HFS_ISDIR )
+ continue;
+ if( !strncmp(s, ent.u.file.type, 4) ) {
+ mi->common->type = FILE;
+ mi->common->file = hfs_open( mi->vol, ent.name );
+ break;
+ }
+ }
+ hfs_closedir( dir );
+ free(path);
+ RET( -1 );
+ }
+
+ mi->common->dir = hfs_opendir(mi->vol, s);
+ if (!mi->common->dir) {
+ mi->common->file = hfs_open( mi->vol, s );
+ if (mi->common->file == NULL) {
+ free(mi->common);
+ free(path);
+ RET( 0 );
+ }
+ mi->common->type = FILE;
+ free(path);
+ RET( -1 );
+ }
+ mi->common->type = DIR;
+ free(path);
+
+ RET( -1 );
+}
+
+/* ( -- ) */
+static void
+hfs_files_close( hfs_info_t *mi )
+{
+ hfscommon *common = mi->common;
+ if (common->type == FILE)
+ hfs_close( common->file );
+ else if (common->type == DIR)
+ hfs_closedir( common->dir );
+ free(common);
+}
+
+/* ( buf len -- actlen ) */
+static void
+hfs_files_read( hfs_info_t *mi )
+{
+ int count = POP();
+ char *buf = (char *)cell2pointer(POP());
+
+ hfscommon *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ RET ( hfs_read( common->file, buf, count ) );
+}
+
+/* ( pos.d -- status ) */
+static void
+hfs_files_seek( hfs_info_t *mi )
+{
+ long long pos = DPOP();
+ int offs = (int)pos;
+ int whence = SEEK_SET;
+ int ret;
+ hfscommon *common = mi->common;
+
+ if (common->type != FILE)
+ RET( -1 );
+
+ switch( whence ) {
+ case SEEK_END:
+ whence = HFS_SEEK_END;
+ break;
+ default:
+ case SEEK_SET:
+ whence = HFS_SEEK_SET;
+ break;
+ }
+
+ ret = hfs_seek( common->file, offs, whence );
+ if (ret != -1)
+ RET( 0 );
+ else
+ RET( -1 );
+}
+
+/* ( addr -- size ) */
+static void
+hfs_files_load( hfs_info_t *mi )
+{
+ char *buf = (char *)cell2pointer(POP());
+ int count;
+
+ hfscommon *common = mi->common;
+ if (common->type != FILE)
+ RET( -1 );
+
+ /* Seek to the end in order to get the file size */
+ hfs_seek(common->file, 0, HFS_SEEK_END);
+ count = common->file->pos;
+ hfs_seek(common->file, 0, HFS_SEEK_SET);
+
+ RET ( hfs_read( common->file, buf, count ) );
+}
+
+/* ( -- success? ) */
+static void
+hfs_files_open_nwrom( hfs_info_t *mi )
+{
+ /* Switch to an existing ROM image file on the fs! */
+ if ( _do_search( mi, NULL ) )
+ RET( -1 );
+
+ RET( 0 );
+}
+
+/* ( -- cstr ) */
+static void
+hfs_files_get_path( hfs_info_t *mi )
+{
+ char buf[256], buf2[256];
+ hfscommon *common = mi->common;
+ hfsvol *vol = hfs_getvol( NULL );
+ hfsdirent ent;
+ int start, ns;
+ unsigned long id;
+
+ if (common->type != FILE)
+ RET( 0 );
+
+ hfs_fstat( common->file, &ent );
+ start = sizeof(buf) - strlen(ent.name) - 1;
+ if( start <= 0 )
+ RET ( 0 );
+ strcpy( buf+start, ent.name );
+ buf[--start] = '\\';
+
+ ns = start;
+ for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) {
+ start = ns;
+ ns -= strlen(buf2);
+ if( ns <= 0 )
+ RET( 0 );
+ strcpy( buf+ns, buf2 );
+ buf[--ns] = buf[start] = '\\';
+ }
+ if( strlen(buf) >= sizeof(buf) )
+ RET( 0 );
+
+ RET( pointer2cell(strdup(buf+start)) );
+}
+
+/* ( -- cstr ) */
+static void
+hfs_files_get_fstype( hfs_info_t *mi )
+{
+ PUSH( pointer2cell(strdup("HFS")) );
+}
+
+/* ( -- cstr|0 ) */
+static void
+hfs_files_volume_name( hfs_info_t *mi )
+{
+ int fd;
+ char *volname = malloc(VOLNAME_SIZE);
+
+ fd = open_ih(my_self());
+ if (fd >= 0) {
+ get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
+ close_io(fd);
+ } else {
+ volname[0] = '\0';
+ }
+
+ PUSH(pointer2cell(volname));
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+hfs_files_dir( hfs_info_t *dummy )
+{
+ hfsvol *volume;
+ hfscommon *common;
+ hfsdirent ent;
+ int i;
+ int fd;
+
+ ihandle_t ih = POP();
+ char *path = pop_fstr_copy();
+
+ fd = open_ih( ih );
+ if ( fd == -1 ) {
+ free( path );
+ return;
+ }
+
+ volume = hfs_mount(fd, 0);
+ if (!volume) {
+ return;
+ }
+
+ common = malloc(sizeof(hfscommon));
+
+ /* HFS paths are colon separated, not backslash separated */
+ for (i = 0; i < strlen(path); i++)
+ if (path[i] == '\\')
+ path[i] = ':';
+
+ common->dir = hfs_opendir(volume, path);
+
+ forth_printf("\n");
+ while( !hfs_readdir(common->dir, &ent) ) {
+ forth_printf("% 10ld ", ent.u.file.dsize);
+ print_date(ent.mddate);
+ if( ent.flags & HFS_ISDIR )
+ forth_printf("%s\\\n", ent.name);
+ else
+ forth_printf("%s\n", ent.name);
+ }
+
+ hfs_closedir( common->dir );
+ hfs_umount( volume );
+
+ close_io( fd );
+
+ free( common );
+ free( path );
+}
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+hfs_files_probe( hfs_info_t *dummy )
+{
+ ihandle_t ih = POP_ih();
+ long long offs = DPOP();
+ int fd, ret = 0;
+
+ fd = open_ih(ih);
+ if (fd >= 0) {
+ if (hfs_probe(fd, offs)) {
+ ret = -1;
+ }
+ close_io(fd);
+ } else {
+ ret = -1;
+ }
+
+ RET (ret);
+}
+
+static void
+hfs_initializer( hfs_info_t *dummy )
+{
+ fword("register-fs-package");
+}
+
+NODE_METHODS( hfs ) = {
+ { "probe", hfs_files_probe },
+ { "open", hfs_files_open },
+ { "close", hfs_files_close },
+ { "read", hfs_files_read },
+ { "seek", hfs_files_seek },
+ { "load", hfs_files_load },
+ { "dir", hfs_files_dir },
+
+ /* special */
+ { "open-nwrom", hfs_files_open_nwrom },
+ { "get-path", hfs_files_get_path },
+ { "get-fstype", hfs_files_get_fstype },
+ { "volume-name", hfs_files_volume_name },
+
+ { NULL, hfs_initializer },
+};
+
+void
+hfs_init( void )
+{
+ REGISTER_NODE( hfs );
+}
diff --git a/qemu/roms/openbios/fs/hfs/include/apple.h b/qemu/roms/openbios/fs/hfs/include/apple.h
new file mode 100644
index 000000000..3de581d82
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/block.h b/qemu/roms/openbios/fs/hfs/include/block.h
new file mode 100644
index 000000000..d7e764518
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/btree.h b/qemu/roms/openbios/fs/hfs/include/btree.h
new file mode 100644
index 000000000..36660f538
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/data.h b/qemu/roms/openbios/fs/hfs/include/data.h
new file mode 100644
index 000000000..f3e20008f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/file.h b/qemu/roms/openbios/fs/hfs/include/file.h
new file mode 100644
index 000000000..dacdc4800
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/hfs.h b/qemu/roms/openbios/fs/hfs/include/hfs.h
new file mode 100644
index 000000000..9996cc8dd
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/libhfs.h b/qemu/roms/openbios/fs/hfs/include/libhfs.h
new file mode 100644
index 000000000..f46f43832
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/low.h b/qemu/roms/openbios/fs/hfs/include/low.h
new file mode 100644
index 000000000..56d049a8e
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/medium.h b/qemu/roms/openbios/fs/hfs/include/medium.h
new file mode 100644
index 000000000..29d97a4e7
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/node.h b/qemu/roms/openbios/fs/hfs/include/node.h
new file mode 100644
index 000000000..d7367fd57
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/record.h b/qemu/roms/openbios/fs/hfs/include/record.h
new file mode 100644
index 000000000..283e809fa
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/include/volume.h b/qemu/roms/openbios/fs/hfs/include/volume.h
new file mode 100644
index 000000000..562c2d194
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/low.c b/qemu/roms/openbios/fs/hfs/low.c
new file mode 100644
index 000000000..e0f7cb0e3
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/medium.c b/qemu/roms/openbios/fs/hfs/medium.c
new file mode 100644
index 000000000..171ba80dc
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/node.c b/qemu/roms/openbios/fs/hfs/node.c
new file mode 100644
index 000000000..1670f038b
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/record.c b/qemu/roms/openbios/fs/hfs/record.c
new file mode 100644
index 000000000..92a3adddf
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs/volume.c b/qemu/roms/openbios/fs/hfs/volume.c
new file mode 100644
index 000000000..4faf7e6c2
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfs_mdb.h b/qemu/roms/openbios/fs/hfs_mdb.h
new file mode 100644
index 000000000..652525d96
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/build.xml b/qemu/roms/openbios/fs/hfsplus/build.xml
new file mode 100644
index 000000000..5f4c28869
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c b/qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c
new file mode 100644
index 000000000..e91009229
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_btree.c b/qemu/roms/openbios/fs/hfsplus/hfsp_btree.c
new file mode 100644
index 000000000..24eca924c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_fs.c b/qemu/roms/openbios/fs/hfsplus/hfsp_fs.c
new file mode 100644
index 000000000..df234bb04
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_record.c b/qemu/roms/openbios/fs/hfsplus/hfsp_record.c
new file mode 100644
index 000000000..d4e7af1bf
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c b/qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c
new file mode 100644
index 000000000..7a34affa1
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/hfsp_volume.c b/qemu/roms/openbios/fs/hfsplus/hfsp_volume.c
new file mode 100644
index 000000000..2d624e23e
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/apple.h b/qemu/roms/openbios/fs/hfsplus/include/apple.h
new file mode 100644
index 000000000..7ba836db6
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/blockiter.h b/qemu/roms/openbios/fs/hfsplus/include/blockiter.h
new file mode 100644
index 000000000..da3e480fd
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/btree.h b/qemu/roms/openbios/fs/hfsplus/include/btree.h
new file mode 100644
index 000000000..46ac8501f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/hfs.h b/qemu/roms/openbios/fs/hfsplus/include/hfs.h
new file mode 100644
index 000000000..5b0cbb490
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/hfsp.h b/qemu/roms/openbios/fs/hfsplus/include/hfsp.h
new file mode 100644
index 000000000..e916473c6
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/hfstime.h b/qemu/roms/openbios/fs/hfsplus/include/hfstime.h
new file mode 100644
index 000000000..bb6bd4a6e
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/libhfsp.h b/qemu/roms/openbios/fs/hfsplus/include/libhfsp.h
new file mode 100644
index 000000000..912cfbd05
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/record.h b/qemu/roms/openbios/fs/hfsplus/include/record.h
new file mode 100644
index 000000000..6454f552a
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/swab.h b/qemu/roms/openbios/fs/hfsplus/include/swab.h
new file mode 100644
index 000000000..c424008ee
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/unicode.h b/qemu/roms/openbios/fs/hfsplus/include/unicode.h
new file mode 100644
index 000000000..e7c86f78a
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/include/volume.h b/qemu/roms/openbios/fs/hfsplus/include/volume.h
new file mode 100644
index 000000000..19be05500
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/hfsplus/libhfsp.c b/qemu/roms/openbios/fs/hfsplus/libhfsp.c
new file mode 100644
index 000000000..af1cde6a9
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/ioglue.c b/qemu/roms/openbios/fs/ioglue.c
new file mode 100644
index 000000000..1d33d8fda
--- /dev/null
+++ b/qemu/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*)&sect;
+
+ 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/qemu/roms/openbios/fs/iso9660/build.xml b/qemu/roms/openbios/fs/iso9660/build.xml
new file mode 100644
index 000000000..00d390217
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660.h b/qemu/roms/openbios/fs/iso9660/iso9660.h
new file mode 100644
index 000000000..ac6dcf091
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_close.c b/qemu/roms/openbios/fs/iso9660/iso9660_close.c
new file mode 100644
index 000000000..ce79c0fd4
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_closedir.c b/qemu/roms/openbios/fs/iso9660/iso9660_closedir.c
new file mode 100644
index 000000000..706cc222f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_fs.c b/qemu/roms/openbios/fs/iso9660/iso9660_fs.c
new file mode 100644
index 000000000..d6f547be1
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_fs.h b/qemu/roms/openbios/fs/iso9660/iso9660_fs.h
new file mode 100644
index 000000000..0de124da9
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_lseek.c b/qemu/roms/openbios/fs/iso9660/iso9660_lseek.c
new file mode 100644
index 000000000..62987583c
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_mount.c b/qemu/roms/openbios/fs/iso9660/iso9660_mount.c
new file mode 100644
index 000000000..a58170408
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_open.c b/qemu/roms/openbios/fs/iso9660/iso9660_open.c
new file mode 100644
index 000000000..77c271f0f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_opendir.c b/qemu/roms/openbios/fs/iso9660/iso9660_opendir.c
new file mode 100644
index 000000000..49eab4b42
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_read.c b/qemu/roms/openbios/fs/iso9660/iso9660_read.c
new file mode 100644
index 000000000..22cc463f0
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/iso9660_readdir.c b/qemu/roms/openbios/fs/iso9660/iso9660_readdir.c
new file mode 100644
index 000000000..003ffb20f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/iso9660/libiso9660.h b/qemu/roms/openbios/fs/iso9660/libiso9660.h
new file mode 100644
index 000000000..8a5b4801f
--- /dev/null
+++ b/qemu/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/qemu/roms/openbios/fs/os.h b/qemu/roms/openbios/fs/os.h
new file mode 100644
index 000000000..b0375f7e2
--- /dev/null
+++ b/qemu/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 */