Home | History | Annotate | Download | only in stage2
      1 /* fsys_jfs.c - an implementation for the IBM JFS file system */
      2 /*
      3  *  GRUB  --  GRand Unified Bootloader
      4  *  Copyright (C) 2001,2002  Free Software Foundation, Inc.
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 #ifdef FSYS_JFS
     22 
     23 #include "shared.h"
     24 #include "filesys.h"
     25 #include "jfs.h"
     26 
     27 #define MAX_LINK_COUNT	8
     28 
     29 #define DTTYPE_INLINE	0
     30 #define DTTYPE_PAGE	1
     31 
     32 struct jfs_info
     33 {
     34 	int bsize;
     35 	int l2bsize;
     36 	int bdlog;
     37 	int xindex;
     38 	int xlastindex;
     39 	int sindex;
     40 	int slastindex;
     41 	int de_index;
     42 	int dttype;
     43 	xad_t *xad;
     44 	ldtentry_t *de;
     45 };
     46 
     47 static struct jfs_info jfs;
     48 
     49 #define xtpage		((xtpage_t *)FSYS_BUF)
     50 #define dtpage		((dtpage_t *)((char *)FSYS_BUF + 4096))
     51 #define fileset		((dinode_t *)((char *)FSYS_BUF + 8192))
     52 #define inode		((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t)))
     53 #define dtroot		((dtroot_t *)(&inode->di_btroot))
     54 
     55 static ldtentry_t de_always[2] = {
     56 	{1, -1, 2, {'.', '.'}},
     57 	{1, -1, 1, {'.'}}
     58 };
     59 
     60 static int
     61 isinxt (s64 key, s64 offset, s64 len)
     62 {
     63 	return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
     64 }
     65 
     66 static xad_t *
     67 first_extent (dinode_t *di)
     68 {
     69 	xtpage_t *xtp;
     70 
     71 	jfs.xindex = 2;
     72 	xtp = (xtpage_t *)&di->di_btroot;
     73 	jfs.xad = &xtp->xad[2];
     74 	if (xtp->header.flag & BT_LEAF) {
     75 	    	jfs.xlastindex = xtp->header.nextindex;
     76 	} else {
     77 		do {
     78 			devread (addressXAD (jfs.xad) << jfs.bdlog, 0,
     79 				 sizeof(xtpage_t), (char *)xtpage);
     80 			jfs.xad = &xtpage->xad[2];
     81 		} while (!(xtpage->header.flag & BT_LEAF));
     82 		jfs.xlastindex = xtpage->header.nextindex;
     83 	}
     84 
     85 	return jfs.xad;
     86 }
     87 
     88 static xad_t *
     89 next_extent (void)
     90 {
     91 	if (++jfs.xindex < jfs.xlastindex) {
     92 	} else if (xtpage->header.next) {
     93 		devread (xtpage->header.next << jfs.bdlog, 0,
     94 			 sizeof(xtpage_t), (char *)xtpage);
     95 		jfs.xlastindex = xtpage->header.nextindex;
     96 		jfs.xindex = XTENTRYSTART;
     97 		jfs.xad = &xtpage->xad[XTENTRYSTART];
     98 	} else {
     99 		return NULL;
    100 	}
    101 	return ++jfs.xad;
    102 }
    103 
    104 
    105 static void
    106 di_read (u32 inum, dinode_t *di)
    107 {
    108 	s64 key;
    109 	u32 xd, ioffset;
    110 	s64 offset;
    111 	xad_t *xad;
    112 	pxd_t pxd;
    113 
    114 	key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize;
    115 	xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT;
    116 	ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE;
    117 	xad = first_extent (fileset);
    118 	do {
    119 		offset = offsetXAD (xad);
    120 		if (isinxt (key, offset, lengthXAD (xad))) {
    121 			devread ((addressXAD (xad) + key - offset) << jfs.bdlog,
    122 				 3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd);
    123 			devread (addressPXD (&pxd) << jfs.bdlog,
    124 				 ioffset, DISIZE, (char *)di);
    125 			break;
    126 		}
    127 	} while ((xad = next_extent ()));
    128 }
    129 
    130 static ldtentry_t *
    131 next_dentry (void)
    132 {
    133 	ldtentry_t *de;
    134 	s8 *stbl;
    135 
    136 	if (jfs.dttype == DTTYPE_INLINE) {
    137 		if (jfs.sindex < jfs.slastindex) {
    138 			return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]];
    139 		}
    140 	} else {
    141 		de = (ldtentry_t *)dtpage->slot;
    142 		stbl = (s8 *)&de[(int)dtpage->header.stblindex];
    143 		if (jfs.sindex < jfs.slastindex) {
    144 			return &de[(int)stbl[jfs.sindex++]];
    145 		} else if (dtpage->header.next) {
    146 			devread (dtpage->header.next << jfs.bdlog, 0,
    147 				 sizeof(dtpage_t), (char *)dtpage);
    148 			jfs.slastindex = dtpage->header.nextindex;
    149 			jfs.sindex = 1;
    150 			return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]];
    151 		}
    152 	}
    153 
    154 	return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL;
    155 }
    156 
    157 static ldtentry_t *
    158 first_dentry (void)
    159 {
    160 	dtroot_t *dtr;
    161 	pxd_t *xd;
    162 	idtentry_t *de;
    163 
    164 	dtr = (dtroot_t *)&inode->di_btroot;
    165 	jfs.sindex = 0;
    166 	jfs.de_index = 0;
    167 
    168 	de_always[0].inumber = inode->di_parent;
    169 	de_always[1].inumber = inode->di_number;
    170 	if (dtr->header.flag & BT_LEAF) {
    171 		jfs.dttype = DTTYPE_INLINE;
    172 		jfs.slastindex = dtr->header.nextindex;
    173 	} else {
    174 		de = (idtentry_t *)dtpage->slot;
    175 		jfs.dttype = DTTYPE_PAGE;
    176 		xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd;
    177 		for (;;) {
    178 			devread (addressPXD (xd) << jfs.bdlog, 0,
    179 				 sizeof(dtpage_t), (char *)dtpage);
    180 			if (dtpage->header.flag & BT_LEAF)
    181 				break;
    182 			xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd;
    183 		}
    184 		jfs.slastindex = dtpage->header.nextindex;
    185 	}
    186 
    187 	return next_dentry ();
    188 }
    189 
    190 
    191 static dtslot_t *
    192 next_dslot (int next)
    193 {
    194 	return (jfs.dttype == DTTYPE_INLINE)
    195 		? (dtslot_t *)&dtroot->slot[next]
    196 		: &((dtslot_t *)dtpage->slot)[next];
    197 }
    198 
    199 static void
    200 uni2ansi (UniChar *uni, char *ansi, int len)
    201 {
    202 	for (; len; len--, uni++)
    203 		*ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni;
    204 }
    205 
    206 int
    207 jfs_mount (void)
    208 {
    209 	struct jfs_superblock super;
    210 
    211 	if (part_length < MINJFS >> SECTOR_BITS
    212 	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
    213 			 sizeof(struct jfs_superblock), (char *)&super)
    214 	    || (super.s_magic != JFS_MAGIC)
    215 	    || !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I,
    216 			 0, DISIZE, (char*)fileset)) {
    217 		return 0;
    218 	}
    219 
    220 	jfs.bsize = super.s_bsize;
    221 	jfs.l2bsize = super.s_l2bsize;
    222 	jfs.bdlog = jfs.l2bsize - SECTOR_BITS;
    223 
    224 	return 1;
    225 }
    226 
    227 int
    228 jfs_read (char *buf, int len)
    229 {
    230 	xad_t *xad;
    231 	s64 endofprev, endofcur;
    232 	s64 offset, xadlen;
    233 	int toread, startpos, endpos;
    234 
    235 	startpos = filepos;
    236 	endpos = filepos + len;
    237 	endofprev = (1ULL << 62) - 1;
    238 	xad = first_extent (inode);
    239 	do {
    240 		offset = offsetXAD (xad);
    241 		xadlen = lengthXAD (xad);
    242 		if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) {
    243 			endofcur = (offset + xadlen) << jfs.l2bsize;
    244 			toread = (endofcur >= endpos)
    245 				  ? len : (endofcur - filepos);
    246 
    247 			disk_read_func = disk_read_hook;
    248 			devread (addressXAD (xad) << jfs.bdlog,
    249 				 filepos - (offset << jfs.l2bsize), toread, buf);
    250 			disk_read_func = NULL;
    251 
    252 			buf += toread;
    253 			len -= toread;
    254 			filepos += toread;
    255 		} else if (offset > endofprev) {
    256 			toread = ((offset << jfs.l2bsize) >= endpos)
    257 				  ? len : ((offset - endofprev) << jfs.l2bsize);
    258 			len -= toread;
    259 			filepos += toread;
    260 			for (; toread; toread--) {
    261 				*buf++ = 0;
    262 			}
    263 			continue;
    264 		}
    265 		endofprev = offset + xadlen;
    266 		xad = next_extent ();
    267 	} while (len > 0 && xad);
    268 
    269 	return filepos - startpos;
    270 }
    271 
    272 int
    273 jfs_dir (char *dirname)
    274 {
    275 	char *ptr, *rest, ch;
    276 	ldtentry_t *de;
    277 	dtslot_t *ds;
    278 	u32 inum, parent_inum;
    279 	s64 di_size;
    280 	u32 di_mode;
    281 	int namlen, cmp, n, link_count;
    282 	char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX];
    283 
    284 	parent_inum = inum = ROOT_I;
    285 	link_count = 0;
    286 	for (;;) {
    287 		di_read (inum, inode);
    288 		di_size = inode->di_size;
    289 		di_mode = inode->di_mode;
    290 
    291 		if ((di_mode & IFMT) == IFLNK) {
    292 			if (++link_count > MAX_LINK_COUNT) {
    293 				errnum = ERR_SYMLINK_LOOP;
    294 				return 0;
    295 			}
    296 			if (di_size < (di_mode & INLINEEA ? 256 : 128)) {
    297 				grub_memmove (linkbuf, inode->di_fastsymlink, di_size);
    298 				n = di_size;
    299 			} else if (di_size < JFS_PATH_MAX - 1) {
    300 				filepos = 0;
    301 				filemax = di_size;
    302 				n = jfs_read (linkbuf, filemax);
    303 			} else {
    304 				errnum = ERR_FILELENGTH;
    305 				return 0;
    306 			}
    307 
    308 			inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum;
    309 			while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++));
    310 			linkbuf[n] = 0;
    311 			dirname = linkbuf;
    312 			continue;
    313 		}
    314 
    315 		if (!*dirname || isspace (*dirname)) {
    316 			if ((di_mode & IFMT) != IFREG) {
    317 				errnum = ERR_BAD_FILETYPE;
    318 				return 0;
    319 			}
    320 			filepos = 0;
    321 			filemax = di_size;
    322 			return 1;
    323 		}
    324 
    325 		if ((di_mode & IFMT) != IFDIR) {
    326 			errnum = ERR_BAD_FILETYPE;
    327 			return 0;
    328 		}
    329 
    330 		for (; *dirname == '/'; dirname++);
    331 
    332 		for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
    333 		*rest = 0;
    334 
    335 		de = first_dentry ();
    336 		for (;;) {
    337 			namlen = de->namlen;
    338 			if (de->next == -1) {
    339 				uni2ansi (de->name, namebuf, namlen);
    340 				namebuf[namlen] = 0;
    341 			} else {
    342 				uni2ansi (de->name, namebuf, DTLHDRDATALEN);
    343 				ptr = namebuf;
    344 				ptr += DTLHDRDATALEN;
    345 				namlen -= DTLHDRDATALEN;
    346 				ds = next_dslot (de->next);
    347 				while (ds->next != -1) {
    348 					uni2ansi (ds->name, ptr, DTSLOTDATALEN);
    349 					ptr += DTSLOTDATALEN;
    350 					namlen -= DTSLOTDATALEN;
    351 					ds = next_dslot (ds->next);
    352 				}
    353 				uni2ansi (ds->name, ptr, namlen);
    354 				ptr += namlen;
    355 				*ptr = 0;
    356 			}
    357 
    358 			cmp = (!*dirname) ? -1 : substring (dirname, namebuf);
    359 #ifndef STAGE1_5
    360 			if (print_possibilities && ch != '/'
    361 			    && cmp <= 0) {
    362 				if (print_possibilities > 0)
    363 					print_possibilities = -print_possibilities;
    364 				print_a_completion (namebuf);
    365 			} else
    366 #endif
    367 			if (cmp == 0) {
    368 				parent_inum = inum;
    369 				inum = de->inumber;
    370 		        	*(dirname = rest) = ch;
    371 				break;
    372 			}
    373 			de = next_dentry ();
    374 			if (de == NULL) {
    375 				if (print_possibilities < 0)
    376 					return 1;
    377 
    378 				errnum = ERR_FILE_NOT_FOUND;
    379 				*rest = ch;
    380 				return 0;
    381 			}
    382 		}
    383 	}
    384 }
    385 
    386 int
    387 jfs_embed (int *start_sector, int needed_sectors)
    388 {
    389 	struct jfs_superblock super;
    390 
    391 	if (needed_sectors > 63
    392 	    || !devread (SUPER1_OFF >> SECTOR_BITS, 0,
    393 			 sizeof (struct jfs_superblock),
    394 			 (char *)&super)
    395 	    || (super.s_magic != JFS_MAGIC)) {
    396 		return 0;
    397 	}
    398 
    399 	*start_sector = 1;
    400 	return 1;
    401 }
    402 
    403 #endif /* FSYS_JFS */
    404