Logo Search packages:      
Sourcecode: xbox-cromwell version File versions  Download package

fsys_jfs.c

/* 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., 675 Mass Ave, Cambridge, MA 02139, 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, {'.', '.'}},
      {1, -1, 1, {'.'}}
};

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 */

Generated by  Doxygen 1.6.0   Back to index