From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1VupcF-0004FC-Tm for mharc-grub-devel@gnu.org; Sun, 22 Dec 2013 15:27:11 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49999) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vupc7-0004Eo-SL for grub-devel@gnu.org; Sun, 22 Dec 2013 15:27:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Vupc2-0003cO-DO for grub-devel@gnu.org; Sun, 22 Dec 2013 15:27:03 -0500 Received: from mail-ea0-x231.google.com ([2a00:1450:4013:c01::231]:53718) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vupc1-0003cG-TW for grub-devel@gnu.org; Sun, 22 Dec 2013 15:26:58 -0500 Received: by mail-ea0-f177.google.com with SMTP id n15so2011924ead.8 for ; Sun, 22 Dec 2013 12:26:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=VFenNjpDiJKwPfPkqLBIp9vRaT8uSF1+kAM2X7e1rFI=; b=k+oSWb0dUrllWsRpGlWIGipfAi1HrOu1ukaLuFLATcLLm/ZznweEKmGm23K1lKRYne t2pt9TNPJapKbHaQFXBdhDB6Pbx8hl4KoLMfosQTnXV82w0A6CXbzXCyMBWvxjF0jqit mpauSTd9BXLGXYbQs2v0oZOe6sXs90l4wj8zYVudoREs/Sg82FWNgaLoXBlxjM2VybmN 8QshYsLL3wXUNaGOGmZX87fNNj4xh+kGD8fxRmpTfdSun/cl9+R9SqG59VNm01rlEAes jmWvOewRS9tkpWFQho8BD06/bGC66GLlsaGmaZznjgNx2bJu1ut/JgrUth8rDF0RsDYS GNnw== X-Received: by 10.15.63.7 with SMTP id l7mr104556eex.113.1387744016879; Sun, 22 Dec 2013 12:26:56 -0800 (PST) Received: from [192.168.1.16] (85-188.196-178.cust.bluewin.ch. [178.196.188.85]) by mx.google.com with ESMTPSA id j46sm39363410eew.18.2013.12.22.12.26.55 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 22 Dec 2013 12:26:55 -0800 (PST) Message-ID: <52B74B0F.702@gmail.com> Date: Sun, 22 Dec 2013 21:26:55 +0100 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20131103 Icedove/17.0.10 MIME-Version: 1.0 To: The development of GRUB 2 Subject: [PATCH] improve boot time with standalone images X-Enigmail-Version: 1.6 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="kfBWNkMOOdPVS4lcr3DtMRlDPUKgibUBa" X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4013:c01::231 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 22 Dec 2013 20:27:09 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --kfBWNkMOOdPVS4lcr3DtMRlDPUKgibUBa Content-Type: multipart/mixed; boundary="------------050104060608020300070001" This is a multi-part message in MIME format. --------------050104060608020300070001 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hello, all. While testing on raspberry pi using standalone image I've noticed that all file operations were sluggish. The culprit was tar that we use as a filesystem for memdisk which requires complete scan to find one file. On most systems it's a minor time penalty but on raspberry pi it almost halved boot time. I propose a specialised compact and fast uncompressed read-only filesystem by storing filenames in sorted array and using binary search. It's a pretty big change but I feel like it's worth to be put into 2.02. Does anybody disagree? --------------050104060608020300070001 Content-Type: text/x-diff; name="greffs.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="greffs.diff" diff --git a/Makefile.util.def b/Makefile.util.def index 27c48e5..d9f7e64 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -119,6 +119,7 @@ library =3D { common =3D grub-core/fs/sfs.c; common =3D grub-core/fs/squash4.c; common =3D grub-core/fs/tar.c; + common =3D grub-core/fs/greffs.c; common =3D grub-core/fs/udf.c; common =3D grub-core/fs/ufs2.c; common =3D grub-core/fs/ufs.c; diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index e5e558c..da3a599 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1400,6 +1400,11 @@ module =3D { }; =20 module =3D { + name =3D greffs; + common =3D fs/greffs.c; +}; + +module =3D { name =3D udf; common =3D fs/udf.c; }; diff --git a/grub-core/fs/greffs.c b/grub-core/fs/greffs.c new file mode 100644 index 0000000..2cc4efb --- /dev/null +++ b/grub-core/fs/greffs.c @@ -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 = =2E + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +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 =3D desc[1] - desc[0]; + if (*size < read_size + 1) + { + grub_free (*buf); + *size =3D (read_size + 4) * 2; + *buf =3D grub_malloc (*size); + if (!*buf) + { + *size =3D 0; + return grub_errno; + } + } + if (grub_disk_read (disk, 0, desc[0], read_size, *buf)) + return grub_errno; + (*buf)[read_size] =3D '\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 =3D 0; + int i; + char *buf =3D NULL; + grub_size_t buf_size =3D 0; + grub_err_t err; + + num_files =3D grub_le_to_cpu32 (head->nfiles); + + for (i =3D 31; i >=3D 0; i--) + { + int cmp; + if ((cur_file | (1 << i)) > num_files) + continue; + err =3D get_string (disk, head, (cur_file | (1 << i)) - 1, &buf, &= buf_size); + if (err) + { + grub_free (buf); + return err; + } + cmp =3D grub_strcmp (buf, name_in); + if (cmp <=3D 0) + cur_file |=3D (1 << i); + if (cmp =3D=3D 0) + { + grub_free (buf); + *f =3D cur_file - 1; + return GRUB_ERR_NONE; + } + } + + grub_free (buf); + if (!exact) + { + *f =3D 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 =3D grub_malloc (grub_strlen (name_in) + 2); + if (!out) + return NULL; + for (iptr =3D name_in, optr =3D out; *iptr; ) + { + while (*iptr =3D=3D '/') + iptr++; + if (iptr[0] =3D=3D '.' && (iptr[1] =3D=3D '/' || iptr[1] =3D=3D 0)= ) + { + iptr +=3D 2; + continue; + } + if (iptr[0] =3D=3D '.' && iptr[1] =3D=3D '.' && (iptr[2] =3D=3D '/= ' || iptr[2] =3D=3D 0)) + { + iptr +=3D 3; + if (optr =3D=3D out) + continue; + for (optr -=3D 2; optr >=3D out && *optr !=3D '/'; optr--); + optr++; + continue; + } + while (*iptr && *iptr !=3D '/') + *optr++ =3D *iptr++; + if (*iptr) + *optr++ =3D *iptr++; + else if (make_dir && optr !=3D out) + *optr++ =3D '/'; + } + *optr =3D 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 =3D 0; + grub_size_t buf_size =3D 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)) != =3D 0) + return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem"); + + can =3D canonicalize (path_in, 1); + if (!can) + return grub_errno; + + if (can[0] =3D=3D '\0') + cur_file =3D 0; + else + { + err =3D find_file (device->disk, &head, can, &cur_file, 0); + if (err) + goto fail; + } + + num_files =3D grub_le_to_cpu32 (head.nfiles); + + len =3D grub_strlen (can); + + while (cur_file < num_files) + { + char *p, *n; + struct grub_dirhook_info info; + + err =3D get_string (device->disk, &head, cur_file, &buf, &buf_size= ); + if (err) + goto fail; + if (grub_memcmp (can, buf, len) !=3D 0) + break; + grub_memset (&info, 0, sizeof (info)); + + n =3D buf + len; + while (*n =3D=3D '/') + n++; + + p =3D grub_strchr (n, '/'); + if (p) + *p =3D 0; + info.dir =3D (p !=3D NULL); + if (hook (n, &info, hook_data)) + goto fail; + if (!p) + cur_file++; + else + { + *p =3D '/' + 1; + p[1] =3D '\0'; + err =3D find_file (device->disk, &head, buf, &cur_file, 0); + if (err) + goto fail; + }=09 + } + + 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)) != =3D 0) + return grub_error (GRUB_ERR_BAD_FS, "not a greffs filesystem"); + + can =3D canonicalize (name_in, 0); + if (!can) + return grub_errno; + + err =3D find_file (file->device->disk, &head, can, &cur_file, 1); + grub_free (can); + if (err) + return err; + + data =3D 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 =3D grub_cpu_to_le32 (inode.start); + file->size =3D grub_cpu_to_le32 (inode.size); + + file->data =3D 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 =3D file->data; + + file->device->disk->read_hook =3D file->read_hook; + file->device->disk->read_hook_data =3D file->read_hook_data; + ret =3D (grub_disk_read (file->device->disk, 0, data->dofs + file->off= set, + len, buf)) ? -1 : (grub_ssize_t) len; + file->device->disk->read_hook =3D 0; + + return ret; +} + +static grub_err_t +grub_greffs_close (grub_file_t file) +{ + struct grub_greffs_data *data; + + data =3D file->data; + grub_free (data); + + return grub_errno; +} + +static struct grub_fs grub_greffs_fs =3D { + .name =3D "greffs", + .dir =3D grub_greffs_dir, + .open =3D grub_greffs_open, + .read =3D grub_greffs_read, + .close =3D grub_greffs_close, +#ifdef GRUB_UTIL + .reserved_first_sector =3D 0, + .blocklist_install =3D 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 index 0000000..6d54bae --- /dev/null +++ b/include/grub/greffs.h @@ -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 . + */ + +#ifndef GRUB_GREFFS_HEADER +#define GRUB_GREFFS_HEADER 1 + +#include + +/* + 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 diff --git a/util/grub-mkstandalone.c b/util/grub-mkstandalone.c index 8e2a2b8..c7dd054 100644 --- a/util/grub-mkstandalone.c +++ b/util/grub-mkstandalone.c @@ -21,6 +21,7 @@ #include #include #include +#include =20 #include =20 @@ -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; =20 enum { @@ -116,91 +116,56 @@ struct argp argp =3D { NULL, help_filter, NULL }; =20 -/* 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 =3D 0; i < len - 1; i++) - field[len - 2 - i] =3D '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; =20 -static void -compute_checksum (struct head *hd) +static inline void +canonicalize (char *name) { - unsigned int chk =3D 0; - unsigned char *ptr; - memset (hd->chksum, ' ', 8); - for (ptr =3D (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); p= tr++) - chk +=3D *ptr; - set_tar_value (hd->chksum, chk, 8); + char *iptr, *optr; + for (iptr =3D name, optr =3D name; *iptr; ) + { + while (*iptr =3D=3D '/') + iptr++; + if (iptr[0] =3D=3D '.' && (iptr[1] =3D=3D '/' || iptr[1] =3D=3D 0)= ) + { + iptr +=3D 2; + continue; + } + if (iptr[0] =3D=3D '.' && iptr[1] =3D=3D '.' && (iptr[2] =3D=3D '/= ' || iptr[2] =3D=3D 0)) + { + iptr +=3D 3; + if (optr =3D=3D name) + continue; + for (optr -=3D 2; optr >=3D name && *optr !=3D '/'; optr--); + optr++; + continue; + } + while (*iptr && *iptr !=3D '/') + *optr++ =3D *iptr++; + if (*iptr) + *optr++ =3D *iptr++; + } + *optr =3D 0; } =20 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 =3D 0; - grub_uint32_t size; - - COMPILE_TIME_ASSERT (sizeof (hd) =3D=3D 512); + size_t idx; =20 if (grub_util_is_special_file (from)) return; =20 - mtime =3D grub_util_get_mtime (from); - - optr =3D tcn =3D xmalloc (strlen (to) + 1); - for (iptr =3D to; *iptr =3D=3D '/'; iptr++); - for (; *iptr; iptr++) - if (!(iptr[0] =3D=3D '/' && iptr[1] =3D=3D '/')) - *optr++ =3D *iptr; - *optr =3D '\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; } =20 - if (optr - tcn > 99) + idx =3D n_file_descs++; + if (idx >=3D 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 =3D '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 =3D 2 * n_file_descs; + file_descs =3D xrealloc (file_descs, alloc_file_descs + * sizeof (file_descs[0])); } =20 in =3D 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_strer= ror ()); =20 - if (!grub_install_copy_buffer) - grub_install_copy_buffer =3D xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE)= ; + file_descs[idx].name =3D xstrdup (to); + file_descs[idx].source =3D xstrdup (from); + canonicalize (file_descs[idx].name); + file_descs[idx].mtime =3D grub_util_get_mtime (from); + file_descs[idx].size =3D grub_util_get_fd_size (in, from, NULL); + + grub_util_fd_close (in); +} =20 - size =3D grub_util_get_fd_size (in, from, NULL); +static int +filecmp (const void *p1, const void *p2) +{ + const struct file_desc *a =3D p1, *b =3D p2; =20 - 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); +} =20 - set_tar_value (hd.size, size, 12); - set_tar_value (hd.mtime, mtime, 12); - hd.typeflag =3D '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 =3D 0, i; + size_t name_pad =3D 0; + grub_uint32_t file_offset; + + qsort (file_descs, n_file_descs, sizeof (file_descs[0]), filecmp); + + for (i =3D 0; i < n_file_descs; i++) + total_strlen +=3D grub_strlen (file_descs[i].name); + name_pad =3D ALIGN_UP (total_strlen, 4) - total_strlen; + total_strlen +=3D name_pad; + + grub_memcpy (head.magic, GRUB_GREFFS_MAGIC, sizeof (head.magic)); + head.nfiles =3D grub_cpu_to_le32 (n_file_descs); + head.inodes_offset =3D grub_cpu_to_le32 (sizeof (head) + + sizeof (grub_uint32_t) + * (n_file_descs + 1)); + head.string_ptrs_offset =3D grub_cpu_to_le32 (sizeof (head)); =20 - compute_checksum (&hd); + memdisk =3D grub_util_fopen (memdisk_img, "wb"); + if (!memdisk) + grub_util_error (_("Can't create file: %s"), strerror (errno)); =20 - fwrite (&hd, 1, sizeof (hd), memdisk); -=20 - while (1) + fwrite (&head, 1, sizeof (head), memdisk); + + grub_uint32_t curname =3D sizeof (head) + sizeof (grub_uint32_t) + * (n_file_descs + 1) + sizeof (inode) * n_file_descs; + for (i =3D 0; i <=3D n_file_descs; i++) { - r =3D grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTAL= L_COPY_BUFFER_SIZE); - if (r <=3D 0) - break; - fwrite (grub_install_copy_buffer, 1, r, memdisk); + grub_uint32_t curname_le =3D grub_cpu_to_le32 (curname); + fwrite (&curname_le, 1, sizeof (curname_le), memdisk); + if (i !=3D n_file_descs) + curname +=3D grub_strlen (file_descs[i].name); } - grub_util_fd_close (in); =20 - write_pad (size); + file_offset =3D sizeof (head) + sizeof (grub_uint32_t) + * (n_file_descs + 1) + sizeof (inode) * n_file_descs + total_strlen;= + for (i =3D 0; i < n_file_descs; i++) + { + inode.start =3D grub_cpu_to_le32 (file_offset); + inode.size =3D grub_cpu_to_le32 (file_descs[i].size); + inode.mtime =3D grub_cpu_to_le32 (file_descs[i].mtime); + inode.type =3D 0; + fwrite (&inode, 1, sizeof (inode), memdisk); + file_offset +=3D file_descs[i].size; + } + + for (i =3D 0; i < n_file_descs; i++) + fwrite (file_descs[i].name, 1, grub_strlen (file_descs[i].name), mem= disk); + + if (!grub_install_copy_buffer) + grub_install_copy_buffer =3D 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 =3D 0; i < n_file_descs; i++) + { + grub_util_fd_t in; + size_t remaining =3D file_descs[i].size; + in =3D grub_util_fd_open (file_descs[i].source, GRUB_UTIL_FD_O_RDO= NLY); + if (!GRUB_UTIL_FD_IS_VALID (in)) + grub_util_error (_("cannot open `%s': %s"), + file_descs[i].source, grub_util_fd_strerror ()); +=20 + while (remaining) + { + size_t toread =3D remaining; + ssize_t r; + if (remaining > GRUB_INSTALL_COPY_BUFFER_SIZE) + toread =3D GRUB_INSTALL_COPY_BUFFER_SIZE; + r =3D grub_util_fd_read (in, grub_install_copy_buffer, toread); + if (r <=3D 0) + break; + fwrite (grub_install_copy_buffer, 1, r, memdisk); + if (r >=3D remaining) + remaining =3D 0; + else + remaining -=3D r;=20 + } + grub_util_fd_close (in); + + grub_memset (grub_install_copy_buffer, 0, GRUB_INSTALL_COPY_BUFFER= _SIZE); + while (remaining) + { + size_t toread =3D remaining; + if (remaining > GRUB_INSTALL_COPY_BUFFER_SIZE) + toread =3D GRUB_INSTALL_COPY_BUFFER_SIZE; + fwrite (grub_install_copy_buffer, 1, toread, memdisk); + remaining -=3D toread;=20 + } + } + + fclose (memdisk); } =20 int @@ -319,8 +353,6 @@ main (int argc, char *argv[]) =20 char *memdisk_img =3D grub_util_make_temporary_file (); =20 - memdisk =3D grub_util_fopen (memdisk_img, "wb"); - add_tar_file (memdisk_dir, ""); for (i =3D 0; i < nfiles; i++) { @@ -341,14 +373,12 @@ main (int argc, char *argv[]) to++; add_tar_file (from, to); } - write_zeros (512); - - fclose (memdisk); =20 + write_memdisk (memdisk_img); grub_util_unlink_recursive (memdisk_dir); =20 grub_install_push_module ("memdisk"); - grub_install_push_module ("tar"); + grub_install_push_module ("greffs"); =20 grub_install_make_image_wrap (grub_install_source_directory, "(memdisk)/boot/grub", output_image, --------------050104060608020300070001-- --kfBWNkMOOdPVS4lcr3DtMRlDPUKgibUBa Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) Comment: Using GnuPG with Icedove - http://www.enigmail.net/ iF4EAREKAAYFAlK3Sw8ACgkQmBXlbbo5nOucUQD/eFtgbEJKy9QNGGxJ8wt5m/6k E9CMqsXSc9diAFS2ZocBAJ+ZXNQ4X8NUmN6P8k4ECHZF80/7B6IilKE/LUogaqMG =yzyj -----END PGP SIGNATURE----- --kfBWNkMOOdPVS4lcr3DtMRlDPUKgibUBa--