404 lines
9.2 KiB
C
404 lines
9.2 KiB
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., 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 */
|