Some adjustment in this patch: as the get_block function is only used
when journal type is GRUB_FSHELP_JOURNAL_TYPE_FILE, i move it to
grub_fshelp_journal instead of using it as a parameter for
grub_fshelp_map_block. also add changelog for reiserfs.c.
2008-02-18 Bean <[EMAIL PROTECTED]>
* fs/fshelp.c (grub_fshelp_map_block): New function.
* include/grub/fshelp.h (grub_fshelp_journal_type): New enum.
(GRUB_FSHELP_JOURNAL_UNUSED_MAPPING): New macro.
(grub_fshelp_journal): New structure.
(grub_fshelp_map_block): New function prototype.
* fs/ext2.c (EXT3_FEATURE_COMPAT_HAS_JOURNAL): New macro.
(EXT3_JOURNAL_MAGIC_NUMBER): Likewise.
(EXT3_JOURNAL_DESCRIPTOR_BLOCK): Likewise.
(EXT3_JOURNAL_COMMIT_BLOCK): Likewise.
(EXT3_JOURNAL_SUPERBLOCK_V1): Likewise.
(EXT3_JOURNAL_SUPERBLOCK_V2): Likewise.
(EXT3_JOURNAL_REVOKE_BLOCK): Likewise.
(EXT3_JOURNAL_FLAG_ESCAPE): Likewise.
(EXT3_JOURNAL_FLAG_SAME_UUID): Likewise.
(EXT3_JOURNAL_FLAG_DELETED): Likewise.
(EXT3_JOURNAL_FLAG_LAST_TAG): Likewise.
(grub_ext2_sblock): New members for journal support.
(grub_ext3_journal_header): New structure.
(grub_ext3_journal_revoke_header): Likewise.
(grub_ext3_journal_block_tag): Likewise.
(grub_ext3_journal_sblock): Likewise.
(grub_fshelp_node): New members logfile and journal.
(grub_ext2_blockgroup): Use grub_fshelp_map_block to get real block
number.
(grub_ext2_read_block): Likewise.
(grub_ext2_read_inode): Likewise.
(grub_ext3_get_journal): New function.
(grub_read_inode): Initialize journal using grub_ext3_get_journal.
(grub_ext2_close): Release memory used by journal.
* fs/reiserfs.c (REISERFS_MAGIC_STRING): Changed to "ReIsEr".
(REISERFS_MAGIC_DESC_BLOCK): New macro.
(grub_reiserfs_transaction_header): Renamed to
grub_reiserfs_description_block, replace field data with real_blocks.
(grub_reiserfs_commit_block): New structure.
(grub_reiserfs_data): New member journal.
(grub_reiserfs_get_item): Use grub_fshelp_map_block to get real block
number.
(grub_reiserfs_read_symlink): Likewise.
(grub_reiserfs_iterate_dir): Likewise.
(grub_reiserfs_open): Likewise.
(grub_reiserfs_read): Likewise.
(grub_reiserfs_get_journal): New function.
(grub_reiserfs_mount): Use "ReIsEr" as super block magic, as there are
three varieties ReIsErFs, ReIsEr2Fs and ReIsEr3Fs. Initialize journal
using grub_reiserfs_get_journal.
(grub_reiserfs_close): Release memory used by journal.
--
Bean
diff --git a/fs/ext2.c b/fs/ext2.c
index ec66582..5dffd69 100644
--- a/fs/ext2.c
+++ b/fs/ext2.c
@@ -71,6 +71,21 @@
? EXT2_GOOD_OLD_INODE_SIZE \
: grub_le_to_cpu16 (data->sblock.inode_size))
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+
+#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
+
+#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
+#define EXT3_JOURNAL_COMMIT_BLOCK 2
+#define EXT3_JOURNAL_SUPERBLOCK_V1 3
+#define EXT3_JOURNAL_SUPERBLOCK_V2 4
+#define EXT3_JOURNAL_REVOKE_BLOCK 5
+
+#define EXT3_JOURNAL_FLAG_ESCAPE 1
+#define EXT3_JOURNAL_FLAG_SAME_UUID 2
+#define EXT3_JOURNAL_FLAG_DELETED 4
+#define EXT3_JOURNAL_FLAG_LAST_TAG 8
+
/* The ext2 superblock. */
struct grub_ext2_sblock
{
@@ -109,6 +124,21 @@ struct grub_ext2_sblock
char volume_name[16];
char last_mounted_on[64];
grub_uint32_t compression_info;
+ grub_uint8_t prealloc_blocks;
+ grub_uint8_t prealloc_dir_blocks;
+ grub_uint16_t reserved_gdt_blocks;
+ grub_uint8_t journal_uuid[16];
+ grub_uint32_t journal_inum;
+ grub_uint32_t journal_dev;
+ grub_uint32_t last_orphan;
+ grub_uint32_t hash_seed[4];
+ grub_uint8_t def_hash_version;
+ grub_uint8_t jnl_backup_type;
+ grub_uint16_t reserved_word_pad;
+ grub_uint32_t default_mount_opts;
+ grub_uint32_t first_meta_bg;
+ grub_uint32_t mkfs_time;
+ grub_uint32_t jnl_blocks[17];
};
/* The ext2 blockgroup. */
@@ -166,6 +196,36 @@ struct ext2_dirent
grub_uint8_t filetype;
};
+struct grub_ext3_journal_header
+{
+ grub_uint32_t magic;
+ grub_uint32_t block_type;
+ grub_uint32_t sequence;
+};
+
+struct grub_ext3_journal_revoke_header
+{
+ struct grub_ext3_journal_header header;
+ grub_uint32_t count;
+ grub_uint32_t data[0];
+};
+
+struct grub_ext3_journal_block_tag
+{
+ grub_uint32_t block;
+ grub_uint32_t flags;
+};
+
+struct grub_ext3_journal_sblock
+{
+ struct grub_ext3_journal_header header;
+ grub_uint32_t block_size;
+ grub_uint32_t maxlen;
+ grub_uint32_t first;
+ grub_uint32_t sequence;
+ grub_uint32_t start;
+};
+
struct grub_fshelp_node
{
struct grub_ext2_data *data;
@@ -181,6 +241,8 @@ struct grub_ext2_data
grub_disk_t disk;
struct grub_ext2_inode *inode;
struct grub_fshelp_node diropen;
+ struct grub_fshelp_node logfile;
+ grub_fshelp_journal_t journal;
};
#ifndef GRUB_UTIL
@@ -196,7 +258,8 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int
group,
struct grub_ext2_block_group *blkgrp)
{
return grub_disk_read (data->disk,
- ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
+ (grub_fshelp_map_block (data->journal,
+ grub_le_to_cpu32
(data->sblock.first_data_block) + 1)
<< LOG2_EXT2_BLOCK_SIZE (data)),
group * sizeof (struct grub_ext2_block_group),
sizeof (struct grub_ext2_block_group), (char *)
blkgrp);
@@ -221,7 +284,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, int
fileblock)
grub_uint32_t indir[blksz / 4];
if (grub_disk_read (data->disk,
- grub_le_to_cpu32 (inode->blocks.indir_block)
+ grub_fshelp_map_block(data->journal,
+ grub_le_to_cpu32
(inode->blocks.indir_block))
<< log2_blksz,
0, blksz, (char *) indir))
return grub_errno;
@@ -237,13 +301,15 @@ grub_ext2_read_block (grub_fshelp_node_t node, int
fileblock)
grub_uint32_t indir[blksz / 4];
if (grub_disk_read (data->disk,
- grub_le_to_cpu32 (inode->blocks.double_indir_block)
+ grub_fshelp_map_block(data->journal,
+ grub_le_to_cpu32
(inode->blocks.double_indir_block))
<< log2_blksz,
0, blksz, (char *) indir))
return grub_errno;
if (grub_disk_read (data->disk,
- grub_le_to_cpu32 (indir[rblock / perblock])
+ grub_fshelp_map_block(data->journal,
+ grub_le_to_cpu32 (indir[rblock
/ perblock]))
<< log2_blksz,
0, blksz, (char *) indir))
return grub_errno;
@@ -259,10 +325,9 @@ grub_ext2_read_block (grub_fshelp_node_t node, int
fileblock)
blknr = -1;
}
- return blknr;
+ return grub_fshelp_map_block (data->journal, blknr);
}
-
/* Read LEN bytes from the file described by DATA starting with byte
POS. Return the amount of read bytes in READ. */
static grub_ssize_t
@@ -308,8 +373,9 @@ grub_ext2_read_inode (struct grub_ext2_data *data,
/* Read the inode. */
if (grub_disk_read (data->disk,
- ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
- << LOG2_EXT2_BLOCK_SIZE (data)),
+ grub_fshelp_map_block(data->journal,
+ grub_le_to_cpu32
(blkgrp.inode_table_id) + blkno)
+ << LOG2_EXT2_BLOCK_SIZE (data),
EXT2_INODE_SIZE (data) * blkoff,
sizeof (struct grub_ext2_inode), (char *) inode))
return grub_errno;
@@ -317,6 +383,164 @@ grub_ext2_read_inode (struct grub_ext2_data *data,
return 0;
}
+static void
+grub_ext3_get_journal (struct grub_ext2_data *data)
+{
+ char buf[1 << LOG2_BLOCK_SIZE (data)];
+ struct grub_ext3_journal_sblock *jsb;
+ grub_fshelp_journal_t log;
+ int last_num, num, block, log2bs;
+ grub_uint32_t seq;
+
+ auto void next_block (void);
+ void next_block (void)
+ {
+ block++;
+ if (block >= log->last_block)
+ block = log->first_block;
+ }
+
+ data->journal = 0;
+
+ if (! (data->sblock.feature_compatibility & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ return;
+
+ if (! data->sblock.journal_inum)
+ return;
+
+ data->logfile.data = data;
+ data->logfile.ino = data->sblock.journal_inum;
+ data->logfile.inode_read = 1;
+
+ if (grub_ext2_read_inode (data, data->logfile.ino, &data->logfile.inode))
+ return;
+
+ log2bs = LOG2_EXT2_BLOCK_SIZE (data);
+ if (grub_fshelp_read_file (data->disk, &data->logfile, 0,
+ 0, sizeof (struct grub_ext3_journal_sblock),
+ buf, grub_ext2_read_block,
+ sizeof (buf), log2bs) !=
+ sizeof (struct grub_ext3_journal_sblock))
+ return;
+
+ jsb = (struct grub_ext3_journal_sblock *) &buf[0];
+ if (grub_be_to_cpu32 (jsb->header.magic) != EXT3_JOURNAL_MAGIC_NUMBER)
+ return;
+
+ /* Empty journal. */
+ if (! jsb->start)
+ return;
+
+ log = grub_malloc (sizeof (struct grub_fshelp_journal) +
+ grub_be_to_cpu32 (jsb->maxlen) * sizeof (grub_uint32_t));
+ if (! log)
+ return;
+
+ log->type = GRUB_FSHELP_JOURNAL_TYPE_FILE;
+ log->node = &data->logfile;
+ log->get_block = grub_ext2_read_block;
+ log->first_block = grub_be_to_cpu32 (jsb->first);
+ log->last_block = grub_be_to_cpu32 (jsb->maxlen);
+ log->start_block = grub_be_to_cpu32 (jsb->start);
+
+ last_num = num = 0;
+ block = log->start_block;
+ seq = grub_be_to_cpu32 (jsb->sequence);
+
+ while (1)
+ {
+ struct grub_ext3_journal_header *jh;
+
+ if (grub_fshelp_read_file (data->disk, &data->logfile, 0,
+ block << (log2bs + 9), sizeof (buf),
+ buf, grub_ext2_read_block,
+ log->last_block << (log2bs + 9),
+ log2bs) !=
+ (int) sizeof (buf))
+ break;
+
+ jh = (struct grub_ext3_journal_header *) &buf[0];
+ if (grub_be_to_cpu32 (jh->magic) != EXT3_JOURNAL_MAGIC_NUMBER)
+ break;
+
+ if (grub_be_to_cpu32 (jh->sequence) != seq)
+ break;
+
+ log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
+ next_block();
+
+ switch (grub_be_to_cpu32 (jh->block_type))
+ {
+ case EXT3_JOURNAL_DESCRIPTOR_BLOCK:
+ {
+ struct grub_ext3_journal_block_tag *tag;
+ int ofs, flags;
+
+ ofs = sizeof (struct grub_ext3_journal_header);
+
+ do
+ {
+ tag = (struct grub_ext3_journal_block_tag *) &buf[ofs];
+ ofs += sizeof (struct grub_ext3_journal_block_tag);
+
+ if (ofs > (int) sizeof (buf))
+ break;
+
+ flags = grub_be_to_cpu32 (tag->flags);
+ if (! (flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+ ofs += 16;
+
+ log->mapping[num++] = grub_be_to_cpu32 (tag->block);
+ next_block();
+ }
+ while (! (flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+
+ continue;
+ }
+
+ case EXT3_JOURNAL_COMMIT_BLOCK:
+ {
+ seq++;
+ last_num = num - 1;
+ continue;
+ }
+
+ case EXT3_JOURNAL_REVOKE_BLOCK:
+ {
+ struct grub_ext3_journal_revoke_header *jrh;
+ grub_uint32_t i;
+
+ jrh = (struct grub_ext3_journal_revoke_header *) jh;
+
+ for (i = 0; i < grub_be_to_cpu32 (jrh->count); i++)
+ {
+ int j;
+ grub_uint32_t map;
+
+ map = grub_be_to_cpu32 (jrh->data[i]);
+ for (j = 0; j < num; j++)
+ if (log->mapping[j] == map)
+ log->mapping[j] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
+ }
+
+ continue;
+ }
+ default:
+ last_num = 0;
+ goto quit;
+ }
+ }
+
+quit:
+ if (! last_num)
+ grub_free (log);
+ else
+ {
+ log->num_mappings = last_num;
+ data->journal = log;
+ }
+}
+
static struct grub_ext2_data *
grub_ext2_mount (grub_disk_t disk)
{
@@ -336,12 +560,14 @@ grub_ext2_mount (grub_disk_t disk)
if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC)
goto fail;
+ data->disk = disk;
+ grub_ext3_get_journal (data);
+
data->diropen.data = data;
data->diropen.ino = 2;
data->diropen.inode_read = 1;
data->inode = &data->diropen.inode;
- data->disk = disk;
grub_ext2_read_inode (data, 2, data->inode);
if (grub_errno)
@@ -540,7 +766,11 @@ grub_ext2_open (struct grub_file *file, const char *name)
static grub_err_t
grub_ext2_close (grub_file_t file)
{
- grub_free (file->data);
+ if (file->data)
+ {
+ grub_free (((struct grub_ext2_data *) file->data)->journal);
+ grub_free (file->data);
+ }
#ifndef GRUB_UTIL
grub_dl_unref (my_mod);
diff --git a/fs/fshelp.c b/fs/fshelp.c
index bbb58ac..d3c2423 100644
--- a/fs/fshelp.c
+++ b/fs/fshelp.c
@@ -72,7 +72,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t
rootnode,
void free_node (grub_fshelp_node_t node)
{
- if (node != rootnode && node != currroot)
+ if (node != rootnode && node != currroot)
grub_free (node);
}
@@ -310,3 +310,30 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned
int *pow)
return GRUB_ERR_NONE;
}
+
+int
+grub_fshelp_map_block (grub_fshelp_journal_t log, int block)
+{
+ int map_block;
+
+ if ((! log) || (log->type == GRUB_FSHELP_JOURNAL_TYPE_NONE))
+ return block;
+
+ for (map_block = log->num_mappings - 1; map_block >= 0; map_block--)
+ {
+ if ((int) log->mapping[map_block] == block)
+ break;
+ }
+
+ if (map_block < 0)
+ return block;
+
+ map_block += log->start_block;
+ if (map_block >= log->last_block)
+ map_block -= log->last_block - log->first_block;
+
+ if (log->type == GRUB_FSHELP_JOURNAL_TYPE_BLOCK)
+ return log->blkno + map_block;
+ else
+ return log->get_block (log->node, map_block);
+}
diff --git a/fs/reiserfs.c b/fs/reiserfs.c
index a4c60ca..79e559a 100644
--- a/fs/reiserfs.c
+++ b/fs/reiserfs.c
@@ -52,7 +52,8 @@
#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
#define REISERFS_MAGIC_LEN 12
-#define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0"
+#define REISERFS_MAGIC_STRING "ReIsEr"
+#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB"
/* If the 3rd bit of an item state is set, then it's visible. */
#define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04)
#define REISERFS_MAX_LABEL_LENGTH 16
@@ -109,8 +110,6 @@ struct grub_reiserfs_superblock
grub_uint32_t inode_generation;
} __attribute__ ((packed));
-#ifdef GRUB_REISERFS_JOURNALING
-# error "Journaling not yet supported."
struct grub_reiserfs_journal_header
{
grub_uint32_t last_flush_uid;
@@ -118,15 +117,20 @@ struct grub_reiserfs_journal_header
grub_uint32_t mount_id;
} __attribute__ ((packed));
-struct grub_reiserfs_transaction_header
+struct grub_reiserfs_description_block
{
grub_uint32_t id;
grub_uint32_t len;
grub_uint32_t mount_id;
- char *data;
- char checksum[12];
+ grub_uint32_t real_blocks[0];
+} __attribute__ ((packed));
+
+struct grub_reiserfs_commit_block
+{
+ grub_uint32_t id;
+ grub_uint32_t len;
+ grub_uint32_t real_blocks[0];
} __attribute__ ((packed));
-#endif
struct grub_reiserfs_stat_item_v1
{
@@ -228,6 +232,7 @@ struct grub_reiserfs_data
{
struct grub_reiserfs_superblock superblock;
grub_disk_t disk;
+ grub_fshelp_journal_t journal;
};
/* Internal-only functions. Not to be used outside of this file. */
@@ -504,8 +509,8 @@ grub_reiserfs_get_item (struct grub_reiserfs_data *data,
do
{
grub_disk_read (data->disk,
- (((grub_disk_addr_t) block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS),
+ grub_fshelp_map_block (data->journal, block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS),
(((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
block_size, (char *) block_header);
@@ -655,8 +660,8 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node)
block_size = grub_le_to_cpu16 (node->data->superblock.block_size);
len = grub_le_to_cpu16 (found.header.item_size);
- block = (((grub_disk_addr_t) found.block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS);
+ block = (grub_fshelp_map_block (node->data->journal, found.block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS));
offset = grub_le_to_cpu16 (found.header.item_location);
symlink_buffer = grub_malloc (len);
@@ -674,6 +679,115 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node)
return 0;
}
+static void
+grub_reiserfs_get_journal (struct grub_reiserfs_data *data)
+{
+ int block_size = grub_le_to_cpu16 (data->superblock.block_size);
+ char buf[block_size];
+ struct grub_reiserfs_journal_header *jh;
+ grub_fshelp_journal_t log;
+ grub_uint32_t seq_id, mount_id;
+ int num_blocks = grub_le_to_cpu32 (data->superblock.journal_original_size);
+ int base_block = grub_le_to_cpu32 (data->superblock.journal_block);
+ int last_num, num, block;
+
+ data->journal = 0;
+
+ if (! data->superblock.journal_block)
+ return;
+
+ if (grub_disk_read (data->disk,
+ (base_block + num_blocks)
+ * (block_size >> GRUB_DISK_SECTOR_BITS),
+ 0, sizeof (struct grub_reiserfs_journal_header),
+ buf))
+ return;
+
+ log = grub_malloc (sizeof (struct grub_fshelp_journal) +
+ num_blocks * sizeof (grub_uint32_t));
+ if (! log)
+ return;
+
+ jh = (struct grub_reiserfs_journal_header *) &buf[0];
+
+ log->type = GRUB_FSHELP_JOURNAL_TYPE_BLOCK;
+ log->blkno = base_block;
+ log->first_block = 0;
+ log->last_block = num_blocks;
+ log->start_block = grub_le_to_cpu32 (jh->unflushed_offset);
+
+ seq_id = grub_le_to_cpu32 (jh->last_flush_uid);
+ mount_id = grub_le_to_cpu32 (jh->mount_id);
+
+ last_num = num = 0;
+ block = log->start_block;
+
+ while (1)
+ {
+ struct grub_reiserfs_description_block *db;
+ struct grub_reiserfs_commit_block *cb;
+ grub_uint32_t i, len, half_len, id;
+
+ if (grub_disk_read (data->disk,
+ (base_block + block)
+ * (block_size >> GRUB_DISK_SECTOR_BITS),
+ 0, sizeof (buf), buf))
+ break;
+
+ if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN],
+ REISERFS_MAGIC_DESC_BLOCK,
+ sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1))
+ break;
+
+ db = (struct grub_reiserfs_description_block *) &buf[0];
+ id = grub_le_to_cpu32 (db->id);
+ len = grub_le_to_cpu32 (db->len);
+ if ((grub_le_to_cpu32 (db->id) <= seq_id) && (id <= mount_id))
+ break;
+
+ log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
+ half_len = ((block_size - 24) >> 2);
+ if (half_len > len)
+ half_len = len;
+
+ for (i = 0; i < half_len; i++)
+ log->mapping[num++] = db->real_blocks[i];
+
+ block += grub_le_to_cpu32 (db->len) + 1;
+ if (block >= log->last_block)
+ block -= log->last_block;
+
+ if (grub_disk_read (data->disk,
+ (base_block + block)
+ * (block_size >> GRUB_DISK_SECTOR_BITS),
+ 0, sizeof (buf), buf))
+ break;
+
+ cb = (struct grub_reiserfs_commit_block *) &buf[0];
+ if ((grub_le_to_cpu32 (cb->id) != id) ||
+ (grub_le_to_cpu32 (cb->len) != len))
+ break;
+
+ for (i = 0; i < len - half_len; i++)
+ log->mapping[num++] = cb->real_blocks[i];
+
+ last_num = num;
+ log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING;
+
+ block++;
+ if (block >= log->last_block)
+ block -= log->last_block;
+ };
+
+ if (! last_num)
+ grub_free (log);
+ else
+ {
+ log->num_mappings = last_num;
+ data->journal = log;
+ }
+}
+
/* Fill the mounted filesystem structure and return it. */
static struct grub_reiserfs_data *
grub_reiserfs_mount (grub_disk_t disk)
@@ -687,12 +801,13 @@ grub_reiserfs_mount (grub_disk_t disk)
if (grub_errno)
goto fail;
if (grub_memcmp (data->superblock.magic_string,
- REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN))
+ REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1))
{
grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem");
goto fail;
}
data->disk = disk;
+ grub_reiserfs_get_journal (data);
return data;
fail:
@@ -740,8 +855,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
struct grub_reiserfs_item_header *item_headers;
grub_disk_read (data->disk,
- (((grub_disk_addr_t) block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS),
+ grub_fshelp_map_block (data->journal, block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS),
(((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
block_size, (char *) block_header);
@@ -835,7 +950,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
{
struct grub_reiserfs_stat_item_v1 entry_v1_stat;
grub_disk_read (data->disk,
- ((grub_disk_addr_t)
entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS,
+ grub_fshelp_map_block
(data->journal, entry_block_number) *
+ (block_size >>
GRUB_DISK_SECTOR_BITS),
grub_le_to_cpu16
(entry_item->header.item_location),
sizeof (entry_v1_stat),
(char *) &entry_v1_stat);
@@ -877,7 +993,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
{
struct grub_reiserfs_stat_item_v2 entry_v2_stat;
grub_disk_read (data->disk,
- ((grub_disk_addr_t)
entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS,
+ grub_fshelp_map_block
(data->journal, entry_block_number) *
+ (block_size >>
GRUB_DISK_SECTOR_BITS),
grub_le_to_cpu16
(entry_item->header.item_location),
sizeof (entry_v2_stat),
(char *) &entry_v2_stat);
@@ -1025,8 +1142,8 @@ grub_reiserfs_open (struct grub_file *file, const char
*name)
{
struct grub_reiserfs_stat_item_v1 entry_v1_stat;
grub_disk_read (data->disk,
- (((grub_disk_addr_t) block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS),
+ grub_fshelp_map_block (data->journal, block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS),
entry_location
+ (((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
@@ -1039,8 +1156,8 @@ grub_reiserfs_open (struct grub_file *file, const char
*name)
{
struct grub_reiserfs_stat_item_v2 entry_v2_stat;
grub_disk_read (data->disk,
- (((grub_disk_addr_t) block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS),
+ grub_fshelp_map_block (data->journal, block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS),
entry_location
+ (((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
@@ -1108,8 +1225,8 @@ grub_reiserfs_read (grub_file_t file, char *buf,
grub_size_t len)
switch (found.type)
{
case GRUB_REISERFS_DIRECT:
- block = (((grub_disk_addr_t) found.block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS);
+ block = (grub_fshelp_map_block (data->journal, found.block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS));
grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
if (initial_position < current_position + item_size)
{
@@ -1141,8 +1258,8 @@ grub_reiserfs_read (grub_file_t file, char *buf,
grub_size_t len)
if (! indirect_block_ptr)
goto fail;
grub_disk_read (found.data->disk,
- (((grub_disk_addr_t) found.block_number * block_size)
- >> GRUB_DISK_SECTOR_BITS),
+ grub_fshelp_map_block (data->journal,
found.block_number) *
+ (block_size >> GRUB_DISK_SECTOR_BITS),
grub_le_to_cpu16 (found.header.item_location),
item_size, (char *) indirect_block_ptr);
if (grub_errno)
@@ -1153,9 +1270,9 @@ grub_reiserfs_read (grub_file_t file, char *buf,
grub_size_t len)
&& current_position < final_position;
indirect_block++)
{
- block = ((grub_disk_addr_t)
- grub_le_to_cpu32 (indirect_block_ptr[indirect_block])
- * block_size) >> GRUB_DISK_SECTOR_BITS;
+ block = (grub_fshelp_map_block (data->journal,
+ grub_le_to_cpu32
(indirect_block_ptr[indirect_block])) *
+ (block_size >> GRUB_DISK_SECTOR_BITS));
grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
if (current_position + block_size >= initial_position)
{
@@ -1254,6 +1371,7 @@ grub_reiserfs_close (grub_file_t file)
struct grub_fshelp_node *node = file->data;
struct grub_reiserfs_data *data = node->data;
+ grub_free (data->journal);
grub_free (data);
grub_free (node);
#ifndef GRUB_UTIL
diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h
index e25dd16..d575007 100644
--- a/include/grub/fshelp.h
+++ b/include/grub/fshelp.h
@@ -34,6 +34,35 @@ enum grub_fshelp_filetype
GRUB_FSHELP_SYMLINK
};
+enum grub_fshelp_journal_type
+ {
+ GRUB_FSHELP_JOURNAL_TYPE_NONE,
+ GRUB_FSHELP_JOURNAL_TYPE_BLOCK,
+ GRUB_FSHELP_JOURNAL_TYPE_FILE
+ };
+
+#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING (grub_uint32_t) -1
+
+struct grub_fshelp_journal
+{
+ int type;
+ union
+ {
+ struct
+ {
+ grub_fshelp_node_t node;
+ int (*get_block) (grub_fshelp_node_t node, int block);
+ };
+ grub_uint32_t blkno;
+ };
+ int first_block;
+ int last_block;
+ int start_block;
+ int num_mappings;
+ grub_uint32_t mapping[0];
+};
+typedef struct grub_fshelp_journal *grub_fshelp_journal_t;
+
/* Lookup the node PATH. The node ROOTNODE describes the root of the
directory tree. The node found is returned in FOUNDNODE, which is
either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to
@@ -75,4 +104,7 @@ unsigned int
EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize,
unsigned int *pow);
+int
+EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, int block);
+
#endif /* ! GRUB_FSHELP_HEADER */
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel