1
/* squash4.c - SquashFS */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2010 Free Software Foundation, Inc.
6
* GRUB is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* GRUB is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21
#include <grub/file.h>
23
#include <grub/misc.h>
24
#include <grub/disk.h>
26
#include <grub/types.h>
27
#include <grub/fshelp.h>
28
#include <grub/deflate.h>
32
#include "xz_stream.h"
34
GRUB_MOD_LICENSE ("GPLv3+");
37
object format Pointed by
38
superblock RAW Fixed offset (0)
39
data RAW ? Fixed offset (60)
40
inode table Chunk superblock
41
dir table Chunk superblock
42
fragment table Chunk unk1
43
unk1 RAW, Chunk superblock
45
UID/GID Chunk exttblptr
46
exttblptr RAW superblock
48
UID/GID table is the array ot uint32_t
49
unk1 contains pointer to fragment table followed by some chunk.
50
unk2 containts one uint64_t
53
struct grub_squash_super
56
#define SQUASH_MAGIC 0x73717368
58
grub_uint32_t creation_time;
59
grub_uint32_t block_size;
61
grub_uint16_t compression;
64
grub_uint16_t root_ino_offset;
65
grub_uint32_t root_ino_chunk;
67
grub_uint64_t total_size;
68
grub_uint64_t exttbloffset;
70
grub_uint64_t inodeoffset;
71
grub_uint64_t diroffset;
72
grub_uint64_t unk1offset;
73
grub_uint64_t unk2offset;
74
} __attribute__ ((packed));
77
struct grub_squash_inode
79
/* Same values as direlem types. */
81
grub_uint16_t dummy[3];
88
grub_uint32_t fragment;
91
grub_uint32_t block_size[0];
92
} __attribute__ ((packed)) file;
96
grub_uint32_t dummy1[3];
97
grub_uint32_t fragment;
100
grub_uint32_t block_size[0];
101
} __attribute__ ((packed)) long_file;
106
grub_uint16_t offset;
107
} __attribute__ ((packed)) dir;
109
grub_uint32_t dummy1;
112
grub_uint32_t dummy2;
113
grub_uint16_t dummy3;
114
grub_uint16_t offset;
115
} __attribute__ ((packed)) long_dir;
118
grub_uint32_t namelen;
120
} __attribute__ ((packed)) symlink;
121
} __attribute__ ((packed));
122
} __attribute__ ((packed));
124
struct grub_squash_cache_inode
126
struct grub_squash_inode ino;
127
grub_disk_addr_t ino_chunk;
128
grub_uint16_t ino_offset;
129
grub_uint32_t *block_sizes;
130
grub_disk_addr_t *cumulated_block_sizes;
134
struct grub_squash_dirent_header
136
/* Actually the value is the number of elements - 1. */
137
grub_uint32_t nelems;
138
grub_uint32_t ino_chunk;
140
} __attribute__ ((packed));
142
struct grub_squash_dirent
144
grub_uint16_t ino_offset;
147
/* Actually the value is the length of name - 1. */
148
grub_uint16_t namelen;
150
} __attribute__ ((packed));
155
SQUASH_TYPE_REGULAR = 2,
156
SQUASH_TYPE_SYMLINK = 3,
157
SQUASH_TYPE_LONG_DIR = 8,
158
SQUASH_TYPE_LONG_REGULAR = 9,
162
struct grub_squash_frag_desc
164
grub_uint64_t offset;
167
} __attribute__ ((packed));
171
SQUASH_CHUNK_FLAGS = 0x8000,
172
SQUASH_CHUNK_UNCOMPRESSED = 0x8000
177
SQUASH_BLOCK_FLAGS = 0x1000000,
178
SQUASH_BLOCK_UNCOMPRESSED = 0x1000000
183
COMPRESSION_ZLIB = 1,
189
#define SQUASH_CHUNK_SIZE 0x2000
190
#define XZBUFSIZ 0x2000
192
struct grub_squash_data
195
struct grub_squash_super sb;
196
struct grub_squash_cache_inode ino;
197
grub_uint64_t fragments;
200
grub_ssize_t (*decompress) (char *inbuf, grub_size_t insize, grub_off_t off,
201
char *outbuf, grub_size_t outsize,
202
struct grub_squash_data *data);
203
struct xz_dec *xzdec;
207
struct grub_fshelp_node
209
struct grub_squash_data *data;
210
struct grub_squash_inode ino;
214
grub_disk_addr_t ino_chunk;
215
grub_uint16_t ino_offset;
220
read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len,
221
grub_uint64_t chunk_start, grub_off_t offset)
230
err = grub_disk_read (data->disk,
231
chunk_start >> GRUB_DISK_SECTOR_BITS,
232
chunk_start & (GRUB_DISK_SECTOR_SIZE - 1),
236
if (offset < SQUASH_CHUNK_SIZE)
238
offset -= SQUASH_CHUNK_SIZE;
239
chunk_start += 2 + (grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS);
242
csize = SQUASH_CHUNK_SIZE - offset;
246
if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED)
248
grub_disk_addr_t a = chunk_start + 2 + offset;
249
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
250
a & (GRUB_DISK_SECTOR_SIZE - 1),
258
grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS;
259
grub_disk_addr_t a = chunk_start + 2;
260
tmp = grub_malloc (bsize);
263
/* FIXME: buffer uncompressed data. */
264
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
265
a & (GRUB_DISK_SECTOR_SIZE - 1),
273
if (data->decompress (tmp, bsize, offset,
274
buf, csize, data) < 0)
283
buf = (char *) buf + csize;
285
return GRUB_ERR_NONE;
289
zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off,
290
char *outbuf, grub_size_t outsize,
291
struct grub_squash_data *data __attribute__ ((unused)))
293
return grub_zlib_decompress (inbuf, insize, off, outbuf, outsize);
297
lzo_decompress (char *inbuf, grub_size_t insize, grub_off_t off,
298
char *outbuf, grub_size_t len, struct grub_squash_data *data)
300
lzo_uint usize = data->blksz;
306
udata = grub_malloc (usize);
310
if (lzo1x_decompress_safe ((grub_uint8_t *) inbuf,
311
insize, udata, &usize, NULL) != LZO_E_OK)
313
grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk");
317
grub_memcpy (outbuf, udata + off, len);
323
xz_decompress (char *inbuf, grub_size_t insize, grub_off_t off,
324
char *outbuf, grub_size_t len, struct grub_squash_data *data)
330
xz_dec_reset (data->xzdec);
331
buf.in = (grub_uint8_t *) inbuf;
333
buf.in_size = insize;
334
buf.out = (grub_uint8_t *) data->xzbuf;
336
buf.out_size = XZBUFSIZ;
344
xzret = xz_dec_run (data->xzdec, &buf);
346
if (xzret != XZ_OK && xzret != XZ_STREAM_END)
348
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "invalid xz chunk");
351
if (pos + buf.out_pos >= off)
353
grub_ssize_t outoff = pos - off;
360
grub_memcpy (outbuf + outoff, buf.out, l);
365
l = buf.out_pos - outoff;
368
grub_memcpy (outbuf, buf.out + outoff, l);
374
if (xzret == XZ_STREAM_END)
380
static struct grub_squash_data *
381
squash_mount (grub_disk_t disk)
383
struct grub_squash_super sb;
385
struct grub_squash_data *data;
388
err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb);
389
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
390
grub_error (GRUB_ERR_BAD_FS, "not a squash4");
393
if (sb.magic != grub_cpu_to_le32_compile_time (SQUASH_MAGIC)
394
|| sb.block_size == 0
395
|| ((sb.block_size - 1) & sb.block_size))
397
grub_error (GRUB_ERR_BAD_FS, "not squash4");
401
err = grub_disk_read (disk,
402
grub_le_to_cpu64 (sb.unk1offset)
403
>> GRUB_DISK_SECTOR_BITS,
404
grub_le_to_cpu64 (sb.unk1offset)
405
& (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag);
406
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
407
grub_error (GRUB_ERR_BAD_FS, "not a squash4");
411
data = grub_zalloc (sizeof (*data));
416
data->fragments = grub_le_to_cpu64 (frag);
418
switch (sb.compression)
420
case grub_cpu_to_le16_compile_time (COMPRESSION_ZLIB):
421
data->decompress = zlib_decompress;
423
case grub_cpu_to_le16_compile_time (COMPRESSION_LZO):
424
data->decompress = lzo_decompress;
426
case grub_cpu_to_le16_compile_time (COMPRESSION_XZ):
427
data->decompress = xz_decompress;
428
data->xzbuf = grub_malloc (XZBUFSIZ);
434
data->xzdec = xz_dec_init (1 << 16);
437
grub_free (data->xzbuf);
444
grub_error (GRUB_ERR_BAD_FS, "unsupported compression %d",
445
grub_le_to_cpu16 (sb.compression));
449
data->blksz = grub_le_to_cpu32 (data->sb.block_size);
450
for (data->log2_blksz = 0;
451
(1U << data->log2_blksz) < data->blksz;
458
grub_squash_read_symlink (grub_fshelp_node_t node)
462
ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1);
464
err = read_chunk (node->data, ret,
465
grub_le_to_cpu32 (node->ino.symlink.namelen),
466
grub_le_to_cpu64 (node->data->sb.inodeoffset)
467
+ node->stack[node->stsize - 1].ino_chunk,
468
node->stack[node->stsize - 1].ino_offset
469
+ (node->ino.symlink.name - (char *) &node->ino));
475
ret[grub_le_to_cpu32 (node->ino.symlink.namelen)] = 0;
480
grub_squash_iterate_dir (grub_fshelp_node_t dir,
482
(*hook) (const char *filename,
483
enum grub_fshelp_filetype filetype,
484
grub_fshelp_node_t node))
487
grub_uint32_t endoff;
491
/* FIXME: why - 3 ? */
492
switch (dir->ino.type)
494
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_DIR):
495
off = grub_le_to_cpu16 (dir->ino.dir.offset);
496
endoff = grub_le_to_cpu16 (dir->ino.dir.size) + off - 3;
497
chunk = grub_le_to_cpu32 (dir->ino.dir.chunk);
499
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_DIR):
500
off = grub_le_to_cpu16 (dir->ino.long_dir.offset);
501
endoff = grub_le_to_cpu16 (dir->ino.long_dir.size) + off - 3;
502
chunk = grub_le_to_cpu32 (dir->ino.long_dir.chunk);
505
grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x",
506
grub_le_to_cpu16 (dir->ino.type));
511
grub_fshelp_node_t node;
512
node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
515
grub_memcpy (node, dir,
516
sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
517
if (hook (".", GRUB_FSHELP_DIR, node))
520
if (dir->stsize != 1)
524
node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
528
grub_memcpy (node, dir,
529
sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
532
err = read_chunk (dir->data, &node->ino, sizeof (node->ino),
533
grub_le_to_cpu64 (dir->data->sb.inodeoffset)
534
+ node->stack[node->stsize - 1].ino_chunk,
535
node->stack[node->stsize - 1].ino_offset);
539
if (hook ("..", GRUB_FSHELP_DIR, node))
546
struct grub_squash_dirent_header dh;
549
err = read_chunk (dir->data, &dh, sizeof (dh),
550
grub_le_to_cpu64 (dir->data->sb.diroffset)
555
for (i = 0; i < (unsigned) grub_le_to_cpu32 (dh.nelems) + 1; i++)
559
struct grub_fshelp_node *node;
560
enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG;
561
struct grub_squash_dirent di;
562
struct grub_squash_inode ino;
564
err = read_chunk (dir->data, &di, sizeof (di),
565
grub_le_to_cpu64 (dir->data->sb.diroffset)
571
err = read_chunk (dir->data, &ino, sizeof (ino),
572
grub_le_to_cpu64 (dir->data->sb.inodeoffset)
573
+ grub_le_to_cpu32 (dh.ino_chunk),
574
grub_cpu_to_le16 (di.ino_offset));
578
buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2);
581
err = read_chunk (dir->data, buf,
582
grub_le_to_cpu16 (di.namelen) + 1,
583
grub_le_to_cpu64 (dir->data->sb.diroffset)
588
off += grub_le_to_cpu16 (di.namelen) + 1;
589
buf[grub_le_to_cpu16 (di.namelen) + 1] = 0;
590
if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_DIR)
591
filetype = GRUB_FSHELP_DIR;
592
if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK)
593
filetype = GRUB_FSHELP_SYMLINK;
595
node = grub_malloc (sizeof (*node)
596
+ (dir->stsize + 1) * sizeof (dir->stack[0]));
600
grub_memcpy (node, dir,
601
sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
604
node->stack[node->stsize].ino_chunk = grub_le_to_cpu32 (dh.ino_chunk);
605
node->stack[node->stsize].ino_offset = grub_le_to_cpu16 (di.ino_offset);
607
r = hook (buf, filetype, node);
618
make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root)
620
grub_memset (root, 0, sizeof (*root));
623
root->stack[0].ino_chunk = grub_le_to_cpu32 (data->sb.root_ino_chunk);
624
root->stack[0].ino_offset = grub_cpu_to_le16 (data->sb.root_ino_offset);
625
return read_chunk (data, &root->ino, sizeof (root->ino),
626
grub_le_to_cpu64 (data->sb.inodeoffset)
627
+ root->stack[0].ino_chunk,
628
root->stack[0].ino_offset);
632
squash_unmount (struct grub_squash_data *data)
635
xz_dec_end (data->xzdec);
636
grub_free (data->xzbuf);
637
grub_free (data->ino.cumulated_block_sizes);
638
grub_free (data->ino.block_sizes);
644
grub_squash_dir (grub_device_t device, const char *path,
645
int (*hook) (const char *filename,
646
const struct grub_dirhook_info *info))
648
auto int NESTED_FUNC_ATTR iterate (const char *filename,
649
enum grub_fshelp_filetype filetype,
650
grub_fshelp_node_t node);
652
int NESTED_FUNC_ATTR iterate (const char *filename,
653
enum grub_fshelp_filetype filetype,
654
grub_fshelp_node_t node)
656
struct grub_dirhook_info info;
657
grub_memset (&info, 0, sizeof (info));
658
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
660
info.mtime = grub_le_to_cpu32 (node->ino.mtime);
662
return hook (filename, &info);
665
struct grub_squash_data *data = 0;
666
struct grub_fshelp_node *fdiro = 0;
667
struct grub_fshelp_node root;
670
data = squash_mount (device->disk);
674
err = make_root_node (data, &root);
678
grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir,
679
grub_squash_read_symlink, GRUB_FSHELP_DIR);
681
grub_squash_iterate_dir (fdiro, iterate);
683
squash_unmount (data);
689
grub_squash_open (struct grub_file *file, const char *name)
691
struct grub_squash_data *data = 0;
692
struct grub_fshelp_node *fdiro = 0;
693
struct grub_fshelp_node root;
696
data = squash_mount (file->device->disk);
700
err = make_root_node (data, &root);
704
grub_fshelp_find_file (name, &root, &fdiro, grub_squash_iterate_dir,
705
grub_squash_read_symlink, GRUB_FSHELP_REG);
708
squash_unmount (data);
713
data->ino.ino = fdiro->ino;
714
data->ino.block_sizes = NULL;
715
data->ino.cumulated_block_sizes = NULL;
716
data->ino.ino_chunk = fdiro->stack[fdiro->stsize - 1].ino_chunk;
717
data->ino.ino_offset = fdiro->stack[fdiro->stsize - 1].ino_offset;
719
switch (fdiro->ino.type)
721
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR):
722
file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size);
724
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR):
725
file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
729
grub_uint16_t type = grub_le_to_cpu16 (fdiro->ino.type);
731
squash_unmount (data);
732
return grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x", type);
738
return GRUB_ERR_NONE;
742
direct_read (struct grub_squash_data *data,
743
struct grub_squash_cache_inode *ino,
744
grub_off_t off, char *buf, grub_size_t len)
747
grub_off_t cumulated_uncompressed_size = 0;
750
grub_size_t origlen = len;
752
switch (ino->ino.type)
754
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR):
755
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
757
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR):
758
a = grub_le_to_cpu32 (ino->ino.file.chunk);
762
if (!ino->block_sizes)
764
grub_off_t total_size = 0;
765
grub_size_t total_blocks;
766
grub_size_t block_offset = 0;
767
switch (ino->ino.type)
769
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR):
770
total_size = grub_le_to_cpu64 (ino->ino.long_file.size);
771
block_offset = ((char *) &ino->ino.long_file.block_size
772
- (char *) &ino->ino);
774
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR):
775
total_size = grub_le_to_cpu32 (ino->ino.file.size);
776
block_offset = ((char *) &ino->ino.file.block_size
777
- (char *) &ino->ino);
780
total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz);
781
ino->block_sizes = grub_malloc (total_blocks
782
* sizeof (ino->block_sizes[0]));
783
ino->cumulated_block_sizes = grub_malloc (total_blocks
784
* sizeof (ino->cumulated_block_sizes[0]));
785
if (!ino->block_sizes || !ino->cumulated_block_sizes)
787
grub_free (ino->block_sizes);
788
grub_free (ino->cumulated_block_sizes);
789
ino->block_sizes = 0;
790
ino->cumulated_block_sizes = 0;
793
err = read_chunk (data, ino->block_sizes,
794
total_blocks * sizeof (ino->block_sizes[0]),
795
grub_le_to_cpu64 (data->sb.inodeoffset)
797
ino->ino_offset + block_offset);
800
grub_free (ino->block_sizes);
801
grub_free (ino->cumulated_block_sizes);
802
ino->block_sizes = 0;
803
ino->cumulated_block_sizes = 0;
806
ino->cumulated_block_sizes[0] = 0;
807
for (i = 1; i < total_blocks; i++)
808
ino->cumulated_block_sizes[i] = ino->cumulated_block_sizes[i - 1]
809
+ (grub_le_to_cpu32 (ino->block_sizes[i - 1]) & ~SQUASH_BLOCK_FLAGS);
813
a = sizeof (struct grub_squash_super);
814
i = off >> data->log2_blksz;
815
cumulated_uncompressed_size = data->blksz * (grub_disk_addr_t) i;
816
while (cumulated_uncompressed_size < off + len)
818
grub_size_t boff, curread;
819
boff = off - cumulated_uncompressed_size;
820
curread = data->blksz - boff;
823
if (!(ino->block_sizes[i]
824
& grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED)))
828
csize = grub_le_to_cpu32 (ino->block_sizes[i]) & ~SQUASH_BLOCK_FLAGS;
829
block = grub_malloc (csize);
832
err = grub_disk_read (data->disk,
833
(ino->cumulated_block_sizes[i] + a)
834
>> GRUB_DISK_SECTOR_BITS,
835
(ino->cumulated_block_sizes[i] + a)
836
& (GRUB_DISK_SECTOR_SIZE - 1),
843
if (data->decompress (block, csize, boff, buf, curread, data)
844
!= (grub_ssize_t) curread)
848
grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk");
854
err = grub_disk_read (data->disk,
855
(ino->cumulated_block_sizes[i] + a + boff)
856
>> GRUB_DISK_SECTOR_BITS,
857
(ino->cumulated_block_sizes[i] + a + boff)
858
& (GRUB_DISK_SECTOR_SIZE - 1),
865
cumulated_uncompressed_size += grub_le_to_cpu32 (data->sb.block_size);
873
grub_squash_read_data (struct grub_squash_data *data,
874
struct grub_squash_cache_inode *ino,
875
grub_off_t off, char *buf, grub_size_t len)
878
grub_uint64_t a = 0, b;
879
grub_uint32_t fragment = 0;
881
struct grub_squash_frag_desc frag;
883
switch (ino->ino.type)
885
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR):
886
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
887
fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment);
889
case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR):
890
a = grub_le_to_cpu32 (ino->ino.file.chunk);
891
fragment = grub_le_to_cpu32 (ino->ino.file.fragment);
895
if (fragment == 0xffffffff)
896
return direct_read (data, ino, off, buf, len);
898
err = read_chunk (data, &frag, sizeof (frag),
899
data->fragments, sizeof (frag) * fragment);
902
a += grub_le_to_cpu64 (frag.offset);
903
compressed = !(frag.size & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED));
904
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
905
b = grub_le_to_cpu32 (ino->ino.long_file.offset) + off;
907
b = grub_le_to_cpu32 (ino->ino.file.offset) + off;
909
/* FIXME: cache uncompressed chunks. */
913
block = grub_malloc (grub_le_to_cpu32 (frag.size));
916
err = grub_disk_read (data->disk,
917
a >> GRUB_DISK_SECTOR_BITS,
918
a & (GRUB_DISK_SECTOR_SIZE - 1),
919
grub_le_to_cpu32 (frag.size), block);
925
if (data->decompress (block, grub_le_to_cpu32 (frag.size),
927
!= (grub_ssize_t) len)
931
grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk");
938
err = grub_disk_read (data->disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
939
(a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
947
grub_squash_read (grub_file_t file, char *buf, grub_size_t len)
949
struct grub_squash_data *data = file->data;
951
return grub_squash_read_data (data, &data->ino,
952
file->offset, buf, len);
956
grub_squash_close (grub_file_t file)
958
squash_unmount (file->data);
959
return GRUB_ERR_NONE;
963
grub_squash_mtime (grub_device_t dev, grub_int32_t *tm)
965
struct grub_squash_data *data = 0;
967
data = squash_mount (dev->disk);
970
*tm = grub_le_to_cpu32 (data->sb.creation_time);
971
squash_unmount (data);
972
return GRUB_ERR_NONE;
975
static struct grub_fs grub_squash_fs =
978
.dir = grub_squash_dir,
979
.open = grub_squash_open,
980
.read = grub_squash_read,
981
.close = grub_squash_close,
982
.mtime = grub_squash_mtime,
984
.reserved_first_sector = 0,
985
.blocklist_install = 0,
990
GRUB_MOD_INIT(squash4)
992
grub_fs_register (&grub_squash_fs);
995
GRUB_MOD_FINI(squash4)
997
grub_fs_unregister (&grub_squash_fs);