]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Support odc, newc and bigendian cpio formats.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 23 Dec 2011 15:15:18 +0000 (16:15 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 23 Dec 2011 15:15:18 +0000 (16:15 +0100)
* Makefile.util.def (libgrubmods): Add odc.c, newc.c and cpio_be.c.
* grub-core/Makefile.core.def (newc): New module.
(odc): Likewise.
(cpio_be): Likewise.
* grub-core/fs/cpio.c (ALIGN_CPIO): New macro.
(MAGIC): Likewise.
(MAGIC2): Likewise.
(head) [MODE_ODC]: Adapt for the format.
(head) [MODE_NEWC]: Likewise.
(head) [!MODE_*]: Write fields of interest as arrays.
(MAGIC_USTAR): Removed.
(read_number) [MODE_NEWC]: Change to hex.
(read_number) [!MODE_*]: Parse binary arrays.
(grub_cpio_find_file): Factor out the code for better structure and
always use read_number.
(grub_cpio_mount): Use MAGIC and MAGIC2.
(grub_cpio_dir): Exit on first hook non-0 return.
(grub_cpio_fs) [MODE_ODC]: Set name to odc.
(grub_cpio_fs) [MODE_NEWC]: Set name to newc.
(GRUB_MOD_INIT) [MODE_ODC]: Set name to odc.
(GRUB_MOD_INIT) [MODE_NEWC]: Set name to newc.
(GRUB_MOD_FINI) [MODE_ODC]: Set name to odc.
(GRUB_MOD_FINI) [MODE_NEWC]: Set name to newc.
* grub-core/fs/newc.c: New file.
* grub-core/fs/odc.c: Likewise.
* grub-core/fs/cpio_be.c: Likewise.

ChangeLog
Makefile.util.def
grub-core/Makefile.core.def
grub-core/fs/cpio.c
grub-core/fs/cpio_be.c [new file with mode: 0644]
grub-core/fs/newc.c [new file with mode: 0644]
grub-core/fs/odc.c [new file with mode: 0644]

index 8a9e25f70187cf22a61621d115972aa6770faddd..220892a754bc849466d72407e30012dfb2ddf65c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2011-12-23  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Support odc, newc and bigendian cpio formats.
+
+       * Makefile.util.def (libgrubmods): Add odc.c, newc.c and cpio_be.c.
+       * grub-core/Makefile.core.def (newc): New module.
+       (odc): Likewise.
+       (cpio_be): Likewise.
+       * grub-core/fs/cpio.c (ALIGN_CPIO): New macro.
+       (MAGIC): Likewise.
+       (MAGIC2): Likewise.
+       (head) [MODE_ODC]: Adapt for the format.
+       (head) [MODE_NEWC]: Likewise.
+       (head) [!MODE_*]: Write fields of interest as arrays.
+       (MAGIC_USTAR): Removed.
+       (read_number) [MODE_NEWC]: Change to hex.
+       (read_number) [!MODE_*]: Parse binary arrays.
+       (grub_cpio_find_file): Factor out the code for better structure and
+       always use read_number.
+       (grub_cpio_mount): Use MAGIC and MAGIC2.
+       (grub_cpio_dir): Exit on first hook non-0 return.
+       (grub_cpio_fs) [MODE_ODC]: Set name to odc.
+       (grub_cpio_fs) [MODE_NEWC]: Set name to newc.
+       (GRUB_MOD_INIT) [MODE_ODC]: Set name to odc.
+       (GRUB_MOD_INIT) [MODE_NEWC]: Set name to newc.
+       (GRUB_MOD_FINI) [MODE_ODC]: Set name to odc.
+       (GRUB_MOD_FINI) [MODE_NEWC]: Set name to newc.
+       * grub-core/fs/newc.c: New file.
+       * grub-core/fs/odc.c: Likewise.
+       * grub-core/fs/cpio_be.c: Likewise.
+
 2011-12-23  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Fix handling of tar numbers occupying the whole field.
index b52b5db9cc0e76b9eb968db400e6d07a75d7f14d..6e026db7eab7ef8321c4737a6ae80a374701b630 100644 (file)
@@ -59,6 +59,9 @@ library = {
   common = grub-core/fs/bfs.c;
   common = grub-core/fs/btrfs.c;
   common = grub-core/fs/cpio.c;
+  common = grub-core/fs/cpio_be.c;
+  common = grub-core/fs/odc.c;
+  common = grub-core/fs/newc.c;
   common = grub-core/fs/ext2.c;
   common = grub-core/fs/fat.c;
   common = grub-core/fs/exfat.c;
index 218f3df641bb400b52cff6c0bf1901c351a55a09..e183f884cc1da8d70c0491f6c861d598d2e69628 100644 (file)
@@ -1014,6 +1014,21 @@ module = {
   common = fs/cpio.c;
 };
 
+module = {
+  name = cpio_be;
+  common = fs/cpio_be.c;
+};
+
+module = {
+  name = newc;
+  common = fs/newc.c;
+};
+
+module = {
+  name = odc;
+  common = fs/odc.c;
+};
+
 module = {
   name = ext2;
   common = fs/ext2.c;
index cfa1b555bb2a8931d27feb7590dae46c81036efd..3107d01944ac2c79ba036e2a279163e296e9b135 100644 (file)
@@ -30,28 +30,69 @@ GRUB_MOD_LICENSE ("GPLv3+");
 #define ATTR_DIR   0040000
 #define ATTR_LNK   0120000
 
-#ifndef MODE_USTAR
+#ifdef MODE_ODC
+#define ALIGN_CPIO(x) x
+#define        MAGIC   "070707"
+struct head
+{
+  char magic[6];
+  char dev[6];
+  char ino[6];
+  char mode[6];
+  char uid[6];
+  char gid[6];
+  char nlink[6];
+  char rdev[6];
+  char mtime[11];
+  char namesize[6];
+  char filesize[11];
+} __attribute__ ((packed));
+#elif defined (MODE_NEWC)
+#define ALIGN_CPIO(x) (ALIGN_UP ((x), 4))
+#define        MAGIC   "070701"
+#define        MAGIC2  "070702"
+struct head
+{
+  char magic[6];
+  char ino[8];
+  char mode[8];
+  char uid[8];
+  char gid[8];
+  char nlink[8];
+  char mtime[8];
+  char filesize[8];
+  char devmajor[8];
+  char devminor[8];
+  char rdevmajor[8];
+  char rdevminor[8];
+  char namesize[8];
+  char check[8];
+} __attribute__ ((packed));
+#elif !defined (MODE_USTAR)
 /* cpio support */
-#define        MAGIC_BCPIO     070707
+#define ALIGN_CPIO(x) (ALIGN_UP ((x), 2))
+#ifdef MODE_BIGENDIAN
+#define        MAGIC       "\x71\xc7"
+#else
+#define        MAGIC       "\xc7\x71"
+#endif
 struct head
 {
-  grub_uint16_t magic;
+  grub_uint16_t magic[1];
   grub_uint16_t dev;
   grub_uint16_t ino;
-  grub_uint16_t mode;
+  grub_uint16_t mode[1];
   grub_uint16_t uid;
   grub_uint16_t gid;
   grub_uint16_t nlink;
   grub_uint16_t rdev;
-  grub_uint16_t mtime_1;
-  grub_uint16_t mtime_2;
-  grub_uint16_t namesize;
-  grub_uint16_t filesize_1;
-  grub_uint16_t filesize_2;
+  grub_uint16_t mtime[2];
+  grub_uint16_t namesize[1];
+  grub_uint16_t filesize[2];
 } __attribute__ ((packed));
 #else
 /* tar support */
-#define MAGIC_USTAR    "ustar"
+#define MAGIC  "ustar"
 struct head
 {
   char name[100];
@@ -108,14 +149,48 @@ canonicalize (char *name)
   *optr = 0;
 }
 
+#if defined (MODE_ODC) || defined (MODE_USTAR)
 static inline unsigned long long
 read_number (const char *str, grub_size_t size)
 {
-  long long ret = 0;
+  unsigned long long ret = 0;
   while (size-- && *str >= '0' && *str <= '7')
-    ret = (ret << 3) | (*str++ & ~'0');
+    ret = (ret << 3) | (*str++ & 0xf);
   return ret;
 }
+#elif defined (MODE_NEWC)
+static inline unsigned long long
+read_number (const char *str, grub_size_t size)
+{
+  unsigned long long ret = 0;
+  while (size-- && grub_isxdigit (*str))
+    {
+      char dig = *str++;
+      if (dig >= '0' && dig <= '9')
+       dig &= 0xf;
+      else if (dig >= 'a' && dig <= 'f')
+       dig -= 'a' - 10;
+      else
+       dig -= 'A' - 10;
+      ret = (ret << 4) | (dig);
+    }
+  return ret;
+}
+#else
+static inline unsigned long long
+read_number (const grub_uint16_t *arr, grub_size_t size)
+{
+  long long ret = 0;
+#ifdef MODE_BIGENDIAN
+  while (size--)
+    ret = (ret << 16) | grub_be_to_cpu16 (*arr++);
+#else
+  while (size--)
+    ret = (ret << 16) | grub_le_to_cpu16 (*arr++);
+#endif
+  return ret;
+}
+#endif
 
 static grub_err_t
 grub_cpio_find_file (struct grub_cpio_data *data, char **name,
@@ -124,35 +199,40 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
 {
 #ifndef MODE_USTAR
   struct head hd;
+  grub_size_t namesize;
+  grub_uint32_t modeval;
 
   if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
     return grub_errno;
 
-  if (hd.magic != MAGIC_BCPIO)
+  if (grub_memcmp (hd.magic, MAGIC, sizeof (hd.magic)) != 0
+#ifdef MAGIC2
+      && grub_memcmp (hd.magic, MAGIC2, sizeof (hd.magic)) != 0
+#endif
+      )
     return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
-
-  data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
+  data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize));
   if (mtime)
-    *mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
-  if (mode)
-    *mode = hd.mode;
+    *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime));
+  modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode));
+  namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize));
 
-  if (hd.namesize & 1)
-    hd.namesize++;
+  if (mode)
+    *mode = modeval;
 
-  *name = grub_malloc (hd.namesize + 1);
+  *name = grub_malloc (namesize + 1);
   if (*name == NULL)
     return grub_errno;
 
   if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
-                     hd.namesize, *name))
+                     namesize, *name))
     {
       grub_free (*name);
       return grub_errno;
     }
-  (*name)[hd.namesize] = 0;
+  (*name)[namesize] = 0;
 
-  if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
+  if (data->size == 0 && modeval == 0 && namesize == 11
       && grub_memcmp(*name, "TRAILER!!!", 11) == 0)
     {
       *ofs = 0;
@@ -162,10 +242,8 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
 
   canonicalize (*name);
 
-  data->dofs = data->hofs + sizeof (hd) + hd.namesize;
-  *ofs = data->dofs + data->size;
-  if (data->size & 1)
-    (*ofs)++;
+  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;
@@ -181,7 +259,7 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
          return GRUB_ERR_NONE;
        }
 
-      if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
+      if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
        return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
 
       if (hd.typeflag == 'L')
@@ -293,12 +371,11 @@ grub_cpio_mount (grub_disk_t disk)
   if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd))
     goto fail;
 
-#ifndef MODE_USTAR
-  if (hd.magic != MAGIC_BCPIO)
-#else
-  if (grub_memcmp (hd.magic, MAGIC_USTAR,
-                  sizeof (MAGIC_USTAR) - 1))
+  if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1)
+#ifdef MAGIC2
+      && grub_memcmp (hd.magic, MAGIC2, sizeof (MAGIC2) - 1)
 #endif
+      )
     goto fail;
 
   data = (struct grub_cpio_data *) grub_zalloc (sizeof (*data));
@@ -469,7 +546,8 @@ grub_cpio_dir (grub_device_t device, const char *path_in,
              info.mtime = mtime;
              info.mtimeset = 1;
 
-             hook (n, &info);
+             if (hook (n, &info))
+               goto fail;
              grub_free (prev);
              prev = name;
            }
@@ -623,6 +701,10 @@ grub_cpio_close (grub_file_t file)
 static struct grub_fs grub_cpio_fs = {
 #ifdef MODE_USTAR
   .name = "tarfs",
+#elif defined (MODE_ODC)
+  .name = "odc",
+#elif defined (MODE_NEWC)
+  .name = "newc",
 #else
   .name = "cpiofs",
 #endif
@@ -637,6 +719,10 @@ static struct grub_fs grub_cpio_fs = {
 
 #ifdef MODE_USTAR
 GRUB_MOD_INIT (tar)
+#elif defined (MODE_ODC)
+GRUB_MOD_INIT (odc)
+#elif defined (MODE_NEWC)
+GRUB_MOD_INIT (newc)
 #else
 GRUB_MOD_INIT (cpio)
 #endif
@@ -647,6 +733,10 @@ GRUB_MOD_INIT (cpio)
 
 #ifdef MODE_USTAR
 GRUB_MOD_FINI (tar)
+#elif defined (MODE_ODC)
+GRUB_MOD_FINI (odc)
+#elif defined (MODE_NEWC)
+GRUB_MOD_FINI (newc)
 #else
 GRUB_MOD_FINI (cpio)
 #endif
diff --git a/grub-core/fs/cpio_be.c b/grub-core/fs/cpio_be.c
new file mode 100644 (file)
index 0000000..8bad314
--- /dev/null
@@ -0,0 +1,2 @@
+#define MODE_BIGENDIAN 1
+#include "cpio.c"
diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c
new file mode 100644 (file)
index 0000000..fdcc160
--- /dev/null
@@ -0,0 +1,2 @@
+#define MODE_NEWC 1
+#include "cpio.c"
diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c
new file mode 100644 (file)
index 0000000..5fa88e3
--- /dev/null
@@ -0,0 +1,2 @@
+#define MODE_ODC 1
+#include "cpio.c"