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