summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/fs/grubfs
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/fs/grubfs
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openbios/fs/grubfs')
-rw-r--r--qemu/roms/openbios/fs/grubfs/Kconfig83
-rw-r--r--qemu/roms/openbios/fs/grubfs/build.xml17
-rw-r--r--qemu/roms/openbios/fs/grubfs/debug.h1
-rw-r--r--qemu/roms/openbios/fs/grubfs/defs.h86
-rw-r--r--qemu/roms/openbios/fs/grubfs/dir.h141
-rw-r--r--qemu/roms/openbios/fs/grubfs/disk_inode.h110
-rw-r--r--qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h101
-rw-r--r--qemu/roms/openbios/fs/grubfs/fat.h99
-rw-r--r--qemu/roms/openbios/fs/grubfs/filesys.h303
-rw-r--r--qemu/roms/openbios/fs/grubfs/fs.h457
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_affs.c712
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c794
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_fat.c477
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ffs.c311
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_iso9660.c342
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_jfs.c404
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_minix.c535
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ntfs.c1255
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c1220
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_ufs.c391
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_vstafs.c254
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_xfs.c639
-rw-r--r--qemu/roms/openbios/fs/grubfs/glue.h48
-rw-r--r--qemu/roms/openbios/fs/grubfs/grubfs_fs.c398
-rw-r--r--qemu/roms/openbios/fs/grubfs/iso9660.h167
-rw-r--r--qemu/roms/openbios/fs/grubfs/jfs.h604
-rw-r--r--qemu/roms/openbios/fs/grubfs/shared.h3
-rw-r--r--qemu/roms/openbios/fs/grubfs/ufs_dinode.h191
-rw-r--r--qemu/roms/openbios/fs/grubfs/ufs_fs.h635
-rw-r--r--qemu/roms/openbios/fs/grubfs/vstafs.h89
-rw-r--r--qemu/roms/openbios/fs/grubfs/xfs.h546
31 files changed, 11413 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/grubfs/Kconfig b/qemu/roms/openbios/fs/grubfs/Kconfig
new file mode 100644
index 000000000..55fec8b72
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/Kconfig
@@ -0,0 +1,83 @@
+config FSYS_EXT2FS
+ depends on GRUBFS
+ bool "EXT2 support"
+ default n
+ help
+ Include EXT2 filesystem support
+
+config FSYS_FAT
+ depends on GRUBFS
+ bool "(V)FAT support"
+ default n
+ help
+ Include VFAT/FAT (MSDOS / Windows95) filesystem support
+
+config FSYS_JFS
+ depends on GRUBFS
+ bool "JFS support"
+ default n
+ help
+ Include JFS support
+
+config FSYS_MINIX
+ depends on GRUBFS
+ bool "Minix filesystem support"
+ default n
+ help
+ Include Minix filesystem support
+
+config FSYS_REISERFS
+ depends on GRUBFS
+ bool "Reiser filesystem support"
+ default n
+ help
+ Include Reiser filesystem support
+
+config FSYS_XFS
+ depends on GRUBFS
+ bool "XFS support"
+ default n
+ help
+ Include XFS support
+
+config FSYS_UFS
+ depends on GRUBFS
+ bool "UFS/UFS2 support"
+ default n
+ help
+ Include UFS/UFS2 support
+
+config FSYS_ISO9660
+ depends on GRUBFS
+ bool "ISO 9660 support"
+ default n
+ help
+ Include ISO9660 (cdrom) filesystem support
+
+config FSYS_FFS
+ depends on GRUBFS
+ bool "FreeBSD FFS support"
+ default n
+ help
+ Include FreeBSD FFS filesystem support
+
+config FSYS_VSTAFS
+ depends on GRUBFS
+ bool "VSTA filesystem support"
+ default n
+ help
+ Include VSTA filesystem support
+
+config FSYS_NTFS
+ depends on GRUBFS
+ bool "NT filesystem support"
+ default n
+ help
+ Include NTFS filesystem support
+
+config FSYS_AFFS
+ depends on GRUBFS
+ bool "Amiga fast filesystem support"
+ default n
+ help
+ Include Amiga FFS filesystem support
diff --git a/qemu/roms/openbios/fs/grubfs/build.xml b/qemu/roms/openbios/fs/grubfs/build.xml
new file mode 100644
index 000000000..e5fb64a5f
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/build.xml
@@ -0,0 +1,17 @@
+<build>
+ <library name="fs" type="static" target="target">
+ <object source="grubfs_fs.c"/>
+ <object source="fsys_ext2fs.c" condition="FSYS_EXT2FS" flags="-DFSYS_EXT2FS -fno-strict-aliasing"/>
+ <object source="fsys_fat.c" condition="FSYS_FAT" flags="-DFSYS_FAT -fno-strict-aliasing"/>
+ <object source="fsys_jfs.c" condition="FSYS_JFS" flags="-DFSYS_JFS -fno-strict-aliasing"/>
+ <object source="fsys_minix.c" condition="FSYS_MINIX" flags="-DFSYS_MINIX -fno-strict-aliasing"/>
+ <object source="fsys_reiserfs.c" condition="FSYS_REISERFS" flags="-DFSYS_REISERFS -fno-strict-aliasing"/>
+ <object source="fsys_xfs.c" condition="FSYS_XFS" flags="-DFSYS_XFS -fno-strict-aliasing"/>
+ <object source="fsys_ufs.c" condition="FSYS_UFS" flags="-DFSYS_UFS -fno-strict-aliasing"/>
+ <object source="fsys_ffs.c" condition="FSYS_FFS" flags="-DFSYS_FFS -fno-strict-aliasing"/>
+ <object source="fsys_vstafs.c" condition="FSYS_VSTAFS" flags="-DFSYS_VSTAFS -fno-strict-aliasing"/>
+ <object source="fsys_iso9660.c" condition="FSYS_ISO9660" flags="-DFSYS_ISO9660 -fno-strict-aliasing"/>
+ <object source="fsys_ntfs.c" condition="FSYS_NTFS" flags="-DFSYS_NTFS -fno-strict-aliasing"/>
+ <object source="fsys_affs.c" condition="FSYS_AFFS" flags="-DFSYS_AFFS -fno-strict-aliasing"/>
+ </library>
+</build>
diff --git a/qemu/roms/openbios/fs/grubfs/debug.h b/qemu/roms/openbios/fs/grubfs/debug.h
new file mode 100644
index 000000000..7494d3169
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/debug.h
@@ -0,0 +1 @@
+/* for grub compatibility */
diff --git a/qemu/roms/openbios/fs/grubfs/defs.h b/qemu/roms/openbios/fs/grubfs/defs.h
new file mode 100644
index 000000000..3a3128ce1
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/defs.h
@@ -0,0 +1,86 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Common definitions for Berkeley Fast File System.
+ */
+
+/*
+ * Compatibility definitions for disk IO.
+ */
+
+/*
+ * Disk devices do all IO in 512-byte blocks.
+ */
+#define DEV_BSIZE 512
+
+/*
+ * Conversion between bytes and disk blocks.
+ */
+#define btodb(byte_offset) ((byte_offset) >> 9)
+#define dbtob(block_number) ((block_number) << 9)
+
+typedef struct _quad_
+ {
+ unsigned int val[2]; /* 2 int values make... */
+ }
+quad; /* an 8-byte item */
+
+typedef unsigned int mach_time_t; /* an unsigned int */
+typedef unsigned int mach_daddr_t; /* an unsigned int */
+typedef unsigned int mach_off_t; /* another unsigned int */
+
+typedef unsigned short mach_uid_t;
+typedef unsigned short mach_gid_t;
+typedef unsigned int mach_ino_t;
+
+#define NBBY 8
+
+/*
+ * The file system is made out of blocks of at most MAXBSIZE units,
+ * with smaller units (fragments) only in the last direct block.
+ * MAXBSIZE primarily determines the size of buffers in the buffer
+ * pool. It may be made larger without any effect on existing
+ * file systems; however, making it smaller may make some file
+ * systems unmountable.
+ *
+ * Note that the disk devices are assumed to have DEV_BSIZE "sectors"
+ * and that fragments must be some multiple of this size.
+ */
+#define MAXBSIZE 8192
+#define MAXFRAG 8
+
+/*
+ * MAXPATHLEN defines the longest permissible path length
+ * after expanding symbolic links.
+ *
+ * MAXSYMLINKS defines the maximum number of symbolic links
+ * that may be expanded in a path name. It should be set
+ * high enough to allow all legitimate uses, but halt infinite
+ * loops reasonably quickly.
+ */
+
+#define MAXPATHLEN 1024
+#define MAXSYMLINKS 8
diff --git a/qemu/roms/openbios/fs/grubfs/dir.h b/qemu/roms/openbios/fs/grubfs/dir.h
new file mode 100644
index 000000000..a775cab8c
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/dir.h
@@ -0,0 +1,141 @@
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)dir.h 7.6 (Berkeley) 5/9/89
+ */
+
+#ifndef _BOOT_UFS_DIR_H_
+#define _BOOT_UFS_DIR_H_
+
+/*
+ * A directory consists of some number of blocks of DIRBLKSIZ
+ * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZ byte block contains some number of directory entry
+ * structures, which are of variable length. Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry. These are followed by the name padded to a 4 byte boundary
+ * with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ *
+ * The macro DIRSIZ(dp) gives the amount of space required to represent
+ * a directory entry. Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes
+ * in a directory block are claimed by the directory entries. This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen. When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen. If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+#define DIRBLKSIZ DEV_BSIZE
+#define MAXNAMLEN 255
+
+struct direct
+ {
+ unsigned int d_ino; /* inode number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned short d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */
+ };
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry. This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#undef DIRSIZ
+#define DIRSIZ(dp) \
+ ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+#ifdef KERNEL
+/*
+ * Template for manipulating directories.
+ * Should use struct direct's, but the name field
+ * is MAXNAMLEN - 1, and this just won't do.
+ */
+struct dirtemplate
+ {
+ unsigned int dot_ino;
+ short dot_reclen;
+ short dot_namlen;
+ char dot_name[4]; /* must be multiple of 4 */
+ unsigned int dotdot_ino;
+ short dotdot_reclen;
+ short dotdot_namlen;
+ char dotdot_name[4]; /* ditto */
+ };
+#endif
+
+/*
+ * The following information should be obtained from <dirent.h>
+ * and is provided solely (and temporarily) for backward compatibility.
+ */
+#ifndef KERNEL
+#define d_fileno d_ino /* compatibility with POSIX */
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 512
+#endif
+/*
+ * Definitions for library routines operating on directories.
+ */
+typedef struct _dirdesc
+ {
+ int dd_fd;
+ int dd_loc;
+ int dd_size;
+ char dd_buf[DIRBLKSIZ];
+ }
+DIR;
+
+#define dirfd(dirp) ((dirp)->dd_fd)
+
+#ifndef NULL
+#define NULL 0
+#endif
+#endif /* not KERNEL */
+#endif /* _BOOT_UFS_DIR_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/disk_inode.h b/qemu/roms/openbios/fs/grubfs/disk_inode.h
new file mode 100644
index 000000000..68a61c7a4
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/disk_inode.h
@@ -0,0 +1,110 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Copyright (c) 1982, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)inode.h 7.5 (Berkeley) 7/3/89
+ */
+
+#ifndef _BOOT_UFS_DISK_INODE_H_
+#define _BOOT_UFS_DISK_INODE_H_
+
+/*
+ * The I node is the focus of all file activity in the BSD Fast File System.
+ * There is a unique inode allocated for each active file,
+ * each current directory, each mounted-on file, text file, and the root.
+ * An inode is 'named' by its dev/inumber pair. (iget/iget.c)
+ * Data in icommon is read in from permanent inode on volume.
+ */
+
+#define FFS_NDADDR 12 /* direct addresses in inode */
+#define FFS_NIADDR 3 /* indirect addresses in inode */
+
+#define FFS_MAX_FASTLINK_SIZE ((FFS_NDADDR + FFS_NIADDR) \
+ * sizeof (mach_daddr_t))
+
+struct icommon
+ {
+ unsigned short ic_mode; /* 0: mode and type of file */
+ short ic_nlink; /* 2: number of links to file */
+ mach_uid_t ic_uid; /* 4: owner's user id */
+ mach_gid_t ic_gid; /* 6: owner's group id */
+ quad ic_size; /* 8: number of bytes in file */
+ mach_time_t ic_atime; /* 16: time last accessed */
+ int ic_atspare;
+ mach_time_t ic_mtime; /* 24: time last modified */
+ int ic_mtspare;
+ mach_time_t ic_ctime; /* 32: last time inode changed */
+ int ic_ctspare;
+ union
+ {
+ struct
+ {
+ mach_daddr_t Mb_db[FFS_NDADDR]; /* 40: disk block addresses */
+ mach_daddr_t Mb_ib[FFS_NIADDR]; /* 88: indirect blocks */
+ }
+ ic_Mb;
+ char ic_Msymlink[FFS_MAX_FASTLINK_SIZE];
+ /* 40: symbolic link name */
+ }
+ ic_Mun;
+#define ic_db ic_Mun.ic_Mb.Mb_db
+#define ic_ib ic_Mun.ic_Mb.Mb_ib
+#define ic_symlink ic_Mun.ic_Msymlink
+ int ic_flags; /* 100: status, currently unused */
+ int ic_blocks; /* 104: blocks actually held */
+ int ic_gen; /* 108: generation number */
+ int ic_spare[4]; /* 112: reserved, currently unused */
+ };
+
+/*
+ * Same structure, but on disk.
+ */
+struct dinode
+ {
+ union
+ {
+ struct icommon di_com;
+ char di_char[128];
+ }
+ di_un;
+ };
+#define di_ic di_un.di_com
+
+#endif /* _BOOT_UFS_DISK_INODE_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h b/qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h
new file mode 100644
index 000000000..3a2cfc6d1
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/disk_inode_ffs.h
@@ -0,0 +1,101 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Copyright (c) 1982, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)inode.h 7.5 (Berkeley) 7/3/89
+ */
+
+#ifndef _BOOT_UFS_DISK_INODE_FFS_H_
+#define _BOOT_UFS_DISK_INODE_FFS_H_
+
+#define NDADDR FFS_NDADDR
+#define NIADDR FFS_NIADDR
+
+#define MAX_FASTLINK_SIZE FFS_MAX_FASTLINK_SIZE
+
+#define IC_FASTLINK 0x0001 /* Symbolic link in inode */
+
+#define i_mode ic_mode
+#define i_nlink ic_nlink
+#define i_uid ic_uid
+#define i_gid ic_gid
+#if defined(BYTE_MSF) && BYTE_MSF
+#define i_size ic_size.val[1]
+#else /* BYTE_LSF */
+#define i_size ic_size.val[0]
+#endif
+#define i_db ic_db
+#define i_ib ic_ib
+#define i_atime ic_atime
+#define i_mtime ic_mtime
+#define i_ctime ic_ctime
+#define i_blocks ic_blocks
+#define i_rdev ic_db[0]
+#define i_symlink ic_symlink
+#define i_flags ic_flags
+#define i_gen ic_gen
+
+/* modes */
+#define IFMT 0xf000 /* type of file */
+#define IFCHR 0x2000 /* character special */
+#define IFDIR 0x4000 /* directory */
+#define IFBLK 0x6000 /* block special */
+#define IFREG 0x8000 /* regular */
+#define IFLNK 0xa000 /* symbolic link */
+#define IFSOCK 0xc000 /* socket */
+
+
+#define ISUID 0x0800 /* set user id on execution */
+#define ISGID 0x0400 /* set group id on execution */
+#define ISVTX 0x0200 /* save swapped text even after use */
+#define IREAD 0x0100 /* read, write, execute permissions */
+#define IWRITE 0x0080
+#define IEXEC 0x0040
+
+#ifdef EEK
+#define f_fs u.ffs.ffs_fs
+#define i_ic u.ffs.ffs_ic
+#define f_nindir u.ffs.ffs_nindir
+#define f_blk u.ffs.ffs_blk
+#define f_blksize u.ffs.ffs_blksize
+#define f_blkno u.ffs.ffs_blkno
+#endif /* EEK */
+
+#endif /* _BOOT_UFS_DISK_INODE_FFS_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/fat.h b/qemu/roms/openbios/fs/grubfs/fat.h
new file mode 100644
index 000000000..43d38aefc
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fat.h
@@ -0,0 +1,99 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+
+/*
+ * Defines for the FAT BIOS Parameter Block (embedded in the first block
+ * of the partition.
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/* Note that some shorts are not aligned, and must therefore
+ * be declared as array of two bytes.
+ */
+struct fat_bpb {
+ __s8 ignored[3]; /* Boot strap short or near jump */
+ __s8 system_id[8]; /* Name - can be used to special case
+ partition manager volumes */
+ __u16 bytes_per_sect; /* bytes per logical sector */
+ __u8 sects_per_clust;/* sectors/cluster */
+ __u16 reserved_sects; /* reserved sectors */
+ __u8 num_fats; /* number of FATs */
+ __u16 dir_entries; /* root directory entries */
+ __u16 short_sectors; /* number of sectors */
+ __u8 media; /* media code (unused) */
+ __u16 fat_length; /* sectors/FAT */
+ __u16 secs_track; /* sectors per track */
+ __u16 heads; /* number of heads */
+ __u32 hidden; /* hidden sectors (unused) */
+ __u32 long_sectors; /* number of sectors (if short_sectors == 0) */
+
+ /* The following fields are only used by FAT32 */
+ __u32 fat32_length; /* sectors/FAT */
+ __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
+ __u16 version; /* major, minor filesystem version */
+ __u32 root_cluster; /* first cluster in root directory */
+ __u16 info_sector; /* filesystem info sector */
+ __u16 backup_boot; /* backup boot sector */
+ __u16 reserved2[6]; /* Unused */
+} __attribute__ ((packed));
+
+/*
+ * Defines how to differentiate a 12-bit and 16-bit FAT.
+ */
+
+#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */
+
+/*
+ * Defines for the file "attribute" byte
+ */
+
+#define FAT_ATTRIB_OK_MASK 0x37
+#define FAT_ATTRIB_NOT_OK_MASK 0xC8
+#define FAT_ATTRIB_DIR 0x10
+#define FAT_ATTRIB_LONGNAME 0x0F
+
+/*
+ * Defines for FAT directory entries
+ */
+
+#define FAT_DIRENTRY_LENGTH 32
+
+#define FAT_DIRENTRY_ATTRIB(entry) \
+ (*((unsigned char *) (entry+11)))
+#define FAT_DIRENTRY_VALID(entry) \
+ ( ((*((unsigned char *) entry)) != 0) \
+ && ((*((unsigned char *) entry)) != 0xE5) \
+ && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
+#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
+ ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
+#define FAT_DIRENTRY_FILELENGTH(entry) \
+ (*((unsigned long *) (entry+28)))
+
+#define FAT_LONGDIR_ID(entry) \
+ (*((unsigned char *) (entry)))
+#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
+ (*((unsigned char *) (entry+13)))
diff --git a/qemu/roms/openbios/fs/grubfs/filesys.h b/qemu/roms/openbios/fs/grubfs/filesys.h
new file mode 100644
index 000000000..6b6f97603
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/filesys.h
@@ -0,0 +1,303 @@
+/* GRUB compatibility header
+ *
+ * taken from filo and grub.
+ */
+
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2003 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+/* This disables some portion of code */
+#define STAGE1_5 1
+
+#if defined CONFIG_X86
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+static __inline__ unsigned int
+ffz (unsigned int word)
+{
+ __asm__ ("bsfl %1,%0"
+ : "=r" (word)
+ : "r" (~word));
+ return word;
+}
+
+static __inline__ unsigned int
+log2 (unsigned int word)
+{
+ __asm__ ("bsfl %1,%0"
+ : "=r" (word)
+ : "r" (word));
+ return word;
+}
+
+#elif defined (CONFIG_PPC)
+static __inline__ unsigned long
+ __ilog2(unsigned long x)
+{
+ unsigned long lz;
+
+ asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+ return 31 - lz;
+}
+
+static __inline__ unsigned long
+ffz(unsigned long x)
+{
+ if ((x = ~x) == 0)
+ return 32;
+
+ return __ilog2(x & -x);
+}
+
+#define log2(n) ffz(~(n))
+
+#else
+
+static __inline__ unsigned int log2(unsigned int word)
+{
+ /* assume 8 bits per byte. */
+ unsigned int i = 1 << (sizeof(word)*8 - 1);
+ unsigned int pow = sizeof(word) * 8 - 1;
+
+ if (! word) {
+ /* invalid parameter */
+ return -1;
+ }
+ for(; i > word; i >>= 1, pow--) ;
+
+ return pow;
+}
+
+#define ffz(n) log2(~(n))
+
+#endif
+
+static inline int
+substring (const char *s1, const char *s2)
+{
+ while (*s1 == *s2)
+ {
+ /* The strings match exactly. */
+ if (! *(s1++))
+ return 0;
+ s2 ++;
+ }
+
+ /* S1 is a substring of S2. */
+ if (*s1 == 0)
+ return -1;
+
+ /* S1 isn't a substring. */
+ return 1;
+}
+
+#define grub_memmove memmove
+#define grub_strcmp strcmp
+
+#define MAXINT 0x7fffffff
+
+/* This is only used by fsys_* to determine if it's hard disk. If it is,
+ * they try to guess filesystem type by partition type. I guess it is
+ * not necessory, so hardcoded to 0 (first floppy) --ts1 */
+#define current_drive 0
+#define current_slice 0
+#define current_partition 0
+
+/* we fake this for now, assuming that the filesystem is not corrupt */
+#define part_length -1
+extern int filepos;
+extern int filemax;
+extern int fsmax;
+
+/* Error codes (descriptions are in common.c) */
+typedef enum
+{
+ ERR_NONE = 0,
+ ERR_BAD_FILENAME,
+ ERR_BAD_FILETYPE,
+ ERR_BAD_GZIP_DATA,
+ ERR_BAD_GZIP_HEADER,
+ ERR_BAD_PART_TABLE,
+ ERR_BAD_VERSION,
+ ERR_BELOW_1MB,
+ ERR_BOOT_COMMAND,
+ ERR_BOOT_FAILURE,
+ ERR_BOOT_FEATURES,
+ ERR_DEV_FORMAT,
+ ERR_DEV_VALUES,
+ ERR_EXEC_FORMAT,
+ ERR_FILELENGTH,
+ ERR_FILE_NOT_FOUND,
+ ERR_FSYS_CORRUPT,
+ ERR_FSYS_MOUNT,
+ ERR_GEOM,
+ ERR_NEED_LX_KERNEL,
+ ERR_NEED_MB_KERNEL,
+ ERR_NO_DISK,
+ ERR_NO_PART,
+ ERR_NUMBER_PARSING,
+ ERR_OUTSIDE_PART,
+ ERR_READ,
+ ERR_SYMLINK_LOOP,
+ ERR_UNRECOGNIZED,
+ ERR_WONT_FIT,
+ ERR_WRITE,
+ ERR_BAD_ARGUMENT,
+ ERR_UNALIGNED,
+ ERR_PRIVILEGED,
+ ERR_DEV_NEED_INIT,
+ ERR_NO_DISK_SPACE,
+ ERR_NUMBER_OVERFLOW,
+
+ MAX_ERR_NUM
+} grub_error_t;
+
+extern grub_error_t errnum;
+
+#define grub_open file_open
+#define grub_read file_read
+#define grub_seek file_seek
+#define grub_close file_close
+
+/* instrumentation variables */
+/* (Not used in FILO) */
+extern void (*disk_read_hook) (int, int, int);
+extern void (*disk_read_func) (int, int, int);
+
+#define FSYS_BUFLEN 0x8000
+extern char FSYS_BUF[FSYS_BUFLEN];
+
+#define print_possibilities 0
+
+#define SECTOR_SIZE 512
+#define SECTOR_BITS 9
+
+#ifdef CONFIG_FSYS_FAT
+int fat_mount (void);
+int fat_read (char *buf, int len);
+int fat_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_EXT2FS
+int ext2fs_mount (void);
+int ext2fs_read (char *buf, int len);
+int ext2fs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_MINIX
+int minix_mount (void);
+int minix_read (char *buf, int len);
+int minix_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_REISERFS
+int reiserfs_mount (void);
+int reiserfs_read (char *buf, int len);
+int reiserfs_dir (char *dirname);
+int reiserfs_embed (int *start_sector, int needed_sectors);
+#endif
+
+#ifdef CONFIG_FSYS_JFS
+int jfs_mount (void);
+int jfs_read (char *buf, int len);
+int jfs_dir (char *dirname);
+int jfs_embed (int *start_sector, int needed_sectors);
+#endif
+
+#ifdef CONFIG_FSYS_XFS
+int xfs_mount (void);
+int xfs_read (char *buf, int len);
+int xfs_dir (char *dirname);
+#endif
+
+#ifdef CONFIG_FSYS_UFS
+int ufs_mount (void);
+int ufs_read (char *buf, int len);
+int ufs_dir (char *dirname);
+int ufs_embed (int *start_sector, int needed_sectors);
+#endif
+
+#ifdef CONFIG_FSYS_ISO9660
+int iso9660_mount (void);
+int iso9660_read (char *buf, int len);
+int iso9660_dir (char *dirname);
+#endif
+
+/* This is not a flag actually, but used as if it were a flag. */
+#define PC_SLICE_TYPE_HIDDEN_FLAG 0x10
+
+#define PC_SLICE_TYPE_NONE 0
+#define PC_SLICE_TYPE_FAT12 1
+#define PC_SLICE_TYPE_FAT16_LT32M 4
+#define PC_SLICE_TYPE_EXTENDED 5
+#define PC_SLICE_TYPE_FAT16_GT32M 6
+#define PC_SLICE_TYPE_FAT32 0xb
+#define PC_SLICE_TYPE_FAT32_LBA 0xc
+#define PC_SLICE_TYPE_FAT16_LBA 0xe
+#define PC_SLICE_TYPE_WIN95_EXTENDED 0xf
+#define PC_SLICE_TYPE_EZD 0x55
+#define PC_SLICE_TYPE_MINIX 0x80
+#define PC_SLICE_TYPE_LINUX_MINIX 0x81
+#define PC_SLICE_TYPE_EXT2FS 0x83
+#define PC_SLICE_TYPE_LINUX_EXTENDED 0x85
+#define PC_SLICE_TYPE_VSTAFS 0x9e
+#define PC_SLICE_TYPE_DELL_UTIL 0xde
+#define PC_SLICE_TYPE_LINUX_RAID 0xfd
+
+/* For convinience. */
+/* Check if TYPE is a FAT partition type. Clear the hidden flag before
+ the check, to allow the user to mount a hidden partition in GRUB. */
+#define IS_PC_SLICE_TYPE_FAT(type) \
+ ({ int _type = (type) & ~PC_SLICE_TYPE_HIDDEN_FLAG; \
+ _type == PC_SLICE_TYPE_FAT12 \
+ || _type == PC_SLICE_TYPE_FAT16_LT32M \
+ || _type == PC_SLICE_TYPE_FAT16_GT32M \
+ || _type == PC_SLICE_TYPE_FAT16_LBA \
+ || _type == PC_SLICE_TYPE_FAT32 \
+ || _type == PC_SLICE_TYPE_FAT32_LBA \
+ || _type == PC_SLICE_TYPE_DELL_UTIL; })
+
+#define IS_PC_SLICE_TYPE_MINIX(type) \
+ (((type) == PC_SLICE_TYPE_MINIX) \
+ || ((type) == PC_SLICE_TYPE_LINUX_MINIX))
+
+#define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0
+
+/* possible values for the *BSD-style partition type */
+#define FS_UNUSED 0 /* unused */
+#define FS_SWAP 1 /* swap */
+#define FS_V6 2 /* Sixth Edition */
+#define FS_V7 3 /* Seventh Edition */
+#define FS_SYSV 4 /* System V */
+#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
+#define FS_V8 6 /* Eighth Edition, 4K blocks */
+#define FS_BSDFFS 7 /* 4.2BSD fast file system */
+#define FS_MSDOS 8 /* MSDOS file system */
+#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
+#define FS_OTHER 10 /* in use, but unknown/unsupported */
+#define FS_HPFS 11 /* OS/2 high-performance file system */
+#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
+#define FS_BOOT 13 /* partition contains bootstrap */
+#define FS_ADOS 14 /* AmigaDOS fast file system */
+#define FS_HFS 15 /* Macintosh HFS */
+#define FS_FILECORE 16 /* Acorn Filecore Filing System */
+#define FS_EXT2FS 17 /* Linux Extended 2 file system */
diff --git a/qemu/roms/openbios/fs/grubfs/fs.h b/qemu/roms/openbios/fs/grubfs/fs.h
new file mode 100644
index 000000000..260e92647
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fs.h
@@ -0,0 +1,457 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)fs.h 7.7 (Berkeley) 5/9/89
+ */
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups. The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss. This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For file system fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ * [fs->fs_sblkno] Super-block
+ * [fs->fs_cblkno] Cylinder group block
+ * [fs->fs_iblkno] Inode blocks
+ * [fs->fs_dblkno] Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * The first boot and super blocks are given in absolute disk addresses.
+ * The byte-offset forms are preferred, as they don't imply a sector size.
+ */
+#define BBSIZE 8192
+#define SBSIZE 8192
+#define BBOFF ((mach_off_t)(0))
+#define SBOFF ((mach_off_t)(BBOFF + BBSIZE))
+#define BBLOCK ((mach_daddr_t)(0))
+#define SBLOCK ((mach_daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressible; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks. To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary. The file system format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided. The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The file system records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ *
+ * The root inode is the root of the file system.
+ * Inode 0 can't be used for normal purposes and
+ * historically bad blocks were linked to inode 1,
+ * thus the root inode is 2. (inode 1 is no longer used for
+ * this purpose, however numerous dump tapes make this
+ * assumption, so we are stuck with it)
+ */
+#define ROOTINO ((mach_ino_t)2) /* i number of all roots */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define MINBSIZE 4096
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ * The limit on the amount of summary information per file system
+ * is defined by MAXCSBUFS. It is currently parameterized for a
+ * maximum of two million cylinders.
+ */
+#define MAXMNTLEN 512
+#define MAXCSBUFS 32
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ *
+ * N.B. sizeof(struct csum) must be a power of two in order for
+ * the ``fs_cs'' macro to work (see below).
+ */
+struct csum
+ {
+ int cs_ndir; /* number of directories */
+ int cs_nbfree; /* number of free blocks */
+ int cs_nifree; /* number of free inodes */
+ int cs_nffree; /* number of free frags */
+ };
+
+/*
+ * Super block for a file system.
+ */
+#define FS_MAGIC 0x011954
+struct fs
+ {
+ int xxx1; /* struct fs *fs_link; */
+ int xxx2; /* struct fs *fs_rlink; */
+ mach_daddr_t fs_sblkno; /* addr of super-block in filesys */
+ mach_daddr_t fs_cblkno; /* offset of cyl-block in filesys */
+ mach_daddr_t fs_iblkno; /* offset of inode-blocks in filesys */
+ mach_daddr_t fs_dblkno; /* offset of first data after cg */
+ int fs_cgoffset; /* cylinder group offset in cylinder */
+ int fs_cgmask; /* used to calc mod fs_ntrak */
+ mach_time_t fs_time; /* last time written */
+ int fs_size; /* number of blocks in fs */
+ int fs_dsize; /* number of data blocks in fs */
+ int fs_ncg; /* number of cylinder groups */
+ int fs_bsize; /* size of basic blocks in fs */
+ int fs_fsize; /* size of frag blocks in fs */
+ int fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ int fs_minfree; /* minimum percentage of free blocks */
+ int fs_rotdelay; /* num of ms for optimal next block */
+ int fs_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ int fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int fs_fmask; /* ``fragoff'' calc of frag offsets */
+ int fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ int fs_maxcontig; /* max number of contiguous blks */
+ int fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ int fs_fragshift; /* block to frag shift */
+ int fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int fs_sbsize; /* actual size of super block */
+ int fs_csmask; /* csum block offset */
+ int fs_csshift; /* csum block number */
+ int fs_nindir; /* value of NINDIR */
+ int fs_inopb; /* value of INOPB */
+ int fs_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ int fs_optim; /* optimization preference, see below */
+/* these fields are derived from the hardware */
+ int fs_npsect; /* # sectors/track including spares */
+ int fs_interleave; /* hardware sector interleave */
+ int fs_trackskew; /* sector 0 skew, per track */
+ int fs_headswitch; /* head switch time, usec */
+ int fs_trkseek; /* track-to-track seek, usec */
+/* sizes determined by number of cylinder groups and their sizes */
+ mach_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */
+ int fs_cssize; /* size of cyl grp summary area */
+ int fs_cgsize; /* cylinder group size */
+/* these fields are derived from the hardware */
+ int fs_ntrak; /* tracks per cylinder */
+ int fs_nsect; /* sectors per track */
+ int fs_spc; /* sectors per cylinder */
+/* this comes from the disk driver partitioning */
+ int fs_ncyl; /* cylinders in file system */
+/* these fields can be computed from the others */
+ int fs_cpg; /* cylinders per group */
+ int fs_ipg; /* inodes per group */
+ int fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct csum fs_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ char fs_fmod; /* super block modified flag */
+ char fs_clean; /* file system is clean flag */
+ char fs_ronly; /* mounted read-only flag */
+ char fs_flags; /* currently unused flag */
+ char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+/* these fields retain the current block allocation info */
+ int fs_cgrotor; /* last cg searched */
+#if 1
+ int was_fs_csp[MAXCSBUFS];
+#else
+ struct csum *fs_csp[MAXCSBUFS]; /* list of fs_cs info buffers */
+#endif
+ int fs_cpc; /* cyl per cycle in postbl */
+ short fs_opostbl[16][8]; /* old rotation block list head */
+ long fs_sparecon[50]; /* reserved for future constants */
+ long fs_contigsumsize; /* size of cluster summary array */
+ long fs_maxsymlinklen; /* max length of an internal symlink */
+ long fs_inodefmt; /* format of on-disk inodes */
+ quad fs_maxfilesize; /* maximum representable file size */
+ quad fs_qbmask; /* ~fs_bmask - for use with quad size */
+ quad fs_qfmask; /* ~fs_fmask - for use with quad size */
+ long fs_state; /* validate fs_clean field */
+ int fs_postblformat; /* format of positional layout tables */
+ int fs_nrpos; /* number of rotaional positions */
+ int fs_postbloff; /* (short) rotation block list head */
+ int fs_rotbloff; /* (char) blocks for each rotation */
+ int fs_magic; /* magic number */
+ unsigned char fs_space[1]; /* list of blocks for each rotation */
+/* actually longer */
+ };
+/*
+ * Preference for optimization.
+ */
+#define FS_OPTTIME 0 /* minimize allocation time */
+#define FS_OPTSPACE 1 /* minimize disk fragmentation */
+
+/*
+ * Rotational layout table format types
+ */
+#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
+#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
+/*
+ * Macros for access to superblock array structures
+ */
+#define fs_postbl(fs, cylno) \
+ (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+ ? ((fs)->fs_opostbl[cylno]) \
+ : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos))
+#define fs_rotbl(fs) \
+ (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+ ? ((fs)->fs_space) \
+ : ((unsigned char *)((char *)(fs) + (fs)->fs_rotbloff)))
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ *
+ * N.B. This macro assumes that sizeof(struct csum) is a power of two.
+ */
+#define fs_cs(fs, indx) \
+ fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ */
+#define CG_MAGIC 0x090255
+struct cg
+ {
+ int xxx1; /* struct cg *cg_link; */
+ int cg_magic; /* magic number */
+ mach_time_t cg_time; /* time last written */
+ int cg_cgx; /* we are the cgx'th cylinder group */
+ short cg_ncyl; /* number of cyl's this cg */
+ short cg_niblk; /* number of inode blocks this cg */
+ int cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int cg_rotor; /* position of last used block */
+ int cg_frotor; /* position of last used frag */
+ int cg_irotor; /* position of last used inode */
+ int cg_frsum[MAXFRAG]; /* counts of available frags */
+ int cg_btotoff; /* (long) block totals per cylinder */
+ int cg_boff; /* (short) free block positions */
+ int cg_iusedoff; /* (char) used inode map */
+ int cg_freeoff; /* (char) free block map */
+ int cg_nextfreeoff; /* (char) next available space */
+ int cg_sparecon[16]; /* reserved for future use */
+ unsigned char cg_space[1]; /* space for cylinder group maps */
+/* actually longer */
+ };
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define cg_blktot(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_btot) \
+ : ((int *)((char *)(cgp) + (cgp)->cg_btotoff)))
+#define cg_blks(fs, cgp, cylno) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_b[cylno]) \
+ : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos))
+#define cg_inosused(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_iused) \
+ : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff)))
+#define cg_blksfree(cgp) \
+ (((cgp)->cg_magic != CG_MAGIC) \
+ ? (((struct ocg *)(cgp))->cg_free) \
+ : ((unsigned char *)((char *)(cgp) + (cgp)->cg_freeoff)))
+#define cg_chkmagic(cgp) \
+ ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC)
+
+/*
+ * The following structure is defined
+ * for compatibility with old file systems.
+ */
+struct ocg
+ {
+ int xxx1; /* struct ocg *cg_link; */
+ int xxx2; /* struct ocg *cg_rlink; */
+ mach_time_t cg_time; /* time last written */
+ int cg_cgx; /* we are the cgx'th cylinder group */
+ short cg_ncyl; /* number of cyl's this cg */
+ short cg_niblk; /* number of inode blocks this cg */
+ int cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int cg_rotor; /* position of last used block */
+ int cg_frotor; /* position of last used frag */
+ int cg_irotor; /* position of last used inode */
+ int cg_frsum[8]; /* counts of available frags */
+ int cg_btot[32]; /* block totals per cylinder */
+ short cg_b[32][8]; /* positions of free blocks */
+ char cg_iused[256]; /* used inode map */
+ int cg_magic; /* magic number */
+ unsigned char cg_free[1]; /* free block map */
+/* actually longer */
+ };
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define cgbase(fs, c) ((mach_daddr_t)((fs)->fs_fpg * (c)))
+#define cgstart(fs, c) \
+ (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
+#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
+#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
+#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to file system block offset.
+ * inode number to cylinder group number.
+ * inode number to file system block address.
+ */
+#define itoo(fs, x) ((x) % INOPB(fs))
+#define itog(fs, x) ((x) / (fs)->fs_ipg)
+#define itod(fs, x) \
+ ((mach_daddr_t)(cgimin(fs, itog(fs, x)) + \
+ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define dtog(fs, d) ((d) / (fs)->fs_fpg)
+#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define blkmap(fs, map, loc) \
+ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+#define cbtocylno(fs, bno) \
+ ((bno) * NSPF(fs) / (fs)->fs_spc)
+#define cbtorpos(fs, bno) \
+ (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \
+ (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \
+ (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
+ ((loc) & ~(fs)->fs_bmask)
+#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
+ ((loc) & ~(fs)->fs_fmask)
+#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
+ ((loc) >> (fs)->fs_bshift)
+#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
+ ((loc) >> (fs)->fs_fshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
+ (((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask)
+#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
+ (((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask)
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
+ ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
+ ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve
+ */
+#define freespace(fs, percentreserved) \
+ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+ (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the file system.
+ */
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+#define dblksize(fs, dip, lbn) \
+ (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
+
+/*
+ * Number of disk sectors per block; assumes DEV_BSIZE byte sector size.
+ */
+#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift)
+#define NSPF(fs) ((fs)->fs_nspf)
+
+/*
+ * INOPB is the number of inodes in a secondary storage block.
+ */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * NINDIR is the number of indirects in a file system block.
+ */
+#define NINDIR(fs) ((fs)->fs_nindir)
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_affs.c b/qemu/roms/openbios/fs/grubfs/fsys_affs.c
new file mode 100644
index 000000000..c4a76322b
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_affs.c
@@ -0,0 +1,712 @@
+#ifdef FSYS_AFFS
+#include "shared.h"
+#include "filesys.h"
+
+/******************************** RDB definitions */
+#define RDB_LOCATION_LIMIT 16
+#define IDNAME_RIGIDDISK 0x5244534B /* 'RDSK' */
+
+struct RigidDiskBlock
+{
+ unsigned long rdb_ID;
+ unsigned long rdb_SummedLongs;
+ long rdb_ChkSum;
+ unsigned long rdb_HostID;
+ unsigned long rdb_BlockBytes;
+ unsigned long rdb_Flags;
+ unsigned long rdb_BadBlockList;
+ unsigned long rdb_PartitionList;
+ unsigned long rdb_FileSysHeaderList;
+ unsigned long rdb_DriveInit;
+ unsigned long rdb_Reserved1[6];
+ unsigned long rdb_Cylinders;
+ unsigned long rdb_Sectors;
+ unsigned long rdb_Heads;
+ unsigned long rdb_Interleave;
+ unsigned long rdb_Park;
+ unsigned long rdb_Reserved2[3];
+ unsigned long rdb_WritePreComp;
+ unsigned long rdb_ReducedWrite;
+ unsigned long rdb_StepRate;
+ unsigned long rdb_Reserved3[5];
+ unsigned long rdb_RDBBlocksLo;
+ unsigned long rdb_RDBBlocksHi;
+ unsigned long rdb_LoCylinder;
+ unsigned long rdb_HiCylinder;
+ unsigned long rdb_CylBlocks;
+ unsigned long rdb_AutoParkSeconds;
+ unsigned long rdb_HighRDSKBlock;
+ unsigned long rdb_Reserved4;
+ char rdb_DiskVendor[8];
+ char rdb_DiskProduct[16];
+ char rdb_DiskRevision[4];
+ char rdb_ControllerVendor[8];
+ char rdb_ControllerProduct[16];
+ char rdb_ControllerRevision[4];
+ char rdb_DriveInitName[40];
+};
+
+struct PartitionBlock
+{
+ unsigned long pb_ID;
+ unsigned long pb_SummedLongs;
+ long pb_ChkSum;
+ unsigned long pb_HostID;
+ unsigned long pb_Next;
+ unsigned long pb_Flags;
+ unsigned long pb_Reserved1[2];
+ unsigned long pb_DevFlags;
+ char pb_DriveName[32];
+ unsigned long pb_Reserved2[15];
+ unsigned long pb_Environment[20];
+ unsigned long pb_EReserved[12];
+};
+
+#define DE_TABLESIZE 0
+#define DE_SIZEBLOCK 1
+#define DE_BLOCKSIZE 2
+#define DE_NUMHEADS 3
+#define DE_SECSPERBLOCK 4
+#define DE_BLKSPERTRACK 5
+#define DE_RESERVEDBLKS 6
+#define DE_PREFAC 7
+#define DE_INTERLEAVE 8
+#define DE_LOWCYL 9
+#define DE_HIGHCYL 10
+#define DE_UPPERCYL DE_HIGHCYL
+#define DE_NUMBUFFERS 11
+#define DE_BUFMEMTYPE 12
+#define DE_MEMBUFTYPE DE_BUFMEMTYPE
+#define DE_MAXTRANSFER 13
+#define DE_MASK 14
+#define DE_BOOTPRI 15
+#define DE_DOSTYPE 16
+#define DE_BAUD 17
+#define DE_CONTROL 18
+#define DE_BOOTBLOCKS 19
+
+
+/******************************** AFFS definitions */
+#define T_SHORT 2
+#define T_LIST 16
+
+#define ST_FILE -3
+#define ST_ROOT 1
+#define ST_USERDIR 2
+
+struct BootBlock{
+ int id;
+ int chksum;
+ int rootblock;
+ int data[127];
+};
+
+struct RootBlock{
+ int p_type; //0
+ int n1[2]; //1-2
+ int hashtable_size; //3
+ int n2; //4
+ int checksum; //5
+ int hashtable[72]; //6-77
+ int bitmap_valid_flag; //78
+ int bitmap_ptrs[25]; //79-103
+ int bitmap_extension; //104
+ int root_days; //105
+ int root_mins; //106
+ int root_ticks; //107;
+ char diskname[32]; //108-115
+ int n3[2]; //116-117
+ int volume_days; //118
+ int volume_mins; //119
+ int volume_ticks; //120
+ int creation_days; //121
+ int creation_mins; //122
+ int creation_ticks; //123
+ int n4[3]; //124-126
+ int s_type; //127
+};
+
+struct DirHeader {
+ int p_type; //0
+ int own_key; //1
+ int n1[3]; //2-4
+ int checksum; //5
+ int hashtable[72]; //6-77
+ int n2; //78
+ int owner; //79
+ int protection; //80
+ int n3; //81
+ char comment[92]; //82-104
+ int days; //105
+ int mins; //106
+ int ticks; //107
+ char name[32]; //108-115
+ int n4[2]; //116-117
+ int linkchain; //118
+ int n5[5]; //119-123
+ int hashchain; //124
+ int parent; //125
+ int n6; //126
+ int s_type; //127
+};
+
+struct FileHeader {
+ int p_type; //0
+ int own_key; //1
+ int n1[3]; //2-4
+ int checksum; //5
+ int filekey_table[72]; //6-77
+ int n2; //78
+ int owner; //79
+ int protection; //80
+ int bytesize; //81
+ char comment[92]; //82-104
+ int days; //105
+ int mins; //106
+ int ticks; //107
+ char name[32]; //108-115
+ int n3[2]; //116-117
+ int linkchain; //118
+ int n4[5]; //119-123
+ int hashchain; //124
+ int parent; //125
+ int extension; //126
+ int s_type; //127
+};
+
+struct FileKeyExtension{
+ int p_type; //0
+ int own_key; //1
+ int table_size; //2
+ int n1[2]; //3-4
+ int checksum; //5
+ int filekey_table[72]; //6-77
+ int info[46]; //78-123
+ int n2; //124
+ int parent; //125
+ int extension; //126
+ int s_type; //127
+};
+
+struct Position {
+ unsigned int block;
+ short filekey;
+ unsigned short byte;
+ unsigned int offset;
+};
+
+struct ReadData {
+ unsigned int header_block;
+ struct Position current;
+ unsigned int filesize;
+};
+
+//#warning "Big vs. little endian for configure needed"
+#define AROS_BE2LONG(l) \
+ ( \
+ ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \
+ ((((unsigned long)(l)) >> 8) & 0x0000FF00UL) | \
+ ((((unsigned long)(l)) << 8) & 0x00FF0000UL) | \
+ ((((unsigned long)(l)) << 24) & 0xFF000000UL) \
+ )
+
+struct CacheBlock {
+ int blocknum;
+ unsigned short flags;
+ unsigned short access_count;
+ unsigned int blockbuffer[128];
+};
+#define LockBuffer(x) (((struct CacheBlock *)(x))->flags |= 0x0001)
+#define UnLockBuffer(x) (((struct CacheBlock *)(x))->flags &= ~0x0001)
+
+#define MAX_CACHE_BLOCKS 10
+
+struct FSysBuffer {
+ struct ReadData file;
+ struct CacheBlock blocks[MAX_CACHE_BLOCKS];
+};
+
+#define bootBlock(x) ((struct BootBlock *)(x)->blockbuffer)
+#define rootBlock(x) ((struct RootBlock *)(x)->blockbuffer)
+#define dirHeader(x) ((struct DirHeader *)(x)->blockbuffer)
+#define fileHeader(x) ((struct FileHeader *)(x)->blockbuffer)
+#define extensionBlock(x) ((struct FileKeyExtension *)(x)->blockbuffer)
+
+#define rdsk(x) ((struct RigidDiskBlock *)(x)->blockbuffer)
+#define part(x) ((struct PartitionBlock *)(x)->blockbuffer)
+
+static struct FSysBuffer *fsysb;
+static int blockoffset; /* offset if there is an embedded RDB partition */
+static int rootb; /* block number of root block */
+static int rdbb; /* block number of rdb block */
+
+static void initCache(void)
+{
+int i;
+
+ for (i=0;i<MAX_CACHE_BLOCKS;i++)
+ {
+ fsysb->blocks[i].blocknum = -1;
+ fsysb->blocks[i].flags = 0;
+ fsysb->blocks[i].access_count = 0;
+ }
+}
+
+static struct CacheBlock *getBlock(unsigned int block)
+{
+struct CacheBlock *freeblock;
+int i;
+
+ /* get first unlocked block */
+ i = 0;
+ do
+ {
+ freeblock = &fsysb->blocks[i++];
+ } while (freeblock->flags & 0x0001);
+ /* search through list if block is already loaded in */
+ for (i=0;i<MAX_CACHE_BLOCKS;i++)
+ {
+ if (fsysb->blocks[i].blocknum == block)
+ {
+ fsysb->blocks[i].access_count++;
+ return &fsysb->blocks[i];
+ }
+ if (!(fsysb->blocks[i].flags & 0x0001))
+ if (freeblock->access_count>fsysb->blocks[i].access_count)
+ freeblock = &fsysb->blocks[i];
+ }
+ freeblock->blocknum = block;
+ devread(block+blockoffset, 0, 512, (char *)freeblock->blockbuffer);
+ return freeblock;
+}
+
+static unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer)
+{
+unsigned int sum=0,count=0;
+
+ for (count=0;count<SizeBlock;count++)
+ sum += AROS_BE2LONG(buffer[count]);
+ return sum;
+}
+
+int affs_mount(void) {
+struct CacheBlock *cblock;
+int i;
+
+ if (
+ (current_drive & 0x80) &&
+ (current_partition != 0xFFFFFF) &&
+ (current_slice != 0x30)
+ )
+ return 0;
+ fsysb = (struct FSysBuffer *)FSYS_BUF;
+ blockoffset = 0;
+ initCache();
+ /* check for rdb partitiontable */
+ for (i=0;i<RDB_LOCATION_LIMIT;i++)
+ {
+ cblock = getBlock(i);
+ if (
+ (
+ ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFFFFFF00)==0x444F5300) &&
+ ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFF)>0)
+ ) ||
+ (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK)
+ )
+ break;
+ }
+ if (i == RDB_LOCATION_LIMIT)
+ return 0;
+ if (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK)
+ {
+ /* we have an RDB partition table within a MBR-Partition */
+ rdbb = i;
+ }
+ else if (i<2)
+ {
+ /* partition type is 0x30 = AROS and AFFS formatted */
+ rdbb = RDB_LOCATION_LIMIT;
+ rootb = (part_length-1+2)/2;
+ cblock = getBlock(rootb);
+ if (
+ (AROS_BE2LONG(rootBlock(cblock)->p_type) != T_SHORT) ||
+ (AROS_BE2LONG(rootBlock(cblock)->s_type) != ST_ROOT) ||
+ calcChkSum(128, cblock->blockbuffer)
+ )
+ return 0;
+ }
+ else
+ return 0;
+ return 1;
+}
+
+static int seek(unsigned long offset)
+{
+struct CacheBlock *cblock;
+unsigned long block;
+unsigned long togo;
+
+ block = fsysb->file.header_block;
+
+ togo = offset / 512;
+ fsysb->file.current.filekey = 71-(togo % 72);
+ togo /= 72;
+ fsysb->file.current.byte = offset % 512;
+ fsysb->file.current.offset = offset;
+ while ((togo) && (block))
+ {
+ disk_read_func = disk_read_hook;
+ cblock = getBlock(block);
+ disk_read_func = NULL;
+ block = AROS_BE2LONG(extensionBlock(cblock)->extension);
+ togo--;
+ }
+ if (togo)
+ return 1;
+ fsysb->file.current.block = block;
+ return 0;
+}
+
+int affs_read(char *buf, int len) {
+struct CacheBlock *cblock;
+unsigned short size;
+unsigned int readbytes = 0;
+
+ if (fsysb->file.current.offset != filepos)
+ {
+ if (seek(filepos))
+ return ERR_FILELENGTH;
+ }
+ if (fsysb->file.current.block == 0)
+ return 0;
+ if (len>(fsysb->file.filesize-fsysb->file.current.offset))
+ len=fsysb->file.filesize-fsysb->file.current.offset;
+ disk_read_func = disk_read_hook;
+ cblock = getBlock(fsysb->file.current.block);
+ disk_read_func = NULL;
+ while (len)
+ {
+ disk_read_func = disk_read_hook;
+ if (fsysb->file.current.filekey<0)
+ {
+ fsysb->file.current.filekey = 71;
+ fsysb->file.current.block = AROS_BE2LONG(extensionBlock(cblock)->extension);
+ if (fsysb->file.current.block)
+ {
+ cblock = getBlock(fsysb->file.current.block);
+ }
+ //#warning "else shouldn't occour"
+ }
+ size = 512;
+ size -= fsysb->file.current.byte;
+ if (size>len)
+ {
+ size = len;
+ devread
+ (
+ AROS_BE2LONG
+ (
+ extensionBlock(cblock)->filekey_table
+ [fsysb->file.current.filekey]
+ )+blockoffset,
+ fsysb->file.current.byte, size, (char *)((long)buf+readbytes)
+ );
+ fsysb->file.current.byte += size;
+ }
+ else
+ {
+ devread
+ (
+ AROS_BE2LONG
+ (
+ extensionBlock(cblock)->filekey_table
+ [fsysb->file.current.filekey]
+ )+blockoffset,
+ fsysb->file.current.byte, size, (char *)((long)buf+readbytes)
+ );
+ fsysb->file.current.byte = 0;
+ fsysb->file.current.filekey--;
+ }
+ disk_read_func = NULL;
+ len -= size;
+ readbytes += size;
+ }
+ fsysb->file.current.offset += readbytes;
+ filepos = fsysb->file.current.offset;
+ return readbytes;
+}
+
+static unsigned char capitalch(unsigned char ch, unsigned char flags)
+{
+
+ if ((flags==0) || (flags==1))
+ return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch);
+ else // DOS\(>=2)
+ return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) ||
+ ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch);
+}
+
+// str2 is a BCPL string
+static int noCaseStrCmp(char *str1, char *str2, unsigned char flags)
+{
+unsigned char length;
+
+ length=str2++[0];
+ do {
+ if ((*str1==0) && (length==0))
+ return 0;
+ length--;
+// if ((*str1==0) && (*str2==0)) return 1;
+ } while (capitalch(*str1++,flags)==capitalch(*str2++,flags));
+ str1--;
+ return (*str1) ? 1 : -1;
+}
+
+static unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags)
+{
+unsigned int length;
+
+ length=0;
+ while (name[length] != 0)
+ length++;
+ while (*name!=0)
+ length=(length * 13 +capitalch(*name++,flags)) & 0x7FF;
+ return length%tablesize;
+}
+
+static grub_error_t getHeaderBlock(char *name, struct CacheBlock **dirh)
+{
+int key;
+
+ key = getHashKey(name, 72, 1);
+ if (!dirHeader(*dirh)->hashtable[key])
+ return ERR_FILE_NOT_FOUND;
+ *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashtable[key]));
+ if (calcChkSum(128, (*dirh)->blockbuffer))
+ {
+#ifdef DEBUG_AFFS
+printf("ghb: %d\n", (*dirh)->blocknum);
+#endif
+ return ERR_FSYS_CORRUPT;
+ }
+ if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT)
+ return ERR_BAD_FILETYPE;
+ while (noCaseStrCmp(name,dirHeader(*dirh)->name,1) != 0)
+ {
+ if (!dirHeader(*dirh)->hashchain)
+ return ERR_FILE_NOT_FOUND;
+ *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashchain));
+ if (calcChkSum(128, (*dirh)->blockbuffer))
+ {
+#ifdef DEBUG_AFFS
+printf("ghb2: %d\n", (*dirh)->blocknum);
+#endif
+ return ERR_FSYS_CORRUPT;
+ }
+ if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT)
+ return ERR_BAD_FILETYPE;
+ }
+ return 0;
+}
+
+static char *copyPart(char *src, char *dst)
+{
+ while ((*src != '/') && (*src))
+ *dst++ = *src++;
+ if (*src == '/')
+ src++;
+ *dst-- = 0;
+ /* cut off spaces at the end */
+ while (*dst == ' ')
+ *dst-- = 0;
+ return src;
+}
+
+static grub_error_t findBlock(char *name, struct CacheBlock **dirh)
+{
+char dname[32];
+int block;
+
+ name++; /* skip "/" */
+ /* partition table part */
+ if (rdbb < RDB_LOCATION_LIMIT)
+ {
+ int bpc;
+
+ blockoffset = 0;
+ *dirh = getBlock(rdbb);
+ if (*name==0)
+ return 0;
+ name = copyPart(name, dname);
+ bpc = AROS_BE2LONG(rdsk(*dirh)->rdb_Sectors)*AROS_BE2LONG(rdsk(*dirh)->rdb_Heads);
+ block = AROS_BE2LONG(rdsk(*dirh)->rdb_PartitionList);
+ while (block != -1)
+ {
+ *dirh = getBlock(block);
+ if (noCaseStrCmp(dname, part(*dirh)->pb_DriveName, 1) == 0)
+ break;
+ block = AROS_BE2LONG(part(*dirh)->pb_Next);
+ }
+ if (block == -1)
+ return ERR_FILE_NOT_FOUND;
+ if (
+ ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFFFFFF00)!=0x444F5300) ||
+ ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFF)==0)
+ )
+ return ERR_BAD_FILETYPE;
+ blockoffset = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_LOWCYL]);
+ rootb = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_HIGHCYL]);
+ rootb = rootb-blockoffset+1; /* highcyl-lowcyl+1 */
+ rootb *= bpc;
+ rootb = rootb-1+AROS_BE2LONG(part(*dirh)->pb_Environment[DE_RESERVEDBLKS]);
+ rootb /= 2;
+ blockoffset *= bpc;
+ }
+
+ /* filesystem part */
+ *dirh = getBlock(rootb);
+ while (*name)
+ {
+ if (
+ (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_ROOT) &&
+ (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_USERDIR)
+ )
+ return ERR_BAD_FILETYPE;
+ name = copyPart(name, dname);
+ errnum = getHeaderBlock(dname, dirh);
+ if (errnum)
+ return errnum;
+ }
+ return 0;
+}
+
+#ifndef STAGE1_5
+static void checkPossibility(char *filename, char *bstr)
+{
+ char cstr[32];
+
+ if (noCaseStrCmp(filename, bstr, 1)<=0)
+ {
+ if (print_possibilities>0)
+ print_possibilities = -print_possibilities;
+ memcpy(cstr, bstr+1, bstr[0]);
+ cstr[bstr[0]]=0;
+ print_a_completion(cstr);
+ }
+}
+#else
+#define checkPossibility(a, b) do { } while(0)
+#endif
+
+int affs_dir(char *dirname)
+{
+ struct CacheBlock *buffer1;
+ struct CacheBlock *buffer2;
+ char *current = dirname;
+ char filename[128];
+ char *fname = filename;
+ int i,block;
+
+ if (print_possibilities)
+ {
+ while (*current)
+ current++;
+ while (*current != '/')
+ current--;
+ current++;
+ while (*current)
+ {
+ *fname++ = *current;
+ *current++ = 0;
+ }
+ *fname=0;
+ errnum = findBlock(dirname, &buffer1);
+ if (errnum)
+ return 0;
+ if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == IDNAME_RIGIDDISK)
+ {
+ block = AROS_BE2LONG(rdsk(buffer1)->rdb_PartitionList);
+ while (block != -1)
+ {
+ buffer1 = getBlock(block);
+ checkPossibility(filename, part(buffer1)->pb_DriveName);
+ block = AROS_BE2LONG(part(buffer1)->pb_Next);
+ }
+#ifndef STAGE1_5
+ if (*filename == 0)
+ if (print_possibilities>0)
+ print_possibilities = -print_possibilities;
+#endif
+ }
+ else if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == T_SHORT)
+ {
+ LockBuffer(buffer1);
+ for (i=0;i<72;i++)
+ {
+ block = dirHeader(buffer1)->hashtable[i];
+ while (block)
+ {
+ buffer2 = getBlock(AROS_BE2LONG(block));
+ if (calcChkSum(128, buffer2->blockbuffer))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ if (AROS_BE2LONG(dirHeader(buffer2)->p_type) != T_SHORT)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ checkPossibility(filename, dirHeader(buffer2)->name);
+ block = dirHeader(buffer2)->hashchain;
+ }
+ }
+ UnLockBuffer(buffer1);
+#ifndef STAGE1_5
+ if (*filename == 0)
+ if (print_possibilities>0)
+ print_possibilities = -print_possibilities;
+#endif
+ }
+ else
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ while (*current != '/')
+ current--;
+ current++;
+ fname = filename;
+ while (*fname)
+ *current++ = *fname++;
+ //#warning "TODO: add some more chars until possibilities differ"
+ if (print_possibilities>0)
+ errnum = ERR_FILE_NOT_FOUND;
+ return (print_possibilities<0);
+ }
+ else
+ {
+ while (*current && !isspace(*current))
+ *fname++ = *current++;
+ *fname = 0;
+
+ errnum = findBlock(filename, &buffer2);
+ if (errnum)
+ return 0;
+ if (AROS_BE2LONG(fileHeader(buffer2)->s_type)!=ST_FILE)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ fsysb->file.header_block = AROS_BE2LONG(fileHeader(buffer2)->own_key);
+ fsysb->file.current.block = AROS_BE2LONG(fileHeader(buffer2)->own_key);
+ fsysb->file.current.filekey = 71;
+ fsysb->file.current.byte = 0;
+ fsysb->file.current.offset = 0;
+ fsysb->file.filesize = AROS_BE2LONG(fileHeader(buffer2)->bytesize);
+ filepos = 0;
+ filemax = fsysb->file.filesize;
+ return 1;
+ }
+}
+#endif
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c b/qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c
new file mode 100644
index 000000000..05425bbd3
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_ext2fs.c
@@ -0,0 +1,794 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_EXT2FS
+
+#include "config.h"
+#include "shared.h"
+#include "filesys.h"
+#include "libc/byteorder.h"
+
+#ifdef CONFIG_DEBUG_EXT2FS
+#define E2DEBUG
+#endif
+
+static int mapblock1, mapblock2;
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE 1024 /* initial block size for superblock read */
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/*
+ * Constants relative to the data blocks, from ext2_fs.h
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/* include/linux/ext2_fs.h */
+struct ext2_super_block
+ {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_pad;
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ __u32 s_reserved[235]; /* Padding to the end of the block */
+ };
+
+struct ext2_group_desc
+ {
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+ };
+
+struct ext2_inode
+ {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Owner Uid */
+ __u32 i_size; /* 4: Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* 12: Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* 20: Deletion Time */
+ __u16 i_gid; /* Group Id */
+ __u16 i_links_count; /* 24: Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* 32: File flags */
+ union
+ {
+ struct
+ {
+ __u32 l_i_reserved1;
+ }
+ linux1;
+ struct
+ {
+ __u32 h_i_translator;
+ }
+ hurd1;
+ struct
+ {
+ __u32 m_i_reserved1;
+ }
+ masix1;
+ }
+ osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ __u32 i_version; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union
+ {
+ struct
+ {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u32 l_i_reserved2[2];
+ }
+ linux2;
+ struct
+ {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ }
+ hurd2;
+ struct
+ {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ }
+ masix2;
+ }
+ osd2; /* OS dependent 2 */
+ };
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/ext2fs.h */
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry
+ {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+ };
+
+/* ext2/super.c */
+#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */
+#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */
+#define PATH_MAX 1024 /* include/linux/limits.h */
+#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+ ((struct ext2_super_block *)(FSYS_BUF))
+#define GROUP_DESC \
+ ((struct ext2_group_desc *) \
+ ((char *)SUPERBLOCK + sizeof(struct ext2_super_block)))
+#define INODE \
+ ((struct ext2_inode *)((char *)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+#define DATABLOCK1 \
+ ((char *)((char *)INODE + sizeof(struct ext2_inode)))
+#define DATABLOCK2 \
+ ((char *)((char *)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+
+/* linux/ext2_fs.h */
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
+
+/* linux/ext2_fs.h */
+#define EXT2_BLOCK_SIZE_BITS(s) (__le32_to_cpu((s)->s_log_block_size) + 10)
+/* kind of from ext2/super.c */
+#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s))
+/* linux/ext2fs.h */
+#define EXT2_DESC_PER_BLOCK(s) \
+ (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+/* linux/stat.h */
+#define S_IFMT 00170000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+
+#ifdef E2DEBUG
+void
+dump_super(struct ext2_super_block *s)
+{
+ printf(" superblock 0x%x:\n", s);
+ printf(" inodes=%d\n", __le32_to_cpu(s->s_inodes_count));
+ printf(" blocks=%d\n", __le32_to_cpu(s->s_blocks_count));
+ printf(" reserved=%d\n", __le32_to_cpu(s->s_r_blocks_count));
+ printf(" i_free=%d\n", __le32_to_cpu(s->s_free_inodes_count));
+ printf(" b_free=%d\n", __le32_to_cpu(s->s_free_blocks_count));
+ printf(" first=%d\n", __le32_to_cpu(s->s_first_data_block));
+ printf(" log_b_size=%d, b_size=%d\n", __le32_to_cpu(s->s_log_block_size), EXT2_BLOCK_SIZE(s));
+ printf(" log_f_size=%d\n", __le32_to_cpu(s->s_log_frag_size));
+ printf(" bpg=%d\n", __le32_to_cpu(s->s_blocks_per_group));
+ printf(" fpg=%d\n", __le32_to_cpu(s->s_frags_per_group));
+ printf(" ipg=%d\n", __le32_to_cpu(s->s_inodes_per_group));
+}
+
+void
+dump_group_desc(struct ext2_group_desc *g)
+{
+ printf(" group_desc 0x%x:\n", g);
+ printf(" b_bmap block=%d\n", __le32_to_cpu(g->bg_block_bitmap));
+ printf(" i_bmap block=%d\n", __le32_to_cpu(g->bg_inode_bitmap));
+ printf(" i_tab block=%d\n", __le32_to_cpu(g->bg_inode_table));
+ printf(" free_blks=%d\n", __le16_to_cpu(g->bg_free_blocks_count));
+ printf(" free_inodes=%d\n", __le16_to_cpu(g->bg_free_inodes_count));
+ printf(" used_dirs=%d\n", __le16_to_cpu(g->bg_used_dirs_count));
+}
+
+void
+dump_inode(struct ext2_inode *i)
+{
+ printf(" inode 0x%x:\n", i);
+ printf(" mode=%o\n", __le16_to_cpu(i->i_mode));
+ printf(" uid=%d\n", __le16_to_cpu(i->i_uid));
+ printf(" gid=%d\n", __le16_to_cpu(i->i_gid));
+ printf(" size=%d\n", __le32_to_cpu(i->i_size));
+ printf(" atime=%d\n", __le32_to_cpu(i->i_atime));
+ printf(" ctime=%d\n", __le32_to_cpu(i->i_ctime));
+ printf(" mtime=%d\n", __le32_to_cpu(i->i_mtime));
+ printf(" dtime=%d\n", __le32_to_cpu(i->i_dtime));
+ printf(" links=%d\n", __le16_to_cpu(i->i_links_count));
+ printf(" blocks=%d\n", __le32_to_cpu(i->i_blocks));
+ printf(" flags=%d\n", __le32_to_cpu(i->i_flags));
+}
+
+void
+dump_inode_data(unsigned char *inode, int len)
+{
+ static char hexdigit[] = "0123456789abcdef";
+ unsigned char *i;
+ for (i = inode;
+ i < (inode + len);
+ i++)
+ {
+ printf ("%c", hexdigit[*i >> 4]);
+ printf ("%c", hexdigit[*i % 16]);
+ if (!((i + 1 - inode) % 16))
+ {
+ printf ("\n");
+ }
+ else
+ {
+ printf (" ");
+ }
+ }
+}
+#endif
+
+/* check filesystem types and read superblock into memory buffer */
+int
+ext2fs_mount (void)
+{
+ int retval = 1;
+
+ if ((((current_drive & 0x80) || (current_slice != 0))
+ && (current_slice != PC_SLICE_TYPE_EXT2FS)
+ && (current_slice != PC_SLICE_TYPE_LINUX_RAID)
+ && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
+ && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
+ || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE))
+ || !devread (SBLOCK, 0, sizeof (struct ext2_super_block),
+ (char *) SUPERBLOCK)
+ || __le16_to_cpu(SUPERBLOCK->s_magic) != EXT2_SUPER_MAGIC)
+ retval = 0;
+
+ return retval;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+ext2_rdfsb (int fsblock, char * buffer)
+{
+#ifdef E2DEBUG
+ printf ("ext2_rdfsb: fsblock %d, devblock %d, size %d\n", fsblock,
+ fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
+ EXT2_BLOCK_SIZE (SUPERBLOCK));
+#endif /* E2DEBUG */
+ return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
+ EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
+}
+
+/* from
+ ext2/inode.c:ext2_bmap()
+*/
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+ a physical block (the location in the file system) via an inode. */
+static int
+ext2fs_block_map (int logical_block)
+{
+
+#ifdef E2DEBUG
+ printf ("ext2fs_block_map(%d)\n", logical_block);
+#endif /* E2DEBUG */
+
+ /* if it is directly pointed to by the inode, return that physical addr */
+ if (logical_block < EXT2_NDIR_BLOCKS)
+ {
+#ifdef E2DEBUG
+ printf ("ext2fs_block_map: returning %d\n", __le32_to_cpu(INODE->i_block[logical_block]));
+#endif /* E2DEBUG */
+ return __le32_to_cpu(INODE->i_block[logical_block]);
+ }
+ /* else */
+ logical_block -= EXT2_NDIR_BLOCKS;
+ /* try the indirect block */
+ if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+ {
+ if (mapblock1 != 1
+ && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_IND_BLOCK]), DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 1;
+ return __le32_to_cpu(((__u32 *) DATABLOCK1)[logical_block]);
+ }
+ /* else */
+ logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
+ /* now try the double indirect block */
+ if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
+ {
+ int bnum;
+ if (mapblock1 != 2
+ && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_DIND_BLOCK]), DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 2;
+ if ((bnum = __le32_to_cpu(((__u32 *) DATABLOCK1)
+ [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
+ != mapblock2
+ && !ext2_rdfsb (bnum, DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock2 = bnum;
+ return __le32_to_cpu(((__u32 *) DATABLOCK2)
+ [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]);
+ }
+ /* else */
+ mapblock2 = -1;
+ logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
+ if (mapblock1 != 3
+ && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_TIND_BLOCK]), DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 3;
+ if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK1)
+ [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
+ * 2)]),
+ DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK2)
+ [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
+ & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]),
+ DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ return __le32_to_cpu(((__u32 *) DATABLOCK2)
+ [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]);
+}
+
+/* preconditions: all preconds of ext2fs_block_map */
+int
+ext2fs_read (char *buf, int len)
+{
+ int logical_block;
+ int offset;
+ int map;
+ int ret = 0;
+ int size = 0;
+
+#ifdef E2DEBUG
+ printf("ext2fs_read(0x%x, %d)\n", buf, len);
+ dump_inode(INODE);
+ dump_inode_data((unsigned char *)INODE, sizeof (struct ext2_inode));
+#endif /* E2DEBUG */
+ while (len > 0)
+ {
+ /* find the (logical) block component of our location */
+ logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+ offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+ map = ext2fs_block_map (logical_block);
+#ifdef E2DEBUG
+ printf ("map=%d\n", map);
+#endif /* E2DEBUG */
+ if (map < 0)
+ break;
+
+ size = EXT2_BLOCK_SIZE (SUPERBLOCK);
+ size -= offset;
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
+ offset, size, buf);
+
+ disk_read_func = NULL;
+
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+
+/* Based on:
+ def_blk_fops points to
+ blkdev_open, which calls (I think):
+ sys_open()
+ do_open()
+ open_namei()
+ dir_namei() which accesses current->fs->root
+ fs->root was set during original mount:
+ (something)... which calls (I think):
+ ext2_read_super()
+ iget()
+ __iget()
+ read_inode()
+ ext2_read_inode()
+ uses desc_per_block_bits, which is set in ext2_read_super()
+ also uses group descriptors loaded during ext2_read_super()
+ lookup()
+ ext2_lookup()
+ ext2_find_entry()
+ ext2_getblk()
+
+*/
+
+/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
+ * known as SUPERBLOCK
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, buffer known as INODE contains the
+ * inode of the file we were trying to look up
+ * side effects: messes up GROUP_DESC buffer area
+ */
+int
+ext2fs_dir (char *dirname)
+{
+ int current_ino = EXT2_ROOT_INO; /* start at the root */
+ int updir_ino = current_ino; /* the parent of the current directory */
+ int group_id; /* which group the inode is in */
+ int group_desc; /* fs pointer to that group */
+ int desc; /* index within that group */
+ int ino_blk; /* fs pointer of the inode's information */
+ int str_chk = 0; /* used to hold the results of a string compare */
+ struct ext2_group_desc *gdp;
+ struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */
+
+ char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
+ int link_count = 0;
+
+ char *rest;
+ char ch; /* temp char holder */
+
+ int off; /* offset within block of directory entry (off mod blocksize) */
+ int loc; /* location within a directory */
+ int blk; /* which data blk within dir entry (off div blocksize) */
+ long map; /* fs pointer of a particular block from dir entry */
+ struct ext2_dir_entry *dp; /* pointer to directory entry */
+
+ /* loop invariants:
+ current_ino = inode to lookup
+ dirname = pointer to filename component we are cur looking up within
+ the directory known pointed to by current_ino (if any)
+ */
+
+#ifdef E2DEBUG
+ printf("****** ext2fs_dir(%s)\n", dirname);
+ dump_super(SUPERBLOCK);
+#endif /* E2DEBUG */
+
+ while (1)
+ {
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: inode %d\n", current_ino);
+ printf ("ext2fs_dir: dirname=%s\n", dirname);
+#endif /* E2DEBUG */
+
+ /* look up an inode */
+ group_id = (current_ino - 1) / __le32_to_cpu(SUPERBLOCK->s_inodes_per_group);
+ group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+ desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: ipg=%d, dpb=%d\n", __le32_to_cpu(SUPERBLOCK->s_inodes_per_group),
+ EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+ printf ("ext2fs_dir: group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
+#endif /* E2DEBUG */
+ if (!ext2_rdfsb (
+ (WHICH_SUPER + group_desc + __le32_to_cpu(SUPERBLOCK->s_first_data_block)),
+ (char*) GROUP_DESC))
+ {
+ return 0;
+ }
+
+#ifdef E2DEBUG
+ dump_group_desc(GROUP_DESC);
+#endif /* E2DEBUG */
+
+ gdp = GROUP_DESC;
+ ino_blk = __le32_to_cpu(gdp[desc].bg_inode_table) +
+ (((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group))
+ >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: itab_blk=%d, i_in_grp=%d, log2=%d\n",
+ __le32_to_cpu(gdp[desc].bg_inode_table),
+ ((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)),
+ log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+ printf ("ext2fs_dir: inode table fsblock=%d\n", ino_blk);
+#endif /* E2DEBUG */
+ if (!ext2_rdfsb (ino_blk, (char *)INODE))
+ {
+ return 0;
+ }
+
+ /* reset indirect blocks! */
+ mapblock2 = mapblock1 = -1;
+
+ raw_inode = INODE +
+ ((current_ino - 1)
+ & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: ipb=%d, sizeof(inode)=%d\n",
+ (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
+ sizeof (struct ext2_inode));
+ printf ("ext2fs_dir: inode=%x, raw_inode=%x\n", INODE, raw_inode);
+ printf ("ext2fs_dir: offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
+ dump_inode(raw_inode);
+ dump_inode_data((unsigned char *)INODE, EXT2_BLOCK_SIZE(SUPERBLOCK));
+ printf ("ext2fs_dir: first word=%x\n", *((int *) raw_inode));
+#endif /* E2DEBUG */
+
+ /* copy inode to fixed location */
+ memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
+
+#ifdef E2DEBUG
+ dump_inode(INODE);
+ printf ("ext2fs_dir: first word=%x\n", *((int *) INODE));
+#endif /* E2DEBUG */
+
+ /* If we've got a symbolic link, then chase it. */
+ if (S_ISLNK (__le16_to_cpu(INODE->i_mode)))
+ {
+ int len;
+ if (++link_count > MAX_LINK_COUNT)
+ {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+
+ /* Find out how long our remaining name is. */
+ len = 0;
+ while (dirname[len] && !isspace (dirname[len]))
+ len++;
+
+ /* Get the symlink size. */
+ filemax = __le32_to_cpu(INODE->i_size);
+ if (filemax + len > sizeof (linkbuf) - 2)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ if (len)
+ {
+ /* Copy the remaining name to the end of the symlink data.
+ Note that DIRNAME and LINKBUF may overlap! */
+ memmove (linkbuf + filemax, dirname, len);
+ }
+ linkbuf[filemax + len] = '\0';
+
+ /* Read the symlink data. */
+ if (__le32_to_cpu(INODE->i_blocks))
+ {
+ /* Read the necessary blocks, and reset the file pointer. */
+ len = file_read (linkbuf, filemax);
+ filepos = 0;
+ if (!len)
+ return 0;
+ }
+ else
+ {
+ /* Copy the data directly from the inode. */
+ len = filemax;
+ memmove (linkbuf, (char *) INODE->i_block, len);
+ }
+
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: symlink=%s\n", linkbuf);
+#endif
+
+ dirname = linkbuf;
+ if (*dirname == '/')
+ {
+ /* It's an absolute link, so look it up in root. */
+ current_ino = EXT2_ROOT_INO;
+ updir_ino = current_ino;
+ }
+ else
+ {
+ /* Relative, so look it up in our parent directory. */
+ current_ino = updir_ino;
+ }
+
+ /* Try again using the new name. */
+ continue;
+ }
+
+ /* if end of filename, INODE points to the file's inode */
+ if (!*dirname || isspace (*dirname))
+ {
+ if (!S_ISREG (__le16_to_cpu(INODE->i_mode)))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filemax = __le32_to_cpu(INODE->i_size);
+ return 1;
+ }
+
+ /* else we have to traverse a directory */
+ updir_ino = current_ino;
+
+ /* skip over slashes */
+ while (*dirname == '/')
+ dirname++;
+
+ /* if this isn't a directory of sufficient size to hold our file, abort */
+ if (!(__le32_to_cpu(INODE->i_size)) || !S_ISDIR (__le16_to_cpu(INODE->i_mode)))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ /* skip to next slash or end of filename (space) */
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+ rest++);
+
+ /* look through this directory and find the next filename component */
+ /* invariant: rest points to slash after the next filename component */
+ *rest = 0;
+ loc = 0;
+
+ do
+ {
+
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
+#endif /* E2DEBUG */
+
+ /* if our location/byte offset into the directory exceeds the size,
+ give up */
+ if (loc >= __le32_to_cpu(INODE->i_size))
+ {
+ if (print_possibilities < 0)
+ {
+# if 0
+ putchar ('\n');
+# endif
+ }
+ else
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ }
+ return (print_possibilities < 0);
+ }
+
+ /* else, find the (logical) block component of our location */
+ blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+
+ /* we know which logical block of the directory entry we are looking
+ for, now we have to translate that to the physical (fs) block on
+ the disk */
+ map = ext2fs_block_map (blk);
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: fs block=%d\n", map);
+#endif /* E2DEBUG */
+ mapblock2 = -1;
+ if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ *rest = ch;
+ return 0;
+ }
+ off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+ dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
+ /* advance loc prematurely to next on-disk directory entry */
+ loc += __le16_to_cpu(dp->rec_len);
+
+ /* NOTE: ext2fs filenames are NOT null-terminated */
+
+#ifdef E2DEBUG
+ printf ("ext2fs_dir: directory entry ino=%d\n", __le32_to_cpu(dp->inode));
+ if (__le32_to_cpu(dp->inode))
+ printf ("entry=%s\n", dp->name);
+#endif /* E2DEBUG */
+
+ if (__le32_to_cpu(dp->inode))
+ {
+ int saved_c = dp->name[dp->name_len];
+
+ dp->name[dp->name_len] = 0;
+ str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/'
+ && (!*dirname || str_chk <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (dp->name);
+ }
+# endif
+
+ dp->name[dp->name_len] = saved_c;
+ }
+
+ }
+ while (!__le32_to_cpu(dp->inode) || (str_chk || (print_possibilities && ch != '/')));
+
+ current_ino = __le32_to_cpu(dp->inode);
+ *(dirname = rest) = ch;
+ }
+ /* never get here */
+}
+
+#endif /* FSYS_EXT2_FS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_fat.c b/qemu/roms/openbios/fs/grubfs/fsys_fat.c
new file mode 100644
index 000000000..a7e160d1d
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_fat.c
@@ -0,0 +1,477 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_FAT
+
+#include "shared.h"
+#include "filesys.h"
+#include "fat.h"
+
+struct fat_superblock
+{
+ int fat_offset;
+ int fat_length;
+ int fat_size;
+ int root_offset;
+ int root_max;
+ int data_offset;
+
+ int num_sectors;
+ int num_clust;
+ int clust_eof_marker;
+ int sects_per_clust;
+ int sectsize_bits;
+ int clustsize_bits;
+ int root_cluster;
+
+ int cached_fat;
+ int file_cluster;
+ int current_cluster_num;
+ int current_cluster;
+};
+
+/* pointer(s) into filesystem info buffer for DOS stuff */
+#define FAT_SUPER ( (struct fat_superblock *) \
+ ( FSYS_BUF + 32256) )/* 512 bytes long */
+#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
+#define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */
+
+#define FAT_CACHE_SIZE 2048
+
+int
+fat_mount (void)
+{
+ struct fat_bpb bpb;
+ __u32 magic, first_fat;
+
+ /* Check partition type for harddisk */
+ if (((current_drive & 0x80) || (current_slice != 0))
+ && ! IS_PC_SLICE_TYPE_FAT (current_slice)
+ && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
+ return 0;
+
+ /* Read bpb */
+ if (! devread (0, 0, sizeof (bpb), (char *) &bpb))
+ return 0;
+
+ /* Check if the number of sectors per cluster is zero here, to avoid
+ zero division. */
+ if (bpb.sects_per_clust == 0)
+ return 0;
+
+ FAT_SUPER->sectsize_bits = log2 (bpb.bytes_per_sect);
+ FAT_SUPER->clustsize_bits
+ = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
+
+ /* Fill in info about super block */
+ FAT_SUPER->num_sectors = bpb.short_sectors
+ ? bpb.short_sectors : bpb.long_sectors;
+
+ /* FAT offset and length */
+ FAT_SUPER->fat_offset = bpb.reserved_sects;
+ FAT_SUPER->fat_length =
+ bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
+
+ /* Rootdir offset and length for FAT12/16 */
+ FAT_SUPER->root_offset =
+ FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
+ FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * bpb.dir_entries;
+
+ /* Data offset and number of clusters */
+ FAT_SUPER->data_offset =
+ FAT_SUPER->root_offset
+ + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
+ FAT_SUPER->num_clust =
+ 2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset)
+ / bpb.sects_per_clust);
+ FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
+
+ if (!bpb.fat_length)
+ {
+ /* This is a FAT32 */
+ if (bpb.dir_entries)
+ return 0;
+
+ if (bpb.flags & 0x0080)
+ {
+ /* FAT mirroring is disabled, get active FAT */
+ int active_fat = bpb.flags & 0x000f;
+ if (active_fat >= bpb.num_fats)
+ return 0;
+ FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
+ }
+
+ FAT_SUPER->fat_size = 8;
+ FAT_SUPER->root_cluster = bpb.root_cluster;
+
+ /* Yes the following is correct. FAT32 should be called FAT28 :) */
+ FAT_SUPER->clust_eof_marker = 0xffffff8;
+ }
+ else
+ {
+ if (!FAT_SUPER->root_max)
+ return 0;
+
+ FAT_SUPER->root_cluster = -1;
+ if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST)
+ {
+ FAT_SUPER->fat_size = 4;
+ FAT_SUPER->clust_eof_marker = 0xfff8;
+ }
+ else
+ {
+ FAT_SUPER->fat_size = 3;
+ FAT_SUPER->clust_eof_marker = 0xff8;
+ }
+ }
+
+
+ /* Now do some sanity checks */
+
+ if (bpb.bytes_per_sect != (1 << FAT_SUPER->sectsize_bits)
+ || bpb.bytes_per_sect != SECTOR_SIZE
+ || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
+ - FAT_SUPER->sectsize_bits))
+ || FAT_SUPER->num_clust <= 2
+ || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
+ > FAT_SUPER->fat_length))
+ return 0;
+
+ /* kbs: Media check on first FAT entry [ported from PUPA] */
+
+ if (!devread(FAT_SUPER->fat_offset, 0,
+ sizeof(first_fat), (char *)&first_fat))
+ return 0;
+
+ if (FAT_SUPER->fat_size == 8)
+ {
+ first_fat &= 0x0fffffff;
+ magic = 0x0fffff00;
+ }
+ else if (FAT_SUPER->fat_size == 4)
+ {
+ first_fat &= 0x0000ffff;
+ magic = 0xff00;
+ }
+ else
+ {
+ first_fat &= 0x00000fff;
+ magic = 0x0f00;
+ }
+
+ if (first_fat != (magic | bpb.media))
+ return 0;
+
+ FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
+ return 1;
+}
+
+int
+fat_read (char *buf, int len)
+{
+ int logical_clust;
+ int offset;
+ int ret = 0;
+ int size;
+
+ if (FAT_SUPER->file_cluster < 0)
+ {
+ /* root directory for fat16 */
+ size = FAT_SUPER->root_max - filepos;
+ if (size > len)
+ size = len;
+ if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
+ return 0;
+ filepos += size;
+ return size;
+ }
+
+ logical_clust = filepos >> FAT_SUPER->clustsize_bits;
+ offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
+ if (logical_clust < FAT_SUPER->current_cluster_num)
+ {
+ FAT_SUPER->current_cluster_num = 0;
+ FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
+ }
+
+ while (len > 0)
+ {
+ int sector;
+ while (logical_clust > FAT_SUPER->current_cluster_num)
+ {
+ /* calculate next cluster */
+ int fat_entry =
+ FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
+ int next_cluster;
+ int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
+
+ if (cached_pos < 0 ||
+ (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
+ {
+ FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
+ cached_pos = (fat_entry - FAT_SUPER->cached_fat);
+ sector = FAT_SUPER->fat_offset
+ + FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
+ if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
+ return 0;
+ }
+ next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
+ if (FAT_SUPER->fat_size == 3)
+ {
+ if (cached_pos & 1)
+ next_cluster >>= 4;
+ next_cluster &= 0xFFF;
+ }
+ else if (FAT_SUPER->fat_size == 4)
+ next_cluster &= 0xFFFF;
+
+ if (next_cluster >= FAT_SUPER->clust_eof_marker)
+ return ret;
+ if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ FAT_SUPER->current_cluster = next_cluster;
+ FAT_SUPER->current_cluster_num++;
+ }
+
+ sector = FAT_SUPER->data_offset +
+ ((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
+ - FAT_SUPER->sectsize_bits));
+ size = (1 << FAT_SUPER->clustsize_bits) - offset;
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ devread(sector, offset, size, buf);
+
+ disk_read_func = NULL;
+
+ len -= size;
+ buf += size;
+ ret += size;
+ filepos += size;
+ logical_clust++;
+ offset = 0;
+ }
+ return errnum ? 0 : ret;
+}
+
+int
+fat_dir (char *dirname)
+{
+ char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
+ char *filename = (char *) NAME_BUF;
+ int attrib = FAT_ATTRIB_DIR;
+#ifndef STAGE1_5
+ int do_possibilities = 0;
+#endif
+
+ /* XXX I18N:
+ * the positions 2,4,6 etc are high bytes of a 16 bit unicode char
+ */
+ static unsigned char longdir_pos[] =
+ { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
+ int slot = -2;
+ int alias_checksum = -1;
+
+ FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
+ filepos = 0;
+ FAT_SUPER->current_cluster_num = MAXINT;
+
+ /* main loop to find desired directory entry */
+ loop:
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (!*dirname || isspace (*dirname))
+ {
+ if (attrib & FAT_ATTRIB_DIR)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* continue with the file/directory name interpretation */
+
+ while (*dirname == '/')
+ dirname++;
+
+ if (!(attrib & FAT_ATTRIB_DIR))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ /* Directories don't have a file size */
+ filemax = MAXINT;
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+
+ *rest = 0;
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/')
+ do_possibilities = 1;
+# endif
+
+ while (1)
+ {
+ if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
+ || dir_buf[0] == 0)
+ {
+ if (!errnum)
+ {
+# ifndef STAGE1_5
+ if (print_possibilities < 0)
+ {
+#if 0
+ putchar ('\n');
+#endif
+ return 1;
+ }
+# endif /* STAGE1_5 */
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ }
+
+ return 0;
+ }
+
+ if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
+ {
+ /* This is a long filename. The filename is build from back
+ * to front and may span multiple entries. To bind these
+ * entries together they all contain the same checksum over
+ * the short alias.
+ *
+ * The id field tells if this is the first entry (the last
+ * part) of the long filename, and also at which offset this
+ * belongs.
+ *
+ * We just write the part of the long filename this entry
+ * describes and continue with the next dir entry.
+ */
+ int i, offset;
+ unsigned char id = FAT_LONGDIR_ID(dir_buf);
+
+ if ((id & 0x40))
+ {
+ id &= 0x3f;
+ slot = id;
+ filename[slot * 13] = 0;
+ alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
+ }
+
+ if (id != slot || slot == 0
+ || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
+ {
+ alias_checksum = -1;
+ continue;
+ }
+
+ slot--;
+ offset = slot * 13;
+
+ for (i=0; i < 13; i++)
+ filename[offset+i] = dir_buf[longdir_pos[i]];
+ continue;
+ }
+
+ if (!FAT_DIRENTRY_VALID (dir_buf))
+ continue;
+
+ if (alias_checksum != -1 && slot == 0)
+ {
+ int i;
+ unsigned char sum;
+
+ slot = -2;
+ for (sum = 0, i = 0; i< 11; i++)
+ sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
+
+ if (sum == alias_checksum)
+ {
+# ifndef STAGE1_5
+ if (do_possibilities)
+ goto print_filename;
+# endif /* STAGE1_5 */
+
+ if (substring (dirname, filename) == 0)
+ break;
+ }
+ }
+
+ /* XXX convert to 8.3 filename format here */
+ {
+ int i, j, c;
+
+ for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
+ && !isspace (c); i++);
+
+ filename[i++] = '.';
+
+ for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
+ && !isspace (c); j++);
+
+ if (j == 0)
+ i--;
+
+ filename[i + j] = 0;
+ }
+
+# ifndef STAGE1_5
+ if (do_possibilities)
+ {
+ print_filename:
+ if (substring (dirname, filename) <= 0)
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (filename);
+ }
+ continue;
+ }
+# endif /* STAGE1_5 */
+
+ if (substring (dirname, filename) == 0)
+ break;
+ }
+
+ *(dirname = rest) = ch;
+
+ attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
+ filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
+ filepos = 0;
+ FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
+ FAT_SUPER->current_cluster_num = MAXINT;
+
+ /* go back to main loop at top of function */
+ goto loop;
+}
+
+#endif /* FSYS_FAT */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_ffs.c b/qemu/roms/openbios/fs/grubfs/fsys_ffs.c
new file mode 100644
index 000000000..c6804b8ba
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_ffs.c
@@ -0,0 +1,311 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+/*
+ * Elements of this file were originally from the FreeBSD "biosboot"
+ * bootloader file "disk.c" dated 4/12/95.
+ *
+ * The license and header comments from that file are included here.
+ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
+ * $Id: fsys_ffs.c,v 1.10 2001/11/12 06:57:29 okuji Exp $
+ */
+
+#ifdef FSYS_FFS
+
+#include "shared.h"
+
+#include "filesys.h"
+
+#include "defs.h"
+#include "disk_inode.h"
+#include "disk_inode_ffs.h"
+#include "dir.h"
+#include "fs.h"
+
+/* used for filesystem map blocks */
+static int mapblock;
+static int mapblock_offset;
+static int mapblock_bsize;
+
+/* pointer to superblock */
+#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 ))
+#define INODE ((struct icommon *) ( FSYS_BUF + 16384 ))
+#define MAPBUF ( FSYS_BUF + 24576 )
+#define MAPBUF_LEN 8192
+
+
+int
+ffs_mount (void)
+{
+ int retval = 1;
+
+ if ((((current_drive & 0x80) || (current_slice != 0))
+ && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_BSDFFS))
+ || part_length < (SBLOCK + (SBSIZE / DEV_BSIZE))
+ || !devread (SBLOCK, 0, SBSIZE, (char *) SUPERBLOCK)
+ || SUPERBLOCK->fs_magic != FS_MAGIC)
+ retval = 0;
+
+ mapblock = -1;
+ mapblock_offset = -1;
+
+ return retval;
+}
+
+static int
+block_map (int file_block)
+{
+ int bnum, offset, bsize;
+
+ if (file_block < NDADDR)
+ return (INODE->i_db[file_block]);
+
+ /* If the blockmap loaded does not include FILE_BLOCK,
+ load a new blockmap. */
+ if ((bnum = fsbtodb (SUPERBLOCK, INODE->i_ib[0])) != mapblock
+ || (mapblock_offset <= bnum && bnum <= mapblock_offset + mapblock_bsize))
+ {
+ if (MAPBUF_LEN < SUPERBLOCK->fs_bsize)
+ {
+ offset = ((file_block - NDADDR) % NINDIR (SUPERBLOCK));
+ bsize = MAPBUF_LEN;
+
+ if (offset + MAPBUF_LEN > SUPERBLOCK->fs_bsize)
+ offset = (SUPERBLOCK->fs_bsize - MAPBUF_LEN) / sizeof (int);
+ }
+ else
+ {
+ bsize = SUPERBLOCK->fs_bsize;
+ offset = 0;
+ }
+
+ if (! devread (bnum, offset * sizeof (int), bsize, (char *) MAPBUF))
+ {
+ mapblock = -1;
+ mapblock_bsize = -1;
+ mapblock_offset = -1;
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+
+ mapblock = bnum;
+ mapblock_bsize = bsize;
+ mapblock_offset = offset;
+ }
+
+ return (((int *) MAPBUF)[((file_block - NDADDR) % NINDIR (SUPERBLOCK))
+ - mapblock_offset]);
+}
+
+
+int
+ffs_read (char *buf, int len)
+{
+ int logno, off, size, map, ret = 0;
+
+ while (len && !errnum)
+ {
+ off = blkoff (SUPERBLOCK, filepos);
+ logno = lblkno (SUPERBLOCK, filepos);
+ size = blksize (SUPERBLOCK, INODE, logno);
+
+ if ((map = block_map (logno)) < 0)
+ break;
+
+ size -= off;
+
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ devread (fsbtodb (SUPERBLOCK, map), off, size, buf);
+
+ disk_read_func = NULL;
+
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+
+int
+ffs_dir (char *dirname)
+{
+ char *rest, ch;
+ int block, off, loc, map, ino = ROOTINO;
+ struct direct *dp;
+
+/* main loop to find destination inode */
+loop:
+
+ /* load current inode (defaults to the root inode) */
+
+ if (!devread (fsbtodb (SUPERBLOCK, itod (SUPERBLOCK, ino)),
+ ino % (SUPERBLOCK->fs_inopb) * sizeof (struct dinode),
+ sizeof (struct dinode), (char *) INODE))
+ return 0; /* XXX what return value? */
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (!*dirname || isspace (*dirname))
+ {
+ if ((INODE->i_mode & IFMT) != IFREG)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filemax = INODE->i_size;
+
+ /* incomplete implementation requires this! */
+ fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize;
+ return 1;
+ }
+
+ /* continue with file/directory name interpretation */
+
+ while (*dirname == '/')
+ dirname++;
+
+ if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+
+ *rest = 0;
+ loc = 0;
+
+ /* loop for reading a the entries in a directory */
+
+ do
+ {
+ if (loc >= INODE->i_size)
+ {
+#if 0
+ putchar ('\n');
+#endif
+
+ if (print_possibilities < 0)
+ return 1;
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+ }
+
+ if (!(off = blkoff (SUPERBLOCK, loc)))
+ {
+ block = lblkno (SUPERBLOCK, loc);
+
+ if ((map = block_map (block)) < 0
+ || !devread (fsbtodb (SUPERBLOCK, map), 0,
+ blksize (SUPERBLOCK, INODE, block),
+ (char *) FSYS_BUF))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ *rest = ch;
+ return 0;
+ }
+ }
+
+ dp = (struct direct *) (FSYS_BUF + off);
+ loc += dp->d_reclen;
+
+#ifndef STAGE1_5
+ if (dp->d_ino && print_possibilities && ch != '/'
+ && (!*dirname || substring (dirname, dp->d_name) <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+
+ print_a_completion (dp->d_name);
+ }
+#endif /* STAGE1_5 */
+ }
+ while (!dp->d_ino || (substring (dirname, dp->d_name) != 0
+ || (print_possibilities && ch != '/')));
+
+ /* only get here if we have a matching directory entry */
+
+ ino = dp->d_ino;
+ *(dirname = rest) = ch;
+
+ /* go back to main loop at top of function */
+ goto loop;
+}
+
+int
+ffs_embed (int *start_sector, int needed_sectors)
+{
+ /* XXX: I don't know if this is really correct. Someone who is
+ familiar with BSD should check for this. */
+ if (needed_sectors > 14)
+ return 0;
+
+ *start_sector = 1;
+#if 1
+ /* FIXME: Disable the embedding in FFS until someone checks if
+ the code above is correct. */
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+#endif /* FSYS_FFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_iso9660.c b/qemu/roms/openbios/fs/grubfs/fsys_iso9660.c
new file mode 100644
index 000000000..12f94b734
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_iso9660.c
@@ -0,0 +1,342 @@
+/*
+ * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
+ * including Rock Ridge Extensions support
+ *
+ * Copyright (C) 1998, 1999 Kousuke Takai <tak@kmc.kyoto-u.ac.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+/*
+ * References:
+ * linux/fs/isofs/rock.[ch]
+ * mkisofs-1.11.1/diag/isoinfo.c
+ * mkisofs-1.11.1/iso9660.h
+ * (all are written by Eric Youngdale)
+ *
+ * Modifications by:
+ * Leonid Lisovskiy <lly@pisem.net> 2003
+ */
+
+/*
+ * Modified to make it work with FILO
+ * 2003-10 by SONE Takeshi
+ */
+
+#ifdef FSYS_ISO9660
+
+#include "shared.h"
+#include "filesys.h"
+#include "iso9660.h"
+#include "debug.h"
+
+#if defined(__sparc__) || defined(__PPC__)
+#define ENDIAN b
+#else
+#define ENDIAN l
+#endif
+
+struct iso_superblock {
+ unsigned long vol_sector;
+
+ unsigned long file_start;
+};
+
+#define ISO_SUPER ((struct iso_superblock *)(FSYS_BUF))
+#define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048))
+#define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096))
+#define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144))
+#define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192))
+
+static int
+iso9660_devread (int sector, int byte_offset, int byte_len, char *buf)
+{
+ /* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte
+ * CD-ROM sector */
+ return devread(sector<<2, byte_offset, byte_len, buf);
+}
+
+int
+iso9660_mount (void)
+{
+ unsigned int sector;
+
+ /*
+ * Because there is no defined slice type ID for ISO-9660 filesystem,
+ * this test will pass only either (1) if entire disk is used, or
+ * (2) if current partition is BSD style sub-partition whose ID is
+ * ISO-9660.
+ */
+ /*if ((current_partition != 0xFFFFFF)
+ && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660))
+ return 0;*/
+
+ /*
+ * Currently, only FIRST session of MultiSession disks are supported !!!
+ */
+ for (sector = 16 ; sector < 32 ; sector++)
+ {
+ if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC))
+ break;
+ /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */
+ if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0')
+ && CHECK2(PRIMDESC->id + 3, '0', '1'))
+ {
+ ISO_SUPER->vol_sector = sector;
+ ISO_SUPER->file_start = 0;
+ fsmax = PRIMDESC->volume_space_size.ENDIAN;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+iso9660_dir (char *dirname)
+{
+ struct iso_directory_record *idr;
+ RR_ptr_t rr_ptr;
+ struct rock_ridge *ce_ptr;
+ unsigned int pathlen;
+ int size;
+ unsigned int extent;
+ unsigned int rr_len;
+ unsigned char file_type;
+ unsigned char rr_flag;
+
+ idr = &PRIMDESC->root_directory_record;
+ ISO_SUPER->file_start = 0;
+
+ do
+ {
+ while (*dirname == '/') /* skip leading slashes */
+ dirname++;
+ /* pathlen = strcspn(dirname, "/\n\t "); */
+ for (pathlen = 0 ;
+ dirname[pathlen]
+ && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ;
+ pathlen++)
+ ;
+
+ size = idr->size.ENDIAN;
+ extent = idr->extent.ENDIAN;
+
+ while (size > 0)
+ {
+ if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ extent++;
+
+ idr = (struct iso_directory_record *)DIRREC;
+ for (; idr->length.ENDIAN > 0;
+ idr = (struct iso_directory_record *)((char *)idr + idr->length.ENDIAN) )
+ {
+ const char *name = (char *)idr->name;
+ unsigned int name_len = idr->name_len.ENDIAN;
+
+ file_type = (idr->flags.ENDIAN & 2) ? ISO_DIRECTORY : ISO_REGULAR;
+ if (name_len == 1)
+ {
+ if ((name[0] == 0) || /* self */
+ (name[0] == 1)) /* parent */
+ continue;
+ }
+ if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1'))
+ {
+ name_len -= 2; /* truncate trailing file version */
+ if (name_len > 1 && name[name_len - 1] == '.')
+ name_len--; /* truncate trailing dot */
+ }
+
+ /*
+ * Parse Rock-Ridge extension
+ */
+ rr_len = (idr->length.ENDIAN - idr->name_len.ENDIAN
+ - (unsigned char)sizeof(struct iso_directory_record)
+ + (unsigned char)sizeof(idr->name));
+ rr_ptr.ptr = ((char *)idr + idr->name_len.ENDIAN
+ + sizeof(struct iso_directory_record)
+ - sizeof(idr->name));
+ if (rr_len & 1)
+ rr_ptr.ptr++, rr_len--;
+ ce_ptr = NULL;
+ rr_flag = RR_FLAG_NM | RR_FLAG_PX;
+
+ while (rr_len >= 4)
+ {
+ if (rr_ptr.rr->version != 1)
+ {
+#ifndef STAGE1_5
+ if (debug)
+ printf(
+ "Non-supported version (%d) RockRidge chunk "
+ "`%c%c'\n", rr_ptr.rr->version,
+ rr_ptr.rr->signature & 0xFF,
+ rr_ptr.rr->signature >> 8);
+#endif
+ }
+ else if (CHECK2(&rr_ptr.rr->signature, 'R', 'R')
+ && rr_ptr.rr->len >= 5)
+ rr_flag &= rr_ptr.rr->u.rr.flags.ENDIAN;
+ else if (CHECK2(&rr_ptr.rr->signature, 'N', 'M'))
+ {
+ name = (char *)rr_ptr.rr->u.nm.name;
+ name_len = rr_ptr.rr->len - 5;
+ rr_flag &= ~RR_FLAG_NM;
+ }
+ else if (CHECK2(&rr_ptr.rr->signature, 'P', 'X')
+ && rr_ptr.rr->len >= 36)
+ {
+ file_type = ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT)
+ == POSIX_S_IFREG
+ ? ISO_REGULAR
+ : ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT)
+ == POSIX_S_IFDIR
+ ? ISO_DIRECTORY : ISO_OTHER));
+ rr_flag &= ~RR_FLAG_PX;
+ }
+ else if (CHECK2(&rr_ptr.rr->signature, 'C', 'E')
+ && rr_ptr.rr->len >= 28)
+ ce_ptr = rr_ptr.rr;
+ if (!rr_flag)
+ /*
+ * There is no more extension we expects...
+ */
+ break;
+ rr_len -= rr_ptr.rr->len;
+ rr_ptr.ptr += rr_ptr.rr->len;
+ if (rr_len < 4 && ce_ptr != NULL)
+ {
+ /* preserve name before loading new extent. */
+ if( RRCONT_BUF <= (unsigned char *)name
+ && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE )
+ {
+ memcpy(NAME_BUF, name, name_len);
+ name = (char *)NAME_BUF;
+ }
+ rr_ptr.ptr = (char *)(RRCONT_BUF + ce_ptr->u.ce.offset.ENDIAN);
+ rr_len = ce_ptr->u.ce.size.ENDIAN;
+ if (!iso9660_devread(ce_ptr->u.ce.extent.ENDIAN, 0,
+ ISO_SECTOR_SIZE, (char *)RRCONT_BUF))
+ {
+ errnum = 0; /* this is not fatal. */
+ break;
+ }
+ ce_ptr = NULL;
+ }
+ } /* rr_len >= 4 */
+
+ filemax = MAXINT;
+ if (name_len >= pathlen
+ && !strnicmp(name, dirname, pathlen))
+ {
+ if (dirname[pathlen] == '/' || !print_possibilities)
+ {
+ /*
+ * DIRNAME is directory component of pathname,
+ * or we are to open a file.
+ */
+ if (pathlen == name_len)
+ {
+ if (dirname[pathlen] == '/')
+ {
+ if (file_type != ISO_DIRECTORY)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ goto next_dir_level;
+ }
+ if (file_type != ISO_REGULAR)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ ISO_SUPER->file_start = idr->extent.ENDIAN;
+ filepos = 0;
+ filemax = idr->size.ENDIAN;
+ return 1;
+ }
+ }
+ else /* Completion */
+ {
+#ifndef STAGE1_5
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ memcpy(NAME_BUF, name, name_len);
+ NAME_BUF[name_len] = '\0';
+ print_a_completion (NAME_BUF);
+#endif
+ }
+ }
+ } /* for */
+
+ size -= ISO_SECTOR_SIZE;
+ } /* size>0 */
+
+ if (dirname[pathlen] == '/' || print_possibilities >= 0)
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+
+next_dir_level:
+ dirname += pathlen;
+
+ } while (*dirname == '/');
+
+ return 1;
+}
+
+int
+iso9660_read (char *buf, int len)
+{
+ int sector, blkoffset, size, ret;
+
+ if (ISO_SUPER->file_start == 0)
+ return 0;
+
+ ret = 0;
+ blkoffset = filepos & (ISO_SECTOR_SIZE - 1);
+ sector = filepos >> ISO_SECTOR_BITS;
+ while (len > 0)
+ {
+ size = ISO_SECTOR_SIZE - blkoffset;
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf))
+ return 0;
+
+ disk_read_func = NULL;
+
+ len -= size;
+ buf += size;
+ ret += size;
+ filepos += size;
+ sector++;
+ blkoffset = 0;
+ }
+
+ return ret;
+}
+
+#endif /* FSYS_ISO9660 */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_jfs.c b/qemu/roms/openbios/fs/grubfs/fsys_jfs.c
new file mode 100644
index 000000000..66469e686
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_jfs.c
@@ -0,0 +1,404 @@
+/* fsys_jfs.c - an implementation for the IBM JFS file system */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2001,2002 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_JFS
+
+#include "shared.h"
+#include "filesys.h"
+#include "jfs.h"
+
+#define MAX_LINK_COUNT 8
+
+#define DTTYPE_INLINE 0
+#define DTTYPE_PAGE 1
+
+struct jfs_info
+{
+ int bsize;
+ int l2bsize;
+ int bdlog;
+ int xindex;
+ int xlastindex;
+ int sindex;
+ int slastindex;
+ int de_index;
+ int dttype;
+ xad_t *xad;
+ ldtentry_t *de;
+};
+
+static struct jfs_info jfs;
+
+#define xtpage ((xtpage_t *)FSYS_BUF)
+#define dtpage ((dtpage_t *)((char *)FSYS_BUF + 4096))
+#define fileset ((dinode_t *)((char *)FSYS_BUF + 8192))
+#define inode ((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t)))
+#define dtroot ((dtroot_t *)(&inode->di_btroot))
+
+static ldtentry_t de_always[2] = {
+ {1, -1, 2, {'.', '.'}, 0},
+ {1, -1, 1, {'.'}, 0}
+};
+
+static int
+isinxt (s64 key, s64 offset, s64 len)
+{
+ return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
+}
+
+static xad_t *
+first_extent (dinode_t *di)
+{
+ xtpage_t *xtp;
+
+ jfs.xindex = 2;
+ xtp = (xtpage_t *)&di->di_btroot;
+ jfs.xad = &xtp->xad[2];
+ if (xtp->header.flag & BT_LEAF) {
+ jfs.xlastindex = xtp->header.nextindex;
+ } else {
+ do {
+ devread (addressXAD (jfs.xad) << jfs.bdlog, 0,
+ sizeof(xtpage_t), (char *)xtpage);
+ jfs.xad = &xtpage->xad[2];
+ } while (!(xtpage->header.flag & BT_LEAF));
+ jfs.xlastindex = xtpage->header.nextindex;
+ }
+
+ return jfs.xad;
+}
+
+static xad_t *
+next_extent (void)
+{
+ if (++jfs.xindex < jfs.xlastindex) {
+ } else if (xtpage->header.next) {
+ devread (xtpage->header.next << jfs.bdlog, 0,
+ sizeof(xtpage_t), (char *)xtpage);
+ jfs.xlastindex = xtpage->header.nextindex;
+ jfs.xindex = XTENTRYSTART;
+ jfs.xad = &xtpage->xad[XTENTRYSTART];
+ } else {
+ return NULL;
+ }
+ return ++jfs.xad;
+}
+
+
+static void
+di_read (u32 inum, dinode_t *di)
+{
+ s64 key;
+ u32 xd, ioffset;
+ s64 offset;
+ xad_t *xad;
+ pxd_t pxd;
+
+ key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize;
+ xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT;
+ ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE;
+ xad = first_extent (fileset);
+ do {
+ offset = offsetXAD (xad);
+ if (isinxt (key, offset, lengthXAD (xad))) {
+ devread ((addressXAD (xad) + key - offset) << jfs.bdlog,
+ 3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd);
+ devread (addressPXD (&pxd) << jfs.bdlog,
+ ioffset, DISIZE, (char *)di);
+ break;
+ }
+ } while ((xad = next_extent ()));
+}
+
+static ldtentry_t *
+next_dentry (void)
+{
+ ldtentry_t *de;
+ s8 *stbl;
+
+ if (jfs.dttype == DTTYPE_INLINE) {
+ if (jfs.sindex < jfs.slastindex) {
+ return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]];
+ }
+ } else {
+ de = (ldtentry_t *)dtpage->slot;
+ stbl = (s8 *)&de[(int)dtpage->header.stblindex];
+ if (jfs.sindex < jfs.slastindex) {
+ return &de[(int)stbl[jfs.sindex++]];
+ } else if (dtpage->header.next) {
+ devread (dtpage->header.next << jfs.bdlog, 0,
+ sizeof(dtpage_t), (char *)dtpage);
+ jfs.slastindex = dtpage->header.nextindex;
+ jfs.sindex = 1;
+ return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]];
+ }
+ }
+
+ return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL;
+}
+
+static ldtentry_t *
+first_dentry (void)
+{
+ dtroot_t *dtr;
+ pxd_t *xd;
+ idtentry_t *de;
+
+ dtr = (dtroot_t *)&inode->di_btroot;
+ jfs.sindex = 0;
+ jfs.de_index = 0;
+
+ de_always[0].inumber = inode->di_parent;
+ de_always[1].inumber = inode->di_number;
+ if (dtr->header.flag & BT_LEAF) {
+ jfs.dttype = DTTYPE_INLINE;
+ jfs.slastindex = dtr->header.nextindex;
+ } else {
+ de = (idtentry_t *)dtpage->slot;
+ jfs.dttype = DTTYPE_PAGE;
+ xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd;
+ for (;;) {
+ devread (addressPXD (xd) << jfs.bdlog, 0,
+ sizeof(dtpage_t), (char *)dtpage);
+ if (dtpage->header.flag & BT_LEAF)
+ break;
+ xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd;
+ }
+ jfs.slastindex = dtpage->header.nextindex;
+ }
+
+ return next_dentry ();
+}
+
+
+static dtslot_t *
+next_dslot (int next)
+{
+ return (jfs.dttype == DTTYPE_INLINE)
+ ? (dtslot_t *)&dtroot->slot[next]
+ : &((dtslot_t *)dtpage->slot)[next];
+}
+
+static void
+uni2ansi (UniChar *uni, char *ansi, int len)
+{
+ for (; len; len--, uni++)
+ *ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni;
+}
+
+int
+jfs_mount (void)
+{
+ struct jfs_superblock super;
+
+ if (part_length < MINJFS >> SECTOR_BITS
+ || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
+ sizeof(struct jfs_superblock), (char *)&super)
+ || (super.s_magic != JFS_MAGIC)
+ || !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I,
+ 0, DISIZE, (char*)fileset)) {
+ return 0;
+ }
+
+ jfs.bsize = super.s_bsize;
+ jfs.l2bsize = super.s_l2bsize;
+ jfs.bdlog = jfs.l2bsize - SECTOR_BITS;
+
+ return 1;
+}
+
+int
+jfs_read (char *buf, int len)
+{
+ xad_t *xad;
+ s64 endofprev, endofcur;
+ s64 offset, xadlen;
+ int toread, startpos, endpos;
+
+ startpos = filepos;
+ endpos = filepos + len;
+ endofprev = (1ULL << 62) - 1;
+ xad = first_extent (inode);
+ do {
+ offset = offsetXAD (xad);
+ xadlen = lengthXAD (xad);
+ if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) {
+ endofcur = (offset + xadlen) << jfs.l2bsize;
+ toread = (endofcur >= endpos)
+ ? len : (endofcur - filepos);
+
+ disk_read_func = disk_read_hook;
+ devread (addressXAD (xad) << jfs.bdlog,
+ filepos - (offset << jfs.l2bsize), toread, buf);
+ disk_read_func = NULL;
+
+ buf += toread;
+ len -= toread;
+ filepos += toread;
+ } else if (offset > endofprev) {
+ toread = ((offset << jfs.l2bsize) >= endpos)
+ ? len : ((offset - endofprev) << jfs.l2bsize);
+ len -= toread;
+ filepos += toread;
+ for (; toread; toread--) {
+ *buf++ = 0;
+ }
+ continue;
+ }
+ endofprev = offset + xadlen;
+ xad = next_extent ();
+ } while (len > 0 && xad);
+
+ return filepos - startpos;
+}
+
+int
+jfs_dir (char *dirname)
+{
+ char *ptr, *rest, ch;
+ ldtentry_t *de;
+ dtslot_t *ds;
+ u32 inum, parent_inum;
+ s64 di_size;
+ u32 di_mode;
+ int namlen, cmp, n, link_count;
+ char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX];
+
+ parent_inum = inum = ROOT_I;
+ link_count = 0;
+ for (;;) {
+ di_read (inum, inode);
+ di_size = inode->di_size;
+ di_mode = inode->di_mode;
+
+ if ((di_mode & IFMT) == IFLNK) {
+ if (++link_count > MAX_LINK_COUNT) {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+ if (di_size < (di_mode & INLINEEA ? 256 : 128)) {
+ grub_memmove (linkbuf, inode->di_fastsymlink, di_size);
+ n = di_size;
+ } else if (di_size < JFS_PATH_MAX - 1) {
+ filepos = 0;
+ filemax = di_size;
+ n = jfs_read (linkbuf, filemax);
+ } else {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum;
+ while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++));
+ linkbuf[n] = 0;
+ dirname = linkbuf;
+ continue;
+ }
+
+ if (!*dirname || isspace (*dirname)) {
+ if ((di_mode & IFMT) != IFREG) {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ filepos = 0;
+ filemax = di_size;
+ return 1;
+ }
+
+ if ((di_mode & IFMT) != IFDIR) {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ for (; *dirname == '/'; dirname++);
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+ *rest = 0;
+
+ de = first_dentry ();
+ for (;;) {
+ namlen = de->namlen;
+ if (de->next == -1) {
+ uni2ansi (de->name, namebuf, namlen);
+ namebuf[namlen] = 0;
+ } else {
+ uni2ansi (de->name, namebuf, DTLHDRDATALEN);
+ ptr = namebuf;
+ ptr += DTLHDRDATALEN;
+ namlen -= DTLHDRDATALEN;
+ ds = next_dslot (de->next);
+ while (ds->next != -1) {
+ uni2ansi (ds->name, ptr, DTSLOTDATALEN);
+ ptr += DTSLOTDATALEN;
+ namlen -= DTSLOTDATALEN;
+ ds = next_dslot (ds->next);
+ }
+ uni2ansi (ds->name, ptr, namlen);
+ ptr += namlen;
+ *ptr = 0;
+ }
+
+ cmp = (!*dirname) ? -1 : substring (dirname, namebuf);
+#ifndef STAGE1_5
+ if (print_possibilities && ch != '/'
+ && cmp <= 0) {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (namebuf);
+ } else
+#endif
+ if (cmp == 0) {
+ parent_inum = inum;
+ inum = de->inumber;
+ *(dirname = rest) = ch;
+ break;
+ }
+ de = next_dentry ();
+ if (de == NULL) {
+ if (print_possibilities < 0)
+ return 1;
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+ }
+ }
+ }
+}
+
+int
+jfs_embed (int *start_sector, int needed_sectors)
+{
+ struct jfs_superblock super;
+
+ if (needed_sectors > 63
+ || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
+ sizeof (struct jfs_superblock),
+ (char *)&super)
+ || (super.s_magic != JFS_MAGIC)) {
+ return 0;
+ }
+
+ *start_sector = 1;
+ return 1;
+}
+
+#endif /* FSYS_JFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_minix.c b/qemu/roms/openbios/fs/grubfs/fsys_minix.c
new file mode 100644
index 000000000..d16b58c87
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_minix.c
@@ -0,0 +1,535 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+/* Restrictions:
+ This is MINIX V1 only (yet)
+ Disk creation is like:
+ mkfs.minix -c DEVICE
+*/
+
+#ifdef FSYS_MINIX
+
+#include "shared.h"
+#include "filesys.h"
+
+/* #define DEBUG_MINIX */
+
+/* indirect blocks */
+static int mapblock1, mapblock2, namelen;
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c (is OK for minix) */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
+
+/* include/asm-i386/type.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/* include/linux/minix_fs.h */
+#define MINIX_ROOT_INO 1
+
+/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
+#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX 65530
+
+#define MINIX_I_MAP_SLOTS 8
+#define MINIX_Z_MAP_SLOTS 64
+#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS 0x0001 /* Clean fs. */
+#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+#define MINIX_V1 0x0001 /* original minix fs */
+#define MINIX_V2 0x0002 /* minix V2 fs */
+
+/* originally this is :
+#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
+ here we have */
+#define INODE_VERSION(inode) (SUPERBLOCK->s_version)
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+ __u16 i_mode;
+ __u16 i_uid;
+ __u32 i_size;
+ __u32 i_time;
+ __u8 i_gid;
+ __u8 i_nlinks;
+ __u16 i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+ __u16 i_mode;
+ __u16 i_nlinks;
+ __u16 i_uid;
+ __u16 i_gid;
+ __u32 i_size;
+ __u32 i_atime;
+ __u32 i_mtime;
+ __u32 i_ctime;
+ __u32 i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+ __u16 s_ninodes;
+ __u16 s_nzones;
+ __u16 s_imap_blocks;
+ __u16 s_zmap_blocks;
+ __u16 s_firstdatazone;
+ __u16 s_log_zone_size;
+ __u32 s_max_size;
+ __u16 s_magic;
+ __u16 s_state;
+ __u32 s_zones;
+};
+
+struct minix_dir_entry {
+ __u16 inode;
+ char name[0];
+};
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+ ((struct minix_super_block *)(FSYS_BUF))
+#define INODE \
+ ((struct minix_inode *)((char *) SUPERBLOCK + BLOCK_SIZE))
+#define DATABLOCK1 \
+ ((char *)((char *)INODE + sizeof(struct minix_inode)))
+#define DATABLOCK2 \
+ ((char *)((char *)DATABLOCK1 + BLOCK_SIZE))
+
+/* linux/stat.h */
+#define S_IFMT 00170000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+
+#define PATH_MAX 1024 /* include/linux/limits.h */
+#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
+
+/* check filesystem types and read superblock into memory buffer */
+int
+minix_mount (void)
+{
+ if (((current_drive & 0x80) || current_slice != 0)
+ && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
+ && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
+ return 0; /* The partition is not of MINIX type */
+
+ if (part_length < (SBLOCK +
+ (sizeof (struct minix_super_block) / DEV_BSIZE)))
+ return 0; /* The partition is too short */
+
+ if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
+ (char *) SUPERBLOCK))
+ return 0; /* Cannot read superblock */
+
+ switch (SUPERBLOCK->s_magic)
+ {
+ case MINIX_SUPER_MAGIC:
+ namelen = 14;
+ break;
+ case MINIX_SUPER_MAGIC2:
+ namelen = 30;
+ break;
+ default:
+ return 0; /* Unsupported type */
+ }
+
+ return 1;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+minix_rdfsb (int fsblock, char *buffer)
+{
+ return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
+ BLOCK_SIZE, buffer);
+}
+
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+ a physical block (the location in the file system) via an inode. */
+static int
+minix_block_map (int logical_block)
+{
+ int i;
+
+ if (logical_block < 7)
+ return INODE->i_zone[logical_block];
+
+ logical_block -= 7;
+ if (logical_block < 512)
+ {
+ i = INODE->i_zone[7];
+
+ if (!i || ((mapblock1 != 1)
+ && !minix_rdfsb (i, DATABLOCK1)))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 1;
+ return ((__u16 *) DATABLOCK1) [logical_block];
+ }
+
+ logical_block -= 512;
+ i = INODE->i_zone[8];
+ if (!i || ((mapblock1 != 2)
+ && !minix_rdfsb (i, DATABLOCK1)))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 2;
+ i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
+ if (!i || ((mapblock2 != i)
+ && !minix_rdfsb (i, DATABLOCK2)))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock2 = i;
+ return ((__u16 *) DATABLOCK2)[logical_block & 511];
+}
+
+/* read from INODE into BUF */
+int
+minix_read (char *buf, int len)
+{
+ int logical_block;
+ int offset;
+ int map;
+ int ret = 0;
+ int size = 0;
+
+ while (len > 0)
+ {
+ /* find the (logical) block component of our location */
+ logical_block = filepos >> BLOCK_SIZE_BITS;
+ offset = filepos & (BLOCK_SIZE - 1);
+ map = minix_block_map (logical_block);
+#ifdef DEBUG_MINIX
+ printf ("map=%d\n", map);
+#endif
+ if (map < 0)
+ break;
+
+ size = BLOCK_SIZE;
+ size -= offset;
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ devread (map * (BLOCK_SIZE / DEV_BSIZE),
+ offset, size, buf);
+
+ disk_read_func = NULL;
+
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+/* preconditions: minix_mount already executed, therefore supblk in buffer
+ known as SUPERBLOCK
+ returns: 0 if error, nonzero iff we were able to find the file successfully
+ postconditions: on a nonzero return, buffer known as INODE contains the
+ inode of the file we were trying to look up
+ side effects: none yet */
+int
+minix_dir (char *dirname)
+{
+ int current_ino = MINIX_ROOT_INO; /* start at the root */
+ int updir_ino = current_ino; /* the parent of the current directory */
+ int ino_blk; /* fs pointer of the inode's info */
+
+ int str_chk = 0; /* used ot hold the results of a string
+ compare */
+
+ struct minix_inode * raw_inode; /* inode info for current_ino */
+
+ char linkbuf[PATH_MAX]; /* buffer for following sym-links */
+ int link_count = 0;
+
+ char * rest;
+ char ch;
+
+ int off; /* offset within block of directory
+ entry */
+ int loc; /* location within a directory */
+ int blk; /* which data blk within dir entry */
+ long map; /* fs pointer of a particular block from
+ dir entry */
+ struct minix_dir_entry * dp; /* pointer to directory entry */
+
+ /* loop invariants:
+ current_ino = inode to lookup
+ dirname = pointer to filename component we are cur looking up within
+ the directory known pointed to by current_ino (if any) */
+
+#ifdef DEBUG_MINIX
+ printf ("\n");
+#endif
+
+ while (1)
+ {
+#ifdef DEBUG_MINIX
+ printf ("inode %d, dirname %s\n", current_ino, dirname);
+#endif
+
+ ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
+ + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
+ if (! minix_rdfsb (ino_blk, (char *) INODE))
+ return 0;
+
+ /* reset indirect blocks! */
+ mapblock2 = mapblock1 = -1;
+
+ raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
+
+ /* copy inode to fixed location */
+ memmove ((void *) INODE, (void *) raw_inode,
+ sizeof (struct minix_inode));
+
+ /* If we've got a symbolic link, then chase it. */
+ if (S_ISLNK (INODE->i_mode))
+ {
+ int len;
+
+ if (++link_count > MAX_LINK_COUNT)
+ {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+#ifdef DEBUG_MINIX
+ printf ("S_ISLNK (%s)\n", dirname);
+#endif
+
+ /* Find out how long our remaining name is. */
+ len = 0;
+ while (dirname[len] && !isspace (dirname[len]))
+ len++;
+
+ /* Get the symlink size. */
+ filemax = (INODE->i_size);
+ if (filemax + len > sizeof (linkbuf) - 2)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ if (len)
+ {
+ /* Copy the remaining name to the end of the symlink data.
+ Note that DIRNAME and LINKBUF may overlap! */
+ memmove (linkbuf + filemax, dirname, len);
+ }
+ linkbuf[filemax + len] = '\0';
+
+ /* Read the necessary blocks, and reset the file pointer. */
+ len = grub_read (linkbuf, filemax);
+ filepos = 0;
+ if (!len)
+ return 0;
+
+#ifdef DEBUG_MINIX
+ printf ("symlink=%s\n", linkbuf);
+#endif
+
+ dirname = linkbuf;
+ if (*dirname == '/')
+ {
+ /* It's an absolute link, so look it up in root. */
+ current_ino = MINIX_ROOT_INO;
+ updir_ino = current_ino;
+ }
+ else
+ {
+ /* Relative, so look it up in our parent directory. */
+ current_ino = updir_ino;
+ }
+
+ /* Try again using the new name. */
+ continue;
+ }
+
+ /* If end of filename, INODE points to the file's inode */
+ if (!*dirname || isspace (*dirname))
+ {
+ if (!S_ISREG (INODE->i_mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filemax = (INODE->i_size);
+ return 1;
+ }
+
+ /* else we have to traverse a directory */
+ updir_ino = current_ino;
+
+ /* skip over slashes */
+ while (*dirname == '/')
+ dirname++;
+
+ /* if this isn't a directory of sufficient size to hold our file,
+ abort */
+ if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ /* skip to next slash or end of filename (space) */
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+ rest++);
+
+ /* look through this directory and find the next filename component */
+ /* invariant: rest points to slash after the next filename component */
+ *rest = 0;
+ loc = 0;
+
+ do
+ {
+#ifdef DEBUG_MINIX
+ printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
+#endif
+
+ /* if our location/byte offset into the directory exceeds the size,
+ give up */
+ if (loc >= INODE->i_size)
+ {
+ if (print_possibilities < 0)
+ {
+#if 0
+ putchar ('\n');
+#endif
+ }
+ else
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ }
+ return (print_possibilities < 0);
+ }
+
+ /* else, find the (logical) block component of our location */
+ blk = loc >> BLOCK_SIZE_BITS;
+
+ /* we know which logical block of the directory entry we are looking
+ for, now we have to translate that to the physical (fs) block on
+ the disk */
+ map = minix_block_map (blk);
+#ifdef DEBUG_MINIX
+ printf ("fs block=%d\n", map);
+#endif
+ mapblock2 = -1;
+ if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ *rest = ch;
+ return 0;
+ }
+ off = loc & (BLOCK_SIZE - 1);
+ dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
+ /* advance loc prematurely to next on-disk directory entry */
+ loc += sizeof (dp->inode) + namelen;
+
+ /* NOTE: minix filenames are NULL terminated if < NAMELEN
+ else exact */
+
+#ifdef DEBUG_MINIX
+ printf ("directory entry ino=%d\n", dp->inode);
+ if (dp->inode)
+ printf ("entry=%s\n", dp->name);
+#endif
+
+ if (dp->inode)
+ {
+ int saved_c = dp->name[namelen];
+
+ dp->name[namelen] = 0;
+ str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/'
+ && (!*dirname || str_chk <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (dp->name);
+ }
+# endif
+
+ dp->name[namelen] = saved_c;
+ }
+
+ }
+ while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
+
+ current_ino = dp->inode;
+ *(dirname = rest) = ch;
+ }
+ /* never get here */
+}
+
+#endif /* FSYS_MINIX */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_ntfs.c b/qemu/roms/openbios/fs/grubfs/fsys_ntfs.c
new file mode 100644
index 000000000..a244f5c6b
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_ntfs.c
@@ -0,0 +1,1255 @@
+/* vim: set sw=4 :*/
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+/*
+ * Samuel Leo <samuel@_.remove.me._szonline.net>
+ * Limitations:
+ * 1. Only 32 bit size support
+ * 2. don't support >1k MFT record size, >16k INDEX record size
+ * 3. don't support recursive at_attribute_list
+ * 4. don't support compressed attribute other than Datastream
+ * 5. all MFT's at_attribute_list must resident at first run list
+ * 6. don't support journaling
+ * 7. don't support EFS encryption
+ * 8. don't support mount point and junction
+ */
+#ifdef FSYS_NTFS
+
+//#define DEBUG_NTFS 1
+
+/*
+#define NO_ATTRIBUTE_LIST 1
+ totally disable at_attribute_list support,
+ if no compressed/fragment file and MFT,
+ not recommended
+#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1
+ disable non-resident at_attribute_list support,
+ if no huge compressed/fragment file and MFT
+#define NO_NTFS_DECOMPRESSION 1
+ disable ntfs compressed file support
+#define NO_ALTERNATE_DATASTREAM 1
+ disable ntfs alternate datastream support
+*/
+
+#include "shared.h"
+#include "filesys.h"
+
+#ifdef STAGE1_5
+/* safe turn off non-resident attribute list if MFT fragments < 4000 */
+//#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1
+#define NO_NTFS_DECOMPRESSION 1
+#endif
+
+#define MAX_MFT_RECORD_SIZE 1024
+#define MAX_INDEX_RECORD_SIZE 16384
+#define MAX_INDEX_BITMAP_SIZE 4096
+#define DECOMP_DEST_BUFFER_SIZE 16384
+#define DECOMP_SOURCE_BUFFER_SIZE (8192+2)
+#define MAX_DIR_DEPTH 64
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE 512
+
+#define WHICH_SUPER 1
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
+
+/* include/asm-i386/type.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+
+#define FILE_MFT 0
+#define FILE_MFTMIRR 1
+#define FILE_LOGFILE 2
+#define FILE_VOLUME 3
+#define FILE_ATTRDEF 4
+#define FILE_ROOT 5
+#define FILE_BITMAP 6
+#define FILE_BOOT 7
+#define FILE_BADCLUS 8
+#define FILE_QUOTA 9
+#define FILE_UPCASE 10
+
+#define at_standard_information 0x10
+#define at_attribute_list 0x20
+#define at_filename 0x30
+#define at_security_descriptor 0x50
+#define at_data 0x80
+#define at_index_root 0x90
+#define at_index_allocation 0xa0
+#define at_bitmap 0xb0
+#define at_symlink 0xc0
+
+#define NONAME ""
+#define ATTR_NORMAL 0
+#define ATTR_COMPRESSED 1
+#define ATTR_RESIDENT 2
+#define ATTR_ENCRYPTED 16384
+#define ATTR_SPARSE 32768
+
+typedef struct run_list {
+ char *start;
+ char *ptr;
+ int svcn;
+ int evcn;
+ int vcn;
+ int cnum0;
+ int cnum;
+ int clen;
+} RUNL;
+
+typedef struct ntfs_mft_record {
+ char mft[MAX_MFT_RECORD_SIZE];
+ char mft2[MAX_MFT_RECORD_SIZE];
+ int attr_type;
+ char *attr_name;
+ int attr_flag;
+ int attr_size;
+ char *attr;
+ int attr_len;
+ RUNL runl;
+ char *attr_list;
+ int attr_list_len;
+ int attr_list_size;
+ int attr_list_off;
+ int attr_inited;
+ char attr_list_buf[2*BLOCK_SIZE];
+ RUNL attr_list_runl;
+} MFTR;
+
+
+#define index_data ((char *)FSYS_BUF)
+#define bitmap_data ((__u8 *)(FSYS_BUF+MAX_INDEX_RECORD_SIZE))
+#define dcdbuf ((__u8 *)index_data)
+#define dcsbuf (bitmap_data)
+#define dcend (dcsbuf+DECOMP_SOURCE_BUFFER_SIZE)
+#define fnbuf ((char *)(bitmap_data+MAX_INDEX_BITMAP_SIZE))
+#define mmft ((MFTR *)dcend)
+#define cmft ((MFTR *)(dcend+sizeof(MFTR)))
+#define mft_run ((RUNL *)(dcend+2*sizeof(MFTR)))
+#define path_ino ((int *)(dcend+2*sizeof(MFTR)+sizeof(RUNL)))
+#define cluster16 (path_ino+MAX_DIR_DEPTH)
+#define index16 cluster16[16]
+#define blocksize cluster16[17]
+#define clustersize cluster16[18]
+#define mft_record_size cluster16[19]
+#define index_record_size cluster16[20]
+#define dcvcn cluster16[21]
+#define dcoff cluster16[22]
+#define dclen cluster16[23]
+#define dcrem cluster16[24]
+#define dcslen cluster16[25]
+#define dcsptr ((__u8 *)cluster16[26])
+#define is_ads_completion cluster16[27]
+
+static int read_mft_record(int mftno, char *mft, int self);
+static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl);
+static int get_next_run(RUNL *runl);
+
+static inline int
+nsubstring (char *s1, char *s2)
+{
+ while (tolower(*s1) == tolower(*s2))
+ {
+ /* The strings match exactly. */
+ if (! *(s1++))
+ return 0;
+ s2 ++;
+ }
+
+ /* S1 is a substring of S2. */
+ if (*s1 == 0)
+ return -1;
+
+ /* S1 isn't a substring. */
+ return 1;
+}
+
+static int fixup_record(char *record, char *magic, int size)
+{
+ int start, count, offset;
+ __u16 fixup;
+
+ if(*(int *)record != *(int *)magic)
+ return 0;
+ start=*(__u16 *)(record+4);
+ count=*(__u16 *)(record+6);
+ count--;
+ if(size && blocksize*count != size)
+ return 0;
+ fixup = *(__u16 *)(record+start);
+ start+=2;
+ offset=blocksize-2;
+ while(count--){
+ if(*(__u16 *)(record+offset)!=fixup)
+ return 0;
+ *(__u16 *)(record+offset) = *(__u16 *)(record+start);
+ start+=2;
+ offset+=blocksize;
+ }
+ return 1;
+}
+
+static void rewind_run_list( RUNL *runl) {
+ runl->vcn = runl->svcn;
+ runl->ptr = runl->start;
+ runl->cnum0 = 0;
+ runl->cnum = 0;
+ runl->clen = 0;
+}
+
+static int get_next_run(RUNL *runl){
+ int t, n, v;
+
+#ifdef DEBUG_NTFS
+ printf("get_next_run: s=%d e=%d c=%d start=%x ptr=%x\n",
+ runl->svcn, runl->evcn, runl->vcn, runl->start, runl->ptr);
+#endif
+
+ runl->vcn += runl->clen;
+ if(runl->vcn > runl->evcn) {
+ return 0;
+ }
+
+ t = *(runl->ptr)++;
+ n = t&0xf;
+ runl->clen = 0; v = 1;
+ while(n--) {
+ runl->clen += v * *((__u8 *)runl->ptr)++;
+ v <<= 8;
+ }
+ n = (t>>4)&0xf;
+ if(n==0)
+ runl->cnum = 0;
+ else {
+ int c = 0;
+ v = 1;
+ while(n--) {
+ c += v * *((__u8 *)runl->ptr)++;
+ v <<= 8;
+ }
+ if(c & (v>>1)) c -= v;
+ runl->cnum0 += c;
+ runl->cnum = runl->cnum0;
+ }
+#ifdef DEBUG_NTFS
+ printf("got_next_run: t=%x cluster %x len %x vcn=%x ecn=%x\n",
+ t, runl->cnum, runl->clen, runl->vcn, runl->evcn);
+#endif
+ return 1;
+}
+
+#ifndef NO_ATTRIBUTE_LIST
+static void init_run_list(char *attr, int len, RUNL *runl, __u32 *initp) {
+ int allocated;
+
+ runl->svcn = *(__u32 *)(attr+0x10); /* only support 32 bit */
+ runl->evcn = *(__u32 *)(attr+0x18); /* only support 32 bit */
+ runl->start = attr + *(__u16 *)(attr+0x20);
+ allocated = *(__u32 *)(attr+0x28);
+ if(initp) *initp = *(__u32 *)(attr+0x38);
+ if(!runl->evcn) runl->evcn = (allocated - 1) / clustersize;
+#ifdef DEBUG_NTFS
+ printf("size %d allocated=%d inited=%d cegin=%x csize=%d vcn=%d-%d\n",
+ /*attr_size*/ *(__u32 *)(attr+0x30),
+ /*allocated*/ *(__u32 *)(attr+0x28),
+ /*attr_inited*/ *(__u32 *)(attr+0x38),
+ /*cengin*/ *(__u16 *)(attr+0x22),
+ /*csize*/ *(__u16 *)(attr+0x40),
+ runl->svcn, runl->evcn);
+#endif
+ rewind_run_list(runl);
+}
+#endif
+
+
+static int find_attribute(char *mft, int type, char *name, char **attr, int *size, int *len, int *flag) {
+ int t, l, r, n, i, namelen;
+ unsigned short *attr_name;
+
+ n = strlen(name);
+ r = mft_record_size - *(__u16 *)(mft+0x14);
+ mft += *(__u16 *)(mft+0x14);
+ while( (t = *(__s32 *)mft) != -1 ) {
+ l = *(__u32 *)(mft+4);
+ if(l>r) break;
+#ifdef DEBUG_NTFS
+ printf("type = %x len = %d namelen=%d resident=%d compresed=%d attrno=%d\n",
+ t, l,
+ /*namelen*/ *(mft+9),
+ //name = (__u16 *)(mft + *(__u16 *)(mft+10)),
+ /*resident */ (*(mft+8) == 0),
+ /*compressed*/ *(__u16 *)(mft+12),
+ /*attrno*/ *(__u16 *)(mft+14));
+#endif
+ namelen = *(mft+9);
+ if(t == type) {
+#ifndef STAGE1_5
+#ifndef NO_ALTERNATE_DATASTREAM
+ if(is_ads_completion && type == at_data) {
+ if(namelen && namelen >= n &&
+ (!*(mft+8)/*resident*/ || !*(__u32 *)(attr+0x10)/*svcn==0*/))
+ {
+ for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i < n; i++)
+ if(tolower(name[i]) != tolower(attr_name[i]))
+ break;
+ if(i >= n) {
+ for(; i < namelen; i++)
+ name[i] = attr_name[i];
+ name[i] = '\0';
+ if(print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion(fnbuf);
+ name[n] = '\0';
+ }
+ }
+ } else
+#endif
+#endif
+ if(namelen == n) {
+
+ for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i<n; i++)
+ if(tolower(name[i]) != tolower(attr_name[i]))
+ break;
+ if(i>=n) {
+ if(flag) *flag = *(__u16 *)(mft+12);
+ if(*(mft+8) == 0) {
+ if(flag) *flag |= ATTR_RESIDENT;
+#ifdef DEBUG_NTFS
+ printf("resident data at %x size %x indexed=%d\n",
+ /*data*/ *(__u16 *)(mft+0x14),
+ /*attr_size*/ *(__u16 *)(mft+0x10),
+ /*indexed*/ *(__u16 *)(mft+0x16));
+#endif
+ if(attr) *attr = mft + *(__u16 *)(mft+0x14);
+ if(size) *size = *(__u16 *)(mft+0x10);
+ if(len) *len = *(__u16 *)(mft+0x10);
+ } else {
+ if(attr) *attr = mft;
+ if(size) *size = *(__u32 *)(mft+0x30);
+ if(len) *len = l;
+ }
+ return 1;
+ }
+ }
+ }
+ mft += l;
+ r -= l;
+ }
+ return 0;
+}
+
+#ifndef NO_ATTRIBUTE_LIST
+static __u32 get_next_attribute_list(MFTR *mftr, int *size) {
+ int l, t, mftno;
+#ifdef DEBUG_NTFS
+ printf("get_next_attribute_list: type=%x\n",mftr->attr_type);
+#endif
+again:
+ while(mftr->attr_list_len>0x14) {
+ t = *(__u32 *)(mftr->attr_list + 0);
+ l = *(__u16 *)(mftr->attr_list + 4);
+#ifdef DEBUG_NTFS
+ printf("attr_list type=%x len=%x remain=%x\n", t, l, mftr->attr_list_len);
+#endif
+ if(l==0 || l>mftr->attr_list_len) return 0;
+ mftno = *(__u32 *)(mftr->attr_list + 0x10);
+ mftr->attr_list_len -= l;
+ mftr->attr_list += l;
+ if(t==mftr->attr_type)
+ {
+#ifdef DEBUG_NTFS
+ printf("attr_list mftno=%x\n", mftno);
+#endif
+ if(read_mft_record(mftno, mftr->mft2, (mftr==mmft))==0)
+ break;
+ if(find_attribute(mftr->mft2, mftr->attr_type, mftr->attr_name,
+ &mftr->attr, size, &mftr->attr_len, &mftr->attr_flag))
+ return 1;
+ }
+ }
+#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST
+ if(mftr->attr_list_off < mftr->attr_list_size) {
+ int len = mftr->attr_list_size - mftr->attr_list_off;
+ if(len > BLOCK_SIZE) len = BLOCK_SIZE;
+
+ if(mftr->attr_list_len)
+ memmove(mftr->attr_list_buf, mftr->attr_list, mftr->attr_list_len);
+ mftr->attr_list = mftr->attr_list_buf;
+
+ if(read_attribute( NULL, mftr->attr_list_off,
+ mftr->attr_list_buf + mftr->attr_list_len,
+ len, &mftr->attr_list_runl) != len)
+ {
+#ifdef DEBUG_NTFS
+ printf("CORRUPT NON-RESIDENT ATTRIBUTE_LIST\n");
+#endif
+ /* corrupt */
+ errnum = ERR_FSYS_CORRUPT;
+ mftr->attr_list_size = 0;
+ mftr->attr_len = 0;
+ mftr->attr_list = NULL;
+ return 0;
+ }
+
+ mftr->attr_list_len += len;
+ mftr->attr_list_off += len;
+ goto again;
+ }
+#endif
+ mftr->attr_list = NULL;
+ return 0;
+}
+#endif
+
+static int search_attribute( MFTR *mftr, int type, char *name)
+{
+#ifdef DEBUG_NTFS
+ printf("searching attribute %x <%s>\n", type, name);
+#endif
+
+ mftr->attr_type = type;
+ mftr->attr_name = name;
+ mftr->attr_list = NULL;
+ mftr->attr_list_len = 0;
+ mftr->attr_list_size = 0;
+ mftr->attr_list_off = 0;
+ dcrem = dclen = 0;
+
+#ifndef NO_ATTRIBUTE_LIST
+ if(find_attribute(mftr->mft, at_attribute_list, NONAME,
+ &mftr->attr_list, &mftr->attr_list_size,
+ &mftr->attr_list_len, &mftr->attr_list_off)) {
+ if(mftr->attr_list_off&ATTR_RESIDENT) {
+ /* resident at_attribute_list */
+ mftr->attr_list_size = 0;
+#ifdef DEBUG_NTFS
+ printf("resident attribute_list len=%x\n", mftr->attr_list_len);
+#endif
+ } else {
+#ifdef DEBUG_NTFS
+ printf("non-resident attribute_list len=%x size=%x\n",
+ mftr->attr_list_len, mftr->attr_list_size);
+#endif
+#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST
+ init_run_list(mftr->attr_list, mftr->attr_list_len, &mftr->attr_list_runl, NULL);
+ if(get_next_run(&mftr->attr_list_runl)==0 ||
+ mftr->attr_list_runl.cnum==0)
+ mftr->attr_list_size = 0;
+#endif
+ mftr->attr_list = NULL;
+ mftr->attr_list_len = 0;
+ }
+ }
+#endif
+
+ if(find_attribute(mftr->mft, type, name,
+ &mftr->attr, &mftr->attr_size, &mftr->attr_len,
+ &mftr->attr_flag)
+#ifndef NO_ATTRIBUTE_LIST
+ || get_next_attribute_list(mftr, &mftr->attr_size)
+#endif
+ )
+ {
+#ifndef NO_ATTRIBUTE_LIST
+ if(!(mftr->attr_flag&ATTR_RESIDENT)){
+ init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, &mftr->attr_inited);
+ if(mftr->attr_inited > mftr->attr_size)
+ mftr->attr_inited = mftr->attr_size;
+ if(get_next_run(&mftr->runl)==0) {
+ mftr->attr_flag |= ATTR_RESIDENT;
+ mftr->attr_len = 0;
+ }
+ } else
+ mftr->attr_inited = mftr->attr_size;
+#endif
+
+ return 1;
+ }
+
+ mftr->attr_type = 0;
+ return 0;
+}
+
+static int get_run( RUNL *rl, int vcn, int *clp, int *lenp) {
+ if(rl->evcn < vcn)
+ return 0;
+
+ if(rl->vcn > vcn) {
+ rewind_run_list(rl);
+ get_next_run(rl);
+ }
+
+ while(rl->vcn+rl->clen <= vcn)
+ {
+ if(get_next_run(rl)==0)
+ return 0;
+ }
+
+ if(clp) *clp = rl->cnum == 0 ? 0 : rl->cnum + vcn - rl->vcn;
+ if(lenp) *lenp = rl->clen - vcn + rl->vcn;
+ return 1;
+}
+
+static int search_run(MFTR *mftr, int vcn) {
+
+ if( mftr->attr==NULL && !search_attribute(mftr, mftr->attr_type, mftr->attr_name))
+ return 0;
+
+ if(mftr->runl.svcn > vcn)
+ search_attribute(mftr, mftr->attr_type, mftr->attr_name);
+
+#ifdef NO_ATTRIBUTE_LIST
+ if(mftr->runl.evcn < vcn)
+ return 0;
+#else
+ while(mftr->runl.evcn < vcn) {
+ if(get_next_attribute_list(mftr, NULL)==0) {
+ mftr->attr = NULL;
+ return 0;
+ }
+ init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, NULL);
+ if(get_next_run(&mftr->runl)==0) {
+ mftr->attr = NULL;
+ return 0;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl) {
+ int vcn;
+ int cnum, clen;
+ int done = 0;
+ int n;
+ RUNL *rl;
+
+ if(!from_rl && (mftr->attr_flag & ATTR_RESIDENT)) {
+ /* resident attribute */
+ if(offset > mftr->attr_len)
+ return 0;
+ if(offset+len > mftr->attr_len)
+ len = mftr->attr_len - offset;
+ memmove( buf, mftr->attr + offset, len);
+ return len;
+ }
+
+ vcn = offset / clustersize;
+ offset %= clustersize;
+
+ while(len>0) {
+ if(from_rl)
+ rl = from_rl;
+ else if(search_run(mftr, vcn) == 0)
+ break;
+ else
+ rl = &mftr->runl;
+ if(get_run(rl, vcn, &cnum, &clen) == 0)
+ break;
+ if(cnum==0 && from_rl)
+ break;
+ n = clen * clustersize - offset;
+ if(n > len) n = len;
+ if(cnum==0) {
+ memset( buf, 0, n);
+ } else if(!devread(cnum*(clustersize>>9)+(offset>>9), offset&0x1ff, n, buf))
+ break;
+
+ buf += n;
+ vcn += (offset+n)/clustersize;
+ done += n;
+ offset = 0;
+ len -= n;
+ }
+ return done;
+}
+
+static int read_mft_record(int mftno, char *mft, int self){
+#ifdef DEBUG_NTFS
+ printf("Reading MFT record: mftno=%d\n", mftno);
+#endif
+ if( read_attribute( mmft, mftno * mft_record_size,
+ mft, mft_record_size, self?mft_run:NULL) != mft_record_size)
+ return 0;
+ if(!fixup_record( mft, "FILE", mft_record_size))
+ return 0;
+ return 1;
+}
+
+#ifndef NO_NTFS_DECOMPRESSION
+static int get_16_cluster(MFTR *mftr, int vcn) {
+ int n = 0, cnum, clen;
+ while(n < 16 && search_run(mftr, vcn) && get_run(&mftr->runl, vcn, &cnum, &clen) && cnum) {
+ if(clen > 16 - n)
+ clen = 16 - n;
+ vcn += clen;
+ while(clen--)
+ cluster16[n++] = cnum++;
+ }
+ cluster16[n] = 0;
+ return n;
+}
+
+static inline int compressed_block_size( unsigned char *src ) {
+ return 3 + (*(__u16 *)src & 0xfff);
+}
+
+static int decompress_block(unsigned char *dest, unsigned char *src) {
+ int head;
+ int copied=0;
+ unsigned char *last;
+ int bits;
+ int tag=0;
+
+ /* high bit indicates that compression was performed */
+ if(!(*(__u16 *)src & 0x8000)) {
+ memmove(dest,src+2,0x1000);
+ return 0x1000;
+ }
+
+ if((head = *(__u16 *)src & 0xFFF)==0)
+ /* block is not used */
+ return 0;
+
+ src += 2;
+ last = src+head;
+ bits = 0;
+
+ while(src<=last)
+ {
+ if(copied>4096)
+ {
+#ifdef DEBUG_NTFS
+ printf("decompress error 1\n");
+#endif
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ if(!bits){
+ tag=*(__u8 *)src;
+ bits=8;
+ src++;
+ if(src>last)
+ break;
+ }
+ if(tag & 1){
+ int i,len,delta,code,lmask,dshift;
+ code = *(__u16 *)src;
+ src+=2;
+ if(!copied)
+ {
+#ifdef DEBUG_NTFS
+ printf("decompress error 2\n");
+#endif
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ for(i=copied-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1)
+ {
+ lmask >>= 1;
+ dshift--;
+ }
+ delta = code >> dshift;
+ len = (code & lmask) + 3;
+ for(i=0; i<len; i++)
+ {
+ dest[copied]=dest[copied-delta-1];
+ copied++;
+ }
+ } else
+ dest[copied++]=*(__u8 *)src++;
+ tag>>=1;
+ bits--;
+ }
+
+ return copied;
+}
+#endif
+
+int ntfs_read(char *buf, int len){
+ int ret;
+#ifdef STAGE1_5
+/* stage2 can't be resident/compressed/encrypted files,
+ * but does sparse flag, cause stage2 never sparsed
+ */
+ if((cmft->attr_flag&~ATTR_SPARSE) != ATTR_NORMAL)
+ return 0;
+ disk_read_func = disk_read_hook;
+ ret = read_attribute(cmft, filepos, buf, len, 0);
+ disk_read_func = NULL;
+ filepos += ret;
+#else
+
+#ifndef NO_NTFS_DECOMPRESSION
+ int off;
+ int vcn;
+ int size;
+ int len0;
+#endif
+
+ if(len<=0 || filepos >= cmft->attr_size || (cmft->attr_flag&ATTR_ENCRYPTED))
+ return 0;
+
+ if(filepos+len > cmft->attr_size)
+ len = cmft->attr_size - filepos;
+ if(filepos >= cmft->attr_inited) {
+#ifdef DEBUG_NTFS
+printf("reading uninitialized data 1\n");
+#endif
+ memset(buf, 0, len);
+ return len;
+ } else if(filepos+len > cmft->attr_inited) {
+ len0 = len;
+ len = cmft->attr_inited - filepos;
+ len0 -= len;
+ } else
+ len0 = 0;
+#ifdef DEBUG_NTFS
+printf("read filepos=%x filemax=%x inited=%x len=%x len0=%x\n",filepos,filemax,cmft->attr_inited,len,len0);
+#endif
+
+ if((cmft->attr_flag&(ATTR_COMPRESSED|ATTR_RESIDENT)) != ATTR_COMPRESSED) {
+ if(cmft->attr_flag==ATTR_NORMAL)
+ disk_read_func = disk_read_hook;
+ ret = read_attribute(cmft, filepos, buf, len, 0);
+ if(cmft->attr_flag==ATTR_NORMAL)
+ disk_read_func = NULL;
+ filepos += ret;
+ if(ret==len && len0) {
+ memset(buf+len, 0, len0);
+ filepos += len0;
+ ret += len0;
+ }
+ return ret;
+ }
+
+ ret = 0;
+
+#ifndef NO_NTFS_DECOMPRESSION
+ /* NTFS don't support compression if cluster size > 4k */
+ if(clustersize > 4096) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ while(len > 0){
+#ifdef DEBUG_NTFS
+printf("Reading filepos=%x len=%x\n", filepos, len);
+#endif
+ if(filepos >= dcoff && filepos < (dcoff+dclen)) {
+#ifdef DEBUG_NTFS
+printf("decompress cache %x+%x\n", dcoff, dclen);
+#endif
+ size = dcoff + dclen - filepos;
+ if(size > len) size = len;
+ memmove( buf, dcdbuf + filepos - dcoff, size);
+ filepos += size;
+ len -= size;
+ ret += size;
+ buf += size;
+ if(len==0) {
+ if(len0) {
+#ifdef DEBUG_NTFS
+printf("reading uninitialized data 2\n");
+#endif
+ memset(buf, 0, len0);
+ filepos += len0;
+ ret += len0;
+ }
+ return ret;
+ }
+ }
+
+ vcn = filepos / clustersize / 16;
+ vcn *= 16;
+ off = filepos % (16 * clustersize);
+ if( dcvcn != vcn || filepos < dcoff)
+ dcrem = 0;
+
+#ifdef DEBUG_NTFS
+printf("vcn %x off %x dcrem %x\n", vcn, off, dcrem);
+#endif
+ if(dcrem) {
+ int head;
+
+ /* reading source */
+ if(dcslen < 2 || compressed_block_size(dcsptr) > dcslen) {
+ if(cluster16[index16]==0) {
+ errnum = ERR_FSYS_CORRUPT;
+ return ret;
+ }
+ if(dcslen)
+ memmove(dcsbuf, dcsptr, dcslen);
+ dcsptr = dcsbuf;
+ while((dcslen+clustersize) < DECOMP_SOURCE_BUFFER_SIZE) {
+ if(cluster16[index16]==0)
+ break;
+#ifdef DEBUG_NTFS
+printf("reading dcslen=%x cluster %x\n", dcslen, cluster16[index16]);
+#endif
+ if(!devread(cluster16[index16]*(clustersize>>9), 0, clustersize, dcsbuf+dcslen))
+ return ret;
+ dcslen += clustersize;
+ index16++;
+ }
+ }
+ /* flush destination */
+ dcoff += dclen;
+ dclen = 0;
+
+ while(dcrem && dclen < DECOMP_DEST_BUFFER_SIZE &&
+ dcslen >= 2 && (head=compressed_block_size(dcsptr)) <= dcslen) {
+ size = decompress_block(dcdbuf+dclen, dcsptr);
+ if(dcrem>=0x1000 && size!=0x1000) {
+ errnum = ERR_FSYS_CORRUPT;
+ return ret;
+ }
+ dcrem -= size;
+ dclen += size;
+ dcsptr += head;
+ dcslen -= head;
+ }
+ continue;
+ }
+ dclen = dcrem = 0;
+#ifdef DEBUG_NTFS
+printf("get next 16 clusters\n");
+#endif
+ switch(get_16_cluster(cmft, vcn)) {
+ case 0:
+#ifdef DEBUG_NTFS
+printf("sparse\n");
+#endif
+ /* sparse */
+ size = 16 * clustersize - off;
+ if( len < size )
+ size = len;
+#ifndef STAGE1_5
+ memset( buf, 0, size);
+#endif
+ filepos += size;
+ len -= size;
+ ret += size;
+ buf += size;
+ break;
+
+ case 16:
+#ifdef DEBUG_NTFS
+printf("uncompressed\n");
+#endif
+ /* uncompressed */
+ index16 = off / clustersize;
+ off %= clustersize;
+ while(index16 < 16) {
+ size = clustersize - off;
+ if( len < size )
+ size = len;
+ if(!devread(cluster16[index16]*(clustersize>>9)+(off>>9), off&0x1ff, size, buf))
+ return ret;
+ filepos += size;
+ len -= size;
+ ret += size;
+ if(len==0)
+ return ret;
+ off = 0;
+ buf += size;
+ index16++;
+ }
+ break;
+
+ default:
+#ifdef DEBUG_NTFS
+printf("compressed\n");
+#endif
+ index16 = 0;
+ dcvcn = vcn;
+ dcoff = vcn * clustersize;
+ dcrem = cmft->attr_inited - dcoff;
+ if(dcrem > 16 * clustersize)
+ dcrem = 16 * clustersize;
+ dcsptr = dcsbuf;
+ dcslen = 0;
+ }
+ }
+ if(len0) {
+#ifdef DEBUG_NTFS
+printf("reading uninitialized data 3\n");
+#endif
+ memset(buf, 0, len0);
+ filepos += len0;
+ ret += len0;
+ }
+#else
+ errnum = FSYS_CORRUPT;
+#endif /*NO_NTFS_DECOMPRESSION*/
+#endif /*STAGE1_5*/
+ return ret;
+}
+
+int ntfs_mount (void)
+{
+ char *sb = (char *)FSYS_BUF;
+ int mft_record;
+ int spc;
+
+ if (((current_drive & 0x80) || (current_slice != 0))
+ && (current_slice != /*PC_SLICE_TYPE_NTFS*/7)
+ && (current_slice != /*PC_SLICE_TYPE_NTFS*/0x17))
+ return 0;
+
+ if (!devread (0, 0, 512, (char *) FSYS_BUF))
+ return 0; /* Cannot read superblock */
+
+ if(sb[3]!='N' || sb[4]!='T' || sb[5]!='F' || sb[6]!='S')
+ return 0;
+ blocksize = *(__u16 *)(sb+0xb);
+ spc = *(unsigned char *)(sb+0xd);
+ clustersize = spc * blocksize;
+ mft_record_size = *(char *)(sb+0x40);
+ index_record_size = *(char *)(sb+0x44);
+ if(mft_record_size>0)
+ mft_record_size *= clustersize;
+ else
+ mft_record_size = 1 << (-mft_record_size);
+
+ index_record_size *= clustersize;
+ mft_record = *(__u32 *)(sb+0x30); /* only support 32 bit */
+ spc = clustersize / 512;
+
+ if(mft_record_size > MAX_MFT_RECORD_SIZE || index_record_size > MAX_INDEX_RECORD_SIZE) {
+ /* only support 1k MFT record, 4k INDEX record */
+ return 0;
+ }
+
+#ifdef DEBUG_NTFS
+ printf("spc=%x mft_record=%x:%x\n", spc, *(__s64 *)(sb+0x30));
+#endif
+
+ if (!devread (mft_record*spc, 0, mft_record_size, mmft->mft))
+ return 0; /* Cannot read superblock */
+
+ if(!fixup_record( mmft->mft, "FILE", mft_record_size))
+ return 0;
+
+#ifndef NO_ALTERNATE_DATASTREAM
+ is_ads_completion = 0;
+#endif
+ if(!search_attribute(mmft, at_data, NONAME)) return 0;
+
+ *mft_run = mmft->runl;
+
+ *path_ino = FILE_ROOT;
+
+ return 1;
+}
+
+int
+ntfs_dir (char *dirname)
+{
+ char *rest, ch;
+ int namelen;
+ int depth = 0;
+ int chk_sfn = 1;
+ int flag = 0;
+ int record_offset;
+ int my_index_record_size;
+ unsigned char *index_entry = 0, *entry, *index_end;
+ int i;
+
+ /* main loop to find desired directory entry */
+loop:
+
+#ifdef DEBUG_NTFS
+ printf("dirname=%s\n", dirname);
+#endif
+ if(!read_mft_record(path_ino[depth], cmft->mft, 0))
+ {
+#ifdef DEBUG_NTFS
+ printf("MFT error 1\n");
+#endif
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (!*dirname || isspace (*dirname) || *dirname==':')
+ {
+#ifndef STAGE1_5
+#ifndef NO_ALTERNATE_DATASTREAM
+ if (*dirname==':' && print_possibilities) {
+ char *tmp;
+
+ /* preparing ADS name completion */
+ for(tmp = dirname; *tmp != '/'; tmp--);
+ for(tmp++, rest=fnbuf; *tmp && !isspace(*tmp); *rest++ = *tmp++)
+ if(*tmp==':') dirname = rest;
+ *rest++ = '\0';
+
+ is_ads_completion = 1;
+ search_attribute(cmft, at_data, dirname+1);
+ is_ads_completion = 0;
+
+ if(errnum==0) {
+ if(print_possibilities < 0)
+ return 1;
+ errnum = ERR_FILE_NOT_FOUND;
+ }
+ return 0;
+ }
+#endif
+#endif
+
+ if (*dirname==':') dirname++;
+ for (rest = dirname; (ch = *rest) && !isspace (ch); rest++);
+ *rest = 0;
+
+#ifdef DEBUG_NTFS
+ printf("got file: search at_data\n");
+#endif
+
+ if (!search_attribute(cmft, at_data, dirname)) {
+ errnum = *(dirname-1)==':'?ERR_FILE_NOT_FOUND:ERR_BAD_FILETYPE;
+ *rest = ch;
+ return 0;
+ }
+ *rest = ch;
+
+ filemax = cmft->attr_size;
+#ifdef DEBUG_NTFS
+ printf("filemax=%x\n", filemax);
+#endif
+ return 1;
+ }
+
+ if(depth >= (MAX_DIR_DEPTH-1)) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ /* continue with the file/directory name interpretation */
+
+ while (*dirname == '/')
+ dirname++;
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/' && ch != ':'; rest++);
+
+ *rest = 0;
+
+ if (!search_attribute(cmft, at_index_root, "$I30"))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ read_attribute(cmft, 0, fnbuf, 16, 0);
+ my_index_record_size = *(__u32 *)(fnbuf+8);
+
+ if(my_index_record_size > MAX_INDEX_RECORD_SIZE) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+#ifdef DEBUG_NTFS
+ printf("index_record_size=%x\n", my_index_record_size);
+#endif
+
+ if(cmft->attr_size > MAX_INDEX_RECORD_SIZE) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ read_attribute(cmft, 0, index_data, cmft->attr_size, 0);
+ index_end = index_data + cmft->attr_size;
+ index_entry = index_data + 0x20;
+ record_offset = -1;
+
+#ifndef STAGE1_5
+ if (print_possibilities && ch != '/' && ch != ':' && !*dirname)
+ {
+ print_possibilities = -print_possibilities;
+ /* fake '.' for empty directory */
+ print_a_completion (".");
+ }
+#endif
+
+ if (search_attribute(cmft, at_bitmap, "$I30")) {
+ if(cmft->attr_size > MAX_INDEX_BITMAP_SIZE) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ read_attribute(cmft, 0, bitmap_data, cmft->attr_size, 0);
+
+ if (search_attribute(cmft, at_index_allocation, "$I30")==0) {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ for(record_offset = 0; record_offset*my_index_record_size<cmft->attr_size; record_offset++){
+ int bit = 1 << (record_offset&3);
+ int byte = record_offset>>3;
+#ifdef DEBUG_NTFS
+ printf("record_offset=%x\n", record_offset);
+#endif
+ if((bitmap_data[byte]&bit))
+ break;
+ }
+
+ if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
+ }
+
+ do
+ {
+ entry = index_entry; index_entry += *(__u16 *)(entry+8);
+ if(entry+0x50>=index_entry||entry>=index_end||
+ index_entry>=index_end||(entry[0x12]&2)){
+ if(record_offset < 0 ||
+ !read_attribute(cmft, record_offset*my_index_record_size, index_data, my_index_record_size, 0)){
+ if (!errnum)
+ {
+ if (print_possibilities < 0)
+ {
+#if 0
+ putchar ('\n');
+#endif
+ return 1;
+ }
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ }
+
+ return 0;
+ }
+ if(!fixup_record( index_data, "INDX", my_index_record_size))
+ {
+#ifdef DEBUG_NTFS
+ printf("index error\n");
+#endif
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+ entry = index_data + 0x18 + *(__u16 *)(index_data+0x18);
+ index_entry = entry + *(__u16 *)(entry+8);
+ index_end = index_data + my_index_record_size - 0x52;
+ for(record_offset++; record_offset*my_index_record_size<cmft->attr_size; record_offset++){
+ int bit = 1 << (record_offset&3);
+ int byte = record_offset>>3;
+ if((bitmap_data[byte]&bit)) break;
+ }
+ if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
+#ifdef DEBUG_NTFS
+ printf("record_offset=%x\n", record_offset);
+#endif
+ }
+ flag = entry[0x51];
+ path_ino[depth+1] = *(__u32 *)entry;
+ if(path_ino[depth+1] < 16)
+ continue;
+ namelen = entry[0x50];
+ //if(index_data[0x48]&2) printf("hidden file\n");
+#ifndef STAGE1_5
+ /* skip short file name */
+ if( flag == 2 && print_possibilities && ch != '/' && ch != ':' )
+ continue;
+#endif
+
+ for( i = 0, entry+=0x52; i < namelen; i++, entry+=2 )
+ {
+ int c = *(__u16 *)entry;
+ if(c==' '||c>=0x100)
+ fnbuf[i] = '_';
+ else
+ fnbuf[i] = c;
+ }
+ fnbuf[namelen] = 0;
+#ifdef DEBUG_NTFS
+ printf("FLAG: %d NAME: %s inum=%d\n", flag,fnbuf,path_ino[depth+1]);
+#endif
+
+ //uncntrl(fnbuf);
+
+ chk_sfn = nsubstring(dirname,fnbuf);
+#ifndef STAGE1_5
+ if (print_possibilities && ch != '/' && ch != ':'
+ && (!*dirname || chk_sfn <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (fnbuf);
+ }
+#endif /* STAGE1_5 */
+ }
+ while (chk_sfn != 0 ||
+ (print_possibilities && ch != '/' && ch != ':'));
+
+ *(dirname = rest) = ch;
+
+ depth++;
+
+ /* go back to main loop at top of function */
+ goto loop;
+}
+
+#ifdef DEBUG_NTFS
+int dump_block(char *msg, char *buf, int size){
+ int l = (size+15)/16;
+ int off;
+ int i, j;
+ int c;
+ printf("----- %s -----\n", msg);
+ for( i = 0, off = 0; i < l; i++, off+=16)
+ {
+ if(off<16)
+ printf("000%x:", off);
+ else if(off<256)
+ printf("00%x:", off);
+ else
+ printf("0%x:", off);
+ for(j=0;j<16;j++)
+ {
+ c = buf[off+j]&0xff;
+ if( c >= 16 )
+ printf("%c%x",j==8?'-':' ',c);
+ else
+ printf("%c0%x",j==8?'-':' ',c);
+ }
+ printf(" ");
+ for(j=0;j<16;j++) {
+ char c = buf[off+j];
+ printf("%c",c<' '||c>='\x7f'?'.':c);
+ }
+ printf("\n");
+ }
+}
+#endif
+#endif /* FSYS_NTFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c b/qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c
new file mode 100644
index 000000000..b94a33529
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_reiserfs.c
@@ -0,0 +1,1220 @@
+/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_REISERFS
+#include "shared.h"
+#include "filesys.h"
+
+#undef REISERDEBUG
+
+/* Some parts of this code (mainly the structures and defines) are
+ * from the original reiser fs code, as found in the linux kernel.
+ */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef unsigned long long __u64;
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+#include "libc/byteorder.h"
+
+/* include/linux/reiser_fs.h */
+/* This is the new super block of a journaling reiserfs system */
+struct reiserfs_super_block
+{
+ __u32 s_block_count; /* blocks count */
+ __u32 s_free_blocks; /* free blocks count */
+ __u32 s_root_block; /* root block number */
+ __u32 s_journal_block; /* journal block number */
+ __u32 s_journal_dev; /* journal device number */
+ __u32 s_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */
+ __u32 s_journal_trans_max; /* max number of blocks in a transaction. */
+ __u32 s_journal_magic; /* random value made on fs creation */
+ __u32 s_journal_max_batch; /* max number of blocks to batch into a trans */
+ __u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */
+ __u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */
+ __u16 s_blocksize; /* block size */
+ __u16 s_oid_maxsize; /* max size of object id array */
+ __u16 s_oid_cursize; /* current size of object id array */
+ __u16 s_state; /* valid or error */
+ char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */
+ __u16 s_tree_height; /* height of disk tree */
+ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */
+ __u16 s_version;
+ char s_unused[128]; /* zero filled by mkreiserfs */
+};
+
+#define REISERFS_MAX_SUPPORTED_VERSION 2
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+
+#define MAX_HEIGHT 7
+
+/* must be correct to keep the desc and commit structs at 4k */
+#define JOURNAL_TRANS_HALF 1018
+
+/* first block written in a commit. */
+struct reiserfs_journal_desc {
+ __u32 j_trans_id; /* id of commit */
+ __u32 j_len; /* length of commit. len +1 is the commit block */
+ __u32 j_mount_id; /* mount id of this trans*/
+ __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */
+ char j_magic[12];
+};
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+ __u32 j_trans_id; /* must match j_trans_id from the desc block */
+ __u32 j_len; /* ditto */
+ __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */
+ char j_digest[16]; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
+};
+
+/* this header block gets written whenever a transaction is considered
+ fully flushed, and is more recent than the last fully flushed
+ transaction.
+ fully flushed means all the log blocks and all the real blocks are
+ on disk, and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+ /* id of last fully flushed transaction */
+ __u32 j_last_flush_trans_id;
+ /* offset in the log of where to start replay after a crash */
+ __u32 j_first_unflushed_offset;
+ /* mount id to detect very old transactions */
+ __u32 j_mount_id;
+};
+
+/* magic string to find desc blocks in the journal */
+#define JOURNAL_DESC_MAGIC "ReIsErLB"
+
+
+/*
+ * directories use this key as well as old files
+ */
+struct offset_v1
+{
+ /*
+ * for regular files this is the offset to the first byte of the
+ * body, contained in the object-item, as measured from the start of
+ * the entire body of the object.
+ *
+ * for directory entries, k_offset consists of hash derived from
+ * hashing the name and using few bits (23 or more) of the resulting
+ * hash, and generation number that allows distinguishing names with
+ * hash collisions. If number of collisions overflows generation
+ * number, we return EEXIST. High order bit is 0 always
+ */
+ __u32 k_offset;
+ __u32 k_uniqueness;
+};
+
+struct offset_v2
+{
+ /*
+ * for regular files this is the offset to the first byte of the
+ * body, contained in the object-item, as measured from the start of
+ * the entire body of the object.
+ *
+ * for directory entries, k_offset consists of hash derived from
+ * hashing the name and using few bits (23 or more) of the resulting
+ * hash, and generation number that allows distinguishing names with
+ * hash collisions. If number of collisions overflows generation
+ * number, we return EEXIST. High order bit is 0 always
+ */
+ __u64 k_offset:60;
+ __u64 k_type: 4;
+};
+
+
+struct key
+{
+ /* packing locality: by default parent directory object id */
+ __u32 k_dir_id;
+ /* object identifier */
+ __u32 k_objectid;
+ /* the offset and node type (old and new form) */
+ union
+ {
+ struct offset_v1 v1;
+ struct offset_v2 v2;
+ }
+ u;
+};
+
+#define KEY_SIZE (sizeof (struct key))
+
+/* Header of a disk block. More precisely, header of a formatted leaf
+ or internal node, and not the header of an unformatted node. */
+struct block_head
+{
+ __u16 blk_level; /* Level of a block in the tree. */
+ __u16 blk_nr_item; /* Number of keys/items in a block. */
+ __u16 blk_free_space; /* Block free space in bytes. */
+ struct key blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes
+ only) */
+};
+#define BLKH_SIZE (sizeof (struct block_head))
+#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */
+
+struct item_head
+{
+ struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/
+
+ union
+ {
+ __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this
+ is an indirect item. This equals 0xFFFF iff this is a direct item or
+ stat data item. Note that the key, not this field, is used to determine
+ the item type, and thus which field this union contains. */
+ __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
+ entries in the directory item. */
+ }
+ u;
+ __u16 ih_item_len; /* total size of the item body */
+ __u16 ih_item_location; /* an offset to the item body within the block */
+ __u16 ih_version; /* ITEM_VERSION_1 for all old items,
+ ITEM_VERSION_2 for new ones.
+ Highest bit is set by fsck
+ temporary, cleaned after all done */
+};
+/* size of item header */
+#define IH_SIZE (sizeof (struct item_head))
+
+#define ITEM_VERSION_1 0
+#define ITEM_VERSION_2 1
+#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \
+ ? (ih)->ih_key.u.v1.k_offset \
+ : (ih)->ih_key.u.v2.k_offset)
+
+#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \
+ ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \
+ : (ih)->ih_key.u.v2.k_type == V2_##type)
+
+/* FIXME these types look wrong. */
+struct disk_child
+{
+ unsigned long dc_block_number; /* Disk child's block number. */
+ unsigned short dc_size; /* Disk child's used space. */
+};
+
+#define DC_SIZE (sizeof (struct disk_child))
+
+/* Stat Data on disk.
+ *
+ * Note that reiserfs has two different forms of stat data. Luckily
+ * the fields needed by grub are at the same position.
+ */
+struct stat_data
+{
+ __u16 sd_mode; /* file type, permissions */
+ __u16 sd_notused1[3]; /* fields not needed by reiserfs */
+ __u32 sd_size; /* file size */
+ __u32 sd_size_hi; /* file size high 32 bits (since version 2) */
+};
+
+struct reiserfs_de_head
+{
+ __u32 deh_offset; /* third component of the directory entry key */
+ __u32 deh_dir_id; /* objectid of the parent directory of the
+ object, that is referenced by directory entry */
+ __u32 deh_objectid;/* objectid of the object, that is referenced by
+ directory entry */
+ __u16 deh_location;/* offset of name in the whole item */
+ __u16 deh_state; /* whether 1) entry contains stat data (for
+ future), and 2) whether entry is hidden
+ (unlinked) */
+};
+
+#define DEH_SIZE (sizeof (struct reiserfs_de_head))
+
+#define DEH_Statdata (1 << 0) /* not used now */
+#define DEH_Visible (1 << 2)
+
+#define SD_OFFSET 0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+#define V1_TYPE_STAT_DATA 0x0
+#define V1_TYPE_DIRECT 0xffffffff
+#define V1_TYPE_INDIRECT 0xfffffffe
+#define V1_TYPE_DIRECTORY_MAX 0xfffffffd
+#define V2_TYPE_STAT_DATA 0
+#define V2_TYPE_INDIRECT 1
+#define V2_TYPE_DIRECT 2
+#define V2_TYPE_DIRENTRY 3
+
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+#define REISERFS_OLD_BLOCKSIZE 4096
+
+#define S_ISREG(mode) (((mode) & 0170000) == 0100000)
+#define S_ISDIR(mode) (((mode) & 0170000) == 0040000)
+#define S_ISLNK(mode) (((mode) & 0170000) == 0120000)
+
+#define PATH_MAX 1024 /* include/linux/limits.h */
+#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
+
+/* The size of the node cache */
+#define FSYSREISER_CACHE_SIZE 24*1024
+#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE
+#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3
+
+/* Info about currently opened file */
+struct fsys_reiser_fileinfo
+{
+ __u32 k_dir_id;
+ __u32 k_objectid;
+};
+
+/* In memory info about the currently mounted filesystem */
+struct fsys_reiser_info
+{
+ /* The last read item head */
+ struct item_head *current_ih;
+ /* The last read item */
+ char *current_item;
+ /* The information for the currently opened file */
+ struct fsys_reiser_fileinfo fileinfo;
+ /* The start of the journal */
+ __u32 journal_block;
+ /* The size of the journal */
+ __u32 journal_block_count;
+ /* The first valid descriptor block in journal
+ (relative to journal_block) */
+ __u32 journal_first_desc;
+
+ /* The ReiserFS version. */
+ __u16 version;
+ /* The current depth of the reiser tree. */
+ __u16 tree_depth;
+ /* SECTOR_SIZE << blocksize_shift == blocksize. */
+ __u8 blocksize_shift;
+ /* 1 << full_blocksize_shift == blocksize. */
+ __u8 fullblocksize_shift;
+ /* The reiserfs block size (must be a power of 2) */
+ __u16 blocksize;
+ /* The number of cached tree nodes */
+ __u16 cached_slots;
+ /* The number of valid transactions in journal */
+ __u16 journal_transactions;
+
+ unsigned int blocks[MAX_HEIGHT];
+ unsigned int next_key_nr[MAX_HEIGHT];
+};
+
+/* The cached s+tree blocks in FSYS_BUF, see below
+ * for a more detailed description.
+ */
+#define ROOT ((char *)FSYS_BUF)
+#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift))
+#define LEAF CACHE (DISK_LEAF_NODE_LEVEL)
+
+#define BLOCKHEAD(cache) ((struct block_head *) cache)
+#define ITEMHEAD ((struct item_head *) ((char *) LEAF + BLKH_SIZE))
+#define KEY(cache) ((struct key *) ((char *) cache + BLKH_SIZE))
+#define DC(cache) ((struct disk_child *) \
+ ((char *) cache + BLKH_SIZE + KEY_SIZE * nr_item))
+/* The fsys_reiser_info block.
+ */
+#define INFO \
+ ((struct fsys_reiser_info *) ((char *) FSYS_BUF + FSYSREISER_CACHE_SIZE))
+/*
+ * The journal cache. For each transaction it contains the number of
+ * blocks followed by the real block numbers of this transaction.
+ *
+ * If the block numbers of some transaction won't fit in this space,
+ * this list is stopped with a 0xffffffff marker and the remaining
+ * uncommitted transactions aren't cached.
+ */
+#define JOURNAL_START ((__u32 *) (INFO + 1))
+#define JOURNAL_END ((__u32 *) (FSYS_BUF + FSYS_BUFLEN))
+
+static __inline__ int
+is_power_of_two (unsigned long word)
+{
+ return (word & -word) == word;
+}
+
+static int
+journal_read (int block, int len, char *buffer)
+{
+ return devread ((INFO->journal_block + block) << INFO->blocksize_shift,
+ 0, len, buffer);
+}
+
+/* Read a block from ReiserFS file system, taking the journal into
+ * account. If the block nr is in the journal, the block from the
+ * journal taken.
+ */
+static int
+block_read (int blockNr, int start, int len, char *buffer)
+{
+ int transactions = INFO->journal_transactions;
+ int desc_block = INFO->journal_first_desc;
+ int journal_mask = INFO->journal_block_count - 1;
+ int translatedNr = blockNr;
+ __u32 *journal_table = JOURNAL_START;
+ while (transactions-- > 0)
+ {
+ int i = 0;
+ int j_len;
+ if (*journal_table != 0xffffffff)
+ {
+ /* Search for the blockNr in cached journal */
+ j_len = *journal_table++;
+ while (i++ < j_len)
+ {
+ if (*journal_table++ == blockNr)
+ {
+ journal_table += j_len - i;
+ goto found;
+ }
+ }
+ }
+ else
+ {
+ /* This is the end of cached journal marker. The remaining
+ * transactions are still on disk.
+ */
+ struct reiserfs_journal_desc desc;
+ struct reiserfs_journal_commit commit;
+
+ if (! journal_read (desc_block, sizeof (desc), (char *) &desc))
+ return 0;
+
+ j_len = desc.j_len;
+ while (i < j_len && i < JOURNAL_TRANS_HALF)
+ if (desc.j_realblock[i++] == blockNr)
+ goto found;
+
+ if (j_len >= JOURNAL_TRANS_HALF)
+ {
+ int commit_block = (desc_block + 1 + j_len) & journal_mask;
+ if (! journal_read (commit_block,
+ sizeof (commit), (char *) &commit))
+ return 0;
+ while (i < j_len)
+ if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr)
+ goto found;
+ }
+ }
+ goto not_found;
+
+ found:
+ translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask);
+#ifdef REISERDEBUG
+ printf ("block_read: block %d is mapped to journal block %d.\n",
+ blockNr, translatedNr - INFO->journal_block);
+#endif
+ /* We must continue the search, as this block may be overwritten
+ * in later transactions.
+ */
+ not_found:
+ desc_block = (desc_block + 2 + j_len) & journal_mask;
+ }
+ return devread (translatedNr << INFO->blocksize_shift, start, len, buffer);
+}
+
+/* Init the journal data structure. We try to cache as much as
+ * possible in the JOURNAL_START-JOURNAL_END space, but if it is full
+ * we can still read the rest from the disk on demand.
+ *
+ * The first number of valid transactions and the descriptor block of the
+ * first valid transaction are held in INFO. The transactions are all
+ * adjacent, but we must take care of the journal wrap around.
+ */
+static int
+journal_init (void)
+{
+ unsigned int block_count = INFO->journal_block_count;
+ unsigned int desc_block;
+ unsigned int commit_block;
+ unsigned int next_trans_id;
+ struct reiserfs_journal_header header;
+ struct reiserfs_journal_desc desc;
+ struct reiserfs_journal_commit commit;
+ __u32 *journal_table = JOURNAL_START;
+
+ journal_read (block_count, sizeof (header), (char *) &header);
+ desc_block = header.j_first_unflushed_offset;
+ if (desc_block >= block_count)
+ return 0;
+
+ INFO->journal_first_desc = desc_block;
+ next_trans_id = header.j_last_flush_trans_id + 1;
+
+#ifdef REISERDEBUG
+ printf ("journal_init: last flushed %d\n",
+ header.j_last_flush_trans_id);
+#endif
+
+ while (1)
+ {
+ journal_read (desc_block, sizeof (desc), (char *) &desc);
+ if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0
+ || desc.j_trans_id != next_trans_id
+ || desc.j_mount_id != header.j_mount_id)
+ /* no more valid transactions */
+ break;
+
+ commit_block = (desc_block + desc.j_len + 1) & (block_count - 1);
+ journal_read (commit_block, sizeof (commit), (char *) &commit);
+ if (desc.j_trans_id != commit.j_trans_id
+ || desc.j_len != commit.j_len)
+ /* no more valid transactions */
+ break;
+
+#ifdef REISERDEBUG
+ printf ("Found valid transaction %d/%d at %d.\n",
+ desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+ next_trans_id++;
+ if (journal_table < JOURNAL_END)
+ {
+ if ((journal_table + 1 + desc.j_len) >= JOURNAL_END)
+ {
+ /* The table is almost full; mark the end of the cached
+ * journal.*/
+ *journal_table = 0xffffffff;
+ journal_table = JOURNAL_END;
+ }
+ else
+ {
+ int i;
+ /* Cache the length and the realblock numbers in the table.
+ * The block number of descriptor can easily be computed.
+ * and need not to be stored here.
+ */
+ *journal_table++ = desc.j_len;
+ for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++)
+ {
+ *journal_table++ = desc.j_realblock[i];
+#ifdef REISERDEBUG
+ printf ("block %d is in journal %d.\n",
+ desc.j_realblock[i], desc_block);
+#endif
+ }
+ for ( ; i < desc.j_len; i++)
+ {
+ *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF];
+#ifdef REISERDEBUG
+ printf ("block %d is in journal %d.\n",
+ commit.j_realblock[i-JOURNAL_TRANS_HALF],
+ desc_block);
+#endif
+ }
+ }
+ }
+ desc_block = (commit_block + 1) & (block_count - 1);
+ }
+#ifdef REISERDEBUG
+ printf ("Transaction %d/%d at %d isn't valid.\n",
+ desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+ INFO->journal_transactions
+ = next_trans_id - header.j_last_flush_trans_id - 1;
+ return errnum == 0;
+}
+
+/* check filesystem types and read superblock into memory buffer */
+int
+reiserfs_mount (void)
+{
+ struct reiserfs_super_block super;
+ int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+
+ if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+ || ! devread (superblock, 0, sizeof (struct reiserfs_super_block),
+ (char *) &super)
+ || (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+ || (/* check that this is not a copy inside the journal log */
+ super.s_journal_block * super.s_blocksize
+ <= REISERFS_DISK_OFFSET_IN_BYTES))
+ {
+ /* Try old super block position */
+ superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+ if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+ || ! devread (superblock, 0, sizeof (struct reiserfs_super_block),
+ (char *) &super))
+ return 0;
+
+ if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+ {
+ /* pre journaling super block ? */
+ if (substring (REISERFS_SUPER_MAGIC_STRING,
+ (char*) ((char *) &super + 20)) > 0)
+ return 0;
+
+ super.s_blocksize = REISERFS_OLD_BLOCKSIZE;
+ super.s_journal_block = 0;
+ super.s_version = 0;
+ }
+ }
+
+ /* check the version number. */
+ if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION)
+ return 0;
+
+ INFO->version = super.s_version;
+ INFO->blocksize = super.s_blocksize;
+ INFO->fullblocksize_shift = log2 (super.s_blocksize);
+ INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS;
+ INFO->cached_slots =
+ (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1;
+
+#ifdef REISERDEBUG
+ printf ("reiserfs_mount: version=%d, blocksize=%d\n",
+ INFO->version, INFO->blocksize);
+#endif /* REISERDEBUG */
+
+ /* Clear node cache. */
+ memset (INFO->blocks, 0, sizeof (INFO->blocks));
+
+ if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE
+ || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE
+ || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize)
+ return 0;
+
+ /* Initialize journal code. If something fails we end with zero
+ * journal_transactions, so we don't access the journal at all.
+ */
+ INFO->journal_transactions = 0;
+ if (super.s_journal_block != 0 && super.s_journal_dev == 0)
+ {
+ INFO->journal_block = super.s_journal_block;
+ INFO->journal_block_count = super.s_journal_size;
+ if (is_power_of_two (INFO->journal_block_count))
+ journal_init ();
+
+ /* Read in super block again, maybe it is in the journal */
+ block_read (superblock >> INFO->blocksize_shift,
+ 0, sizeof (struct reiserfs_super_block), (char *) &super);
+ }
+
+ if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT))
+ return 0;
+
+ INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level;
+
+#ifdef REISERDEBUG
+ printf ("root read_in: block=%d, depth=%d\n",
+ super.s_root_block, INFO->tree_depth);
+#endif /* REISERDEBUG */
+
+ if (INFO->tree_depth >= MAX_HEIGHT)
+ return 0;
+ if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL)
+ {
+ /* There is only one node in the whole filesystem,
+ * which is simultanously leaf and root */
+ memcpy (LEAF, ROOT, INFO->blocksize);
+ }
+ return 1;
+}
+
+/***************** TREE ACCESSING METHODS *****************************/
+
+/* I assume you are familiar with the ReiserFS tree, if not go to
+ * http://www.namesys.com/content_table.html
+ *
+ * My tree node cache is organized as following
+ * 0 ROOT node
+ * 1 LEAF node (if the ROOT is also a LEAF it is copied here
+ * 2-n other nodes on current path from bottom to top.
+ * if there is not enough space in the cache, the top most are
+ * omitted.
+ *
+ * I have only two methods to find a key in the tree:
+ * search_stat(dir_id, objectid) searches for the stat entry (always
+ * the first entry) of an object.
+ * next_key() gets the next key in tree order.
+ *
+ * This means, that I can only sequential reads of files are
+ * efficient, but this really doesn't hurt for grub.
+ */
+
+/* Read in the node at the current path and depth into the node cache.
+ * You must set INFO->blocks[depth] before.
+ */
+static char *
+read_tree_node (unsigned int blockNr, int depth)
+{
+ char* cache = CACHE(depth);
+ int num_cached = INFO->cached_slots;
+ if (depth < num_cached)
+ {
+ /* This is the cached part of the path. Check if same block is
+ * needed.
+ */
+ if (blockNr == INFO->blocks[depth])
+ return cache;
+ }
+ else
+ cache = CACHE(num_cached);
+
+#ifdef REISERDEBUG
+ printf (" next read_in: block=%d (depth=%d)\n",
+ blockNr, depth);
+#endif /* REISERDEBUG */
+ if (! block_read (blockNr, 0, INFO->blocksize, cache))
+ return NULL;
+ /* Make sure it has the right node level */
+ if (BLOCKHEAD (cache)->blk_level != depth)
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return NULL;
+ }
+
+ INFO->blocks[depth] = blockNr;
+ return cache;
+}
+
+/* Get the next key, i.e. the key following the last retrieved key in
+ * tree order. INFO->current_ih and
+ * INFO->current_info are adapted accordingly. */
+static int
+next_key (void)
+{
+ int depth;
+ struct item_head *ih = INFO->current_ih + 1;
+ char *cache;
+
+#ifdef REISERDEBUG
+ printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+
+ if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item])
+ {
+ depth = DISK_LEAF_NODE_LEVEL;
+ /* The last item, was the last in the leaf node.
+ * Read in the next block
+ */
+ do
+ {
+ if (depth == INFO->tree_depth)
+ {
+ /* There are no more keys at all.
+ * Return a dummy item with MAX_KEY */
+ ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key;
+ goto found;
+ }
+ depth++;
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]);
+#endif /* REISERDEBUG */
+ }
+ while (INFO->next_key_nr[depth] == 0);
+
+ if (depth == INFO->tree_depth)
+ cache = ROOT;
+ else if (depth <= INFO->cached_slots)
+ cache = CACHE (depth);
+ else
+ {
+ cache = read_tree_node (INFO->blocks[depth], depth);
+ if (! cache)
+ return 0;
+ }
+
+ do
+ {
+ int nr_item = BLOCKHEAD (cache)->blk_nr_item;
+ int key_nr = INFO->next_key_nr[depth]++;
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item);
+#endif /* REISERDEBUG */
+ if (key_nr == nr_item)
+ /* This is the last item in this block, set the next_key_nr to 0 */
+ INFO->next_key_nr[depth] = 0;
+
+ cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth);
+ if (! cache)
+ return 0;
+ }
+ while (depth > DISK_LEAF_NODE_LEVEL);
+
+ ih = ITEMHEAD;
+ }
+ found:
+ INFO->current_ih = ih;
+ INFO->current_item = &LEAF[ih->ih_item_location];
+#ifdef REISERDEBUG
+ printf (" new ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+ return 1;
+}
+
+/* preconditions: reiserfs_mount already executed, therefore
+ * INFO block is valid
+ * returns: 0 if error (errnum is set),
+ * nonzero iff we were able to find the key successfully.
+ * postconditions: on a nonzero return, the current_ih and
+ * current_item fields describe the key that equals the
+ * searched key. INFO->next_key contains the next key after
+ * the searched key.
+ * side effects: messes around with the cache.
+ */
+static int
+search_stat (__u32 dir_id, __u32 objectid)
+{
+ char *cache;
+ int depth;
+ int nr_item;
+ int i;
+ struct item_head *ih;
+#ifdef REISERDEBUG
+ printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid);
+#endif /* REISERDEBUG */
+
+ depth = INFO->tree_depth;
+ cache = ROOT;
+
+ while (depth > DISK_LEAF_NODE_LEVEL)
+ {
+ struct key *key;
+ nr_item = BLOCKHEAD (cache)->blk_nr_item;
+
+ key = KEY (cache);
+
+ for (i = 0; i < nr_item; i++)
+ {
+ if (key->k_dir_id > dir_id
+ || (key->k_dir_id == dir_id
+ && (key->k_objectid > objectid
+ || (key->k_objectid == objectid
+ && (key->u.v1.k_offset
+ | key->u.v1.k_uniqueness) > 0))))
+ break;
+ key++;
+ }
+
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+ INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1;
+ cache = read_tree_node (DC (cache)[i].dc_block_number, --depth);
+ if (! cache)
+ return 0;
+ }
+
+ /* cache == LEAF */
+ nr_item = BLOCKHEAD (LEAF)->blk_nr_item;
+ ih = ITEMHEAD;
+ for (i = 0; i < nr_item; i++)
+ {
+ if (ih->ih_key.k_dir_id == dir_id
+ && ih->ih_key.k_objectid == objectid
+ && ih->ih_key.u.v1.k_offset == 0
+ && ih->ih_key.u.v1.k_uniqueness == 0)
+ {
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+ INFO->current_ih = ih;
+ INFO->current_item = &LEAF[ih->ih_item_location];
+ return 1;
+ }
+ ih++;
+ }
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+}
+
+int
+reiserfs_read (char *buf, int len)
+{
+ unsigned int blocksize;
+ unsigned int offset;
+ unsigned int to_read;
+ char *prev_buf = buf;
+
+#ifdef REISERDEBUG
+ printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n",
+ filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1);
+#endif /* REISERDEBUG */
+
+ if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid
+ || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1)
+ {
+ search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid);
+ goto get_next_key;
+ }
+
+ while (! errnum)
+ {
+ if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid)
+ break;
+
+ offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1;
+ blocksize = INFO->current_ih->ih_item_len;
+
+#ifdef REISERDEBUG
+ printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n",
+ filepos, len, offset, blocksize);
+#endif /* REISERDEBUG */
+
+ if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT)
+ && offset < blocksize)
+ {
+#ifdef REISERDEBUG
+ printf ("direct_read: offset=%d, blocksize=%d\n",
+ offset, blocksize);
+#endif /* REISERDEBUG */
+ to_read = blocksize - offset;
+ if (to_read > len)
+ to_read = len;
+
+ if (disk_read_hook != NULL)
+ {
+ disk_read_func = disk_read_hook;
+
+ block_read (INFO->blocks[DISK_LEAF_NODE_LEVEL],
+ (INFO->current_item - LEAF + offset), to_read, buf);
+
+ disk_read_func = NULL;
+ }
+ else
+ memcpy (buf, INFO->current_item + offset, to_read);
+ goto update_buf_len;
+ }
+ else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT))
+ {
+ blocksize = (blocksize >> 2) << INFO->fullblocksize_shift;
+#ifdef REISERDEBUG
+ printf ("indirect_read: offset=%d, blocksize=%d\n",
+ offset, blocksize);
+#endif /* REISERDEBUG */
+
+ while (offset < blocksize)
+ {
+ __u32 blocknr = ((__u32 *) INFO->current_item)
+ [offset >> INFO->fullblocksize_shift];
+ int blk_offset = offset & (INFO->blocksize-1);
+
+ to_read = INFO->blocksize - blk_offset;
+ if (to_read > len)
+ to_read = len;
+
+ disk_read_func = disk_read_hook;
+
+ /* Journal is only for meta data. Data blocks can be read
+ * directly without using block_read
+ */
+ devread (blocknr << INFO->blocksize_shift,
+ blk_offset, to_read, buf);
+
+ disk_read_func = NULL;
+ update_buf_len:
+ len -= to_read;
+ buf += to_read;
+ offset += to_read;
+ filepos += to_read;
+ if (len == 0)
+ goto done;
+ }
+ }
+ get_next_key:
+ next_key ();
+ }
+ done:
+ return errnum ? 0 : buf - prev_buf;
+}
+
+
+/* preconditions: reiserfs_mount already executed, therefore
+ * INFO block is valid
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, INFO->fileinfo contains the info
+ * of the file we were trying to look up, filepos is 0 and filemax is
+ * the size of the file.
+ */
+int
+reiserfs_dir (char *dirname)
+{
+ struct reiserfs_de_head *de_head;
+ char *rest, ch;
+ __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;
+#ifndef STAGE1_5
+ int do_possibilities = 0;
+#endif /* ! STAGE1_5 */
+ char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
+ int link_count = 0;
+ int mode;
+
+ dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+ objectid = REISERFS_ROOT_OBJECTID;
+
+ while (1)
+ {
+#ifdef REISERDEBUG
+ printf ("dirname=%s\n", dirname);
+#endif /* REISERDEBUG */
+
+ /* Search for the stat info first. */
+ if (! search_stat (dir_id, objectid))
+ return 0;
+
+#ifdef REISERDEBUG
+ printf ("sd_mode=%x sd_size=%d\n",
+ ((struct stat_data *) INFO->current_item)->sd_mode,
+ ((struct stat_data *) INFO->current_item)->sd_size);
+#endif /* REISERDEBUG */
+
+ mode = ((struct stat_data *) INFO->current_item)->sd_mode;
+
+ /* If we've got a symbolic link, then chase it. */
+ if (S_ISLNK (mode))
+ {
+ int len;
+ if (++link_count > MAX_LINK_COUNT)
+ {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+
+ /* Get the symlink size. */
+ filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+ /* Find out how long our remaining name is. */
+ len = 0;
+ while (dirname[len] && !isspace (dirname[len]))
+ len++;
+
+ if (filemax + len > sizeof (linkbuf) - 1)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ /* Copy the remaining name to the end of the symlink data.
+ Note that DIRNAME and LINKBUF may overlap! */
+ grub_memmove (linkbuf + filemax, dirname, len+1);
+
+ INFO->fileinfo.k_dir_id = dir_id;
+ INFO->fileinfo.k_objectid = objectid;
+ filepos = 0;
+ if (! next_key ()
+ || reiserfs_read (linkbuf, filemax) != filemax)
+ {
+ if (! errnum)
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+#ifdef REISERDEBUG
+ printf ("symlink=%s\n", linkbuf);
+#endif /* REISERDEBUG */
+
+ dirname = linkbuf;
+ if (*dirname == '/')
+ {
+ /* It's an absolute link, so look it up in root. */
+ dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+ objectid = REISERFS_ROOT_OBJECTID;
+ }
+ else
+ {
+ /* Relative, so look it up in our parent directory. */
+ dir_id = parent_dir_id;
+ objectid = parent_objectid;
+ }
+
+ /* Now lookup the new name. */
+ continue;
+ }
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (! *dirname || isspace (*dirname))
+ {
+ if (! S_ISREG (mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filepos = 0;
+ filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+ /* If this is a new stat data and size is > 4GB set filemax to
+ * maximum
+ */
+ if (INFO->current_ih->ih_version == ITEM_VERSION_2
+ && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0)
+ filemax = 0xffffffff;
+
+ INFO->fileinfo.k_dir_id = dir_id;
+ INFO->fileinfo.k_objectid = objectid;
+ return next_key ();
+ }
+
+ /* continue with the file/directory name interpretation */
+ while (*dirname == '/')
+ dirname++;
+ if (! S_ISDIR (mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++);
+ *rest = 0;
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/')
+ do_possibilities = 1;
+# endif /* ! STAGE1_5 */
+
+ while (1)
+ {
+ char *name_end;
+ int num_entries;
+
+ if (! next_key ())
+ return 0;
+#ifdef REISERDEBUG
+ printf ("ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+
+ if (INFO->current_ih->ih_key.k_objectid != objectid)
+ break;
+
+ name_end = INFO->current_item + INFO->current_ih->ih_item_len;
+ de_head = (struct reiserfs_de_head *) INFO->current_item;
+ num_entries = INFO->current_ih->u.ih_entry_count;
+ while (num_entries > 0)
+ {
+ char *filename = INFO->current_item + de_head->deh_location;
+ char tmp = *name_end;
+ if ((de_head->deh_state & DEH_Visible))
+ {
+ int cmp;
+ /* Directory names in ReiserFS are not null
+ * terminated. We write a temporary 0 behind it.
+ * NOTE: that this may overwrite the first block in
+ * the tree cache. That doesn't hurt as long as we
+ * don't call next_key () in between.
+ */
+ *name_end = 0;
+ cmp = substring (dirname, filename);
+ *name_end = tmp;
+# ifndef STAGE1_5
+ if (do_possibilities)
+ {
+ if (cmp <= 0)
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ *name_end = 0;
+ print_a_completion (filename);
+ *name_end = tmp;
+ }
+ }
+ else
+# endif /* ! STAGE1_5 */
+ if (cmp == 0)
+ goto found;
+ }
+ /* The beginning of this name marks the end of the next name.
+ */
+ name_end = filename;
+ de_head++;
+ num_entries--;
+ }
+ }
+
+# ifndef STAGE1_5
+ if (print_possibilities < 0)
+ return 1;
+# endif /* ! STAGE1_5 */
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+
+ found:
+
+ *rest = ch;
+ dirname = rest;
+
+ parent_dir_id = dir_id;
+ parent_objectid = objectid;
+ dir_id = de_head->deh_dir_id;
+ objectid = de_head->deh_objectid;
+ }
+}
+
+int
+reiserfs_embed (int *start_sector, int needed_sectors)
+{
+ struct reiserfs_super_block super;
+ int num_sectors;
+
+ if (! devread (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0,
+ sizeof (struct reiserfs_super_block), (char *) &super))
+ return 0;
+
+ *start_sector = 1; /* reserve first sector for stage1 */
+ if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+ || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0)
+ && (/* check that this is not a super block copy inside
+ * the journal log */
+ super.s_journal_block * super.s_blocksize
+ > REISERFS_DISK_OFFSET_IN_BYTES))
+ num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+ else
+ num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+
+ return (needed_sectors <= num_sectors);
+}
+#endif /* FSYS_REISERFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_ufs.c b/qemu/roms/openbios/fs/grubfs/fsys_ufs.c
new file mode 100644
index 000000000..8e0a0f776
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_ufs.c
@@ -0,0 +1,391 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (c) 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (c) 2005 Rink Springer
+ *
+ * This file is based on FreeBSD 5.4-RELEASE's /sys/boot/common/ufsread.c,
+ * and has some minor patches so it'll work with Cromwell/GRUB.
+ *
+ */
+/*-
+ * Copyright (c) 2002 McAfee, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and McAfee Research,, the Security Research Division of
+ * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as
+ * part of the DARPA CHATS research program
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+#ifdef FSYS_UFS
+
+#include "asm/types.h"
+
+#include "shared.h"
+#include "filesys.h"
+
+#include "ufs_dinode.h"
+#include "ufs_fs.h"
+
+#ifdef __i386__
+/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase
+ (see sys/ufs/ffs/fs.h rev 1.39) so that i386 boot loader (boot2) can
+ support both UFS1 and UFS2 again. */
+#undef cgbase
+#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
+#endif
+
+/*
+ * We use 4k `virtual' blocks for filesystem data, whatever the actual
+ * filesystem block size. FFS blocks are always a multiple of 4k.
+ */
+#define VBLKSHIFT 12
+#define VBLKSIZE (1 << VBLKSHIFT)
+#define VBLKMASK (VBLKSIZE - 1)
+#define DBPERVBLK (VBLKSIZE / DEV_BSIZE)
+#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
+#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
+#define INO_TO_VBA(fs, ipervblk, x) \
+ (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \
+ (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK))
+#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk)
+#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \
+ ((off) / VBLKSIZE) * DBPERVBLK)
+#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK)
+
+/* Buffers that must not span a 64k boundary. */
+struct dmadat {
+ char blkbuf[VBLKSIZE]; /* filesystem blocks */
+ char indbuf[VBLKSIZE]; /* indir blocks */
+ char sbbuf[SBLOCKSIZE]; /* superblock */
+ char secbuf[DEV_BSIZE]; /* for MBR/disklabel */
+};
+static struct dmadat *dmadat = (struct dmadat*)FSYS_BUF;
+
+#define SUPERBLOCK ((struct fs*)dmadat->sbbuf)
+
+ino_t lookup(const char *);
+ssize_t fsread(ino_t, void *, size_t);
+
+static int dsk_meta;
+static uint32_t fs_off;
+static ino_t cur_ino = 0;
+
+static inline int
+dskread (void* buf, unsigned lba, unsigned nblk)
+{
+ return !devread (lba, 0, nblk * DEV_BSIZE, buf) ? -1 : 0;
+}
+
+#if defined(UFS2_ONLY)
+#define DIP(field) dp2.field
+#elif defined(UFS1_ONLY)
+#define DIP(field) dp1.field
+#else
+#define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
+#endif
+
+static __inline int
+fsfind(const char *name, ino_t * ino)
+{
+ char buf[DEV_BSIZE];
+ struct ufs_dirent *d;
+ char *s;
+ ssize_t n;
+#ifndef UFS2_ONLY
+ static struct ufs1_dinode dp1;
+#endif
+#ifndef UFS1_ONLY
+ static struct ufs2_dinode dp2;
+#endif
+ char* blkbuf = dmadat->blkbuf;
+ struct fs* fs = (struct fs *)dmadat->sbbuf;
+
+ fs_off = 0;
+ while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
+ for (s = buf; s < buf + DEV_BSIZE;) {
+ d = (void *)s;
+ if (!strcmp(name, d->d_name)) {
+ *ino = d->d_fileno;
+
+ /* below is for grub, which wants the file size
+ */
+ n = IPERVBLK(fs);
+ if (dskread(blkbuf, INO_TO_VBA(fs, n, (*ino)), DBPERVBLK))
+ return -1;
+ n = INO_TO_VBO(n, (*ino));
+#if defined(UFS1_ONLY)
+ dp1 = ((struct ufs1_dinode *)blkbuf)[n];
+#elif defined(UFS2_ONLY)
+ dp2 = ((struct ufs2_dinode *)blkbuf)[n];
+#else
+ if (fs->fs_magic == FS_UFS1_MAGIC)
+ dp1 = ((struct ufs1_dinode *)blkbuf)[n];
+ else
+ dp2 = ((struct ufs2_dinode *)blkbuf)[n];
+#endif
+
+ filemax = DIP(di_size);
+ return d->d_type;
+ }
+ s += d->d_reclen;
+ }
+ return 0;
+}
+
+ino_t
+lookup(const char *path)
+{
+ char name[MAXNAMLEN + 1];
+ const char *s;
+ ino_t ino;
+ ssize_t n;
+ int dt;
+
+ ino = ROOTINO;
+ dt = DT_DIR;
+ name[0] = '/';
+ name[1] = '\0';
+ for (;;) {
+ if (*path == '/')
+ path++;
+ if (!*path)
+ break;
+ for (s = path; *s && *s != '/'; s++);
+ if ((n = s - path) > MAXNAMLEN)
+ return 0;
+ memcpy(name, path, n);
+ name[n] = 0;
+ if (dt != DT_DIR) {
+ printk("%s: not a directory.\n", name);
+ return (0);
+ }
+ if ((dt = fsfind(name, &ino)) <= 0)
+ break;
+ path = s;
+ }
+ return dt == DT_REG ? ino : 0;
+}
+
+/*
+ * Possible superblock locations ordered from most to least likely.
+ */
+static const int sblock_try[] = SBLOCKSEARCH;
+
+ssize_t
+fsread(ino_t inode, void *buf, size_t nbyte)
+{
+#ifndef UFS2_ONLY
+ static struct ufs1_dinode dp1;
+#endif
+#ifndef UFS1_ONLY
+ static struct ufs2_dinode dp2;
+#endif
+ static ino_t inomap;
+ char *blkbuf;
+ void *indbuf;
+ struct fs *fs;
+ char *s;
+ size_t n, nb, size, off, vboff;
+ ufs_lbn_t lbn;
+ ufs2_daddr_t addr, vbaddr;
+ static ufs2_daddr_t blkmap, indmap;
+ unsigned int u;
+
+
+ blkbuf = dmadat->blkbuf;
+ indbuf = dmadat->indbuf;
+ fs = (struct fs *)dmadat->sbbuf;
+ if (!dsk_meta) {
+ inomap = 0;
+ for (n = 0; sblock_try[n] != -1; n++) {
+ if (dskread(fs, sblock_try[n] / DEV_BSIZE,
+ SBLOCKSIZE / DEV_BSIZE))
+ return -1;
+ if ((
+#if defined(UFS1_ONLY)
+ fs->fs_magic == FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+ (fs->fs_magic == FS_UFS2_MAGIC &&
+ fs->fs_sblockloc == sblock_try[n])
+#else
+ fs->fs_magic == FS_UFS1_MAGIC ||
+ (fs->fs_magic == FS_UFS2_MAGIC &&
+ fs->fs_sblockloc == sblock_try[n])
+#endif
+ ) &&
+ fs->fs_bsize <= MAXBSIZE &&
+ fs->fs_bsize >= sizeof(struct fs))
+ break;
+ }
+ if (sblock_try[n] == -1) {
+ printk("Not ufs\n");
+ return -1;
+ }
+ dsk_meta++;
+ }
+ if (!inode)
+ return 0;
+ if (inomap != inode) {
+ n = IPERVBLK(fs);
+ if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK))
+ return -1;
+ n = INO_TO_VBO(n, inode);
+#if defined(UFS1_ONLY)
+ dp1 = ((struct ufs1_dinode *)blkbuf)[n];
+#elif defined(UFS2_ONLY)
+ dp2 = ((struct ufs2_dinode *)blkbuf)[n];
+#else
+ if (fs->fs_magic == FS_UFS1_MAGIC)
+ dp1 = ((struct ufs1_dinode *)blkbuf)[n];
+ else
+ dp2 = ((struct ufs2_dinode *)blkbuf)[n];
+#endif
+ inomap = inode;
+ fs_off = 0;
+ blkmap = indmap = 0;
+ }
+ s = buf;
+ size = DIP(di_size);
+ n = size - fs_off;
+ if (nbyte > n)
+ nbyte = n;
+ nb = nbyte;
+ while (nb) {
+ lbn = lblkno(fs, fs_off);
+ off = blkoff(fs, fs_off);
+ if (lbn < NDADDR) {
+ addr = DIP(di_db[lbn]);
+ } else if (lbn < NDADDR + NINDIR(fs)) {
+ n = INDIRPERVBLK(fs);
+ addr = DIP(di_ib[0]);
+ u = (unsigned int)(lbn - NDADDR) / (n * DBPERVBLK);
+ vbaddr = fsbtodb(fs, addr) + u;
+ if (indmap != vbaddr) {
+ if (dskread(indbuf, vbaddr, DBPERVBLK))
+ return -1;
+ indmap = vbaddr;
+ }
+ n = (lbn - NDADDR) & (n - 1);
+#if defined(UFS1_ONLY)
+ addr = ((ufs1_daddr_t *)indbuf)[n];
+#elif defined(UFS2_ONLY)
+ addr = ((ufs2_daddr_t *)indbuf)[n];
+#else
+ if (fs->fs_magic == FS_UFS1_MAGIC)
+ addr = ((ufs1_daddr_t *)indbuf)[n];
+ else
+ addr = ((ufs2_daddr_t *)indbuf)[n];
+#endif
+ } else {
+ return -1;
+ }
+ vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK;
+ vboff = off & VBLKMASK;
+ n = sblksize(fs, size, lbn) - (off & ~VBLKMASK);
+ if (n > VBLKSIZE)
+ n = VBLKSIZE;
+ if (blkmap != vbaddr) {
+ if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT))
+ return -1;
+ blkmap = vbaddr;
+ }
+ n -= vboff;
+ if (n > nb)
+ n = nb;
+ memcpy(s, blkbuf + vboff, n);
+ s += n;
+ fs_off += n;
+ nb -= n;
+ }
+ return nbyte;
+}
+
+int
+ufs_mount (void)
+{
+ int i, retval = 0;
+
+ /*
+ * We don't care about stuff being in disklabels or not. If the magic
+ * matches, we're good to go.
+ */
+ for (i = 0; sblock_try[i] != -1; ++i)
+ {
+ if (! (part_length < (sblock_try[i] + (SBLOCKSIZE / DEV_BSIZE))
+ || ! devread (0, sblock_try[i], SBLOCKSIZE, (char *) SUPERBLOCK)))
+ {
+ if (
+#if defined(UFS1_ONLY)
+ SUPERBLOCK->fs_magic == FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+ (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC &&
+ SUPERBLOCK->fs_sblockloc == sblock_try[i])
+#else
+ SUPERBLOCK->fs_magic == FS_UFS1_MAGIC ||
+ (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC &&
+ SUPERBLOCK->fs_sblockloc == sblock_try[i])
+#endif
+ ) {
+ retval = 1; break;
+ }
+ }
+ }
+ return retval;
+}
+
+int
+ufs_read (char *buf, int len)
+{
+ return fsread(cur_ino, buf, len);
+}
+
+int
+ufs_dir (char *dirname)
+{
+ cur_ino = lookup(dirname);
+ return cur_ino & 0xffffffff;
+}
+
+int
+ufs_embed (int* start_sector, int needed_sectors)
+{
+ /* TODO; unused by Cromwell */
+ return 0;
+}
+
+#endif /* FSYS_UFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_vstafs.c b/qemu/roms/openbios/fs/grubfs/fsys_vstafs.c
new file mode 100644
index 000000000..e06d3e73e
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_vstafs.c
@@ -0,0 +1,254 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_VSTAFS
+
+#include "shared.h"
+#include "filesys.h"
+#include "vstafs.h"
+
+
+static void get_file_info (int sector);
+static struct dir_entry *vstafs_readdir (long sector);
+static struct dir_entry *vstafs_nextdir (void);
+
+
+#define FIRST_SECTOR ((struct first_sector *) FSYS_BUF)
+#define FILE_INFO ((struct fs_file *) (long) FIRST_SECTOR + 8192)
+#define DIRECTORY_BUF ((struct dir_entry *) (long) FILE_INFO + 512)
+
+#define ROOT_SECTOR 1
+
+/*
+ * In f_sector we store the sector number in which the information about
+ * the found file is.
+ */
+static int f_sector;
+
+int
+vstafs_mount (void)
+{
+ int retval = 1;
+
+ if( (((current_drive & 0x80) || (current_slice != 0))
+ && current_slice != PC_SLICE_TYPE_VSTAFS)
+ || ! devread (0, 0, BLOCK_SIZE, (char *) FSYS_BUF)
+ || FIRST_SECTOR->fs_magic != 0xDEADFACE)
+ retval = 0;
+
+ return retval;
+}
+
+static void
+get_file_info (int sector)
+{
+ devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO);
+}
+
+static int curr_ext, current_direntry, current_blockpos;
+static struct alloc *a1;
+
+static struct dir_entry *
+vstafs_readdir (long sector)
+{
+ /*
+ * Get some information from the current directory
+ */
+ get_file_info (sector);
+ if (FILE_INFO->type != 2)
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ return NULL;
+ }
+
+ a1 = FILE_INFO->blocks;
+ curr_ext = 0;
+ devread (a1[curr_ext].a_start, 0, 512, (char *) DIRECTORY_BUF);
+ current_direntry = 11;
+ current_blockpos = 0;
+
+ return &DIRECTORY_BUF[10];
+}
+
+static struct dir_entry *
+vstafs_nextdir (void)
+{
+ if (current_direntry > 15)
+ {
+ current_direntry = 0;
+ if (++current_blockpos > (a1[curr_ext].a_len - 1))
+ {
+ current_blockpos = 0;
+ curr_ext++;
+ }
+
+ if (curr_ext < FILE_INFO->extents)
+ {
+ devread (a1[curr_ext].a_start + current_blockpos, 0,
+ 512, (char *) DIRECTORY_BUF);
+ }
+ else
+ {
+ /* errnum =ERR_FILE_NOT_FOUND; */
+ return NULL;
+ }
+ }
+
+ return &DIRECTORY_BUF[current_direntry++];
+}
+
+int
+vstafs_dir (char *dirname)
+{
+ char *fn, ch;
+ struct dir_entry *d;
+ /* int l, i, s; */
+
+ /*
+ * Read in the entries of the current directory.
+ */
+ f_sector = ROOT_SECTOR;
+ do
+ {
+ if (! (d = vstafs_readdir (f_sector)))
+ {
+ return 0;
+ }
+
+ /*
+ * Find the file in the path
+ */
+ while (*dirname == '/') dirname++;
+ fn = dirname;
+ while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++;
+ *fn = 0;
+
+ do
+ {
+ if (d->name[0] == 0 || d->name[0] & 0x80)
+ continue;
+
+#ifndef STAGE1_5
+ if (print_possibilities && ch != '/'
+ && (! *dirname || strcmp (dirname, d->name) <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+
+ printf (" %s", d->name);
+ }
+#endif
+ if (! grub_strcmp (dirname, d->name))
+ {
+ f_sector = d->start;
+ get_file_info (f_sector);
+ filemax = FILE_INFO->len;
+ break;
+ }
+ }
+ while ((d =vstafs_nextdir ()));
+
+ *(dirname = fn) = ch;
+ if (! d)
+ {
+ if (print_possibilities < 0)
+ {
+#ifndef STAGE1_5
+ putchar ('\n');
+#endif
+ return 1;
+ }
+
+ errnum = ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+ }
+ while (*dirname && ! isspace (ch));
+
+ return 1;
+}
+
+int
+vstafs_read (char *addr, int len)
+{
+ struct alloc *a2;
+ int size, ret = 0, offset, curr_len = 0;
+ int curr_ext2;
+ char extent;
+ int ext_size;
+ char *curr_pos;
+
+ get_file_info (f_sector);
+ size = FILE_INFO->len-VSTAFS_START_DATA;
+ a2 = FILE_INFO->blocks;
+
+ if (filepos > 0)
+ {
+ if (filepos < a2[0].a_len * 512 - VSTAFS_START_DATA)
+ {
+ offset = filepos + VSTAFS_START_DATA;
+ extent = 0;
+ curr_len = a2[0].a_len * 512 - offset - filepos;
+ }
+ else
+ {
+ ext_size = a2[0].a_len * 512 - VSTAFS_START_DATA;
+ offset = filepos - ext_size;
+ extent = 1;
+ do
+ {
+ curr_len -= ext_size;
+ offset -= ext_size;
+ ext_size = a2[extent+1].a_len * 512;
+ }
+ while (extent < FILE_INFO->extents && offset>ext_size);
+ }
+ }
+ else
+ {
+ offset = VSTAFS_START_DATA;
+ extent = 0;
+ curr_len = a2[0].a_len * 512 - offset;
+ }
+
+ curr_pos = addr;
+ if (curr_len > len)
+ curr_len = len;
+
+ for (curr_ext2=extent;
+ curr_ext2 < FILE_INFO->extents;
+ curr_len = a2[curr_ext].a_len * 512, curr_pos += curr_len, curr_ext2++)
+ {
+ ret += curr_len;
+ size -= curr_len;
+ if (size < 0)
+ {
+ ret += size;
+ curr_len += size;
+ }
+
+ devread (a2[curr_ext2].a_start,offset, curr_len, curr_pos);
+ offset = 0;
+ }
+
+ return ret;
+}
+
+#endif /* FSYS_VSTAFS */
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_xfs.c b/qemu/roms/openbios/fs/grubfs/fsys_xfs.c
new file mode 100644
index 000000000..b082621c7
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/fsys_xfs.c
@@ -0,0 +1,639 @@
+/* fsys_xfs.c - an implementation for the SGI XFS file system */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2001,2002 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef FSYS_XFS
+
+#include "shared.h"
+#include "filesys.h"
+#include "xfs.h"
+
+#define MAX_LINK_COUNT 8
+
+typedef struct xad {
+ xfs_fileoff_t offset;
+ xfs_fsblock_t start;
+ xfs_filblks_t len;
+} xad_t;
+
+struct xfs_info {
+ int bsize;
+ int dirbsize;
+ int isize;
+ unsigned int agblocks;
+ int bdlog;
+ int blklog;
+ int inopblog;
+ int agblklog;
+ int agnolog;
+ unsigned int nextents;
+ xfs_daddr_t next;
+ xfs_daddr_t daddr;
+ xfs_dablk_t forw;
+ xfs_dablk_t dablk;
+ xfs_bmbt_rec_32_t *xt;
+ xfs_bmbt_ptr_t ptr0;
+ int btnode_ptr0_off;
+ int i8param;
+ int dirpos;
+ int dirmax;
+ int blkoff;
+ int fpos;
+ xfs_ino_t rootino;
+};
+
+static struct xfs_info xfs;
+
+#define dirbuf ((char *)FSYS_BUF)
+#define filebuf ((char *)FSYS_BUF + 4096)
+#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
+#define icore (inode->di_core)
+
+#define mask32lo(n) (((__uint32_t)1 << (n)) - 1)
+
+#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1))
+#define XFS_INO_OFFSET_BITS xfs.inopblog
+#define XFS_INO_AGBNO_BITS xfs.agblklog
+#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog)
+#define XFS_INO_AGNO_BITS xfs.agnolog
+
+static inline xfs_agblock_t
+agino2agbno (xfs_agino_t agino)
+{
+ return agino >> XFS_INO_OFFSET_BITS;
+}
+
+static inline xfs_agnumber_t
+ino2agno (xfs_ino_t ino)
+{
+ return ino >> XFS_INO_AGINO_BITS;
+}
+
+static inline xfs_agino_t
+ino2agino (xfs_ino_t ino)
+{
+ return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
+}
+
+static inline int
+ino2offset (xfs_ino_t ino)
+{
+ return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
+}
+
+static inline __uint16_t
+le16 (__uint16_t x)
+{
+#ifdef __i386__
+ __asm__("xchgb %b0,%h0" \
+ : "=q" (x) \
+ : "0" (x)); \
+ return x;
+#else
+ return __be16_to_cpu(x);
+#endif
+}
+
+static inline __uint32_t
+le32 (__uint32_t x)
+{
+#ifdef __i386__
+#if 1
+ /* 386 doesn't have bswap. So what. */
+ __asm__("bswap %0" : "=r" (x) : "0" (x));
+#else
+ /* This is slower but this works on all x86 architectures. */
+ __asm__("xchgb %b0, %h0" \
+ "\n\troll $16, %0" \
+ "\n\txchgb %b0, %h0" \
+ : "=q" (x) : "0" (x));
+#endif
+ return x;
+#else
+ return __be32_to_cpu(x);
+#endif
+}
+
+static inline __uint64_t
+le64 (__uint64_t x)
+{
+ __uint32_t h = x >> 32;
+ __uint32_t l = x & ((1ULL<<32)-1);
+ return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h)));
+}
+
+
+static xfs_fsblock_t
+xt_start (xfs_bmbt_rec_32_t *r)
+{
+ return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) |
+ (((xfs_fsblock_t)le32 (r->l2)) << 11) |
+ (((xfs_fsblock_t)le32 (r->l3)) >> 21);
+}
+
+static xfs_fileoff_t
+xt_offset (xfs_bmbt_rec_32_t *r)
+{
+ return (((xfs_fileoff_t)le32 (r->l0) &
+ mask32lo(31)) << 23) |
+ (((xfs_fileoff_t)le32 (r->l1)) >> 9);
+}
+
+static xfs_filblks_t
+xt_len (xfs_bmbt_rec_32_t *r)
+{
+ return le32(r->l3) & mask32lo(21);
+}
+
+static inline int
+xfs_highbit32(__uint32_t v)
+{
+ int i;
+
+ if (--v) {
+ for (i = 0; i < 31; i++, v >>= 1) {
+ if (v == 0)
+ return i;
+ }
+ }
+ return 0;
+}
+
+static int
+isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
+{
+ return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
+}
+
+static xfs_daddr_t
+agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
+{
+ return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
+}
+
+static xfs_daddr_t
+fsb2daddr (xfs_fsblock_t fsbno)
+{
+ return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
+ (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
+}
+
+#undef offsetof
+#define offsetof(t,m) ((long)&(((t *)0)->m))
+
+static inline int
+btroot_maxrecs (void)
+{
+ int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
+
+ return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
+ (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
+}
+
+static int
+di_read (xfs_ino_t ino)
+{
+ xfs_agino_t agino;
+ xfs_agnumber_t agno;
+ xfs_agblock_t agbno;
+ xfs_daddr_t daddr;
+ int offset;
+
+ agno = ino2agno (ino);
+ agino = ino2agino (ino);
+ agbno = agino2agbno (agino);
+ offset = ino2offset (ino);
+ daddr = agb2daddr (agno, agbno);
+
+ devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
+
+ xfs.ptr0 = *(xfs_bmbt_ptr_t *)
+ (inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
+ + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
+
+ return 1;
+}
+
+static void
+init_extents (void)
+{
+ xfs_bmbt_ptr_t ptr0;
+ xfs_btree_lblock_t h;
+
+ switch (icore.di_format) {
+ case XFS_DINODE_FMT_EXTENTS:
+ xfs.xt = inode->di_u.di_bmx;
+ xfs.nextents = le32 (icore.di_nextents);
+ break;
+ case XFS_DINODE_FMT_BTREE:
+ ptr0 = xfs.ptr0;
+ for (;;) {
+ xfs.daddr = fsb2daddr (le64(ptr0));
+ devread (xfs.daddr, 0,
+ sizeof(xfs_btree_lblock_t), (char *)&h);
+ if (!h.bb_level) {
+ xfs.nextents = le16(h.bb_numrecs);
+ xfs.next = fsb2daddr (le64(h.bb_rightsib));
+ xfs.fpos = sizeof(xfs_btree_block_t);
+ return;
+ }
+ devread (xfs.daddr, xfs.btnode_ptr0_off,
+ sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
+ }
+ }
+}
+
+static xad_t *
+next_extent (void)
+{
+ static xad_t xad;
+
+ switch (icore.di_format) {
+ case XFS_DINODE_FMT_EXTENTS:
+ if (xfs.nextents == 0)
+ return NULL;
+ break;
+ case XFS_DINODE_FMT_BTREE:
+ if (xfs.nextents == 0) {
+ xfs_btree_lblock_t h;
+ if (xfs.next == 0)
+ return NULL;
+ xfs.daddr = xfs.next;
+ devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
+ xfs.nextents = le16(h.bb_numrecs);
+ xfs.next = fsb2daddr (le64(h.bb_rightsib));
+ xfs.fpos = sizeof(xfs_btree_block_t);
+ }
+ /* Yeah, I know that's slow, but I really don't care */
+ devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
+ xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
+ xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
+ }
+ xad.offset = xt_offset (xfs.xt);
+ xad.start = xt_start (xfs.xt);
+ xad.len = xt_len (xfs.xt);
+ ++xfs.xt;
+ --xfs.nextents;
+
+ return &xad;
+}
+
+/*
+ * Name lies - the function reads only first 100 bytes
+ */
+static void
+xfs_dabread (void)
+{
+ xad_t *xad;
+ xfs_fileoff_t offset;;
+
+ init_extents ();
+ while ((xad = next_extent ())) {
+ offset = xad->offset;
+ if (isinxt (xfs.dablk, offset, xad->len)) {
+ devread (fsb2daddr (xad->start + xfs.dablk - offset),
+ 0, 100, dirbuf);
+ break;
+ }
+ }
+}
+
+static inline xfs_ino_t
+sf_ino (char *sfe, int namelen)
+{
+ void *p = sfe + namelen + 3;
+
+ return (xfs.i8param == 0)
+ ? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p);
+}
+
+static inline xfs_ino_t
+sf_parent_ino (void)
+{
+ return (xfs.i8param == 0)
+ ? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
+ : le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
+}
+
+static inline int
+roundup8 (int n)
+{
+ return ((n+7)&~7);
+}
+
+static char *
+next_dentry (xfs_ino_t *ino)
+{
+ int namelen = 1;
+ int toread;
+ static char *usual[2];
+ static xfs_dir2_sf_entry_t *sfe;
+ char *name;
+
+ if (!usual[0]) {
+ usual[0] = strdup(".");
+ usual[1] = strdup("..");
+ }
+ name = usual[0];
+
+ if (xfs.dirpos >= xfs.dirmax) {
+ if (xfs.forw == 0)
+ return NULL;
+ xfs.dablk = xfs.forw;
+ xfs_dabread ();
+#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
+ xfs.dirmax = le16 (h->count) - le16 (h->stale);
+ xfs.forw = le32 (h->info.forw);
+#undef h
+ xfs.dirpos = 0;
+ }
+
+ switch (icore.di_format) {
+ case XFS_DINODE_FMT_LOCAL:
+ switch (xfs.dirpos) {
+ case -2:
+ *ino = 0;
+ break;
+ case -1:
+ *ino = sf_parent_ino ();
+ ++name;
+ ++namelen;
+ sfe = (xfs_dir2_sf_entry_t *)
+ (inode->di_u.di_c
+ + sizeof(xfs_dir2_sf_hdr_t)
+ - xfs.i8param);
+ break;
+ default:
+ namelen = sfe->namelen;
+ *ino = sf_ino ((char *)sfe, namelen);
+ name = (char *)sfe->name;
+ sfe = (xfs_dir2_sf_entry_t *)
+ ((char *)sfe + namelen + 11 - xfs.i8param);
+ }
+ break;
+ case XFS_DINODE_FMT_BTREE:
+ case XFS_DINODE_FMT_EXTENTS:
+#define dau ((xfs_dir2_data_union_t *)dirbuf)
+ for (;;) {
+ if (xfs.blkoff >= xfs.dirbsize) {
+ xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
+ filepos &= ~(xfs.dirbsize - 1);
+ filepos |= xfs.blkoff;
+ }
+ xfs_read (dirbuf, 4);
+ xfs.blkoff += 4;
+ if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
+ toread = roundup8 (le16(dau->unused.length)) - 4;
+ xfs.blkoff += toread;
+ filepos += toread;
+ continue;
+ }
+ break;
+ }
+ xfs_read ((char *)dirbuf + 4, 5);
+ *ino = le64 (dau->entry.inumber);
+ namelen = dau->entry.namelen;
+#undef dau
+ toread = roundup8 (namelen + 11) - 9;
+ xfs_read (dirbuf, toread);
+ name = (char *)dirbuf;
+ xfs.blkoff += toread + 5;
+ }
+ ++xfs.dirpos;
+ name[namelen] = 0;
+
+ return name;
+}
+
+static char *
+first_dentry (xfs_ino_t *ino)
+{
+ xfs.forw = 0;
+ switch (icore.di_format) {
+ case XFS_DINODE_FMT_LOCAL:
+ xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
+ xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
+ xfs.dirpos = -2;
+ break;
+ case XFS_DINODE_FMT_EXTENTS:
+ case XFS_DINODE_FMT_BTREE:
+ filepos = 0;
+ xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
+ if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
+#define tail ((xfs_dir2_block_tail_t *)dirbuf)
+ filepos = xfs.dirbsize - sizeof(*tail);
+ xfs_read (dirbuf, sizeof(*tail));
+ xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
+#undef tail
+ } else {
+ xfs.dablk = (1ULL << 35) >> xfs.blklog;
+#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
+#define n ((xfs_da_intnode_t *)dirbuf)
+ for (;;) {
+ xfs_dabread ();
+ if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
+ || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
+ xfs.dirmax = le16 (h->count) - le16 (h->stale);
+ xfs.forw = le32 (h->info.forw);
+ break;
+ }
+ xfs.dablk = le32 (n->btree[0].before);
+ }
+#undef n
+#undef h
+ }
+ xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
+ filepos = xfs.blkoff;
+ xfs.dirpos = 0;
+ }
+ return next_dentry (ino);
+}
+
+int
+xfs_mount (void)
+{
+ xfs_sb_t super;
+
+ if (!devread (0, 0, sizeof(super), (char *)&super)
+ || (le32(super.sb_magicnum) != XFS_SB_MAGIC)
+ || ((le16(super.sb_versionnum)
+ & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
+ return 0;
+ }
+
+ xfs.bsize = le32 (super.sb_blocksize);
+ xfs.blklog = super.sb_blocklog;
+ xfs.bdlog = xfs.blklog - SECTOR_BITS;
+ xfs.rootino = le64 (super.sb_rootino);
+ xfs.isize = le16 (super.sb_inodesize);
+ xfs.agblocks = le32 (super.sb_agblocks);
+ xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
+
+ xfs.inopblog = super.sb_inopblog;
+ xfs.agblklog = super.sb_agblklog;
+ xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
+
+ xfs.btnode_ptr0_off =
+ ((xfs.bsize - sizeof(xfs_btree_block_t)) /
+ (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
+ * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
+
+ return 1;
+}
+
+int
+xfs_read (char *buf, int len)
+{
+ xad_t *xad;
+ xfs_fileoff_t endofprev, endofcur, offset;
+ xfs_filblks_t xadlen;
+ int toread, startpos, endpos;
+
+ if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
+ grub_memmove (buf, inode->di_u.di_c + filepos, len);
+ filepos += len;
+ return len;
+ }
+
+ startpos = filepos;
+ endpos = filepos + len;
+ endofprev = (xfs_fileoff_t)-1;
+ init_extents ();
+ while (len > 0 && (xad = next_extent ())) {
+ offset = xad->offset;
+ xadlen = xad->len;
+ if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
+ endofcur = (offset + xadlen) << xfs.blklog;
+ toread = (endofcur >= endpos)
+ ? len : (endofcur - filepos);
+
+ disk_read_func = disk_read_hook;
+ devread (fsb2daddr (xad->start),
+ filepos - (offset << xfs.blklog), toread, buf);
+ disk_read_func = NULL;
+
+ buf += toread;
+ len -= toread;
+ filepos += toread;
+ } else if (offset > endofprev) {
+ toread = ((offset << xfs.blklog) >= endpos)
+ ? len : ((offset - endofprev) << xfs.blklog);
+ len -= toread;
+ filepos += toread;
+ for (; toread; toread--) {
+ *buf++ = 0;
+ }
+ continue;
+ }
+ endofprev = offset + xadlen;
+ }
+
+ return filepos - startpos;
+}
+
+int
+xfs_dir (char *dirname)
+{
+ xfs_ino_t ino, parent_ino, new_ino;
+ xfs_fsize_t di_size;
+ int di_mode;
+ int cmp, n, link_count;
+ char linkbuf[xfs.bsize];
+ char *rest, *name, ch;
+
+ parent_ino = ino = xfs.rootino;
+ link_count = 0;
+ for (;;) {
+ di_read (ino);
+ di_size = le64 (icore.di_size);
+ di_mode = le16 (icore.di_mode);
+
+ if ((di_mode & IFMT) == IFLNK) {
+ if (++link_count > MAX_LINK_COUNT) {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+ if (di_size < xfs.bsize - 1) {
+ filepos = 0;
+ filemax = di_size;
+ n = xfs_read (linkbuf, filemax);
+ } else {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
+ while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
+ linkbuf[n] = 0;
+ dirname = linkbuf;
+ continue;
+ }
+
+ if (!*dirname || isspace (*dirname)) {
+ if ((di_mode & IFMT) != IFREG) {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ filepos = 0;
+ filemax = di_size;
+ return 1;
+ }
+
+ if ((di_mode & IFMT) != IFDIR) {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ for (; *dirname == '/'; dirname++);
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+ *rest = 0;
+
+ name = first_dentry (&new_ino);
+ for (;;) {
+ cmp = (!*dirname) ? -1 : substring (dirname, name);
+#ifndef STAGE1_5
+ if (print_possibilities && ch != '/' && cmp <= 0) {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (name);
+ } else
+#endif
+ if (cmp == 0) {
+ parent_ino = ino;
+ if (new_ino)
+ ino = new_ino;
+ *(dirname = rest) = ch;
+ break;
+ }
+ name = next_dentry (&new_ino);
+ if (name == NULL) {
+ if (print_possibilities < 0)
+ return 1;
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+ }
+ }
+ }
+}
+
+#endif /* FSYS_XFS */
diff --git a/qemu/roms/openbios/fs/grubfs/glue.h b/qemu/roms/openbios/fs/grubfs/glue.h
new file mode 100644
index 000000000..7f2129372
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/glue.h
@@ -0,0 +1,48 @@
+#ifndef __GLUE_H
+#define __GLUE_H
+
+#include "asm/types.h"
+#include "config.h"
+#include "libc/byteorder.h"
+
+typedef uint64_t sector_t;
+
+int devopen(void);
+
+int devread(unsigned long sector, unsigned long byte_offset,
+ unsigned long byte_len, void *buf);
+
+int file_open(const char *filename);
+int file_read(void *buf, unsigned long len);
+int file_seek(unsigned long offset);
+unsigned long file_size(void);
+void file_close(void);
+
+int mount_fs(void);
+
+extern int using_devsize;
+
+/*
+ * some of the filesystem drivers don't correctly provide their
+ * prototypes. we fix this here so we can leave them untouched.
+ */
+
+int ffs_mount (void);
+int ffs_read (char *buf, int len);
+int ffs_dir (char *dirname);
+int ffs_embed (int *start_sector, int needed_sectors);
+
+int vstafs_mount (void);
+int vstafs_dir (char *dirname);
+int vstafs_read (char *addr, int len);
+
+int ntfs_mount (void);
+int ntfs_dir (char *dirname);
+int ntfs_read (char *addr, int len);
+
+int affs_mount (void);
+int affs_dir (char *dirname);
+int affs_read (char *addr, int len);
+
+
+#endif /* FS_H */
diff --git a/qemu/roms/openbios/fs/grubfs/grubfs_fs.c b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c
new file mode 100644
index 000000000..acd2a6441
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c
@@ -0,0 +1,398 @@
+/*
+ * /packages/grubfs-files
+ *
+ * grub vfs
+ *
+ * Copyright (C) 2004 Stefan Reinauer
+ * Copyright (C) 2004 Samuel Rydh
+ * Copyright (C) 2010 Mark Cave-Ayland
+ *
+ * inspired by HFS code from Samuel Rydh
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "fs/fs.h"
+#include "filesys.h"
+#include "glue.h"
+#include "libc/diskio.h"
+#include "libc/vsprintf.h"
+
+extern void grubfs_init( void );
+
+/************************************************************************/
+/* grub GLOBALS (horrible... but difficult to fix) */
+/************************************************************************/
+
+/* the grub drivers want these: */
+int filepos;
+int filemax;
+grub_error_t errnum;
+char FSYS_BUF[FSYS_BUFLEN];
+
+/* these are not even used by us, instead
+ * the grub fs drivers want them:
+ */
+int fsmax;
+void (*disk_read_hook) (int, int, int);
+void (*disk_read_func) (int, int, int);
+
+
+/************************************************************************/
+/* filsystem table */
+/************************************************************************/
+
+typedef struct fsys_entry {
+ const char *name;
+ int (*mount_func) (void);
+ int (*read_func) (char *buf, int len);
+ int (*dir_func) (char *dirname);
+ void (*close_func) (void);
+ int (*embed_func) (int *start_sector, int needed_sectors);
+} fsys_entry_t;
+
+static const struct fsys_entry fsys_table[] = {
+# ifdef CONFIG_FSYS_FAT
+ {"fat", fat_mount, fat_read, fat_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_EXT2FS
+ {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_MINIX
+ {"minix", minix_mount, minix_read, minix_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_REISERFS
+ {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, NULL, reiserfs_embed},
+# endif
+# ifdef CONFIG_FSYS_JFS
+ {"jfs", jfs_mount, jfs_read, jfs_dir, NULL, jfs_embed},
+# endif
+# ifdef CONFIG_FSYS_XFS
+ {"xfs", xfs_mount, xfs_read, xfs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_UFS
+ {"ufs", ufs_mount, ufs_read, ufs_dir, NULL, ufs_embed},
+# endif
+# ifdef CONFIG_FSYS_ISO9660
+ {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_NTFS
+ {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_AFFS
+ {"affs", affs_mount, affs_read, affs_dir, NULL, NULL},
+# endif
+};
+
+/* We don't provide a file search mechanism (yet) */
+typedef struct {
+ unsigned long pos;
+ unsigned long len;
+ const char *path;
+} grubfile_t;
+
+typedef struct {
+ const struct fsys_entry *fsys;
+ grubfile_t *fd;
+ int dev_fd;
+ long long offset; /* Offset added onto each device read; should only ever be non-zero
+ when probing a partition for a filesystem */
+} grubfs_t;
+
+typedef struct {
+ grubfs_t *gfs;
+} grubfs_info_t;
+
+/* Static block and global pointer required for I/O glue */
+static grubfs_t dummy_fs;
+static grubfs_t *curfs = &dummy_fs;
+
+DECLARE_NODE( grubfs, 0, sizeof(grubfs_info_t), "+/packages/grubfs-files" );
+
+
+/************************************************************************/
+/* I/O glue (called by grub source) */
+/************************************************************************/
+
+int
+devread( unsigned long sector, unsigned long byte_offset,
+ unsigned long byte_len, void *buf )
+{
+ long long offs = (long long)sector * 512 + byte_offset;
+
+#ifdef CONFIG_DEBUG_FS
+ //printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd);
+#endif
+
+ if( !curfs ) {
+#ifdef CONFIG_DEBUG_FS
+ printk("devread: fsys == NULL!\n");
+#endif
+ return -1;
+ }
+
+ if( seek_io(curfs->dev_fd, offs + curfs->offset) ) {
+#ifdef CONFIG_DEBUG_FS
+ printk("seek failure\n");
+#endif
+ return -1;
+ }
+ return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0;
+}
+
+int
+file_read( void *buf, unsigned long len )
+{
+ if (filepos < 0 || filepos > filemax)
+ filepos = filemax;
+ if (len > filemax-filepos)
+ len = filemax - filepos;
+ errnum = 0;
+ return curfs->fsys->read_func( buf, len );
+}
+
+
+/************************************************************************/
+/* Standard package methods */
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+grubfs_files_open( grubfs_info_t *mi )
+{
+ int fd, i;
+ char *path = my_args_copy();
+ char *s;
+
+ fd = open_ih( my_parent() );
+ if ( fd == -1 ) {
+ free( path );
+ RET( 0 );
+ }
+
+ mi->gfs = &dummy_fs;
+
+ for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
+#ifdef CONFIG_DEBUG_FS
+ printk("Trying %s\n", fsys_table[i].name);
+#endif
+ if (fsys_table[i].mount_func()) {
+ const fsys_entry_t *fsys = &fsys_table[i];
+#ifdef CONFIG_DEBUG_FS
+ printk("Mounted %s\n", fsys->name);
+#endif
+ mi->gfs = malloc(sizeof(grubfs_t));
+ mi->gfs->fsys = fsys;
+ mi->gfs->dev_fd = fd;
+ mi->gfs->offset = 0;
+
+ s = path;
+ while (*s) {
+ if(*s=='\\') *s='/';
+ s++;
+ }
+#ifdef CONFIG_DEBUG_FS
+ printk("Path=%s\n",path);
+#endif
+ if (!mi->gfs->fsys->dir_func((char *) path)) {
+ forth_printf("File not found\n");
+ RET( 0 );
+ }
+
+ mi->gfs->fd = malloc(sizeof(grubfile_t));
+ mi->gfs->fd->pos = filepos;
+ mi->gfs->fd->len = filemax;
+ mi->gfs->fd->path = strdup(path);
+
+ RET( -1 );
+ }
+ }
+#ifdef CONFIG_DEBUG_FS
+ printk("Unknown filesystem type\n");
+#endif
+
+ RET( 0 );
+}
+
+/* ( -- ) */
+static void
+grubfs_files_close( grubfs_info_t *mi )
+{
+ grubfile_t *gf = mi->gfs->fd;
+
+ if (gf->path)
+ free((void *)(gf->path));
+ free(gf);
+
+ filepos = 0;
+ filemax = 0;
+}
+
+/* ( buf len -- actlen ) */
+static void
+grubfs_files_read( grubfs_info_t *mi )
+{
+ int count = POP();
+ char *buf = (char *)cell2pointer(POP());
+
+ grubfile_t *file = mi->gfs->fd;
+ int ret;
+
+ filepos = file->pos;
+ filemax = file->len;
+
+ if (count > filemax - filepos)
+ count = filemax - filepos;
+
+ ret = mi->gfs->fsys->read_func(buf, count);
+
+ file->pos = filepos;
+
+ RET( ret );
+}
+
+/* ( pos.d -- status ) */
+static void
+grubfs_files_seek( grubfs_info_t *mi )
+{
+ long long pos = DPOP();
+ int offs = (int)pos;
+ int whence = SEEK_SET;
+
+ grubfile_t *file = mi->gfs->fd;
+ unsigned long newpos;
+
+ switch( whence ) {
+ case SEEK_END:
+ if (offs < 0 && (unsigned long) -offs > file->len)
+ newpos = 0;
+ else
+ newpos = file->len + offs;
+ break;
+ default:
+ case SEEK_SET:
+ newpos = (offs < 0) ? 0 : offs;
+ break;
+ }
+
+ if (newpos > file->len)
+ newpos = file->len;
+
+ file->pos = newpos;
+
+ if (newpos)
+ RET( -1 );
+ else
+ RET( 0 );
+}
+
+/* ( addr -- size ) */
+static void
+grubfs_files_load( grubfs_info_t *mi )
+{
+ char *buf = (char *)cell2pointer(POP());
+ int count, ret;
+
+ grubfile_t *file = mi->gfs->fd;
+ count = file->len;
+
+ ret = mi->gfs->fsys->read_func(buf, count);
+ file->pos = filepos;
+
+ RET( ret );
+}
+
+/* ( -- cstr ) */
+static void
+grubfs_files_get_path( grubfs_info_t *mi )
+{
+ grubfile_t *file = mi->gfs->fd;
+ const char *path = file->path;
+
+ RET( pointer2cell(strdup(path)) );
+}
+
+/* ( -- cstr ) */
+static void
+grubfs_files_get_fstype( grubfs_info_t *mi )
+{
+ grubfs_t *gfs = mi->gfs;
+
+ PUSH( pointer2cell(strdup(gfs->fsys->name)) );
+}
+
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+grubfs_files_probe( grubfs_info_t *dummy )
+{
+ ihandle_t ih = POP_ih();
+ long long offs = DPOP();
+ int i;
+
+ curfs->dev_fd = open_ih(ih);
+ if (curfs->dev_fd == -1) {
+ RET( -1 );
+ }
+ curfs->offset = offs;
+
+ for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
+#ifdef CONFIG_DEBUG_FS
+ printk("Probing for %s\n", fsys_table[i].name);
+#endif
+ if (fsys_table[i].mount_func()) {
+ RET( -1 );
+ }
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ printk("Unknown filesystem type\n");
+#endif
+
+ close_io(curfs->dev_fd);
+
+ RET ( 0 );
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+grubfs_files_dir( grubfs_info_t *dummy )
+{
+ forth_printf("dir method not implemented for grubfs filesystem\n");
+ POP();
+ POP();
+ POP();
+}
+
+static void
+grubfs_initializer( grubfs_info_t *dummy )
+{
+ fword("register-fs-package");
+}
+
+NODE_METHODS( grubfs ) = {
+ { "probe", grubfs_files_probe },
+ { "open", grubfs_files_open },
+ { "close", grubfs_files_close },
+ { "read", grubfs_files_read },
+ { "seek", grubfs_files_seek },
+ { "load", grubfs_files_load },
+ { "dir", grubfs_files_dir },
+
+ /* special */
+ { "get-path", grubfs_files_get_path },
+ { "get-fstype", grubfs_files_get_fstype },
+
+ { NULL, grubfs_initializer },
+};
+
+void
+grubfs_init( void )
+{
+ REGISTER_NODE( grubfs );
+}
diff --git a/qemu/roms/openbios/fs/grubfs/iso9660.h b/qemu/roms/openbios/fs/grubfs/iso9660.h
new file mode 100644
index 000000000..6423a8f68
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/iso9660.h
@@ -0,0 +1,167 @@
+/*
+ * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
+ * including Rock Ridge Extensions support
+ *
+ * Copyright (C) 1998, 1999 Kousuke Takai <tak@kmc.kyoto-u.ac.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+/*
+ * References:
+ * linux/fs/isofs/rock.[ch]
+ * mkisofs-1.11.1/diag/isoinfo.c
+ * mkisofs-1.11.1/iso9660.h
+ * (all are written by Eric Youngdale)
+ */
+
+/*
+ * Modified by SONE Takeshi to work with FILO
+ */
+
+#ifndef _ISO9660_H_
+#define _ISO9660_H_
+
+#define ISO_SECTOR_BITS (11)
+#define ISO_SECTOR_SIZE (1<<ISO_SECTOR_BITS)
+
+#define ISO_REGULAR 1 /* regular file */
+#define ISO_DIRECTORY 2 /* directory */
+#define ISO_OTHER 0 /* other file (with Rock Ridge) */
+
+#define RR_FLAG_PX 0x01 /* have POSIX file attributes */
+#define RR_FLAG_NM 0x08 /* have alternate file name */
+
+/* POSIX file attributes for Rock Ridge extensions */
+#define POSIX_S_IFMT 0xF000
+#define POSIX_S_IFREG 0x8000
+#define POSIX_S_IFDIR 0x4000
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+#ifndef ASM_FILE
+
+typedef union {
+ uint8_t l,b;
+} iso_8bit_t;
+
+typedef struct __iso_16bit {
+ uint16_t l, b;
+} iso_16bit_t;
+
+typedef struct __iso_32bit {
+ uint32_t l, b;
+} iso_32bit_t;
+
+typedef uint8_t iso_date_t[7];
+
+struct iso_directory_record {
+ iso_8bit_t length;
+ iso_8bit_t ext_attr_length;
+ iso_32bit_t extent;
+ iso_32bit_t size;
+ iso_date_t date;
+ iso_8bit_t flags;
+ iso_8bit_t file_unit_size;
+ iso_8bit_t interleave;
+ iso_16bit_t volume_seq_number;
+ iso_8bit_t name_len;
+ uint8_t name[1];
+} __attribute__ ((packed));
+
+struct iso_primary_descriptor {
+ iso_8bit_t type;
+ uint8_t id[5];
+ iso_8bit_t version;
+ uint8_t _unused1[1];
+ uint8_t system_id[32];
+ uint8_t volume_id[32];
+ uint8_t _unused2[8];
+ iso_32bit_t volume_space_size;
+ uint8_t _unused3[32];
+ iso_16bit_t volume_set_size;
+ iso_16bit_t volume_seq_number;
+ iso_16bit_t logical_block_size;
+ iso_32bit_t path_table_size;
+ uint8_t type_l_path_table[4];
+ uint8_t opt_type_l_path_table[4];
+ uint8_t type_m_path_table[4];
+ uint8_t opt_type_m_path_table[4];
+ struct iso_directory_record root_directory_record;
+ uint8_t volume_set_id[128];
+ uint8_t publisher_id[128];
+ uint8_t preparer_id[128];
+ uint8_t application_id[128];
+ uint8_t copyright_file_id[37];
+ uint8_t abstract_file_id[37];
+ uint8_t bibliographic_file_id[37];
+ uint8_t creation_date[17];
+ uint8_t modification_date[17];
+ uint8_t expiration_date[17];
+ uint8_t effective_date[17];
+ iso_8bit_t file_structure_version;
+ uint8_t _unused4[1];
+ uint8_t application_data[512];
+ uint8_t _unused5[653];
+} __attribute__ ((packed));
+
+struct rock_ridge {
+ uint16_t signature;
+ uint8_t len;
+ uint8_t version;
+ union {
+ struct CE {
+ iso_32bit_t extent;
+ iso_32bit_t offset;
+ iso_32bit_t size;
+ } ce;
+ struct NM {
+ iso_8bit_t flags;
+ uint8_t name[0];
+ } nm;
+ struct PX {
+ iso_32bit_t mode;
+ iso_32bit_t nlink;
+ iso_32bit_t uid;
+ iso_32bit_t gid;
+ } px;
+ struct RR {
+ iso_8bit_t flags;
+ } rr;
+ } u;
+} __attribute__ ((packed));
+
+typedef union RR_ptr {
+ struct rock_ridge *rr;
+ char *ptr;
+ int i;
+} RR_ptr_t;
+
+#define CHECK2(ptr, c1, c2) \
+ (*(unsigned char *)(ptr) == (c1) && \
+ *((unsigned char *)(ptr) + 1) == (c2))
+#define CHECK4(ptr, c1, c2, c3, c4) \
+ (*(unsigned char *)(ptr) == (c1) && \
+ *((unsigned char *)(ptr) + 1) == (c2) && \
+ *((unsigned char *)(ptr) + 2) == (c3) && \
+ *((unsigned char *)(ptr) + 3) == (c4))
+
+#endif /* !ASM_FILE */
+
+#endif /* _ISO9660_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/jfs.h b/qemu/roms/openbios/fs/grubfs/jfs.h
new file mode 100644
index 000000000..afe7263d2
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/jfs.h
@@ -0,0 +1,604 @@
+/* jfs.h - an extractions from linux/include/linux/jfs/jfs* into one file */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000 International Business Machines Corp.
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef _JFS_H_
+#define _JFS_H_
+
+/* those are from jfs_filsys.h */
+
+/*
+ * file system option (superblock flag)
+ */
+/* platform option (conditional compilation) */
+#define JFS_AIX 0x80000000 /* AIX support */
+/* POSIX name/directory support */
+
+#define JFS_OS2 0x40000000 /* OS/2 support */
+/* case-insensitive name/directory support */
+
+#define JFS_LINUX 0x10000000 /* Linux support */
+/* case-sensitive name/directory support */
+
+/* directory option */
+#define JFS_UNICODE 0x00000001 /* unicode name */
+
+/* bba */
+#define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */
+
+
+/*
+ * buffer cache configuration
+ */
+/* page size */
+#ifdef PSIZE
+#undef PSIZE
+#endif
+#define PSIZE 4096 /* page size (in byte) */
+
+/*
+ * fs fundamental size
+ *
+ * PSIZE >= file system block size >= PBSIZE >= DISIZE
+ */
+#define PBSIZE 512 /* physical block size (in byte) */
+#define DISIZE 512 /* on-disk inode size (in byte) */
+#define L2DISIZE 9
+#define INOSPERIAG 4096 /* number of disk inodes per iag */
+#define L2INOSPERIAG 12
+#define INOSPEREXT 32 /* number of disk inode per extent */
+#define L2INOSPEREXT 5
+
+/* Minimum number of bytes supported for a JFS partition */
+#define MINJFS (0x1000000)
+
+/*
+ * fixed byte offset address
+ */
+#define SUPER1_OFF 0x8000 /* primary superblock */
+
+#define AITBL_OFF (SUPER1_OFF + PSIZE + (PSIZE << 1))
+
+/*
+ * fixed reserved inode number
+ */
+/* aggregate inode */
+#define AGGREGATE_I 1 /* aggregate inode map inode */
+#define FILESYSTEM_I 16 /* 1st/only fileset inode in ait:
+ * fileset inode map inode
+ */
+
+/* per fileset inode */
+#define ROOT_I 2 /* fileset root inode */
+
+/*
+ * directory configuration
+ */
+#define JFS_NAME_MAX 255
+#define JFS_PATH_MAX PSIZE
+
+#if 0
+typedef unsigned char u8;
+typedef char s8;
+typedef unsigned short u16;
+typedef short s16;
+typedef unsigned int u32;
+typedef int s32;
+typedef unsigned long long u64;
+typedef long long s64;
+#endif
+
+typedef u16 UniChar;
+
+/* these from jfs_btree.h */
+
+/* btpaget_t flag */
+#define BT_TYPE 0x07 /* B+-tree index */
+#define BT_ROOT 0x01 /* root page */
+#define BT_LEAF 0x02 /* leaf page */
+#define BT_INTERNAL 0x04 /* internal page */
+#define BT_RIGHTMOST 0x10 /* rightmost page */
+#define BT_LEFTMOST 0x20 /* leftmost page */
+
+/* those are from jfs_types.h */
+
+struct timestruc_t {
+ u32 tv_sec;
+ u32 tv_nsec;
+};
+
+/*
+ * physical xd (pxd)
+ */
+typedef struct {
+ unsigned len:24;
+ unsigned addr1:8;
+ u32 addr2;
+} pxd_t;
+
+/* xd_t field extraction */
+#define lengthPXD(pxd) ((pxd)->len)
+#define addressPXD(pxd) (((s64)((pxd)->addr1)) << 32 | ((pxd)->addr2))
+
+/*
+ * data extent descriptor (dxd)
+ */
+typedef struct {
+ unsigned flag:8; /* 1: flags */
+ unsigned rsrvd:24; /* 3: */
+ u32 size; /* 4: size in byte */
+ unsigned len:24; /* 3: length in unit of fsblksize */
+ unsigned addr1:8; /* 1: address in unit of fsblksize */
+ u32 addr2; /* 4: address in unit of fsblksize */
+} dxd_t; /* - 16 - */
+
+/*
+ * DASD limit information - stored in directory inode
+ */
+typedef struct dasd {
+ u8 thresh; /* Alert Threshold (in percent) */
+ u8 delta; /* Alert Threshold delta (in percent) */
+ u8 rsrvd1;
+ u8 limit_hi; /* DASD limit (in logical blocks) */
+ u32 limit_lo; /* DASD limit (in logical blocks) */
+ u8 rsrvd2[3];
+ u8 used_hi; /* DASD usage (in logical blocks) */
+ u32 used_lo; /* DASD usage (in logical blocks) */
+} dasd_t;
+
+
+/* from jfs_superblock.h */
+
+#define JFS_MAGIC 0x3153464A /* "JFS1" */
+
+struct jfs_superblock
+{
+ u32 s_magic; /* 4: magic number */
+ u32 s_version; /* 4: version number */
+
+ s64 s_size; /* 8: aggregate size in hardware/LVM blocks;
+ * VFS: number of blocks
+ */
+ s32 s_bsize; /* 4: aggregate block size in bytes;
+ * VFS: fragment size
+ */
+ s16 s_l2bsize; /* 2: log2 of s_bsize */
+ s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
+ s32 s_pbsize; /* 4: hardware/LVM block size in bytes */
+ s16 s_l2pbsize; /* 2: log2 of s_pbsize */
+ s16 pad; /* 2: padding necessary for alignment */
+
+ u32 s_agsize; /* 4: allocation group size in aggr. blocks */
+
+ u32 s_flag; /* 4: aggregate attributes:
+ * see jfs_filsys.h
+ */
+ u32 s_state; /* 4: mount/unmount/recovery state:
+ * see jfs_filsys.h
+ */
+ s32 s_compress; /* 4: > 0 if data compression */
+
+ pxd_t s_ait2; /* 8: first extent of secondary
+ * aggregate inode table
+ */
+
+ pxd_t s_aim2; /* 8: first extent of secondary
+ * aggregate inode map
+ */
+ u32 s_logdev; /* 4: device address of log */
+ s32 s_logserial; /* 4: log serial number at aggregate mount */
+ pxd_t s_logpxd; /* 8: inline log extent */
+
+ pxd_t s_fsckpxd; /* 8: inline fsck work space extent */
+
+ struct timestruc_t s_time; /* 8: time last updated */
+
+ s32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for
+ * the fsck service log.
+ * N.B. These blocks are divided among the
+ * versions kept. This is not a per
+ * version size.
+ * N.B. These blocks are included in the
+ * length field of s_fsckpxd.
+ */
+ s8 s_fscklog; /* 1: which fsck service log is most recent
+ * 0 => no service log data yet
+ * 1 => the first one
+ * 2 => the 2nd one
+ */
+ char s_fpack[11]; /* 11: file system volume name
+ * N.B. This must be 11 bytes to
+ * conform with the OS/2 BootSector
+ * requirements
+ */
+
+ /* extendfs() parameter under s_state & FM_EXTENDFS */
+ s64 s_xsize; /* 8: extendfs s_size */
+ pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */
+ pxd_t s_xlogpxd; /* 8: extendfs logpxd */
+ /* - 128 byte boundary - */
+
+ /*
+ * DFS VFS support (preliminary)
+ */
+ char s_attach; /* 1: VFS: flag: set when aggregate is attached
+ */
+ u8 rsrvd4[7]; /* 7: reserved - set to 0 */
+
+ u64 totalUsable; /* 8: VFS: total of 1K blocks which are
+ * available to "normal" (non-root) users.
+ */
+ u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for
+ * exclusive use of root. This value can be 0,
+ * and if it is then totalUsable will be equal
+ * to # of blocks in aggregate. I believe this
+ * means that minFree + totalUsable = # blocks.
+ * In that case, we don't need to store both
+ * totalUsable and minFree since we can compute
+ * one from the other. I would guess minFree
+ * would be the one we should store, and
+ * totalUsable would be the one we should
+ * compute. (Just a guess...)
+ */
+
+ u64 realFree; /* 8: VFS: # of free 1K blocks can be used by
+ * "normal" users. It may be this is something
+ * we should compute when asked for instead of
+ * storing in the superblock. I don't know how
+ * often this information is needed.
+ */
+ /*
+ * graffiti area
+ */
+};
+
+/* from jfs_dtree.h */
+
+/*
+ * entry segment/slot
+ *
+ * an entry consists of type dependent head/only segment/slot and
+ * additional segments/slots linked vi next field;
+ * N.B. last/only segment of entry is terminated by next = -1;
+ */
+/*
+ * directory page slot
+ */
+typedef struct {
+ s8 next; /* 1: */
+ s8 cnt; /* 1: */
+ UniChar name[15]; /* 30: */
+} dtslot_t; /* (32) */
+
+#define DTSLOTDATALEN 15
+
+/*
+ * internal node entry head/only segment
+ */
+typedef struct {
+ pxd_t xd; /* 8: child extent descriptor */
+
+ s8 next; /* 1: */
+ u8 namlen; /* 1: */
+ UniChar name[11]; /* 22: 2-byte aligned */
+} idtentry_t; /* (32) */
+
+/*
+ * leaf node entry head/only segment
+ *
+ * For legacy filesystems, name contains 13 unichars -- no index field
+ */
+typedef struct {
+ u32 inumber; /* 4: 4-byte aligned */
+ s8 next; /* 1: */
+ u8 namlen; /* 1: */
+ UniChar name[11]; /* 22: 2-byte aligned */
+ u32 index; /* 4: index into dir_table */
+} ldtentry_t; /* (32) */
+
+#define DTLHDRDATALEN 11
+
+/*
+ * dir_table used for directory traversal during readdir
+*/
+
+/*
+ * Maximum entry in inline directory table
+ */
+
+typedef struct dir_table_slot {
+ u8 rsrvd; /* 1: */
+ u8 flag; /* 1: 0 if free */
+ u8 slot; /* 1: slot within leaf page of entry */
+ u8 addr1; /* 1: upper 8 bits of leaf page address */
+ u32 addr2; /* 4: lower 32 bits of leaf page address -OR-
+ index of next entry when this entry was deleted */
+} dir_table_slot_t; /* (8) */
+
+/*
+ * directory root page (in-line in on-disk inode):
+ *
+ * cf. dtpage_t below.
+ */
+typedef union {
+ struct {
+ dasd_t DASD; /* 16: DASD limit/usage info F226941 */
+
+ u8 flag; /* 1: */
+ s8 nextindex; /* 1: next free entry in stbl */
+ s8 freecnt; /* 1: free count */
+ s8 freelist; /* 1: freelist header */
+
+ u32 idotdot; /* 4: parent inode number */
+
+ s8 stbl[8]; /* 8: sorted entry index table */
+ } header; /* (32) */
+
+ dtslot_t slot[9];
+} dtroot_t;
+
+/*
+ * directory regular page:
+ *
+ * entry slot array of 32 byte slot
+ *
+ * sorted entry slot index table (stbl):
+ * contiguous slots at slot specified by stblindex,
+ * 1-byte per entry
+ * 512 byte block: 16 entry tbl (1 slot)
+ * 1024 byte block: 32 entry tbl (1 slot)
+ * 2048 byte block: 64 entry tbl (2 slot)
+ * 4096 byte block: 128 entry tbl (4 slot)
+ *
+ * data area:
+ * 512 byte block: 16 - 2 = 14 slot
+ * 1024 byte block: 32 - 2 = 30 slot
+ * 2048 byte block: 64 - 3 = 61 slot
+ * 4096 byte block: 128 - 5 = 123 slot
+ *
+ * N.B. index is 0-based; index fields refer to slot index
+ * except nextindex which refers to entry index in stbl;
+ * end of entry stot list or freelist is marked with -1.
+ */
+typedef union {
+ struct {
+ s64 next; /* 8: next sibling */
+ s64 prev; /* 8: previous sibling */
+
+ u8 flag; /* 1: */
+ s8 nextindex; /* 1: next entry index in stbl */
+ s8 freecnt; /* 1: */
+ s8 freelist; /* 1: slot index of head of freelist */
+
+ u8 maxslot; /* 1: number of slots in page slot[] */
+ s8 stblindex; /* 1: slot index of start of stbl */
+ u8 rsrvd[2]; /* 2: */
+
+ pxd_t self; /* 8: self pxd */
+ } header; /* (32) */
+
+ dtslot_t slot[128];
+} dtpage_t;
+
+/* from jfs_xtree.h */
+
+/*
+ * extent allocation descriptor (xad)
+ */
+typedef struct xad {
+ unsigned flag:8; /* 1: flag */
+ unsigned rsvrd:16; /* 2: reserved */
+ unsigned off1:8; /* 1: offset in unit of fsblksize */
+ u32 off2; /* 4: offset in unit of fsblksize */
+ unsigned len:24; /* 3: length in unit of fsblksize */
+ unsigned addr1:8; /* 1: address in unit of fsblksize */
+ u32 addr2; /* 4: address in unit of fsblksize */
+} xad_t; /* (16) */
+
+/* xad_t field extraction */
+#define offsetXAD(xad) (((s64)((xad)->off1)) << 32 | ((xad)->off2))
+#define addressXAD(xad) (((s64)((xad)->addr1)) << 32 | ((xad)->addr2))
+#define lengthXAD(xad) ((xad)->len)
+
+/* possible values for maxentry */
+#define XTPAGEMAXSLOT 256
+#define XTENTRYSTART 2
+
+/*
+ * xtree page:
+ */
+typedef union {
+ struct xtheader {
+ s64 next; /* 8: */
+ s64 prev; /* 8: */
+
+ u8 flag; /* 1: */
+ u8 rsrvd1; /* 1: */
+ s16 nextindex; /* 2: next index = number of entries */
+ s16 maxentry; /* 2: max number of entries */
+ s16 rsrvd2; /* 2: */
+
+ pxd_t self; /* 8: self */
+ } header; /* (32) */
+
+ xad_t xad[XTPAGEMAXSLOT]; /* 16 * maxentry: xad array */
+} xtpage_t;
+
+/* from jfs_dinode.h */
+
+struct dinode {
+ /*
+ * I. base area (128 bytes)
+ * ------------------------
+ *
+ * define generic/POSIX attributes
+ */
+ u32 di_inostamp; /* 4: stamp to show inode belongs to fileset */
+ s32 di_fileset; /* 4: fileset number */
+ u32 di_number; /* 4: inode number, aka file serial number */
+ u32 di_gen; /* 4: inode generation number */
+
+ pxd_t di_ixpxd; /* 8: inode extent descriptor */
+
+ s64 di_size; /* 8: size */
+ s64 di_nblocks; /* 8: number of blocks allocated */
+
+ u32 di_nlink; /* 4: number of links to the object */
+
+ u32 di_uid; /* 4: user id of owner */
+ u32 di_gid; /* 4: group id of owner */
+
+ u32 di_mode; /* 4: attribute, format and permission */
+
+ struct timestruc_t di_atime; /* 8: time last data accessed */
+ struct timestruc_t di_ctime; /* 8: time last status changed */
+ struct timestruc_t di_mtime; /* 8: time last data modified */
+ struct timestruc_t di_otime; /* 8: time created */
+
+ dxd_t di_acl; /* 16: acl descriptor */
+
+ dxd_t di_ea; /* 16: ea descriptor */
+
+ s32 di_next_index; /* 4: Next available dir_table index */
+
+ s32 di_acltype; /* 4: Type of ACL */
+
+ /*
+ * Extension Areas.
+ *
+ * Historically, the inode was partitioned into 4 128-byte areas,
+ * the last 3 being defined as unions which could have multiple
+ * uses. The first 96 bytes had been completely unused until
+ * an index table was added to the directory. It is now more
+ * useful to describe the last 3/4 of the inode as a single
+ * union. We would probably be better off redesigning the
+ * entire structure from scratch, but we don't want to break
+ * commonality with OS/2's JFS at this time.
+ */
+ union {
+ struct {
+ /*
+ * This table contains the information needed to
+ * find a directory entry from a 32-bit index.
+ * If the index is small enough, the table is inline,
+ * otherwise, an x-tree root overlays this table
+ */
+ dir_table_slot_t _table[12]; /* 96: inline */
+
+ dtroot_t _dtroot; /* 288: dtree root */
+ } _dir; /* (384) */
+#define di_dirtable u._dir._table
+#define di_dtroot u._dir._dtroot
+#define di_parent di_dtroot.header.idotdot
+#define di_DASD di_dtroot.header.DASD
+
+ struct {
+ union {
+ u8 _data[96]; /* 96: unused */
+ struct {
+ void *_imap; /* 4: unused */
+ u32 _gengen; /* 4: generator */
+ } _imap;
+ } _u1; /* 96: */
+#define di_gengen u._file._u1._imap._gengen
+
+ union {
+ xtpage_t _xtroot;
+ struct {
+ u8 unused[16]; /* 16: */
+ dxd_t _dxd; /* 16: */
+ union {
+ u32 _rdev; /* 4: */
+ u8 _fastsymlink[128];
+ } _u;
+ u8 _inlineea[128];
+ } _special;
+ } _u2;
+ } _file;
+#define di_xtroot u._file._u2._xtroot
+#define di_dxd u._file._u2._special._dxd
+#define di_btroot di_xtroot
+#define di_inlinedata u._file._u2._special._u
+#define di_rdev u._file._u2._special._u._rdev
+#define di_fastsymlink u._file._u2._special._u._fastsymlink
+#define di_inlineea u._file._u2._special._inlineea
+ } u;
+};
+
+typedef struct dinode dinode_t;
+
+/* di_mode */
+#define IFMT 0xF000 /* S_IFMT - mask of file type */
+#define IFDIR 0x4000 /* S_IFDIR - directory */
+#define IFREG 0x8000 /* S_IFREG - regular file */
+#define IFLNK 0xA000 /* S_IFLNK - symbolic link */
+
+/* extended mode bits (on-disk inode di_mode) */
+#define INLINEEA 0x00040000 /* inline EA area free */
+
+/* from jfs_imap.h */
+
+#define EXTSPERIAG 128 /* number of disk inode extent per iag */
+#define SMAPSZ 4 /* number of words per summary map */
+#define MAXAG 128 /* maximum number of allocation groups */
+
+/*
+ * inode allocation map:
+ *
+ * inode allocation map consists of
+ * . the inode map control page and
+ * . inode allocation group pages (per 4096 inodes)
+ * which are addressed by standard JFS xtree.
+ */
+/*
+ * inode allocation group page (per 4096 inodes of an AG)
+ */
+typedef struct {
+ s64 agstart; /* 8: starting block of ag */
+ s32 iagnum; /* 4: inode allocation group number */
+ s32 inofreefwd; /* 4: ag inode free list forward */
+ s32 inofreeback; /* 4: ag inode free list back */
+ s32 extfreefwd; /* 4: ag inode extent free list forward */
+ s32 extfreeback; /* 4: ag inode extent free list back */
+ s32 iagfree; /* 4: iag free list */
+
+ /* summary map: 1 bit per inode extent */
+ s32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes;
+ * note: this indicates free and backed
+ * inodes, if the extent is not backed the
+ * value will be 1. if the extent is
+ * backed but all inodes are being used the
+ * value will be 1. if the extent is
+ * backed but at least one of the inodes is
+ * free the value will be 0.
+ */
+ s32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */
+ s32 nfreeinos; /* 4: number of free inodes */
+ s32 nfreeexts; /* 4: number of free extents */
+ /* (72) */
+ u8 pad[1976]; /* 1976: pad to 2048 bytes */
+ /* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
+ u32 wmap[EXTSPERIAG]; /* 512: working allocation map */
+ u32 pmap[EXTSPERIAG]; /* 512: persistent allocation map */
+ pxd_t inoext[EXTSPERIAG]; /* 1024: inode extent addresses */
+} iag_t; /* (4096) */
+
+#endif /* _JFS_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/shared.h b/qemu/roms/openbios/fs/grubfs/shared.h
new file mode 100644
index 000000000..b3034e03c
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/shared.h
@@ -0,0 +1,3 @@
+/* Sorry, nothing is shared here ;) Just for GRUB compatibility. */
+
+#include "glue.h"
diff --git a/qemu/roms/openbios/fs/grubfs/ufs_dinode.h b/qemu/roms/openbios/fs/grubfs/ufs_dinode.h
new file mode 100644
index 000000000..f3f7fca02
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/ufs_dinode.h
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dinode.h 8.3 (Berkeley) 1/21/94
+ * $FreeBSD: src/sys/ufs/ufs/dinode.h,v 1.13.2.1 2005/01/31 23:27:01 imp Exp $
+ */
+
+#ifndef _UFS_UFS_DINODE_H_
+#define _UFS_UFS_DINODE_H_
+
+/*
+ * The root inode is the root of the filesystem. Inode 0 can't be used for
+ * normal purposes and historically bad blocks were linked to inode 1, thus
+ * the root inode is 2. (Inode 1 is no longer used for this purpose, however
+ * numerous dump tapes make this assumption, so we are stuck with it).
+ */
+#define ROOTINO ((ino_t)2)
+
+/*
+ * The Whiteout inode# is a dummy non-zero inode number which will
+ * never be allocated to a real file. It is used as a place holder
+ * in the directory entry which has been tagged as a DT_W entry.
+ * See the comments about ROOTINO above.
+ */
+#define WINO ((ino_t)1)
+
+/*
+ * The size of physical and logical block numbers and time fields in UFS.
+ */
+typedef int32_t ufs1_daddr_t;
+typedef int64_t ufs2_daddr_t;
+typedef int64_t ufs_lbn_t;
+typedef int64_t ufs_time_t;
+
+/* File permissions. */
+#define IEXEC 0000100 /* Executable. */
+#define IWRITE 0000200 /* Writeable. */
+#define IREAD 0000400 /* Readable. */
+#define ISVTX 0001000 /* Sticky bit. */
+#define ISGID 0002000 /* Set-gid. */
+#define ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define IFMT 0170000 /* Mask of file type. */
+#define IFIFO 0010000 /* Named pipe (fifo). */
+#define IFCHR 0020000 /* Character device. */
+#define IFDIR 0040000 /* Directory file. */
+#define IFBLK 0060000 /* Block device. */
+#define IFREG 0100000 /* Regular file. */
+#define IFLNK 0120000 /* Symbolic link. */
+#define IFSOCK 0140000 /* UNIX domain socket. */
+#define IFWHT 0160000 /* Whiteout. */
+
+/*
+ * A dinode contains all the meta-data associated with a UFS2 file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NXADDR 2 /* External addresses in inode. */
+#define NDADDR 12 /* Direct addresses in inode. */
+#define NIADDR 3 /* Indirect addresses in inode. */
+
+struct ufs2_dinode {
+ uint16_t di_mode; /* 0: IFMT, permissions; see below. */
+ int16_t di_nlink; /* 2: File link count. */
+ uint32_t di_uid; /* 4: File owner. */
+ uint32_t di_gid; /* 8: File group. */
+ uint32_t di_blksize; /* 12: Inode blocksize. */
+ uint64_t di_size; /* 16: File byte count. */
+ uint64_t di_blocks; /* 24: Bytes actually held. */
+ ufs_time_t di_atime; /* 32: Last access time. */
+ ufs_time_t di_mtime; /* 40: Last modified time. */
+ ufs_time_t di_ctime; /* 48: Last inode change time. */
+ ufs_time_t di_birthtime; /* 56: Inode creation time. */
+ int32_t di_mtimensec; /* 64: Last modified time. */
+ int32_t di_atimensec; /* 68: Last access time. */
+ int32_t di_ctimensec; /* 72: Last inode change time. */
+ int32_t di_birthnsec; /* 76: Inode creation time. */
+ int32_t di_gen; /* 80: Generation number. */
+ uint32_t di_kernflags; /* 84: Kernel flags. */
+ uint32_t di_flags; /* 88: Status flags (chflags). */
+ int32_t di_extsize; /* 92: External attributes block. */
+ ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */
+ ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */
+ ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
+ int64_t di_spare[3]; /* 232: Reserved; currently unused */
+};
+
+/*
+ * The di_db fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+#define di_rdev di_db[0]
+
+/*
+ * A UFS1 dinode contains all the meta-data associated with a UFS1 file.
+ * This structure defines the on-disk format of a UFS1 dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+struct ufs1_dinode {
+ uint16_t di_mode; /* 0: IFMT, permissions; see below. */
+ int16_t di_nlink; /* 2: File link count. */
+ union {
+ uint16_t oldids[2]; /* 4: Ffs: old user and group ids. */
+ } di_u;
+ uint64_t di_size; /* 8: File byte count. */
+ int32_t di_atime; /* 16: Last access time. */
+ int32_t di_atimensec; /* 20: Last access time. */
+ int32_t di_mtime; /* 24: Last modified time. */
+ int32_t di_mtimensec; /* 28: Last modified time. */
+ int32_t di_ctime; /* 32: Last inode change time. */
+ int32_t di_ctimensec; /* 36: Last inode change time. */
+ ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */
+ ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
+ uint32_t di_flags; /* 100: Status flags (chflags). */
+ int32_t di_blocks; /* 104: Blocks actually held. */
+ int32_t di_gen; /* 108: Generation number. */
+ uint32_t di_uid; /* 112: File owner. */
+ uint32_t di_gid; /* 116: File group. */
+ int32_t di_spare[2]; /* 120: Reserved; currently unused */
+};
+#define di_ogid di_u.oldids[1]
+#define di_ouid di_u.oldids[0]
+
+#endif /* _UFS_UFS_DINODE_H_ */
diff --git a/qemu/roms/openbios/fs/grubfs/ufs_fs.h b/qemu/roms/openbios/fs/grubfs/ufs_fs.h
new file mode 100644
index 000000000..bd11cc968
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/ufs_fs.h
@@ -0,0 +1,635 @@
+/*-
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fs.h 8.13 (Berkeley) 3/21/95
+ * $FreeBSD: src/sys/ufs/ffs/fs.h,v 1.43.2.3 2005/02/28 16:04:53 delphij Exp $
+ */
+
+#ifndef _UFS_FFS_FS_H_
+#define _UFS_FFS_FS_H_
+
+/*
+ * Each disk drive contains some number of filesystems.
+ * A filesystem consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A filesystem is described by its super-block, which in turn
+ * describes the cylinder groups. The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss. This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For filesystem fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ * [fs->fs_sblkno] Super-block
+ * [fs->fs_cblkno] Cylinder group block
+ * [fs->fs_iblkno] Inode blocks
+ * [fs->fs_dblkno] Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * Depending on the architecture and the media, the superblock may
+ * reside in any one of four places. For tiny media where every block
+ * counts, it is placed at the very front of the partition. Historically,
+ * UFS1 placed it 8K from the front to leave room for the disk label and
+ * a small bootstrap. For UFS2 it got moved to 64K from the front to leave
+ * room for the disk label and a bigger bootstrap, and for really piggy
+ * systems we check at 256K from the front if the first three fail. In
+ * all cases the size of the superblock will be SBLOCKSIZE. All values are
+ * given in byte-offset form, so they do not imply a sector size. The
+ * SBLOCKSEARCH specifies the order in which the locations should be searched.
+ */
+#define SBLOCK_FLOPPY 0
+#define SBLOCK_UFS1 8192
+#define SBLOCK_UFS2 65536
+#define SBLOCK_PIGGY 262144
+#define SBLOCKSIZE 8192
+#define SBLOCKSEARCH \
+ { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
+
+/*
+ * Max number of fragments per block. This value is NOT tweakable.
+ */
+#define MAXFRAG 8
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressable; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks. To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary. The filesystem format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided. The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The filesystem records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define MINBSIZE 4096
+
+/*
+ * The path name on which the filesystem is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define MAXMNTLEN 468
+
+/*
+ * The volume name for this filesystem is maintained in fs_volname.
+ * MAXVOLLEN defines the length of the buffer allocated.
+ */
+#define MAXVOLLEN 32
+
+/*
+ * There is a 128-byte region in the superblock reserved for in-core
+ * pointers to summary information. Originally this included an array
+ * of pointers to blocks of struct csum; now there are just a few
+ * pointers and the remaining space is padded with fs_ocsp[].
+ *
+ * NOCSPTRS determines the size of this padding. One pointer (fs_csp)
+ * is taken away to point to a contiguous array of struct csum for
+ * all cylinder groups; a second (fs_maxcluster) points to an array
+ * of cluster sizes that is computed as cylinder groups are inspected,
+ * and the third points to an array that tracks the creation of new
+ * directories. A fourth pointer, fs_active, is used when creating
+ * snapshots; it points to a bitmap of cylinder groups for which the
+ * free-block bitmap has changed since the snapshot operation began.
+ */
+#define NOCSPTRS ((128 / sizeof(void *)) - 4)
+
+/*
+ * A summary of contiguous blocks of various sizes is maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig. To conserve space, a maximum summary size
+ * is set by FS_MAXCONTIG.
+ */
+#define FS_MAXCONTIG 16
+
+/*
+ * MINFREE gives the minimum acceptable percentage of filesystem
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the filesystem
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define MINFREE 8
+#define DEFAULTOPT FS_OPTTIME
+
+/*
+ * Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
+ * tune the layout preferences for directories within a filesystem.
+ * His algorithm can be tuned by adjusting the following parameters
+ * which tell the system the average file size and the average number
+ * of files per directory. These defaults are well selected for typical
+ * filesystems, but may need to be tuned for odd cases like filesystems
+ * being used for squid caches or news spools.
+ */
+#define AVFILESIZ 16384 /* expected average file size */
+#define AFPDIR 64 /* expected number of files per directory */
+
+/*
+ * The maximum number of snapshot nodes that can be associated
+ * with each filesystem. This limit affects only the number of
+ * snapshot files that can be recorded within the superblock so
+ * that they can be found when the filesystem is mounted. However,
+ * maintaining too many will slow the filesystem performance, so
+ * having this limit is a good idea.
+ */
+#define FSMAXSNAP 20
+
+/*
+ * Used to identify special blocks in snapshots:
+ *
+ * BLK_NOCOPY - A block that was unallocated at the time the snapshot
+ * was taken, hence does not need to be copied when written.
+ * BLK_SNAP - A block held by another snapshot that is not needed by this
+ * snapshot. When the other snapshot is freed, the BLK_SNAP entries
+ * are converted to BLK_NOCOPY. These are needed to allow fsck to
+ * identify blocks that are in use by other snapshots (which are
+ * expunged from this snapshot).
+ */
+#define BLK_NOCOPY ((ufs2_daddr_t)(1))
+#define BLK_SNAP ((ufs2_daddr_t)(2))
+
+/*
+ * Sysctl values for the fast filesystem.
+ */
+#define FFS_ADJ_REFCNT 1 /* adjust inode reference count */
+#define FFS_ADJ_BLKCNT 2 /* adjust inode used block count */
+#define FFS_BLK_FREE 3 /* free range of blocks in map */
+#define FFS_DIR_FREE 4 /* free specified dir inodes in map */
+#define FFS_FILE_FREE 5 /* free specified file inodes in map */
+#define FFS_SET_FLAGS 6 /* set filesystem flags */
+#define FFS_ADJ_NDIR 7 /* adjust number of directories */
+#define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */
+#define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */
+#define FFS_ADJ_NFFREE 10 /* adjust number of free frags */
+#define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */
+#define FFS_MAXID 12 /* number of valid ffs ids */
+
+/*
+ * Command structure passed in to the filesystem to adjust filesystem values.
+ */
+#define FFS_CMD_VERSION 0x19790518 /* version ID */
+struct fsck_cmd {
+ int32_t version; /* version of command structure */
+ int32_t handle; /* reference to filesystem to be changed */
+ int64_t value; /* inode or block number to be affected */
+ int64_t size; /* amount or range to be adjusted */
+ int64_t spare; /* reserved for future use */
+};
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ */
+struct csum {
+ int32_t cs_ndir; /* number of directories */
+ int32_t cs_nbfree; /* number of free blocks */
+ int32_t cs_nifree; /* number of free inodes */
+ int32_t cs_nffree; /* number of free frags */
+};
+struct csum_total {
+ int64_t cs_ndir; /* number of directories */
+ int64_t cs_nbfree; /* number of free blocks */
+ int64_t cs_nifree; /* number of free inodes */
+ int64_t cs_nffree; /* number of free frags */
+ int64_t cs_numclusters; /* number of free clusters */
+ int64_t cs_spare[3]; /* future expansion */
+};
+
+/*
+ * Super block for an FFS filesystem.
+ */
+struct fs {
+ int32_t fs_firstfield; /* historic filesystem linked list, */
+ int32_t fs_unused_1; /* used for incore super blocks */
+ int32_t fs_sblkno; /* offset of super-block in filesys */
+ int32_t fs_cblkno; /* offset of cyl-block in filesys */
+ int32_t fs_iblkno; /* offset of inode-blocks in filesys */
+ int32_t fs_dblkno; /* offset of first data after cg */
+ int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
+ int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
+ int32_t fs_old_time; /* last time written */
+ int32_t fs_old_size; /* number of blocks in fs */
+ int32_t fs_old_dsize; /* number of data blocks in fs */
+ int32_t fs_ncg; /* number of cylinder groups */
+ int32_t fs_bsize; /* size of basic blocks in fs */
+ int32_t fs_fsize; /* size of frag blocks in fs */
+ int32_t fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ int32_t fs_minfree; /* minimum percentage of free blocks */
+ int32_t fs_old_rotdelay; /* num of ms for optimal next block */
+ int32_t fs_old_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
+ int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int32_t fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ int32_t fs_maxcontig; /* max number of contiguous blks */
+ int32_t fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ int32_t fs_fragshift; /* block to frag shift */
+ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int32_t fs_sbsize; /* actual size of super block */
+ int32_t fs_spare1[2]; /* old fs_csmask */
+ /* old fs_csshift */
+ int32_t fs_nindir; /* value of NINDIR */
+ int32_t fs_inopb; /* value of INOPB */
+ int32_t fs_old_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ int32_t fs_optim; /* optimization preference, see below */
+ int32_t fs_old_npsect; /* # sectors/track including spares */
+ int32_t fs_old_interleave; /* hardware sector interleave */
+ int32_t fs_old_trackskew; /* sector 0 skew, per track */
+ int32_t fs_id[2]; /* unique filesystem id */
+/* sizes determined by number of cylinder groups and their sizes */
+ int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
+ int32_t fs_cssize; /* size of cyl grp summary area */
+ int32_t fs_cgsize; /* cylinder group size */
+ int32_t fs_spare2; /* old fs_ntrak */
+ int32_t fs_old_nsect; /* sectors per track */
+ int32_t fs_old_spc; /* sectors per cylinder */
+ int32_t fs_old_ncyl; /* cylinders in filesystem */
+ int32_t fs_old_cpg; /* cylinders per group */
+ int32_t fs_ipg; /* inodes per group */
+ int32_t fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct csum fs_old_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ int8_t fs_fmod; /* super block modified flag */
+ int8_t fs_clean; /* filesystem is clean flag */
+ int8_t fs_ronly; /* mounted read-only flag */
+ int8_t fs_old_flags; /* old FS_ flags */
+ char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+ char fs_volname[MAXVOLLEN]; /* volume name */
+ uint64_t fs_swuid; /* system-wide uid */
+ int32_t fs_pad; /* due to alignment of fs_swuid */
+/* these fields retain the current block allocation info */
+ int32_t fs_cgrotor; /* last cg searched */
+ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
+ uint8_t *fs_contigdirs; /* # of contiguously allocated dirs */
+ struct csum *fs_csp; /* cg summary info buffer for fs_cs */
+ int32_t *fs_maxcluster; /* max cluster in each cyl group */
+ unsigned int *fs_active; /* used by snapshots to track fs */
+ int32_t fs_old_cpc; /* cyl per cycle in postbl */
+ int32_t fs_maxbsize; /* maximum blocking factor permitted */
+ int64_t fs_sparecon64[17]; /* old rotation block list head */
+ int64_t fs_sblockloc; /* byte offset of standard superblock */
+ struct csum_total fs_cstotal; /* cylinder summary information */
+ ufs_time_t fs_time; /* last time written */
+ int64_t fs_size; /* number of blocks in fs */
+ int64_t fs_dsize; /* number of data blocks in fs */
+ ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */
+ int64_t fs_pendingblocks; /* blocks in process of being freed */
+ int32_t fs_pendinginodes; /* inodes in process of being freed */
+ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
+ int32_t fs_avgfilesize; /* expected average file size */
+ int32_t fs_avgfpdir; /* expected # of files per directory */
+ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
+ int32_t fs_sparecon32[26]; /* reserved for future constants */
+ int32_t fs_flags; /* see FS_ flags below */
+ int32_t fs_contigsumsize; /* size of cluster summary array */
+ int32_t fs_maxsymlinklen; /* max length of an internal symlink */
+ int32_t fs_old_inodefmt; /* format of on-disk inodes */
+ uint64_t fs_maxfilesize; /* maximum representable file size */
+ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
+ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
+ int32_t fs_state; /* validate fs_clean field */
+ int32_t fs_old_postblformat; /* format of positional layout tables */
+ int32_t fs_old_nrpos; /* number of rotational positions */
+ int32_t fs_spare5[2]; /* old fs_postbloff */
+ /* old fs_rotbloff */
+ int32_t fs_magic; /* magic number */
+};
+
+/* Sanity checking. */
+#ifdef CTASSERT
+CTASSERT(sizeof(struct fs) == 1376);
+#endif
+
+/*
+ * Filesystem identification
+ */
+#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */
+#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */
+#define FS_BAD_MAGIC 0x19960408 /* UFS incomplete newfs magic number */
+#define FS_OKAY 0x7c269d38 /* superblock checksum */
+#define FS_42INODEFMT -1 /* 4.2BSD inode format */
+#define FS_44INODEFMT 2 /* 4.4BSD inode format */
+
+/*
+ * Preference for optimization.
+ */
+#define FS_OPTTIME 0 /* minimize allocation time */
+#define FS_OPTSPACE 1 /* minimize disk fragmentation */
+
+/*
+ * Filesystem flags.
+ *
+ * The FS_UNCLEAN flag is set by the kernel when the filesystem was
+ * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates
+ * that the filesystem should be managed by the soft updates code.
+ * Note that the FS_NEEDSFSCK flag is set and cleared only by the
+ * fsck utility. It is set when background fsck finds an unexpected
+ * inconsistency which requires a traditional foreground fsck to be
+ * run. Such inconsistencies should only be found after an uncorrectable
+ * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when
+ * it has successfully cleaned up the filesystem. The kernel uses this
+ * flag to enforce that inconsistent filesystems be mounted read-only.
+ * The FS_INDEXDIRS flag when set indicates that the kernel maintains
+ * on-disk auxiliary indexes (such as B-trees) for speeding directory
+ * accesses. Kernels that do not support auxiliary indicies clear the
+ * flag to indicate that the indicies need to be rebuilt (by fsck) before
+ * they can be used.
+ *
+ * FS_ACLS indicates that ACLs are administratively enabled for the
+ * file system, so they should be loaded from extended attributes,
+ * observed for access control purposes, and be administered by object
+ * owners. FS_MULTILABEL indicates that the TrustedBSD MAC Framework
+ * should attempt to back MAC labels into extended attributes on the
+ * file system rather than maintain a single mount label for all
+ * objects.
+ */
+#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */
+#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */
+#define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */
+#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */
+#define FS_ACLS 0x10 /* file system has ACLs enabled */
+#define FS_MULTILABEL 0x20 /* file system is MAC multi-label */
+#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
+
+/*
+ * Macros to access bits in the fs_active array.
+ */
+#define ACTIVECGNUM(fs, cg) ((fs)->fs_active[(cg) / (NBBY * sizeof(int))])
+#define ACTIVECGOFF(cg) (1 << ((cg) % (NBBY * sizeof(int))))
+
+/*
+ * The size of a cylinder group is calculated by CGSIZE. The maximum size
+ * is limited by the fact that cylinder groups are at most one block.
+ * Its size is derived from the size of the maps maintained in the
+ * cylinder group and the (struct cg) size.
+ */
+#define CGSIZE(fs) \
+ /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \
+ /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \
+ /* old boff */ (fs)->fs_old_cpg * sizeof(uint16_t) + \
+ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \
+ /* block map */ howmany((fs)->fs_fpg, NBBY) +\
+ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \
+ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \
+ /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY)))
+
+/*
+ * The minimal number of cylinder groups that should be created.
+ */
+#define MINCYLGRPS 4
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define fs_cs(fs, indx) fs_csp[indx]
+
+/*
+ * Cylinder group block for a filesystem.
+ */
+#define CG_MAGIC 0x090255
+struct cg {
+ int32_t cg_firstfield; /* historic cyl groups linked list */
+ int32_t cg_magic; /* magic number */
+ int32_t cg_old_time; /* time last written */
+ int32_t cg_cgx; /* we are the cgx'th cylinder group */
+ int16_t cg_old_ncyl; /* number of cyl's this cg */
+ int16_t cg_old_niblk; /* number of inode blocks this cg */
+ int32_t cg_ndblk; /* number of data blocks this cg */
+ struct csum cg_cs; /* cylinder summary information */
+ int32_t cg_rotor; /* position of last used block */
+ int32_t cg_frotor; /* position of last used frag */
+ int32_t cg_irotor; /* position of last used inode */
+ int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
+ int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
+ int32_t cg_old_boff; /* (uint16) free block positions */
+ int32_t cg_iusedoff; /* (uint8) used inode map */
+ int32_t cg_freeoff; /* (uint8) free block map */
+ int32_t cg_nextfreeoff; /* (uint8) next available space */
+ int32_t cg_clustersumoff; /* (uint32) counts of avail clusters */
+ int32_t cg_clusteroff; /* (uint8) free cluster map */
+ int32_t cg_nclusterblks; /* number of clusters this cg */
+ int32_t cg_niblk; /* number of inode blocks this cg */
+ int32_t cg_initediblk; /* last initialized inode */
+ int32_t cg_sparecon32[3]; /* reserved for future use */
+ ufs_time_t cg_time; /* time last written */
+ int64_t cg_sparecon64[3]; /* reserved for future use */
+ uint8_t cg_space[1]; /* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
+#define cg_inosused(cgp) \
+ ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_iusedoff))
+#define cg_blksfree(cgp) \
+ ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_freeoff))
+#define cg_clustersfree(cgp) \
+ ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_clusteroff))
+#define cg_clustersum(cgp) \
+ ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff))
+
+/*
+ * Turn filesystem block numbers into disk block addresses.
+ * This maps filesystem blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc filesystem addresses of cylinder group data structures.
+ */
+#define cgbase(fs, c) (((ufs2_daddr_t)(fs)->fs_fpg) * (c))
+#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
+#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */
+#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */
+#define cgstart(fs, c) \
+ ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \
+ (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask))))
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to filesystem block offset.
+ * inode number to cylinder group number.
+ * inode number to filesystem block address.
+ */
+#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
+#define ino_to_fsba(fs, x) \
+ ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
+ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
+
+/*
+ * Give cylinder group number for a filesystem block.
+ * Give cylinder group block number for a filesystem block.
+ */
+#define dtog(fs, d) ((d) / (fs)->fs_fpg)
+#define dtogd(fs, d) ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define blkmap(fs, map, loc) \
+ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
+ ((loc) & (fs)->fs_qbmask)
+#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \
+ ((loc) & (fs)->fs_qfmask)
+#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \
+ (((off_t)(frag)) << (fs)->fs_fshift)
+#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \
+ (((off_t)(blk)) << (fs)->fs_bshift)
+/* Use this only when `blk' is known to be small, e.g., < NDADDR. */
+#define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \
+ ((blk) << (fs)->fs_bshift)
+#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
+ ((loc) >> (fs)->fs_bshift)
+#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
+ ((loc) >> (fs)->fs_fshift)
+#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \
+ (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
+#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
+ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
+ ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
+ ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define freespace(fs, percentreserved) \
+ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+ (fs)->fs_cstotal.cs_nffree - \
+ (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the filesystem.
+ */
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+#define sblksize(fs, size, lbn) \
+ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (size)))))
+
+
+/*
+ * Number of inodes in a secondary storage block/fragment.
+ */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * Number of indirects in a filesystem block.
+ */
+#define NINDIR(fs) ((fs)->fs_nindir)
+
+extern int inside[], around[];
+extern char *fragtbl[];
+
+struct ufs_dirent {
+ uint32_t d_fileno; /* file number of entry */
+ uint16_t d_reclen; /* length of this record */
+ uint8_t d_type; /* file type, see below */
+ uint8_t d_namlen; /* length of string in d_name */
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/* XXX: We hardcode BSIZE and BSIZE_SHIFT here. fsys_ffs seems to do the same,
+ * so we should get away with it :-) */
+#define DEV_BSIZE 512
+#define DEV_BSHIFT 9 /* 2**9 = 512 */
+#define MAXBSIZE 8192
+
+typedef unsigned int ino_t;
+
+#endif
diff --git a/qemu/roms/openbios/fs/grubfs/vstafs.h b/qemu/roms/openbios/fs/grubfs/vstafs.h
new file mode 100644
index 000000000..f240ffc4a
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/vstafs.h
@@ -0,0 +1,89 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+
+#ifndef VSTAFS_H
+#define VSTAFS_H 1
+
+
+#define LINE 16
+#define BLOCK_SIZE 512
+#define VSTAFS_START_DATA 320
+
+struct bootrecord
+{
+ unsigned char flag;
+ unsigned char s_sector;
+ unsigned char s_head;
+ unsigned char s_cylinder;
+ unsigned char p_type;
+ unsigned char e_sector;
+ unsigned char e_head;
+ unsigned char e_cylinder;
+ unsigned long start_lba;
+ unsigned long nr_sector_lba;
+};
+
+struct alloc
+{
+ unsigned long a_start;
+ unsigned long a_len;
+};
+
+struct first_sector
+{
+ unsigned long fs_magic;
+ unsigned long fs_size;
+ unsigned long fs_extsize;
+ unsigned long fs_free;
+ struct alloc fs_freesecs[0];
+};
+
+struct prot
+{
+ unsigned char len;
+ unsigned char pdefault;
+ unsigned char id[7];
+ unsigned char bits[7];
+};
+
+struct fs_file
+{
+ unsigned long prev;
+ unsigned long rev;
+ unsigned long len;
+ unsigned short type;
+ unsigned short nlink;
+ struct prot pprot;
+ unsigned int owner;
+ unsigned int extents;
+ struct alloc blocks[32];
+ long fs_ctime, fs_mtime; /* it is not lon but time_t */
+ char pad[16];
+ char data[0];
+};
+
+struct dir_entry
+{
+ char name[28];
+ unsigned long start;
+};
+
+#endif /* ! VSTAFS_H */
diff --git a/qemu/roms/openbios/fs/grubfs/xfs.h b/qemu/roms/openbios/fs/grubfs/xfs.h
new file mode 100644
index 000000000..0ed07042c
--- /dev/null
+++ b/qemu/roms/openbios/fs/grubfs/xfs.h
@@ -0,0 +1,546 @@
+/* xfs.h - an extraction from xfsprogs-1.3.5/include/xfs* into one file */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#ifndef _BITS_TYPES_H
+typedef signed char __int8_t;
+typedef unsigned char __uint8_t;
+typedef short __int16_t;
+typedef unsigned short __uint16_t;
+typedef int __int32_t;
+typedef unsigned int __uint32_t;
+typedef long long __int64_t;
+typedef unsigned long long __uint64_t;
+#endif
+
+typedef __uint64_t xfs_ino_t;
+typedef __uint32_t xfs_agino_t;
+typedef __int64_t xfs_daddr_t;
+typedef __int64_t xfs_off_t;
+typedef __uint8_t uuid_t[16];
+
+
+/* those are from xfs_types.h */
+
+typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef __uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef __uint32_t xfs_agnumber_t; /* allocation group number */
+typedef __int32_t xfs_extnum_t; /* # of extents in a file */
+typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef __int64_t xfs_fsize_t; /* bytes in a file */
+
+typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * Disk based types:
+ */
+typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef __uint64_t xfs_dfiloff_t; /* block number in a file */
+
+typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef __uint64_t xfs_fileoff_t; /* block number in a file */
+typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+
+/* those are from xfs_sb.h */
+
+#define XFS_SB_MAGIC 0x58465342 /* 'XFSB'*/
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+
+typedef struct xfs_sb
+{
+ __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ __uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ __uint16_t sb_sectsize; /* volume sector size, bytes */
+ __uint16_t sb_inodesize; /* inode size, bytes */
+ __uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ __uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ __uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ __uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ __uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ __uint8_t sb_rextslog; /* log2 of sb_rextents */
+ __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ __uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ __uint64_t sb_icount; /* allocated inodes */
+ __uint64_t sb_ifree; /* free inodes */
+ __uint64_t sb_fdblocks; /* free data blocks */
+ __uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ __uint16_t sb_qflags; /* quota flags */
+ __uint8_t sb_flags; /* misc. flags */
+ __uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ __uint32_t sb_unit; /* stripe or raid unit */
+ __uint32_t sb_width; /* stripe or raid width */
+ __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ __uint8_t sb_dummy[7]; /* padding */
+} xfs_sb_t;
+
+
+/* those are from xfs_btree.h */
+
+/*
+ * Long form header: bmap btrees.
+ */
+typedef struct xfs_btree_lblock
+{
+ __uint32_t bb_magic; /* magic number for block type */
+ __uint16_t bb_level; /* 0 is a leaf */
+ __uint16_t bb_numrecs; /* current # of data records */
+ xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */
+ xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */
+} xfs_btree_lblock_t;
+
+/*
+ * Combined header and structure, used by common code.
+ */
+typedef struct xfs_btree_hdr
+{
+ __uint32_t bb_magic; /* magic number for block type */
+ __uint16_t bb_level; /* 0 is a leaf */
+ __uint16_t bb_numrecs; /* current # of data records */
+} xfs_btree_hdr_t;
+
+typedef struct xfs_btree_block
+{
+ xfs_btree_hdr_t bb_h; /* header */
+ union {
+ struct {
+ xfs_agblock_t bb_leftsib;
+ xfs_agblock_t bb_rightsib;
+ } s; /* short form pointers */
+ struct {
+ xfs_dfsbno_t bb_leftsib;
+ xfs_dfsbno_t bb_rightsib;
+ } l; /* long form pointers */
+ } bb_u; /* rest */
+} xfs_btree_block_t;
+
+/* those are from xfs_bmap_btree.h */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block
+{
+ __uint16_t bb_level; /* 0 is a leaf */
+ __uint16_t bb_numrecs; /* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ * For 32-bit kernels,
+ * l0:31 is an extent flag (value 1 indicates non-normal).
+ * l0:0-30 and l1:9-31 are startoff.
+ * l1:0-8, l2:0-31, and l3:21-31 are startblock.
+ * l3:0-20 are blockcount.
+ * For 64-bit kernels,
+ * l0:63 is an extent flag (value 1 indicates non-normal).
+ * l0:9-62 are startoff.
+ * l0:0-8 and l1:21-63 are startblock.
+ * l1:0-20 are blockcount.
+ */
+
+#define BMBT_USE_64 1
+
+typedef struct xfs_bmbt_rec_32
+{
+ __uint32_t l0, l1, l2, l3;
+} xfs_bmbt_rec_32_t;
+typedef struct xfs_bmbt_rec_64
+{
+ __uint64_t l0, l1;
+} xfs_bmbt_rec_64_t;
+
+#if BMBT_USE_64
+typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */
+typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
+#else /* !BMBT_USE_64 */
+typedef __uint32_t xfs_bmbt_rec_base_t; /* use this for casts */
+typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
+#endif /* BMBT_USE_64 */
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key
+{
+ xfs_dfiloff_t br_startoff; /* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */
+ /* btree block header type */
+typedef struct xfs_btree_lblock xfs_bmbt_block_t;
+
+
+/* those are from xfs_dir2.h */
+/*
+ * Directory version 2.
+ * There are 4 possible formats:
+ * shortform
+ * single block - data with embedded leaf at the end
+ * multiple data blocks, single leaf+freeindex block
+ * data blocks, node&leaf blocks (btree), freeindex blocks
+ *
+ * The shortform format is in xfs_dir2_sf.h.
+ * The single block format is in xfs_dir2_block.h.
+ * The data block format is in xfs_dir2_data.h.
+ * The leaf and freeindex block formats are in xfs_dir2_leaf.h.
+ * Node blocks are the same as the other version, in xfs_da_btree.h.
+ */
+
+/*
+ * Byte offset in data block and shortform entry.
+ */
+typedef __uint16_t xfs_dir2_data_off_t;
+
+/*
+ * Byte offset in a directory.
+ */
+typedef xfs_off_t xfs_dir2_off_t;
+
+/* those are from xfs_da_btree.h */
+/*========================================================================
+ * Directory Structure when greater than XFS_LBSIZE(mp) bytes.
+ *========================================================================*/
+
+/*
+ * This structure is common to both leaf nodes and non-leaf nodes in the Btree.
+ *
+ * Is is used to manage a doubly linked list of all blocks at the same
+ * level in the Btree, and to identify which type of block this is.
+ */
+#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */
+#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */
+
+typedef struct xfs_da_blkinfo {
+ xfs_dablk_t forw; /* previous block in list */
+ xfs_dablk_t back; /* following block in list */
+ __uint16_t magic; /* validity check on block */
+ __uint16_t pad; /* unused */
+} xfs_da_blkinfo_t;
+
+/*
+ * This is the structure of the root and intermediate nodes in the Btree.
+ * The leaf nodes are defined above.
+ *
+ * Entries are not packed.
+ *
+ * Since we have duplicate keys, use a binary search but always follow
+ * all match in the block, not just the first match found.
+ */
+
+typedef struct xfs_da_intnode {
+ struct xfs_da_node_hdr { /* constant-structure header block */
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ __uint16_t count; /* count of active entries */
+ __uint16_t level; /* level above leaves (leaf == 0) */
+ } hdr;
+ struct xfs_da_node_entry {
+ xfs_dahash_t hashval; /* hash value for this descendant */
+ xfs_dablk_t before; /* Btree block before this key */
+ } btree[1]; /* variable sized array of keys */
+} xfs_da_intnode_t;
+
+
+/* those are from xfs_dir2_data.h */
+/*
+ * Directory format 2, data block structures.
+ */
+
+/*
+ * Constants.
+ */
+#define XFS_DIR2_DATA_FREE_TAG 0xffff
+#define XFS_DIR2_DATA_FD_COUNT 3
+
+/*
+ * Structures.
+ */
+
+/*
+ * Describe a free area in the data block.
+ * The freespace will be formatted as a xfs_dir2_data_unused_t.
+ */
+typedef struct xfs_dir2_data_free {
+ xfs_dir2_data_off_t offset; /* start of freespace */
+ xfs_dir2_data_off_t length; /* length of freespace */
+} xfs_dir2_data_free_t;
+
+/*
+ * Header for the data blocks.
+ * Always at the beginning of a directory-sized block.
+ * The code knows that XFS_DIR2_DATA_FD_COUNT is 3.
+ */
+typedef struct xfs_dir2_data_hdr {
+ __uint32_t magic; /* XFS_DIR2_DATA_MAGIC */
+ /* or XFS_DIR2_BLOCK_MAGIC */
+ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} xfs_dir2_data_hdr_t;
+
+/*
+ * Active entry in a data block. Aligned to 8 bytes.
+ * Tag appears as the last 2 bytes.
+ */
+typedef struct xfs_dir2_data_entry {
+ xfs_ino_t inumber; /* inode number */
+ __uint8_t namelen; /* name length */
+ __uint8_t name[1]; /* name bytes, no null */
+ /* variable offset */
+ xfs_dir2_data_off_t tag; /* starting offset of us */
+} xfs_dir2_data_entry_t;
+
+/*
+ * Unused entry in a data block. Aligned to 8 bytes.
+ * Tag appears as the last 2 bytes.
+ */
+typedef struct xfs_dir2_data_unused {
+ __uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+ xfs_dir2_data_off_t length; /* total free length */
+ /* variable offset */
+ xfs_dir2_data_off_t tag; /* starting offset of us */
+} xfs_dir2_data_unused_t;
+
+typedef union {
+ xfs_dir2_data_entry_t entry;
+ xfs_dir2_data_unused_t unused;
+} xfs_dir2_data_union_t;
+
+
+/* those are from xfs_dir2_leaf.h */
+/*
+ * Directory version 2, leaf block structures.
+ */
+
+/*
+ * Leaf block header.
+ */
+typedef struct xfs_dir2_leaf_hdr {
+ xfs_da_blkinfo_t info; /* header for da routines */
+ __uint16_t count; /* count of entries */
+ __uint16_t stale; /* count of stale entries */
+} xfs_dir2_leaf_hdr_t;
+
+
+/* those are from xfs_dir2_block.h */
+/*
+ * xfs_dir2_block.h
+ * Directory version 2, single block format structures
+ */
+
+/*
+ * The single block format is as follows:
+ * xfs_dir2_data_hdr_t structure
+ * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures
+ * xfs_dir2_leaf_entry_t structures
+ * xfs_dir2_block_tail_t structure
+ */
+
+#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */
+
+typedef struct xfs_dir2_block_tail {
+ __uint32_t count; /* count of leaf entries */
+ __uint32_t stale; /* count of stale lf entries */
+} xfs_dir2_block_tail_t;
+
+
+/* those are from xfs_dir2_sf.h */
+
+/*
+ * Directory layout when stored internal to an inode.
+ *
+ * Small directories are packed as tightly as possible so as to
+ * fit into the literal area of the inode.
+ */
+
+/*
+ * Inode number stored as 8 8-bit values.
+ */
+typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t;
+
+/*
+ * Inode number stored as 4 8-bit values.
+ * Works a lot of the time, when all the inode numbers in a directory
+ * fit in 32 bits.
+ */
+typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t;
+
+typedef union {
+ xfs_dir2_ino8_t i8;
+ xfs_dir2_ino4_t i4;
+} xfs_dir2_inou_t;
+
+/*
+ * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t.
+ * Only need 16 bits, this is the byte offset into the single block form.
+ */
+typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t;
+
+/*
+ * The parent directory has a dedicated field, and the self-pointer must
+ * be calculated on the fly.
+ *
+ * Entries are packed toward the top as tightly as possible. The header
+ * and the elements must be bcopy()'d out into a work area to get correct
+ * alignment for the inode number fields.
+ */
+typedef struct xfs_dir2_sf_hdr {
+ __uint8_t count; /* count of entries */
+ __uint8_t i8count; /* count of 8-byte inode #s */
+ xfs_dir2_inou_t parent; /* parent dir inode number */
+} xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+ __uint8_t namelen; /* actual name length */
+ xfs_dir2_sf_off_t offset; /* saved offset */
+ __uint8_t name[1]; /* name, variable size */
+ xfs_dir2_inou_t inumber; /* inode number, var. offset */
+} xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+ xfs_dir2_sf_hdr_t hdr; /* shortform header */
+ xfs_dir2_sf_entry_t list[1]; /* shortform entries */
+} xfs_dir2_sf_t;
+
+/* those are from xfs_dinode.h */
+
+#define XFS_DINODE_VERSION_1 1
+#define XFS_DINODE_VERSION_2 2
+#define XFS_DINODE_MAGIC 0x494e /* 'IN' */
+
+/*
+ * Disk inode structure.
+ * This is just the header; the inode is expanded to fill a variable size
+ * with the last field expanding. It is split into the core and "other"
+ * because we only need the core part in the in-core inode.
+ */
+typedef struct xfs_timestamp {
+ __int32_t t_sec; /* timestamp seconds */
+ __int32_t t_nsec; /* timestamp nanoseconds */
+} xfs_timestamp_t;
+
+/*
+ * Note: Coordinate changes to this structure with the XFS_DI_* #defines
+ * below and the offsets table in xfs_ialloc_log_di().
+ */
+typedef struct xfs_dinode_core
+{
+ __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
+ __uint16_t di_mode; /* mode and type of file */
+ __int8_t di_version; /* inode version */
+ __int8_t di_format; /* format of di_c data */
+ __uint16_t di_onlink; /* old number of links to file */
+ __uint32_t di_uid; /* owner's user id */
+ __uint32_t di_gid; /* owner's group id */
+ __uint32_t di_nlink; /* number of links to file */
+ __uint16_t di_projid; /* owner's project id */
+ __uint8_t di_pad[10]; /* unused, zeroed space */
+ xfs_timestamp_t di_atime; /* time last accessed */
+ xfs_timestamp_t di_mtime; /* time last modified */
+ xfs_timestamp_t di_ctime; /* time created/inode modified */
+ xfs_fsize_t di_size; /* number of bytes in file */
+ xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */
+ xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
+ xfs_extnum_t di_nextents; /* number of extents in data fork */
+ xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/
+ __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
+ __int8_t di_aformat; /* format of attr fork's data */
+ __uint32_t di_dmevmask; /* DMIG event mask */
+ __uint16_t di_dmstate; /* DMIG state info */
+ __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
+ __uint32_t di_gen; /* generation number */
+} xfs_dinode_core_t;
+
+typedef struct xfs_dinode
+{
+ xfs_dinode_core_t di_core;
+ xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */
+ union {
+ xfs_bmdr_block_t di_bmbt; /* btree root block */
+ xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */
+ xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */
+ char di_c[1]; /* local contents */
+ } di_u;
+} xfs_dinode_t;
+
+/*
+ * Values for di_format
+ */
+typedef enum xfs_dinode_fmt
+{
+ XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */
+ XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */
+ /* LNK: di_symlink */
+ XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */
+ XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */
+ XFS_DINODE_FMT_UUID /* MNT: di_uuid */
+} xfs_dinode_fmt_t;
+
+/*
+ * File types (mode field)
+ */
+#define IFMT 0170000 /* type of file */
+#define IFDIR 0040000 /* directory */
+#define IFREG 0100000 /* regular */
+#define IFLNK 0120000 /* symbolic link */