2008-05-20 Bean <bean123ch@gmail.com>

* fs/fshelp.c (grub_fshelp_map_block): New function.
	(grub_fshelp_find_file): Use 64-bit type for pos and block address.
	Use `>>' and `&' operator to avoid 64-bit divide and modulo.

	* 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.
	(grub_fshelp_read_file): Use grub_disk_addr_t as block type.
	(grub_fshelp_map_block): Likewise.

	* 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_read_block): Change block type to grub_disk_addr_t. Use
	grub_fshelp_map_block to get real block number.
	(grub_ext2_blockgroup): Use grub_fshelp_map_block to get real block
	number.
	(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.

	* fs/affs.c (grub_affs_read_block): Change block type to
	grub_disk_addr_t. Use grub_divmod64 to do 64-bit division.

	* fs/afs.c (grub_afs_read_block): Change block type to grub_disk_addr_t.

	* fs/hfsplus.c (grub_hfsplus_read_block): Likewise.

	* fs/ntfs.c (grub_ntfs_read_block): Likewise.

	* fs/udf.c (grub_udf_read_block): Change block type to
	grub_disk_addr_t. Use type cast to avoid warning.

	* fs/xfs.c (grub_xfs_read_block): Likewise.
This commit is contained in:
bean 2008-05-20 05:00:53 +00:00
parent b7c6bed50e
commit 887d2619bf
12 changed files with 575 additions and 83 deletions

View file

@ -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 + 1);
@ -675,6 +680,124 @@ 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_disk_addr_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, mid;
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);
mid = grub_le_to_cpu32 (db->mount_id);
if ((id <= seq_id) && (mid <= 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;
seq_id = id;
mount_id = mid;
};
if (! last_num)
grub_free (log);
else
{
int size;
size = sizeof (struct grub_fshelp_journal) +
last_num * sizeof (grub_disk_addr_t);
log->num_mappings = last_num;
data->journal = grub_realloc (log, size);
}
}
/* Fill the mounted filesystem structure and return it. */
static struct grub_reiserfs_data *
grub_reiserfs_mount (grub_disk_t disk)
@ -688,12 +811,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:
@ -741,8 +865,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);
@ -836,7 +960,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);
@ -878,7 +1003,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);
@ -1026,8 +1152,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)),
@ -1040,8 +1166,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)),
@ -1109,8 +1235,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)
{
@ -1142,8 +1268,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)
@ -1154,9 +1280,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)
{
@ -1255,6 +1381,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