]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Support for cbfs. Also factor out the part which is common
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 15 Jun 2013 22:06:13 +0000 (00:06 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 15 Jun 2013 22:06:13 +0000 (00:06 +0200)
for all archives to a separate module. This splits tar from cpio
as they are very different but keeps cpio, cpio_be, odc and newc
together since they're very similar.

15 files changed:
ChangeLog
Makefile.util.def
grub-core/Makefile.core.def
grub-core/commands/nativedisk.c
grub-core/fs/archelp.c [new file with mode: 0644]
grub-core/fs/cbfs.c [new file with mode: 0644]
grub-core/fs/cpio.c
grub-core/fs/cpio_be.c
grub-core/fs/cpio_common.c
grub-core/fs/newc.c
grub-core/fs/odc.c
grub-core/fs/tar.c
include/grub/archelp.h [new file with mode: 0644]
include/grub/cbfs_core.h [new file with mode: 0644]
include/grub/disk.h

index 4e7abb564aa8a062c170724a85244a814306aac7..83e90df94ece56ff8018194d238673255b5dfd4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-06-15  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Support for cbfs. Also factor out the part which is common
+       for all archives to a separate module. This splits tar from cpio
+       as they are very different but keeps cpio, cpio_be, odc and newc
+       together since they're very similar.
+
 2013-06-15  David Michael  <fedora.dm0@gmail.com>
 
        * configure.ac (FREETYPE): Change AC_CHECK_PROGS to AC_CHECK_TOOLS.
index 220bf6ac419a1490e476c9285206ee47dc51494f..97abd84c288ec248c7431b71555b678ab9fec1e7 100644 (file)
@@ -75,6 +75,8 @@ library = {
   common = grub-core/fs/afs.c;
   common = grub-core/fs/bfs.c;
   common = grub-core/fs/btrfs.c;
+  common = grub-core/fs/cbfs.c;
+  common = grub-core/fs/archelp.c;
   common = grub-core/fs/cpio.c;
   common = grub-core/fs/cpio_be.c;
   common = grub-core/fs/odc.c;
index ed4b727245b02141d96d79267f7d9dbf7434a1b6..9d177c6740f42fba29f22b49242adbd176fe8779 100644 (file)
@@ -1145,6 +1145,16 @@ module = {
   cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
 };
 
+module = {
+  name = archelp;
+  common = fs/archelp.c;
+};
+
+module = {
+  name = cbfs;
+  common = fs/cbfs.c;
+};
+
 module = {
   name = cpio;
   common = fs/cpio.c;
index 71d7bc4103d252af42672e4f0b6b3c1d52d089fd..af31913137ce150aa13d1288d4799737cb3acbf2 100644 (file)
@@ -78,8 +78,12 @@ get_uuid (const char *name, char **uuid, int getnative)
        break;
 
       /* Virtual disks.  */
+      /* GRUB dynamically generated files.  */
     case GRUB_DISK_DEVICE_PROCFS_ID:
+      /* To access through host OS routines (grub-emu only).  */
     case GRUB_DISK_DEVICE_HOST_ID:
+      /* To access coreboot roms.  */
+    case GRUB_DISK_DEVICE_CBFSDISK_ID:
       /* GRUB-only memdisk. Can't match any of firmware devices.  */
     case GRUB_DISK_DEVICE_MEMDISK_ID:
       grub_dprintf ("nativedisk", "Skipping native disk %s\n",
diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c
new file mode 100644 (file)
index 0000000..4a7ace1
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2007,2008,2009,2013 Free Software Foundation, Inc.
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/archelp.h>
+#include <grub/err.h>
+#include <grub/fs.h>
+#include <grub/disk.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static inline void
+canonicalize (char *name)
+{
+  char *iptr, *optr;
+  for (iptr = name, optr = name; *iptr; )
+    {
+      while (*iptr == '/')
+       iptr++;
+      if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
+       {
+         iptr += 2;
+         continue;
+       }
+      if (iptr[0] == '.' && iptr[1] == '.' && (iptr[2] == '/' || iptr[2] == 0))
+       {
+         iptr += 3;
+         if (optr == name)
+           continue;
+         for (optr -= 2; optr >= name && *optr != '/'; optr--);
+         optr++;
+         continue;
+       }
+      while (*iptr && *iptr != '/')
+       *optr++ = *iptr++;
+      if (*iptr)
+       *optr++ = *iptr++;
+    }
+  *optr = 0;
+}
+
+static grub_err_t
+handle_symlink (struct grub_archelp_data *data,
+               struct grub_archelp_ops *arcops,
+               const char *fn, char **name,
+               grub_uint32_t mode, int *restart)
+{
+  grub_size_t flen;
+  char *target;
+  char *ptr;
+  char *lastslash;
+  grub_size_t prefixlen;
+  char *rest;
+  char *linktarget;
+
+  *restart = 0;
+
+  if ((mode & GRUB_ARCHELP_ATTR_TYPE) != GRUB_ARCHELP_ATTR_LNK
+      || !arcops->get_link_target)
+    return GRUB_ERR_NONE;
+  flen = grub_strlen (fn);
+  if (grub_memcmp (*name, fn, flen) != 0 
+      || ((*name)[flen] != 0 && (*name)[flen] != '/'))
+    return GRUB_ERR_NONE;
+  rest = *name + flen;
+  lastslash = rest;
+  if (*rest)
+    rest++;
+  while (lastslash >= *name && *lastslash != '/')
+    lastslash--;
+  if (lastslash >= *name)
+    prefixlen = lastslash - *name;
+  else
+    prefixlen = 0;
+
+  if (prefixlen)
+    prefixlen++;
+
+  linktarget = arcops->get_link_target (data);
+  if (!linktarget)
+    return grub_errno;
+  if (linktarget[0] == '\0')
+    return GRUB_ERR_NONE;
+  target = grub_malloc (grub_strlen (linktarget) + grub_strlen (*name) + 2);
+  if (!target)
+    return grub_errno;
+
+  grub_strcpy (target + prefixlen, linktarget);
+  grub_free (linktarget);
+  if (target[prefixlen] == '/')
+    {
+      ptr = grub_stpcpy (target, target + prefixlen);
+      ptr = grub_stpcpy (ptr, rest);
+      *ptr = 0;
+      grub_dprintf ("archelp", "symlink redirected %s to %s\n",
+                   *name, target);
+      grub_free (*name);
+
+      canonicalize (target);
+      *name = target;
+      *restart = 1;
+      return GRUB_ERR_NONE;
+    }
+  if (prefixlen)
+    {
+      grub_memcpy (target, *name, prefixlen);
+      target[prefixlen-1] = '/';
+    }
+  grub_strcat (target, rest);
+  grub_dprintf ("archelp", "symlink redirected %s to %s\n",
+               *name, target);
+  grub_free (*name);
+  canonicalize (target);
+  *name = target;
+  *restart = 1;
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_archelp_dir (struct grub_archelp_data *data,
+                 struct grub_archelp_ops *arcops,
+                 const char *path_in,
+                 grub_fs_dir_hook_t hook, void *hook_data)
+{
+  char *prev, *name, *path, *ptr;
+  grub_size_t len;
+  int symlinknest = 0;
+
+  path = grub_strdup (path_in + 1);
+  if (!path)
+    return grub_errno;
+  canonicalize (path);
+  for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--)
+    *ptr = 0;
+
+  prev = 0;
+
+  len = grub_strlen (path);
+  while (1)
+    {
+      grub_int32_t mtime;
+      grub_uint32_t mode;
+      grub_err_t err;
+
+      if (arcops->find_file (data, &name, &mtime, &mode))
+       goto fail;
+
+      if (mode == GRUB_ARCHELP_ATTR_END)
+       break;
+
+      canonicalize (name);
+
+      if (grub_memcmp (path, name, len) == 0
+         && (name[len] == 0 || name[len] == '/' || len == 0))
+       {
+         char *p, *n;
+
+         n = name + len;
+         while (*n == '/')
+           n++;
+
+         p = grub_strchr (n, '/');
+         if (p)
+           *p = 0;
+
+         if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0)
+           {
+             struct grub_dirhook_info info;
+             grub_memset (&info, 0, sizeof (info));
+             info.dir = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE)
+                                        == GRUB_ARCHELP_ATTR_DIR);
+             if (!(mode & GRUB_ARCHELP_ATTR_NOTIME))
+               {
+                 info.mtime = mtime;
+                 info.mtimeset = 1;
+               }
+             if (hook (n, &info, hook_data))
+               {
+                 grub_free (name);
+                 goto fail;
+               }
+             grub_free (prev);
+             prev = name;
+           }
+         else
+           {
+             int restart = 0;
+             err = handle_symlink (data, arcops, name,
+                                   &path, mode, &restart);
+             grub_free (name);
+             if (err)
+               goto fail;
+             if (restart)
+               {
+                 len = grub_strlen (path);
+                 if (++symlinknest == 8)
+                   {
+                     grub_error (GRUB_ERR_SYMLINK_LOOP,
+                                 N_("too deep nesting of symlinks"));
+                     goto fail;
+                   }
+                 arcops->rewind (data);
+               }
+           }
+       }
+      else
+       grub_free (name);
+    }
+
+fail:
+
+  grub_free (path);
+  grub_free (prev);
+
+  return grub_errno;
+}
+
+grub_err_t
+grub_archelp_open (struct grub_archelp_data *data,
+                  struct grub_archelp_ops *arcops,
+                  const char *name_in)
+{
+  char *fn;
+  char *name = grub_strdup (name_in + 1);
+  int symlinknest = 0;
+
+  if (!name)
+    return grub_errno;
+
+  canonicalize (name);
+
+  while (1)
+    {
+      grub_uint32_t mode;
+      int restart;
+      
+      if (arcops->find_file (data, &fn, NULL, &mode))
+       goto fail;
+
+      if (mode == GRUB_ARCHELP_ATTR_END)
+       {
+         grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in);
+         break;
+       }
+
+      canonicalize (fn);
+
+      if (handle_symlink (data, arcops, fn, &name, mode, &restart))
+       {
+         grub_free (fn);
+         goto fail;
+       }
+
+      if (restart)
+       {
+         arcops->rewind (data);
+         if (++symlinknest == 8)
+           {
+             grub_error (GRUB_ERR_SYMLINK_LOOP,
+                         N_("too deep nesting of symlinks"));
+             goto fail;
+           }
+         goto no_match;
+       }
+
+      if (grub_strcmp (name, fn) != 0)
+       goto no_match;
+
+      grub_free (fn);
+      grub_free (name);
+
+      return GRUB_ERR_NONE;
+
+    no_match:
+
+      grub_free (fn);
+    }
+
+fail:
+  grub_free (name);
+
+  return grub_errno;
+}
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
new file mode 100644 (file)
index 0000000..d1631f1
--- /dev/null
@@ -0,0 +1,382 @@
+/* cbfs.c - cbfs and tar filesystem.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2007,2008,2009,2013 Free Software Foundation, Inc.
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/archelp.h>
+
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/i18n.h>
+#include <grub/cbfs_core.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+
+struct grub_archelp_data
+{
+  grub_disk_t disk;
+  grub_off_t hofs, next_hofs;
+  grub_off_t dofs;
+  grub_off_t size;
+  grub_off_t cbfs_start;
+  grub_off_t cbfs_end;
+  grub_off_t cbfs_align;
+};
+
+static grub_err_t
+grub_cbfs_find_file (struct grub_archelp_data *data, char **name,
+                    grub_int32_t *mtime,
+                    grub_uint32_t *mode)
+{
+  grub_size_t offset;
+  for (;;
+       data->dofs = data->hofs + offset,
+        data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align))
+    {
+      struct cbfs_file hd;
+      grub_size_t namesize;
+
+      data->hofs = data->next_hofs;
+
+      if (data->hofs >= data->cbfs_end)
+       {
+         *mode = GRUB_ARCHELP_ATTR_END;
+         return GRUB_ERR_NONE;
+       }
+
+      if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
+       return grub_errno;
+
+      if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (hd.magic)) != 0)
+       {
+         *mode = GRUB_ARCHELP_ATTR_END;
+         return GRUB_ERR_NONE;
+       }
+      data->size = grub_be_to_cpu32 (hd.len);
+      (void) mtime;
+      offset = grub_be_to_cpu32 (hd.offset);
+
+      if (mode)
+       *mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;
+
+      namesize = offset;
+      if (namesize >= sizeof (hd))
+       namesize -= sizeof (hd);
+      if (namesize == 0)
+       continue;
+      *name = grub_malloc (namesize + 1);
+      if (*name == NULL)
+       return grub_errno;
+
+      if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
+                         namesize, *name))
+       {
+         grub_free (*name);
+         return grub_errno;
+       }
+
+      if ((*name)[0] == '\0')
+       {
+         grub_free (*name);
+         *name = NULL;
+         continue;
+       }
+
+      (*name)[namesize] = 0;
+
+      data->dofs = data->hofs + offset;
+      data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align);
+      return GRUB_ERR_NONE;
+    }
+}
+
+static void
+grub_cbfs_rewind (struct grub_archelp_data *data)
+{
+  data->next_hofs = data->cbfs_start;
+}
+
+static struct grub_archelp_ops arcops =
+  {
+    .find_file = grub_cbfs_find_file,
+    .rewind = grub_cbfs_rewind
+  };
+
+static int
+validate_head (struct cbfs_header *head)
+{
+  return (head->magic == grub_cpu_to_be32_compile_time (CBFS_HEADER_MAGIC)
+         && (head->version
+             == grub_cpu_to_be32_compile_time (CBFS_HEADER_VERSION1)
+             || head->version
+             == grub_cpu_to_be32_compile_time (CBFS_HEADER_VERSION2))
+         && (grub_be_to_cpu32 (head->bootblocksize)
+             < grub_be_to_cpu32 (head->romsize))
+         && (grub_be_to_cpu32 (head->offset)
+             < grub_be_to_cpu32 (head->romsize))
+         && (grub_be_to_cpu32 (head->offset)
+             + grub_be_to_cpu32 (head->bootblocksize)
+             < grub_be_to_cpu32 (head->romsize))
+         && head->align != 0
+         && (head->align & (head->align - 1)) == 0
+         && head->romsize != 0);
+}
+
+static struct grub_archelp_data *
+grub_cbfs_mount (grub_disk_t disk)
+{
+  struct cbfs_file hd;
+  struct grub_archelp_data *data;
+  grub_uint32_t ptr;
+  grub_off_t header_off;
+  struct cbfs_header head;
+
+  if (grub_disk_read (disk, grub_disk_get_size (disk) - 1,
+                     GRUB_DISK_SECTOR_SIZE - sizeof (ptr),
+                     sizeof (ptr), &ptr))
+    goto fail;
+
+  ptr = grub_cpu_to_le32 (ptr);
+  header_off = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS)
+    + (grub_int32_t) ptr;
+
+  if (grub_disk_read (disk, 0, header_off,
+                     sizeof (head), &head))
+    goto fail;
+
+  if (!validate_head (&head))
+    goto fail;
+
+  data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data));
+  if (!data)
+    goto fail;
+
+  data->cbfs_start = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS)
+    - (grub_be_to_cpu32 (head.romsize) - grub_be_to_cpu32 (head.offset));
+  data->cbfs_end = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS)
+    - grub_be_to_cpu32 (head.bootblocksize);
+  data->cbfs_align = grub_be_to_cpu32 (head.align);
+
+  if (data->cbfs_start >= (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS))
+    goto fail;
+  if (data->cbfs_end > (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS))
+    data->cbfs_end = (grub_disk_get_size (disk) << GRUB_DISK_SECTOR_BITS);
+
+  data->next_hofs = data->cbfs_start;
+
+  if (grub_disk_read (disk, 0, data->cbfs_start, sizeof (hd), &hd))
+    goto fail;
+
+  if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (CBFS_FILE_MAGIC) - 1))
+    goto fail;
+
+  data->disk = disk;
+
+  return data;
+
+fail:
+  grub_error (GRUB_ERR_BAD_FS, "not a cbfs filesystem");
+  return 0;
+}
+
+static grub_err_t
+grub_cbfs_dir (grub_device_t device, const char *path_in,
+              grub_fs_dir_hook_t hook, void *hook_data)
+{
+  struct grub_archelp_data *data;
+  grub_err_t err;
+
+  data = grub_cbfs_mount (device->disk);
+  if (!data)
+    return grub_errno;
+
+  err = grub_archelp_dir (data, &arcops,
+                         path_in, hook, hook_data);
+
+  grub_free (data);
+
+  return err;
+}
+
+static grub_err_t
+grub_cbfs_open (grub_file_t file, const char *name_in)
+{
+  struct grub_archelp_data *data;
+  grub_err_t err;
+
+  data = grub_cbfs_mount (file->device->disk);
+  if (!data)
+    return grub_errno;
+
+  err = grub_archelp_open (data, &arcops, name_in);
+  if (err)
+    {
+      grub_free (data);
+    }
+  else
+    {
+      file->data = data;
+      file->size = data->size;
+    }
+  return err;
+}
+
+static grub_ssize_t
+grub_cbfs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+  struct grub_archelp_data *data;
+
+  data = file->data;
+  return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
+                         len, buf)) ? -1 : (grub_ssize_t) len;
+}
+
+static grub_err_t
+grub_cbfs_close (grub_file_t file)
+{
+  struct grub_archelp_data *data;
+
+  data = file->data;
+  grub_free (data);
+
+  return grub_errno;
+}
+
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL)
+
+static char *cbfsdisk_addr;
+static grub_off_t cbfsdisk_size = 0;
+
+static int
+grub_cbfsdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+                      grub_disk_pull_t pull)
+{
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
+  return hook ("cbfsdisk", hook_data);
+}
+
+static grub_err_t
+grub_cbfsdisk_open (const char *name, grub_disk_t disk)
+{
+  if (grub_strcmp (name, "cbfsdisk"))
+      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a cbfsdisk");
+
+  disk->total_sectors = cbfsdisk_size / GRUB_DISK_SECTOR_SIZE;
+  disk->id = (unsigned long) "cbfs";
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+grub_cbfsdisk_close (grub_disk_t disk __attribute((unused)))
+{
+}
+
+static grub_err_t
+grub_cbfsdisk_read (grub_disk_t disk __attribute((unused)),
+                   grub_disk_addr_t sector,
+                   grub_size_t size, char *buf)
+{
+  grub_memcpy (buf, cbfsdisk_addr + (sector << GRUB_DISK_SECTOR_BITS),
+              size << GRUB_DISK_SECTOR_BITS);
+  return 0;
+}
+
+static grub_err_t
+grub_cbfsdisk_write (grub_disk_t disk __attribute__ ((unused)),
+                    grub_disk_addr_t sector __attribute__ ((unused)),
+                    grub_size_t size __attribute__ ((unused)),
+                    const char *buf __attribute__ ((unused)))
+{
+  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                    "rom flashing isn't implemented yet");
+}
+
+static struct grub_disk_dev grub_cbfsdisk_dev =
+  {
+    .name = "cbfsdisk",
+    .id = GRUB_DISK_DEVICE_CBFSDISK_ID,
+    .iterate = grub_cbfsdisk_iterate,
+    .open = grub_cbfsdisk_open,
+    .close = grub_cbfsdisk_close,
+    .read = grub_cbfsdisk_read,
+    .write = grub_cbfsdisk_write,
+    .next = 0
+  };
+
+static void
+init_cbfsdisk (void)
+{
+  grub_uint32_t ptr;
+  struct cbfs_header *head;
+
+  ptr = *(grub_uint32_t *) 0xfffffffc;
+  head = (struct cbfs_header *) ptr;
+
+  if (!validate_head (head))
+    return;
+
+  cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (head->romsize),
+                           GRUB_DISK_SECTOR_SIZE);
+  cbfsdisk_addr = (void *) (grub_addr_t) (0x100000000ULL - cbfsdisk_size);
+
+  grub_disk_dev_register (&grub_cbfsdisk_dev);
+}
+
+static void
+fini_cbfsdisk (void)
+{
+  if (! cbfsdisk_size)
+    return;
+  grub_disk_dev_unregister (&grub_cbfsdisk_dev);
+}
+
+#endif
+
+static struct grub_fs grub_cbfs_fs = {
+  .name = "cbfs",
+  .dir = grub_cbfs_dir,
+  .open = grub_cbfs_open,
+  .read = grub_cbfs_read,
+  .close = grub_cbfs_close,
+#ifdef GRUB_UTIL
+  .reserved_first_sector = 0,
+  .blocklist_install = 0,
+#endif
+};
+
+GRUB_MOD_INIT (cbfs)
+{
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL)
+  init_cbfsdisk ();
+#endif
+  grub_fs_register (&grub_cbfs_fs);
+}
+
+GRUB_MOD_FINI (cbfs)
+{
+  grub_fs_unregister (&grub_cbfs_fs);
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL)
+  fini_cbfsdisk ();
+#endif
+}
index 628680d2346832a089b6bfa353c9306d55572eda..b14e190f924cebb6602592941eb5805895ac9ed9 100644 (file)
@@ -53,7 +53,6 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
 GRUB_MOD_INIT (cpio)
 {
   grub_fs_register (&grub_cpio_fs);
-  my_mod = mod;
 }
 
 GRUB_MOD_FINI (cpio)
index 40894b97ea30cb3dc915dcf77948a465a889f7f3..83df8195b5ba0f40249d4c6b056a8b22f617cdf7 100644 (file)
@@ -53,7 +53,6 @@ read_number (const grub_uint16_t *arr, grub_size_t size)
 GRUB_MOD_INIT (cpio_be)
 {
   grub_fs_register (&grub_cpio_fs);
-  my_mod = mod;
 }
 
 GRUB_MOD_FINI (cpio_be)
index ee1bc4e9c2b8dcf40594ae91eaf1edcc47518aa8..370324ceb53169ef08626e70cbdac8c2f5fc8c50 100644 (file)
 #include <grub/disk.h>
 #include <grub/dl.h>
 #include <grub/i18n.h>
+#include <grub/archelp.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-#define ATTR_TYPE  0160000
-#define ATTR_FILE  0100000
-#define ATTR_DIR   0040000
-#define ATTR_LNK   0120000
-
-struct grub_cpio_data
+struct grub_archelp_data
 {
   grub_disk_t disk;
   grub_off_t hofs;
+  grub_off_t next_hofs;
   grub_off_t dofs;
   grub_off_t size;
-#ifdef MODE_USTAR
-  char *linkname;
-  grub_size_t linkname_alloc;
-#endif
 };
 
-static grub_dl_t my_mod;
-
-static inline void
-canonicalize (char *name)
-{
-  char *iptr, *optr;
-  for (iptr = name, optr = name; *iptr; )
-    {
-      while (*iptr == '/')
-       iptr++;
-      if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
-       {
-         iptr += 2;
-         continue;
-       }
-      if (iptr[0] == '.' && iptr[1] == '.' && (iptr[2] == '/' || iptr[2] == 0))
-       {
-         iptr += 3;
-         if (optr == name)
-           continue;
-         for (optr -= 2; optr >= name && *optr != '/'; optr--);
-         optr++;
-         continue;
-       }
-      while (*iptr && *iptr != '/')
-       *optr++ = *iptr++;
-      if (*iptr)
-       *optr++ = *iptr++;
-    }
-  *optr = 0;
-}
-
 static grub_err_t
-grub_cpio_find_file (struct grub_cpio_data *data, char **name,
-                    grub_int32_t *mtime, grub_disk_addr_t *ofs,
-                    grub_uint32_t *mode)
+grub_cpio_find_file (struct grub_archelp_data *data, char **name,
+                    grub_int32_t *mtime, grub_uint32_t *mode)
 {
-#ifndef MODE_USTAR
   struct head hd;
   grub_size_t namesize;
   grub_uint32_t modeval;
 
+  data->hofs = data->next_hofs;
+
   if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
     return grub_errno;
 
@@ -118,153 +79,57 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
   if (data->size == 0 && modeval == 0 && namesize == 11
       && grub_memcmp(*name, "TRAILER!!!", 11) == 0)
     {
-      *ofs = 0;
+      *mode = GRUB_ARCHELP_ATTR_END;
       grub_free (*name);
       return GRUB_ERR_NONE;
     }
 
-  canonicalize (*name);
-
   data->dofs = data->hofs + ALIGN_CPIO (sizeof (hd) + namesize);
-  *ofs = data->dofs + ALIGN_CPIO (data->size);
-#else
-  struct head hd;
-  int reread = 0, have_longname = 0, have_longlink = 0;
+  data->next_hofs = data->dofs + ALIGN_CPIO (data->size);
+  return GRUB_ERR_NONE;
+}
+
+static char *
+grub_cpio_get_link_target (struct grub_archelp_data *data)
+{
+  char *ret;
+  grub_err_t err;
+
+  if (data->size == 0)
+    return grub_strdup ("");
+  ret = grub_malloc (data->size + 1);
+  if (!ret)
+    return NULL;
 
-  for (reread = 0; reread < 3; reread++)
+  err = grub_disk_read (data->disk, 0, data->dofs, data->size, 
+                       ret);
+  if (err)
     {
-      if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
-       return grub_errno;
-
-      if (!hd.name[0] && !hd.prefix[0])
-       {
-         *ofs = 0;
-         return GRUB_ERR_NONE;
-       }
-
-      if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
-       return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
-
-      if (hd.typeflag == 'L')
-       {
-         grub_err_t err;
-         grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
-         *name = grub_malloc (namesize + 1);
-         if (*name == NULL)
-           return grub_errno;
-         err = grub_disk_read (data->disk, 0,
-                               data->hofs + GRUB_DISK_SECTOR_SIZE, namesize,
-                               *name);
-         (*name)[namesize] = 0;
-         if (err)
-           return err;
-         data->hofs += GRUB_DISK_SECTOR_SIZE
-           + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) &
-              ~(GRUB_DISK_SECTOR_SIZE - 1));
-         have_longname = 1;
-         continue;
-       }
-
-      if (hd.typeflag == 'K')
-       {
-         grub_err_t err;
-         grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
-         if (data->linkname_alloc < linksize + 1)
-           {
-             char *n;
-             n = grub_malloc (2 * (linksize + 1));
-             if (!n)
-               return grub_errno;
-             grub_free (data->linkname);
-             data->linkname = n;
-             data->linkname_alloc = 2 * (linksize + 1);
-           }
-
-         err = grub_disk_read (data->disk, 0,
-                               data->hofs + GRUB_DISK_SECTOR_SIZE, linksize,
-                               data->linkname);
-         if (err)
-           return err;
-         data->linkname[linksize] = 0;
-         data->hofs += GRUB_DISK_SECTOR_SIZE
-           + ((linksize + GRUB_DISK_SECTOR_SIZE - 1) &
-              ~(GRUB_DISK_SECTOR_SIZE - 1));
-         have_longlink = 1;
-         continue;
-       }
-
-      if (!have_longname)
-       {
-         grub_size_t extra_size = 0;
-
-         while (extra_size < sizeof (hd.prefix)
-                && hd.prefix[extra_size])
-           extra_size++;
-         *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
-         if (*name == NULL)
-           return grub_errno;
-         if (hd.prefix[0])
-           {
-             grub_memcpy (*name, hd.prefix, extra_size);
-             (*name)[extra_size++] = '/';
-           }
-         grub_memcpy (*name + extra_size, hd.name, sizeof (hd.name));
-         (*name)[extra_size + sizeof (hd.name)] = 0;
-       }
-
-      data->size = read_number (hd.size, sizeof (hd.size));
-      data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
-      *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
-                          ~(GRUB_DISK_SECTOR_SIZE - 1));
-      if (mtime)
-       *mtime = read_number (hd.mtime, sizeof (hd.mtime));
-      if (mode)
-       {
-         *mode = read_number (hd.mode, sizeof (hd.mode));
-         switch (hd.typeflag)
-           {
-             /* Hardlink.  */
-           case '1':
-             /* Symlink.  */
-           case '2':
-             *mode |= ATTR_LNK;
-             break;
-           case '0':
-             *mode |= ATTR_FILE;
-             break;
-           case '5':
-             *mode |= ATTR_DIR;
-             break;
-           }
-       }
-      if (!have_longlink)
-       {
-         if (data->linkname_alloc < 101)
-           {
-             char *n;
-             n = grub_malloc (101);
-             if (!n)
-               return grub_errno;
-             grub_free (data->linkname);
-             data->linkname = n;
-             data->linkname_alloc = 101;
-           }
-         grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname));
-         data->linkname[100] = 0;
-       }
-
-      canonicalize (*name);
-      return GRUB_ERR_NONE;
+      grub_free (ret);
+      return NULL;
     }
-#endif
-  return GRUB_ERR_NONE;
+  ret[data->size] = '\0';
+  return ret;
 }
 
-static struct grub_cpio_data *
+static void
+grub_cpio_rewind (struct grub_archelp_data *data)
+{
+  data->next_hofs = 0;
+}
+
+static struct grub_archelp_ops arcops =
+  {
+    .find_file = grub_cpio_find_file,
+    .get_link_target = grub_cpio_get_link_target,
+    .rewind = grub_cpio_rewind
+  };
+
+static struct grub_archelp_data *
 grub_cpio_mount (grub_disk_t disk)
 {
   struct head hd;
-  struct grub_cpio_data *data;
+  struct grub_archelp_data *data;
 
   if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd))
     goto fail;
@@ -276,7 +141,7 @@ grub_cpio_mount (grub_disk_t disk)
       )
     goto fail;
 
-  data = (struct grub_cpio_data *) grub_zalloc (sizeof (*data));
+  data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data));
   if (!data)
     goto fail;
 
@@ -289,293 +154,52 @@ fail:
   return 0;
 }
 
-static grub_err_t
-handle_symlink (struct grub_cpio_data *data,
-               const char *fn, char **name,
-               grub_uint32_t mode, int *restart)
-{
-  grub_size_t flen;
-  char *target;
-#ifndef MODE_USTAR
-  grub_err_t err;
-#endif
-  char *ptr;
-  char *lastslash;
-  grub_size_t prefixlen;
-  char *rest;
-  grub_size_t size;
-
-  *restart = 0;
-
-  if ((mode & ATTR_TYPE) != ATTR_LNK)
-    return GRUB_ERR_NONE;
-  flen = grub_strlen (fn);
-  if (grub_memcmp (*name, fn, flen) != 0 
-      || ((*name)[flen] != 0 && (*name)[flen] != '/'))
-    return GRUB_ERR_NONE;
-  rest = *name + flen;
-  lastslash = rest;
-  if (*rest)
-    rest++;
-  while (lastslash >= *name && *lastslash != '/')
-    lastslash--;
-  if (lastslash >= *name)
-    prefixlen = lastslash - *name;
-  else
-    prefixlen = 0;
-
-  if (prefixlen)
-    prefixlen++;
-
-#ifdef MODE_USTAR
-  size = grub_strlen (data->linkname);
-#else
-  size = data->size;
-#endif
-  if (size == 0)
-    return GRUB_ERR_NONE;
-  target = grub_malloc (size + grub_strlen (*name) + 2);
-  if (!target)
-    return grub_errno;
-
-#ifdef MODE_USTAR
-  grub_memcpy (target + prefixlen, data->linkname, size);
-#else
-  err = grub_disk_read (data->disk, 0, data->dofs, data->size, 
-                       target + prefixlen);
-  if (err)
-    return err;
-#endif
-  if (target[prefixlen] == '/')
-    {
-      grub_memmove (target, target + prefixlen, size);
-      ptr = target + size;
-      ptr = grub_stpcpy (ptr, rest);
-      *ptr = 0;
-      grub_dprintf ("cpio", "symlink redirected %s to %s\n",
-                   *name, target);
-      grub_free (*name);
-
-      canonicalize (target);
-      *name = target;
-      *restart = 1;
-      return GRUB_ERR_NONE;
-    }
-  if (prefixlen)
-    {
-      grub_memcpy (target, *name, prefixlen);
-      target[prefixlen-1] = '/';
-    }
-  ptr = target + prefixlen + size;
-  ptr = grub_stpcpy (ptr, rest);
-  *ptr = 0;
-  grub_dprintf ("cpio", "symlink redirected %s to %s\n",
-               *name, target);
-  grub_free (*name);
-  canonicalize (target);
-  *name = target;
-  *restart = 1;
-  return GRUB_ERR_NONE;
-}
-
 static grub_err_t
 grub_cpio_dir (grub_device_t device, const char *path_in,
               grub_fs_dir_hook_t hook, void *hook_data)
 {
-  struct grub_cpio_data *data;
-  grub_disk_addr_t ofs;
-  char *prev, *name, *path, *ptr;
-  grub_size_t len;
-  int symlinknest = 0;
-
-  path = grub_strdup (path_in + 1);
-  if (!path)
-    return grub_errno;
-  canonicalize (path);
-  for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--)
-    *ptr = 0;
-
-  grub_dl_ref (my_mod);
-
-  prev = 0;
+  struct grub_archelp_data *data;
+  grub_err_t err;
 
   data = grub_cpio_mount (device->disk);
   if (!data)
-    {
-      grub_free (path);
-      return grub_errno;
-    }
-
-  len = grub_strlen (path);
-  data->hofs = 0;
-  while (1)
-    {
-      grub_int32_t mtime;
-      grub_uint32_t mode;
-      grub_err_t err;
-
-      if (grub_cpio_find_file (data, &name, &mtime, &ofs, &mode))
-       goto fail;
-
-      if (!ofs)
-       break;
-
-      if (grub_memcmp (path, name, len) == 0
-         && (name[len] == 0 || name[len] == '/' || len == 0))
-       {
-         char *p, *n;
-
-         n = name + len;
-         while (*n == '/')
-           n++;
-
-         p = grub_strchr (n, '/');
-         if (p)
-           *p = 0;
-
-         if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0)
-           {
-             struct grub_dirhook_info info;
-             grub_memset (&info, 0, sizeof (info));
-             info.dir = (p != NULL) || ((mode & ATTR_TYPE) == ATTR_DIR);
-             info.mtime = mtime;
-             info.mtimeset = 1;
-
-             if (hook (n, &info, hook_data))
-               {
-                 grub_free (name);
-                 goto fail;
-               }
-             grub_free (prev);
-             prev = name;
-           }
-         else
-           {
-             int restart = 0;
-             err = handle_symlink (data, name, &path, mode, &restart);
-             grub_free (name);
-             if (err)
-               goto fail;
-             if (restart)
-               {
-                 len = grub_strlen (path);
-                 if (++symlinknest == 8)
-                   {
-                     grub_error (GRUB_ERR_SYMLINK_LOOP,
-                                 N_("too deep nesting of symlinks"));
-                     goto fail;
-                   }
-                 ofs = 0;
-               }
-           }
-       }
-      else
-       grub_free (name);
-      data->hofs = ofs;
-    }
+    return grub_errno;
 
-fail:
+  err = grub_archelp_dir (data, &arcops,
+                         path_in, hook, hook_data);
 
-  grub_free (path);
-  grub_free (prev);
-#ifdef MODE_USTAR
-  grub_free (data->linkname);
-#endif
   grub_free (data);
 
-  grub_dl_unref (my_mod);
-
-  return grub_errno;
+  return err;
 }
 
 static grub_err_t
 grub_cpio_open (grub_file_t file, const char *name_in)
 {
-  struct grub_cpio_data *data;
-  grub_disk_addr_t ofs;
-  char *fn;
-  char *name = grub_strdup (name_in + 1);
-  int symlinknest = 0;
-
-  if (!name)
-    return grub_errno;
-
-  canonicalize (name);
-
-  grub_dl_ref (my_mod);
+  struct grub_archelp_data *data;
+  grub_err_t err;
 
   data = grub_cpio_mount (file->device->disk);
   if (!data)
+    return grub_errno;
+
+  err = grub_archelp_open (data, &arcops, name_in);
+  if (err)
     {
-      grub_free (name);
-      return grub_errno;
+      grub_free (data);
     }
-
-  data->hofs = 0;
-  while (1)
+  else
     {
-      grub_uint32_t mode;
-      int restart;
-      
-      if (grub_cpio_find_file (data, &fn, NULL, &ofs, &mode))
-       goto fail;
-
-      if (!ofs)
-       {
-         grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in);
-         break;
-       }
-
-      if (handle_symlink (data, fn, &name, mode, &restart))
-       {
-         grub_free (fn);
-         goto fail;
-       }
-
-      if (restart)
-       {
-         ofs = 0;
-         if (++symlinknest == 8)
-           {
-             grub_error (GRUB_ERR_SYMLINK_LOOP,
-                         N_("too deep nesting of symlinks"));
-             goto fail;
-           }
-         goto no_match;
-       }
-
-      if (grub_strcmp (name, fn) != 0)
-       goto no_match;
-
       file->data = data;
       file->size = data->size;
-      grub_free (fn);
-      grub_free (name);
-
-      return GRUB_ERR_NONE;
-
-    no_match:
-
-      grub_free (fn);
-      data->hofs = ofs;
     }
-
-fail:
-#ifdef MODE_USTAR
-  grub_free (data->linkname);
-#endif
-  grub_free (data);
-  grub_free (name);
-
-  grub_dl_unref (my_mod);
-
-  return grub_errno;
+  return err;
 }
 
 static grub_ssize_t
 grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
 {
-  struct grub_cpio_data *data;
+  struct grub_archelp_data *data;
 
   data = file->data;
   return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
@@ -585,16 +209,11 @@ grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
 static grub_err_t
 grub_cpio_close (grub_file_t file)
 {
-  struct grub_cpio_data *data;
+  struct grub_archelp_data *data;
 
   data = file->data;
-#ifdef MODE_USTAR
-  grub_free (data->linkname);
-#endif
   grub_free (data);
 
-  grub_dl_unref (my_mod);
-
   return grub_errno;
 }
 
index 0a911e5439e2a7308045887241d7cff340a32791..c7767ed3be59adfd37234b070ddd8846091b2fd7 100644 (file)
@@ -65,7 +65,6 @@ read_number (const char *str, grub_size_t size)
 GRUB_MOD_INIT (newc)
 {
   grub_fs_register (&grub_cpio_fs);
-  my_mod = mod;
 }
 
 GRUB_MOD_FINI (newc)
index 99e9cd62920ad73d33e78e625d2b486571fcb538..7b8a7220edd99f446b24c6729c705607886f1e4f 100644 (file)
@@ -20,6 +20,7 @@
 #include <grub/misc.h>
 
 #define ALIGN_CPIO(x) x
+
 #define        MAGIC   "070707"
 struct head
 {
@@ -52,7 +53,6 @@ read_number (const char *str, grub_size_t size)
 GRUB_MOD_INIT (odc)
 {
   grub_fs_register (&grub_cpio_fs);
-  my_mod = mod;
 }
 
 GRUB_MOD_FINI (odc)
index bf3ce8c3f7ea91b1db1dc6ea4312e76b5d5ab583..85382974ce26af27b155c719edab009af0b350bd 100644 (file)
  */
 
 #include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/archelp.h>
 
-#define MODE_USTAR 1
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
 
 /* tar support */
 #define MAGIC  "ustar"
@@ -52,14 +59,277 @@ read_number (const char *str, grub_size_t size)
   return ret;
 }
 
-#define FSNAME "tarfs"
+struct grub_archelp_data
+{
+  grub_disk_t disk;
+  grub_off_t hofs, next_hofs;
+  grub_off_t dofs;
+  grub_off_t size;
+  char *linkname;
+  grub_size_t linkname_alloc;
+};
+
+static grub_err_t
+grub_cpio_find_file (struct grub_archelp_data *data, char **name,
+                    grub_int32_t *mtime,
+                    grub_uint32_t *mode)
+{
+  struct head hd;
+  int reread = 0, have_longname = 0, have_longlink = 0;
+
+  data->hofs = data->next_hofs;
+
+  for (reread = 0; reread < 3; reread++)
+    {
+      if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
+       return grub_errno;
+
+      if (!hd.name[0] && !hd.prefix[0])
+       {
+         *mode = GRUB_ARCHELP_ATTR_END;
+         return GRUB_ERR_NONE;
+       }
+
+      if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
+       return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
+
+      if (hd.typeflag == 'L')
+       {
+         grub_err_t err;
+         grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
+         *name = grub_malloc (namesize + 1);
+         if (*name == NULL)
+           return grub_errno;
+         err = grub_disk_read (data->disk, 0,
+                               data->hofs + GRUB_DISK_SECTOR_SIZE, namesize,
+                               *name);
+         (*name)[namesize] = 0;
+         if (err)
+           return err;
+         data->hofs += GRUB_DISK_SECTOR_SIZE
+           + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) &
+              ~(GRUB_DISK_SECTOR_SIZE - 1));
+         have_longname = 1;
+         continue;
+       }
+
+      if (hd.typeflag == 'K')
+       {
+         grub_err_t err;
+         grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
+         if (data->linkname_alloc < linksize + 1)
+           {
+             char *n;
+             n = grub_malloc (2 * (linksize + 1));
+             if (!n)
+               return grub_errno;
+             grub_free (data->linkname);
+             data->linkname = n;
+             data->linkname_alloc = 2 * (linksize + 1);
+           }
+
+         err = grub_disk_read (data->disk, 0,
+                               data->hofs + GRUB_DISK_SECTOR_SIZE, linksize,
+                               data->linkname);
+         if (err)
+           return err;
+         data->linkname[linksize] = 0;
+         data->hofs += GRUB_DISK_SECTOR_SIZE
+           + ((linksize + GRUB_DISK_SECTOR_SIZE - 1) &
+              ~(GRUB_DISK_SECTOR_SIZE - 1));
+         have_longlink = 1;
+         continue;
+       }
+
+      if (!have_longname)
+       {
+         grub_size_t extra_size = 0;
+
+         while (extra_size < sizeof (hd.prefix)
+                && hd.prefix[extra_size])
+           extra_size++;
+         *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
+         if (*name == NULL)
+           return grub_errno;
+         if (hd.prefix[0])
+           {
+             grub_memcpy (*name, hd.prefix, extra_size);
+             (*name)[extra_size++] = '/';
+           }
+         grub_memcpy (*name + extra_size, hd.name, sizeof (hd.name));
+         (*name)[extra_size + sizeof (hd.name)] = 0;
+       }
+
+      data->size = read_number (hd.size, sizeof (hd.size));
+      data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
+      data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
+                          ~(GRUB_DISK_SECTOR_SIZE - 1));
+      if (mtime)
+       *mtime = read_number (hd.mtime, sizeof (hd.mtime));
+      if (mode)
+       {
+         *mode = read_number (hd.mode, sizeof (hd.mode));
+         switch (hd.typeflag)
+           {
+             /* Hardlink.  */
+           case '1':
+             /* Symlink.  */
+           case '2':
+             *mode |= GRUB_ARCHELP_ATTR_LNK;
+             break;
+           case '0':
+             *mode |= GRUB_ARCHELP_ATTR_FILE;
+             break;
+           case '5':
+             *mode |= GRUB_ARCHELP_ATTR_DIR;
+             break;
+           }
+       }
+      if (!have_longlink)
+       {
+         if (data->linkname_alloc < 101)
+           {
+             char *n;
+             n = grub_malloc (101);
+             if (!n)
+               return grub_errno;
+             grub_free (data->linkname);
+             data->linkname = n;
+             data->linkname_alloc = 101;
+           }
+         grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname));
+         data->linkname[100] = 0;
+       }
+      return GRUB_ERR_NONE;
+    }
+  return GRUB_ERR_NONE;
+}
+
+static char *
+grub_cpio_get_link_target (struct grub_archelp_data *data)
+{
+  return grub_strdup (data->linkname);
+}
+
+static void
+grub_cpio_rewind (struct grub_archelp_data *data)
+{
+  data->next_hofs = 0;
+}
+
+static struct grub_archelp_ops arcops =
+  {
+    .find_file = grub_cpio_find_file,
+    .get_link_target = grub_cpio_get_link_target,
+    .rewind = grub_cpio_rewind
+  };
+
+static struct grub_archelp_data *
+grub_cpio_mount (grub_disk_t disk)
+{
+  struct head hd;
+  struct grub_archelp_data *data;
+
+  if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd))
+    goto fail;
+
+  if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
+    goto fail;
+
+  data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data));
+  if (!data)
+    goto fail;
+
+  data->disk = disk;
+
+  return data;
+
+fail:
+  grub_error (GRUB_ERR_BAD_FS, "not a tarfs filesystem");
+  return 0;
+}
+
+static grub_err_t
+grub_cpio_dir (grub_device_t device, const char *path_in,
+              grub_fs_dir_hook_t hook, void *hook_data)
+{
+  struct grub_archelp_data *data;
+  grub_err_t err;
+
+  data = grub_cpio_mount (device->disk);
+  if (!data)
+    return grub_errno;
+
+  err = grub_archelp_dir (data, &arcops,
+                         path_in, hook, hook_data);
+
+  grub_free (data->linkname);
+  grub_free (data);
+
+  return err;
+}
+
+static grub_err_t
+grub_cpio_open (grub_file_t file, const char *name_in)
+{
+  struct grub_archelp_data *data;
+  grub_err_t err;
+
+  data = grub_cpio_mount (file->device->disk);
+  if (!data)
+    return grub_errno;
+
+  err = grub_archelp_open (data, &arcops, name_in);
+  if (err)
+    {
+      grub_free (data->linkname);
+      grub_free (data);
+    }
+  else
+    {
+      file->data = data;
+      file->size = data->size;
+    }
+  return err;
+}
+
+static grub_ssize_t
+grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
+{
+  struct grub_archelp_data *data;
+
+  data = file->data;
+  return (grub_disk_read (data->disk, 0, data->dofs + file->offset,
+                         len, buf)) ? -1 : (grub_ssize_t) len;
+}
+
+static grub_err_t
+grub_cpio_close (grub_file_t file)
+{
+  struct grub_archelp_data *data;
+
+  data = file->data;
+  grub_free (data->linkname);
+  grub_free (data);
+
+  return grub_errno;
+}
 
-#include "cpio_common.c"
+static struct grub_fs grub_cpio_fs = {
+  .name = "tarfs",
+  .dir = grub_cpio_dir,
+  .open = grub_cpio_open,
+  .read = grub_cpio_read,
+  .close = grub_cpio_close,
+#ifdef GRUB_UTIL
+  .reserved_first_sector = 0,
+  .blocklist_install = 0,
+#endif
+};
 
 GRUB_MOD_INIT (tar)
 {
   grub_fs_register (&grub_cpio_fs);
-  my_mod = mod;
 }
 
 GRUB_MOD_FINI (tar)
diff --git a/include/grub/archelp.h b/include/grub/archelp.h
new file mode 100644 (file)
index 0000000..2611d7f
--- /dev/null
@@ -0,0 +1,63 @@
+/* archelp.h -- Archive helper functions */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_ARCHELP_HEADER
+#define GRUB_ARCHELP_HEADER    1
+
+#include <grub/fs.h>
+#include <grub/file.h>
+
+typedef enum
+  {
+    GRUB_ARCHELP_ATTR_TYPE = 0160000,
+    GRUB_ARCHELP_ATTR_FILE = 0100000,
+    GRUB_ARCHELP_ATTR_DIR = 0040000,
+    GRUB_ARCHELP_ATTR_LNK = 0120000,
+    GRUB_ARCHELP_ATTR_NOTIME = 0x80000000,
+    GRUB_ARCHELP_ATTR_END = 0xffffffff
+  } grub_archelp_mode_t;
+
+struct grub_archelp_data;
+
+struct grub_archelp_ops
+{
+  grub_err_t
+  (*find_file) (struct grub_archelp_data *data, char **name,
+               grub_int32_t *mtime,
+               grub_archelp_mode_t *mode);
+
+  char *
+  (*get_link_target) (struct grub_archelp_data *data);
+
+  void
+  (*rewind) (struct grub_archelp_data *data);
+};
+
+grub_err_t
+grub_archelp_dir (struct grub_archelp_data *data,
+                 struct grub_archelp_ops *ops,
+                 const char *path_in,
+                 grub_fs_dir_hook_t hook, void *hook_data);
+
+grub_err_t
+grub_archelp_open (struct grub_archelp_data *data,
+                  struct grub_archelp_ops *ops,
+                  const char *name_in);
+
+#endif
diff --git a/include/grub/cbfs_core.h b/include/grub/cbfs_core.h
new file mode 100644 (file)
index 0000000..5067b6e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
+ * Copyright (C) 2012 Google, Inc.
+ * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ *
+ * This file is dual-licensed. You can choose between:
+ *   - The GNU GPL, version 2, as published by the Free Software Foundation
+ *   - The revised BSD license (without advertising clause)
+ *
+ * ---------------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ * ---------------------------------------------------------------------------
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ---------------------------------------------------------------------------
+ */
+
+#ifndef _CBFS_CORE_H_
+#define _CBFS_CORE_H_
+
+#include <grub/types.h>
+
+/** These are standard values for the known compression
+    alogrithms that coreboot knows about for stages and
+    payloads.  Of course, other CBFS users can use whatever
+    values they want, as long as they understand them. */
+
+#define CBFS_COMPRESS_NONE  0
+#define CBFS_COMPRESS_LZMA  1
+
+/** These are standard component types for well known
+    components (i.e - those that coreboot needs to consume.
+    Users are welcome to use any other value for their
+    components */
+
+#define CBFS_TYPE_STAGE      0x10
+#define CBFS_TYPE_PAYLOAD    0x20
+#define CBFS_TYPE_OPTIONROM  0x30
+#define CBFS_TYPE_BOOTSPLASH 0x40
+#define CBFS_TYPE_RAW        0x50
+#define CBFS_TYPE_VSA        0x51
+#define CBFS_TYPE_MBI        0x52
+#define CBFS_TYPE_MICROCODE  0x53
+#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
+#define CBFS_COMPONENT_CMOS_LAYOUT 0x01aa
+
+#define CBFS_HEADER_MAGIC  0x4F524243
+#define CBFS_HEADER_VERSION1 0x31313131
+#define CBFS_HEADER_VERSION2 0x31313132
+#define CBFS_HEADER_VERSION  CBFS_HEADER_VERSION2
+
+#define CBFS_HEADER_INVALID_ADDRESS    ((void*)(0xffffffff))
+
+/** this is the master cbfs header - it need to be located somewhere available
+    to bootblock (to load romstage).  Where it actually lives is up to coreboot.
+    On x86, a pointer to this header will live at 0xFFFFFFFC.
+    For other platforms, you need to define CONFIG_CBFS_HEADER_ROM_OFFSET */
+
+struct cbfs_header {
+       grub_uint32_t magic;
+       grub_uint32_t version;
+       grub_uint32_t romsize;
+       grub_uint32_t bootblocksize;
+       grub_uint32_t align;
+       grub_uint32_t offset;
+       grub_uint32_t architecture;
+       grub_uint32_t pad[1];
+} __attribute__((packed));
+
+/* "Unknown" refers to CBFS headers version 1,
+ * before the architecture was defined (i.e., x86 only).
+ */
+#define CBFS_ARCHITECTURE_UNKNOWN  0xFFFFFFFF
+#define CBFS_ARCHITECTURE_X86      0x00000001
+#define CBFS_ARCHITECTURE_ARMV7    0x00000010
+
+/** This is a component header - every entry in the CBFS
+    will have this header.
+
+    This is how the component is arranged in the ROM:
+
+    --------------   <- 0
+    component header
+    --------------   <- sizeof(struct component)
+    component name
+    --------------   <- offset
+    data
+    ...
+    --------------   <- offset + len
+*/
+
+#define CBFS_FILE_MAGIC "LARCHIVE"
+
+struct cbfs_file {
+       char magic[8];
+       grub_uint32_t len;
+       grub_uint32_t type;
+       grub_uint32_t checksum;
+       grub_uint32_t offset;
+} __attribute__((packed));
+
+/*** Component sub-headers ***/
+
+/* Following are component sub-headers for the "standard"
+   component types */
+
+/** This is the sub-header for stage components.  Stages are
+    loaded by coreboot during the normal boot process */
+
+struct cbfs_stage {
+       grub_uint32_t compression;  /** Compression type */
+       grub_uint64_t entry;  /** entry point */
+       grub_uint64_t load;   /** Where to load in memory */
+       grub_uint32_t len;          /** length of data to load */
+       grub_uint32_t memlen;      /** total length of object in memory */
+} __attribute__((packed));
+
+/** this is the sub-header for payload components.  Payloads
+    are loaded by coreboot at the end of the boot process */
+
+struct cbfs_payload_segment {
+       grub_uint32_t type;
+       grub_uint32_t compression;
+       grub_uint32_t offset;
+       grub_uint64_t load_addr;
+       grub_uint32_t len;
+       grub_uint32_t mem_len;
+} __attribute__((packed));
+
+struct cbfs_payload {
+       struct cbfs_payload_segment segments;
+};
+
+#define PAYLOAD_SEGMENT_CODE   0x45444F43
+#define PAYLOAD_SEGMENT_DATA   0x41544144
+#define PAYLOAD_SEGMENT_BSS    0x20535342
+#define PAYLOAD_SEGMENT_PARAMS 0x41524150
+#define PAYLOAD_SEGMENT_ENTRY  0x52544E45
+
+struct cbfs_optionrom {
+       grub_uint32_t compression;
+       grub_uint32_t len;
+} __attribute__((packed));
+
+#endif
index 8fa09a6dfdd1ce16b3f5ac8f9a7f26ebc8cc40ff..c91583dfda31baeac83d4f79179aab73d5ab0e39 100644 (file)
@@ -46,6 +46,7 @@ enum grub_disk_dev_id
     GRUB_DISK_DEVICE_ARCDISK_ID,
     GRUB_DISK_DEVICE_HOSTDISK_ID,
     GRUB_DISK_DEVICE_PROCFS_ID,
+    GRUB_DISK_DEVICE_CBFSDISK_ID
   };
 
 struct grub_disk;