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