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
;
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];
96 grub_uint32_t dummy1
[3];
97 grub_uint32_t fragment
;
100 grub_uint32_t block_size
[0];
101 } GRUB_PACKED long_file
;
106 grub_uint16_t offset
;
109 grub_uint32_t dummy1
;
112 grub_uint32_t dummy2
;
113 grub_uint16_t dummy3
;
114 grub_uint16_t offset
;
115 } GRUB_PACKED long_dir
;
118 grub_uint32_t namelen
;
120 } GRUB_PACKED symlink
;
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
;
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
;
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
;
171 SQUASH_CHUNK_FLAGS
= 0x8000,
172 SQUASH_CHUNK_UNCOMPRESSED
= 0x8000
177 SQUASH_BLOCK_FLAGS
= 0x1000000,
178 SQUASH_BLOCK_UNCOMPRESSED
= 0x1000000
183 COMPRESSION_ZLIB
= 1,
190 #define SQUASH_CHUNK_SIZE 0x2000
191 #define XZBUFSIZ 0x2000
193 struct grub_squash_data
196 struct grub_squash_super sb
;
197 struct grub_squash_cache_inode ino
;
198 grub_uint64_t fragments
;
201 grub_ssize_t (*decompress
) (char *inbuf
, grub_size_t insize
, grub_off_t off
,
202 char *outbuf
, grub_size_t outsize
,
203 struct grub_squash_data
*data
);
204 struct xz_dec
*xzdec
;
208 struct grub_fshelp_node
210 struct grub_squash_data
*data
;
211 struct grub_squash_inode ino
;
215 grub_disk_addr_t ino_chunk
;
216 grub_uint16_t ino_offset
;
221 read_chunk (struct grub_squash_data
*data
, void *buf
, grub_size_t len
,
222 grub_uint64_t chunk_start
, grub_off_t offset
)
231 err
= grub_disk_read (data
->disk
,
232 chunk_start
>> GRUB_DISK_SECTOR_BITS
,
233 chunk_start
& (GRUB_DISK_SECTOR_SIZE
- 1),
237 if (offset
< SQUASH_CHUNK_SIZE
)
239 offset
-= SQUASH_CHUNK_SIZE
;
240 chunk_start
+= 2 + (grub_le_to_cpu16 (d
) & ~SQUASH_CHUNK_FLAGS
);
243 csize
= SQUASH_CHUNK_SIZE
- offset
;
247 if (grub_le_to_cpu16 (d
) & SQUASH_CHUNK_UNCOMPRESSED
)
249 grub_disk_addr_t a
= chunk_start
+ 2 + offset
;
250 err
= grub_disk_read (data
->disk
, (a
>> GRUB_DISK_SECTOR_BITS
),
251 a
& (GRUB_DISK_SECTOR_SIZE
- 1),
259 grub_size_t bsize
= grub_le_to_cpu16 (d
) & ~SQUASH_CHUNK_FLAGS
;
260 grub_disk_addr_t a
= chunk_start
+ 2;
261 tmp
= grub_malloc (bsize
);
264 /* FIXME: buffer uncompressed data. */
265 err
= grub_disk_read (data
->disk
, (a
>> GRUB_DISK_SECTOR_BITS
),
266 a
& (GRUB_DISK_SECTOR_SIZE
- 1),
274 if (data
->decompress (tmp
, bsize
, offset
,
275 buf
, csize
, data
) < 0)
284 buf
= (char *) buf
+ csize
;
286 return GRUB_ERR_NONE
;
290 zlib_decompress (char *inbuf
, grub_size_t insize
, grub_off_t off
,
291 char *outbuf
, grub_size_t outsize
,
292 struct grub_squash_data
*data
__attribute__ ((unused
)))
294 return grub_zlib_decompress (inbuf
, insize
, off
, outbuf
, outsize
);
298 lzo_decompress (char *inbuf
, grub_size_t insize
, grub_off_t off
,
299 char *outbuf
, grub_size_t len
, struct grub_squash_data
*data
)
301 lzo_uint usize
= data
->blksz
;
307 udata
= grub_malloc (usize
);
311 if (lzo1x_decompress_safe ((grub_uint8_t
*) inbuf
,
312 insize
, udata
, &usize
, NULL
) != LZO_E_OK
)
314 grub_error (GRUB_ERR_BAD_FS
, "incorrect compressed chunk");
318 grub_memcpy (outbuf
, udata
+ off
, len
);
324 xz_decompress (char *inbuf
, grub_size_t insize
, grub_off_t off
,
325 char *outbuf
, grub_size_t len
, struct grub_squash_data
*data
)
331 xz_dec_reset (data
->xzdec
);
332 buf
.in
= (grub_uint8_t
*) inbuf
;
334 buf
.in_size
= insize
;
335 buf
.out
= (grub_uint8_t
*) data
->xzbuf
;
337 buf
.out_size
= XZBUFSIZ
;
345 xzret
= xz_dec_run (data
->xzdec
, &buf
);
347 if (xzret
!= XZ_OK
&& xzret
!= XZ_STREAM_END
)
349 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
, "invalid xz chunk");
352 if (pos
+ buf
.out_pos
>= off
)
354 grub_ssize_t outoff
= pos
- off
;
361 grub_memcpy (outbuf
+ outoff
, buf
.out
, l
);
366 l
= buf
.out_pos
- outoff
;
369 grub_memcpy (outbuf
, buf
.out
+ outoff
, l
);
375 if (xzret
== XZ_STREAM_END
)
381 int LZ4_uncompress_unknownOutputSize(const char *source
, char *dest
, int isize
, int maxOutputSize
);
382 static grub_ssize_t
lz4_decompress_wrap(char *inbuf
, grub_size_t insize
, grub_off_t off
,
383 char *outbuf
, grub_size_t len
, struct grub_squash_data
*data
)
386 int usize
= data
->blksz
;
391 udata
= grub_malloc (usize
);
395 LZ4_uncompress_unknownOutputSize(inbuf
, udata
, insize
, usize
);
396 grub_memcpy (outbuf
, udata
+ off
, len
);
401 static struct grub_squash_data
*
402 squash_mount (grub_disk_t disk
)
404 struct grub_squash_super sb
;
406 struct grub_squash_data
*data
;
409 err
= grub_disk_read (disk
, 0, 0, sizeof (sb
), &sb
);
410 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
411 grub_error (GRUB_ERR_BAD_FS
, "not a squash4");
414 if (sb
.magic
!= grub_cpu_to_le32_compile_time (SQUASH_MAGIC
)
415 || sb
.block_size
== 0
416 || ((sb
.block_size
- 1) & sb
.block_size
))
418 grub_error (GRUB_ERR_BAD_FS
, "not squash4");
422 err
= grub_disk_read (disk
,
423 grub_le_to_cpu64 (sb
.unk1offset
)
424 >> GRUB_DISK_SECTOR_BITS
,
425 grub_le_to_cpu64 (sb
.unk1offset
)
426 & (GRUB_DISK_SECTOR_SIZE
- 1), sizeof (frag
), &frag
);
427 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
428 grub_error (GRUB_ERR_BAD_FS
, "not a squash4");
432 data
= grub_zalloc (sizeof (*data
));
437 data
->fragments
= grub_le_to_cpu64 (frag
);
439 switch (sb
.compression
)
441 case grub_cpu_to_le16_compile_time (COMPRESSION_ZLIB
):
442 data
->decompress
= zlib_decompress
;
444 case grub_cpu_to_le16_compile_time (COMPRESSION_LZO
):
445 data
->decompress
= lzo_decompress
;
447 case grub_cpu_to_le16_compile_time (COMPRESSION_LZ4
):
448 data
->decompress
= lz4_decompress_wrap
;
450 case grub_cpu_to_le16_compile_time (COMPRESSION_XZ
):
451 data
->decompress
= xz_decompress
;
452 data
->xzbuf
= grub_malloc (XZBUFSIZ
);
458 data
->xzdec
= xz_dec_init (1 << 16);
461 grub_free (data
->xzbuf
);
468 grub_error (GRUB_ERR_BAD_FS
, "unsupported compression %d",
469 grub_le_to_cpu16 (sb
.compression
));
473 data
->blksz
= grub_le_to_cpu32 (data
->sb
.block_size
);
474 for (data
->log2_blksz
= 0;
475 (1U << data
->log2_blksz
) < data
->blksz
;
482 grub_squash_read_symlink (grub_fshelp_node_t node
)
486 ret
= grub_malloc (grub_le_to_cpu32 (node
->ino
.symlink
.namelen
) + 1);
488 err
= read_chunk (node
->data
, ret
,
489 grub_le_to_cpu32 (node
->ino
.symlink
.namelen
),
490 grub_le_to_cpu64 (node
->data
->sb
.inodeoffset
)
491 + node
->stack
[node
->stsize
- 1].ino_chunk
,
492 node
->stack
[node
->stsize
- 1].ino_offset
493 + (node
->ino
.symlink
.name
- (char *) &node
->ino
));
499 ret
[grub_le_to_cpu32 (node
->ino
.symlink
.namelen
)] = 0;
504 grub_squash_iterate_dir (grub_fshelp_node_t dir
,
505 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
508 grub_uint32_t endoff
;
512 /* FIXME: why - 3 ? */
513 switch (dir
->ino
.type
)
515 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_DIR
):
516 off
= grub_le_to_cpu16 (dir
->ino
.dir
.offset
);
517 endoff
= grub_le_to_cpu16 (dir
->ino
.dir
.size
) + off
- 3;
518 chunk
= grub_le_to_cpu32 (dir
->ino
.dir
.chunk
);
520 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_DIR
):
521 off
= grub_le_to_cpu16 (dir
->ino
.long_dir
.offset
);
522 endoff
= grub_le_to_cpu16 (dir
->ino
.long_dir
.size
) + off
- 3;
523 chunk
= grub_le_to_cpu32 (dir
->ino
.long_dir
.chunk
);
526 grub_error (GRUB_ERR_BAD_FS
, "unexpected ino type 0x%x",
527 grub_le_to_cpu16 (dir
->ino
.type
));
532 grub_fshelp_node_t node
;
533 node
= grub_malloc (sizeof (*node
) + dir
->stsize
* sizeof (dir
->stack
[0]));
536 grub_memcpy (node
, dir
,
537 sizeof (*node
) + dir
->stsize
* sizeof (dir
->stack
[0]));
538 if (hook (".", GRUB_FSHELP_DIR
, node
, hook_data
))
541 if (dir
->stsize
!= 1)
545 node
= grub_malloc (sizeof (*node
) + dir
->stsize
* sizeof (dir
->stack
[0]));
549 grub_memcpy (node
, dir
,
550 sizeof (*node
) + dir
->stsize
* sizeof (dir
->stack
[0]));
553 err
= read_chunk (dir
->data
, &node
->ino
, sizeof (node
->ino
),
554 grub_le_to_cpu64 (dir
->data
->sb
.inodeoffset
)
555 + node
->stack
[node
->stsize
- 1].ino_chunk
,
556 node
->stack
[node
->stsize
- 1].ino_offset
);
560 if (hook ("..", GRUB_FSHELP_DIR
, node
, hook_data
))
567 struct grub_squash_dirent_header dh
;
570 err
= read_chunk (dir
->data
, &dh
, sizeof (dh
),
571 grub_le_to_cpu64 (dir
->data
->sb
.diroffset
)
576 for (i
= 0; i
< (unsigned) grub_le_to_cpu32 (dh
.nelems
) + 1; i
++)
580 struct grub_fshelp_node
*node
;
581 enum grub_fshelp_filetype filetype
= GRUB_FSHELP_REG
;
582 struct grub_squash_dirent di
;
583 struct grub_squash_inode ino
;
585 err
= read_chunk (dir
->data
, &di
, sizeof (di
),
586 grub_le_to_cpu64 (dir
->data
->sb
.diroffset
)
592 err
= read_chunk (dir
->data
, &ino
, sizeof (ino
),
593 grub_le_to_cpu64 (dir
->data
->sb
.inodeoffset
)
594 + grub_le_to_cpu32 (dh
.ino_chunk
),
595 grub_cpu_to_le16 (di
.ino_offset
));
599 buf
= grub_malloc (grub_le_to_cpu16 (di
.namelen
) + 2);
602 err
= read_chunk (dir
->data
, buf
,
603 grub_le_to_cpu16 (di
.namelen
) + 1,
604 grub_le_to_cpu64 (dir
->data
->sb
.diroffset
)
609 off
+= grub_le_to_cpu16 (di
.namelen
) + 1;
610 buf
[grub_le_to_cpu16 (di
.namelen
) + 1] = 0;
611 if (grub_le_to_cpu16 (di
.type
) == SQUASH_TYPE_DIR
)
612 filetype
= GRUB_FSHELP_DIR
;
613 if (grub_le_to_cpu16 (di
.type
) == SQUASH_TYPE_SYMLINK
)
614 filetype
= GRUB_FSHELP_SYMLINK
;
616 node
= grub_malloc (sizeof (*node
)
617 + (dir
->stsize
+ 1) * sizeof (dir
->stack
[0]));
621 grub_memcpy (node
, dir
,
622 sizeof (*node
) + dir
->stsize
* sizeof (dir
->stack
[0]));
625 node
->stack
[node
->stsize
].ino_chunk
= grub_le_to_cpu32 (dh
.ino_chunk
);
626 node
->stack
[node
->stsize
].ino_offset
= grub_le_to_cpu16 (di
.ino_offset
);
628 r
= hook (buf
, filetype
, node
, hook_data
);
639 make_root_node (struct grub_squash_data
*data
, struct grub_fshelp_node
*root
)
641 grub_memset (root
, 0, sizeof (*root
));
644 root
->stack
[0].ino_chunk
= grub_le_to_cpu32 (data
->sb
.root_ino_chunk
);
645 root
->stack
[0].ino_offset
= grub_cpu_to_le16 (data
->sb
.root_ino_offset
);
646 return read_chunk (data
, &root
->ino
, sizeof (root
->ino
),
647 grub_le_to_cpu64 (data
->sb
.inodeoffset
)
648 + root
->stack
[0].ino_chunk
,
649 root
->stack
[0].ino_offset
);
653 squash_unmount (struct grub_squash_data
*data
)
656 xz_dec_end (data
->xzdec
);
657 grub_free (data
->xzbuf
);
658 grub_free (data
->ino
.cumulated_block_sizes
);
659 grub_free (data
->ino
.block_sizes
);
664 /* Context for grub_squash_dir. */
665 struct grub_squash_dir_ctx
667 grub_fs_dir_hook_t hook
;
671 /* Helper for grub_squash_dir. */
673 grub_squash_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
674 grub_fshelp_node_t node
, void *data
)
676 struct grub_squash_dir_ctx
*ctx
= data
;
677 struct grub_dirhook_info info
;
679 grub_memset (&info
, 0, sizeof (info
));
680 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
682 info
.mtime
= grub_le_to_cpu32 (node
->ino
.mtime
);
684 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
688 grub_squash_dir (grub_device_t device
, const char *path
,
689 grub_fs_dir_hook_t hook
, void *hook_data
)
691 struct grub_squash_dir_ctx ctx
= { hook
, hook_data
};
692 struct grub_squash_data
*data
= 0;
693 struct grub_fshelp_node
*fdiro
= 0;
694 struct grub_fshelp_node root
;
697 data
= squash_mount (device
->disk
);
701 err
= make_root_node (data
, &root
);
705 grub_fshelp_find_file (path
, &root
, &fdiro
, grub_squash_iterate_dir
,
706 grub_squash_read_symlink
, GRUB_FSHELP_DIR
);
708 grub_squash_iterate_dir (fdiro
, grub_squash_dir_iter
, &ctx
);
710 squash_unmount (data
);
716 grub_squash_open (struct grub_file
*file
, const char *name
)
718 struct grub_squash_data
*data
= 0;
719 struct grub_fshelp_node
*fdiro
= 0;
720 struct grub_fshelp_node root
;
723 data
= squash_mount (file
->device
->disk
);
727 err
= make_root_node (data
, &root
);
731 grub_fshelp_find_file (name
, &root
, &fdiro
, grub_squash_iterate_dir
,
732 grub_squash_read_symlink
, GRUB_FSHELP_REG
);
735 squash_unmount (data
);
740 data
->ino
.ino
= fdiro
->ino
;
741 data
->ino
.block_sizes
= NULL
;
742 data
->ino
.cumulated_block_sizes
= NULL
;
743 data
->ino
.ino_chunk
= fdiro
->stack
[fdiro
->stsize
- 1].ino_chunk
;
744 data
->ino
.ino_offset
= fdiro
->stack
[fdiro
->stsize
- 1].ino_offset
;
746 switch (fdiro
->ino
.type
)
748 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR
):
749 file
->size
= grub_le_to_cpu64 (fdiro
->ino
.long_file
.size
);
751 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR
):
752 file
->size
= grub_le_to_cpu32 (fdiro
->ino
.file
.size
);
756 grub_uint16_t type
= grub_le_to_cpu16 (fdiro
->ino
.type
);
758 squash_unmount (data
);
759 return grub_error (GRUB_ERR_BAD_FS
, "unexpected ino type 0x%x", type
);
765 return GRUB_ERR_NONE
;
769 direct_read (struct grub_squash_data
*data
,
770 struct grub_squash_cache_inode
*ino
,
771 grub_off_t off
, char *buf
, grub_size_t len
)
774 grub_off_t cumulated_uncompressed_size
= 0;
777 grub_size_t origlen
= len
;
779 switch (ino
->ino
.type
)
781 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR
):
782 a
= grub_le_to_cpu64 (ino
->ino
.long_file
.chunk
);
784 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR
):
785 a
= grub_le_to_cpu32 (ino
->ino
.file
.chunk
);
789 if (!ino
->block_sizes
)
791 grub_off_t total_size
= 0;
792 grub_size_t total_blocks
;
793 grub_size_t block_offset
= 0;
794 switch (ino
->ino
.type
)
796 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR
):
797 total_size
= grub_le_to_cpu64 (ino
->ino
.long_file
.size
);
798 block_offset
= ((char *) &ino
->ino
.long_file
.block_size
799 - (char *) &ino
->ino
);
801 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR
):
802 total_size
= grub_le_to_cpu32 (ino
->ino
.file
.size
);
803 block_offset
= ((char *) &ino
->ino
.file
.block_size
804 - (char *) &ino
->ino
);
807 total_blocks
= ((total_size
+ data
->blksz
- 1) >> data
->log2_blksz
);
808 ino
->block_sizes
= grub_malloc (total_blocks
809 * sizeof (ino
->block_sizes
[0]));
810 ino
->cumulated_block_sizes
= grub_malloc (total_blocks
811 * sizeof (ino
->cumulated_block_sizes
[0]));
812 if (!ino
->block_sizes
|| !ino
->cumulated_block_sizes
)
814 grub_free (ino
->block_sizes
);
815 grub_free (ino
->cumulated_block_sizes
);
816 ino
->block_sizes
= 0;
817 ino
->cumulated_block_sizes
= 0;
820 err
= read_chunk (data
, ino
->block_sizes
,
821 total_blocks
* sizeof (ino
->block_sizes
[0]),
822 grub_le_to_cpu64 (data
->sb
.inodeoffset
)
824 ino
->ino_offset
+ block_offset
);
827 grub_free (ino
->block_sizes
);
828 grub_free (ino
->cumulated_block_sizes
);
829 ino
->block_sizes
= 0;
830 ino
->cumulated_block_sizes
= 0;
833 ino
->cumulated_block_sizes
[0] = 0;
834 for (i
= 1; i
< total_blocks
; i
++)
835 ino
->cumulated_block_sizes
[i
] = ino
->cumulated_block_sizes
[i
- 1]
836 + (grub_le_to_cpu32 (ino
->block_sizes
[i
- 1]) & ~SQUASH_BLOCK_FLAGS
);
840 a
= sizeof (struct grub_squash_super
);
841 i
= off
>> data
->log2_blksz
;
842 cumulated_uncompressed_size
= data
->blksz
* (grub_disk_addr_t
) i
;
843 while (cumulated_uncompressed_size
< off
+ len
)
845 grub_size_t boff
, curread
;
846 boff
= off
- cumulated_uncompressed_size
;
847 curread
= data
->blksz
- boff
;
850 if (!ino
->block_sizes
[i
])
853 grub_memset (buf
, '\0', curread
);
855 else if (!(ino
->block_sizes
[i
]
856 & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED
)))
860 csize
= grub_le_to_cpu32 (ino
->block_sizes
[i
]) & ~SQUASH_BLOCK_FLAGS
;
861 block
= grub_malloc (csize
);
864 err
= grub_disk_read (data
->disk
,
865 (ino
->cumulated_block_sizes
[i
] + a
)
866 >> GRUB_DISK_SECTOR_BITS
,
867 (ino
->cumulated_block_sizes
[i
] + a
)
868 & (GRUB_DISK_SECTOR_SIZE
- 1),
875 if (data
->decompress (block
, csize
, boff
, buf
, curread
, data
)
876 != (grub_ssize_t
) curread
)
880 grub_error (GRUB_ERR_BAD_FS
, "incorrect compressed chunk");
886 err
= grub_disk_read (data
->disk
,
887 (ino
->cumulated_block_sizes
[i
] + a
+ boff
)
888 >> GRUB_DISK_SECTOR_BITS
,
889 (ino
->cumulated_block_sizes
[i
] + a
+ boff
)
890 & (GRUB_DISK_SECTOR_SIZE
- 1),
897 cumulated_uncompressed_size
+= grub_le_to_cpu32 (data
->sb
.block_size
);
905 grub_squash_read (grub_file_t file
, char *buf
, grub_size_t len
)
907 struct grub_squash_data
*data
= file
->data
;
908 struct grub_squash_cache_inode
*ino
= &data
->ino
;
909 grub_off_t off
= file
->offset
;
912 grub_uint32_t fragment
= 0;
914 struct grub_squash_frag_desc frag
;
915 grub_off_t direct_len
;
916 grub_uint64_t mask
= grub_le_to_cpu32 (data
->sb
.block_size
) - 1;
917 grub_size_t orig_len
= len
;
919 switch (ino
->ino
.type
)
921 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR
):
922 fragment
= grub_le_to_cpu32 (ino
->ino
.long_file
.fragment
);
924 case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR
):
925 fragment
= grub_le_to_cpu32 (ino
->ino
.file
.fragment
);
929 /* Squash may pack file tail as fragment. So read initial part directly and
930 get tail from fragments */
931 direct_len
= fragment
== 0xffffffff ? file
->size
: file
->size
& ~mask
;
932 if (off
< direct_len
)
934 grub_size_t read_len
= direct_len
- off
;
939 res
= direct_read (data
, ino
, off
, buf
, read_len
);
940 if ((grub_size_t
) res
!= read_len
)
941 return -1; /* FIXME: is short read possible here? */
951 err
= read_chunk (data
, &frag
, sizeof (frag
),
952 data
->fragments
, sizeof (frag
) * fragment
);
955 a
= grub_le_to_cpu64 (frag
.offset
);
956 compressed
= !(frag
.size
& grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED
));
957 if (ino
->ino
.type
== grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR
))
958 b
= grub_le_to_cpu32 (ino
->ino
.long_file
.offset
) + off
;
960 b
= grub_le_to_cpu32 (ino
->ino
.file
.offset
) + off
;
962 /* FIXME: cache uncompressed chunks. */
966 block
= grub_malloc (grub_le_to_cpu32 (frag
.size
));
969 err
= grub_disk_read (data
->disk
,
970 a
>> GRUB_DISK_SECTOR_BITS
,
971 a
& (GRUB_DISK_SECTOR_SIZE
- 1),
972 grub_le_to_cpu32 (frag
.size
), block
);
978 if (data
->decompress (block
, grub_le_to_cpu32 (frag
.size
),
980 != (grub_ssize_t
) len
)
984 grub_error (GRUB_ERR_BAD_FS
, "incorrect compressed chunk");
991 err
= grub_disk_read (data
->disk
, (a
+ b
) >> GRUB_DISK_SECTOR_BITS
,
992 (a
+ b
) & (GRUB_DISK_SECTOR_SIZE
- 1), len
, buf
);
1000 grub_squash_close (grub_file_t file
)
1002 squash_unmount (file
->data
);
1003 return GRUB_ERR_NONE
;
1007 grub_squash_mtime (grub_device_t dev
, grub_int32_t
*tm
)
1009 struct grub_squash_data
*data
= 0;
1011 data
= squash_mount (dev
->disk
);
1014 *tm
= grub_le_to_cpu32 (data
->sb
.creation_time
);
1015 squash_unmount (data
);
1016 return GRUB_ERR_NONE
;
1019 static struct grub_fs grub_squash_fs
=
1022 .fs_dir
= grub_squash_dir
,
1023 .fs_open
= grub_squash_open
,
1024 .fs_read
= grub_squash_read
,
1025 .fs_close
= grub_squash_close
,
1026 .fs_mtime
= grub_squash_mtime
,
1028 .reserved_first_sector
= 0,
1029 .blocklist_install
= 0,
1034 GRUB_MOD_INIT(squash4
)
1036 grub_fs_register (&grub_squash_fs
);
1039 GRUB_MOD_FINI(squash4
)
1041 grub_fs_unregister (&grub_squash_fs
);