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