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