Hi,

This new patch is synced with the current cvs head, also some minor changes.

If nobody objects, I'd commit this in a few days.


2008-05-15  Bean  <[EMAIL PROTECTED]>

        * 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.

-- 
Bean
diff --git a/fs/affs.c b/fs/affs.c
index 8ebfa40..5418ffb 100644
--- a/fs/affs.c
+++ b/fs/affs.c
@@ -109,18 +109,19 @@ static grub_dl_t my_mod;
 #endif
 
 
-static int
-grub_affs_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   int links;
   grub_uint32_t pos;
   int block = node->block;
   struct grub_affs_file file;
   struct grub_affs_data *data = node->data;
+  grub_uint32_t mod;
 
   /* Find the block that points to the fileblock we are looking up by
      following the chain until the right table is reached.  */
-  for (links = fileblock / (data->htsize); links; links--)
+  for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--)
     {
       grub_disk_read (data->disk, block + data->blocksize - 1,
                      data->blocksize * (GRUB_DISK_SECTOR_SIZE
@@ -133,7 +134,7 @@ grub_affs_read_block (grub_fshelp_node_t node, int 
fileblock)
     }
 
   /* Translate the fileblock to the block within the right table.  */
-  fileblock = fileblock % (data->htsize);
+  fileblock = mod;
   grub_disk_read (data->disk, block,
                  GRUB_AFFS_BLOCKPTR_OFFSET
                  + (data->htsize - fileblock - 1) * sizeof (pos),
@@ -567,4 +568,3 @@ GRUB_MOD_FINI(affs)
 {
   grub_fs_unregister (&grub_affs_fs);
 }
-
diff --git a/fs/afs.c b/fs/afs.c
index 7c61671..5b5eb68 100644
--- a/fs/afs.c
+++ b/fs/afs.c
@@ -199,12 +199,12 @@ grub_afs_read_inode (struct grub_afs_data *data,
 }
 
 static int
-grub_afs_read_block (grub_fshelp_node_t node, int fileblock)
+grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   struct grub_afs_sblock *sb = &node->data->sblock;
   struct grub_afs_datastream *ds = &node->inode.stream;
 
-  if ((grub_uint32_t) fileblock < U64 (sb, ds->max_direct_range))
+  if (fileblock < U64 (sb, ds->max_direct_range))
     {
       int i;
 
@@ -215,7 +215,7 @@ grub_afs_read_block (grub_fshelp_node_t node, int fileblock)
           fileblock -= U16 (sb, ds->direct[i].len);
         }
     }
-  else if ((grub_uint32_t) fileblock < U64 (sb, ds->max_indirect_range))
+  else if (fileblock < U64 (sb, ds->max_indirect_range))
     {
       int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun);
       struct grub_afs_blockrun indir[ptrs_per_blk];
diff --git a/fs/ext2.c b/fs/ext2.c
index ec66582..ce7b2fa 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,20 +258,21 @@ 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);
 }
 
 
-static int
-grub_ext2_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   struct grub_ext2_data *data = node->data;
   struct grub_ext2_inode *inode = &node->inode;
   int blknr;
-  int blksz = EXT2_BLOCK_SIZE (data);
+  unsigned int blksz = EXT2_BLOCK_SIZE (data);
   int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
   
   /* Direct blocks.  */
@@ -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,169 @@ 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_disk_addr_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
+    {
+      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);
+    }
+}
+
 static struct grub_ext2_data *
 grub_ext2_mount (grub_disk_t disk)
 {
@@ -336,12 +565,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 +771,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..13a81b6 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);
        }
       
@@ -223,25 +223,26 @@ grub_fshelp_find_file (const char *path, 
grub_fshelp_node_t rootnode,
 grub_ssize_t
 grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
                       void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t 
sector,
-                                         unsigned offset, unsigned length),
-                      int pos, grub_size_t len, char *buf,
-                      int (*get_block) (grub_fshelp_node_t node, int block),
+                                                           unsigned offset,
+                                                           unsigned length),
+                      grub_off_t pos, grub_size_t len, char *buf,
+                      grub_disk_addr_t (*get_block) (grub_fshelp_node_t node,
+                                                      grub_disk_addr_t block),
                       grub_off_t filesize, int log2blocksize)
 {
-  int i;
-  int blockcnt;
+  grub_disk_addr_t i, blockcnt;
   int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
 
   /* Adjust LEN so it we can't read past the end of the file.  */
-  if (len > filesize)
-    len = filesize;
+  if (pos + len > filesize)
+    len = filesize - pos;
 
-  blockcnt = ((len + pos) + blocksize - 1) / blocksize;
+  blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + 
GRUB_DISK_SECTOR_BITS);
 
-  for (i = pos / blocksize; i < blockcnt; i++)
+  for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
     {
-      int blknr;
-      int blockoff = pos % blocksize;
+      grub_disk_addr_t blknr;
+      int blockoff = pos & (blocksize - 1);
       int blockend = blocksize;
 
       int skipfirst = 0;
@@ -255,7 +256,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t 
node,
       /* Last block.  */
       if (i == blockcnt - 1)
        {
-         blockend = (len + pos) % blocksize;
+         blockend = (len + pos) & (blocksize - 1);
          
          /* The last portion is exactly blocksize.  */
          if (! blockend)
@@ -263,7 +264,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t 
node,
        }
 
       /* First block.  */
-      if (i == pos / blocksize)
+      if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS)))
        {
          skipfirst = blockoff;
          blockend -= skipfirst;
@@ -310,3 +311,30 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned 
int *pow)
 
   return GRUB_ERR_NONE;
 }
+
+grub_disk_addr_t
+grub_fshelp_map_block (grub_fshelp_journal_t log, grub_disk_addr_t block)
+{
+  int map_block;
+
+  if (! log)
+    return block;
+
+  for (map_block = log->num_mappings - 1; map_block >= 0; map_block--)
+    {
+      if (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/hfsplus.c b/fs/hfsplus.c
index fe72539..f4106f0 100644
--- a/fs/hfsplus.c
+++ b/fs/hfsplus.c
@@ -285,8 +285,8 @@ static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key 
*keya,
 
 /* Search for the block FILEBLOCK inside the file NODE.  Return the
    blocknumber of this block on disk.  */
-static int
-grub_hfsplus_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   struct grub_hfsplus_btnode *nnode = 0;
   int blksleft = fileblock;
diff --git a/fs/ntfs.c b/fs/ntfs.c
index 2922ade..786f0e3 100644
--- a/fs/ntfs.c
+++ b/fs/ntfs.c
@@ -331,8 +331,8 @@ retry:
   return 0;
 }
 
-static int
-grub_ntfs_read_block (grub_fshelp_node_t node, int block)
+static grub_disk_addr_t
+grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block)
 {
   struct grub_ntfs_rlst *ctx;
 
diff --git a/fs/reiserfs.c b/fs/reiserfs.c
index b536b21..87a754c 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 + 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
diff --git a/fs/sfs.c b/fs/sfs.c
index a453bc6..99081bd 100644
--- a/fs/sfs.c
+++ b/fs/sfs.c
@@ -219,8 +219,8 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned 
int block,
   return grub_error (GRUB_ERR_FILE_READ_ERROR, "SFS extent not found");
 }
 
-static int
-grub_sfs_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_sfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   int blk = node->block;
   int size = 0;
@@ -239,7 +239,7 @@ grub_sfs_read_block (grub_fshelp_node_t node, int fileblock)
       if (err)
        return 0;
 
-      if (fileblock < size)
+      if (fileblock < (unsigned int) size)
        return fileblock + blk;
 
       fileblock -= size;
diff --git a/fs/udf.c b/fs/udf.c
index 8f833eb..072e44f 100644
--- a/fs/udf.c
+++ b/fs/udf.c
@@ -404,8 +404,8 @@ grub_udf_read_icb (struct grub_udf_data *data,
   return 0;
 }
 
-static int
-grub_udf_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   char *ptr;
   int len;
@@ -429,7 +429,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock)
       len /= sizeof (struct grub_udf_short_ad);
       while (len > 0)
        {
-         if (fileblock < (int) U32 (ad->length))
+         if (fileblock < U32 (ad->length))
            return ((U32 (ad->position) & GRUB_UDF_EXT_MASK) ? 0 :
                     (grub_udf_get_block (node->data,
                                          node->part_ref,
@@ -448,7 +448,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock)
       len /= sizeof (struct grub_udf_long_ad);
       while (len > 0)
        {
-         if (fileblock < (int) U32 (ad->length))
+         if (fileblock < U32 (ad->length))
            return ((U32 (ad->block.block_num) & GRUB_UDF_EXT_MASK) ?  0 :
                     (grub_udf_get_block (node->data,
                                          ad->block.part_ref,
diff --git a/fs/xfs.c b/fs/xfs.c
index 88d22be..b8ce3e9 100644
--- a/fs/xfs.c
+++ b/fs/xfs.c
@@ -220,8 +220,8 @@ grub_xfs_read_inode (struct grub_xfs_data *data, 
grub_uint64_t ino,
 }
 
 
-static int
-grub_xfs_read_block (grub_fshelp_node_t node, int fileblock)
+static grub_disk_addr_t
+grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
   struct grub_xfs_btree_node *leaf = 0;
   int ex, nrec;
@@ -244,7 +244,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock)
 
           for (i = 0; i < nrec; i++)
             {
-              if ((grub_uint64_t) fileblock < grub_be_to_cpu64 (keys[i]))
+              if (fileblock < grub_be_to_cpu64 (keys[i]))
                 break;
             }
 
@@ -292,8 +292,8 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock)
   for (ex = 0; ex < nrec; ex++)
     {
       grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (exts, ex);
-      int offset = GRUB_XFS_EXTENT_OFFSET (exts, ex);
-      int size = GRUB_XFS_EXTENT_SIZE (exts, ex);
+      grub_uint64_t offset = GRUB_XFS_EXTENT_OFFSET (exts, ex);
+      grub_uint64_t size = GRUB_XFS_EXTENT_SIZE (exts, ex);
 
       /* Sparse block.  */
       if (fileblock < offset)
diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h
index e25dd16..32d47a3 100644
--- a/include/grub/fshelp.h
+++ b/include/grub/fshelp.h
@@ -34,6 +34,34 @@ enum grub_fshelp_filetype
     GRUB_FSHELP_SYMLINK
   };
 
+enum grub_fshelp_journal_type
+  {
+    GRUB_FSHELP_JOURNAL_TYPE_BLOCK,
+    GRUB_FSHELP_JOURNAL_TYPE_FILE
+  };
+
+#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING     (grub_disk_addr_t) -1
+
+struct grub_fshelp_journal
+{
+  int type;
+  union
+    {
+      struct
+        {
+          grub_fshelp_node_t node;
+          grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, 
grub_disk_addr_t block);
+        };
+       grub_disk_addr_t blkno;
+    };
+  int first_block;
+  int last_block;
+  int start_block;
+  int num_mappings;
+  grub_disk_addr_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
@@ -64,15 +92,18 @@ EXPORT_FUNC(grub_fshelp_find_file) (const char *path,
 grub_ssize_t
 EXPORT_FUNC(grub_fshelp_read_file) (grub_disk_t disk, grub_fshelp_node_t node,
                                    void NESTED_FUNC_ATTR (*read_hook) 
(grub_disk_addr_t sector,
-                                                      unsigned offset,
-                                                      unsigned length),
-                                   int pos, grub_size_t len, char *buf,
-                                   int (*get_block) (grub_fshelp_node_t node,
-                                                     int block),
+                                                                        
unsigned offset,
+                                                                        
unsigned length),
+                                   grub_off_t pos, grub_size_t len, char *buf,
+                                   grub_disk_addr_t (*get_block) 
(grub_fshelp_node_t node,
+                                                                   
grub_disk_addr_t block),
                                    grub_off_t filesize, int log2blocksize);
 
 unsigned int
 EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize,
                                      unsigned int *pow);
 
+grub_disk_addr_t
+EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, 
grub_disk_addr_t block);
+
 #endif /* ! GRUB_FSHELP_HEADER */
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to