summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/fs/grubfs/fsys_jfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/fs/grubfs/fsys_jfs.c')
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_jfs.c404
1 files changed, 404 insertions, 0 deletions
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 */