Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / grubfs / fsys_jfs.c
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_jfs.c b/qemu/roms/openbios/fs/grubfs/fsys_jfs.c
new file mode 100644 (file)
index 0000000..66469e6
--- /dev/null
@@ -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 */