grub_uint32_t dummy1;
grub_uint32_t creation_time;
grub_uint32_t dummy2;
- grub_uint32_t dummy3[4];
+ grub_uint32_t dummy3[2];
+ 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_uint16_t root_ino_chunk;
- grub_uint32_t dummy4;
+ grub_uint32_t dummy5;
grub_uint64_t total_size;
grub_uint64_t exttbloffset;
- grub_uint32_t dummy5[2];
+ grub_uint32_t dummy6[2];
grub_uint64_t inodeoffset;
grub_uint64_t diroffset;
grub_uint64_t unk1offset;
grub_squash_read (grub_file_t file, char *buf, grub_size_t len)
{
grub_err_t err;
- grub_uint64_t a;
+ grub_uint64_t a, b;
struct grub_squash_data *data = file->data;
+ int compressed = 0;
if (grub_le_to_cpu16 (data->ino.fragment) == 0xffff)
{
a = grub_le_to_cpu32 (data->ino.chunk);
else
a = sizeof (struct grub_squash_super);
+ compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_DATA);
}
else
{
if (err)
return -1;
a = grub_le_to_cpu64 (frag.offset) + grub_le_to_cpu32 (data->ino.chunk);
+ compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS);
}
- a += grub_le_to_cpu32 (data->ino.offset) + file->offset;
+ b = grub_le_to_cpu32 (data->ino.offset) + file->offset;
- err = grub_disk_read (file->device->disk, a >> GRUB_DISK_SECTOR_BITS,
- a & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
+ /* FIXME: cache uncompressed chunks. */
+ if (compressed)
+ err = grub_zlib_disk_read (file->device->disk, a, b, buf, len);
+ else
+ err = grub_disk_read (file->device->disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
+ (a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
if (err)
return -1;
return len;
#include <grub/fs.h>
#include <grub/file.h>
#include <grub/dl.h>
+#include <grub/disk.h>
#include <grub/deflate.h>
/*
/* 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. */
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);
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);
}
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;
+}
+
\f
static struct grub_fs grub_gzio_fs =