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
);