]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Half boot time on pi when using standalone by using greffs phcoder/greffs
authorVladimir Serbinenko <phcoder@gmail.com>
Sun, 22 Dec 2013 20:17:54 +0000 (21:17 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sun, 22 Dec 2013 20:17:54 +0000 (21:17 +0100)
Makefile.util.def
grub-core/Makefile.core.def
grub-core/fs/greffs.c [new file with mode: 0644]
include/grub/greffs.h [new file with mode: 0644]
util/grub-mkstandalone.c

index 27c48e5f88ab525d49028bb530669b8dd43db8b4..d9f7e64895221f17b0d497b06faf708b0bc10210 100644 (file)
@@ -119,6 +119,7 @@ library = {
   common = grub-core/fs/sfs.c;
   common = grub-core/fs/squash4.c;
   common = grub-core/fs/tar.c;
+  common = grub-core/fs/greffs.c;
   common = grub-core/fs/udf.c;
   common = grub-core/fs/ufs2.c;
   common = grub-core/fs/ufs.c;
index e5e558c996ccea6fafa7ac648fdfa6e2c6084954..da3a59982c10b663cca4c485625f3eda09fab353 100644 (file)
@@ -1399,6 +1399,11 @@ module = {
   common = fs/tar.c;
 };
 
+module = {
+  name = greffs;
+  common = fs/greffs.c;
+};
+
 module = {
   name = udf;
   common = fs/udf.c;
diff --git a/grub-core/fs/greffs.c b/grub-core/fs/greffs.c
new file mode 100644 (file)
index 0000000..2cc4efb
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/greffs.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_greffs_data
+{
+  grub_uint32_t dofs;
+};
+
+static grub_err_t
+get_string (grub_disk_t disk,
+           const struct grub_greffs_header *head,
+           grub_uint32_t fn,
+           char **buf, grub_size_t *size)
+{
+  grub_uint32_t desc[2];
+  grub_size_t read_size;
+
+  if (grub_disk_read (disk, 0,
+                     grub_cpu_to_le32 (head->string_ptrs_offset)
+                     + fn * sizeof (desc[0]), sizeof (desc), &desc))
+    return grub_errno;
+  read_size = desc[1] - desc[0];
+  if (*size < read_size + 1)
+    {
+      grub_free (*buf);
+      *size = (read_size + 4) * 2;
+      *buf = grub_malloc (*size);
+      if (!*buf)
+       {
+         *size = 0;
+         return grub_errno;
+       }
+    }
+  if (grub_disk_read (disk, 0, desc[0], read_size, *buf))
+    return grub_errno;
+  (*buf)[read_size] = '\0';
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+find_file (grub_disk_t disk,
+          struct grub_greffs_header *head,
+          const char *name_in, grub_uint32_t *f, int exact)
+{
+  grub_uint32_t num_files, cur_file = 0;
+  int i;
+  char *buf = NULL;
+  grub_size_t buf_size = 0;
+  grub_err_t err;
+
+  num_files = grub_le_to_cpu32 (head->nfiles);
+
+  for (i = 31; i >= 0; i--)
+    {
+      int cmp;
+      if ((cur_file | (1 << i)) > num_files)
+       continue;
+      err = get_string (disk, head, (cur_file | (1 << i)) - 1, &buf, &buf_size);
+      if (err)
+       {
+         grub_free (buf);
+         return err;
+       }
+      cmp = grub_strcmp (buf, name_in);
+      if (cmp <= 0)
+       cur_file |= (1 << i);
+      if (cmp == 0)
+       {
+         grub_free (buf);
+         *f = cur_file - 1;
+         return GRUB_ERR_NONE;
+       }
+    }
+
+  grub_free (buf);
+  if (!exact)
+    {
+      *f = cur_file;
+      return GRUB_ERR_NONE;
+    }
+  return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
+                    name_in);
+}
+
+static char *
+canonicalize (const char *name_in, int make_dir)
+{
+  const char *iptr;
+  char *out, *optr;
+  out = grub_malloc (grub_strlen (name_in) + 2);
+  if (!out)
+    return NULL;
+  for (iptr = name_in, optr = out; *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 == out)
+           continue;
+         for (optr -= 2; optr >= out && *optr != '/'; optr--);
+         optr++;
+         continue;
+       }
+      while (*iptr && *iptr != '/')
+       *optr++ = *iptr++;
+      if (*iptr)
+       *optr++ = *iptr++;
+      else if (make_dir && optr != out)
+       *optr++ = '/';
+    }
+  *optr = 0;
+  return out;
+}
+
+static grub_err_t
+grub_greffs_dir (grub_device_t device, const char *path_in,
+              grub_fs_dir_hook_t hook, void *hook_data)
+{
+  grub_err_t err;
+  grub_uint32_t cur_file, num_files;
+  char *buf = 0;
+  grub_size_t buf_size = 0;
+  char *can;
+  grub_size_t len;
+  struct grub_greffs_header head;
+
+  if (grub_disk_read (device->disk, 0, 0, sizeof (head), &head))
+    return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem");
+
+  if (grub_memcmp (head.magic, GRUB_GREFFS_MAGIC, sizeof (head.magic)) != 0)
+    return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem");
+
+  can = canonicalize (path_in, 1);
+  if (!can)
+    return grub_errno;
+
+  if (can[0] == '\0')
+    cur_file = 0;
+  else
+    {
+      err = find_file (device->disk, &head, can, &cur_file, 0);
+      if (err)
+       goto fail;
+    }
+
+  num_files = grub_le_to_cpu32 (head.nfiles);
+
+  len = grub_strlen (can);
+
+  while (cur_file < num_files)
+    {
+      char *p, *n;
+      struct grub_dirhook_info info;
+
+      err = get_string (device->disk, &head, cur_file, &buf, &buf_size);
+      if (err)
+       goto fail;
+      if (grub_memcmp (can, buf, len) != 0)
+       break;
+      grub_memset (&info, 0, sizeof (info));
+
+      n = buf + len;
+      while (*n == '/')
+       n++;
+
+      p = grub_strchr (n, '/');
+      if (p)
+       *p = 0;
+      info.dir = (p != NULL);
+      if (hook (n, &info, hook_data))
+       goto fail;
+      if (!p)
+       cur_file++;
+      else
+       {
+         *p = '/' + 1;
+         p[1] = '\0';
+         err = find_file (device->disk, &head, buf, &cur_file, 0);
+         if (err)
+           goto fail;
+       }       
+    }
+
+ fail:
+  grub_free (buf);
+  grub_free (can);
+  return grub_errno;
+}
+
+
+static grub_err_t
+grub_greffs_open (grub_file_t file, const char *name_in)
+{
+  struct grub_greffs_header head;
+  struct grub_greffs_data *data;
+  struct grub_greffs_inode inode;
+  grub_err_t err;
+  grub_uint32_t cur_file;
+  char *can;
+
+  if (grub_disk_read (file->device->disk, 0, 0, sizeof (head), &head))
+    return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem");
+
+  if (grub_memcmp (head.magic, GRUB_GREFFS_MAGIC, sizeof (head.magic)) != 0)
+    return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem");
+
+  can = canonicalize (name_in, 0);
+  if (!can)
+    return grub_errno;
+
+  err = find_file (file->device->disk, &head, can, &cur_file, 1);
+  grub_free (can);
+  if (err)
+    return err;
+
+  data = grub_malloc (sizeof (*data));
+  if (!data)
+    return grub_errno;
+  if (grub_disk_read (file->device->disk,
+                     0, grub_le_to_cpu32 (head.inodes_offset)
+                     + sizeof (inode) * cur_file, sizeof (inode), &inode))
+    return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem");
+
+  data->dofs = grub_cpu_to_le32 (inode.start);
+  file->size = grub_cpu_to_le32 (inode.size);
+
+  file->data = data;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+grub_greffs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+  struct grub_greffs_data *data;
+  grub_ssize_t ret;
+
+  data = file->data;
+
+  file->device->disk->read_hook = file->read_hook;
+  file->device->disk->read_hook_data = file->read_hook_data;
+  ret = (grub_disk_read (file->device->disk, 0, data->dofs + file->offset,
+                        len, buf)) ? -1 : (grub_ssize_t) len;
+  file->device->disk->read_hook = 0;
+
+  return ret;
+}
+
+static grub_err_t
+grub_greffs_close (grub_file_t file)
+{
+  struct grub_greffs_data *data;
+
+  data = file->data;
+  grub_free (data);
+
+  return grub_errno;
+}
+
+static struct grub_fs grub_greffs_fs = {
+  .name = "greffs",
+  .dir = grub_greffs_dir,
+  .open = grub_greffs_open,
+  .read = grub_greffs_read,
+  .close = grub_greffs_close,
+#ifdef GRUB_UTIL
+  .reserved_first_sector = 0,
+  .blocklist_install = 0,
+#endif
+};
+
+GRUB_MOD_INIT (greffs)
+{
+  grub_fs_register (&grub_greffs_fs);
+}
+
+GRUB_MOD_FINI (greffs)
+{
+  grub_fs_unregister (&grub_greffs_fs);
+}
diff --git a/include/grub/greffs.h b/include/grub/greffs.h
new file mode 100644 (file)
index 0000000..6d54bae
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  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_GREFFS_HEADER
+#define GRUB_GREFFS_HEADER     1
+
+#include <grub/types.h>
+
+/*
+  Layout:
+  header
+  grub_uint32_t[] pointers to names
+  inodes
+  names
+  contents.
+  Everything is little-endian.
+ */
+
+struct grub_greffs_header
+{
+  char magic[4];
+#define GRUB_GREFFS_MAGIC "gref"
+  grub_uint32_t nfiles;
+  /* must be divisible by 4.  */
+  grub_uint32_t inodes_offset;
+  /* must be divisible by 4.  */
+  grub_uint32_t string_ptrs_offset;
+};
+
+struct grub_greffs_inode
+{
+  grub_uint32_t start;
+  grub_uint32_t size;
+  grub_uint32_t mtime;
+  /* Currently always 0. If we ever need symlinks,
+     it could be added.  */
+  grub_uint32_t type;
+};
+
+#endif
index 8e2a2b8c27a0fd84cc438c790a49f653369c7165..c7dd0547789f1835e2d6baf648b58bdca63065b7 100644 (file)
@@ -21,6 +21,7 @@
 #include <grub/util/install.h>
 #include <grub/util/misc.h>
 #include <grub/emu/config.h>
+#include <grub/greffs.h>
 
 #include <string.h>
 
@@ -34,7 +35,6 @@ static char *output_image;
 static char **files;
 static int nfiles;
 const struct grub_install_image_target_desc *format;
-static FILE *memdisk;
 
 enum
   {
@@ -116,91 +116,56 @@ struct argp argp = {
   NULL, help_filter, NULL
 };
 
-/* tar support */
-#define MAGIC  "ustar"
-struct head
+struct file_desc
 {
-  char name[100];
-  char mode[8];
-  char uid[8];
-  char gid[8];
-  char size[12];
-  char mtime[12];
-  char chksum[8];
-  char typeflag;
-  char linkname[100];
-  char magic[6];
-  char version[2];
-  char uname[32];
-  char gname[32];
-  char devmajor[8];
-  char devminor[8];
-  char prefix[155];
-  char pad[12];
-} GRUB_PACKED;
-
-static void
-write_zeros (unsigned rsz)
-{
-  char buf[512];
-
-  memset (buf, 0, 512);
-  fwrite (buf, 1, rsz, memdisk);
-}
-
-static void
-write_pad (unsigned sz)
-{
-  write_zeros ((~sz + 1) & 511);
-}
-
-static void
-set_tar_value (char *field, grub_uint32_t val,
-              unsigned len)
-{
-  unsigned i;
-  for (i = 0; i < len - 1; i++)
-    field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7);
-}
+  char *name;
+  char *source;
+  grub_size_t size;
+  grub_size_t mtime;
+};
+static struct file_desc *file_descs;
+static size_t n_file_descs, alloc_file_descs;
 
-static void
-compute_checksum (struct head *hd)
+static inline void
+canonicalize (char *name)
 {
-  unsigned int chk = 0;
-  unsigned char *ptr;
-  memset (hd->chksum, ' ', 8);
-  for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++)
-    chk += *ptr;
-  set_tar_value (hd->chksum, chk, 8);
+  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 void
 add_tar_file (const char *from,
              const char *to)
 {
-  char *tcn;
-  const char *iptr;
-  char *optr;
-  struct head hd;
   grub_util_fd_t in;
-  ssize_t r;
-  grub_uint32_t mtime = 0;
-  grub_uint32_t size;
-
-  COMPILE_TIME_ASSERT (sizeof (hd) == 512);
+  size_t idx;
 
   if (grub_util_is_special_file (from))
     return;
 
-  mtime = grub_util_get_mtime (from);
-
-  optr = tcn = xmalloc (strlen (to) + 1);
-  for (iptr = to; *iptr == '/'; iptr++);
-  for (; *iptr; iptr++)
-    if (!(iptr[0] == '/' && iptr[1] == '/'))
-      *optr++ = *iptr;
-  *optr = '\0';
-
   if (grub_util_is_directory (from))
     {
       grub_util_fd_dir_t d;
@@ -221,69 +186,138 @@ add_tar_file (const char *from,
          free (fp);
        }
       grub_util_fd_closedir (d);
-      free (tcn);
       return;
     }
 
-  if (optr - tcn > 99)
+  idx = n_file_descs++;
+  if (idx >= alloc_file_descs)
     {
-      memset (&hd, 0, sizeof (hd));
-      memcpy (hd.name, tcn, 99);
-      memcpy (hd.mode, "0000600", 7);
-      memcpy (hd.uid, "0001750", 7);
-      memcpy (hd.gid, "0001750", 7);
-
-      set_tar_value (hd.size, optr - tcn, 12);
-      set_tar_value (hd.mtime, mtime, 12);
-      hd.typeflag = 'L';
-      memcpy (hd.magic, "ustar  ", 7);
-      memcpy (hd.uname, "grub", 4);
-      memcpy (hd.gname, "grub", 4);
-
-      compute_checksum (&hd);
-
-      fwrite (&hd, 1, sizeof (hd), memdisk);
-      fwrite (tcn, 1, optr - tcn, memdisk);
-
-      write_pad (optr - tcn);
+      alloc_file_descs = 2 * n_file_descs;
+      file_descs = xrealloc (file_descs, alloc_file_descs
+                            * sizeof (file_descs[0]));
     }
 
   in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY);
   if (!GRUB_UTIL_FD_IS_VALID (in))
     grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ());
 
-  if (!grub_install_copy_buffer)
-    grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
+  file_descs[idx].name = xstrdup (to);
+  file_descs[idx].source = xstrdup (from);
+  canonicalize (file_descs[idx].name);
+  file_descs[idx].mtime = grub_util_get_mtime (from);
+  file_descs[idx].size = grub_util_get_fd_size (in, from, NULL);
+
+  grub_util_fd_close (in);
+}
 
-  size = grub_util_get_fd_size (in, from, NULL);
+static int
+filecmp (const void *p1, const void *p2)
+{
+  const struct file_desc *a = p1, *b = p2;
 
-  memset (&hd, 0, sizeof (hd));
-  memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99);
-  memcpy (hd.mode, "0000600", 7);
-  memcpy (hd.uid, "0001750", 7);
-  memcpy (hd.gid, "0001750", 7);
+  /* Don't use strcmp, it's buggy on some systems.  */
+  return grub_strcmp (a->name, b->name);
+}
 
-  set_tar_value (hd.size, size, 12);
-  set_tar_value (hd.mtime, mtime, 12);
-  hd.typeflag = '0';
-  memcpy (hd.magic, "ustar  ", 7);
-  memcpy (hd.uname, "grub", 4);
-  memcpy (hd.gname, "grub", 4);
+static void
+write_memdisk (char *memdisk_img)
+{
+  FILE *memdisk;
+  struct grub_greffs_header head;
+  struct grub_greffs_inode inode;
+  size_t total_strlen = 0, i;
+  size_t name_pad = 0;
+  grub_uint32_t file_offset;
+
+  qsort (file_descs, n_file_descs, sizeof (file_descs[0]), filecmp);
+
+  for (i = 0; i < n_file_descs; i++)
+    total_strlen += grub_strlen (file_descs[i].name);
+  name_pad = ALIGN_UP (total_strlen, 4) - total_strlen;
+  total_strlen += name_pad;
+
+  grub_memcpy (head.magic, GRUB_GREFFS_MAGIC, sizeof (head.magic));
+  head.nfiles = grub_cpu_to_le32 (n_file_descs);
+  head.inodes_offset = grub_cpu_to_le32 (sizeof (head)
+                                        + sizeof (grub_uint32_t)
+                                        * (n_file_descs + 1));
+  head.string_ptrs_offset = grub_cpu_to_le32 (sizeof (head));
 
-  compute_checksum (&hd);
+  memdisk = grub_util_fopen (memdisk_img, "wb");
+  if (!memdisk)
+    grub_util_error (_("Can't create file: %s"), strerror (errno));
 
-  fwrite (&hd, 1, sizeof (hd), memdisk);
-  while (1)
+  fwrite (&head, 1, sizeof (head), memdisk);
+
+  grub_uint32_t curname = sizeof (head) + sizeof (grub_uint32_t)
+    * (n_file_descs + 1) + sizeof (inode) * n_file_descs;
+  for (i = 0; i <= n_file_descs; i++)
     {
-      r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
-      if (r <= 0)
-       break;
-      fwrite (grub_install_copy_buffer, 1, r, memdisk);
+      grub_uint32_t curname_le = grub_cpu_to_le32 (curname);
+      fwrite (&curname_le, 1, sizeof (curname_le), memdisk);
+      if (i != n_file_descs)
+       curname += grub_strlen (file_descs[i].name);
     }
-  grub_util_fd_close (in);
 
-  write_pad (size);
+  file_offset = sizeof (head) + sizeof (grub_uint32_t)
+    * (n_file_descs + 1) + sizeof (inode) * n_file_descs + total_strlen;
+  for (i = 0; i < n_file_descs; i++)
+    {
+      inode.start = grub_cpu_to_le32 (file_offset);
+      inode.size = grub_cpu_to_le32 (file_descs[i].size);
+      inode.mtime = grub_cpu_to_le32 (file_descs[i].mtime);
+      inode.type = 0;
+      fwrite (&inode, 1, sizeof (inode), memdisk);
+      file_offset += file_descs[i].size;
+    }
+
+  for (i = 0; i < n_file_descs; i++)
+    fwrite (file_descs[i].name, 1, grub_strlen (file_descs[i].name), memdisk);
+
+  if (!grub_install_copy_buffer)
+    grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
+
+  grub_memset (grub_install_copy_buffer, 0, 4);
+  fwrite (grub_install_copy_buffer, 1, name_pad, memdisk);
+
+  for (i = 0; i < n_file_descs; i++)
+    {
+      grub_util_fd_t in;
+      size_t remaining = file_descs[i].size;
+      in = grub_util_fd_open (file_descs[i].source, GRUB_UTIL_FD_O_RDONLY);
+      if (!GRUB_UTIL_FD_IS_VALID (in))
+       grub_util_error (_("cannot open `%s': %s"),
+                        file_descs[i].source, grub_util_fd_strerror ());
+      while (remaining)
+       {
+         size_t toread = remaining;
+         ssize_t r;
+         if (remaining > GRUB_INSTALL_COPY_BUFFER_SIZE)
+           toread = GRUB_INSTALL_COPY_BUFFER_SIZE;
+         r = grub_util_fd_read (in, grub_install_copy_buffer, toread);
+         if (r <= 0)
+           break;
+         fwrite (grub_install_copy_buffer, 1, r, memdisk);
+         if (r >= remaining)
+           remaining = 0;
+         else
+           remaining -= r; 
+       }
+      grub_util_fd_close (in);
+
+      grub_memset (grub_install_copy_buffer, 0, GRUB_INSTALL_COPY_BUFFER_SIZE);
+      while (remaining)
+       {
+         size_t toread = remaining;
+         if (remaining > GRUB_INSTALL_COPY_BUFFER_SIZE)
+           toread = GRUB_INSTALL_COPY_BUFFER_SIZE;
+         fwrite (grub_install_copy_buffer, 1, toread, memdisk);
+         remaining -= toread; 
+       }
+    }
+
+  fclose (memdisk);
 }
 
 int
@@ -319,8 +353,6 @@ main (int argc, char *argv[])
 
   char *memdisk_img = grub_util_make_temporary_file ();
 
-  memdisk = grub_util_fopen (memdisk_img, "wb");
-
   add_tar_file (memdisk_dir, "");
   for (i = 0; i < nfiles; i++)
     {
@@ -341,14 +373,12 @@ main (int argc, char *argv[])
        to++;
       add_tar_file (from, to);
     }
-  write_zeros (512);
-
-  fclose (memdisk);
 
+  write_memdisk (memdisk_img);
   grub_util_unlink_recursive (memdisk_dir);
 
   grub_install_push_module ("memdisk");
-  grub_install_push_module ("tar");
+  grub_install_push_module ("greffs");
 
   grub_install_make_image_wrap (grub_install_source_directory,
                                "(memdisk)/boot/grub", output_image,
@@ -356,5 +386,6 @@ main (int argc, char *argv[])
                                grub_util_get_target_name (format), 0);
 
   grub_util_unlink (memdisk_img);
+
   return 0;
 }