]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
* grub-core/fs/xfs.c (grub_xfs_inode): New field fork_offset.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 16 Oct 2011 09:48:54 +0000 (11:48 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 16 Oct 2011 09:48:54 +0000 (11:48 +0200)
(GRUB_XFS_INO_AGBITS): Make into inline function.
(GRUB_XFS_INO_INOINAG): Likewise.
(GRUB_XFS_INO_AG): Likewise.
(GRUB_XFS_FSB_TO_BLOCK): Likewise.
(GRUB_XFS_EXTENT_OFFSET): Likewise.
(GRUB_XFS_EXTENT_BLOCK): Likewise.
(GRUB_XFS_EXTENT_SIZE): Likewise.
(GRUB_XFS_ROUND_TO_DIRENT): Likewise.
(GRUB_XFS_NEXT_DIRENT): Likewise.
(grub_xfs_read_block): Rewrite the btree parsing. Fixes invalid BMAP.
(grub_xfs_read_file): Fix offset type.

ChangeLog
grub-core/fs/xfs.c

index 11b14ec2825227b6cbd9a886d4ff86f1deeba842..abe19dc7810432456aa20211e61dd4e1f2bc3761 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-10-16  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       * grub-core/fs/xfs.c (grub_xfs_inode): New field fork_offset.
+       (GRUB_XFS_INO_AGBITS): Make into inline function.
+       (GRUB_XFS_INO_INOINAG): Likewise.
+       (GRUB_XFS_INO_AG): Likewise.
+       (GRUB_XFS_FSB_TO_BLOCK): Likewise.
+       (GRUB_XFS_EXTENT_OFFSET): Likewise.
+       (GRUB_XFS_EXTENT_BLOCK): Likewise.
+       (GRUB_XFS_EXTENT_SIZE): Likewise.
+       (GRUB_XFS_ROUND_TO_DIRENT): Likewise.
+       (GRUB_XFS_NEXT_DIRENT): Likewise.
+       (grub_xfs_read_block): Rewrite the btree parsing. Fixes invalid BMAP.
+       (grub_xfs_read_file): Fix offset type.
+
 2011-10-15  Robert Millan  <rmh@gnu.org>
 
        * util/getroot.c (grub_util_get_grub_dev): Fix OS selection #ifdefs.
index eb0783407bc9cfbc146f8ae507a65ac8082c26d8..3dc5e0af052ba3912fdddb8533faa48d8413e6e5 100644 (file)
@@ -120,7 +120,9 @@ struct grub_xfs_inode
   grub_uint64_t nblocks;
   grub_uint32_t extsize;
   grub_uint32_t nextents;
-  grub_uint8_t unused3[20];
+  grub_uint16_t unused3;
+  grub_uint8_t fork_offset;
+  grub_uint8_t unused4[17];
   union
   {
     char raw[156];
@@ -154,7 +156,7 @@ struct grub_xfs_data
   grub_disk_t disk;
   int pos;
   int bsize;
-  int agsize;
+  grub_uint32_t agsize;
   struct grub_fshelp_node diropen;
 };
 
@@ -168,33 +170,67 @@ static grub_dl_t my_mod;
 #define FILETYPE_INO_DIRECTORY 0040000
 #define FILETYPE_INO_SYMLINK   0120000
 
-#define GRUB_XFS_INO_AGBITS(data)              \
-  ((data)->sblock.log2_agblk + (data)->sblock.log2_inop)
-#define GRUB_XFS_INO_INOINAG(data, ino)                \
-  (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1))
-#define GRUB_XFS_INO_AG(data,ino)              \
-  (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data))
-
-#define GRUB_XFS_FSB_TO_BLOCK(data, fsb) \
-  (((fsb) >> (data)->sblock.log2_agblk) * (data)->agsize \
- + ((fsb) & ((1LL << (data)->sblock.log2_agblk) - 1)))
-
-#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \
-       ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \
-       | grub_be_to_cpu32 (exts[ex][1]) >> 9)
-
-#define GRUB_XFS_EXTENT_BLOCK(exts,ex)         \
-  ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \
-                 & (0x1ff)) << 43 \
-   | (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \
-   | grub_be_to_cpu32 (exts[ex][3]) >> 21)
-
-#define GRUB_XFS_EXTENT_SIZE(exts,ex)          \
-  (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1))
-
-#define GRUB_XFS_ROUND_TO_DIRENT(pos)  ((((pos) + 8 - 1) / 8) * 8)
-#define GRUB_XFS_NEXT_DIRENT(pos,len)          \
-  (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2)
+static inline int
+GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data)
+{
+  return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
+                     grub_uint64_t ino)
+{
+  return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
+}
+
+static inline grub_uint64_t
+GRUB_XFS_INO_AG (struct grub_xfs_data *data,
+                grub_uint64_t ino)
+{
+  return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
+}
+
+static inline grub_disk_addr_t
+GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
+{
+  return ((fsb >> data->sblock.log2_agblk) * data->agsize
+         + (fsb & ((1LL << data->sblock.log2_agblk) - 1)));
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_OFFSET (grub_xfs_extent *exts, int ex)
+{
+  return ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23
+         | grub_be_to_cpu32 (exts[ex][1]) >> 9);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_BLOCK (grub_xfs_extent *exts, int ex)
+{
+  return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1])
+                          & (0x1ff)) << 43
+         | (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11
+         | grub_be_to_cpu32 (exts[ex][3]) >> 21);
+}
+
+static inline grub_uint64_t
+GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *exts, int ex)
+{
+  return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1));
+}
+
+static inline int
+GRUB_XFS_ROUND_TO_DIRENT (int pos)
+{
+  return ((((pos) + 8 - 1) / 8) * 8);
+}
+
+static inline int
+GRUB_XFS_NEXT_DIRENT (int pos, int len)
+{
+  return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2);
+}
+
 \f
 static inline grub_uint64_t
 grub_xfs_inode_block (struct grub_xfs_data *data,
@@ -250,13 +286,23 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
   if (node->inode.format == XFS_INODE_FORMAT_BTREE)
     {
       grub_uint64_t *keys;
+      int recoffset;
 
-      leaf = grub_malloc (node->data->sblock.bsize);
+      leaf = grub_malloc (node->data->bsize);
       if (leaf == 0)
         return 0;
 
       nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
       keys = &node->inode.data.btree.keys[0];
+      if (node->inode.fork_offset)
+       recoffset = (node->inode.fork_offset
+                    - ((char *) &node->inode.data.btree.keys - (char *) &node->inode))
+         / (2 * sizeof (grub_uint64_t));
+      else
+       recoffset = ((1 << node->data->sblock.log2_inode)
+                    - ((char *) &node->inode.data.btree.keys
+                       - (char *) &node->inode))
+         / (2 * sizeof (grub_uint64_t));
       do
         {
           int i;
@@ -273,12 +319,9 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
               grub_free (leaf);
               return 0;
             }
-
           if (grub_disk_read (node->data->disk,
-                              grub_be_to_cpu64 (keys[i - 1 + nrec])
-                              << (node->data->sblock.log2_bsize
-                                  - GRUB_DISK_SECTOR_BITS),
-                              0, node->data->sblock.bsize, leaf))
+                              GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (keys[i - 1 + recoffset])) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
+                              0, node->data->bsize, leaf))
             return 0;
 
           if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
@@ -290,7 +333,11 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 
           nrec = grub_be_to_cpu16 (leaf->numrecs);
           keys = &leaf->keys[0];
-        } while (leaf->level);
+         recoffset = ((node->data->bsize - ((char *) &leaf->keys
+                                            - (char *) leaf))
+                      / (2 * sizeof (grub_uint64_t)));
+       }
+      while (leaf->level);
       exts = (grub_xfs_extent *) keys;
     }
   else if (node->inode.format == XFS_INODE_FORMAT_EXT)
@@ -336,7 +383,7 @@ static grub_ssize_t
 grub_xfs_read_file (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)
+                    grub_off_t pos, grub_size_t len, char *buf)
 {
   return grub_fshelp_read_file (node->data->disk, node, read_hook,
                                pos, len, buf, grub_xfs_read_block,