1
/* fsys_xfs.c - an implementation for the SGI XFS file system */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2001,2002,2004 Free Software Foundation, Inc.
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.
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.
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.
27
#define MAX_LINK_COUNT 8
39
unsigned int agblocks;
45
unsigned int nextents;
50
xfs_bmbt_rec_32_t *xt;
61
static struct xfs_info xfs;
63
#define dirbuf ((char *)FSYS_BUF)
64
#define filebuf ((char *)FSYS_BUF + 4096)
65
#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
66
#define icore (inode->di_core)
68
#define mask32lo(n) (((xfs_uint32_t)1 << (n)) - 1)
70
#define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1))
71
#define XFS_INO_OFFSET_BITS xfs.inopblog
72
#define XFS_INO_AGBNO_BITS xfs.agblklog
73
#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog)
74
#define XFS_INO_AGNO_BITS xfs.agnolog
75
#define NAME_BUF ((char *)FSYS_BUF + 12288)
77
static inline xfs_agblock_t
78
agino2agbno (xfs_agino_t agino)
80
return agino >> XFS_INO_OFFSET_BITS;
83
static inline xfs_agnumber_t
84
ino2agno (xfs_ino_t ino)
86
return ino >> XFS_INO_AGINO_BITS;
89
static inline xfs_agino_t
90
ino2agino (xfs_ino_t ino)
92
return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
96
ino2offset (xfs_ino_t ino)
98
return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
101
static inline /*__const__*/ xfs_uint16_t
102
le16 (xfs_uint16_t x)
104
__asm__("xchgb %b0,%h0" \
110
static inline /*__const__*/ xfs_uint32_t
111
le32 (xfs_uint32_t x)
114
/* 386 doesn't have bswap. */
115
__asm__("bswap %0" : "=r" (x) : "0" (x));
117
/* This is slower but this works on all x86 architectures. */
118
__asm__("xchgb %b0, %h0" \
120
"\n\txchgb %b0, %h0" \
121
: "=q" (x) : "0" (x));
126
static inline /*__const__*/ xfs_uint64_t
127
le64 (xfs_uint64_t x)
129
xfs_uint32_t h = x >> 32;
130
xfs_uint32_t l = x & ((1ULL<<32)-1);
131
return (((xfs_uint64_t)le32(l)) << 32) | ((xfs_uint64_t)(le32(h)));
136
xt_start (xfs_bmbt_rec_32_t *r)
138
return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) |
139
(((xfs_fsblock_t)le32 (r->l2)) << 11) |
140
(((xfs_fsblock_t)le32 (r->l3)) >> 21);
144
xt_offset (xfs_bmbt_rec_32_t *r)
146
return (((xfs_fileoff_t)le32 (r->l0) &
147
mask32lo(31)) << 23) |
148
(((xfs_fileoff_t)le32 (r->l1)) >> 9);
152
xt_len (xfs_bmbt_rec_32_t *r)
154
return le32(r->l3) & mask32lo(21);
158
xfs_highbit32(xfs_uint32_t v)
163
for (i = 0; i < 31; i++, v >>= 1) {
172
isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
174
return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
178
agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
180
return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
184
fsb2daddr (xfs_fsblock_t fsbno)
186
return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
187
(xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
191
#define offsetof(t,m) ((int)&(((t *)0)->m))
194
btroot_maxrecs (void)
196
int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
198
return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
199
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
203
di_read (xfs_ino_t ino)
211
agno = ino2agno (ino);
212
agino = ino2agino (ino);
213
agbno = agino2agbno (agino);
214
offset = ino2offset (ino);
215
daddr = agb2daddr (agno, agbno);
217
devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
219
xfs.ptr0 = *(xfs_bmbt_ptr_t *)
220
(inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
221
+ btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
230
xfs_btree_lblock_t h;
232
switch (icore.di_format) {
233
case XFS_DINODE_FMT_EXTENTS:
234
xfs.xt = inode->di_u.di_bmx;
235
xfs.nextents = le32 (icore.di_nextents);
237
case XFS_DINODE_FMT_BTREE:
240
xfs.daddr = fsb2daddr (le64(ptr0));
241
devread (xfs.daddr, 0,
242
sizeof(xfs_btree_lblock_t), (char *)&h);
244
xfs.nextents = le16(h.bb_numrecs);
245
xfs.next = fsb2daddr (le64(h.bb_rightsib));
246
xfs.fpos = sizeof(xfs_btree_block_t);
249
devread (xfs.daddr, xfs.btnode_ptr0_off,
250
sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
260
switch (icore.di_format) {
261
case XFS_DINODE_FMT_EXTENTS:
262
if (xfs.nextents == 0)
265
case XFS_DINODE_FMT_BTREE:
266
if (xfs.nextents == 0) {
267
xfs_btree_lblock_t h;
270
xfs.daddr = xfs.next;
271
devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
272
xfs.nextents = le16(h.bb_numrecs);
273
xfs.next = fsb2daddr (le64(h.bb_rightsib));
274
xfs.fpos = sizeof(xfs_btree_block_t);
276
/* Yeah, I know that's slow, but I really don't care */
277
devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
278
xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
279
xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
281
xad.offset = xt_offset (xfs.xt);
282
xad.start = xt_start (xfs.xt);
283
xad.len = xt_len (xfs.xt);
291
* Name lies - the function reads only first 100 bytes
297
xfs_fileoff_t offset;;
300
while ((xad = next_extent ())) {
301
offset = xad->offset;
302
if (isinxt (xfs.dablk, offset, xad->len)) {
303
devread (fsb2daddr (xad->start + xfs.dablk - offset),
310
static inline xfs_ino_t
311
sf_ino (char *sfe, int namelen)
313
void *p = sfe + namelen + 3;
315
return (xfs.i8param == 0)
316
? le64(*(xfs_ino_t *)p) : le32(*(xfs_uint32_t *)p);
319
static inline xfs_ino_t
322
return (xfs.i8param == 0)
323
? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
324
: le32(*(xfs_uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
334
next_dentry (xfs_ino_t *ino)
338
static char usual[2][3] = {".", ".."};
339
static xfs_dir2_sf_entry_t *sfe;
340
char *name = usual[0];
344
// char tmp_name[512];
346
char *tmp_name = NAME_BUF; /* MAXNAMLEN is 255, so 512 byte buffer is needed. */
349
if (xfs.dirpos >= xfs.dirmax) {
352
xfs.dablk = xfs.forw;
354
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
355
xfs.dirmax = le16 (h->count) - le16 (h->stale);
356
xfs.forw = le32 (h->info.forw);
361
switch (icore.di_format) {
362
case XFS_DINODE_FMT_LOCAL:
363
switch (xfs.dirpos) {
368
*ino = sf_parent_ino ();
371
sfe = (xfs_dir2_sf_entry_t *)
373
+ sizeof(xfs_dir2_sf_hdr_t)
377
namelen = sfe->namelen;
378
*ino = sf_ino ((char *)sfe, namelen);
379
name = (char *)(sfe->name);
380
sfe = (xfs_dir2_sf_entry_t *)
381
((char *)sfe + namelen + 11 - xfs.i8param);
384
case XFS_DINODE_FMT_BTREE:
385
case XFS_DINODE_FMT_EXTENTS:
386
#define dau ((xfs_dir2_data_union_t *)dirbuf)
388
if (xfs.blkoff >= xfs.dirbsize) {
389
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
390
filepos &= ~(xfs.dirbsize - 1);
391
filepos |= xfs.blkoff;
393
xfs_read (dirbuf, 4);
395
if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
396
toread = roundup8 (le16(dau->unused.length)) - 4;
397
xfs.blkoff += toread;
403
xfs_read ((char *)dirbuf + 4, 5);
404
*ino = le64 (dau->entry.inumber);
405
namelen = dau->entry.namelen;
407
toread = roundup8 (namelen + 11) - 9;
408
xfs_read (dirbuf, toread);
409
name = (char *)dirbuf;
410
xfs.blkoff += toread + 5;
415
/* copy name to tmp_name, and quote the spaces with a '\\' */
416
for (j = 0, k = 0; j < namelen; j++)
418
if (! (ch1 = name[j]))
421
tmp_name[k++] = '\\';
429
first_dentry (xfs_ino_t *ino)
432
switch (icore.di_format) {
433
case XFS_DINODE_FMT_LOCAL:
434
xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
435
xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
438
case XFS_DINODE_FMT_EXTENTS:
439
case XFS_DINODE_FMT_BTREE:
441
xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
442
if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
443
#define tail ((xfs_dir2_block_tail_t *)dirbuf)
444
filepos = xfs.dirbsize - sizeof(*tail);
445
xfs_read (dirbuf, sizeof(*tail));
446
xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
449
xfs.dablk = (1ULL << 35) >> xfs.blklog;
450
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
451
#define n ((xfs_da_intnode_t *)dirbuf)
454
if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
455
|| (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
456
xfs.dirmax = le16 (h->count) - le16 (h->stale);
457
xfs.forw = le32 (h->info.forw);
460
xfs.dablk = le32 (n->btree[0].before);
465
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
466
filepos = xfs.blkoff;
469
return next_dentry (ino);
476
xfs_sb_t super1; /* struct size 188 */
477
xfs_sb_t *super = &super1;
479
xfs_sb_t *super = (xfs_sb_t *)0x600;
482
if (!devread (0, 0, sizeof(xfs_sb_t), (char *)super)
483
|| (le32(super->sb_magicnum) != XFS_SB_MAGIC)
484
|| ((le16(super->sb_versionnum)
485
& XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
489
xfs.bsize = le32 (super->sb_blocksize);
490
xfs.blklog = super->sb_blocklog;
491
xfs.bdlog = xfs.blklog - SECTOR_BITS;
492
xfs.rootino = le64 (super->sb_rootino);
493
xfs.isize = le16 (super->sb_inodesize);
494
xfs.agblocks = le32 (super->sb_agblocks);
495
xfs.dirbsize = xfs.bsize << super->sb_dirblklog;
497
xfs.inopblog = super->sb_inopblog;
498
xfs.agblklog = super->sb_agblklog;
499
xfs.agnolog = xfs_highbit32 (le32(super->sb_agcount));
501
xfs.btnode_ptr0_off =
502
((xfs.bsize - sizeof(xfs_btree_block_t)) /
503
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
504
* sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
510
xfs_read (char *buf, unsigned long len)
513
xfs_fileoff_t endofprev, endofcur, offset;
514
xfs_filblks_t xadlen;
515
unsigned long toread, startpos, endpos;
517
if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
518
grub_memmove (buf, inode->di_u.di_c + filepos, len);
524
endpos = filepos + len;
525
endofprev = (xfs_fileoff_t)-1;
527
while (len > 0 && (xad = next_extent ()))
529
offset = xad->offset;
531
if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
532
endofcur = (offset + xadlen) << xfs.blklog;
533
toread = (endofcur >= endpos)
534
? len : (endofcur - filepos);
536
disk_read_func = disk_read_hook;
537
devread (fsb2daddr (xad->start),
538
filepos - (offset << xfs.blklog), toread, buf);
539
disk_read_func = NULL;
542
len -= toread; /* len always >= 0 */
544
} else if (offset > endofprev) {
545
toread = ((offset << xfs.blklog) >= endpos)
546
? len : ((offset - endofprev) << xfs.blklog);
549
for (; toread; toread--) {
552
if (len + toread < toread)
556
endofprev = offset + xadlen;
559
return filepos - startpos;
563
xfs_dir (char *dirname)
565
xfs_ino_t ino, parent_ino, new_ino;
567
unsigned long di_mode;
569
unsigned long n, link_count;
570
char *rest, *name, ch;
573
char linkbuf[xfs.bsize];
575
char *linkbuf = (char *)(FSYS_BUF - xfs.bsize);
578
parent_ino = ino = xfs.rootino;
582
di_size = le64 (icore.di_size);
583
di_mode = le16 (icore.di_mode);
585
if ((di_mode & IFMT) == IFLNK) {
586
if (++link_count > MAX_LINK_COUNT) {
587
errnum = ERR_SYMLINK_LOOP;
590
if (di_size < xfs.bsize - 1) {
593
n = xfs_read (linkbuf, filemax);
595
errnum = ERR_FILELENGTH;
599
ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
600
while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
606
if (!*dirname || isspace (*dirname)) {
607
if ((di_mode & IFMT) != IFREG) {
608
errnum = ERR_BAD_FILETYPE;
616
if ((di_mode & IFMT) != IFDIR) {
617
errnum = ERR_BAD_FILETYPE;
621
for (; *dirname == '/'; dirname++);
623
//for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
624
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++)
635
name = first_dentry (&new_ino);
637
cmp = (!*dirname) ? -1 : substring (dirname, name, 0);
639
if (print_possibilities && ch != '/' && cmp <= 0) {
640
if (print_possibilities > 0)
641
print_possibilities = -print_possibilities;
642
print_a_completion (name);
649
*(dirname = rest) = ch;
652
name = next_dentry (&new_ino);
654
if (print_possibilities < 0)
657
errnum = ERR_FILE_NOT_FOUND;
665
#endif /* FSYS_XFS */