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
isinxt(s64 key,s64 offset,s64 len)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 *
first_extent(dinode_t * di)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 *
next_extent(void)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
di_read(u32 inum,dinode_t * di)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 *
next_dentry(void)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 *
first_dentry(void)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 *
next_dslot(int next)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
uni2ansi(UniChar * uni,char * ansi,int len)200 uni2ansi (UniChar *uni, char *ansi, int len)
201 {
202 for (; len; len--, uni++)
203 *ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni;
204 }
205
206 int
jfs_mount(void)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
jfs_read(char * buf,int len)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
jfs_dir(char * dirname)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
jfs_embed(unsigned long long * start_sector,int needed_sectors)387 jfs_embed (unsigned long long *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