/* lzopio.c - decompression support for lzop */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2011 Free Software Foundation, Inc.
*
* 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 <minilzo.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* Header flags - copied from conf.h of LZOP source code. */
struct block_header
{
unsigned char *cdata;
unsigned char *udata;
};
struct grub_lzopio
{
int has_ccheck;
int has_ucheck;
};
/* Some helper functions. On errors memory allocated by those function is free
* either on close() so no risk of leaks. This makes functions simpler. */
/* Read block header from file, after successful exit file points to
* beginning of block data. */
static int
{
/* Free cached block data if any. */
return -1;
/* Last block has uncompressed data size == 0 and no other fields. */
{
return 0;
else
return -1;
}
/* Read compressed data block size. */
return -1;
/* Corrupted. */
return -1;
/* Read checksum of uncompressed data. */
if (lzopio->has_ucheck)
{
return -1;
}
/* Read checksum of compressed data. */
if (lzopio->has_ccheck)
{
/* Incompressible data block. */
{
}
else
{
return -1;
}
}
return 0;
}
/* Read block data into memory. File must be set to beginning of block data.
* Can't be called on last block. */
static int
{
return -1;
return -1;
if (lzopio->ccheck_fun)
{
if (grub_memcmp
return -1;
}
return 0;
}
/* Read block data, uncompressed and also store it in memory. */
/* XXX Investigate possibility of in-place decompression to reduce memory
* footprint. Or try to uncompress directly to buf if possible. */
static int
{
if (read_block_data (lzopio) < 0)
return -1;
/* Incompressible data. */
{
}
else
{
return -1;
!= LZO_E_OK)
return -1;
if (lzopio->ucheck_fun)
{
if (grub_memcmp
return -1;
}
/* Compressed data can be free now. */
}
return 0;
}
/* Jump to next block and read its header. */
static int
{
/* only jump if block was not decompressed (and read from disk) */
{
return -1;
}
return read_block_header (lzopio);
}
static int
{
if (read_block_header (lzopio) < 0)
return -1;
/* FIXME: Don't do this for not easily seekable files. */
{
if (jump_block (lzopio) < 0)
return -1;
}
return 0;
}
struct lzop_header
{
/* grub_uint32_t filter; */ /* No filters support. Rarely used anyway. */
} __attribute__ ((packed));
static int
{
{
return 0;
}
{
return 0;
}
{
"unsupported (too old) LZOP version");
return 0;
}
/* Too new version, should upgrade minilzo? */
{
"unsupported (too new) LZO version");
return 0;
}
{
}
else if (flags & F_ADLER32_D)
{
}
{
}
else if (flags & F_ADLER32_C)
{
}
else
if (hcheck) {
if (! context)
return 0;
/* MAGIC is not included in check calculation. */
}
{
if (! name)
{
return 0;
}
{
goto CORRUPTED;
}
if (hcheck)
}
if (hcheck)
sizeof (checksum))
goto CORRUPTED;
if (hcheck)
{
goto CORRUPTED;
}
if (calculate_uncompressed_size (file) < 0)
goto CORRUPTED;
/* Get back to start block. */
/* Read first block - grub_lzopio_read() expects valid block. */
if (read_block_header (lzopio) < 0)
goto CORRUPTED;
return 1;
return 0;
}
static grub_file_t
{
if (!file)
return 0;
if (!lzopio)
{
return 0;
}
if (!test_header (file))
{
grub_file_seek (io, 0);
return io;
}
return file;
}
static grub_ssize_t
{
/* Backward seek before last read block. */
{
if (read_block_header (lzopio) < 0)
goto CORRUPTED;
}
/* Forward to first block with requested data. */
{
/* EOF, could be possible files with unknown size. */
return 0;
if (jump_block (lzopio) < 0)
goto CORRUPTED;
}
{
/* Block not decompressed yet. */
goto CORRUPTED;
/* Copy requested data into buffer. */
off = 0;
/* Read next block if needed. */
goto CORRUPTED;
}
return ret;
return -1;
}
/* Release everything, including the underlying file object. */
static grub_err_t
{
/* Device must not be closed twice. */
return grub_errno;
}
.name = "lzopio",
.dir = 0,
.open = 0,
.read = grub_lzopio_read,
.label = 0,
.next = 0
};
{
}
{
}