]> git.proxmox.com Git - grub2.git/commitdiff
Several AFFS fixes.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 9 Nov 2011 10:43:39 +0000 (11:43 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 9 Nov 2011 10:43:39 +0000 (11:43 +0100)
* grub-core/fs/affs.c (grub_affs_bblock): Replace flags with version.
(GRUB_AFFS_FLAG_FFS): Removed.
(GRUB_AFFS_SYMLINK_SIZE): Likewise.
(GRUB_AFFS_FILETYPE_DIR): Make positive and unsigned.
(GRUB_AFFS_FILETYPE_DIR), (GRUB_AFFS_FILETYPE_REG): Fix a mix-up.
(grub_fshelp_node): Make block 32-bit.
Add block_cache and last_block_cache.
(grub_affs_read_block): Fill and use block cache.
(grub_affs_read_file): Removed.
(grub_affs_mount): Zero-fill node. Fix version check. Don't reread
boot block.
(grub_affs_read_symlink): Fix symlink size. Add a \0 at the end for
safety.
(grub_affs_iterate_dir): Use more appropriate types. Zero-fill allocated
space.
(grub_affs_close): Free block cache.
(grub_affs_read): Use grub_fshelp_read_file directly.

ChangeLog
grub-core/fs/affs.c

index f8f4241764331d6f5239d71f7a32c474c347961c..035f1819438d7ba0fa817c68ce5d60be44b78dc4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2011-11-09  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Several AFFS fixes.
+
+       * grub-core/fs/affs.c (grub_affs_bblock): Replace flags with version.
+       (GRUB_AFFS_FLAG_FFS): Removed.
+       (GRUB_AFFS_SYMLINK_SIZE): Likewise.
+       (GRUB_AFFS_FILETYPE_DIR): Make positive and unsigned.
+       (GRUB_AFFS_FILETYPE_DIR), (GRUB_AFFS_FILETYPE_REG): Fix a mix-up.
+       (grub_fshelp_node): Make block 32-bit.
+       Add block_cache and last_block_cache.
+       (grub_affs_read_block): Fill and use block cache.
+       (grub_affs_read_file): Removed.
+       (grub_affs_mount): Zero-fill node. Fix version check. Don't reread
+       boot block.
+       (grub_affs_read_symlink): Fix symlink size. Add a \0 at the end for
+       safety.
+       (grub_affs_iterate_dir): Use more appropriate types. Zero-fill allocated
+       space.
+       (grub_affs_close): Free block cache.
+       (grub_affs_read): Use grub_fshelp_read_file directly.
+
 2011-11-08  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/fs/zfs/zfs.c (read_dva): Issue an error if read failed
index adf2932bdf87d0929b3ff78bf9ecf9e783be2dea..06f41c4c34ad03c5b2282de01b5c960778baa785 100644 (file)
@@ -32,15 +32,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
 struct grub_affs_bblock
 {
   grub_uint8_t type[3];
-  grub_uint8_t flags;
+  grub_uint8_t version;
   grub_uint32_t checksum;
   grub_uint32_t rootblock;
 } __attribute__ ((packed));
 
-/* Set if the filesystem is a AFFS filesystem.  Otherwise this is an
-   OFS filesystem.  */
-#define GRUB_AFFS_FLAG_FFS     1
-
 /* The affs rootblock.  */
 struct grub_affs_rblock
 {
@@ -85,19 +81,19 @@ struct grub_affs_file
 #define GRUB_AFFS_BLOCKPTR_OFFSET      24
 #define GRUB_AFFS_SYMLINK_OFFSET       24
 
-#define GRUB_AFFS_SYMLINK_SIZE(blocksize) ((blocksize) - 225)
-
-#define GRUB_AFFS_FILETYPE_DIR         -3
-#define GRUB_AFFS_FILETYPE_REG         2
+#define GRUB_AFFS_FILETYPE_REG         0xfffffffd
+#define GRUB_AFFS_FILETYPE_DIR         2
 #define GRUB_AFFS_FILETYPE_SYMLINK     3
 \f
 
 struct grub_fshelp_node
 {
   struct grub_affs_data *data;
-  grub_disk_addr_t block;
+  grub_uint32_t block;
   struct grub_fshelp_node *parent;
   struct grub_affs_file di;
+  grub_uint32_t *block_cache;
+  grub_uint32_t last_block_cache;
 };
 
 /* Information about a "mounted" affs filesystem.  */
@@ -120,32 +116,46 @@ static grub_dl_t my_mod;
 static grub_disk_addr_t
 grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 {
-  int links;
+  grub_uint32_t target, curblock;
   grub_uint32_t pos;
-  int block = node->block;
   struct grub_affs_file file;
   struct grub_affs_data *data = node->data;
   grub_uint64_t mod;
 
+  if (!node->block_cache)
+    {
+      node->block_cache = grub_malloc ((((grub_be_to_cpu32 (node->di.size)
+                                         + 511) >> 9)  / data->htsize + 1)
+                                      * sizeof (node->block_cache[0]));
+      if (!node->block_cache)
+       return -1;
+      node->last_block_cache = 0;
+      node->block_cache[0] = node->block;
+    }
+
+  /* Files are at most 2G on AFFS, so no need for 64-bit division.  */
+  target = (grub_uint32_t) fileblock / data->htsize;
+  mod = (grub_uint32_t) fileblock % data->htsize;
   /* Find the block that points to the fileblock we are looking up by
      following the chain until the right table is reached.  */
-  for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--)
+  for (curblock = node->last_block_cache + 1; curblock <= target; curblock++)
     {
-      grub_disk_read (data->disk, block + data->blocksize - 1,
+      grub_disk_read (data->disk,
+                     node->block_cache[curblock - 1] + data->blocksize - 1,
                      data->blocksize * (GRUB_DISK_SECTOR_SIZE
                                         - GRUB_AFFS_FILE_LOCATION),
                      sizeof (file), &file);
       if (grub_errno)
        return 0;
 
-      block = grub_be_to_cpu32 (file.extension);
+      node->block_cache[curblock] = grub_be_to_cpu32 (file.extension);
+      node->last_block_cache = curblock;
     }
 
   /* Translate the fileblock to the block within the right table.  */
-  fileblock = mod;
-  grub_disk_read (data->disk, block,
+  grub_disk_read (data->disk, node->block_cache[target],
                  GRUB_AFFS_BLOCKPTR_OFFSET
-                 + (data->htsize - fileblock - 1) * sizeof (pos),
+                 + (data->htsize - mod - 1) * sizeof (pos),
                  sizeof (pos), &pos);
   if (grub_errno)
     return 0;
@@ -153,21 +163,6 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
   return grub_be_to_cpu32 (pos);
 }
 
-
-/* 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
-grub_affs_read_file (grub_fshelp_node_t node,
-                    void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
-                                       unsigned offset, unsigned length),
-                    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_affs_read_block,
-                               grub_be_to_cpu32 (node->di.size), 0);
-}
-
-
 static struct grub_affs_data *
 grub_affs_mount (grub_disk_t disk)
 {
@@ -178,7 +173,7 @@ grub_affs_mount (grub_disk_t disk)
   int checksum = 0;
   int blocksize = 0;
 
-  data = grub_malloc (sizeof (struct grub_affs_data));
+  data = grub_zalloc (sizeof (struct grub_affs_data));
   if (!data)
     return 0;
 
@@ -196,18 +191,12 @@ grub_affs_mount (grub_disk_t disk)
     }
 
   /* Test if the filesystem is a OFS filesystem.  */
-  if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS))
+  if (data->bblock.version < 1)
     {
       grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported");
       goto fail;
     }
 
-  /* Read the bootblock.  */
-  grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock),
-                 &data->bblock);
-  if (grub_errno)
-    goto fail;
-
   /* No sane person uses more than 8KB for a block.  At least I hope
      for that person because in that case this won't work.  */
   rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE * 16);
@@ -270,18 +259,21 @@ grub_affs_read_symlink (grub_fshelp_node_t node)
 {
   struct grub_affs_data *data = node->data;
   char *symlink;
+  const grub_size_t symlink_size = (data->blocksize * GRUB_DISK_SECTOR_SIZE
+                                   - 225);
 
-  symlink = grub_malloc (GRUB_AFFS_SYMLINK_SIZE (data->blocksize));
+  symlink = grub_malloc (symlink_size + 1);
   if (!symlink)
     return 0;
 
   grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET,
-                 GRUB_AFFS_SYMLINK_SIZE (data->blocksize), symlink);
+                 symlink_size, symlink);
   if (grub_errno)
     {
       grub_free (symlink);
       return 0;
     }
+  symlink[symlink_size] = 1;
   grub_dprintf ("affs", "Symlink: `%s'\n", symlink);
   return symlink;
 }
@@ -301,24 +293,24 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
   grub_uint32_t *hashtable;
 
   auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, 
-                                                  grub_disk_addr_t block,
+                                                  grub_uint32_t block,
                                                   const struct grub_affs_file *fil);
 
   int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
-                                             grub_disk_addr_t block,
+                                             grub_uint32_t block,
                                              const struct grub_affs_file *fil)
     {
       int type;
-      node = grub_malloc (sizeof (*node));
+      node = grub_zalloc (sizeof (*node));
       if (!node)
        {
          grub_free (hashtable);
          return 1;
        }
 
-      if ((int) grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
+      if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
        type = GRUB_FSHELP_REG;
-      else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
+      else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
        type = GRUB_FSHELP_DIR;
       else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK)
        type = GRUB_FSHELP_SYMLINK;
@@ -339,7 +331,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
     }
 
   /* Create the directory entries for `.' and `..'.  */
-  node = grub_malloc (sizeof (*node));
+  node = grub_zalloc (sizeof (*node));
   if (!node)
     return 1;
     
@@ -348,7 +340,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
     return 1;
   if (dir->parent)
     {
-      node = grub_malloc (sizeof (*node));
+      node = grub_zalloc (sizeof (*node));
       if (!node)
        return 1;
       *node = *dir->parent;
@@ -356,7 +348,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
        return 1;
     }
 
-  hashtable = grub_malloc (data->htsize * sizeof (*hashtable));
+  hashtable = grub_zalloc (data->htsize * sizeof (*hashtable));
   if (!hashtable)
     return 1;
 
@@ -367,7 +359,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
 
   for (i = 0; i < data->htsize; i++)
     {
-      grub_uint64_t next;
+      grub_uint32_t next;
 
       if (!hashtable[i])
        continue;
@@ -441,10 +433,13 @@ grub_affs_open (struct grub_file *file, const char *name)
   return grub_errno;
 }
 
-
 static grub_err_t
 grub_affs_close (grub_file_t file)
 {
+  struct grub_affs_data *data =
+    (struct grub_affs_data *) file->data;
+
+  grub_free (data->diropen.block_cache);
   grub_free (file->data);
 
   grub_dl_unref (my_mod);
@@ -452,7 +447,6 @@ grub_affs_close (grub_file_t file)
   return GRUB_ERR_NONE;
 }
 
-
 /* Read LEN bytes data from FILE into BUF.  */
 static grub_ssize_t
 grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
@@ -460,13 +454,12 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
   struct grub_affs_data *data =
     (struct grub_affs_data *) file->data;
 
-  int size = grub_affs_read_file (&data->diropen, file->read_hook,
-                             file->offset, len, buf);
-
-  return size;
+  return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
+                               file->read_hook,
+                               file->offset, len, buf, grub_affs_read_block,
+                               grub_be_to_cpu32 (data->diropen.di.size), 0);
 }
 
-
 static grub_err_t
 grub_affs_dir (grub_device_t device, const char *path,
               int (*hook) (const char *filename,