From e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Fri, 28 Aug 2015 09:58:54 +0800 Subject: Add qemu 2.4.0 Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang --- qemu/roms/openbios/fs/build.xml | 14 + qemu/roms/openbios/fs/ext2/build.xml | 14 + qemu/roms/openbios/fs/ext2/ext2.h | 33 + qemu/roms/openbios/fs/ext2/ext2_close.c | 18 + qemu/roms/openbios/fs/ext2/ext2_closedir.c | 18 + qemu/roms/openbios/fs/ext2/ext2_fs.c | 309 +++++ qemu/roms/openbios/fs/ext2/ext2_fs.h | 534 +++++++++ qemu/roms/openbios/fs/ext2/ext2_lseek.c | 38 + qemu/roms/openbios/fs/ext2/ext2_mount.c | 62 + qemu/roms/openbios/fs/ext2/ext2_open.c | 65 ++ qemu/roms/openbios/fs/ext2/ext2_opendir.c | 49 + qemu/roms/openbios/fs/ext2/ext2_read.c | 23 + qemu/roms/openbios/fs/ext2/ext2_readdir.c | 25 + qemu/roms/openbios/fs/ext2/ext2_utils.c | 332 ++++++ qemu/roms/openbios/fs/ext2/ext2_utils.h | 54 + qemu/roms/openbios/fs/ext2/libext2.h | 25 + qemu/roms/openbios/fs/grubfs/Kconfig | 83 ++ qemu/roms/openbios/fs/grubfs/build.xml | 17 + qemu/roms/openbios/fs/grubfs/debug.h | 1 + qemu/roms/openbios/fs/grubfs/defs.h | 86 ++ qemu/roms/openbios/fs/grubfs/dir.h | 141 +++ qemu/roms/openbios/fs/grubfs/disk_inode.h | 110 ++ qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h | 101 ++ qemu/roms/openbios/fs/grubfs/fat.h | 99 ++ qemu/roms/openbios/fs/grubfs/filesys.h | 303 +++++ qemu/roms/openbios/fs/grubfs/fs.h | 457 ++++++++ qemu/roms/openbios/fs/grubfs/fsys_affs.c | 712 ++++++++++++ qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c | 794 +++++++++++++ qemu/roms/openbios/fs/grubfs/fsys_fat.c | 477 ++++++++ qemu/roms/openbios/fs/grubfs/fsys_ffs.c | 311 +++++ qemu/roms/openbios/fs/grubfs/fsys_iso9660.c | 342 ++++++ qemu/roms/openbios/fs/grubfs/fsys_jfs.c | 404 +++++++ qemu/roms/openbios/fs/grubfs/fsys_minix.c | 535 +++++++++ qemu/roms/openbios/fs/grubfs/fsys_ntfs.c | 1255 +++++++++++++++++++++ qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c | 1220 ++++++++++++++++++++ qemu/roms/openbios/fs/grubfs/fsys_ufs.c | 391 +++++++ qemu/roms/openbios/fs/grubfs/fsys_vstafs.c | 254 +++++ qemu/roms/openbios/fs/grubfs/fsys_xfs.c | 639 +++++++++++ qemu/roms/openbios/fs/grubfs/glue.h | 48 + qemu/roms/openbios/fs/grubfs/grubfs_fs.c | 398 +++++++ qemu/roms/openbios/fs/grubfs/iso9660.h | 167 +++ qemu/roms/openbios/fs/grubfs/jfs.h | 604 ++++++++++ qemu/roms/openbios/fs/grubfs/shared.h | 3 + qemu/roms/openbios/fs/grubfs/ufs_dinode.h | 191 ++++ qemu/roms/openbios/fs/grubfs/ufs_fs.h | 635 +++++++++++ qemu/roms/openbios/fs/grubfs/vstafs.h | 89 ++ qemu/roms/openbios/fs/grubfs/xfs.h | 546 +++++++++ qemu/roms/openbios/fs/hfs/block.c | 612 ++++++++++ qemu/roms/openbios/fs/hfs/btree.c | 230 ++++ qemu/roms/openbios/fs/hfs/build.xml | 15 + qemu/roms/openbios/fs/hfs/data.c | 476 ++++++++ qemu/roms/openbios/fs/hfs/file.c | 191 ++++ qemu/roms/openbios/fs/hfs/hfs.c | 747 ++++++++++++ qemu/roms/openbios/fs/hfs/hfs_fs.c | 593 ++++++++++ qemu/roms/openbios/fs/hfs/include/apple.h | 273 +++++ qemu/roms/openbios/fs/hfs/include/block.h | 41 + qemu/roms/openbios/fs/hfs/include/btree.h | 34 + qemu/roms/openbios/fs/hfs/include/data.h | 57 + qemu/roms/openbios/fs/hfs/include/file.h | 46 + qemu/roms/openbios/fs/hfs/include/hfs.h | 180 +++ qemu/roms/openbios/fs/hfs/include/libhfs.h | 225 ++++ qemu/roms/openbios/fs/hfs/include/low.h | 45 + qemu/roms/openbios/fs/hfs/include/medium.h | 43 + qemu/roms/openbios/fs/hfs/include/node.h | 35 + qemu/roms/openbios/fs/hfs/include/record.h | 48 + qemu/roms/openbios/fs/hfs/include/volume.h | 71 ++ qemu/roms/openbios/fs/hfs/low.c | 157 +++ qemu/roms/openbios/fs/hfs/medium.c | 84 ++ qemu/roms/openbios/fs/hfs/node.c | 60 + qemu/roms/openbios/fs/hfs/record.c | 553 +++++++++ qemu/roms/openbios/fs/hfs/volume.c | 612 ++++++++++ qemu/roms/openbios/fs/hfs_mdb.h | 118 ++ qemu/roms/openbios/fs/hfsplus/build.xml | 11 + qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c | 141 +++ qemu/roms/openbios/fs/hfsplus/hfsp_btree.c | 372 ++++++ qemu/roms/openbios/fs/hfsplus/hfsp_fs.c | 632 +++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_record.c | 759 +++++++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c | 511 +++++++++ qemu/roms/openbios/fs/hfsplus/hfsp_volume.c | 323 ++++++ qemu/roms/openbios/fs/hfsplus/include/apple.h | 111 ++ qemu/roms/openbios/fs/hfsplus/include/blockiter.h | 59 + qemu/roms/openbios/fs/hfsplus/include/btree.h | 50 + qemu/roms/openbios/fs/hfsplus/include/hfs.h | 32 + qemu/roms/openbios/fs/hfsplus/include/hfsp.h | 305 +++++ qemu/roms/openbios/fs/hfsplus/include/hfstime.h | 34 + qemu/roms/openbios/fs/hfsplus/include/libhfsp.h | 201 ++++ qemu/roms/openbios/fs/hfsplus/include/record.h | 80 ++ qemu/roms/openbios/fs/hfsplus/include/swab.h | 64 ++ qemu/roms/openbios/fs/hfsplus/include/unicode.h | 28 + qemu/roms/openbios/fs/hfsplus/include/volume.h | 87 ++ qemu/roms/openbios/fs/hfsplus/libhfsp.c | 29 + qemu/roms/openbios/fs/ioglue.c | 92 ++ qemu/roms/openbios/fs/iso9660/build.xml | 13 + qemu/roms/openbios/fs/iso9660/iso9660.h | 58 + qemu/roms/openbios/fs/iso9660/iso9660_close.c | 15 + qemu/roms/openbios/fs/iso9660/iso9660_closedir.c | 19 + qemu/roms/openbios/fs/iso9660/iso9660_fs.c | 263 +++++ qemu/roms/openbios/fs/iso9660/iso9660_fs.h | 161 +++ qemu/roms/openbios/fs/iso9660/iso9660_lseek.c | 37 + qemu/roms/openbios/fs/iso9660/iso9660_mount.c | 210 ++++ qemu/roms/openbios/fs/iso9660/iso9660_open.c | 39 + qemu/roms/openbios/fs/iso9660/iso9660_opendir.c | 133 +++ qemu/roms/openbios/fs/iso9660/iso9660_read.c | 74 ++ qemu/roms/openbios/fs/iso9660/iso9660_readdir.c | 50 + qemu/roms/openbios/fs/iso9660/libiso9660.h | 27 + qemu/roms/openbios/fs/os.h | 57 + 106 files changed, 23649 insertions(+) create mode 100644 qemu/roms/openbios/fs/build.xml create mode 100644 qemu/roms/openbios/fs/ext2/build.xml create mode 100644 qemu/roms/openbios/fs/ext2/ext2.h create mode 100644 qemu/roms/openbios/fs/ext2/ext2_close.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_closedir.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_fs.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_fs.h create mode 100644 qemu/roms/openbios/fs/ext2/ext2_lseek.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_mount.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_open.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_opendir.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_read.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_readdir.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_utils.c create mode 100644 qemu/roms/openbios/fs/ext2/ext2_utils.h create mode 100644 qemu/roms/openbios/fs/ext2/libext2.h create mode 100644 qemu/roms/openbios/fs/grubfs/Kconfig create mode 100644 qemu/roms/openbios/fs/grubfs/build.xml create mode 100644 qemu/roms/openbios/fs/grubfs/debug.h create mode 100644 qemu/roms/openbios/fs/grubfs/defs.h create mode 100644 qemu/roms/openbios/fs/grubfs/dir.h create mode 100644 qemu/roms/openbios/fs/grubfs/disk_inode.h create mode 100644 qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h create mode 100644 qemu/roms/openbios/fs/grubfs/fat.h create mode 100644 qemu/roms/openbios/fs/grubfs/filesys.h create mode 100644 qemu/roms/openbios/fs/grubfs/fs.h create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_affs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_fat.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_ffs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_iso9660.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_jfs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_minix.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_ntfs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_ufs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_vstafs.c create mode 100644 qemu/roms/openbios/fs/grubfs/fsys_xfs.c create mode 100644 qemu/roms/openbios/fs/grubfs/glue.h create mode 100644 qemu/roms/openbios/fs/grubfs/grubfs_fs.c create mode 100644 qemu/roms/openbios/fs/grubfs/iso9660.h create mode 100644 qemu/roms/openbios/fs/grubfs/jfs.h create mode 100644 qemu/roms/openbios/fs/grubfs/shared.h create mode 100644 qemu/roms/openbios/fs/grubfs/ufs_dinode.h create mode 100644 qemu/roms/openbios/fs/grubfs/ufs_fs.h create mode 100644 qemu/roms/openbios/fs/grubfs/vstafs.h create mode 100644 qemu/roms/openbios/fs/grubfs/xfs.h create mode 100644 qemu/roms/openbios/fs/hfs/block.c create mode 100644 qemu/roms/openbios/fs/hfs/btree.c create mode 100644 qemu/roms/openbios/fs/hfs/build.xml create mode 100644 qemu/roms/openbios/fs/hfs/data.c create mode 100644 qemu/roms/openbios/fs/hfs/file.c create mode 100644 qemu/roms/openbios/fs/hfs/hfs.c create mode 100644 qemu/roms/openbios/fs/hfs/hfs_fs.c create mode 100644 qemu/roms/openbios/fs/hfs/include/apple.h create mode 100644 qemu/roms/openbios/fs/hfs/include/block.h create mode 100644 qemu/roms/openbios/fs/hfs/include/btree.h create mode 100644 qemu/roms/openbios/fs/hfs/include/data.h create mode 100644 qemu/roms/openbios/fs/hfs/include/file.h create mode 100644 qemu/roms/openbios/fs/hfs/include/hfs.h create mode 100644 qemu/roms/openbios/fs/hfs/include/libhfs.h create mode 100644 qemu/roms/openbios/fs/hfs/include/low.h create mode 100644 qemu/roms/openbios/fs/hfs/include/medium.h create mode 100644 qemu/roms/openbios/fs/hfs/include/node.h create mode 100644 qemu/roms/openbios/fs/hfs/include/record.h create mode 100644 qemu/roms/openbios/fs/hfs/include/volume.h create mode 100644 qemu/roms/openbios/fs/hfs/low.c create mode 100644 qemu/roms/openbios/fs/hfs/medium.c create mode 100644 qemu/roms/openbios/fs/hfs/node.c create mode 100644 qemu/roms/openbios/fs/hfs/record.c create mode 100644 qemu/roms/openbios/fs/hfs/volume.c create mode 100644 qemu/roms/openbios/fs/hfs_mdb.h create mode 100644 qemu/roms/openbios/fs/hfsplus/build.xml create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_blockiter.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_btree.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_fs.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_record.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_unicode.c create mode 100644 qemu/roms/openbios/fs/hfsplus/hfsp_volume.c create mode 100644 qemu/roms/openbios/fs/hfsplus/include/apple.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/blockiter.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/btree.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfs.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfsp.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/hfstime.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/libhfsp.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/record.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/swab.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/unicode.h create mode 100644 qemu/roms/openbios/fs/hfsplus/include/volume.h create mode 100644 qemu/roms/openbios/fs/hfsplus/libhfsp.c create mode 100644 qemu/roms/openbios/fs/ioglue.c create mode 100644 qemu/roms/openbios/fs/iso9660/build.xml create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660.h create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_close.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_closedir.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_fs.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_fs.h create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_lseek.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_mount.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_open.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_opendir.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_read.c create mode 100644 qemu/roms/openbios/fs/iso9660/iso9660_readdir.c create mode 100644 qemu/roms/openbios/fs/iso9660/libiso9660.h create mode 100644 qemu/roms/openbios/fs/os.h (limited to 'qemu/roms/openbios/fs') 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 @@ + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 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 + * + * 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 + * + * 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 + * + * 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 + * (c) 2010 Mark Cave-Ayland + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 @@ + + + + + + + + + + + + + + + + + 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 + * 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;iblocks[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;iblocks[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;countid) & 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 + * + * 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 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<. 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 + * 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) { + 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>=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_sizeattr_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_sizeattr_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 + * + * 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<= 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 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 @@ + + + + + + + + + + + + + + + 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 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 @@ + + + + + + + + + + + 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 + * Original work by 1996-1998 Robert Leslie + * 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 + * Original 1996-1998 Robert Leslie + * 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 + * Original 1996-1998 Robert Leslie + * 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 + * Original work by 1996-1998 Robert Leslie + * 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 + * Original code 1996-1998 by Robert Leslie + * 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 + * Original work by 1996-1998 Robert Leslie + * 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 + * Original 1996-1998 Robert Leslie + * 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 + * Original code 1996-1998 by Robert Leslie + * 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 + * Original code 1996-1998 by Robert Leslie + * 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 ^ + * Original 1996-1998 Robert Leslie + * 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 + * Original 1996-1998 Robert Leslie + * 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 + * Original work 1996-1998 Robert Leslie + * + * 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 ^ + * Original 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.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> + * + * + * + * I/O API used by the filesystem code + * + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "fs/fs.h" +#include "libc/diskio.h" +#include "os.h" +#include "hfs_mdb.h" + +/************************************************************************/ +/* functionsions used by the various filesystems */ +/************************************************************************/ + +char * +get_hfs_vol_name( int fd, char *buf, int size ) +{ + char sect[512]; + hfs_mdb_t *mdb = (hfs_mdb_t*)§ + + seek_io( fd, 0x400 ); + read_io( fd, sect, sizeof(sect) ); + if( hfs_get_ushort(mdb->drSigWord) == HFS_SIGNATURE ) { + unsigned int n = mdb->drVN[0]; + if( n >= size ) + n = size - 1; + memcpy( buf, &mdb->drVN[1], n ); + buf[n] = 0; + } else if( hfs_get_ushort(mdb->drSigWord) == HFS_PLUS_SIGNATURE ) { + strncpy( buf, "Unembedded HFS+", size ); + } else { + strncpy( buf, "Error", size ); + } + return buf; +} + +unsigned long +os_read( int fd, void *buf, unsigned long len, int blksize_bits ) +{ + /* printk("os_read %d\n", (int)len); */ + + int cnt = read_io( fd, buf, len << blksize_bits ); + return (cnt > 0)? (cnt >> blksize_bits) : cnt; +} + +unsigned long +os_seek( int fd, unsigned long blknum, int blksize_bits ) +{ + /* printk("os_seek %d\n", blknum ); */ + long long offs = (long long)blknum << blksize_bits; + + /* offset == -1 means seek to EOF */ + if( (int)blknum == -1 ) + offs = -1; + + if( seek_io(fd, offs) ) { + /* printk("os_seek failure\n"); */ + return (unsigned long)-1; + } + + if( (int)blknum == -1 ) { + if( (offs=tell(fd)) < 0 ) + return -1; + blknum = offs >> blksize_bits; + } + return blknum; +} + +void +os_seek_offset( int fd, long long offset ) +{ + seek_io(fd, offset); +} + +int +os_same( int fd1, int fd2 ) +{ + return fd1 == fd2; +} diff --git a/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 @@ + + + + + + + + + + + + + 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 + * + * 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 + * + * 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 + * + * 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 + * (c) 2010 Mark Cave-Ayland + */ + +#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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 */ -- cgit 1.2.3-korg