diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openbios/fs/grubfs | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (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')
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 */ |