1*518e2e1aSwdenk /* 2*518e2e1aSwdenk * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README 3*518e2e1aSwdenk * 4*518e2e1aSwdenk * GRUB -- GRand Unified Bootloader 5*518e2e1aSwdenk * Copyright (C) 2000, 2001 Free Software Foundation, Inc. 6*518e2e1aSwdenk * 7*518e2e1aSwdenk * (C) Copyright 2003 - 2004 8*518e2e1aSwdenk * Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com> 9*518e2e1aSwdenk * 10*518e2e1aSwdenk * 11*518e2e1aSwdenk * This program is free software; you can redistribute it and/or modify 12*518e2e1aSwdenk * it under the terms of the GNU General Public License as published by 13*518e2e1aSwdenk * the Free Software Foundation; either version 2 of the License, or 14*518e2e1aSwdenk * (at your option) any later version. 15*518e2e1aSwdenk * 16*518e2e1aSwdenk * This program is distributed in the hope that it will be useful, 17*518e2e1aSwdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 18*518e2e1aSwdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19*518e2e1aSwdenk * GNU General Public License for more details. 20*518e2e1aSwdenk * 21*518e2e1aSwdenk * You should have received a copy of the GNU General Public License 22*518e2e1aSwdenk * along with this program; if not, write to the Free Software 23*518e2e1aSwdenk * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24*518e2e1aSwdenk */ 25*518e2e1aSwdenk 26*518e2e1aSwdenk /* An implementation for the ReiserFS filesystem ported from GRUB. 27*518e2e1aSwdenk * Some parts of this code (mainly the structures and defines) are 28*518e2e1aSwdenk * from the original reiser fs code, as found in the linux kernel. 29*518e2e1aSwdenk */ 30*518e2e1aSwdenk 31*518e2e1aSwdenk #include <common.h> 32*518e2e1aSwdenk #if (CONFIG_COMMANDS & CFG_CMD_REISER) 33*518e2e1aSwdenk 34*518e2e1aSwdenk #include <malloc.h> 35*518e2e1aSwdenk #include <linux/ctype.h> 36*518e2e1aSwdenk #include <linux/time.h> 37*518e2e1aSwdenk #include <asm/byteorder.h> 38*518e2e1aSwdenk #include <reiserfs.h> 39*518e2e1aSwdenk 40*518e2e1aSwdenk #include "reiserfs_private.h" 41*518e2e1aSwdenk 42*518e2e1aSwdenk #undef REISERDEBUG 43*518e2e1aSwdenk 44*518e2e1aSwdenk /* Some parts of this code (mainly the structures and defines) are 45*518e2e1aSwdenk * from the original reiser fs code, as found in the linux kernel. 46*518e2e1aSwdenk */ 47*518e2e1aSwdenk 48*518e2e1aSwdenk static char fsys_buf[FSYS_BUFLEN]; 49*518e2e1aSwdenk static reiserfs_error_t errnum = ERR_NONE; 50*518e2e1aSwdenk static int print_possibilities; 51*518e2e1aSwdenk static unsigned int filepos, filemax; 52*518e2e1aSwdenk 53*518e2e1aSwdenk static int 54*518e2e1aSwdenk substring (const char *s1, const char *s2) 55*518e2e1aSwdenk { 56*518e2e1aSwdenk while (*s1 == *s2) 57*518e2e1aSwdenk { 58*518e2e1aSwdenk /* The strings match exactly. */ 59*518e2e1aSwdenk if (! *(s1++)) 60*518e2e1aSwdenk return 0; 61*518e2e1aSwdenk s2 ++; 62*518e2e1aSwdenk } 63*518e2e1aSwdenk 64*518e2e1aSwdenk /* S1 is a substring of S2. */ 65*518e2e1aSwdenk if (*s1 == 0) 66*518e2e1aSwdenk return -1; 67*518e2e1aSwdenk 68*518e2e1aSwdenk /* S1 isn't a substring. */ 69*518e2e1aSwdenk return 1; 70*518e2e1aSwdenk } 71*518e2e1aSwdenk 72*518e2e1aSwdenk static void sd_print_item (struct item_head * ih, char * item) 73*518e2e1aSwdenk { 74*518e2e1aSwdenk char filetime[30]; 75*518e2e1aSwdenk time_t ttime; 76*518e2e1aSwdenk 77*518e2e1aSwdenk if (stat_data_v1 (ih)) { 78*518e2e1aSwdenk struct stat_data_v1 * sd = (struct stat_data_v1 *)item; 79*518e2e1aSwdenk ttime = sd_v1_mtime(sd); 80*518e2e1aSwdenk ctime_r(&ttime, filetime); 81*518e2e1aSwdenk printf ("%-10s %4hd %6d %6d %9d %24.24s", 82*518e2e1aSwdenk bb_mode_string(sd_v1_mode(sd)), sd_v1_nlink(sd),sd_v1_uid(sd), sd_v1_gid(sd), 83*518e2e1aSwdenk sd_v1_size(sd), filetime); 84*518e2e1aSwdenk } else { 85*518e2e1aSwdenk struct stat_data * sd = (struct stat_data *)item; 86*518e2e1aSwdenk ttime = sd_v2_mtime(sd); 87*518e2e1aSwdenk ctime_r(&ttime, filetime); 88*518e2e1aSwdenk printf ("%-10s %4d %6d %6d %9d %24.24s", 89*518e2e1aSwdenk bb_mode_string(sd_v2_mode(sd)), sd_v2_nlink(sd),sd_v2_uid(sd),sd_v2_gid(sd), 90*518e2e1aSwdenk (__u32) sd_v2_size(sd), filetime); 91*518e2e1aSwdenk } 92*518e2e1aSwdenk } 93*518e2e1aSwdenk 94*518e2e1aSwdenk static int 95*518e2e1aSwdenk journal_read (int block, int len, char *buffer) 96*518e2e1aSwdenk { 97*518e2e1aSwdenk return reiserfs_devread ((INFO->journal_block + block) << INFO->blocksize_shift, 98*518e2e1aSwdenk 0, len, buffer); 99*518e2e1aSwdenk } 100*518e2e1aSwdenk 101*518e2e1aSwdenk /* Read a block from ReiserFS file system, taking the journal into 102*518e2e1aSwdenk * account. If the block nr is in the journal, the block from the 103*518e2e1aSwdenk * journal taken. 104*518e2e1aSwdenk */ 105*518e2e1aSwdenk static int 106*518e2e1aSwdenk block_read (unsigned int blockNr, int start, int len, char *buffer) 107*518e2e1aSwdenk { 108*518e2e1aSwdenk int transactions = INFO->journal_transactions; 109*518e2e1aSwdenk int desc_block = INFO->journal_first_desc; 110*518e2e1aSwdenk int journal_mask = INFO->journal_block_count - 1; 111*518e2e1aSwdenk int translatedNr = blockNr; 112*518e2e1aSwdenk __u32 *journal_table = JOURNAL_START; 113*518e2e1aSwdenk while (transactions-- > 0) 114*518e2e1aSwdenk { 115*518e2e1aSwdenk int i = 0; 116*518e2e1aSwdenk int j_len; 117*518e2e1aSwdenk if (__le32_to_cpu(*journal_table) != 0xffffffff) 118*518e2e1aSwdenk { 119*518e2e1aSwdenk /* Search for the blockNr in cached journal */ 120*518e2e1aSwdenk j_len = __le32_to_cpu(*journal_table++); 121*518e2e1aSwdenk while (i++ < j_len) 122*518e2e1aSwdenk { 123*518e2e1aSwdenk if (__le32_to_cpu(*journal_table++) == blockNr) 124*518e2e1aSwdenk { 125*518e2e1aSwdenk journal_table += j_len - i; 126*518e2e1aSwdenk goto found; 127*518e2e1aSwdenk } 128*518e2e1aSwdenk } 129*518e2e1aSwdenk } 130*518e2e1aSwdenk else 131*518e2e1aSwdenk { 132*518e2e1aSwdenk /* This is the end of cached journal marker. The remaining 133*518e2e1aSwdenk * transactions are still on disk. 134*518e2e1aSwdenk */ 135*518e2e1aSwdenk struct reiserfs_journal_desc desc; 136*518e2e1aSwdenk struct reiserfs_journal_commit commit; 137*518e2e1aSwdenk 138*518e2e1aSwdenk if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) 139*518e2e1aSwdenk return 0; 140*518e2e1aSwdenk 141*518e2e1aSwdenk j_len = __le32_to_cpu(desc.j_len); 142*518e2e1aSwdenk while (i < j_len && i < JOURNAL_TRANS_HALF) 143*518e2e1aSwdenk if (__le32_to_cpu(desc.j_realblock[i++]) == blockNr) 144*518e2e1aSwdenk goto found; 145*518e2e1aSwdenk 146*518e2e1aSwdenk if (j_len >= JOURNAL_TRANS_HALF) 147*518e2e1aSwdenk { 148*518e2e1aSwdenk int commit_block = (desc_block + 1 + j_len) & journal_mask; 149*518e2e1aSwdenk if (! journal_read (commit_block, 150*518e2e1aSwdenk sizeof (commit), (char *) &commit)) 151*518e2e1aSwdenk return 0; 152*518e2e1aSwdenk while (i < j_len) 153*518e2e1aSwdenk if (__le32_to_cpu(commit.j_realblock[i++ - JOURNAL_TRANS_HALF]) == blockNr) 154*518e2e1aSwdenk goto found; 155*518e2e1aSwdenk } 156*518e2e1aSwdenk } 157*518e2e1aSwdenk goto not_found; 158*518e2e1aSwdenk 159*518e2e1aSwdenk found: 160*518e2e1aSwdenk translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); 161*518e2e1aSwdenk #ifdef REISERDEBUG 162*518e2e1aSwdenk printf ("block_read: block %d is mapped to journal block %d.\n", 163*518e2e1aSwdenk blockNr, translatedNr - INFO->journal_block); 164*518e2e1aSwdenk #endif 165*518e2e1aSwdenk /* We must continue the search, as this block may be overwritten 166*518e2e1aSwdenk * in later transactions. 167*518e2e1aSwdenk */ 168*518e2e1aSwdenk not_found: 169*518e2e1aSwdenk desc_block = (desc_block + 2 + j_len) & journal_mask; 170*518e2e1aSwdenk } 171*518e2e1aSwdenk return reiserfs_devread (translatedNr << INFO->blocksize_shift, start, len, buffer); 172*518e2e1aSwdenk } 173*518e2e1aSwdenk 174*518e2e1aSwdenk /* Init the journal data structure. We try to cache as much as 175*518e2e1aSwdenk * possible in the JOURNAL_START-JOURNAL_END space, but if it is full 176*518e2e1aSwdenk * we can still read the rest from the disk on demand. 177*518e2e1aSwdenk * 178*518e2e1aSwdenk * The first number of valid transactions and the descriptor block of the 179*518e2e1aSwdenk * first valid transaction are held in INFO. The transactions are all 180*518e2e1aSwdenk * adjacent, but we must take care of the journal wrap around. 181*518e2e1aSwdenk */ 182*518e2e1aSwdenk static int 183*518e2e1aSwdenk journal_init (void) 184*518e2e1aSwdenk { 185*518e2e1aSwdenk unsigned int block_count = INFO->journal_block_count; 186*518e2e1aSwdenk unsigned int desc_block; 187*518e2e1aSwdenk unsigned int commit_block; 188*518e2e1aSwdenk unsigned int next_trans_id; 189*518e2e1aSwdenk struct reiserfs_journal_header header; 190*518e2e1aSwdenk struct reiserfs_journal_desc desc; 191*518e2e1aSwdenk struct reiserfs_journal_commit commit; 192*518e2e1aSwdenk __u32 *journal_table = JOURNAL_START; 193*518e2e1aSwdenk 194*518e2e1aSwdenk journal_read (block_count, sizeof (header), (char *) &header); 195*518e2e1aSwdenk desc_block = __le32_to_cpu(header.j_first_unflushed_offset); 196*518e2e1aSwdenk if (desc_block >= block_count) 197*518e2e1aSwdenk return 0; 198*518e2e1aSwdenk 199*518e2e1aSwdenk INFO->journal_first_desc = desc_block; 200*518e2e1aSwdenk next_trans_id = __le32_to_cpu(header.j_last_flush_trans_id) + 1; 201*518e2e1aSwdenk 202*518e2e1aSwdenk #ifdef REISERDEBUG 203*518e2e1aSwdenk printf ("journal_init: last flushed %d\n", 204*518e2e1aSwdenk __le32_to_cpu(header.j_last_flush_trans_id)); 205*518e2e1aSwdenk #endif 206*518e2e1aSwdenk 207*518e2e1aSwdenk while (1) 208*518e2e1aSwdenk { 209*518e2e1aSwdenk journal_read (desc_block, sizeof (desc), (char *) &desc); 210*518e2e1aSwdenk if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0 211*518e2e1aSwdenk || __le32_to_cpu(desc.j_trans_id) != next_trans_id 212*518e2e1aSwdenk || __le32_to_cpu(desc.j_mount_id) != __le32_to_cpu(header.j_mount_id)) 213*518e2e1aSwdenk /* no more valid transactions */ 214*518e2e1aSwdenk break; 215*518e2e1aSwdenk 216*518e2e1aSwdenk commit_block = (desc_block + __le32_to_cpu(desc.j_len) + 1) & (block_count - 1); 217*518e2e1aSwdenk journal_read (commit_block, sizeof (commit), (char *) &commit); 218*518e2e1aSwdenk if (__le32_to_cpu(desc.j_trans_id) != commit.j_trans_id 219*518e2e1aSwdenk || __le32_to_cpu(desc.j_len) != __le32_to_cpu(commit.j_len)) 220*518e2e1aSwdenk /* no more valid transactions */ 221*518e2e1aSwdenk break; 222*518e2e1aSwdenk 223*518e2e1aSwdenk #ifdef REISERDEBUG 224*518e2e1aSwdenk printf ("Found valid transaction %d/%d at %d.\n", 225*518e2e1aSwdenk __le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); 226*518e2e1aSwdenk #endif 227*518e2e1aSwdenk 228*518e2e1aSwdenk next_trans_id++; 229*518e2e1aSwdenk if (journal_table < JOURNAL_END) 230*518e2e1aSwdenk { 231*518e2e1aSwdenk if ((journal_table + 1 + __le32_to_cpu(desc.j_len)) >= JOURNAL_END) 232*518e2e1aSwdenk { 233*518e2e1aSwdenk /* The table is almost full; mark the end of the cached 234*518e2e1aSwdenk * journal.*/ 235*518e2e1aSwdenk *journal_table = __cpu_to_le32(0xffffffff); 236*518e2e1aSwdenk journal_table = JOURNAL_END; 237*518e2e1aSwdenk } 238*518e2e1aSwdenk else 239*518e2e1aSwdenk { 240*518e2e1aSwdenk unsigned int i; 241*518e2e1aSwdenk /* Cache the length and the realblock numbers in the table. 242*518e2e1aSwdenk * The block number of descriptor can easily be computed. 243*518e2e1aSwdenk * and need not to be stored here. 244*518e2e1aSwdenk */ 245*518e2e1aSwdenk 246*518e2e1aSwdenk /* both are in the little endian format */ 247*518e2e1aSwdenk *journal_table++ = desc.j_len; 248*518e2e1aSwdenk for (i = 0; i < __le32_to_cpu(desc.j_len) && i < JOURNAL_TRANS_HALF; i++) 249*518e2e1aSwdenk { 250*518e2e1aSwdenk /* both are in the little endian format */ 251*518e2e1aSwdenk *journal_table++ = desc.j_realblock[i]; 252*518e2e1aSwdenk #ifdef REISERDEBUG 253*518e2e1aSwdenk printf ("block %d is in journal %d.\n", 254*518e2e1aSwdenk __le32_to_cpu(desc.j_realblock[i]), desc_block); 255*518e2e1aSwdenk #endif 256*518e2e1aSwdenk } 257*518e2e1aSwdenk for ( ; i < __le32_to_cpu(desc.j_len); i++) 258*518e2e1aSwdenk { 259*518e2e1aSwdenk /* both are in the little endian format */ 260*518e2e1aSwdenk *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; 261*518e2e1aSwdenk #ifdef REISERDEBUG 262*518e2e1aSwdenk printf ("block %d is in journal %d.\n", 263*518e2e1aSwdenk __le32_to_cpu(commit.j_realblock[i-JOURNAL_TRANS_HALF]), 264*518e2e1aSwdenk desc_block); 265*518e2e1aSwdenk #endif 266*518e2e1aSwdenk } 267*518e2e1aSwdenk } 268*518e2e1aSwdenk } 269*518e2e1aSwdenk desc_block = (commit_block + 1) & (block_count - 1); 270*518e2e1aSwdenk } 271*518e2e1aSwdenk #ifdef REISERDEBUG 272*518e2e1aSwdenk printf ("Transaction %d/%d at %d isn't valid.\n", 273*518e2e1aSwdenk __le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); 274*518e2e1aSwdenk #endif 275*518e2e1aSwdenk 276*518e2e1aSwdenk INFO->journal_transactions 277*518e2e1aSwdenk = next_trans_id - __le32_to_cpu(header.j_last_flush_trans_id) - 1; 278*518e2e1aSwdenk return errnum == 0; 279*518e2e1aSwdenk } 280*518e2e1aSwdenk 281*518e2e1aSwdenk /* check filesystem types and read superblock into memory buffer */ 282*518e2e1aSwdenk int 283*518e2e1aSwdenk reiserfs_mount (unsigned part_length) 284*518e2e1aSwdenk { 285*518e2e1aSwdenk struct reiserfs_super_block super; 286*518e2e1aSwdenk int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; 287*518e2e1aSwdenk 288*518e2e1aSwdenk if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) 289*518e2e1aSwdenk || ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), 290*518e2e1aSwdenk (char *) &super) 291*518e2e1aSwdenk || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0 292*518e2e1aSwdenk && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 293*518e2e1aSwdenk && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) 294*518e2e1aSwdenk || (/* check that this is not a copy inside the journal log */ 295*518e2e1aSwdenk sb_journal_block(&super) * sb_blocksize(&super) 296*518e2e1aSwdenk <= REISERFS_DISK_OFFSET_IN_BYTES)) 297*518e2e1aSwdenk { 298*518e2e1aSwdenk /* Try old super block position */ 299*518e2e1aSwdenk superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; 300*518e2e1aSwdenk if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) 301*518e2e1aSwdenk || ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), 302*518e2e1aSwdenk (char *) &super)) 303*518e2e1aSwdenk return 0; 304*518e2e1aSwdenk 305*518e2e1aSwdenk if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 306*518e2e1aSwdenk && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) 307*518e2e1aSwdenk { 308*518e2e1aSwdenk /* pre journaling super block ? */ 309*518e2e1aSwdenk if (substring (REISERFS_SUPER_MAGIC_STRING, 310*518e2e1aSwdenk (char*) ((int) &super + 20)) > 0) 311*518e2e1aSwdenk return 0; 312*518e2e1aSwdenk 313*518e2e1aSwdenk set_sb_blocksize(&super, REISERFS_OLD_BLOCKSIZE); 314*518e2e1aSwdenk set_sb_journal_block(&super, 0); 315*518e2e1aSwdenk set_sb_version(&super, 0); 316*518e2e1aSwdenk } 317*518e2e1aSwdenk } 318*518e2e1aSwdenk 319*518e2e1aSwdenk /* check the version number. */ 320*518e2e1aSwdenk if (sb_version(&super) > REISERFS_MAX_SUPPORTED_VERSION) 321*518e2e1aSwdenk return 0; 322*518e2e1aSwdenk 323*518e2e1aSwdenk INFO->version = sb_version(&super); 324*518e2e1aSwdenk INFO->blocksize = sb_blocksize(&super); 325*518e2e1aSwdenk INFO->fullblocksize_shift = log2 (sb_blocksize(&super)); 326*518e2e1aSwdenk INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; 327*518e2e1aSwdenk INFO->cached_slots = 328*518e2e1aSwdenk (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; 329*518e2e1aSwdenk 330*518e2e1aSwdenk #ifdef REISERDEBUG 331*518e2e1aSwdenk printf ("reiserfs_mount: version=%d, blocksize=%d\n", 332*518e2e1aSwdenk INFO->version, INFO->blocksize); 333*518e2e1aSwdenk #endif /* REISERDEBUG */ 334*518e2e1aSwdenk 335*518e2e1aSwdenk /* Clear node cache. */ 336*518e2e1aSwdenk memset (INFO->blocks, 0, sizeof (INFO->blocks)); 337*518e2e1aSwdenk 338*518e2e1aSwdenk if (sb_blocksize(&super) < FSYSREISER_MIN_BLOCKSIZE 339*518e2e1aSwdenk || sb_blocksize(&super) > FSYSREISER_MAX_BLOCKSIZE 340*518e2e1aSwdenk || (SECTOR_SIZE << INFO->blocksize_shift) != sb_blocksize(&super)) 341*518e2e1aSwdenk return 0; 342*518e2e1aSwdenk 343*518e2e1aSwdenk /* Initialize journal code. If something fails we end with zero 344*518e2e1aSwdenk * journal_transactions, so we don't access the journal at all. 345*518e2e1aSwdenk */ 346*518e2e1aSwdenk INFO->journal_transactions = 0; 347*518e2e1aSwdenk if (sb_journal_block(&super) != 0 && super.s_journal_dev == 0) 348*518e2e1aSwdenk { 349*518e2e1aSwdenk INFO->journal_block = sb_journal_block(&super); 350*518e2e1aSwdenk INFO->journal_block_count = sb_journal_size(&super); 351*518e2e1aSwdenk if (is_power_of_two (INFO->journal_block_count)) 352*518e2e1aSwdenk journal_init (); 353*518e2e1aSwdenk 354*518e2e1aSwdenk /* Read in super block again, maybe it is in the journal */ 355*518e2e1aSwdenk block_read (superblock >> INFO->blocksize_shift, 356*518e2e1aSwdenk 0, sizeof (struct reiserfs_super_block), (char *) &super); 357*518e2e1aSwdenk } 358*518e2e1aSwdenk 359*518e2e1aSwdenk if (! block_read (sb_root_block(&super), 0, INFO->blocksize, (char*) ROOT)) 360*518e2e1aSwdenk return 0; 361*518e2e1aSwdenk 362*518e2e1aSwdenk INFO->tree_depth = __le16_to_cpu(BLOCKHEAD (ROOT)->blk_level); 363*518e2e1aSwdenk 364*518e2e1aSwdenk #ifdef REISERDEBUG 365*518e2e1aSwdenk printf ("root read_in: block=%d, depth=%d\n", 366*518e2e1aSwdenk sb_root_block(&super), INFO->tree_depth); 367*518e2e1aSwdenk #endif /* REISERDEBUG */ 368*518e2e1aSwdenk 369*518e2e1aSwdenk if (INFO->tree_depth >= MAX_HEIGHT) 370*518e2e1aSwdenk return 0; 371*518e2e1aSwdenk if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) 372*518e2e1aSwdenk { 373*518e2e1aSwdenk /* There is only one node in the whole filesystem, 374*518e2e1aSwdenk * which is simultanously leaf and root */ 375*518e2e1aSwdenk memcpy (LEAF, ROOT, INFO->blocksize); 376*518e2e1aSwdenk } 377*518e2e1aSwdenk return 1; 378*518e2e1aSwdenk } 379*518e2e1aSwdenk 380*518e2e1aSwdenk /***************** TREE ACCESSING METHODS *****************************/ 381*518e2e1aSwdenk 382*518e2e1aSwdenk /* I assume you are familiar with the ReiserFS tree, if not go to 383*518e2e1aSwdenk * http://www.namesys.com/content_table.html 384*518e2e1aSwdenk * 385*518e2e1aSwdenk * My tree node cache is organized as following 386*518e2e1aSwdenk * 0 ROOT node 387*518e2e1aSwdenk * 1 LEAF node (if the ROOT is also a LEAF it is copied here 388*518e2e1aSwdenk * 2-n other nodes on current path from bottom to top. 389*518e2e1aSwdenk * if there is not enough space in the cache, the top most are 390*518e2e1aSwdenk * omitted. 391*518e2e1aSwdenk * 392*518e2e1aSwdenk * I have only two methods to find a key in the tree: 393*518e2e1aSwdenk * search_stat(dir_id, objectid) searches for the stat entry (always 394*518e2e1aSwdenk * the first entry) of an object. 395*518e2e1aSwdenk * next_key() gets the next key in tree order. 396*518e2e1aSwdenk * 397*518e2e1aSwdenk * This means, that I can only sequential reads of files are 398*518e2e1aSwdenk * efficient, but this really doesn't hurt for grub. 399*518e2e1aSwdenk */ 400*518e2e1aSwdenk 401*518e2e1aSwdenk /* Read in the node at the current path and depth into the node cache. 402*518e2e1aSwdenk * You must set INFO->blocks[depth] before. 403*518e2e1aSwdenk */ 404*518e2e1aSwdenk static char * 405*518e2e1aSwdenk read_tree_node (unsigned int blockNr, int depth) 406*518e2e1aSwdenk { 407*518e2e1aSwdenk char* cache = CACHE(depth); 408*518e2e1aSwdenk int num_cached = INFO->cached_slots; 409*518e2e1aSwdenk if (depth < num_cached) 410*518e2e1aSwdenk { 411*518e2e1aSwdenk /* This is the cached part of the path. Check if same block is 412*518e2e1aSwdenk * needed. 413*518e2e1aSwdenk */ 414*518e2e1aSwdenk if (blockNr == INFO->blocks[depth]) 415*518e2e1aSwdenk return cache; 416*518e2e1aSwdenk } 417*518e2e1aSwdenk else 418*518e2e1aSwdenk cache = CACHE(num_cached); 419*518e2e1aSwdenk 420*518e2e1aSwdenk #ifdef REISERDEBUG 421*518e2e1aSwdenk printf (" next read_in: block=%d (depth=%d)\n", 422*518e2e1aSwdenk blockNr, depth); 423*518e2e1aSwdenk #endif /* REISERDEBUG */ 424*518e2e1aSwdenk if (! block_read (blockNr, 0, INFO->blocksize, cache)) 425*518e2e1aSwdenk return 0; 426*518e2e1aSwdenk /* Make sure it has the right node level */ 427*518e2e1aSwdenk if (__le16_to_cpu(BLOCKHEAD (cache)->blk_level) != depth) 428*518e2e1aSwdenk { 429*518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 430*518e2e1aSwdenk return 0; 431*518e2e1aSwdenk } 432*518e2e1aSwdenk 433*518e2e1aSwdenk INFO->blocks[depth] = blockNr; 434*518e2e1aSwdenk return cache; 435*518e2e1aSwdenk } 436*518e2e1aSwdenk 437*518e2e1aSwdenk /* Get the next key, i.e. the key following the last retrieved key in 438*518e2e1aSwdenk * tree order. INFO->current_ih and 439*518e2e1aSwdenk * INFO->current_info are adapted accordingly. */ 440*518e2e1aSwdenk static int 441*518e2e1aSwdenk next_key (void) 442*518e2e1aSwdenk { 443*518e2e1aSwdenk int depth; 444*518e2e1aSwdenk struct item_head *ih = INFO->current_ih + 1; 445*518e2e1aSwdenk char *cache; 446*518e2e1aSwdenk 447*518e2e1aSwdenk #ifdef REISERDEBUG 448*518e2e1aSwdenk printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n", 449*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 450*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 451*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 452*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 453*518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 454*518e2e1aSwdenk #endif /* REISERDEBUG */ 455*518e2e1aSwdenk 456*518e2e1aSwdenk if (ih == &ITEMHEAD[__le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item)]) 457*518e2e1aSwdenk { 458*518e2e1aSwdenk depth = DISK_LEAF_NODE_LEVEL; 459*518e2e1aSwdenk /* The last item, was the last in the leaf node. 460*518e2e1aSwdenk * Read in the next block 461*518e2e1aSwdenk */ 462*518e2e1aSwdenk do 463*518e2e1aSwdenk { 464*518e2e1aSwdenk if (depth == INFO->tree_depth) 465*518e2e1aSwdenk { 466*518e2e1aSwdenk /* There are no more keys at all. 467*518e2e1aSwdenk * Return a dummy item with MAX_KEY */ 468*518e2e1aSwdenk ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; 469*518e2e1aSwdenk goto found; 470*518e2e1aSwdenk } 471*518e2e1aSwdenk depth++; 472*518e2e1aSwdenk #ifdef REISERDEBUG 473*518e2e1aSwdenk printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); 474*518e2e1aSwdenk #endif /* REISERDEBUG */ 475*518e2e1aSwdenk } 476*518e2e1aSwdenk while (INFO->next_key_nr[depth] == 0); 477*518e2e1aSwdenk 478*518e2e1aSwdenk if (depth == INFO->tree_depth) 479*518e2e1aSwdenk cache = ROOT; 480*518e2e1aSwdenk else if (depth <= INFO->cached_slots) 481*518e2e1aSwdenk cache = CACHE (depth); 482*518e2e1aSwdenk else 483*518e2e1aSwdenk { 484*518e2e1aSwdenk cache = read_tree_node (INFO->blocks[depth], depth); 485*518e2e1aSwdenk if (! cache) 486*518e2e1aSwdenk return 0; 487*518e2e1aSwdenk } 488*518e2e1aSwdenk 489*518e2e1aSwdenk do 490*518e2e1aSwdenk { 491*518e2e1aSwdenk int nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); 492*518e2e1aSwdenk int key_nr = INFO->next_key_nr[depth]++; 493*518e2e1aSwdenk #ifdef REISERDEBUG 494*518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item); 495*518e2e1aSwdenk #endif /* REISERDEBUG */ 496*518e2e1aSwdenk if (key_nr == nr_item) 497*518e2e1aSwdenk /* This is the last item in this block, set the next_key_nr to 0 */ 498*518e2e1aSwdenk INFO->next_key_nr[depth] = 0; 499*518e2e1aSwdenk 500*518e2e1aSwdenk cache = read_tree_node (dc_block_number(&(DC (cache)[key_nr])), --depth); 501*518e2e1aSwdenk if (! cache) 502*518e2e1aSwdenk return 0; 503*518e2e1aSwdenk } 504*518e2e1aSwdenk while (depth > DISK_LEAF_NODE_LEVEL); 505*518e2e1aSwdenk 506*518e2e1aSwdenk ih = ITEMHEAD; 507*518e2e1aSwdenk } 508*518e2e1aSwdenk found: 509*518e2e1aSwdenk INFO->current_ih = ih; 510*518e2e1aSwdenk INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; 511*518e2e1aSwdenk #ifdef REISERDEBUG 512*518e2e1aSwdenk printf (" new ih: key %d:%d:%d:%d version:%d\n", 513*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 514*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 515*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 516*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 517*518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 518*518e2e1aSwdenk #endif /* REISERDEBUG */ 519*518e2e1aSwdenk return 1; 520*518e2e1aSwdenk } 521*518e2e1aSwdenk 522*518e2e1aSwdenk /* preconditions: reiserfs_mount already executed, therefore 523*518e2e1aSwdenk * INFO block is valid 524*518e2e1aSwdenk * returns: 0 if error (errnum is set), 525*518e2e1aSwdenk * nonzero iff we were able to find the key successfully. 526*518e2e1aSwdenk * postconditions: on a nonzero return, the current_ih and 527*518e2e1aSwdenk * current_item fields describe the key that equals the 528*518e2e1aSwdenk * searched key. INFO->next_key contains the next key after 529*518e2e1aSwdenk * the searched key. 530*518e2e1aSwdenk * side effects: messes around with the cache. 531*518e2e1aSwdenk */ 532*518e2e1aSwdenk static int 533*518e2e1aSwdenk search_stat (__u32 dir_id, __u32 objectid) 534*518e2e1aSwdenk { 535*518e2e1aSwdenk char *cache; 536*518e2e1aSwdenk int depth; 537*518e2e1aSwdenk int nr_item; 538*518e2e1aSwdenk int i; 539*518e2e1aSwdenk struct item_head *ih; 540*518e2e1aSwdenk #ifdef REISERDEBUG 541*518e2e1aSwdenk printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid); 542*518e2e1aSwdenk #endif /* REISERDEBUG */ 543*518e2e1aSwdenk 544*518e2e1aSwdenk depth = INFO->tree_depth; 545*518e2e1aSwdenk cache = ROOT; 546*518e2e1aSwdenk 547*518e2e1aSwdenk while (depth > DISK_LEAF_NODE_LEVEL) 548*518e2e1aSwdenk { 549*518e2e1aSwdenk struct key *key; 550*518e2e1aSwdenk nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); 551*518e2e1aSwdenk 552*518e2e1aSwdenk key = KEY (cache); 553*518e2e1aSwdenk 554*518e2e1aSwdenk for (i = 0; i < nr_item; i++) 555*518e2e1aSwdenk { 556*518e2e1aSwdenk if (__le32_to_cpu(key->k_dir_id) > dir_id 557*518e2e1aSwdenk || (__le32_to_cpu(key->k_dir_id) == dir_id 558*518e2e1aSwdenk && (__le32_to_cpu(key->k_objectid) > objectid 559*518e2e1aSwdenk || (__le32_to_cpu(key->k_objectid) == objectid 560*518e2e1aSwdenk && (__le32_to_cpu(key->u.v1.k_offset) 561*518e2e1aSwdenk | __le32_to_cpu(key->u.v1.k_uniqueness)) > 0)))) 562*518e2e1aSwdenk break; 563*518e2e1aSwdenk key++; 564*518e2e1aSwdenk } 565*518e2e1aSwdenk 566*518e2e1aSwdenk #ifdef REISERDEBUG 567*518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); 568*518e2e1aSwdenk #endif /* REISERDEBUG */ 569*518e2e1aSwdenk INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; 570*518e2e1aSwdenk cache = read_tree_node (dc_block_number(&(DC (cache)[i])), --depth); 571*518e2e1aSwdenk if (! cache) 572*518e2e1aSwdenk return 0; 573*518e2e1aSwdenk } 574*518e2e1aSwdenk 575*518e2e1aSwdenk /* cache == LEAF */ 576*518e2e1aSwdenk nr_item = __le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item); 577*518e2e1aSwdenk ih = ITEMHEAD; 578*518e2e1aSwdenk for (i = 0; i < nr_item; i++) 579*518e2e1aSwdenk { 580*518e2e1aSwdenk if (__le32_to_cpu(ih->ih_key.k_dir_id) == dir_id 581*518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.k_objectid) == objectid 582*518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.u.v1.k_offset) == 0 583*518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.u.v1.k_uniqueness) == 0) 584*518e2e1aSwdenk { 585*518e2e1aSwdenk #ifdef REISERDEBUG 586*518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); 587*518e2e1aSwdenk #endif /* REISERDEBUG */ 588*518e2e1aSwdenk INFO->current_ih = ih; 589*518e2e1aSwdenk INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; 590*518e2e1aSwdenk return 1; 591*518e2e1aSwdenk } 592*518e2e1aSwdenk ih++; 593*518e2e1aSwdenk } 594*518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 595*518e2e1aSwdenk return 0; 596*518e2e1aSwdenk } 597*518e2e1aSwdenk 598*518e2e1aSwdenk int 599*518e2e1aSwdenk reiserfs_read (char *buf, unsigned len) 600*518e2e1aSwdenk { 601*518e2e1aSwdenk unsigned int blocksize; 602*518e2e1aSwdenk unsigned int offset; 603*518e2e1aSwdenk unsigned int to_read; 604*518e2e1aSwdenk char *prev_buf = buf; 605*518e2e1aSwdenk 606*518e2e1aSwdenk #ifdef REISERDEBUG 607*518e2e1aSwdenk printf ("reiserfs_read: filepos=%d len=%d, offset=%Lx\n", 608*518e2e1aSwdenk filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1); 609*518e2e1aSwdenk #endif /* REISERDEBUG */ 610*518e2e1aSwdenk 611*518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid 612*518e2e1aSwdenk || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1) 613*518e2e1aSwdenk { 614*518e2e1aSwdenk search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid); 615*518e2e1aSwdenk goto get_next_key; 616*518e2e1aSwdenk } 617*518e2e1aSwdenk 618*518e2e1aSwdenk while (! errnum) 619*518e2e1aSwdenk { 620*518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid) { 621*518e2e1aSwdenk break; 622*518e2e1aSwdenk } 623*518e2e1aSwdenk 624*518e2e1aSwdenk offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1; 625*518e2e1aSwdenk blocksize = __le16_to_cpu(INFO->current_ih->ih_item_len); 626*518e2e1aSwdenk 627*518e2e1aSwdenk #ifdef REISERDEBUG 628*518e2e1aSwdenk printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n", 629*518e2e1aSwdenk filepos, len, offset, blocksize); 630*518e2e1aSwdenk #endif /* REISERDEBUG */ 631*518e2e1aSwdenk 632*518e2e1aSwdenk if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT) 633*518e2e1aSwdenk && offset < blocksize) 634*518e2e1aSwdenk { 635*518e2e1aSwdenk #ifdef REISERDEBUG 636*518e2e1aSwdenk printf ("direct_read: offset=%d, blocksize=%d\n", 637*518e2e1aSwdenk offset, blocksize); 638*518e2e1aSwdenk #endif /* REISERDEBUG */ 639*518e2e1aSwdenk to_read = blocksize - offset; 640*518e2e1aSwdenk if (to_read > len) 641*518e2e1aSwdenk to_read = len; 642*518e2e1aSwdenk 643*518e2e1aSwdenk memcpy (buf, INFO->current_item + offset, to_read); 644*518e2e1aSwdenk goto update_buf_len; 645*518e2e1aSwdenk } 646*518e2e1aSwdenk else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT)) 647*518e2e1aSwdenk { 648*518e2e1aSwdenk blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; 649*518e2e1aSwdenk #ifdef REISERDEBUG 650*518e2e1aSwdenk printf ("indirect_read: offset=%d, blocksize=%d\n", 651*518e2e1aSwdenk offset, blocksize); 652*518e2e1aSwdenk #endif /* REISERDEBUG */ 653*518e2e1aSwdenk 654*518e2e1aSwdenk while (offset < blocksize) 655*518e2e1aSwdenk { 656*518e2e1aSwdenk __u32 blocknr = __le32_to_cpu(((__u32 *) INFO->current_item) 657*518e2e1aSwdenk [offset >> INFO->fullblocksize_shift]); 658*518e2e1aSwdenk int blk_offset = offset & (INFO->blocksize-1); 659*518e2e1aSwdenk to_read = INFO->blocksize - blk_offset; 660*518e2e1aSwdenk if (to_read > len) 661*518e2e1aSwdenk to_read = len; 662*518e2e1aSwdenk 663*518e2e1aSwdenk /* Journal is only for meta data. Data blocks can be read 664*518e2e1aSwdenk * directly without using block_read 665*518e2e1aSwdenk */ 666*518e2e1aSwdenk reiserfs_devread (blocknr << INFO->blocksize_shift, 667*518e2e1aSwdenk blk_offset, to_read, buf); 668*518e2e1aSwdenk update_buf_len: 669*518e2e1aSwdenk len -= to_read; 670*518e2e1aSwdenk buf += to_read; 671*518e2e1aSwdenk offset += to_read; 672*518e2e1aSwdenk filepos += to_read; 673*518e2e1aSwdenk if (len == 0) 674*518e2e1aSwdenk goto done; 675*518e2e1aSwdenk } 676*518e2e1aSwdenk } 677*518e2e1aSwdenk get_next_key: 678*518e2e1aSwdenk next_key (); 679*518e2e1aSwdenk } 680*518e2e1aSwdenk done: 681*518e2e1aSwdenk return errnum ? 0 : buf - prev_buf; 682*518e2e1aSwdenk } 683*518e2e1aSwdenk 684*518e2e1aSwdenk 685*518e2e1aSwdenk /* preconditions: reiserfs_mount already executed, therefore 686*518e2e1aSwdenk * INFO block is valid 687*518e2e1aSwdenk * returns: 0 if error, nonzero iff we were able to find the file successfully 688*518e2e1aSwdenk * postconditions: on a nonzero return, INFO->fileinfo contains the info 689*518e2e1aSwdenk * of the file we were trying to look up, filepos is 0 and filemax is 690*518e2e1aSwdenk * the size of the file. 691*518e2e1aSwdenk */ 692*518e2e1aSwdenk static int 693*518e2e1aSwdenk reiserfs_dir (char *dirname) 694*518e2e1aSwdenk { 695*518e2e1aSwdenk struct reiserfs_de_head *de_head; 696*518e2e1aSwdenk char *rest, ch; 697*518e2e1aSwdenk __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; 698*518e2e1aSwdenk #ifndef STAGE1_5 699*518e2e1aSwdenk int do_possibilities = 0; 700*518e2e1aSwdenk #endif /* ! STAGE1_5 */ 701*518e2e1aSwdenk char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ 702*518e2e1aSwdenk int link_count = 0; 703*518e2e1aSwdenk int mode; 704*518e2e1aSwdenk 705*518e2e1aSwdenk dir_id = REISERFS_ROOT_PARENT_OBJECTID; 706*518e2e1aSwdenk objectid = REISERFS_ROOT_OBJECTID; 707*518e2e1aSwdenk 708*518e2e1aSwdenk while (1) 709*518e2e1aSwdenk { 710*518e2e1aSwdenk #ifdef REISERDEBUG 711*518e2e1aSwdenk printf ("dirname=%s\n", dirname); 712*518e2e1aSwdenk #endif /* REISERDEBUG */ 713*518e2e1aSwdenk 714*518e2e1aSwdenk /* Search for the stat info first. */ 715*518e2e1aSwdenk if (! search_stat (dir_id, objectid)) 716*518e2e1aSwdenk return 0; 717*518e2e1aSwdenk 718*518e2e1aSwdenk #ifdef REISERDEBUG 719*518e2e1aSwdenk printf ("sd_mode=%x sd_size=%d\n", 720*518e2e1aSwdenk stat_data_v1(INFO->current_ih) ? sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : 721*518e2e1aSwdenk sd_v2_mode((struct stat_data *) (INFO->current_item)), 722*518e2e1aSwdenk stat_data_v1(INFO->current_ih) ? sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 723*518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item) 724*518e2e1aSwdenk ); 725*518e2e1aSwdenk 726*518e2e1aSwdenk #endif /* REISERDEBUG */ 727*518e2e1aSwdenk mode = stat_data_v1(INFO->current_ih) ? 728*518e2e1aSwdenk sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : 729*518e2e1aSwdenk sd_v2_mode((struct stat_data *) INFO->current_item); 730*518e2e1aSwdenk 731*518e2e1aSwdenk /* If we've got a symbolic link, then chase it. */ 732*518e2e1aSwdenk if (S_ISLNK (mode)) 733*518e2e1aSwdenk { 734*518e2e1aSwdenk unsigned int len; 735*518e2e1aSwdenk if (++link_count > MAX_LINK_COUNT) 736*518e2e1aSwdenk { 737*518e2e1aSwdenk errnum = ERR_SYMLINK_LOOP; 738*518e2e1aSwdenk return 0; 739*518e2e1aSwdenk } 740*518e2e1aSwdenk 741*518e2e1aSwdenk /* Get the symlink size. */ 742*518e2e1aSwdenk filemax = stat_data_v1(INFO->current_ih) ? 743*518e2e1aSwdenk sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 744*518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item); 745*518e2e1aSwdenk 746*518e2e1aSwdenk /* Find out how long our remaining name is. */ 747*518e2e1aSwdenk len = 0; 748*518e2e1aSwdenk while (dirname[len] && !isspace (dirname[len])) 749*518e2e1aSwdenk len++; 750*518e2e1aSwdenk 751*518e2e1aSwdenk if (filemax + len > sizeof (linkbuf) - 1) 752*518e2e1aSwdenk { 753*518e2e1aSwdenk errnum = ERR_FILELENGTH; 754*518e2e1aSwdenk return 0; 755*518e2e1aSwdenk } 756*518e2e1aSwdenk 757*518e2e1aSwdenk /* Copy the remaining name to the end of the symlink data. 758*518e2e1aSwdenk Note that DIRNAME and LINKBUF may overlap! */ 759*518e2e1aSwdenk memmove (linkbuf + filemax, dirname, len+1); 760*518e2e1aSwdenk 761*518e2e1aSwdenk INFO->fileinfo.k_dir_id = dir_id; 762*518e2e1aSwdenk INFO->fileinfo.k_objectid = objectid; 763*518e2e1aSwdenk filepos = 0; 764*518e2e1aSwdenk if (! next_key () 765*518e2e1aSwdenk || reiserfs_read (linkbuf, filemax) != filemax) 766*518e2e1aSwdenk { 767*518e2e1aSwdenk if (! errnum) 768*518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 769*518e2e1aSwdenk return 0; 770*518e2e1aSwdenk } 771*518e2e1aSwdenk 772*518e2e1aSwdenk #ifdef REISERDEBUG 773*518e2e1aSwdenk printf ("symlink=%s\n", linkbuf); 774*518e2e1aSwdenk #endif /* REISERDEBUG */ 775*518e2e1aSwdenk 776*518e2e1aSwdenk dirname = linkbuf; 777*518e2e1aSwdenk if (*dirname == '/') 778*518e2e1aSwdenk { 779*518e2e1aSwdenk /* It's an absolute link, so look it up in root. */ 780*518e2e1aSwdenk dir_id = REISERFS_ROOT_PARENT_OBJECTID; 781*518e2e1aSwdenk objectid = REISERFS_ROOT_OBJECTID; 782*518e2e1aSwdenk } 783*518e2e1aSwdenk else 784*518e2e1aSwdenk { 785*518e2e1aSwdenk /* Relative, so look it up in our parent directory. */ 786*518e2e1aSwdenk dir_id = parent_dir_id; 787*518e2e1aSwdenk objectid = parent_objectid; 788*518e2e1aSwdenk } 789*518e2e1aSwdenk 790*518e2e1aSwdenk /* Now lookup the new name. */ 791*518e2e1aSwdenk continue; 792*518e2e1aSwdenk } 793*518e2e1aSwdenk 794*518e2e1aSwdenk /* if we have a real file (and we're not just printing possibilities), 795*518e2e1aSwdenk then this is where we want to exit */ 796*518e2e1aSwdenk 797*518e2e1aSwdenk if (! *dirname || isspace (*dirname)) 798*518e2e1aSwdenk { 799*518e2e1aSwdenk if (! S_ISREG (mode)) 800*518e2e1aSwdenk { 801*518e2e1aSwdenk errnum = ERR_BAD_FILETYPE; 802*518e2e1aSwdenk return 0; 803*518e2e1aSwdenk } 804*518e2e1aSwdenk 805*518e2e1aSwdenk filepos = 0; 806*518e2e1aSwdenk filemax = stat_data_v1(INFO->current_ih) ? 807*518e2e1aSwdenk sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 808*518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item); 809*518e2e1aSwdenk #if 0 810*518e2e1aSwdenk /* If this is a new stat data and size is > 4GB set filemax to 811*518e2e1aSwdenk * maximum 812*518e2e1aSwdenk */ 813*518e2e1aSwdenk if (__le16_to_cpu(INFO->current_ih->ih_version) == ITEM_VERSION_2 814*518e2e1aSwdenk && sd_size_hi((struct stat_data *) INFO->current_item) > 0) 815*518e2e1aSwdenk filemax = 0xffffffff; 816*518e2e1aSwdenk #endif 817*518e2e1aSwdenk INFO->fileinfo.k_dir_id = dir_id; 818*518e2e1aSwdenk INFO->fileinfo.k_objectid = objectid; 819*518e2e1aSwdenk return next_key (); 820*518e2e1aSwdenk } 821*518e2e1aSwdenk 822*518e2e1aSwdenk /* continue with the file/directory name interpretation */ 823*518e2e1aSwdenk while (*dirname == '/') 824*518e2e1aSwdenk dirname++; 825*518e2e1aSwdenk if (! S_ISDIR (mode)) 826*518e2e1aSwdenk { 827*518e2e1aSwdenk errnum = ERR_BAD_FILETYPE; 828*518e2e1aSwdenk return 0; 829*518e2e1aSwdenk } 830*518e2e1aSwdenk for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++); 831*518e2e1aSwdenk *rest = 0; 832*518e2e1aSwdenk 833*518e2e1aSwdenk # ifndef STAGE1_5 834*518e2e1aSwdenk if (print_possibilities && ch != '/') 835*518e2e1aSwdenk do_possibilities = 1; 836*518e2e1aSwdenk # endif /* ! STAGE1_5 */ 837*518e2e1aSwdenk 838*518e2e1aSwdenk while (1) 839*518e2e1aSwdenk { 840*518e2e1aSwdenk char *name_end; 841*518e2e1aSwdenk int num_entries; 842*518e2e1aSwdenk 843*518e2e1aSwdenk if (! next_key ()) 844*518e2e1aSwdenk return 0; 845*518e2e1aSwdenk #ifdef REISERDEBUG 846*518e2e1aSwdenk printf ("ih: key %d:%d:%d:%d version:%d\n", 847*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 848*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 849*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 850*518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 851*518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 852*518e2e1aSwdenk #endif /* REISERDEBUG */ 853*518e2e1aSwdenk 854*518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != objectid) 855*518e2e1aSwdenk break; 856*518e2e1aSwdenk 857*518e2e1aSwdenk name_end = INFO->current_item + __le16_to_cpu(INFO->current_ih->ih_item_len); 858*518e2e1aSwdenk de_head = (struct reiserfs_de_head *) INFO->current_item; 859*518e2e1aSwdenk num_entries = __le16_to_cpu(INFO->current_ih->u.ih_entry_count); 860*518e2e1aSwdenk while (num_entries > 0) 861*518e2e1aSwdenk { 862*518e2e1aSwdenk char *filename = INFO->current_item + deh_location(de_head); 863*518e2e1aSwdenk char tmp = *name_end; 864*518e2e1aSwdenk if ((deh_state(de_head) & DEH_Visible)) 865*518e2e1aSwdenk { 866*518e2e1aSwdenk int cmp; 867*518e2e1aSwdenk /* Directory names in ReiserFS are not null 868*518e2e1aSwdenk * terminated. We write a temporary 0 behind it. 869*518e2e1aSwdenk * NOTE: that this may overwrite the first block in 870*518e2e1aSwdenk * the tree cache. That doesn't hurt as long as we 871*518e2e1aSwdenk * don't call next_key () in between. 872*518e2e1aSwdenk */ 873*518e2e1aSwdenk *name_end = 0; 874*518e2e1aSwdenk cmp = substring (dirname, filename); 875*518e2e1aSwdenk *name_end = tmp; 876*518e2e1aSwdenk # ifndef STAGE1_5 877*518e2e1aSwdenk if (do_possibilities) 878*518e2e1aSwdenk { 879*518e2e1aSwdenk if (cmp <= 0) 880*518e2e1aSwdenk { 881*518e2e1aSwdenk char fn[PATH_MAX]; 882*518e2e1aSwdenk struct fsys_reiser_info info_save; 883*518e2e1aSwdenk 884*518e2e1aSwdenk if (print_possibilities > 0) 885*518e2e1aSwdenk print_possibilities = -print_possibilities; 886*518e2e1aSwdenk *name_end = 0; 887*518e2e1aSwdenk strcpy(fn, filename); 888*518e2e1aSwdenk *name_end = tmp; 889*518e2e1aSwdenk 890*518e2e1aSwdenk /* If NAME is "." or "..", do not count it. */ 891*518e2e1aSwdenk if (strcmp (fn, ".") != 0 && strcmp (fn, "..") != 0) { 892*518e2e1aSwdenk memcpy(&info_save, INFO, sizeof(struct fsys_reiser_info)); 893*518e2e1aSwdenk search_stat (deh_dir_id(de_head), deh_objectid(de_head)); 894*518e2e1aSwdenk sd_print_item(INFO->current_ih, INFO->current_item); 895*518e2e1aSwdenk printf(" %s\n", fn); 896*518e2e1aSwdenk search_stat (dir_id, objectid); 897*518e2e1aSwdenk memcpy(INFO, &info_save, sizeof(struct fsys_reiser_info)); 898*518e2e1aSwdenk } 899*518e2e1aSwdenk } 900*518e2e1aSwdenk } 901*518e2e1aSwdenk else 902*518e2e1aSwdenk # endif /* ! STAGE1_5 */ 903*518e2e1aSwdenk if (cmp == 0) 904*518e2e1aSwdenk goto found; 905*518e2e1aSwdenk } 906*518e2e1aSwdenk /* The beginning of this name marks the end of the next name. 907*518e2e1aSwdenk */ 908*518e2e1aSwdenk name_end = filename; 909*518e2e1aSwdenk de_head++; 910*518e2e1aSwdenk num_entries--; 911*518e2e1aSwdenk } 912*518e2e1aSwdenk } 913*518e2e1aSwdenk 914*518e2e1aSwdenk # ifndef STAGE1_5 915*518e2e1aSwdenk if (print_possibilities < 0) 916*518e2e1aSwdenk return 1; 917*518e2e1aSwdenk # endif /* ! STAGE1_5 */ 918*518e2e1aSwdenk 919*518e2e1aSwdenk errnum = ERR_FILE_NOT_FOUND; 920*518e2e1aSwdenk *rest = ch; 921*518e2e1aSwdenk return 0; 922*518e2e1aSwdenk 923*518e2e1aSwdenk found: 924*518e2e1aSwdenk *rest = ch; 925*518e2e1aSwdenk dirname = rest; 926*518e2e1aSwdenk 927*518e2e1aSwdenk parent_dir_id = dir_id; 928*518e2e1aSwdenk parent_objectid = objectid; 929*518e2e1aSwdenk dir_id = deh_dir_id(de_head); 930*518e2e1aSwdenk objectid = deh_objectid(de_head); 931*518e2e1aSwdenk } 932*518e2e1aSwdenk } 933*518e2e1aSwdenk 934*518e2e1aSwdenk /* 935*518e2e1aSwdenk * U-Boot interface functions 936*518e2e1aSwdenk */ 937*518e2e1aSwdenk 938*518e2e1aSwdenk /* 939*518e2e1aSwdenk * List given directory 940*518e2e1aSwdenk * 941*518e2e1aSwdenk * RETURN: 0 - OK, else grub_error_t errnum 942*518e2e1aSwdenk */ 943*518e2e1aSwdenk int 944*518e2e1aSwdenk reiserfs_ls (char *dirname) 945*518e2e1aSwdenk { 946*518e2e1aSwdenk char *dir_slash; 947*518e2e1aSwdenk int res; 948*518e2e1aSwdenk 949*518e2e1aSwdenk errnum = 0; 950*518e2e1aSwdenk dir_slash = malloc(strlen(dirname) + 1); 951*518e2e1aSwdenk if (dir_slash == NULL) { 952*518e2e1aSwdenk return ERR_NUMBER_OVERFLOW; 953*518e2e1aSwdenk } 954*518e2e1aSwdenk strcpy(dir_slash, dirname); 955*518e2e1aSwdenk /* add "/" to the directory name */ 956*518e2e1aSwdenk strcat(dir_slash, "/"); 957*518e2e1aSwdenk 958*518e2e1aSwdenk print_possibilities = 1; 959*518e2e1aSwdenk res = reiserfs_dir (dir_slash); 960*518e2e1aSwdenk free(dir_slash); 961*518e2e1aSwdenk if (!res || errnum) { 962*518e2e1aSwdenk return errnum; 963*518e2e1aSwdenk } 964*518e2e1aSwdenk 965*518e2e1aSwdenk return 0; 966*518e2e1aSwdenk } 967*518e2e1aSwdenk 968*518e2e1aSwdenk /* 969*518e2e1aSwdenk * Open file for reading 970*518e2e1aSwdenk * 971*518e2e1aSwdenk * RETURN: >0 - OK, size of opened file 972*518e2e1aSwdenk * <0 - ERROR -grub_error_t errnum 973*518e2e1aSwdenk */ 974*518e2e1aSwdenk int 975*518e2e1aSwdenk reiserfs_open (char *filename) 976*518e2e1aSwdenk { 977*518e2e1aSwdenk /* open the file */ 978*518e2e1aSwdenk errnum = 0; 979*518e2e1aSwdenk print_possibilities = 0; 980*518e2e1aSwdenk if (!reiserfs_dir (filename) || errnum) { 981*518e2e1aSwdenk return -errnum; 982*518e2e1aSwdenk } 983*518e2e1aSwdenk return filemax; 984*518e2e1aSwdenk } 985*518e2e1aSwdenk 986*518e2e1aSwdenk #endif /* CFG_CMD_REISER */ 987