Squashfs v4 support.
* Makefile.util.def (libgrubmods.a): Add squash4. * grub-core/Makefile.core.def (squash4): New module. * grub-core/fs/squash4.c: New file. * grub-core/io/gzio.c (grub_gzio): New members disk_input_off, disk_input_start, disk_input. (get_byte): Handle disk_input. (grub_zlib_disk_read): New function. * include/grub/deflate.h (grub_zlib_disk_read): New proto.
This commit is contained in:
commit
d4680a3556
6 changed files with 619 additions and 3 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2011-05-15 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Squashfs v4 support.
|
||||
|
||||
* Makefile.util.def (libgrubmods.a): Add squash4.
|
||||
* grub-core/Makefile.core.def (squash4): New module.
|
||||
* grub-core/fs/squash4.c: New file.
|
||||
* grub-core/io/gzio.c (grub_gzio): New members disk_input_off,
|
||||
disk_input_start, disk_input.
|
||||
(get_byte): Handle disk_input.
|
||||
(grub_zlib_disk_read): New function.
|
||||
* include/grub/deflate.h (grub_zlib_disk_read): New proto.
|
||||
|
||||
2011-05-15 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
2011-05-15 Feiran Zheng <famcool@gmail.com>
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ library = {
|
|||
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;
|
||||
|
|
|
@ -1014,6 +1014,11 @@ module = {
|
|||
common = fs/sfs.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = squash4;
|
||||
common = fs/squash4.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = tar;
|
||||
common = fs/tar.c;
|
||||
|
|
546
grub-core/fs/squash4.c
Normal file
546
grub-core/fs/squash4.c
Normal file
|
@ -0,0 +1,546 @@
|
|||
/* 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>
|
||||
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
|
@ -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 @@ struct grub_gzio
|
|||
/* 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 @@ get_byte (grub_gzio_t gzio)
|
|||
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 @@ gzio_seek (grub_gzio_t gzio, grub_off_t off)
|
|||
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 @@ grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct grub_fs grub_gzio_fs =
|
||||
|
|
|
@ -23,4 +23,8 @@ grub_ssize_t
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue