]> git.proxmox.com Git - grub2.git/commitdiff
Fix minixfs with non-power-of-two blocks since it's supported by minix.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 9 May 2012 22:12:02 +0000 (00:12 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 9 May 2012 22:12:02 +0000 (00:12 +0200)
* grub-core/fs/minix.c (GRUB_MINIX_ZONESZ): Use block_size.
(grub_minix_data): Replace log_block_size with block_size.
(grub_minix_read_file): Use block_size but avoid 64-bit division.
(grub_minix_mount): Fill block_size.

ChangeLog
grub-core/fs/minix.c

index ce525768f61db2978c8ac401944514e9d3be4c9a..3df8588c4d2261c96e1e9f688011167ae805802f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
-2012-04-18  Vladimir Serbinenko  <phcoder@gmail.com>
+2012-05-09  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Fix minixfs with non-power-of-two blocks since it's supported by minix.
+
+       * grub-core/fs/minix.c (GRUB_MINIX_ZONESZ): Use block_size.
+       (grub_minix_data): Replace log_block_size with block_size.
+       (grub_minix_read_file): Use block_size but avoid 64-bit division.
+       (grub_minix_mount): Fill block_size.
+
+2012-05-09  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * configure.ac: Bump to beta5.
 
index dee29fc06c93c3454676e693340974d899d69d01..af04f11a4cdb53dfd50a6a5bc80f6e0ca3ed514d 100644 (file)
@@ -87,11 +87,11 @@ typedef grub_uint16_t grub_minix_ino_t;
 #define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE                          \
                                 + grub_minix_to_cpu16 (data->sblock.log2_zone_size))
 #endif
-#define GRUB_MINIX_ZONESZ      (1 << (data->log_block_size             \
-                                      + grub_minix_to_cpu16 (data->sblock.log2_zone_size)))
+#define GRUB_MINIX_ZONESZ      ((grub_uint64_t) data->block_size <<                    \
+                                (GRUB_DISK_SECTOR_BITS + grub_minix_to_cpu16 (data->sblock.log2_zone_size)))
 
 #ifdef MODE_MINIX3
-#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << (data->log_block_size - GRUB_DISK_SECTOR_BITS))
+#define GRUB_MINIX_ZONE2SECT(zone) ((zone) * data->block_size)
 #else
 #define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ)
 #endif
@@ -170,7 +170,7 @@ struct grub_minix_data
   int linknest;
   grub_disk_t disk;
   int filename_size;
-  grub_size_t log_block_size;
+  grub_size_t block_size;
 };
 
 static grub_dl_t my_mod;
@@ -251,26 +251,31 @@ static grub_ssize_t
 grub_minix_read_file (struct grub_minix_data *data,
                      void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
                                         unsigned offset, unsigned length),
-                     grub_off_t pos, grub_disk_addr_t len, char *buf)
+                     grub_off_t pos, grub_size_t len, char *buf)
 {
-  grub_disk_addr_t i;
-  grub_disk_addr_t blockcnt;
-  grub_uint64_t posblock;
-  grub_uint64_t blockoff;
+  grub_uint32_t i;
+  grub_uint32_t blockcnt;
+  grub_uint32_t posblock;
+  grub_uint32_t blockoff;
 
   /* Adjust len so it we can't read past the end of the file.  */
   if (len + pos > GRUB_MINIX_INODE_SIZE (data))
     len = GRUB_MINIX_INODE_SIZE (data) - pos;
 
-  blockcnt = ((len + pos + (1 << data->log_block_size) - 1)
-             >> data->log_block_size);
-  posblock = pos >> data->log_block_size;
-  blockoff = pos & ((1 << data->log_block_size) - 1);
+  /* Files are at most 2G/4G - 1 bytes on minixfs. Avoid 64-bit division.  */
+  blockcnt = ((grub_uint32_t) ((len + pos
+                               + (data->block_size << GRUB_DISK_SECTOR_BITS)
+                               - 1)
+              >> GRUB_DISK_SECTOR_BITS)) / data->block_size;
+  posblock = (((grub_uint32_t) pos)
+             / (data->block_size << GRUB_DISK_SECTOR_BITS));
+  blockoff = (((grub_uint32_t) pos)
+             % (data->block_size << GRUB_DISK_SECTOR_BITS));
 
   for (i = posblock; i < blockcnt; i++)
     {
       grub_disk_addr_t blknr;
-      grub_uint64_t blockend = 1 << data->log_block_size;
+      grub_uint64_t blockend = data->block_size << GRUB_DISK_SECTOR_BITS;
       grub_off_t skipfirst = 0;
 
       blknr = grub_minix_get_file_block (data, i);
@@ -280,10 +285,12 @@ grub_minix_read_file (struct grub_minix_data *data,
       /* Last block.  */
       if (i == blockcnt - 1)
        {
-         blockend = (len + pos) & ((1 << data->log_block_size) - 1);
+         /* len + pos < 4G (checked above), so it doesn't overflow.  */
+         blockend = (((grub_uint32_t) (len + pos))
+                     % (data->block_size << GRUB_DISK_SECTOR_BITS));
 
          if (!blockend)
-           blockend = 1 << data->log_block_size;
+           blockend = data->block_size << GRUB_DISK_SECTOR_BITS;
        }
 
       /* First block.  */
@@ -301,7 +308,7 @@ grub_minix_read_file (struct grub_minix_data *data,
       if (grub_errno)
        return -1;
 
-      buf += (1 << data->log_block_size) - skipfirst;
+      buf += (data->block_size << GRUB_DISK_SECTOR_BITS) - skipfirst;
     }
 
   return len;
@@ -492,18 +499,18 @@ grub_minix_mount (grub_disk_t disk)
 #ifdef MODE_MINIX3
   /* These tests are endian-independent. No need to byteswap.  */
   if (data->sblock.block_size == 0xffff)
-    data->log_block_size = 10;
+    data->block_size = 2;
   else
     {
-      if ((data->sblock.block_size & (data->sblock.block_size - 1))
-         || data->sblock.block_size == 0)
+      if ((data->sblock.block_size == grub_cpu_to_minix16_compile_time (0x200))
+         || (data->sblock.block_size == 0)
+         || (data->sblock.block_size & grub_cpu_to_minix16_compile_time (0x1ff)))
        goto fail;
-      for (data->log_block_size = 0; (1 << data->log_block_size)
-            < grub_minix_to_cpu16 (data->sblock.block_size);
-          data->log_block_size++);
+      data->block_size = grub_minix_to_cpu16 (data->sblock.block_size)
+       >> GRUB_DISK_SECTOR_BITS;
     }
 #else
-  data->log_block_size = 10;
+  data->block_size = 2;
 #endif
 
   return data;