|
|
1.1 root 1: /* fsys_xfs.c - an implementation for the SGI XFS 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_XFS
23:
24: #include "shared.h"
25: #include "filesys.h"
26: #include "xfs.h"
27:
28: #define MAX_LINK_COUNT 8
29:
30: typedef struct xad {
31: xfs_fileoff_t offset;
32: xfs_fsblock_t start;
33: xfs_filblks_t len;
34: } xad_t;
35:
36: struct xfs_info {
37: int bsize;
38: int dirbsize;
39: int isize;
40: unsigned int agblocks;
41: int bdlog;
42: int blklog;
43: int inopblog;
44: int agblklog;
45: int agnolog;
46: unsigned int nextents;
47: xfs_daddr_t next;
48: xfs_daddr_t daddr;
49: xfs_dablk_t forw;
50: xfs_dablk_t dablk;
51: xfs_bmbt_rec_32_t *xt;
52: xfs_bmbt_ptr_t ptr0;
53: int btnode_ptr0_off;
54: int i8param;
55: int dirpos;
56: int dirmax;
57: int blkoff;
58: int fpos;
59: xfs_ino_t rootino;
60: };
61:
62: static struct xfs_info xfs;
63:
64: #define dirbuf ((char *)FSYS_BUF)
65: #define filebuf ((char *)FSYS_BUF + 4096)
66: #define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
67: #define icore (inode->di_core)
68:
69: #define mask32lo(n) (((__uint32_t)1 << (n)) - 1)
70:
71: #define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1))
72: #define XFS_INO_OFFSET_BITS xfs.inopblog
73: #define XFS_INO_AGBNO_BITS xfs.agblklog
74: #define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog)
75: #define XFS_INO_AGNO_BITS xfs.agnolog
76:
77: static inline xfs_agblock_t
78: agino2agbno (xfs_agino_t agino)
79: {
80: return agino >> XFS_INO_OFFSET_BITS;
81: }
82:
83: static inline xfs_agnumber_t
84: ino2agno (xfs_ino_t ino)
85: {
86: return ino >> XFS_INO_AGINO_BITS;
87: }
88:
89: static inline xfs_agino_t
90: ino2agino (xfs_ino_t ino)
91: {
92: return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
93: }
94:
95: static inline int
96: ino2offset (xfs_ino_t ino)
97: {
98: return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
99: }
100:
101: static inline __uint16_t
102: le16 (__uint16_t x)
103: {
104: #ifdef __i386__
105: __asm__("xchgb %b0,%h0" \
106: : "=q" (x) \
107: : "0" (x)); \
108: return x;
109: #else
110: return __be16_to_cpu(x);
111: #endif
112: }
113:
114: static inline __uint32_t
115: le32 (__uint32_t x)
116: {
117: #ifdef __i386__
118: #if 1
119: /* 386 doesn't have bswap. So what. */
120: __asm__("bswap %0" : "=r" (x) : "0" (x));
121: #else
122: /* This is slower but this works on all x86 architectures. */
123: __asm__("xchgb %b0, %h0" \
124: "\n\troll $16, %0" \
125: "\n\txchgb %b0, %h0" \
126: : "=q" (x) : "0" (x));
127: #endif
128: return x;
129: #else
130: return __be32_to_cpu(x);
131: #endif
132: }
133:
134: static inline __uint64_t
135: le64 (__uint64_t x)
136: {
137: __uint32_t h = x >> 32;
138: __uint32_t l = x & ((1ULL<<32)-1);
139: return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h)));
140: }
141:
142:
143: static xfs_fsblock_t
144: xt_start (xfs_bmbt_rec_32_t *r)
145: {
146: return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) |
147: (((xfs_fsblock_t)le32 (r->l2)) << 11) |
148: (((xfs_fsblock_t)le32 (r->l3)) >> 21);
149: }
150:
151: static xfs_fileoff_t
152: xt_offset (xfs_bmbt_rec_32_t *r)
153: {
154: return (((xfs_fileoff_t)le32 (r->l0) &
155: mask32lo(31)) << 23) |
156: (((xfs_fileoff_t)le32 (r->l1)) >> 9);
157: }
158:
159: static xfs_filblks_t
160: xt_len (xfs_bmbt_rec_32_t *r)
161: {
162: return le32(r->l3) & mask32lo(21);
163: }
164:
165: static inline int
166: xfs_highbit32(__uint32_t v)
167: {
168: int i;
169:
170: if (--v) {
171: for (i = 0; i < 31; i++, v >>= 1) {
172: if (v == 0)
173: return i;
174: }
175: }
176: return 0;
177: }
178:
179: static int
180: isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
181: {
182: return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
183: }
184:
185: static xfs_daddr_t
186: agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
187: {
188: return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
189: }
190:
191: static xfs_daddr_t
192: fsb2daddr (xfs_fsblock_t fsbno)
193: {
194: return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
195: (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
196: }
197:
198: #undef offsetof
199: #define offsetof(t,m) ((long)&(((t *)0)->m))
200:
201: static inline int
202: btroot_maxrecs (void)
203: {
204: int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
205:
206: return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
207: (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
208: }
209:
210: static int
211: di_read (xfs_ino_t ino)
212: {
213: xfs_agino_t agino;
214: xfs_agnumber_t agno;
215: xfs_agblock_t agbno;
216: xfs_daddr_t daddr;
217: int offset;
218:
219: agno = ino2agno (ino);
220: agino = ino2agino (ino);
221: agbno = agino2agbno (agino);
222: offset = ino2offset (ino);
223: daddr = agb2daddr (agno, agbno);
224:
225: devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
226:
227: xfs.ptr0 = *(xfs_bmbt_ptr_t *)
228: (inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
229: + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
230:
231: return 1;
232: }
233:
234: static void
235: init_extents (void)
236: {
237: xfs_bmbt_ptr_t ptr0;
238: xfs_btree_lblock_t h;
239:
240: switch (icore.di_format) {
241: case XFS_DINODE_FMT_EXTENTS:
242: xfs.xt = inode->di_u.di_bmx;
243: xfs.nextents = le32 (icore.di_nextents);
244: break;
245: case XFS_DINODE_FMT_BTREE:
246: ptr0 = xfs.ptr0;
247: for (;;) {
248: xfs.daddr = fsb2daddr (le64(ptr0));
249: devread (xfs.daddr, 0,
250: sizeof(xfs_btree_lblock_t), (char *)&h);
251: if (!h.bb_level) {
252: xfs.nextents = le16(h.bb_numrecs);
253: xfs.next = fsb2daddr (le64(h.bb_rightsib));
254: xfs.fpos = sizeof(xfs_btree_block_t);
255: return;
256: }
257: devread (xfs.daddr, xfs.btnode_ptr0_off,
258: sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
259: }
260: }
261: }
262:
263: static xad_t *
264: next_extent (void)
265: {
266: static xad_t xad;
267:
268: switch (icore.di_format) {
269: case XFS_DINODE_FMT_EXTENTS:
270: if (xfs.nextents == 0)
271: return NULL;
272: break;
273: case XFS_DINODE_FMT_BTREE:
274: if (xfs.nextents == 0) {
275: xfs_btree_lblock_t h;
276: if (xfs.next == 0)
277: return NULL;
278: xfs.daddr = xfs.next;
279: devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
280: xfs.nextents = le16(h.bb_numrecs);
281: xfs.next = fsb2daddr (le64(h.bb_rightsib));
282: xfs.fpos = sizeof(xfs_btree_block_t);
283: }
284: /* Yeah, I know that's slow, but I really don't care */
285: devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
286: xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
287: xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
288: }
289: xad.offset = xt_offset (xfs.xt);
290: xad.start = xt_start (xfs.xt);
291: xad.len = xt_len (xfs.xt);
292: ++xfs.xt;
293: --xfs.nextents;
294:
295: return &xad;
296: }
297:
298: /*
299: * Name lies - the function reads only first 100 bytes
300: */
301: static void
302: xfs_dabread (void)
303: {
304: xad_t *xad;
305: xfs_fileoff_t offset;;
306:
307: init_extents ();
308: while ((xad = next_extent ())) {
309: offset = xad->offset;
310: if (isinxt (xfs.dablk, offset, xad->len)) {
311: devread (fsb2daddr (xad->start + xfs.dablk - offset),
312: 0, 100, dirbuf);
313: break;
314: }
315: }
316: }
317:
318: static inline xfs_ino_t
319: sf_ino (char *sfe, int namelen)
320: {
321: void *p = sfe + namelen + 3;
322:
323: return (xfs.i8param == 0)
324: ? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p);
325: }
326:
327: static inline xfs_ino_t
328: sf_parent_ino (void)
329: {
330: return (xfs.i8param == 0)
331: ? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
332: : le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
333: }
334:
335: static inline int
336: roundup8 (int n)
337: {
338: return ((n+7)&~7);
339: }
340:
341: static char *
342: next_dentry (xfs_ino_t *ino)
343: {
344: int namelen = 1;
345: int toread;
346: static char *usual[2];
347: static xfs_dir2_sf_entry_t *sfe;
348: char *name;
349:
350: if (!usual[0]) {
351: usual[0] = strdup(".");
352: usual[1] = strdup("..");
353: }
354: name = usual[0];
355:
356: if (xfs.dirpos >= xfs.dirmax) {
357: if (xfs.forw == 0)
358: return NULL;
359: xfs.dablk = xfs.forw;
360: xfs_dabread ();
361: #define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
362: xfs.dirmax = le16 (h->count) - le16 (h->stale);
363: xfs.forw = le32 (h->info.forw);
364: #undef h
365: xfs.dirpos = 0;
366: }
367:
368: switch (icore.di_format) {
369: case XFS_DINODE_FMT_LOCAL:
370: switch (xfs.dirpos) {
371: case -2:
372: *ino = 0;
373: break;
374: case -1:
375: *ino = sf_parent_ino ();
376: ++name;
377: ++namelen;
378: sfe = (xfs_dir2_sf_entry_t *)
379: (inode->di_u.di_c
380: + sizeof(xfs_dir2_sf_hdr_t)
381: - xfs.i8param);
382: break;
383: default:
384: namelen = sfe->namelen;
385: *ino = sf_ino ((char *)sfe, namelen);
386: name = (char *)sfe->name;
387: sfe = (xfs_dir2_sf_entry_t *)
388: ((char *)sfe + namelen + 11 - xfs.i8param);
389: }
390: break;
391: case XFS_DINODE_FMT_BTREE:
392: case XFS_DINODE_FMT_EXTENTS:
393: #define dau ((xfs_dir2_data_union_t *)dirbuf)
394: for (;;) {
395: if (xfs.blkoff >= xfs.dirbsize) {
396: xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
397: filepos &= ~(xfs.dirbsize - 1);
398: filepos |= xfs.blkoff;
399: }
400: xfs_read (dirbuf, 4);
401: xfs.blkoff += 4;
402: if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
403: toread = roundup8 (le16(dau->unused.length)) - 4;
404: xfs.blkoff += toread;
405: filepos += toread;
406: continue;
407: }
408: break;
409: }
410: xfs_read ((char *)dirbuf + 4, 5);
411: *ino = le64 (dau->entry.inumber);
412: namelen = dau->entry.namelen;
413: #undef dau
414: toread = roundup8 (namelen + 11) - 9;
415: xfs_read (dirbuf, toread);
416: name = (char *)dirbuf;
417: xfs.blkoff += toread + 5;
418: }
419: ++xfs.dirpos;
420: name[namelen] = 0;
421:
422: return name;
423: }
424:
425: static char *
426: first_dentry (xfs_ino_t *ino)
427: {
428: xfs.forw = 0;
429: switch (icore.di_format) {
430: case XFS_DINODE_FMT_LOCAL:
431: xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
432: xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
433: xfs.dirpos = -2;
434: break;
435: case XFS_DINODE_FMT_EXTENTS:
436: case XFS_DINODE_FMT_BTREE:
437: filepos = 0;
438: xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
439: if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
440: #define tail ((xfs_dir2_block_tail_t *)dirbuf)
441: filepos = xfs.dirbsize - sizeof(*tail);
442: xfs_read (dirbuf, sizeof(*tail));
443: xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
444: #undef tail
445: } else {
446: xfs.dablk = (1ULL << 35) >> xfs.blklog;
447: #define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
448: #define n ((xfs_da_intnode_t *)dirbuf)
449: for (;;) {
450: xfs_dabread ();
451: if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
452: || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
453: xfs.dirmax = le16 (h->count) - le16 (h->stale);
454: xfs.forw = le32 (h->info.forw);
455: break;
456: }
457: xfs.dablk = le32 (n->btree[0].before);
458: }
459: #undef n
460: #undef h
461: }
462: xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
463: filepos = xfs.blkoff;
464: xfs.dirpos = 0;
465: }
466: return next_dentry (ino);
467: }
468:
469: int
470: xfs_mount (void)
471: {
472: xfs_sb_t super;
473:
474: if (!devread (0, 0, sizeof(super), (char *)&super)
475: || (le32(super.sb_magicnum) != XFS_SB_MAGIC)
476: || ((le16(super.sb_versionnum)
477: & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
478: return 0;
479: }
480:
481: xfs.bsize = le32 (super.sb_blocksize);
482: xfs.blklog = super.sb_blocklog;
483: xfs.bdlog = xfs.blklog - SECTOR_BITS;
484: xfs.rootino = le64 (super.sb_rootino);
485: xfs.isize = le16 (super.sb_inodesize);
486: xfs.agblocks = le32 (super.sb_agblocks);
487: xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
488:
489: xfs.inopblog = super.sb_inopblog;
490: xfs.agblklog = super.sb_agblklog;
491: xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
492:
493: xfs.btnode_ptr0_off =
494: ((xfs.bsize - sizeof(xfs_btree_block_t)) /
495: (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
496: * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
497:
498: return 1;
499: }
500:
501: int
502: xfs_read (char *buf, int len)
503: {
504: xad_t *xad;
505: xfs_fileoff_t endofprev, endofcur, offset;
506: xfs_filblks_t xadlen;
507: int toread, startpos, endpos;
508:
509: if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
510: grub_memmove (buf, inode->di_u.di_c + filepos, len);
511: filepos += len;
512: return len;
513: }
514:
515: startpos = filepos;
516: endpos = filepos + len;
517: endofprev = (xfs_fileoff_t)-1;
518: init_extents ();
519: while (len > 0 && (xad = next_extent ())) {
520: offset = xad->offset;
521: xadlen = xad->len;
522: if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
523: endofcur = (offset + xadlen) << xfs.blklog;
524: toread = (endofcur >= endpos)
525: ? len : (endofcur - filepos);
526:
527: disk_read_func = disk_read_hook;
528: devread (fsb2daddr (xad->start),
529: filepos - (offset << xfs.blklog), toread, buf);
530: disk_read_func = NULL;
531:
532: buf += toread;
533: len -= toread;
534: filepos += toread;
535: } else if (offset > endofprev) {
536: toread = ((offset << xfs.blklog) >= endpos)
537: ? len : ((offset - endofprev) << xfs.blklog);
538: len -= toread;
539: filepos += toread;
540: for (; toread; toread--) {
541: *buf++ = 0;
542: }
543: continue;
544: }
545: endofprev = offset + xadlen;
546: }
547:
548: return filepos - startpos;
549: }
550:
551: int
552: xfs_dir (char *dirname)
553: {
554: xfs_ino_t ino, parent_ino, new_ino;
555: xfs_fsize_t di_size;
556: int di_mode;
557: int cmp, n, link_count;
558: char linkbuf[xfs.bsize];
559: char *rest, *name, ch;
560:
561: parent_ino = ino = xfs.rootino;
562: link_count = 0;
563: for (;;) {
564: di_read (ino);
565: di_size = le64 (icore.di_size);
566: di_mode = le16 (icore.di_mode);
567:
568: if ((di_mode & IFMT) == IFLNK) {
569: if (++link_count > MAX_LINK_COUNT) {
570: errnum = ERR_SYMLINK_LOOP;
571: return 0;
572: }
573: if (di_size < xfs.bsize - 1) {
574: filepos = 0;
575: filemax = di_size;
576: n = xfs_read (linkbuf, filemax);
577: } else {
578: errnum = ERR_FILELENGTH;
579: return 0;
580: }
581:
582: ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
583: while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
584: linkbuf[n] = 0;
585: dirname = linkbuf;
586: continue;
587: }
588:
589: if (!*dirname || isspace (*dirname)) {
590: if ((di_mode & IFMT) != IFREG) {
591: errnum = ERR_BAD_FILETYPE;
592: return 0;
593: }
594: filepos = 0;
595: filemax = di_size;
596: return 1;
597: }
598:
599: if ((di_mode & IFMT) != IFDIR) {
600: errnum = ERR_BAD_FILETYPE;
601: return 0;
602: }
603:
604: for (; *dirname == '/'; dirname++);
605:
606: for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
607: *rest = 0;
608:
609: name = first_dentry (&new_ino);
610: for (;;) {
611: cmp = (!*dirname) ? -1 : substring (dirname, name);
612: #ifndef STAGE1_5
613: if (print_possibilities && ch != '/' && cmp <= 0) {
614: if (print_possibilities > 0)
615: print_possibilities = -print_possibilities;
616: print_a_completion (name);
617: } else
618: #endif
619: if (cmp == 0) {
620: parent_ino = ino;
621: if (new_ino)
622: ino = new_ino;
623: *(dirname = rest) = ch;
624: break;
625: }
626: name = next_dentry (&new_ino);
627: if (name == NULL) {
628: if (print_possibilities < 0)
629: return 1;
630:
631: errnum = ERR_FILE_NOT_FOUND;
632: *rest = ch;
633: return 0;
634: }
635: }
636: }
637: }
638:
639: #endif /* FSYS_XFS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.