1518e2e1aSwdenk /* 2518e2e1aSwdenk * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README 3518e2e1aSwdenk * 4518e2e1aSwdenk * GRUB -- GRand Unified Bootloader 5518e2e1aSwdenk * Copyright (C) 2000, 2001 Free Software Foundation, Inc. 6518e2e1aSwdenk * 7518e2e1aSwdenk * (C) Copyright 2003 - 2004 8518e2e1aSwdenk * Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com> 9518e2e1aSwdenk * 10518e2e1aSwdenk * 11518e2e1aSwdenk * This program is free software; you can redistribute it and/or modify 12518e2e1aSwdenk * it under the terms of the GNU General Public License as published by 13518e2e1aSwdenk * the Free Software Foundation; either version 2 of the License, or 14518e2e1aSwdenk * (at your option) any later version. 15518e2e1aSwdenk * 16518e2e1aSwdenk * This program is distributed in the hope that it will be useful, 17518e2e1aSwdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 18518e2e1aSwdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19518e2e1aSwdenk * GNU General Public License for more details. 20518e2e1aSwdenk * 21518e2e1aSwdenk * You should have received a copy of the GNU General Public License 22518e2e1aSwdenk * along with this program; if not, write to the Free Software 23518e2e1aSwdenk * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24518e2e1aSwdenk */ 25518e2e1aSwdenk 26518e2e1aSwdenk /* An implementation for the ReiserFS filesystem ported from GRUB. 27518e2e1aSwdenk * Some parts of this code (mainly the structures and defines) are 28518e2e1aSwdenk * from the original reiser fs code, as found in the linux kernel. 29518e2e1aSwdenk */ 30518e2e1aSwdenk 31518e2e1aSwdenk #include <common.h> 32518e2e1aSwdenk #include <malloc.h> 33518e2e1aSwdenk #include <linux/ctype.h> 34518e2e1aSwdenk #include <linux/time.h> 35518e2e1aSwdenk #include <asm/byteorder.h> 36518e2e1aSwdenk #include <reiserfs.h> 37518e2e1aSwdenk 38518e2e1aSwdenk #include "reiserfs_private.h" 39518e2e1aSwdenk 40518e2e1aSwdenk #undef REISERDEBUG 41518e2e1aSwdenk 42518e2e1aSwdenk /* Some parts of this code (mainly the structures and defines) are 43518e2e1aSwdenk * from the original reiser fs code, as found in the linux kernel. 44518e2e1aSwdenk */ 45518e2e1aSwdenk 46518e2e1aSwdenk static char fsys_buf[FSYS_BUFLEN]; 47518e2e1aSwdenk static reiserfs_error_t errnum = ERR_NONE; 48518e2e1aSwdenk static int print_possibilities; 49518e2e1aSwdenk static unsigned int filepos, filemax; 50518e2e1aSwdenk 51518e2e1aSwdenk static int 52518e2e1aSwdenk substring (const char *s1, const char *s2) 53518e2e1aSwdenk { 54518e2e1aSwdenk while (*s1 == *s2) 55518e2e1aSwdenk { 56518e2e1aSwdenk /* The strings match exactly. */ 57518e2e1aSwdenk if (! *(s1++)) 58518e2e1aSwdenk return 0; 59518e2e1aSwdenk s2 ++; 60518e2e1aSwdenk } 61518e2e1aSwdenk 62518e2e1aSwdenk /* S1 is a substring of S2. */ 63518e2e1aSwdenk if (*s1 == 0) 64518e2e1aSwdenk return -1; 65518e2e1aSwdenk 66518e2e1aSwdenk /* S1 isn't a substring. */ 67518e2e1aSwdenk return 1; 68518e2e1aSwdenk } 69518e2e1aSwdenk 70518e2e1aSwdenk static void sd_print_item (struct item_head * ih, char * item) 71518e2e1aSwdenk { 72518e2e1aSwdenk char filetime[30]; 73518e2e1aSwdenk time_t ttime; 74518e2e1aSwdenk 75518e2e1aSwdenk if (stat_data_v1 (ih)) { 76518e2e1aSwdenk struct stat_data_v1 * sd = (struct stat_data_v1 *)item; 77518e2e1aSwdenk ttime = sd_v1_mtime(sd); 78518e2e1aSwdenk ctime_r(&ttime, filetime); 79518e2e1aSwdenk printf ("%-10s %4hd %6d %6d %9d %24.24s", 80518e2e1aSwdenk bb_mode_string(sd_v1_mode(sd)), sd_v1_nlink(sd),sd_v1_uid(sd), sd_v1_gid(sd), 81518e2e1aSwdenk sd_v1_size(sd), filetime); 82518e2e1aSwdenk } else { 83518e2e1aSwdenk struct stat_data * sd = (struct stat_data *)item; 84518e2e1aSwdenk ttime = sd_v2_mtime(sd); 85518e2e1aSwdenk ctime_r(&ttime, filetime); 86518e2e1aSwdenk printf ("%-10s %4d %6d %6d %9d %24.24s", 87518e2e1aSwdenk bb_mode_string(sd_v2_mode(sd)), sd_v2_nlink(sd),sd_v2_uid(sd),sd_v2_gid(sd), 88518e2e1aSwdenk (__u32) sd_v2_size(sd), filetime); 89518e2e1aSwdenk } 90518e2e1aSwdenk } 91518e2e1aSwdenk 92518e2e1aSwdenk static int 93518e2e1aSwdenk journal_read (int block, int len, char *buffer) 94518e2e1aSwdenk { 95518e2e1aSwdenk return reiserfs_devread ((INFO->journal_block + block) << INFO->blocksize_shift, 96518e2e1aSwdenk 0, len, buffer); 97518e2e1aSwdenk } 98518e2e1aSwdenk 99518e2e1aSwdenk /* Read a block from ReiserFS file system, taking the journal into 100518e2e1aSwdenk * account. If the block nr is in the journal, the block from the 101518e2e1aSwdenk * journal taken. 102518e2e1aSwdenk */ 103518e2e1aSwdenk static int 104518e2e1aSwdenk block_read (unsigned int blockNr, int start, int len, char *buffer) 105518e2e1aSwdenk { 106518e2e1aSwdenk int transactions = INFO->journal_transactions; 107518e2e1aSwdenk int desc_block = INFO->journal_first_desc; 108518e2e1aSwdenk int journal_mask = INFO->journal_block_count - 1; 109518e2e1aSwdenk int translatedNr = blockNr; 110518e2e1aSwdenk __u32 *journal_table = JOURNAL_START; 111518e2e1aSwdenk while (transactions-- > 0) 112518e2e1aSwdenk { 113518e2e1aSwdenk int i = 0; 114518e2e1aSwdenk int j_len; 115518e2e1aSwdenk if (__le32_to_cpu(*journal_table) != 0xffffffff) 116518e2e1aSwdenk { 117518e2e1aSwdenk /* Search for the blockNr in cached journal */ 118518e2e1aSwdenk j_len = __le32_to_cpu(*journal_table++); 119518e2e1aSwdenk while (i++ < j_len) 120518e2e1aSwdenk { 121518e2e1aSwdenk if (__le32_to_cpu(*journal_table++) == blockNr) 122518e2e1aSwdenk { 123518e2e1aSwdenk journal_table += j_len - i; 124518e2e1aSwdenk goto found; 125518e2e1aSwdenk } 126518e2e1aSwdenk } 127518e2e1aSwdenk } 128518e2e1aSwdenk else 129518e2e1aSwdenk { 130518e2e1aSwdenk /* This is the end of cached journal marker. The remaining 131518e2e1aSwdenk * transactions are still on disk. 132518e2e1aSwdenk */ 133518e2e1aSwdenk struct reiserfs_journal_desc desc; 134518e2e1aSwdenk struct reiserfs_journal_commit commit; 135518e2e1aSwdenk 136518e2e1aSwdenk if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) 137518e2e1aSwdenk return 0; 138518e2e1aSwdenk 139518e2e1aSwdenk j_len = __le32_to_cpu(desc.j_len); 140518e2e1aSwdenk while (i < j_len && i < JOURNAL_TRANS_HALF) 141518e2e1aSwdenk if (__le32_to_cpu(desc.j_realblock[i++]) == blockNr) 142518e2e1aSwdenk goto found; 143518e2e1aSwdenk 144518e2e1aSwdenk if (j_len >= JOURNAL_TRANS_HALF) 145518e2e1aSwdenk { 146518e2e1aSwdenk int commit_block = (desc_block + 1 + j_len) & journal_mask; 147518e2e1aSwdenk if (! journal_read (commit_block, 148518e2e1aSwdenk sizeof (commit), (char *) &commit)) 149518e2e1aSwdenk return 0; 150518e2e1aSwdenk while (i < j_len) 151518e2e1aSwdenk if (__le32_to_cpu(commit.j_realblock[i++ - JOURNAL_TRANS_HALF]) == blockNr) 152518e2e1aSwdenk goto found; 153518e2e1aSwdenk } 154518e2e1aSwdenk } 155518e2e1aSwdenk goto not_found; 156518e2e1aSwdenk 157518e2e1aSwdenk found: 158518e2e1aSwdenk translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); 159518e2e1aSwdenk #ifdef REISERDEBUG 160518e2e1aSwdenk printf ("block_read: block %d is mapped to journal block %d.\n", 161518e2e1aSwdenk blockNr, translatedNr - INFO->journal_block); 162518e2e1aSwdenk #endif 163518e2e1aSwdenk /* We must continue the search, as this block may be overwritten 164518e2e1aSwdenk * in later transactions. 165518e2e1aSwdenk */ 166518e2e1aSwdenk not_found: 167518e2e1aSwdenk desc_block = (desc_block + 2 + j_len) & journal_mask; 168518e2e1aSwdenk } 169518e2e1aSwdenk return reiserfs_devread (translatedNr << INFO->blocksize_shift, start, len, buffer); 170518e2e1aSwdenk } 171518e2e1aSwdenk 172518e2e1aSwdenk /* Init the journal data structure. We try to cache as much as 173518e2e1aSwdenk * possible in the JOURNAL_START-JOURNAL_END space, but if it is full 174518e2e1aSwdenk * we can still read the rest from the disk on demand. 175518e2e1aSwdenk * 176518e2e1aSwdenk * The first number of valid transactions and the descriptor block of the 177518e2e1aSwdenk * first valid transaction are held in INFO. The transactions are all 178518e2e1aSwdenk * adjacent, but we must take care of the journal wrap around. 179518e2e1aSwdenk */ 180518e2e1aSwdenk static int 181518e2e1aSwdenk journal_init (void) 182518e2e1aSwdenk { 183518e2e1aSwdenk unsigned int block_count = INFO->journal_block_count; 184518e2e1aSwdenk unsigned int desc_block; 185518e2e1aSwdenk unsigned int commit_block; 186518e2e1aSwdenk unsigned int next_trans_id; 187518e2e1aSwdenk struct reiserfs_journal_header header; 188518e2e1aSwdenk struct reiserfs_journal_desc desc; 189518e2e1aSwdenk struct reiserfs_journal_commit commit; 190518e2e1aSwdenk __u32 *journal_table = JOURNAL_START; 191518e2e1aSwdenk 192518e2e1aSwdenk journal_read (block_count, sizeof (header), (char *) &header); 193518e2e1aSwdenk desc_block = __le32_to_cpu(header.j_first_unflushed_offset); 194518e2e1aSwdenk if (desc_block >= block_count) 195518e2e1aSwdenk return 0; 196518e2e1aSwdenk 197518e2e1aSwdenk INFO->journal_first_desc = desc_block; 198518e2e1aSwdenk next_trans_id = __le32_to_cpu(header.j_last_flush_trans_id) + 1; 199518e2e1aSwdenk 200518e2e1aSwdenk #ifdef REISERDEBUG 201518e2e1aSwdenk printf ("journal_init: last flushed %d\n", 202518e2e1aSwdenk __le32_to_cpu(header.j_last_flush_trans_id)); 203518e2e1aSwdenk #endif 204518e2e1aSwdenk 205518e2e1aSwdenk while (1) 206518e2e1aSwdenk { 207518e2e1aSwdenk journal_read (desc_block, sizeof (desc), (char *) &desc); 208518e2e1aSwdenk if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0 209518e2e1aSwdenk || __le32_to_cpu(desc.j_trans_id) != next_trans_id 210518e2e1aSwdenk || __le32_to_cpu(desc.j_mount_id) != __le32_to_cpu(header.j_mount_id)) 211518e2e1aSwdenk /* no more valid transactions */ 212518e2e1aSwdenk break; 213518e2e1aSwdenk 214518e2e1aSwdenk commit_block = (desc_block + __le32_to_cpu(desc.j_len) + 1) & (block_count - 1); 215518e2e1aSwdenk journal_read (commit_block, sizeof (commit), (char *) &commit); 216518e2e1aSwdenk if (__le32_to_cpu(desc.j_trans_id) != commit.j_trans_id 217518e2e1aSwdenk || __le32_to_cpu(desc.j_len) != __le32_to_cpu(commit.j_len)) 218518e2e1aSwdenk /* no more valid transactions */ 219518e2e1aSwdenk break; 220518e2e1aSwdenk 221518e2e1aSwdenk #ifdef REISERDEBUG 222518e2e1aSwdenk printf ("Found valid transaction %d/%d at %d.\n", 223518e2e1aSwdenk __le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); 224518e2e1aSwdenk #endif 225518e2e1aSwdenk 226518e2e1aSwdenk next_trans_id++; 227518e2e1aSwdenk if (journal_table < JOURNAL_END) 228518e2e1aSwdenk { 229518e2e1aSwdenk if ((journal_table + 1 + __le32_to_cpu(desc.j_len)) >= JOURNAL_END) 230518e2e1aSwdenk { 231518e2e1aSwdenk /* The table is almost full; mark the end of the cached 232518e2e1aSwdenk * journal.*/ 233518e2e1aSwdenk *journal_table = __cpu_to_le32(0xffffffff); 234518e2e1aSwdenk journal_table = JOURNAL_END; 235518e2e1aSwdenk } 236518e2e1aSwdenk else 237518e2e1aSwdenk { 238518e2e1aSwdenk unsigned int i; 239518e2e1aSwdenk /* Cache the length and the realblock numbers in the table. 240518e2e1aSwdenk * The block number of descriptor can easily be computed. 241518e2e1aSwdenk * and need not to be stored here. 242518e2e1aSwdenk */ 243518e2e1aSwdenk 244518e2e1aSwdenk /* both are in the little endian format */ 245518e2e1aSwdenk *journal_table++ = desc.j_len; 246518e2e1aSwdenk for (i = 0; i < __le32_to_cpu(desc.j_len) && i < JOURNAL_TRANS_HALF; i++) 247518e2e1aSwdenk { 248518e2e1aSwdenk /* both are in the little endian format */ 249518e2e1aSwdenk *journal_table++ = desc.j_realblock[i]; 250518e2e1aSwdenk #ifdef REISERDEBUG 251518e2e1aSwdenk printf ("block %d is in journal %d.\n", 252518e2e1aSwdenk __le32_to_cpu(desc.j_realblock[i]), desc_block); 253518e2e1aSwdenk #endif 254518e2e1aSwdenk } 255518e2e1aSwdenk for ( ; i < __le32_to_cpu(desc.j_len); i++) 256518e2e1aSwdenk { 257518e2e1aSwdenk /* both are in the little endian format */ 258518e2e1aSwdenk *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; 259518e2e1aSwdenk #ifdef REISERDEBUG 260518e2e1aSwdenk printf ("block %d is in journal %d.\n", 261518e2e1aSwdenk __le32_to_cpu(commit.j_realblock[i-JOURNAL_TRANS_HALF]), 262518e2e1aSwdenk desc_block); 263518e2e1aSwdenk #endif 264518e2e1aSwdenk } 265518e2e1aSwdenk } 266518e2e1aSwdenk } 267518e2e1aSwdenk desc_block = (commit_block + 1) & (block_count - 1); 268518e2e1aSwdenk } 269518e2e1aSwdenk #ifdef REISERDEBUG 270518e2e1aSwdenk printf ("Transaction %d/%d at %d isn't valid.\n", 271518e2e1aSwdenk __le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); 272518e2e1aSwdenk #endif 273518e2e1aSwdenk 274518e2e1aSwdenk INFO->journal_transactions 275518e2e1aSwdenk = next_trans_id - __le32_to_cpu(header.j_last_flush_trans_id) - 1; 276518e2e1aSwdenk return errnum == 0; 277518e2e1aSwdenk } 278518e2e1aSwdenk 279518e2e1aSwdenk /* check filesystem types and read superblock into memory buffer */ 280518e2e1aSwdenk int 281518e2e1aSwdenk reiserfs_mount (unsigned part_length) 282518e2e1aSwdenk { 283518e2e1aSwdenk struct reiserfs_super_block super; 284518e2e1aSwdenk int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; 285*fa75f515SAnatolij Gustschin char *cache; 286518e2e1aSwdenk 287518e2e1aSwdenk if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) 288518e2e1aSwdenk || ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), 289518e2e1aSwdenk (char *) &super) 290518e2e1aSwdenk || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0 291518e2e1aSwdenk && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 292518e2e1aSwdenk && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) 293518e2e1aSwdenk || (/* check that this is not a copy inside the journal log */ 294518e2e1aSwdenk sb_journal_block(&super) * sb_blocksize(&super) 295518e2e1aSwdenk <= REISERFS_DISK_OFFSET_IN_BYTES)) 296518e2e1aSwdenk { 297518e2e1aSwdenk /* Try old super block position */ 298518e2e1aSwdenk superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; 299518e2e1aSwdenk if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) 300518e2e1aSwdenk || ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), 301518e2e1aSwdenk (char *) &super)) 302518e2e1aSwdenk return 0; 303518e2e1aSwdenk 304518e2e1aSwdenk if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 305518e2e1aSwdenk && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) 306518e2e1aSwdenk { 307518e2e1aSwdenk /* pre journaling super block ? */ 308518e2e1aSwdenk if (substring (REISERFS_SUPER_MAGIC_STRING, 309518e2e1aSwdenk (char*) ((int) &super + 20)) > 0) 310518e2e1aSwdenk return 0; 311518e2e1aSwdenk 312518e2e1aSwdenk set_sb_blocksize(&super, REISERFS_OLD_BLOCKSIZE); 313518e2e1aSwdenk set_sb_journal_block(&super, 0); 314518e2e1aSwdenk set_sb_version(&super, 0); 315518e2e1aSwdenk } 316518e2e1aSwdenk } 317518e2e1aSwdenk 318518e2e1aSwdenk /* check the version number. */ 319518e2e1aSwdenk if (sb_version(&super) > REISERFS_MAX_SUPPORTED_VERSION) 320518e2e1aSwdenk return 0; 321518e2e1aSwdenk 322518e2e1aSwdenk INFO->version = sb_version(&super); 323518e2e1aSwdenk INFO->blocksize = sb_blocksize(&super); 324518e2e1aSwdenk INFO->fullblocksize_shift = log2 (sb_blocksize(&super)); 325518e2e1aSwdenk INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; 326518e2e1aSwdenk INFO->cached_slots = 327518e2e1aSwdenk (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; 328518e2e1aSwdenk 329518e2e1aSwdenk #ifdef REISERDEBUG 330518e2e1aSwdenk printf ("reiserfs_mount: version=%d, blocksize=%d\n", 331518e2e1aSwdenk INFO->version, INFO->blocksize); 332518e2e1aSwdenk #endif /* REISERDEBUG */ 333518e2e1aSwdenk 334518e2e1aSwdenk /* Clear node cache. */ 335518e2e1aSwdenk memset (INFO->blocks, 0, sizeof (INFO->blocks)); 336518e2e1aSwdenk 337518e2e1aSwdenk if (sb_blocksize(&super) < FSYSREISER_MIN_BLOCKSIZE 338518e2e1aSwdenk || sb_blocksize(&super) > FSYSREISER_MAX_BLOCKSIZE 339518e2e1aSwdenk || (SECTOR_SIZE << INFO->blocksize_shift) != sb_blocksize(&super)) 340518e2e1aSwdenk return 0; 341518e2e1aSwdenk 342518e2e1aSwdenk /* Initialize journal code. If something fails we end with zero 343518e2e1aSwdenk * journal_transactions, so we don't access the journal at all. 344518e2e1aSwdenk */ 345518e2e1aSwdenk INFO->journal_transactions = 0; 346518e2e1aSwdenk if (sb_journal_block(&super) != 0 && super.s_journal_dev == 0) 347518e2e1aSwdenk { 348518e2e1aSwdenk INFO->journal_block = sb_journal_block(&super); 349518e2e1aSwdenk INFO->journal_block_count = sb_journal_size(&super); 350518e2e1aSwdenk if (is_power_of_two (INFO->journal_block_count)) 351518e2e1aSwdenk journal_init (); 352518e2e1aSwdenk 353518e2e1aSwdenk /* Read in super block again, maybe it is in the journal */ 354518e2e1aSwdenk block_read (superblock >> INFO->blocksize_shift, 355518e2e1aSwdenk 0, sizeof (struct reiserfs_super_block), (char *) &super); 356518e2e1aSwdenk } 357518e2e1aSwdenk 358518e2e1aSwdenk if (! block_read (sb_root_block(&super), 0, INFO->blocksize, (char*) ROOT)) 359518e2e1aSwdenk return 0; 360518e2e1aSwdenk 361*fa75f515SAnatolij Gustschin cache = ROOT; 362*fa75f515SAnatolij Gustschin INFO->tree_depth = __le16_to_cpu(BLOCKHEAD (cache)->blk_level); 363518e2e1aSwdenk 364518e2e1aSwdenk #ifdef REISERDEBUG 365518e2e1aSwdenk printf ("root read_in: block=%d, depth=%d\n", 366518e2e1aSwdenk sb_root_block(&super), INFO->tree_depth); 367518e2e1aSwdenk #endif /* REISERDEBUG */ 368518e2e1aSwdenk 369518e2e1aSwdenk if (INFO->tree_depth >= MAX_HEIGHT) 370518e2e1aSwdenk return 0; 371518e2e1aSwdenk if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) 372518e2e1aSwdenk { 373518e2e1aSwdenk /* There is only one node in the whole filesystem, 374518e2e1aSwdenk * which is simultanously leaf and root */ 375518e2e1aSwdenk memcpy (LEAF, ROOT, INFO->blocksize); 376518e2e1aSwdenk } 377518e2e1aSwdenk return 1; 378518e2e1aSwdenk } 379518e2e1aSwdenk 380518e2e1aSwdenk /***************** TREE ACCESSING METHODS *****************************/ 381518e2e1aSwdenk 382518e2e1aSwdenk /* I assume you are familiar with the ReiserFS tree, if not go to 383518e2e1aSwdenk * http://www.namesys.com/content_table.html 384518e2e1aSwdenk * 385518e2e1aSwdenk * My tree node cache is organized as following 386518e2e1aSwdenk * 0 ROOT node 387518e2e1aSwdenk * 1 LEAF node (if the ROOT is also a LEAF it is copied here 388518e2e1aSwdenk * 2-n other nodes on current path from bottom to top. 389518e2e1aSwdenk * if there is not enough space in the cache, the top most are 390518e2e1aSwdenk * omitted. 391518e2e1aSwdenk * 392518e2e1aSwdenk * I have only two methods to find a key in the tree: 393518e2e1aSwdenk * search_stat(dir_id, objectid) searches for the stat entry (always 394518e2e1aSwdenk * the first entry) of an object. 395518e2e1aSwdenk * next_key() gets the next key in tree order. 396518e2e1aSwdenk * 397518e2e1aSwdenk * This means, that I can only sequential reads of files are 398518e2e1aSwdenk * efficient, but this really doesn't hurt for grub. 399518e2e1aSwdenk */ 400518e2e1aSwdenk 401518e2e1aSwdenk /* Read in the node at the current path and depth into the node cache. 402518e2e1aSwdenk * You must set INFO->blocks[depth] before. 403518e2e1aSwdenk */ 404518e2e1aSwdenk static char * 405518e2e1aSwdenk read_tree_node (unsigned int blockNr, int depth) 406518e2e1aSwdenk { 407518e2e1aSwdenk char* cache = CACHE(depth); 408518e2e1aSwdenk int num_cached = INFO->cached_slots; 409518e2e1aSwdenk if (depth < num_cached) 410518e2e1aSwdenk { 411518e2e1aSwdenk /* This is the cached part of the path. Check if same block is 412518e2e1aSwdenk * needed. 413518e2e1aSwdenk */ 414518e2e1aSwdenk if (blockNr == INFO->blocks[depth]) 415518e2e1aSwdenk return cache; 416518e2e1aSwdenk } 417518e2e1aSwdenk else 418518e2e1aSwdenk cache = CACHE(num_cached); 419518e2e1aSwdenk 420518e2e1aSwdenk #ifdef REISERDEBUG 421518e2e1aSwdenk printf (" next read_in: block=%d (depth=%d)\n", 422518e2e1aSwdenk blockNr, depth); 423518e2e1aSwdenk #endif /* REISERDEBUG */ 424518e2e1aSwdenk if (! block_read (blockNr, 0, INFO->blocksize, cache)) 425518e2e1aSwdenk return 0; 426518e2e1aSwdenk /* Make sure it has the right node level */ 427518e2e1aSwdenk if (__le16_to_cpu(BLOCKHEAD (cache)->blk_level) != depth) 428518e2e1aSwdenk { 429518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 430518e2e1aSwdenk return 0; 431518e2e1aSwdenk } 432518e2e1aSwdenk 433518e2e1aSwdenk INFO->blocks[depth] = blockNr; 434518e2e1aSwdenk return cache; 435518e2e1aSwdenk } 436518e2e1aSwdenk 437518e2e1aSwdenk /* Get the next key, i.e. the key following the last retrieved key in 438518e2e1aSwdenk * tree order. INFO->current_ih and 439518e2e1aSwdenk * INFO->current_info are adapted accordingly. */ 440518e2e1aSwdenk static int 441518e2e1aSwdenk next_key (void) 442518e2e1aSwdenk { 443518e2e1aSwdenk int depth; 444518e2e1aSwdenk struct item_head *ih = INFO->current_ih + 1; 445518e2e1aSwdenk char *cache; 446518e2e1aSwdenk 447518e2e1aSwdenk #ifdef REISERDEBUG 448518e2e1aSwdenk printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n", 449518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 450518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 451518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 452518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 453518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 454518e2e1aSwdenk #endif /* REISERDEBUG */ 455518e2e1aSwdenk 456518e2e1aSwdenk if (ih == &ITEMHEAD[__le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item)]) 457518e2e1aSwdenk { 458518e2e1aSwdenk depth = DISK_LEAF_NODE_LEVEL; 459518e2e1aSwdenk /* The last item, was the last in the leaf node. 460518e2e1aSwdenk * Read in the next block 461518e2e1aSwdenk */ 462518e2e1aSwdenk do 463518e2e1aSwdenk { 464518e2e1aSwdenk if (depth == INFO->tree_depth) 465518e2e1aSwdenk { 466518e2e1aSwdenk /* There are no more keys at all. 467518e2e1aSwdenk * Return a dummy item with MAX_KEY */ 468518e2e1aSwdenk ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; 469518e2e1aSwdenk goto found; 470518e2e1aSwdenk } 471518e2e1aSwdenk depth++; 472518e2e1aSwdenk #ifdef REISERDEBUG 473518e2e1aSwdenk printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); 474518e2e1aSwdenk #endif /* REISERDEBUG */ 475518e2e1aSwdenk } 476518e2e1aSwdenk while (INFO->next_key_nr[depth] == 0); 477518e2e1aSwdenk 478518e2e1aSwdenk if (depth == INFO->tree_depth) 479518e2e1aSwdenk cache = ROOT; 480518e2e1aSwdenk else if (depth <= INFO->cached_slots) 481518e2e1aSwdenk cache = CACHE (depth); 482518e2e1aSwdenk else 483518e2e1aSwdenk { 484518e2e1aSwdenk cache = read_tree_node (INFO->blocks[depth], depth); 485518e2e1aSwdenk if (! cache) 486518e2e1aSwdenk return 0; 487518e2e1aSwdenk } 488518e2e1aSwdenk 489518e2e1aSwdenk do 490518e2e1aSwdenk { 491518e2e1aSwdenk int nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); 492518e2e1aSwdenk int key_nr = INFO->next_key_nr[depth]++; 493518e2e1aSwdenk #ifdef REISERDEBUG 494518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item); 495518e2e1aSwdenk #endif /* REISERDEBUG */ 496518e2e1aSwdenk if (key_nr == nr_item) 497518e2e1aSwdenk /* This is the last item in this block, set the next_key_nr to 0 */ 498518e2e1aSwdenk INFO->next_key_nr[depth] = 0; 499518e2e1aSwdenk 500518e2e1aSwdenk cache = read_tree_node (dc_block_number(&(DC (cache)[key_nr])), --depth); 501518e2e1aSwdenk if (! cache) 502518e2e1aSwdenk return 0; 503518e2e1aSwdenk } 504518e2e1aSwdenk while (depth > DISK_LEAF_NODE_LEVEL); 505518e2e1aSwdenk 506518e2e1aSwdenk ih = ITEMHEAD; 507518e2e1aSwdenk } 508518e2e1aSwdenk found: 509518e2e1aSwdenk INFO->current_ih = ih; 510518e2e1aSwdenk INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; 511518e2e1aSwdenk #ifdef REISERDEBUG 512518e2e1aSwdenk printf (" new ih: key %d:%d:%d:%d version:%d\n", 513518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 514518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 515518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 516518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 517518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 518518e2e1aSwdenk #endif /* REISERDEBUG */ 519518e2e1aSwdenk return 1; 520518e2e1aSwdenk } 521518e2e1aSwdenk 522518e2e1aSwdenk /* preconditions: reiserfs_mount already executed, therefore 523518e2e1aSwdenk * INFO block is valid 524518e2e1aSwdenk * returns: 0 if error (errnum is set), 525518e2e1aSwdenk * nonzero iff we were able to find the key successfully. 526518e2e1aSwdenk * postconditions: on a nonzero return, the current_ih and 527518e2e1aSwdenk * current_item fields describe the key that equals the 528518e2e1aSwdenk * searched key. INFO->next_key contains the next key after 529518e2e1aSwdenk * the searched key. 530518e2e1aSwdenk * side effects: messes around with the cache. 531518e2e1aSwdenk */ 532518e2e1aSwdenk static int 533518e2e1aSwdenk search_stat (__u32 dir_id, __u32 objectid) 534518e2e1aSwdenk { 535518e2e1aSwdenk char *cache; 536518e2e1aSwdenk int depth; 537518e2e1aSwdenk int nr_item; 538518e2e1aSwdenk int i; 539518e2e1aSwdenk struct item_head *ih; 540518e2e1aSwdenk #ifdef REISERDEBUG 541518e2e1aSwdenk printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid); 542518e2e1aSwdenk #endif /* REISERDEBUG */ 543518e2e1aSwdenk 544518e2e1aSwdenk depth = INFO->tree_depth; 545518e2e1aSwdenk cache = ROOT; 546518e2e1aSwdenk 547518e2e1aSwdenk while (depth > DISK_LEAF_NODE_LEVEL) 548518e2e1aSwdenk { 549518e2e1aSwdenk struct key *key; 550518e2e1aSwdenk nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); 551518e2e1aSwdenk 552518e2e1aSwdenk key = KEY (cache); 553518e2e1aSwdenk 554518e2e1aSwdenk for (i = 0; i < nr_item; i++) 555518e2e1aSwdenk { 556518e2e1aSwdenk if (__le32_to_cpu(key->k_dir_id) > dir_id 557518e2e1aSwdenk || (__le32_to_cpu(key->k_dir_id) == dir_id 558518e2e1aSwdenk && (__le32_to_cpu(key->k_objectid) > objectid 559518e2e1aSwdenk || (__le32_to_cpu(key->k_objectid) == objectid 560518e2e1aSwdenk && (__le32_to_cpu(key->u.v1.k_offset) 561518e2e1aSwdenk | __le32_to_cpu(key->u.v1.k_uniqueness)) > 0)))) 562518e2e1aSwdenk break; 563518e2e1aSwdenk key++; 564518e2e1aSwdenk } 565518e2e1aSwdenk 566518e2e1aSwdenk #ifdef REISERDEBUG 567518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); 568518e2e1aSwdenk #endif /* REISERDEBUG */ 569518e2e1aSwdenk INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; 570518e2e1aSwdenk cache = read_tree_node (dc_block_number(&(DC (cache)[i])), --depth); 571518e2e1aSwdenk if (! cache) 572518e2e1aSwdenk return 0; 573518e2e1aSwdenk } 574518e2e1aSwdenk 575518e2e1aSwdenk /* cache == LEAF */ 576518e2e1aSwdenk nr_item = __le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item); 577518e2e1aSwdenk ih = ITEMHEAD; 578518e2e1aSwdenk for (i = 0; i < nr_item; i++) 579518e2e1aSwdenk { 580518e2e1aSwdenk if (__le32_to_cpu(ih->ih_key.k_dir_id) == dir_id 581518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.k_objectid) == objectid 582518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.u.v1.k_offset) == 0 583518e2e1aSwdenk && __le32_to_cpu(ih->ih_key.u.v1.k_uniqueness) == 0) 584518e2e1aSwdenk { 585518e2e1aSwdenk #ifdef REISERDEBUG 586518e2e1aSwdenk printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); 587518e2e1aSwdenk #endif /* REISERDEBUG */ 588518e2e1aSwdenk INFO->current_ih = ih; 589518e2e1aSwdenk INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; 590518e2e1aSwdenk return 1; 591518e2e1aSwdenk } 592518e2e1aSwdenk ih++; 593518e2e1aSwdenk } 594518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 595518e2e1aSwdenk return 0; 596518e2e1aSwdenk } 597518e2e1aSwdenk 598518e2e1aSwdenk int 599518e2e1aSwdenk reiserfs_read (char *buf, unsigned len) 600518e2e1aSwdenk { 601518e2e1aSwdenk unsigned int blocksize; 602518e2e1aSwdenk unsigned int offset; 603518e2e1aSwdenk unsigned int to_read; 604518e2e1aSwdenk char *prev_buf = buf; 605518e2e1aSwdenk 606518e2e1aSwdenk #ifdef REISERDEBUG 607518e2e1aSwdenk printf ("reiserfs_read: filepos=%d len=%d, offset=%Lx\n", 608518e2e1aSwdenk filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1); 609518e2e1aSwdenk #endif /* REISERDEBUG */ 610518e2e1aSwdenk 611518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid 612518e2e1aSwdenk || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1) 613518e2e1aSwdenk { 614518e2e1aSwdenk search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid); 615518e2e1aSwdenk goto get_next_key; 616518e2e1aSwdenk } 617518e2e1aSwdenk 618518e2e1aSwdenk while (! errnum) 619518e2e1aSwdenk { 620518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid) { 621518e2e1aSwdenk break; 622518e2e1aSwdenk } 623518e2e1aSwdenk 624518e2e1aSwdenk offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1; 625518e2e1aSwdenk blocksize = __le16_to_cpu(INFO->current_ih->ih_item_len); 626518e2e1aSwdenk 627518e2e1aSwdenk #ifdef REISERDEBUG 628518e2e1aSwdenk printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n", 629518e2e1aSwdenk filepos, len, offset, blocksize); 630518e2e1aSwdenk #endif /* REISERDEBUG */ 631518e2e1aSwdenk 632518e2e1aSwdenk if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT) 633518e2e1aSwdenk && offset < blocksize) 634518e2e1aSwdenk { 635518e2e1aSwdenk #ifdef REISERDEBUG 636518e2e1aSwdenk printf ("direct_read: offset=%d, blocksize=%d\n", 637518e2e1aSwdenk offset, blocksize); 638518e2e1aSwdenk #endif /* REISERDEBUG */ 639518e2e1aSwdenk to_read = blocksize - offset; 640518e2e1aSwdenk if (to_read > len) 641518e2e1aSwdenk to_read = len; 642518e2e1aSwdenk 643518e2e1aSwdenk memcpy (buf, INFO->current_item + offset, to_read); 644518e2e1aSwdenk goto update_buf_len; 645518e2e1aSwdenk } 646518e2e1aSwdenk else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT)) 647518e2e1aSwdenk { 648518e2e1aSwdenk blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; 649518e2e1aSwdenk #ifdef REISERDEBUG 650518e2e1aSwdenk printf ("indirect_read: offset=%d, blocksize=%d\n", 651518e2e1aSwdenk offset, blocksize); 652518e2e1aSwdenk #endif /* REISERDEBUG */ 653518e2e1aSwdenk 654518e2e1aSwdenk while (offset < blocksize) 655518e2e1aSwdenk { 656518e2e1aSwdenk __u32 blocknr = __le32_to_cpu(((__u32 *) INFO->current_item) 657518e2e1aSwdenk [offset >> INFO->fullblocksize_shift]); 658518e2e1aSwdenk int blk_offset = offset & (INFO->blocksize-1); 659518e2e1aSwdenk to_read = INFO->blocksize - blk_offset; 660518e2e1aSwdenk if (to_read > len) 661518e2e1aSwdenk to_read = len; 662518e2e1aSwdenk 663518e2e1aSwdenk /* Journal is only for meta data. Data blocks can be read 664518e2e1aSwdenk * directly without using block_read 665518e2e1aSwdenk */ 666518e2e1aSwdenk reiserfs_devread (blocknr << INFO->blocksize_shift, 667518e2e1aSwdenk blk_offset, to_read, buf); 668518e2e1aSwdenk update_buf_len: 669518e2e1aSwdenk len -= to_read; 670518e2e1aSwdenk buf += to_read; 671518e2e1aSwdenk offset += to_read; 672518e2e1aSwdenk filepos += to_read; 673518e2e1aSwdenk if (len == 0) 674518e2e1aSwdenk goto done; 675518e2e1aSwdenk } 676518e2e1aSwdenk } 677518e2e1aSwdenk get_next_key: 678518e2e1aSwdenk next_key (); 679518e2e1aSwdenk } 680518e2e1aSwdenk done: 681518e2e1aSwdenk return errnum ? 0 : buf - prev_buf; 682518e2e1aSwdenk } 683518e2e1aSwdenk 684518e2e1aSwdenk 685518e2e1aSwdenk /* preconditions: reiserfs_mount already executed, therefore 686518e2e1aSwdenk * INFO block is valid 687518e2e1aSwdenk * returns: 0 if error, nonzero iff we were able to find the file successfully 688518e2e1aSwdenk * postconditions: on a nonzero return, INFO->fileinfo contains the info 689518e2e1aSwdenk * of the file we were trying to look up, filepos is 0 and filemax is 690518e2e1aSwdenk * the size of the file. 691518e2e1aSwdenk */ 692518e2e1aSwdenk static int 693518e2e1aSwdenk reiserfs_dir (char *dirname) 694518e2e1aSwdenk { 695518e2e1aSwdenk struct reiserfs_de_head *de_head; 696518e2e1aSwdenk char *rest, ch; 697518e2e1aSwdenk __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; 698518e2e1aSwdenk #ifndef STAGE1_5 699518e2e1aSwdenk int do_possibilities = 0; 700518e2e1aSwdenk #endif /* ! STAGE1_5 */ 701518e2e1aSwdenk char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ 702518e2e1aSwdenk int link_count = 0; 703518e2e1aSwdenk int mode; 704518e2e1aSwdenk 705518e2e1aSwdenk dir_id = REISERFS_ROOT_PARENT_OBJECTID; 706518e2e1aSwdenk objectid = REISERFS_ROOT_OBJECTID; 707518e2e1aSwdenk 708518e2e1aSwdenk while (1) 709518e2e1aSwdenk { 710518e2e1aSwdenk #ifdef REISERDEBUG 711518e2e1aSwdenk printf ("dirname=%s\n", dirname); 712518e2e1aSwdenk #endif /* REISERDEBUG */ 713518e2e1aSwdenk 714518e2e1aSwdenk /* Search for the stat info first. */ 715518e2e1aSwdenk if (! search_stat (dir_id, objectid)) 716518e2e1aSwdenk return 0; 717518e2e1aSwdenk 718518e2e1aSwdenk #ifdef REISERDEBUG 719518e2e1aSwdenk printf ("sd_mode=%x sd_size=%d\n", 720518e2e1aSwdenk stat_data_v1(INFO->current_ih) ? sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : 721518e2e1aSwdenk sd_v2_mode((struct stat_data *) (INFO->current_item)), 722518e2e1aSwdenk stat_data_v1(INFO->current_ih) ? sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 723518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item) 724518e2e1aSwdenk ); 725518e2e1aSwdenk 726518e2e1aSwdenk #endif /* REISERDEBUG */ 727518e2e1aSwdenk mode = stat_data_v1(INFO->current_ih) ? 728518e2e1aSwdenk sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : 729518e2e1aSwdenk sd_v2_mode((struct stat_data *) INFO->current_item); 730518e2e1aSwdenk 731518e2e1aSwdenk /* If we've got a symbolic link, then chase it. */ 732518e2e1aSwdenk if (S_ISLNK (mode)) 733518e2e1aSwdenk { 734518e2e1aSwdenk unsigned int len; 735518e2e1aSwdenk if (++link_count > MAX_LINK_COUNT) 736518e2e1aSwdenk { 737518e2e1aSwdenk errnum = ERR_SYMLINK_LOOP; 738518e2e1aSwdenk return 0; 739518e2e1aSwdenk } 740518e2e1aSwdenk 741518e2e1aSwdenk /* Get the symlink size. */ 742518e2e1aSwdenk filemax = stat_data_v1(INFO->current_ih) ? 743518e2e1aSwdenk sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 744518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item); 745518e2e1aSwdenk 746518e2e1aSwdenk /* Find out how long our remaining name is. */ 747518e2e1aSwdenk len = 0; 748518e2e1aSwdenk while (dirname[len] && !isspace (dirname[len])) 749518e2e1aSwdenk len++; 750518e2e1aSwdenk 751518e2e1aSwdenk if (filemax + len > sizeof (linkbuf) - 1) 752518e2e1aSwdenk { 753518e2e1aSwdenk errnum = ERR_FILELENGTH; 754518e2e1aSwdenk return 0; 755518e2e1aSwdenk } 756518e2e1aSwdenk 757518e2e1aSwdenk /* Copy the remaining name to the end of the symlink data. 758518e2e1aSwdenk Note that DIRNAME and LINKBUF may overlap! */ 759518e2e1aSwdenk memmove (linkbuf + filemax, dirname, len+1); 760518e2e1aSwdenk 761518e2e1aSwdenk INFO->fileinfo.k_dir_id = dir_id; 762518e2e1aSwdenk INFO->fileinfo.k_objectid = objectid; 763518e2e1aSwdenk filepos = 0; 764518e2e1aSwdenk if (! next_key () 765518e2e1aSwdenk || reiserfs_read (linkbuf, filemax) != filemax) 766518e2e1aSwdenk { 767518e2e1aSwdenk if (! errnum) 768518e2e1aSwdenk errnum = ERR_FSYS_CORRUPT; 769518e2e1aSwdenk return 0; 770518e2e1aSwdenk } 771518e2e1aSwdenk 772518e2e1aSwdenk #ifdef REISERDEBUG 773518e2e1aSwdenk printf ("symlink=%s\n", linkbuf); 774518e2e1aSwdenk #endif /* REISERDEBUG */ 775518e2e1aSwdenk 776518e2e1aSwdenk dirname = linkbuf; 777518e2e1aSwdenk if (*dirname == '/') 778518e2e1aSwdenk { 779518e2e1aSwdenk /* It's an absolute link, so look it up in root. */ 780518e2e1aSwdenk dir_id = REISERFS_ROOT_PARENT_OBJECTID; 781518e2e1aSwdenk objectid = REISERFS_ROOT_OBJECTID; 782518e2e1aSwdenk } 783518e2e1aSwdenk else 784518e2e1aSwdenk { 785518e2e1aSwdenk /* Relative, so look it up in our parent directory. */ 786518e2e1aSwdenk dir_id = parent_dir_id; 787518e2e1aSwdenk objectid = parent_objectid; 788518e2e1aSwdenk } 789518e2e1aSwdenk 790518e2e1aSwdenk /* Now lookup the new name. */ 791518e2e1aSwdenk continue; 792518e2e1aSwdenk } 793518e2e1aSwdenk 794518e2e1aSwdenk /* if we have a real file (and we're not just printing possibilities), 795518e2e1aSwdenk then this is where we want to exit */ 796518e2e1aSwdenk 797518e2e1aSwdenk if (! *dirname || isspace (*dirname)) 798518e2e1aSwdenk { 799518e2e1aSwdenk if (! S_ISREG (mode)) 800518e2e1aSwdenk { 801518e2e1aSwdenk errnum = ERR_BAD_FILETYPE; 802518e2e1aSwdenk return 0; 803518e2e1aSwdenk } 804518e2e1aSwdenk 805518e2e1aSwdenk filepos = 0; 806518e2e1aSwdenk filemax = stat_data_v1(INFO->current_ih) ? 807518e2e1aSwdenk sd_v1_size((struct stat_data_v1 *) INFO->current_item) : 808518e2e1aSwdenk sd_v2_size((struct stat_data *) INFO->current_item); 809518e2e1aSwdenk #if 0 810518e2e1aSwdenk /* If this is a new stat data and size is > 4GB set filemax to 811518e2e1aSwdenk * maximum 812518e2e1aSwdenk */ 813518e2e1aSwdenk if (__le16_to_cpu(INFO->current_ih->ih_version) == ITEM_VERSION_2 814518e2e1aSwdenk && sd_size_hi((struct stat_data *) INFO->current_item) > 0) 815518e2e1aSwdenk filemax = 0xffffffff; 816518e2e1aSwdenk #endif 817518e2e1aSwdenk INFO->fileinfo.k_dir_id = dir_id; 818518e2e1aSwdenk INFO->fileinfo.k_objectid = objectid; 819518e2e1aSwdenk return next_key (); 820518e2e1aSwdenk } 821518e2e1aSwdenk 822518e2e1aSwdenk /* continue with the file/directory name interpretation */ 823518e2e1aSwdenk while (*dirname == '/') 824518e2e1aSwdenk dirname++; 825518e2e1aSwdenk if (! S_ISDIR (mode)) 826518e2e1aSwdenk { 827518e2e1aSwdenk errnum = ERR_BAD_FILETYPE; 828518e2e1aSwdenk return 0; 829518e2e1aSwdenk } 830518e2e1aSwdenk for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++); 831518e2e1aSwdenk *rest = 0; 832518e2e1aSwdenk 833518e2e1aSwdenk # ifndef STAGE1_5 834518e2e1aSwdenk if (print_possibilities && ch != '/') 835518e2e1aSwdenk do_possibilities = 1; 836518e2e1aSwdenk # endif /* ! STAGE1_5 */ 837518e2e1aSwdenk 838518e2e1aSwdenk while (1) 839518e2e1aSwdenk { 840518e2e1aSwdenk char *name_end; 841518e2e1aSwdenk int num_entries; 842518e2e1aSwdenk 843518e2e1aSwdenk if (! next_key ()) 844518e2e1aSwdenk return 0; 845518e2e1aSwdenk #ifdef REISERDEBUG 846518e2e1aSwdenk printf ("ih: key %d:%d:%d:%d version:%d\n", 847518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), 848518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.k_objectid), 849518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), 850518e2e1aSwdenk __le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), 851518e2e1aSwdenk __le16_to_cpu(INFO->current_ih->ih_version)); 852518e2e1aSwdenk #endif /* REISERDEBUG */ 853518e2e1aSwdenk 854518e2e1aSwdenk if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != objectid) 855518e2e1aSwdenk break; 856518e2e1aSwdenk 857518e2e1aSwdenk name_end = INFO->current_item + __le16_to_cpu(INFO->current_ih->ih_item_len); 858518e2e1aSwdenk de_head = (struct reiserfs_de_head *) INFO->current_item; 859518e2e1aSwdenk num_entries = __le16_to_cpu(INFO->current_ih->u.ih_entry_count); 860518e2e1aSwdenk while (num_entries > 0) 861518e2e1aSwdenk { 862518e2e1aSwdenk char *filename = INFO->current_item + deh_location(de_head); 863518e2e1aSwdenk char tmp = *name_end; 864518e2e1aSwdenk if ((deh_state(de_head) & DEH_Visible)) 865518e2e1aSwdenk { 866518e2e1aSwdenk int cmp; 867518e2e1aSwdenk /* Directory names in ReiserFS are not null 868518e2e1aSwdenk * terminated. We write a temporary 0 behind it. 869518e2e1aSwdenk * NOTE: that this may overwrite the first block in 870518e2e1aSwdenk * the tree cache. That doesn't hurt as long as we 871518e2e1aSwdenk * don't call next_key () in between. 872518e2e1aSwdenk */ 873518e2e1aSwdenk *name_end = 0; 874518e2e1aSwdenk cmp = substring (dirname, filename); 875518e2e1aSwdenk *name_end = tmp; 876518e2e1aSwdenk # ifndef STAGE1_5 877518e2e1aSwdenk if (do_possibilities) 878518e2e1aSwdenk { 879518e2e1aSwdenk if (cmp <= 0) 880518e2e1aSwdenk { 881518e2e1aSwdenk char fn[PATH_MAX]; 882518e2e1aSwdenk struct fsys_reiser_info info_save; 883518e2e1aSwdenk 884518e2e1aSwdenk if (print_possibilities > 0) 885518e2e1aSwdenk print_possibilities = -print_possibilities; 886518e2e1aSwdenk *name_end = 0; 887518e2e1aSwdenk strcpy(fn, filename); 888518e2e1aSwdenk *name_end = tmp; 889518e2e1aSwdenk 890518e2e1aSwdenk /* If NAME is "." or "..", do not count it. */ 891518e2e1aSwdenk if (strcmp (fn, ".") != 0 && strcmp (fn, "..") != 0) { 892518e2e1aSwdenk memcpy(&info_save, INFO, sizeof(struct fsys_reiser_info)); 893518e2e1aSwdenk search_stat (deh_dir_id(de_head), deh_objectid(de_head)); 894518e2e1aSwdenk sd_print_item(INFO->current_ih, INFO->current_item); 895518e2e1aSwdenk printf(" %s\n", fn); 896518e2e1aSwdenk search_stat (dir_id, objectid); 897518e2e1aSwdenk memcpy(INFO, &info_save, sizeof(struct fsys_reiser_info)); 898518e2e1aSwdenk } 899518e2e1aSwdenk } 900518e2e1aSwdenk } 901518e2e1aSwdenk else 902518e2e1aSwdenk # endif /* ! STAGE1_5 */ 903518e2e1aSwdenk if (cmp == 0) 904518e2e1aSwdenk goto found; 905518e2e1aSwdenk } 906518e2e1aSwdenk /* The beginning of this name marks the end of the next name. 907518e2e1aSwdenk */ 908518e2e1aSwdenk name_end = filename; 909518e2e1aSwdenk de_head++; 910518e2e1aSwdenk num_entries--; 911518e2e1aSwdenk } 912518e2e1aSwdenk } 913518e2e1aSwdenk 914518e2e1aSwdenk # ifndef STAGE1_5 915518e2e1aSwdenk if (print_possibilities < 0) 916518e2e1aSwdenk return 1; 917518e2e1aSwdenk # endif /* ! STAGE1_5 */ 918518e2e1aSwdenk 919518e2e1aSwdenk errnum = ERR_FILE_NOT_FOUND; 920518e2e1aSwdenk *rest = ch; 921518e2e1aSwdenk return 0; 922518e2e1aSwdenk 923518e2e1aSwdenk found: 924518e2e1aSwdenk *rest = ch; 925518e2e1aSwdenk dirname = rest; 926518e2e1aSwdenk 927518e2e1aSwdenk parent_dir_id = dir_id; 928518e2e1aSwdenk parent_objectid = objectid; 929518e2e1aSwdenk dir_id = deh_dir_id(de_head); 930518e2e1aSwdenk objectid = deh_objectid(de_head); 931518e2e1aSwdenk } 932518e2e1aSwdenk } 933518e2e1aSwdenk 934518e2e1aSwdenk /* 935518e2e1aSwdenk * U-Boot interface functions 936518e2e1aSwdenk */ 937518e2e1aSwdenk 938518e2e1aSwdenk /* 939518e2e1aSwdenk * List given directory 940518e2e1aSwdenk * 941518e2e1aSwdenk * RETURN: 0 - OK, else grub_error_t errnum 942518e2e1aSwdenk */ 943518e2e1aSwdenk int 944518e2e1aSwdenk reiserfs_ls (char *dirname) 945518e2e1aSwdenk { 946518e2e1aSwdenk char *dir_slash; 947518e2e1aSwdenk int res; 948518e2e1aSwdenk 949518e2e1aSwdenk errnum = 0; 950518e2e1aSwdenk dir_slash = malloc(strlen(dirname) + 1); 951518e2e1aSwdenk if (dir_slash == NULL) { 952518e2e1aSwdenk return ERR_NUMBER_OVERFLOW; 953518e2e1aSwdenk } 954518e2e1aSwdenk strcpy(dir_slash, dirname); 955518e2e1aSwdenk /* add "/" to the directory name */ 956518e2e1aSwdenk strcat(dir_slash, "/"); 957518e2e1aSwdenk 958518e2e1aSwdenk print_possibilities = 1; 959518e2e1aSwdenk res = reiserfs_dir (dir_slash); 960518e2e1aSwdenk free(dir_slash); 961518e2e1aSwdenk if (!res || errnum) { 962518e2e1aSwdenk return errnum; 963518e2e1aSwdenk } 964518e2e1aSwdenk 965518e2e1aSwdenk return 0; 966518e2e1aSwdenk } 967518e2e1aSwdenk 968518e2e1aSwdenk /* 969518e2e1aSwdenk * Open file for reading 970518e2e1aSwdenk * 971518e2e1aSwdenk * RETURN: >0 - OK, size of opened file 972518e2e1aSwdenk * <0 - ERROR -grub_error_t errnum 973518e2e1aSwdenk */ 974518e2e1aSwdenk int 975518e2e1aSwdenk reiserfs_open (char *filename) 976518e2e1aSwdenk { 977518e2e1aSwdenk /* open the file */ 978518e2e1aSwdenk errnum = 0; 979518e2e1aSwdenk print_possibilities = 0; 980518e2e1aSwdenk if (!reiserfs_dir (filename) || errnum) { 981518e2e1aSwdenk return -errnum; 982518e2e1aSwdenk } 983518e2e1aSwdenk return filemax; 984518e2e1aSwdenk } 985