summaryrefslogtreecommitdiffstats
path: root/master/debian/branch_squash.patch
diff options
context:
space:
mode:
authorroot <root@arianrhod.panaceas.james.local>2012-11-16 11:52:02 +0000
committerroot <root@arianrhod.panaceas.james.local>2012-11-16 11:52:02 +0000
commita109bb6d0eb936ac4e2a9f0ee46a269a58ec48ce (patch)
tree9a6b9c35465b23ce5871feec5e9ba0c7d5ac7797 /master/debian/branch_squash.patch
downloadgrub-1.99-pq-a109bb6d0eb936ac4e2a9f0ee46a269a58ec48ce.tar.gz
grub-1.99-pq-a109bb6d0eb936ac4e2a9f0ee46a269a58ec48ce.tar.bz2
grub-1.99-pq-a109bb6d0eb936ac4e2a9f0ee46a269a58ec48ce.zip
fish
Diffstat (limited to 'master/debian/branch_squash.patch')
-rw-r--r--master/debian/branch_squash.patch694
1 files changed, 694 insertions, 0 deletions
diff --git a/master/debian/branch_squash.patch b/master/debian/branch_squash.patch
new file mode 100644
index 0000000..594d03c
--- /dev/null
+++ b/master/debian/branch_squash.patch
@@ -0,0 +1,694 @@
+Description: Add squashfs 4 support
+Author: Vladimir Serbinenko <phcoder@gmail.com>
+Origin: upstream, http://bzr.sv.gnu.org/r/grub/branches/squash/
+Forwarded: not-needed
+Applied-Upstream: http://bazaar.launchpad.net/~vcs-imports/grub/grub2-bzr/revision/3278
+Last-Update: 2011-05-19
+
+Index: b/Makefile.util.def
+===================================================================
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -65,6 +65,7 @@
+ common = grub-core/fs/ntfscomp.c;
+ common = grub-core/fs/reiserfs.c;
+ common = grub-core/fs/sfs.c;
++ common = grub-core/fs/squash4.c;
+ common = grub-core/fs/tar.c;
+ common = grub-core/fs/udf.c;
+ common = grub-core/fs/ufs2.c;
+Index: b/grub-core/Makefile.core.def
+===================================================================
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -985,6 +985,11 @@
+ };
+
+ module = {
++ name = squash4;
++ common = fs/squash4.c;
++};
++
++module = {
+ name = tar;
+ common = fs/tar.c;
+ };
+Index: b/grub-core/fs/squash4.c
+===================================================================
+--- /dev/null
++++ b/grub-core/fs/squash4.c
+@@ -0,0 +1,548 @@
++/* squash4.c - SquashFS */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2010 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/>.
++ */
++
++#include <grub/err.h>
++#include <grub/file.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/disk.h>
++#include <grub/dl.h>
++#include <grub/types.h>
++#include <grub/fshelp.h>
++#include <grub/deflate.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++/*
++ object format Pointed by
++ superblock RAW Fixed offset (0)
++ data RAW ? Fixed offset (60)
++ inode table Chunk superblock
++ dir table Chunk superblock
++ fragment table Chunk unk1
++ unk1 RAW, Chunk superblock
++ unk2 RAW superblock
++ UID/GID Chunk exttblptr
++ exttblptr RAW superblock
++
++ UID/GID table is the array ot uint32_t
++ unk1 contains pointer to unk3 followed by some chunk.
++ unk2 containts one uint64_t
++*/
++
++struct grub_squash_super
++{
++ grub_uint32_t magic;
++#define SQUASH_MAGIC 0x73717368
++ grub_uint32_t dummy1;
++ grub_uint32_t creation_time;
++ grub_uint32_t dummy2;
++ grub_uint64_t dummy3;
++ grub_uint8_t flags;
++#define SQUASH_FLAG_UNCOMPRESSED_INODES 1
++#define SQUASH_FLAG_UNCOMPRESSED_DATA 2
++#define SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS 8
++ grub_uint8_t dummy4[7];
++ grub_uint16_t root_ino_offset;
++ grub_uint32_t root_ino_chunk;
++ grub_uint16_t dummy5;
++ grub_uint64_t total_size;
++ grub_uint64_t exttbloffset;
++ grub_uint64_t dummy6;
++ grub_uint64_t inodeoffset;
++ grub_uint64_t diroffset;
++ grub_uint64_t unk1offset;
++ grub_uint64_t unk2offset;
++} __attribute__ ((packed));
++
++
++/* Chunk-based */
++struct grub_squash_inode
++{
++ /* Same values as direlem types. */
++ grub_uint16_t type;
++ grub_uint16_t dummy[3];
++ grub_uint32_t mtime;
++ union
++ {
++ struct {
++ grub_uint32_t dummy;
++ grub_uint32_t chunk;
++ grub_uint32_t fragment;
++ grub_uint32_t offset;
++ grub_uint32_t size;
++ } __attribute__ ((packed)) file;
++ struct {
++ grub_uint32_t dummy1;
++ grub_uint32_t chunk;
++ grub_uint32_t dummy2;
++ grub_uint16_t size;
++ grub_uint32_t offset;
++ grub_uint16_t dummy3;
++ } __attribute__ ((packed)) dir;
++ struct {
++ grub_uint64_t dummy;
++ grub_uint32_t namelen;
++ char name[0];
++ } __attribute__ ((packed)) symlink;
++ } __attribute__ ((packed));
++} __attribute__ ((packed));
++
++/* Chunk-based. */
++struct grub_squash_dirent_header
++{
++ /* Actually the value is the number of elements - 1. */
++ grub_uint32_t nelems;
++ grub_uint64_t ino_chunk;
++} __attribute__ ((packed));
++
++struct grub_squash_dirent
++{
++ grub_uint16_t ino_offset;
++ grub_uint16_t dummy;
++ grub_uint16_t type;
++#define SQUASH_TYPE_DIR 1
++#define SQUASH_TYPE_REGULAR 2
++#define SQUASH_TYPE_SYMLINK 3
++ /* Actually the value is the length of name - 1. */
++ grub_uint16_t namelen;
++ char name[0];
++} __attribute__ ((packed));
++
++struct grub_squash_frag_desc
++{
++ grub_uint64_t offset;
++ grub_uint64_t dummy;
++} __attribute__ ((packed));
++
++#define SQUASH_CHUNK_SIZE 0x2000
++#define SQUASH_CHUNK_FLAGS 0x8000
++#define SQUASH_CHUNK_UNCOMPRESSED 0x8000
++
++struct grub_squash_data
++{
++ grub_disk_t disk;
++ struct grub_squash_super sb;
++ struct grub_squash_inode ino;
++ grub_uint64_t fragments;
++};
++
++struct grub_fshelp_node
++{
++ struct grub_squash_data *data;
++ struct grub_squash_inode ino;
++ grub_uint32_t ino_chunk;
++ grub_uint16_t ino_offset;
++};
++
++static grub_err_t
++read_chunk (grub_disk_t disk, void *buf, grub_size_t len,
++ grub_uint64_t chunk, grub_off_t offset)
++{
++ grub_uint64_t chunk_start;
++ chunk_start = grub_le_to_cpu64 (chunk);
++ while (len > 0)
++ {
++ grub_uint64_t csize;
++ grub_uint16_t d;
++ grub_err_t err;
++ while (1)
++ {
++ err = grub_disk_read (disk, chunk_start >> GRUB_DISK_SECTOR_BITS,
++ chunk_start & (GRUB_DISK_SECTOR_SIZE - 1),
++ sizeof (d), &d);
++ if (err)
++ return err;
++ if (offset < SQUASH_CHUNK_SIZE)
++ break;
++ offset -= SQUASH_CHUNK_SIZE;
++ chunk_start += 2 + (grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS);
++ }
++
++ csize = SQUASH_CHUNK_SIZE - offset;
++ if (csize > len)
++ csize = len;
++
++ if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED)
++ {
++ grub_disk_addr_t a = chunk_start + 2 + offset;
++ err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS),
++ a & (GRUB_DISK_SECTOR_SIZE - 1),
++ csize, buf);
++ if (err)
++ return err;
++ }
++ else
++ {
++ char *tmp;
++ grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS;
++ grub_disk_addr_t a = chunk_start + 2;
++ tmp = grub_malloc (bsize);
++ if (!tmp)
++ return grub_errno;
++ /* FIXME: buffer uncompressed data. */
++ err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS),
++ a & (GRUB_DISK_SECTOR_SIZE - 1),
++ bsize, tmp);
++ if (err)
++ {
++ grub_free (tmp);
++ return err;
++ }
++
++ if (grub_zlib_decompress (tmp, bsize, offset,
++ buf, csize) < 0)
++ {
++ grub_free (tmp);
++ return grub_errno;
++ }
++ grub_free (tmp);
++ }
++ len -= csize;
++ offset += csize;
++ buf = (char *) buf + csize;
++ }
++ return GRUB_ERR_NONE;
++}
++
++static struct grub_squash_data *
++squash_mount (grub_disk_t disk)
++{
++ struct grub_squash_super sb;
++ grub_err_t err;
++ struct grub_squash_data *data;
++ grub_uint64_t frag;
++
++ err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb);
++ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
++ grub_error (GRUB_ERR_BAD_FS, "not a squash4");
++ if (err)
++ return NULL;
++ if (grub_le_to_cpu32 (sb.magic) != SQUASH_MAGIC)
++ {
++ grub_error (GRUB_ERR_BAD_FS, "not squash4");
++ return NULL;
++ }
++
++ err = grub_disk_read (disk, grub_le_to_cpu32 (sb.unk1offset)
++ >> GRUB_DISK_SECTOR_BITS,
++ grub_le_to_cpu32 (sb.unk1offset)
++ & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag);
++ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
++ grub_error (GRUB_ERR_BAD_FS, "not a squash4");
++ if (err)
++ return NULL;
++
++ data = grub_malloc (sizeof (*data));
++ if (!data)
++ return NULL;
++ data->sb = sb;
++ data->disk = disk;
++ data->fragments = frag;
++
++ return data;
++}
++
++static char *
++grub_squash_read_symlink (grub_fshelp_node_t node)
++{
++ char *ret;
++ grub_err_t err;
++ ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1);
++
++ err = read_chunk (node->data->disk, ret,
++ grub_le_to_cpu32 (node->ino.symlink.namelen),
++ grub_le_to_cpu64 (node->data->sb.inodeoffset)
++ + node->ino_chunk,
++ node->ino_offset + (node->ino.symlink.name
++ - (char *) &node->ino));
++ if (err)
++ {
++ grub_free (ret);
++ return NULL;
++ }
++ ret[grub_le_to_cpu32 (node->ino.symlink.namelen)] = 0;
++ return ret;
++}
++
++static int
++grub_squash_iterate_dir (grub_fshelp_node_t dir,
++ int NESTED_FUNC_ATTR
++ (*hook) (const char *filename,
++ enum grub_fshelp_filetype filetype,
++ grub_fshelp_node_t node))
++{
++ grub_uint32_t off = grub_le_to_cpu16 (dir->ino.dir.offset);
++ grub_uint32_t endoff;
++ unsigned i;
++
++ /* FIXME: why - 3 ? */
++ endoff = grub_le_to_cpu32 (dir->ino.dir.size) + off - 3;
++
++ while (off < endoff)
++ {
++ struct grub_squash_dirent_header dh;
++ grub_err_t err;
++
++ err = read_chunk (dir->data->disk, &dh, sizeof (dh),
++ grub_le_to_cpu64 (dir->data->sb.diroffset)
++ + grub_le_to_cpu32 (dir->ino.dir.chunk), off);
++ if (err)
++ return 0;
++ off += sizeof (dh);
++ for (i = 0; i < (unsigned) grub_le_to_cpu16 (dh.nelems) + 1; i++)
++ {
++ char *buf;
++ int r;
++ struct grub_fshelp_node *node;
++ enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG;
++ struct grub_squash_dirent di;
++ struct grub_squash_inode ino;
++
++ err = read_chunk (dir->data->disk, &di, sizeof (di),
++ grub_le_to_cpu64 (dir->data->sb.diroffset)
++ + grub_le_to_cpu32 (dir->ino.dir.chunk), off);
++ if (err)
++ return 0;
++ off += sizeof (di);
++
++ err = read_chunk (dir->data->disk, &ino, sizeof (ino),
++ grub_le_to_cpu64 (dir->data->sb.inodeoffset)
++ + grub_le_to_cpu32 (dh.ino_chunk),
++ grub_cpu_to_le16 (di.ino_offset));
++ if (err)
++ return 0;
++
++ buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2);
++ if (!buf)
++ return 0;
++ err = read_chunk (dir->data->disk, buf,
++ grub_le_to_cpu16 (di.namelen) + 1,
++ grub_le_to_cpu64 (dir->data->sb.diroffset)
++ + grub_le_to_cpu32 (dir->ino.dir.chunk), off);
++ if (err)
++ return 0;
++
++ off += grub_le_to_cpu16 (di.namelen) + 1;
++ buf[grub_le_to_cpu16 (di.namelen) + 1] = 0;
++ if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_DIR)
++ filetype = GRUB_FSHELP_DIR;
++ if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK)
++ filetype = GRUB_FSHELP_SYMLINK;
++
++ node = grub_malloc (sizeof (*node));
++ if (! node)
++ return 0;
++ *node = *dir;
++ node->ino = ino;
++ node->ino_chunk = grub_le_to_cpu32 (dh.ino_chunk);
++ node->ino_offset = grub_le_to_cpu16 (di.ino_offset);
++
++ r = hook (buf, filetype, node);
++
++ grub_free (buf);
++ if (r)
++ return r;
++ }
++ }
++ return 0;
++}
++
++static grub_err_t
++make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root)
++{
++ grub_memset (root, 0, sizeof (*root));
++ root->data = data;
++
++ return read_chunk (data->disk, &root->ino, sizeof (root->ino),
++ grub_le_to_cpu64 (data->sb.inodeoffset)
++ + grub_le_to_cpu16 (data->sb.root_ino_chunk),
++ grub_cpu_to_le16 (data->sb.root_ino_offset));
++}
++
++static grub_err_t
++grub_squash_dir (grub_device_t device, const char *path,
++ int (*hook) (const char *filename,
++ const struct grub_dirhook_info *info))
++{
++ auto int NESTED_FUNC_ATTR iterate (const char *filename,
++ enum grub_fshelp_filetype filetype,
++ grub_fshelp_node_t node);
++
++ int NESTED_FUNC_ATTR iterate (const char *filename,
++ enum grub_fshelp_filetype filetype,
++ grub_fshelp_node_t node)
++ {
++ struct grub_dirhook_info info;
++ grub_memset (&info, 0, sizeof (info));
++ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
++ info.mtimeset = 1;
++ info.mtime = grub_le_to_cpu32 (node->ino.mtime);
++ return hook (filename, &info);
++ }
++
++ struct grub_squash_data *data = 0;
++ struct grub_fshelp_node *fdiro = 0;
++ struct grub_fshelp_node root;
++ grub_err_t err;
++
++ data = squash_mount (device->disk);
++ if (! data)
++ return grub_errno;
++
++ err = make_root_node (data, &root);
++ if (err)
++ return err;
++
++ grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir,
++ grub_squash_read_symlink, GRUB_FSHELP_DIR);
++ if (!grub_errno)
++ grub_squash_iterate_dir (fdiro, iterate);
++
++ grub_free (data);
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_squash_open (struct grub_file *file, const char *name)
++{
++ struct grub_squash_data *data = 0;
++ struct grub_fshelp_node *fdiro = 0;
++ struct grub_fshelp_node root;
++ grub_err_t err;
++
++ data = squash_mount (file->device->disk);
++ if (! data)
++ return grub_errno;
++
++ err = make_root_node (data, &root);
++ if (err)
++ return err;
++
++ grub_fshelp_find_file (name, &root, &fdiro, grub_squash_iterate_dir,
++ grub_squash_read_symlink, GRUB_FSHELP_REG);
++ if (grub_errno)
++ {
++ grub_free (data);
++ return grub_errno;
++ }
++
++ file->data = data;
++ data->ino = fdiro->ino;
++ file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++grub_squash_read_data (struct grub_squash_data *data,
++ grub_disk_t disk, const struct grub_squash_inode *ino,
++ grub_off_t off, char *buf, grub_size_t len)
++{
++ grub_err_t err;
++ grub_uint64_t a, b;
++ int compressed = 0;
++
++ if (grub_le_to_cpu16 (ino->file.fragment) == 0xffff)
++ {
++ if (grub_le_to_cpu32 (ino->file.chunk))
++ a = grub_le_to_cpu32 (ino->file.chunk);
++ else
++ a = sizeof (struct grub_squash_super);
++ compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_DATA);
++ }
++ else
++ {
++ struct grub_squash_frag_desc frag;
++ err = read_chunk (disk, &frag, sizeof (frag),
++ data->fragments, sizeof (frag)
++ * grub_le_to_cpu16 (ino->file.fragment));
++ if (err)
++ return -1;
++ a = grub_le_to_cpu64 (frag.offset) + grub_le_to_cpu32 (ino->file.chunk);
++ compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS);
++ }
++
++ b = grub_le_to_cpu32 (data->ino.file.offset) + off;
++
++ /* FIXME: cache uncompressed chunks. */
++ if (compressed)
++ err = grub_zlib_disk_read (disk, a, b, buf, len);
++ else
++ err = grub_disk_read (disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
++ (a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
++ if (err)
++ return -1;
++ return len;
++}
++
++static grub_ssize_t
++grub_squash_read (grub_file_t file, char *buf, grub_size_t len)
++{
++ struct grub_squash_data *data = file->data;
++
++ return grub_squash_read_data (data, file->device->disk, &data->ino,
++ file->offset, buf, len);
++}
++
++static grub_err_t
++grub_squash_close (grub_file_t file)
++{
++ grub_free (file->data);
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_squash_mtime (grub_device_t dev, grub_int32_t *tm)
++{
++ struct grub_squash_data *data = 0;
++
++ data = squash_mount (dev->disk);
++ if (! data)
++ return grub_errno;
++ *tm = grub_le_to_cpu32 (data->sb.creation_time);
++ grub_free (data);
++ return GRUB_ERR_NONE;
++}
++
++static struct grub_fs grub_squash_fs =
++ {
++ .name = "squash4",
++ .dir = grub_squash_dir,
++ .open = grub_squash_open,
++ .read = grub_squash_read,
++ .close = grub_squash_close,
++ .mtime = grub_squash_mtime,
++#ifdef GRUB_UTIL
++ .reserved_first_sector = 0,
++#endif
++ .next = 0
++ };
++
++GRUB_MOD_INIT(squash4)
++{
++ grub_fs_register (&grub_squash_fs);
++}
++
++GRUB_MOD_FINI(squash4)
++{
++ grub_fs_unregister (&grub_squash_fs);
++}
++
+Index: b/grub-core/io/gzio.c
+===================================================================
+--- a/grub-core/io/gzio.c
++++ b/grub-core/io/gzio.c
+@@ -41,6 +41,7 @@
+ #include <grub/fs.h>
+ #include <grub/file.h>
+ #include <grub/dl.h>
++#include <grub/disk.h>
+ #include <grub/deflate.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+@@ -64,6 +65,9 @@
+ /* If input is in memory following fields are used instead of file. */
+ grub_size_t mem_input_size, mem_input_off;
+ grub_uint8_t *mem_input;
++ grub_disk_addr_t disk_input_off;
++ grub_disk_addr_t disk_input_start;
++ grub_disk_t disk_input;
+ /* The offset at which the data starts in the underlying file. */
+ grub_off_t data_offset;
+ /* The type of current block. */
+@@ -384,8 +388,21 @@
+ return 0;
+ }
+
+- if (grub_file_tell (gzio->file) == (grub_off_t) gzio->data_offset
+- || gzio->inbuf_d == INBUFSIZ)
++ if (gzio->disk_input && (gzio->disk_input_off == gzio->data_offset
++ || gzio->inbuf_d == INBUFSIZ))
++ {
++ grub_disk_addr_t d = gzio->disk_input_start + gzio->disk_input_off;
++ gzio->inbuf_d = 0;
++ grub_disk_read (gzio->disk_input,
++ d >> GRUB_DISK_SECTOR_BITS,
++ d & (GRUB_DISK_SECTOR_SIZE - 1),
++ INBUFSIZ, gzio->inbuf);
++ gzio->disk_input_off += INBUFSIZ;
++ }
++
++ if (gzio->file && (grub_file_tell (gzio->file)
++ == (grub_off_t) gzio->data_offset
++ || gzio->inbuf_d == INBUFSIZ))
+ {
+ gzio->inbuf_d = 0;
+ grub_file_read (gzio->file, gzio->inbuf, INBUFSIZ);
+@@ -403,8 +420,10 @@
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "attempt to seek outside of the file");
+ else
+- gzio->mem_input_off = gzio->data_offset;
++ gzio->mem_input_off = off;
+ }
++ else if (gzio->disk_input)
++ gzio->disk_input_off = off;
+ else
+ grub_file_seek (gzio->file, off);
+ }
+@@ -1298,6 +1317,34 @@
+ return ret;
+ }
+
++grub_err_t
++grub_zlib_disk_read (grub_disk_t disk, grub_disk_addr_t zlibstart,
++ grub_off_t off, char *outbuf, grub_size_t outsize)
++{
++ grub_gzio_t gzio = 0;
++ grub_ssize_t ret;
++
++ gzio = grub_zalloc (sizeof (*gzio));
++ if (! gzio)
++ return -1;
++
++ gzio->disk_input_off = 0;
++ gzio->disk_input_start = zlibstart;
++ gzio->disk_input = disk;
++
++ if (!test_zlib_header (gzio))
++ {
++ grub_free (gzio);
++ return -1;
++ }
++
++ ret = grub_gzio_read_real (gzio, off, outbuf, outsize);
++ grub_free (gzio);
++
++ /* FIXME: Check Adler. */
++ return ret < 0 ? grub_errno : GRUB_ERR_NONE;
++}
++
+
+
+ static struct grub_fs grub_gzio_fs =
+Index: b/include/grub/deflate.h
+===================================================================
+--- a/include/grub/deflate.h
++++ b/include/grub/deflate.h
+@@ -23,4 +23,8 @@
+ grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off,
+ char *outbuf, grub_size_t outsize);
+
++grub_err_t
++grub_zlib_disk_read (grub_disk_t disk, grub_disk_addr_t zlibstart,
++ grub_off_t off, char *outbuf, grub_size_t outsize);
++
+ #endif