2N/A/* reiserfs.c - ReiserFS versions up to 3.6 */
2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (C) 2003,2004,2005,2008 Free Software Foundation, Inc.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A/*
2N/A TODO:
2N/A implement journal handling (ram replay)
2N/A test tail packing & direct files
2N/A validate partition label position
2N/A*/
2N/A
2N/A#if 0
2N/A# define GRUB_REISERFS_DEBUG
2N/A# define GRUB_REISERFS_JOURNALING
2N/A# define GRUB_HEXDUMP
2N/A#endif
2N/A
2N/A#include <grub/err.h>
2N/A#include <grub/file.h>
2N/A#include <grub/mm.h>
2N/A#include <grub/misc.h>
2N/A#include <grub/disk.h>
2N/A#include <grub/dl.h>
2N/A#include <grub/types.h>
2N/A#include <grub/fshelp.h>
2N/A
2N/AGRUB_MOD_LICENSE ("GPLv3+");
2N/A
2N/A#define MIN(a, b) \
2N/A ({ typeof (a) _a = (a); \
2N/A typeof (b) _b = (b); \
2N/A _a < _b ? _a : _b; })
2N/A
2N/A#define MAX(a, b) \
2N/A ({ typeof (a) _a = (a); \
2N/A typeof (b) _b = (b); \
2N/A _a > _b ? _a : _b; })
2N/A
2N/A#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
2N/A#define REISERFS_MAGIC_LEN 12
2N/A#define REISERFS_MAGIC_STRING "ReIsEr"
2N/A#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
2N/A/* If the 3rd bit of an item state is set, then it's visible. */
2N/A#define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
2N/A
2N/A#define S_IFLNK 0xA000
2N/A
2N/Astatic grub_dl_t my_mod;
2N/A
2N/A#define assert(boolean) real_assert (boolean, GRUB_FILE, __LINE__)
2N/Astatic inline void
2N/Areal_assert (int boolean, const char *file, const int line)
2N/A{
2N/A if (! boolean)
2N/A grub_printf ("Assertion failed at %s:%d\n", file, line);
2N/A}
2N/A
2N/Aenum grub_reiserfs_item_type
2N/A {
2N/A GRUB_REISERFS_STAT,
2N/A GRUB_REISERFS_DIRECTORY,
2N/A GRUB_REISERFS_DIRECT,
2N/A GRUB_REISERFS_INDIRECT,
2N/A /* Matches both _DIRECT and _INDIRECT when searching. */
2N/A GRUB_REISERFS_ANY,
2N/A GRUB_REISERFS_UNKNOWN
2N/A };
2N/A
2N/Astruct grub_reiserfs_superblock
2N/A{
2N/A grub_uint32_t block_count;
2N/A grub_uint32_t block_free_count;
2N/A grub_uint32_t root_block;
2N/A grub_uint32_t journal_block;
2N/A grub_uint32_t journal_device;
2N/A grub_uint32_t journal_original_size;
2N/A grub_uint32_t journal_max_transaction_size;
2N/A grub_uint32_t journal_block_count;
2N/A grub_uint32_t journal_max_batch;
2N/A grub_uint32_t journal_max_commit_age;
2N/A grub_uint32_t journal_max_transaction_age;
2N/A grub_uint16_t block_size;
2N/A grub_uint16_t oid_max_size;
2N/A grub_uint16_t oid_current_size;
2N/A grub_uint16_t state;
2N/A grub_uint8_t magic_string[REISERFS_MAGIC_LEN];
2N/A grub_uint32_t function_hash_code;
2N/A grub_uint16_t tree_height;
2N/A grub_uint16_t bitmap_number;
2N/A grub_uint16_t version;
2N/A grub_uint16_t reserved;
2N/A grub_uint32_t inode_generation;
2N/A grub_uint8_t unused[4];
2N/A grub_uint16_t uuid[8];
2N/A char label[16];
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_journal_header
2N/A{
2N/A grub_uint32_t last_flush_uid;
2N/A grub_uint32_t unflushed_offset;
2N/A grub_uint32_t mount_id;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_description_block
2N/A{
2N/A grub_uint32_t id;
2N/A grub_uint32_t len;
2N/A grub_uint32_t mount_id;
2N/A grub_uint32_t real_blocks[0];
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_commit_block
2N/A{
2N/A grub_uint32_t id;
2N/A grub_uint32_t len;
2N/A grub_uint32_t real_blocks[0];
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_stat_item_v1
2N/A{
2N/A grub_uint16_t mode;
2N/A grub_uint16_t hardlink_count;
2N/A grub_uint16_t uid;
2N/A grub_uint16_t gid;
2N/A grub_uint32_t size;
2N/A grub_uint32_t atime;
2N/A grub_uint32_t mtime;
2N/A grub_uint32_t ctime;
2N/A grub_uint32_t rdev;
2N/A grub_uint32_t first_direct_byte;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_stat_item_v2
2N/A{
2N/A grub_uint16_t mode;
2N/A grub_uint16_t reserved;
2N/A grub_uint32_t hardlink_count;
2N/A grub_uint64_t size;
2N/A grub_uint32_t uid;
2N/A grub_uint32_t gid;
2N/A grub_uint32_t atime;
2N/A grub_uint32_t mtime;
2N/A grub_uint32_t ctime;
2N/A grub_uint32_t blocks;
2N/A grub_uint32_t first_direct_byte;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_key
2N/A{
2N/A grub_uint32_t directory_id;
2N/A grub_uint32_t object_id;
2N/A union
2N/A {
2N/A struct
2N/A {
2N/A grub_uint32_t offset;
2N/A grub_uint32_t type;
2N/A } v1 __attribute__ ((packed));
2N/A struct
2N/A {
2N/A grub_uint64_t offset_type;
2N/A } v2 __attribute__ ((packed));
2N/A } u;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_item_header
2N/A{
2N/A struct grub_reiserfs_key key;
2N/A union
2N/A {
2N/A grub_uint16_t free_space;
2N/A grub_uint16_t entry_count;
2N/A } u __attribute__ ((packed));
2N/A grub_uint16_t item_size;
2N/A grub_uint16_t item_location;
2N/A grub_uint16_t version;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_block_header
2N/A{
2N/A grub_uint16_t level;
2N/A grub_uint16_t item_count;
2N/A grub_uint16_t free_space;
2N/A grub_uint16_t reserved;
2N/A struct grub_reiserfs_key block_right_delimiting_key;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_disk_child
2N/A{
2N/A grub_uint32_t block_number;
2N/A grub_uint16_t size;
2N/A grub_uint16_t reserved;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_reiserfs_directory_header
2N/A{
2N/A grub_uint32_t offset;
2N/A grub_uint32_t directory_id;
2N/A grub_uint32_t object_id;
2N/A grub_uint16_t location;
2N/A grub_uint16_t state;
2N/A} __attribute__ ((packed));
2N/A
2N/Astruct grub_fshelp_node
2N/A{
2N/A struct grub_reiserfs_data *data;
2N/A grub_uint32_t block_number; /* 0 if node is not found. */
2N/A grub_uint16_t block_position;
2N/A grub_uint64_t next_offset;
2N/A grub_int32_t mtime;
2N/A enum grub_reiserfs_item_type type; /* To know how to read the header. */
2N/A struct grub_reiserfs_item_header header;
2N/A};
2N/A
2N/A/* Returned when opening a file. */
2N/Astruct grub_reiserfs_data
2N/A{
2N/A struct grub_reiserfs_superblock superblock;
2N/A grub_disk_t disk;
2N/A};
2N/A
2N/A/* Internal-only functions. Not to be used outside of this file. */
2N/A
2N/A/* Return the type of given v2 key. */
2N/Astatic enum grub_reiserfs_item_type
2N/Agrub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key *key)
2N/A{
2N/A switch (grub_le_to_cpu64 (key->u.v2.offset_type) >> 60)
2N/A {
2N/A case 0:
2N/A return GRUB_REISERFS_STAT;
2N/A case 15:
2N/A return GRUB_REISERFS_ANY;
2N/A case 3:
2N/A return GRUB_REISERFS_DIRECTORY;
2N/A case 2:
2N/A return GRUB_REISERFS_DIRECT;
2N/A case 1:
2N/A return GRUB_REISERFS_INDIRECT;
2N/A }
2N/A return GRUB_REISERFS_UNKNOWN;
2N/A}
2N/A
2N/A/* Return the type of given v1 key. */
2N/Astatic enum grub_reiserfs_item_type
2N/Agrub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key *key)
2N/A{
2N/A switch (grub_le_to_cpu32 (key->u.v1.type))
2N/A {
2N/A case 0:
2N/A return GRUB_REISERFS_STAT;
2N/A case 555:
2N/A return GRUB_REISERFS_ANY;
2N/A case 500:
2N/A return GRUB_REISERFS_DIRECTORY;
2N/A case 0x20000000:
2N/A case 0xFFFFFFFF:
2N/A return GRUB_REISERFS_DIRECT;
2N/A case 0x10000000:
2N/A case 0xFFFFFFFE:
2N/A return GRUB_REISERFS_INDIRECT;
2N/A }
2N/A return GRUB_REISERFS_UNKNOWN;
2N/A}
2N/A
2N/A/* Return 1 if the given key is version 1 key, 2 otherwise. */
2N/Astatic int
2N/Agrub_reiserfs_get_key_version (const struct grub_reiserfs_key *key)
2N/A{
2N/A return grub_reiserfs_get_key_v1_type (key) == GRUB_REISERFS_UNKNOWN ? 2 : 1;
2N/A}
2N/A
2N/A#ifdef GRUB_HEXDUMP
2N/Astatic void
2N/Agrub_hexdump (char *buffer, grub_size_t len)
2N/A{
2N/A grub_size_t a;
2N/A for (a = 0; a < len; a++)
2N/A {
2N/A if (! (a & 0x0F))
2N/A grub_printf ("\n%08x ", a);
2N/A grub_printf ("%02x ",
2N/A ((unsigned int) ((unsigned char *) buffer)[a]) & 0xFF);
2N/A }
2N/A grub_printf ("\n");
2N/A}
2N/A#endif
2N/A
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/Astatic grub_uint64_t
2N/Agrub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key);
2N/A
2N/Astatic enum grub_reiserfs_item_type
2N/Agrub_reiserfs_get_key_type (const struct grub_reiserfs_key *key);
2N/A
2N/Astatic void
2N/Agrub_reiserfs_print_key (const struct grub_reiserfs_key *key)
2N/A{
2N/A unsigned int a;
2N/A char *reiserfs_type_strings[] = {
2N/A "stat ",
2N/A "directory",
2N/A "direct ",
2N/A "indirect ",
2N/A "any ",
2N/A "unknown "
2N/A };
2N/A
2N/A for (a = 0; a < sizeof (struct grub_reiserfs_key); a++)
2N/A grub_printf ("%02x ", ((unsigned int) ((unsigned char *) key)[a]) & 0xFF);
2N/A grub_printf ("parent id = 0x%08x, self id = 0x%08x, type = %s, offset = ",
2N/A grub_le_to_cpu32 (key->directory_id),
2N/A grub_le_to_cpu32 (key->object_id),
2N/A reiserfs_type_strings [grub_reiserfs_get_key_type (key)]);
2N/A if (grub_reiserfs_get_key_version (key) == 1)
2N/A grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset (key));
2N/A else
2N/A grub_printf("0x%07x%08x",
2N/A (unsigned) (grub_reiserfs_get_key_offset (key) >> 32),
2N/A (unsigned) (grub_reiserfs_get_key_offset (key) & 0xFFFFFFFF));
2N/A grub_printf ("\n");
2N/A}
2N/A#endif
2N/A
2N/A/* Return the offset of given key. */
2N/Astatic grub_uint64_t
2N/Agrub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key)
2N/A{
2N/A if (grub_reiserfs_get_key_version (key) == 1)
2N/A return grub_le_to_cpu32 (key->u.v1.offset);
2N/A else
2N/A return grub_le_to_cpu64 (key->u.v2.offset_type) & (~0ULL >> 4);
2N/A}
2N/A
2N/A/* Set the offset of given key. */
2N/Astatic void
2N/Agrub_reiserfs_set_key_offset (struct grub_reiserfs_key *key,
2N/A grub_uint64_t value)
2N/A{
2N/A if (grub_reiserfs_get_key_version (key) == 1)
2N/A key->u.v1.offset = grub_cpu_to_le32 (value);
2N/A else
2N/A key->u.v2.offset_type \
2N/A = ((key->u.v2.offset_type & grub_cpu_to_le64 (15ULL << 60))
2N/A | grub_cpu_to_le64 (value & (~0ULL >> 4)));
2N/A}
2N/A
2N/A/* Return the type of given key. */
2N/Astatic enum grub_reiserfs_item_type
2N/Agrub_reiserfs_get_key_type (const struct grub_reiserfs_key *key)
2N/A{
2N/A if (grub_reiserfs_get_key_version (key) == 1)
2N/A return grub_reiserfs_get_key_v1_type (key);
2N/A else
2N/A return grub_reiserfs_get_key_v2_type (key);
2N/A}
2N/A
2N/A/* Set the type of given key, with given version number. */
2N/Astatic void
2N/Agrub_reiserfs_set_key_type (struct grub_reiserfs_key *key,
2N/A enum grub_reiserfs_item_type grub_type,
2N/A int version)
2N/A{
2N/A grub_uint32_t type;
2N/A
2N/A switch (grub_type)
2N/A {
2N/A case GRUB_REISERFS_STAT:
2N/A type = 0;
2N/A break;
2N/A case GRUB_REISERFS_ANY:
2N/A type = (version == 1) ? 555 : 15;
2N/A break;
2N/A case GRUB_REISERFS_DIRECTORY:
2N/A type = (version == 1) ? 500 : 3;
2N/A break;
2N/A case GRUB_REISERFS_DIRECT:
2N/A type = (version == 1) ? 0xFFFFFFFF : 2;
2N/A break;
2N/A case GRUB_REISERFS_INDIRECT:
2N/A type = (version == 1) ? 0xFFFFFFFE : 1;
2N/A break;
2N/A default:
2N/A return;
2N/A }
2N/A
2N/A if (version == 1)
2N/A key->u.v1.type = grub_cpu_to_le32 (type);
2N/A else
2N/A key->u.v2.offset_type
2N/A = ((key->u.v2.offset_type & grub_cpu_to_le64 (~0ULL >> 4))
2N/A | grub_cpu_to_le64 ((grub_uint64_t) type << 60));
2N/A
2N/A assert (grub_reiserfs_get_key_type (key) == grub_type);
2N/A}
2N/A
2N/A/* -1 if key 1 if lower than key 2.
2N/A 0 if key 1 is equal to key 2.
2N/A 1 if key 1 is higher than key 2. */
2N/Astatic int
2N/Agrub_reiserfs_compare_keys (const struct grub_reiserfs_key *key1,
2N/A const struct grub_reiserfs_key *key2)
2N/A{
2N/A grub_uint64_t offset1, offset2;
2N/A enum grub_reiserfs_item_type type1, type2;
2N/A grub_uint32_t id1, id2;
2N/A
2N/A if (! key1 || ! key2)
2N/A return -2;
2N/A
2N/A id1 = grub_le_to_cpu32 (key1->directory_id);
2N/A id2 = grub_le_to_cpu32 (key2->directory_id);
2N/A if (id1 < id2)
2N/A return -1;
2N/A if (id1 > id2)
2N/A return 1;
2N/A
2N/A id1 = grub_le_to_cpu32 (key1->object_id);
2N/A id2 = grub_le_to_cpu32 (key2->object_id);
2N/A if (id1 < id2)
2N/A return -1;
2N/A if (id1 > id2)
2N/A return 1;
2N/A
2N/A offset1 = grub_reiserfs_get_key_offset (key1);
2N/A offset2 = grub_reiserfs_get_key_offset (key2);
2N/A if (offset1 < offset2)
2N/A return -1;
2N/A if (offset1 > offset2)
2N/A return 1;
2N/A
2N/A type1 = grub_reiserfs_get_key_type (key1);
2N/A type2 = grub_reiserfs_get_key_type (key2);
2N/A if ((type1 == GRUB_REISERFS_ANY
2N/A && (type2 == GRUB_REISERFS_DIRECT
2N/A || type2 == GRUB_REISERFS_INDIRECT))
2N/A || (type2 == GRUB_REISERFS_ANY
2N/A && (type1 == GRUB_REISERFS_DIRECT
2N/A || type1 == GRUB_REISERFS_INDIRECT)))
2N/A return 0;
2N/A if (type1 < type2)
2N/A return -1;
2N/A if (type1 > type2)
2N/A return 1;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A/* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM
2N/A accordingly to what was found. */
2N/Astatic grub_err_t
2N/Agrub_reiserfs_get_item (struct grub_reiserfs_data *data,
2N/A const struct grub_reiserfs_key *key,
2N/A struct grub_fshelp_node *item)
2N/A{
2N/A grub_uint32_t block_number;
2N/A struct grub_reiserfs_block_header *block_header = 0;
2N/A struct grub_reiserfs_key *block_key = 0;
2N/A grub_uint16_t block_size, item_count, current_level;
2N/A grub_uint16_t i;
2N/A grub_uint16_t previous_level = ~0;
2N/A struct grub_reiserfs_item_header *item_headers = 0;
2N/A
2N/A if (! data)
2N/A {
2N/A grub_error (GRUB_ERR_TEST_FAILURE, "data is NULL");
2N/A goto fail;
2N/A }
2N/A
2N/A if (! key)
2N/A {
2N/A grub_error (GRUB_ERR_TEST_FAILURE, "key is NULL");
2N/A goto fail;
2N/A }
2N/A
2N/A if (! item)
2N/A {
2N/A grub_error (GRUB_ERR_TEST_FAILURE, "item is NULL");
2N/A goto fail;
2N/A }
2N/A
2N/A block_size = grub_le_to_cpu16 (data->superblock.block_size);
2N/A block_number = grub_le_to_cpu32 (data->superblock.root_block);
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A grub_printf("Searching for ");
2N/A grub_reiserfs_print_key (key);
2N/A#endif
2N/A block_header = grub_malloc (block_size);
2N/A if (! block_header)
2N/A goto fail;
2N/A
2N/A item->next_offset = 0;
2N/A do
2N/A {
2N/A grub_disk_read (data->disk,
2N/A block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A (((grub_off_t) block_number * block_size)
2N/A & (GRUB_DISK_SECTOR_SIZE - 1)),
2N/A block_size, block_header);
2N/A if (grub_errno)
2N/A goto fail;
2N/A current_level = grub_le_to_cpu16 (block_header->level);
2N/A grub_dprintf ("reiserfs_tree", " at level %d\n", current_level);
2N/A if (current_level >= previous_level)
2N/A {
2N/A grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n");
2N/A grub_error (GRUB_ERR_FILE_READ_ERROR, "level loop");
2N/A goto fail;
2N/A }
2N/A previous_level = current_level;
2N/A item_count = grub_le_to_cpu16 (block_header->item_count);
2N/A grub_dprintf ("reiserfs_tree", " number of contained items : %d\n",
2N/A item_count);
2N/A if (current_level > 1)
2N/A {
2N/A /* Internal node. Navigate to the child that should contain
2N/A the searched key. */
2N/A struct grub_reiserfs_key *keys
2N/A = (struct grub_reiserfs_key *) (block_header + 1);
2N/A struct grub_reiserfs_disk_child *children
2N/A = ((struct grub_reiserfs_disk_child *)
2N/A (keys + item_count));
2N/A
2N/A for (i = 0;
2N/A i < item_count
2N/A && grub_reiserfs_compare_keys (key, &(keys[i])) >= 0;
2N/A i++)
2N/A {
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A grub_printf("i %03d/%03d ", i + 1, item_count + 1);
2N/A grub_reiserfs_print_key (&(keys[i]));
2N/A#endif
2N/A }
2N/A block_number = grub_le_to_cpu32 (children[i].block_number);
2N/A if ((i < item_count) && (key->directory_id == keys[i].directory_id)
2N/A && (key->object_id == keys[i].object_id))
2N/A item->next_offset = grub_reiserfs_get_key_offset(&(keys[i]));
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A if (i == item_count
2N/A || grub_reiserfs_compare_keys (key, &(keys[i])) == 0)
2N/A grub_printf(">");
2N/A else
2N/A grub_printf("<");
2N/A if (i < item_count)
2N/A {
2N/A grub_printf (" %03d/%03d ", i + 1, item_count + 1);
2N/A grub_reiserfs_print_key (&(keys[i]));
2N/A if (i + 1 < item_count)
2N/A {
2N/A grub_printf ("+ %03d/%03d ", i + 2, item_count);
2N/A grub_reiserfs_print_key (&(keys[i + 1]));
2N/A }
2N/A }
2N/A else
2N/A grub_printf ("Accessing rightmost child at block %d.\n",
2N/A block_number);
2N/A#endif
2N/A }
2N/A else
2N/A {
2N/A /* Leaf node. Check that the key is actually present. */
2N/A item_headers
2N/A = (struct grub_reiserfs_item_header *) (block_header + 1);
2N/A for (i = 0;
2N/A i < item_count
2N/A && (grub_reiserfs_compare_keys (key, &(item_headers[i].key))
2N/A != 0);
2N/A i++)
2N/A {
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A if (key->directory_id == item_headers[i].key.directory_id && \
2N/A key->object_id == item_headers[i].key.object_id)
2N/A grub_printf("C");
2N/A else
2N/A grub_printf(" ");
2N/A grub_printf(" %03d/%03d ", i + 1, item_count);
2N/A grub_reiserfs_print_key (&(item_headers[i].key));
2N/A#endif
2N/A }
2N/A if (i < item_count)
2N/A block_key = &(item_headers[i].key);
2N/A }
2N/A }
2N/A while (current_level > 1);
2N/A
2N/A item->data = data;
2N/A
2N/A if (i == item_count || grub_reiserfs_compare_keys (key, block_key))
2N/A {
2N/A item->block_number = 0;
2N/A item->block_position = 0;
2N/A item->type = GRUB_REISERFS_UNKNOWN;
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A grub_printf("Not found.\n");
2N/A#endif
2N/A }
2N/A else
2N/A {
2N/A item->block_number = block_number;
2N/A item->block_position = i;
2N/A item->type = grub_reiserfs_get_key_type (block_key);
2N/A grub_memcpy (&(item->header), &(item_headers[i]),
2N/A sizeof (struct grub_reiserfs_item_header));
2N/A#ifdef GRUB_REISERFS_DEBUG
2N/A grub_printf ("F %03d/%03d ", i + 1, item_count);
2N/A grub_reiserfs_print_key (block_key);
2N/A#endif
2N/A }
2N/A
2N/A assert (grub_errno == GRUB_ERR_NONE);
2N/A grub_free (block_header);
2N/A return GRUB_ERR_NONE;
2N/A
2N/A fail:
2N/A assert (grub_errno != GRUB_ERR_NONE);
2N/A grub_free (block_header);
2N/A assert (grub_errno != GRUB_ERR_NONE);
2N/A return grub_errno;
2N/A}
2N/A
2N/A/* Return the path of the file which is pointed at by symlink NODE. */
2N/Astatic char *
2N/Agrub_reiserfs_read_symlink (grub_fshelp_node_t node)
2N/A{
2N/A char *symlink_buffer = 0;
2N/A grub_uint16_t block_size;
2N/A grub_disk_addr_t block;
2N/A grub_off_t offset;
2N/A grub_size_t len;
2N/A struct grub_fshelp_node found;
2N/A struct grub_reiserfs_key key;
2N/A
2N/A grub_memcpy (&key, &(node->header.key), sizeof (key));
2N/A grub_reiserfs_set_key_offset (&key, 1);
2N/A grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECT,
2N/A grub_reiserfs_get_key_version (&key));
2N/A
2N/A if (grub_reiserfs_get_item (node->data, &key, &found) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A
2N/A if (found.block_number == 0)
2N/A goto fail;
2N/A
2N/A block_size = grub_le_to_cpu16 (node->data->superblock.block_size);
2N/A len = grub_le_to_cpu16 (found.header.item_size);
2N/A block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
2N/A offset = grub_le_to_cpu16 (found.header.item_location);
2N/A
2N/A symlink_buffer = grub_malloc (len + 1);
2N/A if (! symlink_buffer)
2N/A goto fail;
2N/A
2N/A grub_disk_read (node->data->disk, block, offset, len, symlink_buffer);
2N/A if (grub_errno)
2N/A goto fail;
2N/A
2N/A symlink_buffer[len] = 0;
2N/A return symlink_buffer;
2N/A
2N/A fail:
2N/A grub_free (symlink_buffer);
2N/A return 0;
2N/A}
2N/A
2N/A/* Fill the mounted filesystem structure and return it. */
2N/Astatic struct grub_reiserfs_data *
2N/Agrub_reiserfs_mount (grub_disk_t disk)
2N/A{
2N/A struct grub_reiserfs_data *data = 0;
2N/A data = grub_malloc (sizeof (*data));
2N/A if (! data)
2N/A goto fail;
2N/A grub_disk_read (disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE,
2N/A 0, sizeof (data->superblock), &(data->superblock));
2N/A if (grub_errno)
2N/A goto fail;
2N/A if (grub_memcmp (data->superblock.magic_string,
2N/A REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1))
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem");
2N/A goto fail;
2N/A }
2N/A data->disk = disk;
2N/A return data;
2N/A
2N/A fail:
2N/A /* Disk is too small to contain a ReiserFS. */
2N/A if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
2N/A grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem");
2N/A
2N/A grub_free (data);
2N/A return 0;
2N/A}
2N/A
2N/A/* Call HOOK for each file in directory ITEM. */
2N/Astatic int
2N/Agrub_reiserfs_iterate_dir (grub_fshelp_node_t item,
2N/A int NESTED_FUNC_ATTR
2N/A (*hook) (const char *filename,
2N/A enum grub_fshelp_filetype filetype,
2N/A grub_fshelp_node_t node))
2N/A{
2N/A struct grub_reiserfs_data *data = item->data;
2N/A struct grub_reiserfs_block_header *block_header = 0;
2N/A grub_uint16_t block_size, block_position;
2N/A grub_uint32_t block_number;
2N/A grub_uint64_t next_offset = item->next_offset;
2N/A int ret = 0;
2N/A
2N/A if (item->type != GRUB_REISERFS_DIRECTORY)
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FILE_TYPE,
2N/A "grub_reiserfs_iterate_dir called on a non-directory item");
2N/A goto fail;
2N/A }
2N/A block_size = grub_le_to_cpu16 (data->superblock.block_size);
2N/A block_header = grub_malloc (block_size);
2N/A if (! block_header)
2N/A goto fail;
2N/A block_number = item->block_number;
2N/A block_position = item->block_position;
2N/A grub_dprintf ("reiserfs", "Iterating directory...\n");
2N/A do
2N/A {
2N/A struct grub_reiserfs_directory_header *directory_headers;
2N/A struct grub_fshelp_node directory_item;
2N/A grub_uint16_t entry_count, entry_number;
2N/A struct grub_reiserfs_item_header *item_headers;
2N/A
2N/A grub_disk_read (data->disk,
2N/A block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A (((grub_off_t) block_number * block_size)
2N/A & (GRUB_DISK_SECTOR_SIZE - 1)),
2N/A block_size, (char *) block_header);
2N/A if (grub_errno)
2N/A goto fail;
2N/A
2N/A#if 0
2N/A if (grub_le_to_cpu16 (block_header->level) != 1)
2N/A {
2N/A grub_error (GRUB_ERR_TEST_FAILURE,
2N/A "reiserfs: block %d is not a leaf block",
2N/A block_number);
2N/A goto fail;
2N/A }
2N/A#endif
2N/A
2N/A item_headers = (struct grub_reiserfs_item_header *) (block_header + 1);
2N/A directory_headers
2N/A = ((struct grub_reiserfs_directory_header *)
2N/A ((char *) block_header
2N/A + grub_le_to_cpu16 (item_headers[block_position].item_location)));
2N/A entry_count
2N/A = grub_le_to_cpu16 (item_headers[block_position].u.entry_count);
2N/A for (entry_number = 0; entry_number < entry_count; entry_number++)
2N/A {
2N/A struct grub_reiserfs_directory_header *directory_header
2N/A = &directory_headers[entry_number];
2N/A grub_uint16_t entry_state
2N/A = grub_le_to_cpu16 (directory_header->state);
2N/A
2N/A if (entry_state & GRUB_REISERFS_VISIBLE_MASK)
2N/A {
2N/A grub_fshelp_node_t entry_item;
2N/A struct grub_reiserfs_key entry_key;
2N/A enum grub_reiserfs_item_type entry_type;
2N/A char *entry_name;
2N/A
2N/A entry_name = (((char *) directory_headers)
2N/A + grub_le_to_cpu16 (directory_header->location));
2N/A entry_key.directory_id = directory_header->directory_id;
2N/A entry_key.object_id = directory_header->object_id;
2N/A entry_key.u.v2.offset_type = 0;
2N/A grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_DIRECTORY,
2N/A 2);
2N/A grub_reiserfs_set_key_offset (&entry_key, 1);
2N/A
2N/A entry_item = grub_malloc (sizeof (*entry_item));
2N/A if (! entry_item)
2N/A goto fail;
2N/A
2N/A if (grub_reiserfs_get_item (data, &entry_key, entry_item)
2N/A != GRUB_ERR_NONE)
2N/A {
2N/A grub_free (entry_item);
2N/A goto fail;
2N/A }
2N/A
2N/A if (entry_item->type == GRUB_REISERFS_DIRECTORY)
2N/A entry_type = GRUB_FSHELP_DIR;
2N/A else
2N/A {
2N/A grub_uint32_t entry_block_number;
2N/A /* Order is very important here.
2N/A First set the offset to 0 using current key version.
2N/A Then change the key type, which affects key version
2N/A detection. */
2N/A grub_reiserfs_set_key_offset (&entry_key, 0);
2N/A grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_STAT,
2N/A 2);
2N/A if (grub_reiserfs_get_item (data, &entry_key, entry_item)
2N/A != GRUB_ERR_NONE)
2N/A {
2N/A grub_free (entry_item);
2N/A goto fail;
2N/A }
2N/A
2N/A if (entry_item->block_number != 0)
2N/A {
2N/A grub_uint16_t entry_version;
2N/A entry_version
2N/A = grub_le_to_cpu16 (entry_item->header.version);
2N/A entry_block_number = entry_item->block_number;
2N/A#if 0
2N/A grub_dprintf ("reiserfs",
2N/A "version %04x block %08x (%08x) position %08x\n",
2N/A entry_version, entry_block_number,
2N/A ((grub_disk_addr_t) entry_block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
2N/A grub_le_to_cpu16 (entry_item->header.item_location));
2N/A#endif
2N/A if (entry_version == 0) /* Version 1 stat item. */
2N/A {
2N/A struct grub_reiserfs_stat_item_v1 entry_v1_stat;
2N/A grub_disk_read (data->disk,
2N/A entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A grub_le_to_cpu16 (entry_item->header.item_location),
2N/A sizeof (entry_v1_stat),
2N/A (char *) &entry_v1_stat);
2N/A if (grub_errno)
2N/A goto fail;
2N/A#if 0
2N/A grub_dprintf ("reiserfs",
2N/A "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
2N/A grub_le_to_cpu16 (entry_v1_stat.mode),
2N/A grub_le_to_cpu16 (entry_v1_stat.hardlink_count),
2N/A grub_le_to_cpu16 (entry_v1_stat.uid),
2N/A grub_le_to_cpu16 (entry_v1_stat.gid),
2N/A grub_le_to_cpu32 (entry_v1_stat.size),
2N/A grub_le_to_cpu32 (entry_v1_stat.atime),
2N/A grub_le_to_cpu32 (entry_v1_stat.mtime),
2N/A grub_le_to_cpu32 (entry_v1_stat.ctime),
2N/A grub_le_to_cpu32 (entry_v1_stat.rdev),
2N/A grub_le_to_cpu32 (entry_v1_stat.first_direct_byte));
2N/A grub_dprintf ("reiserfs",
2N/A "%04x %04x %04x %04x %08x %08x | %08x %08x %08x %08x\n",
2N/A entry_v1_stat.mode,
2N/A entry_v1_stat.hardlink_count,
2N/A entry_v1_stat.uid,
2N/A entry_v1_stat.gid,
2N/A entry_v1_stat.size,
2N/A entry_v1_stat.atime,
2N/A entry_v1_stat.mtime,
2N/A entry_v1_stat.ctime,
2N/A entry_v1_stat.rdev,
2N/A entry_v1_stat.first_direct_byte);
2N/A#endif
2N/A entry_item->mtime = grub_le_to_cpu32 (entry_v1_stat.mtime);
2N/A if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK)
2N/A == S_IFLNK)
2N/A entry_type = GRUB_FSHELP_SYMLINK;
2N/A else
2N/A entry_type = GRUB_FSHELP_REG;
2N/A }
2N/A else
2N/A {
2N/A struct grub_reiserfs_stat_item_v2 entry_v2_stat;
2N/A grub_disk_read (data->disk,
2N/A entry_block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A grub_le_to_cpu16 (entry_item->header.item_location),
2N/A sizeof (entry_v2_stat),
2N/A (char *) &entry_v2_stat);
2N/A if (grub_errno)
2N/A goto fail;
2N/A#if 0
2N/A grub_dprintf ("reiserfs",
2N/A "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
2N/A grub_le_to_cpu16 (entry_v2_stat.mode),
2N/A grub_le_to_cpu16 (entry_v2_stat.reserved),
2N/A grub_le_to_cpu32 (entry_v2_stat.hardlink_count),
2N/A (unsigned int) (grub_le_to_cpu64 (entry_v2_stat.size) >> 32),
2N/A (unsigned int) (grub_le_to_cpu64 (entry_v2_stat.size) && 0xFFFFFFFF),
2N/A grub_le_to_cpu32 (entry_v2_stat.uid),
2N/A grub_le_to_cpu32 (entry_v2_stat.gid),
2N/A grub_le_to_cpu32 (entry_v2_stat.atime),
2N/A grub_le_to_cpu32 (entry_v2_stat.mtime),
2N/A grub_le_to_cpu32 (entry_v2_stat.ctime),
2N/A grub_le_to_cpu32 (entry_v2_stat.blocks),
2N/A grub_le_to_cpu32 (entry_v2_stat.first_direct_byte));
2N/A grub_dprintf ("reiserfs",
2N/A "%04x %04x %08x %08x%08x | %08x %08x %08x %08x | %08x %08x %08x\n",
2N/A entry_v2_stat.mode,
2N/A entry_v2_stat.reserved,
2N/A entry_v2_stat.hardlink_count,
2N/A (unsigned int) (entry_v2_stat.size >> 32),
2N/A (unsigned int) (entry_v2_stat.size && 0xFFFFFFFF),
2N/A entry_v2_stat.uid,
2N/A entry_v2_stat.gid,
2N/A entry_v2_stat.atime,
2N/A entry_v2_stat.mtime,
2N/A entry_v2_stat.ctime,
2N/A entry_v2_stat.blocks,
2N/A entry_v2_stat.first_direct_byte);
2N/A#endif
2N/A entry_item->mtime = grub_le_to_cpu32 (entry_v2_stat.mtime);
2N/A if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
2N/A == S_IFLNK)
2N/A entry_type = GRUB_FSHELP_SYMLINK;
2N/A else
2N/A entry_type = GRUB_FSHELP_REG;
2N/A }
2N/A }
2N/A else
2N/A {
2N/A /* Pseudo file ".." never has stat block. */
2N/A if (grub_strcmp (entry_name, ".."))
2N/A grub_dprintf ("reiserfs",
2N/A "Warning : %s has no stat block !\n",
2N/A entry_name);
2N/A grub_free (entry_item);
2N/A goto next;
2N/A }
2N/A }
2N/A if (hook (entry_name, entry_type, entry_item))
2N/A {
2N/A grub_dprintf ("reiserfs", "Found : %s, type=%d\n",
2N/A entry_name, entry_type);
2N/A ret = 1;
2N/A goto found;
2N/A }
2N/A
2N/Anext:
2N/A *entry_name = 0; /* Make sure next entry name (which is just
2N/A before this one in disk order) stops before
2N/A the current one. */
2N/A }
2N/A }
2N/A
2N/A if (next_offset == 0)
2N/A break;
2N/A
2N/A grub_reiserfs_set_key_offset (&(item_headers[block_position].key),
2N/A next_offset);
2N/A if (grub_reiserfs_get_item (data, &(item_headers[block_position].key),
2N/A &directory_item) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A block_number = directory_item.block_number;
2N/A block_position = directory_item.block_position;
2N/A next_offset = directory_item.next_offset;
2N/A }
2N/A while (block_number);
2N/A
2N/A found:
2N/A assert (grub_errno == GRUB_ERR_NONE);
2N/A grub_free (block_header);
2N/A return ret;
2N/A fail:
2N/A assert (grub_errno != GRUB_ERR_NONE);
2N/A grub_free (block_header);
2N/A return 0;
2N/A}
2N/A
2N/A/****************************************************************************/
2N/A/* grub api functions */
2N/A/****************************************************************************/
2N/A
2N/A/* Open a file named NAME and initialize FILE. */
2N/Astatic grub_err_t
2N/Agrub_reiserfs_open (struct grub_file *file, const char *name)
2N/A{
2N/A struct grub_reiserfs_data *data = 0;
2N/A struct grub_fshelp_node root, *found = 0, info;
2N/A struct grub_reiserfs_key key;
2N/A grub_uint32_t block_number;
2N/A grub_uint16_t entry_version, block_size, entry_location;
2N/A
2N/A grub_dl_ref (my_mod);
2N/A data = grub_reiserfs_mount (file->device->disk);
2N/A if (! data)
2N/A goto fail;
2N/A block_size = grub_le_to_cpu16 (data->superblock.block_size);
2N/A key.directory_id = grub_cpu_to_le32 (1);
2N/A key.object_id = grub_cpu_to_le32 (2);
2N/A key.u.v2.offset_type = 0;
2N/A grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECTORY, 2);
2N/A grub_reiserfs_set_key_offset (&key, 1);
2N/A if (grub_reiserfs_get_item (data, &key, &root) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A if (root.block_number == 0)
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FS, "unable to find root item");
2N/A goto fail; /* Should never happen since checked at mount. */
2N/A }
2N/A grub_fshelp_find_file (name, &root, &found,
2N/A grub_reiserfs_iterate_dir,
2N/A grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
2N/A if (grub_errno)
2N/A goto fail;
2N/A key.directory_id = found->header.key.directory_id;
2N/A key.object_id = found->header.key.object_id;
2N/A grub_reiserfs_set_key_type (&key, GRUB_REISERFS_STAT, 2);
2N/A grub_reiserfs_set_key_offset (&key, 0);
2N/A if (grub_reiserfs_get_item (data, &key, &info) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A if (info.block_number == 0)
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FS, "unable to find searched item");
2N/A goto fail;
2N/A }
2N/A entry_version = grub_le_to_cpu16 (info.header.version);
2N/A entry_location = grub_le_to_cpu16 (info.header.item_location);
2N/A block_number = info.block_number;
2N/A if (entry_version == 0) /* Version 1 stat item. */
2N/A {
2N/A struct grub_reiserfs_stat_item_v1 entry_v1_stat;
2N/A grub_disk_read (data->disk,
2N/A block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A entry_location
2N/A + (((grub_off_t) block_number * block_size)
2N/A & (GRUB_DISK_SECTOR_SIZE - 1)),
2N/A sizeof (entry_v1_stat), &entry_v1_stat);
2N/A if (grub_errno)
2N/A goto fail;
2N/A file->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
2N/A }
2N/A else
2N/A {
2N/A struct grub_reiserfs_stat_item_v2 entry_v2_stat;
2N/A grub_disk_read (data->disk,
2N/A block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A entry_location
2N/A + (((grub_off_t) block_number * block_size)
2N/A & (GRUB_DISK_SECTOR_SIZE - 1)),
2N/A sizeof (entry_v2_stat), &entry_v2_stat);
2N/A if (grub_errno)
2N/A goto fail;
2N/A file->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
2N/A }
2N/A grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
2N/A (unsigned int) file->size,
2N/A (unsigned int) (file->size >> 32), (unsigned int) file->size);
2N/A file->offset = 0;
2N/A file->data = found;
2N/A return GRUB_ERR_NONE;
2N/A
2N/A fail:
2N/A assert (grub_errno != GRUB_ERR_NONE);
2N/A grub_free (found);
2N/A grub_free (data);
2N/A grub_dl_unref (my_mod);
2N/A return grub_errno;
2N/A}
2N/A
2N/Astatic grub_ssize_t
2N/Agrub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
2N/A{
2N/A unsigned int indirect_block, indirect_block_count;
2N/A struct grub_reiserfs_key key;
2N/A struct grub_fshelp_node *node = file->data;
2N/A struct grub_reiserfs_data *data = node->data;
2N/A struct grub_fshelp_node found;
2N/A grub_uint16_t block_size = grub_le_to_cpu16 (data->superblock.block_size);
2N/A grub_uint16_t item_size;
2N/A grub_uint32_t *indirect_block_ptr = 0;
2N/A grub_uint64_t current_key_offset = 1;
2N/A grub_off_t initial_position, current_position, final_position, length;
2N/A grub_disk_addr_t block;
2N/A grub_off_t offset;
2N/A
2N/A key.directory_id = node->header.key.directory_id;
2N/A key.object_id = node->header.key.object_id;
2N/A key.u.v2.offset_type = 0;
2N/A grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
2N/A initial_position = file->offset;
2N/A current_position = 0;
2N/A final_position = MIN (len + initial_position, file->size);
2N/A grub_dprintf ("reiserfs",
2N/A "Reading from %lld to %lld (%lld instead of requested %ld)\n",
2N/A (unsigned long long) initial_position,
2N/A (unsigned long long) final_position,
2N/A (unsigned long long) (final_position - initial_position),
2N/A (unsigned long) len);
2N/A while (current_position < final_position)
2N/A {
2N/A grub_reiserfs_set_key_offset (&key, current_key_offset);
2N/A
2N/A if (grub_reiserfs_get_item (data, &key, &found) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A if (found.block_number == 0)
2N/A goto fail;
2N/A item_size = grub_le_to_cpu16 (found.header.item_size);
2N/A switch (found.type)
2N/A {
2N/A case GRUB_REISERFS_DIRECT:
2N/A block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
2N/A grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
2N/A if (initial_position < current_position + item_size)
2N/A {
2N/A offset = MAX ((signed) (initial_position - current_position), 0);
2N/A length = (MIN (item_size, final_position - current_position)
2N/A - offset);
2N/A grub_dprintf ("reiserfs",
2N/A "Reading direct block %u from %u to %u...\n",
2N/A (unsigned) block, (unsigned) offset,
2N/A (unsigned) (offset + length));
2N/A found.data->disk->read_hook = file->read_hook;
2N/A grub_disk_read (found.data->disk,
2N/A block,
2N/A offset
2N/A + grub_le_to_cpu16 (found.header.item_location),
2N/A length, buf);
2N/A found.data->disk->read_hook = 0;
2N/A if (grub_errno)
2N/A goto fail;
2N/A buf += length;
2N/A current_position += offset + length;
2N/A }
2N/A else
2N/A current_position += item_size;
2N/A break;
2N/A case GRUB_REISERFS_INDIRECT:
2N/A indirect_block_count = item_size / sizeof (*indirect_block_ptr);
2N/A indirect_block_ptr = grub_malloc (item_size);
2N/A if (! indirect_block_ptr)
2N/A goto fail;
2N/A grub_disk_read (found.data->disk,
2N/A found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
2N/A grub_le_to_cpu16 (found.header.item_location),
2N/A item_size, indirect_block_ptr);
2N/A if (grub_errno)
2N/A goto fail;
2N/A found.data->disk->read_hook = file->read_hook;
2N/A for (indirect_block = 0;
2N/A indirect_block < indirect_block_count
2N/A && current_position < final_position;
2N/A indirect_block++)
2N/A {
2N/A block = grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) *
2N/A (block_size >> GRUB_DISK_SECTOR_BITS);
2N/A grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
2N/A if (current_position + block_size >= initial_position)
2N/A {
2N/A offset = MAX ((signed) (initial_position - current_position),
2N/A 0);
2N/A length = (MIN (block_size, final_position - current_position)
2N/A - offset);
2N/A grub_dprintf ("reiserfs",
2N/A "Reading indirect block %u from %u to %u...\n",
2N/A (unsigned) block, (unsigned) offset,
2N/A (unsigned) (offset + length));
2N/A#if 0
2N/A grub_dprintf ("reiserfs",
2N/A "\nib=%04d/%04d, ip=%d, cp=%d, fp=%d, off=%d, l=%d, tl=%d\n",
2N/A indirect_block + 1, indirect_block_count,
2N/A initial_position, current_position,
2N/A final_position, offset, length, len);
2N/A#endif
2N/A grub_disk_read (found.data->disk, block, offset, length, buf);
2N/A if (grub_errno)
2N/A goto fail;
2N/A buf += length;
2N/A current_position += offset + length;
2N/A }
2N/A else
2N/A current_position += block_size;
2N/A }
2N/A found.data->disk->read_hook = 0;
2N/A grub_free (indirect_block_ptr);
2N/A indirect_block_ptr = 0;
2N/A break;
2N/A default:
2N/A goto fail;
2N/A }
2N/A current_key_offset = current_position + 1;
2N/A }
2N/A
2N/A grub_dprintf ("reiserfs",
2N/A "Have successfully read %lld bytes (%ld requested)\n",
2N/A (unsigned long long) (current_position - initial_position),
2N/A (unsigned long) len);
2N/A return current_position - initial_position;
2N/A
2N/A#if 0
2N/A switch (found.type)
2N/A {
2N/A case GRUB_REISERFS_DIRECT:
2N/A read_length = MIN (len, item_size - file->offset);
2N/A grub_disk_read (found.data->disk,
2N/A (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
2N/A grub_le_to_cpu16 (found.header.item_location) + file->offset,
2N/A read_length, buf);
2N/A if (grub_errno)
2N/A goto fail;
2N/A break;
2N/A case GRUB_REISERFS_INDIRECT:
2N/A indirect_block_count = item_size / sizeof (*indirect_block_ptr);
2N/A indirect_block_ptr = grub_malloc (item_size);
2N/A if (!indirect_block_ptr)
2N/A goto fail;
2N/A grub_disk_read (found.data->disk,
2N/A (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
2N/A grub_le_to_cpu16 (found.header.item_location),
2N/A item_size, (char *) indirect_block_ptr);
2N/A if (grub_errno)
2N/A goto fail;
2N/A len = MIN (len, file->size - file->offset);
2N/A for (indirect_block = file->offset / block_size;
2N/A indirect_block < indirect_block_count && read_length < len;
2N/A indirect_block++)
2N/A {
2N/A read = MIN (block_size, len - read_length);
2N/A grub_disk_read (found.data->disk,
2N/A (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
2N/A file->offset % block_size, read,
2N/A ((void *) buf) + read_length);
2N/A if (grub_errno)
2N/A goto fail;
2N/A read_length += read;
2N/A }
2N/A grub_free (indirect_block_ptr);
2N/A break;
2N/A default:
2N/A goto fail;
2N/A }
2N/A
2N/A return read_length;
2N/A#endif
2N/A
2N/A fail:
2N/A grub_free (indirect_block_ptr);
2N/A return 0;
2N/A}
2N/A
2N/A/* Close the file FILE. */
2N/Astatic grub_err_t
2N/Agrub_reiserfs_close (grub_file_t file)
2N/A{
2N/A struct grub_fshelp_node *node = file->data;
2N/A struct grub_reiserfs_data *data = node->data;
2N/A
2N/A grub_free (data);
2N/A grub_free (node);
2N/A grub_dl_unref (my_mod);
2N/A return GRUB_ERR_NONE;
2N/A}
2N/A
2N/A/* Call HOOK with each file under DIR. */
2N/Astatic grub_err_t
2N/Agrub_reiserfs_dir (grub_device_t device, const char *path,
2N/A int (*hook) (const char *filename,
2N/A const struct grub_dirhook_info *info))
2N/A{
2N/A struct grub_reiserfs_data *data = 0;
2N/A struct grub_fshelp_node root, *found;
2N/A struct grub_reiserfs_key root_key;
2N/A
2N/A auto int NESTED_FUNC_ATTR iterate (const char *filename,
2N/A enum grub_fshelp_filetype filetype,
2N/A grub_fshelp_node_t node);
2N/A
2N/A int NESTED_FUNC_ATTR iterate (const char *filename,
2N/A enum grub_fshelp_filetype filetype,
2N/A grub_fshelp_node_t node)
2N/A {
2N/A struct grub_dirhook_info info;
2N/A grub_memset (&info, 0, sizeof (info));
2N/A info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
2N/A info.mtimeset = 1;
2N/A info.mtime = node->mtime;
2N/A grub_free (node);
2N/A return hook (filename, &info);
2N/A }
2N/A grub_dl_ref (my_mod);
2N/A data = grub_reiserfs_mount (device->disk);
2N/A if (! data)
2N/A goto fail;
2N/A root_key.directory_id = grub_cpu_to_le32 (1);
2N/A root_key.object_id = grub_cpu_to_le32 (2);
2N/A root_key.u.v2.offset_type = 0;
2N/A grub_reiserfs_set_key_type (&root_key, GRUB_REISERFS_DIRECTORY, 2);
2N/A grub_reiserfs_set_key_offset (&root_key, 1);
2N/A if (grub_reiserfs_get_item (data, &root_key, &root) != GRUB_ERR_NONE)
2N/A goto fail;
2N/A if (root.block_number == 0)
2N/A {
2N/A grub_error(GRUB_ERR_BAD_FS, "root not found");
2N/A goto fail;
2N/A }
2N/A grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir,
2N/A grub_reiserfs_read_symlink, GRUB_FSHELP_DIR);
2N/A if (grub_errno)
2N/A goto fail;
2N/A grub_reiserfs_iterate_dir (found, iterate);
2N/A grub_free (data);
2N/A grub_dl_unref (my_mod);
2N/A return GRUB_ERR_NONE;
2N/A
2N/A fail:
2N/A grub_free (data);
2N/A grub_dl_unref (my_mod);
2N/A return grub_errno;
2N/A}
2N/A
2N/A/* Return the label of the device DEVICE in LABEL. The label is
2N/A returned in a grub_malloc'ed buffer and should be freed by the
2N/A caller. */
2N/Astatic grub_err_t
2N/Agrub_reiserfs_label (grub_device_t device, char **label)
2N/A{
2N/A struct grub_reiserfs_data *data;
2N/A grub_disk_t disk = device->disk;
2N/A
2N/A grub_dl_ref (my_mod);
2N/A
2N/A data = grub_reiserfs_mount (disk);
2N/A if (data)
2N/A {
2N/A *label = grub_strndup (data->superblock.label,
2N/A sizeof (data->superblock.label));
2N/A }
2N/A else
2N/A *label = NULL;
2N/A
2N/A grub_dl_unref (my_mod);
2N/A
2N/A grub_free (data);
2N/A
2N/A return grub_errno;
2N/A}
2N/A
2N/Astatic grub_err_t
2N/Agrub_reiserfs_uuid (grub_device_t device, char **uuid)
2N/A{
2N/A struct grub_reiserfs_data *data;
2N/A grub_disk_t disk = device->disk;
2N/A
2N/A grub_dl_ref (my_mod);
2N/A
2N/A *uuid = NULL;
2N/A data = grub_reiserfs_mount (disk);
2N/A if (data)
2N/A {
2N/A unsigned i;
2N/A for (i = 0; i < ARRAY_SIZE (data->superblock.uuid); i++)
2N/A if (data->superblock.uuid[i])
2N/A break;
2N/A if (i < ARRAY_SIZE (data->superblock.uuid))
2N/A *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
2N/A grub_be_to_cpu16 (data->superblock.uuid[0]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[1]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[2]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[3]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[4]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[5]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[6]),
2N/A grub_be_to_cpu16 (data->superblock.uuid[7]));
2N/A }
2N/A
2N/A grub_dl_unref (my_mod);
2N/A
2N/A grub_free (data);
2N/A
2N/A return grub_errno;
2N/A}
2N/A
2N/Astatic struct grub_fs grub_reiserfs_fs =
2N/A {
2N/A .name = "reiserfs",
2N/A .dir = grub_reiserfs_dir,
2N/A .open = grub_reiserfs_open,
2N/A .read = grub_reiserfs_read,
2N/A .close = grub_reiserfs_close,
2N/A .label = grub_reiserfs_label,
2N/A .uuid = grub_reiserfs_uuid,
2N/A .next = 0
2N/A };
2N/A
2N/AGRUB_MOD_INIT(reiserfs)
2N/A{
2N/A grub_fs_register (&grub_reiserfs_fs);
2N/A my_mod = mod;
2N/A}
2N/A
2N/AGRUB_MOD_FINI(reiserfs)
2N/A{
2N/A grub_fs_unregister (&grub_reiserfs_fs);
2N/A}