1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Bootlin
5 * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
7 * sqfs.c: SquashFS filesystem implementation
10 #include <asm/unaligned.h>
14 #include <linux/types.h>
15 #include <asm/byteorder.h>
22 #include "sqfs_decompressor.h"
23 #include "sqfs_filesystem.h"
24 #include "sqfs_utils.h"
26 static struct squashfs_ctxt ctxt
;
28 static int sqfs_disk_read(__u32 block
, __u32 nr_blocks
, void *buf
)
35 ret
= blk_dread(ctxt
.cur_dev
, ctxt
.cur_part_info
.start
+ block
,
44 static int sqfs_read_sblk(struct squashfs_super_block
**sblk
)
46 *sblk
= malloc_cache_aligned(ctxt
.cur_dev
->blksz
);
50 if (sqfs_disk_read(0, 1, *sblk
) != 1) {
59 static int sqfs_count_tokens(const char *filename
)
61 int token_count
= 1, l
;
63 for (l
= 1; l
< strlen(filename
); l
++) {
64 if (filename
[l
] == '/')
68 /* Ignore trailing '/' in path */
69 if (filename
[strlen(filename
) - 1] == '/')
79 * Calculates how many blocks are needed for the buffer used in sqfs_disk_read.
80 * The memory section (e.g. inode table) start offset and its end (i.e. the next
81 * table start) must be specified. It also calculates the offset from which to
82 * start reading the buffer.
84 static int sqfs_calc_n_blks(__le64 start
, __le64 end
, u64
*offset
)
86 u64 start_
, table_size
;
88 table_size
= le64_to_cpu(end
) - le64_to_cpu(start
);
89 start_
= le64_to_cpu(start
) / ctxt
.cur_dev
->blksz
;
90 *offset
= le64_to_cpu(start
) - (start_
* ctxt
.cur_dev
->blksz
);
92 return DIV_ROUND_UP(table_size
+ *offset
, ctxt
.cur_dev
->blksz
);
96 * Retrieves fragment block entry and returns true if the fragment block is
99 static int sqfs_frag_lookup(u32 inode_fragment_index
,
100 struct squashfs_fragment_block_entry
*e
)
102 u64 start
, n_blks
, src_len
, table_offset
, start_block
;
103 unsigned char *metadata_buffer
, *metadata
, *table
;
104 struct squashfs_fragment_block_entry
*entries
;
105 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
106 unsigned long dest_len
;
107 int block
, offset
, ret
;
110 metadata_buffer
= NULL
;
114 if (inode_fragment_index
>= get_unaligned_le32(&sblk
->fragments
))
117 start
= get_unaligned_le64(&sblk
->fragment_table_start
) /
119 n_blks
= sqfs_calc_n_blks(sblk
->fragment_table_start
,
120 sblk
->export_table_start
,
123 /* Allocate a proper sized buffer to store the fragment index table */
124 table
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
130 if (sqfs_disk_read(start
, n_blks
, table
) < 0) {
135 block
= SQFS_FRAGMENT_INDEX(inode_fragment_index
);
136 offset
= SQFS_FRAGMENT_INDEX_OFFSET(inode_fragment_index
);
139 * Get the start offset of the metadata block that contains the right
140 * fragment block entry
142 start_block
= get_unaligned_le64(table
+ table_offset
+ block
*
145 start
= start_block
/ ctxt
.cur_dev
->blksz
;
146 n_blks
= sqfs_calc_n_blks(cpu_to_le64(start_block
),
147 sblk
->fragment_table_start
, &table_offset
);
149 metadata_buffer
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
150 if (!metadata_buffer
) {
155 if (sqfs_disk_read(start
, n_blks
, metadata_buffer
) < 0) {
160 /* Every metadata block starts with a 16-bit header */
161 header
= get_unaligned_le16(metadata_buffer
+ table_offset
);
162 metadata
= metadata_buffer
+ table_offset
+ SQFS_HEADER_SIZE
;
164 if (!metadata
|| !header
) {
169 entries
= malloc(SQFS_METADATA_BLOCK_SIZE
);
175 if (SQFS_COMPRESSED_METADATA(header
)) {
176 src_len
= SQFS_METADATA_SIZE(header
);
177 dest_len
= SQFS_METADATA_BLOCK_SIZE
;
178 ret
= sqfs_decompress(&ctxt
, entries
, &dest_len
, metadata
,
185 memcpy(entries
, metadata
, SQFS_METADATA_SIZE(header
));
188 *e
= entries
[offset
];
189 ret
= SQFS_COMPRESSED_BLOCK(e
->size
);
193 free(metadata_buffer
);
200 * The entry name is a flexible array member, and we don't know its size before
201 * actually reading the entry. So we need a first copy to retrieve this size so
202 * we can finally copy the whole struct.
204 static int sqfs_read_entry(struct squashfs_directory_entry
**dest
, void *src
)
206 struct squashfs_directory_entry
*tmp
;
210 sz
= get_unaligned_le16(src
+ sizeof(*tmp
) - sizeof(u16
));
212 * 'src' points to the begin of a directory entry, and 'sz' gets its
213 * 'name_size' member's value. name_size is actually the string
214 * length - 1, so adding 2 compensates this difference and adds space
215 * for the trailling null byte.
217 *dest
= malloc(sizeof(*tmp
) + sz
+ 2);
221 memcpy(*dest
, src
, sizeof(*tmp
) + sz
+ 1);
222 (*dest
)->name
[sz
+ 1] = '\0';
227 static int sqfs_get_tokens_length(char **tokens
, int count
)
232 * 1 is added to the result of strlen to consider the slash separator
233 * between the tokens.
235 for (i
= 0; i
< count
; i
++)
236 length
+= strlen(tokens
[i
]) + 1;
241 /* Takes a token list and returns a single string with '/' as separator. */
242 static char *sqfs_concat_tokens(char **token_list
, int token_count
)
245 int i
, length
= 0, offset
= 0;
247 length
= sqfs_get_tokens_length(token_list
, token_count
);
249 result
= malloc(length
+ 1);
253 result
[length
] = '\0';
255 for (i
= 0; i
< token_count
; i
++) {
256 strcpy(result
+ offset
, token_list
[i
]);
257 offset
+= strlen(token_list
[i
]);
258 result
[offset
++] = '/';
265 * Differently from sqfs_concat_tokens, sqfs_join writes the result into a
266 * previously allocated string, and returns the number of bytes written.
268 static int sqfs_join(char **strings
, char *dest
, int start
, int end
,
273 for (i
= start
; i
< end
; i
++) {
274 strcpy(dest
+ offset
, strings
[i
]);
275 offset
+= strlen(strings
[i
]);
277 dest
[offset
++] = separator
;
284 * Fills the given token list using its size (count) and a source string (str)
286 static int sqfs_tokenize(char **tokens
, int count
, const char *str
)
295 if (!strcmp(strc
, "/")) {
296 tokens
[0] = strdup(strc
);
302 for (j
= 0; j
< count
; j
++) {
303 aux
= strtok(!j
? strc
: NULL
, "/");
304 tokens
[j
] = strdup(aux
);
306 for (i
= 0; i
< j
; i
++)
321 * Remove last 'updir + 1' tokens from the base path tokens list. This leaves us
322 * with a token list containing only the tokens needed to form the resolved
323 * path, and returns the decremented size of the token list.
325 static int sqfs_clean_base_path(char **base
, int count
, int updir
)
329 for (i
= count
- updir
- 1; i
< count
; i
++)
332 return count
- updir
- 1;
336 * Given the base ("current dir.") path and the relative one, generate the
339 static char *sqfs_get_abs_path(const char *base
, const char *rel
)
341 char **base_tokens
, **rel_tokens
, *resolved
= NULL
;
342 int ret
, bc
, rc
, i
, updir
= 0, resolved_size
= 0, offset
= 0;
347 /* Memory allocation for the token lists */
348 bc
= sqfs_count_tokens(base
);
349 rc
= sqfs_count_tokens(rel
);
350 if (bc
< 1 || rc
< 1)
353 base_tokens
= calloc(bc
, sizeof(char *));
357 rel_tokens
= calloc(rc
, sizeof(char *));
361 /* Fill token lists */
362 ret
= sqfs_tokenize(base_tokens
, bc
, base
);
366 ret
= sqfs_tokenize(rel_tokens
, rc
, rel
);
370 /* count '..' occurrences in target path */
371 for (i
= 0; i
< rc
; i
++) {
372 if (!strcmp(rel_tokens
[i
], ".."))
376 /* Remove the last token and the '..' occurrences */
377 bc
= sqfs_clean_base_path(base_tokens
, bc
, updir
);
381 /* Calculate resolved path size */
385 resolved_size
+= sqfs_get_tokens_length(base_tokens
, bc
) +
386 sqfs_get_tokens_length(rel_tokens
, rc
);
388 resolved
= malloc(resolved_size
+ 1);
392 /* Set resolved path */
393 memset(resolved
, '\0', resolved_size
+ 1);
394 offset
+= sqfs_join(base_tokens
, resolved
+ offset
, 0, bc
, '/');
395 resolved
[offset
++] = '/';
396 offset
+= sqfs_join(rel_tokens
, resolved
+ offset
, updir
, rc
, '/');
400 for (i
= 0; i
< rc
; i
++)
403 for (i
= 0; i
< bc
; i
++)
404 free(base_tokens
[i
]);
412 static char *sqfs_resolve_symlink(struct squashfs_symlink_inode
*sym
,
413 const char *base_path
)
415 char *resolved
, *target
;
418 sz
= get_unaligned_le32(&sym
->symlink_size
);
419 target
= malloc(sz
+ 1);
424 * There is no trailling null byte in the symlink's target path, so a
425 * copy is made and a '\0' is added at its end.
428 /* Get target name (relative path) */
429 strncpy(target
, sym
->symlink
, sz
);
431 /* Relative -> absolute path conversion */
432 resolved
= sqfs_get_abs_path(base_path
, target
);
440 * m_list contains each metadata block's position, and m_count is the number of
441 * elements of m_list. Those metadata blocks come from the compressed directory
444 static int sqfs_search_dir(struct squashfs_dir_stream
*dirs
, char **token_list
,
445 int token_count
, u32
*m_list
, int m_count
)
447 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
448 char *path
, *target
, **sym_tokens
, *res
, *rem
;
449 int j
, ret
= 0, new_inode_number
, offset
;
450 struct squashfs_symlink_inode
*sym
;
451 struct squashfs_ldir_inode
*ldir
;
452 struct squashfs_dir_inode
*dir
;
453 struct fs_dir_stream
*dirsp
;
454 struct fs_dirent
*dent
;
455 unsigned char *table
;
463 dirsp
= (struct fs_dir_stream
*)dirs
;
465 /* Start by root inode */
466 table
= sqfs_find_inode(dirs
->inode_table
, le32_to_cpu(sblk
->inodes
),
467 sblk
->inodes
, sblk
->block_size
);
469 dir
= (struct squashfs_dir_inode
*)table
;
470 ldir
= (struct squashfs_ldir_inode
*)table
;
472 /* get directory offset in directory table */
473 offset
= sqfs_dir_offset(table
, m_list
, m_count
);
474 dirs
->table
= &dirs
->dir_table
[offset
];
476 /* Setup directory header */
477 dirs
->dir_header
= malloc(SQFS_DIR_HEADER_SIZE
);
478 if (!dirs
->dir_header
)
481 memcpy(dirs
->dir_header
, dirs
->table
, SQFS_DIR_HEADER_SIZE
);
483 /* Initialize squashfs_dir_stream members */
484 dirs
->table
+= SQFS_DIR_HEADER_SIZE
;
485 dirs
->size
= get_unaligned_le16(&dir
->file_size
) - SQFS_DIR_HEADER_SIZE
;
486 dirs
->entry_count
= dirs
->dir_header
->count
+ 1;
488 /* No path given -> root directory */
489 if (!strcmp(token_list
[0], "/")) {
490 dirs
->table
= &dirs
->dir_table
[offset
];
491 memcpy(&dirs
->i_dir
, dir
, sizeof(*dir
));
495 for (j
= 0; j
< token_count
; j
++) {
496 if (!sqfs_is_dir(get_unaligned_le16(&dir
->inode_type
))) {
497 printf("** Cannot find directory. **\n");
502 while (!sqfs_readdir(dirsp
, &dent
)) {
503 ret
= strcmp(dent
->name
, token_list
[j
]);
511 printf("** Cannot find directory. **\n");
516 /* Redefine inode as the found token */
517 new_inode_number
= dirs
->entry
->inode_offset
+
518 dirs
->dir_header
->inode_number
;
520 /* Get reference to inode in the inode table */
521 table
= sqfs_find_inode(dirs
->inode_table
, new_inode_number
,
522 sblk
->inodes
, sblk
->block_size
);
523 dir
= (struct squashfs_dir_inode
*)table
;
525 /* Check for symbolic link and inode type sanity */
526 if (get_unaligned_le16(&dir
->inode_type
) == SQFS_SYMLINK_TYPE
) {
527 sym
= (struct squashfs_symlink_inode
*)table
;
528 /* Get first j + 1 tokens */
529 path
= sqfs_concat_tokens(token_list
, j
+ 1);
534 /* Resolve for these tokens */
535 target
= sqfs_resolve_symlink(sym
, path
);
540 /* Join remaining tokens */
541 rem
= sqfs_concat_tokens(token_list
+ j
+ 1, token_count
-
547 /* Concatenate remaining tokens and symlink's target */
548 res
= malloc(strlen(rem
) + strlen(target
) + 1);
554 res
[strlen(target
)] = '/';
555 strcpy(res
+ strlen(target
) + 1, rem
);
556 token_count
= sqfs_count_tokens(res
);
558 if (token_count
< 0) {
563 sym_tokens
= malloc(token_count
* sizeof(char *));
569 /* Fill tokens list */
570 ret
= sqfs_tokenize(sym_tokens
, token_count
, res
);
578 ret
= sqfs_search_dir(dirs
, sym_tokens
, token_count
,
581 } else if (!sqfs_is_dir(get_unaligned_le16(&dir
->inode_type
))) {
582 printf("** Cannot find directory. **\n");
589 /* Check if it is an extended dir. */
590 if (get_unaligned_le16(&dir
->inode_type
) == SQFS_LDIR_TYPE
)
591 ldir
= (struct squashfs_ldir_inode
*)table
;
593 /* Get dir. offset into the directory table */
594 offset
= sqfs_dir_offset(table
, m_list
, m_count
);
595 dirs
->table
= &dirs
->dir_table
[offset
];
597 /* Copy directory header */
598 memcpy(dirs
->dir_header
, &dirs
->dir_table
[offset
],
599 SQFS_DIR_HEADER_SIZE
);
601 /* Check for empty directory */
602 if (sqfs_is_empty_dir(table
)) {
603 printf("Empty directory.\n");
606 ret
= SQFS_EMPTY_DIR
;
610 dirs
->table
+= SQFS_DIR_HEADER_SIZE
;
611 dirs
->size
= get_unaligned_le16(&dir
->file_size
);
612 dirs
->entry_count
= dirs
->dir_header
->count
+ 1;
613 dirs
->size
-= SQFS_DIR_HEADER_SIZE
;
618 offset
= sqfs_dir_offset(table
, m_list
, m_count
);
619 dirs
->table
= &dirs
->dir_table
[offset
];
621 if (get_unaligned_le16(&dir
->inode_type
) == SQFS_DIR_TYPE
)
622 memcpy(&dirs
->i_dir
, dir
, sizeof(*dir
));
624 memcpy(&dirs
->i_ldir
, ldir
, sizeof(*ldir
));
636 * Inode and directory tables are stored as a series of metadata blocks, and
637 * given the compressed size of this table, we can calculate how much metadata
638 * blocks are needed to store the result of the decompression, since a
639 * decompressed metadata block should have a size of 8KiB.
641 static int sqfs_count_metablks(void *table
, u32 offset
, int table_size
)
643 int count
= 0, cur_size
= 0, ret
;
648 ret
= sqfs_read_metablock(table
, offset
+ cur_size
, &comp
,
652 cur_size
+= data_size
+ SQFS_HEADER_SIZE
;
654 } while (cur_size
< table_size
);
660 * Storing the metadata blocks header's positions will be useful while looking
661 * for an entry in the directory table, using the reference (index and offset)
662 * given by its inode.
664 static int sqfs_get_metablk_pos(u32
*pos_list
, void *table
, u32 offset
,
667 u32 data_size
, cur_size
= 0;
674 for (j
= 0; j
< metablks_count
; j
++) {
675 ret
= sqfs_read_metablock(table
, offset
+ cur_size
, &comp
,
680 cur_size
+= data_size
+ SQFS_HEADER_SIZE
;
681 pos_list
[j
] = cur_size
;
687 static int sqfs_read_inode_table(unsigned char **inode_table
)
689 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
690 u64 start
, n_blks
, table_offset
, table_size
;
691 int j
, ret
= 0, metablks_count
;
692 unsigned char *src_table
, *itb
;
693 u32 src_len
, dest_offset
= 0;
694 unsigned long dest_len
= 0;
697 table_size
= get_unaligned_le64(&sblk
->directory_table_start
) -
698 get_unaligned_le64(&sblk
->inode_table_start
);
699 start
= get_unaligned_le64(&sblk
->inode_table_start
) /
701 n_blks
= sqfs_calc_n_blks(sblk
->inode_table_start
,
702 sblk
->directory_table_start
, &table_offset
);
704 /* Allocate a proper sized buffer (itb) to store the inode table */
705 itb
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
709 if (sqfs_disk_read(start
, n_blks
, itb
) < 0) {
714 /* Parse inode table (metadata block) header */
715 ret
= sqfs_read_metablock(itb
, table_offset
, &compressed
, &src_len
);
721 /* Calculate size to store the whole decompressed table */
722 metablks_count
= sqfs_count_metablks(itb
, table_offset
, table_size
);
723 if (metablks_count
< 1) {
728 *inode_table
= malloc(metablks_count
* SQFS_METADATA_BLOCK_SIZE
);
731 printf("Error: failed to allocate squashfs inode_table of size %i, increasing CONFIG_SYS_MALLOC_LEN could help\n",
732 metablks_count
* SQFS_METADATA_BLOCK_SIZE
);
736 src_table
= itb
+ table_offset
+ SQFS_HEADER_SIZE
;
738 /* Extract compressed Inode table */
739 for (j
= 0; j
< metablks_count
; j
++) {
740 sqfs_read_metablock(itb
, table_offset
, &compressed
, &src_len
);
742 dest_len
= SQFS_METADATA_BLOCK_SIZE
;
743 ret
= sqfs_decompress(&ctxt
, *inode_table
+
744 dest_offset
, &dest_len
,
752 dest_offset
+= dest_len
;
754 memcpy(*inode_table
+ (j
* SQFS_METADATA_BLOCK_SIZE
),
759 * Offsets to the decompression destination, to the metadata
760 * buffer 'itb' and to the decompression source, respectively.
763 table_offset
+= src_len
+ SQFS_HEADER_SIZE
;
764 src_table
+= src_len
+ SQFS_HEADER_SIZE
;
773 static int sqfs_read_directory_table(unsigned char **dir_table
, u32
**pos_list
)
775 u64 start
, n_blks
, table_offset
, table_size
;
776 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
777 int j
, ret
= 0, metablks_count
= -1;
778 unsigned char *src_table
, *dtb
;
779 u32 src_len
, dest_offset
= 0;
780 unsigned long dest_len
= 0;
785 /* DIRECTORY TABLE */
786 table_size
= get_unaligned_le64(&sblk
->fragment_table_start
) -
787 get_unaligned_le64(&sblk
->directory_table_start
);
788 start
= get_unaligned_le64(&sblk
->directory_table_start
) /
790 n_blks
= sqfs_calc_n_blks(sblk
->directory_table_start
,
791 sblk
->fragment_table_start
, &table_offset
);
793 /* Allocate a proper sized buffer (dtb) to store the directory table */
794 dtb
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
798 if (sqfs_disk_read(start
, n_blks
, dtb
) < 0)
801 /* Parse directory table (metadata block) header */
802 ret
= sqfs_read_metablock(dtb
, table_offset
, &compressed
, &src_len
);
806 /* Calculate total size to store the whole decompressed table */
807 metablks_count
= sqfs_count_metablks(dtb
, table_offset
, table_size
);
808 if (metablks_count
< 1)
811 *dir_table
= malloc(metablks_count
* SQFS_METADATA_BLOCK_SIZE
);
815 *pos_list
= malloc(metablks_count
* sizeof(u32
));
819 ret
= sqfs_get_metablk_pos(*pos_list
, dtb
, table_offset
,
826 src_table
= dtb
+ table_offset
+ SQFS_HEADER_SIZE
;
828 /* Extract compressed Directory table */
830 for (j
= 0; j
< metablks_count
; j
++) {
831 sqfs_read_metablock(dtb
, table_offset
, &compressed
, &src_len
);
833 dest_len
= SQFS_METADATA_BLOCK_SIZE
;
834 ret
= sqfs_decompress(&ctxt
, *dir_table
+
835 (j
* SQFS_METADATA_BLOCK_SIZE
),
836 &dest_len
, src_table
, src_len
);
842 if (dest_len
< SQFS_METADATA_BLOCK_SIZE
) {
843 dest_offset
+= dest_len
;
847 dest_offset
+= dest_len
;
849 memcpy(*dir_table
+ (j
* SQFS_METADATA_BLOCK_SIZE
),
854 * Offsets to the decompression destination, to the metadata
855 * buffer 'dtb' and to the decompression source, respectively.
857 table_offset
+= src_len
+ SQFS_HEADER_SIZE
;
858 src_table
+= src_len
+ SQFS_HEADER_SIZE
;
862 if (metablks_count
< 1) {
870 return metablks_count
;
873 int sqfs_opendir(const char *filename
, struct fs_dir_stream
**dirsp
)
875 unsigned char *inode_table
= NULL
, *dir_table
= NULL
;
876 int j
, token_count
= 0, ret
= 0, metablks_count
;
877 struct squashfs_dir_stream
*dirs
;
878 char **token_list
= NULL
, *path
= NULL
;
879 u32
*pos_list
= NULL
;
881 dirs
= calloc(1, sizeof(*dirs
));
885 /* these should be set to NULL to prevent dangling pointers */
886 dirs
->dir_header
= NULL
;
889 dirs
->inode_table
= NULL
;
890 dirs
->dir_table
= NULL
;
892 ret
= sqfs_read_inode_table(&inode_table
);
898 metablks_count
= sqfs_read_directory_table(&dir_table
, &pos_list
);
899 if (metablks_count
< 1) {
904 /* Tokenize filename */
905 token_count
= sqfs_count_tokens(filename
);
906 if (token_count
< 0) {
911 path
= strdup(filename
);
917 token_list
= malloc(token_count
* sizeof(char *));
923 /* Fill tokens list */
924 ret
= sqfs_tokenize(token_list
, token_count
, path
);
928 * ldir's (extended directory) size is greater than dir, so it works as
929 * a general solution for the malloc size, since 'i' is a union.
931 dirs
->inode_table
= inode_table
;
932 dirs
->dir_table
= dir_table
;
933 ret
= sqfs_search_dir(dirs
, token_list
, token_count
, pos_list
,
938 if (le16_to_cpu(dirs
->i_dir
.inode_type
) == SQFS_DIR_TYPE
)
939 dirs
->size
= le16_to_cpu(dirs
->i_dir
.file_size
);
941 dirs
->size
= le32_to_cpu(dirs
->i_ldir
.file_size
);
943 /* Setup directory header */
944 memcpy(dirs
->dir_header
, dirs
->table
, SQFS_DIR_HEADER_SIZE
);
945 dirs
->entry_count
= dirs
->dir_header
->count
+ 1;
946 dirs
->size
-= SQFS_DIR_HEADER_SIZE
;
950 dirs
->table
+= SQFS_DIR_HEADER_SIZE
;
952 *dirsp
= (struct fs_dir_stream
*)dirs
;
955 for (j
= 0; j
< token_count
; j
++)
968 int sqfs_readdir(struct fs_dir_stream
*fs_dirs
, struct fs_dirent
**dentp
)
970 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
971 struct squashfs_dir_stream
*dirs
;
972 struct squashfs_lreg_inode
*lreg
;
973 struct squashfs_base_inode
*base
;
974 struct squashfs_reg_inode
*reg
;
975 int i_number
, offset
= 0, ret
;
976 struct fs_dirent
*dent
;
980 dirs
= (struct squashfs_dir_stream
*)fs_dirs
;
983 return -SQFS_STOP_READDIR
;
988 if (!dirs
->entry_count
) {
989 if (dirs
->size
> SQFS_DIR_HEADER_SIZE
) {
990 dirs
->size
-= SQFS_DIR_HEADER_SIZE
;
994 return -SQFS_STOP_READDIR
;
997 if (dirs
->size
> SQFS_EMPTY_FILE_SIZE
) {
998 /* Read follow-up (emitted) dir. header */
999 memcpy(dirs
->dir_header
, dirs
->table
,
1000 SQFS_DIR_HEADER_SIZE
);
1001 dirs
->entry_count
= dirs
->dir_header
->count
+ 1;
1002 ret
= sqfs_read_entry(&dirs
->entry
, dirs
->table
+
1003 SQFS_DIR_HEADER_SIZE
);
1005 return -SQFS_STOP_READDIR
;
1007 dirs
->table
+= SQFS_DIR_HEADER_SIZE
;
1010 ret
= sqfs_read_entry(&dirs
->entry
, dirs
->table
);
1012 return -SQFS_STOP_READDIR
;
1015 i_number
= dirs
->dir_header
->inode_number
+ dirs
->entry
->inode_offset
;
1016 ipos
= sqfs_find_inode(dirs
->inode_table
, i_number
, sblk
->inodes
,
1019 base
= (struct squashfs_base_inode
*)ipos
;
1021 /* Set entry type and size */
1022 switch (dirs
->entry
->type
) {
1024 case SQFS_LDIR_TYPE
:
1025 dent
->type
= FS_DT_DIR
;
1028 case SQFS_LREG_TYPE
:
1030 * Entries do not differentiate extended from regular types, so
1031 * it needs to be verified manually.
1033 if (get_unaligned_le16(&base
->inode_type
) == SQFS_LREG_TYPE
) {
1034 lreg
= (struct squashfs_lreg_inode
*)ipos
;
1035 dent
->size
= get_unaligned_le64(&lreg
->file_size
);
1037 reg
= (struct squashfs_reg_inode
*)ipos
;
1038 dent
->size
= get_unaligned_le32(®
->file_size
);
1041 dent
->type
= FS_DT_REG
;
1043 case SQFS_BLKDEV_TYPE
:
1044 case SQFS_CHRDEV_TYPE
:
1045 case SQFS_LBLKDEV_TYPE
:
1046 case SQFS_LCHRDEV_TYPE
:
1047 case SQFS_FIFO_TYPE
:
1048 case SQFS_SOCKET_TYPE
:
1049 case SQFS_LFIFO_TYPE
:
1050 case SQFS_LSOCKET_TYPE
:
1051 dent
->type
= SQFS_MISC_ENTRY_TYPE
;
1053 case SQFS_SYMLINK_TYPE
:
1054 case SQFS_LSYMLINK_TYPE
:
1055 dent
->type
= FS_DT_LNK
;
1058 return -SQFS_STOP_READDIR
;
1061 /* Set entry name (capped at FS_DIRENT_NAME_LEN which is a U-Boot limitation) */
1062 name_size
= min_t(u16
, dirs
->entry
->name_size
+ 1, FS_DIRENT_NAME_LEN
- 1);
1063 strncpy(dent
->name
, dirs
->entry
->name
, name_size
);
1064 dent
->name
[name_size
] = '\0';
1066 offset
= dirs
->entry
->name_size
+ 1 + SQFS_ENTRY_BASE_LENGTH
;
1067 dirs
->entry_count
--;
1069 /* Decrement size to be read */
1070 if (dirs
->size
> offset
)
1071 dirs
->size
-= offset
;
1075 /* Keep a reference to the current entry before incrementing it */
1076 dirs
->table
+= offset
;
1083 int sqfs_probe(struct blk_desc
*fs_dev_desc
, struct disk_partition
*fs_partition
)
1085 struct squashfs_super_block
*sblk
;
1088 ctxt
.cur_dev
= fs_dev_desc
;
1089 ctxt
.cur_part_info
= *fs_partition
;
1091 ret
= sqfs_read_sblk(&sblk
);
1095 /* Make sure it has a valid SquashFS magic number*/
1096 if (get_unaligned_le32(&sblk
->s_magic
) != SQFS_MAGIC_NUMBER
) {
1097 debug("Bad magic number for SquashFS image.\n");
1104 ret
= sqfs_decompressor_init(&ctxt
);
1111 ctxt
.cur_dev
= NULL
;
1117 static char *sqfs_basename(char *path
)
1121 fname
= path
+ strlen(path
) - 1;
1122 while (fname
>= path
) {
1123 if (*fname
== '/') {
1134 static char *sqfs_dirname(char *path
)
1138 fname
= sqfs_basename(path
);
1146 * Takes a path to file and splits it in two parts: the filename itself and the
1147 * directory's path, e.g.:
1148 * path: /path/to/file.txt
1152 static int sqfs_split_path(char **file
, char **dir
, const char *path
)
1154 char *dirc
, *basec
, *bname
, *dname
, *tmp_path
;
1165 /* check for first slash in path*/
1166 if (path
[0] == '/') {
1167 tmp_path
= strdup(path
);
1173 tmp_path
= malloc(strlen(path
) + 2);
1179 strcpy(tmp_path
+ 1, path
);
1182 /* String duplicates */
1183 dirc
= strdup(tmp_path
);
1189 basec
= strdup(tmp_path
);
1195 dname
= sqfs_dirname(dirc
);
1196 bname
= sqfs_basename(basec
);
1198 *file
= strdup(bname
);
1205 if (*dname
== '\0') {
1215 *dir
= strdup(dname
);
1236 static int sqfs_get_regfile_info(struct squashfs_reg_inode
*reg
,
1237 struct squashfs_file_info
*finfo
,
1238 struct squashfs_fragment_block_entry
*fentry
,
1241 int datablk_count
= 0, ret
;
1243 finfo
->size
= get_unaligned_le32(®
->file_size
);
1244 finfo
->offset
= get_unaligned_le32(®
->offset
);
1245 finfo
->start
= get_unaligned_le32(®
->start_block
);
1246 finfo
->frag
= SQFS_IS_FRAGMENTED(get_unaligned_le32(®
->fragment
));
1248 if (finfo
->frag
&& finfo
->offset
== 0xFFFFFFFF)
1251 if (finfo
->size
< 1 || finfo
->start
== 0xFFFFFFFF)
1255 datablk_count
= finfo
->size
/ le32_to_cpu(blksz
);
1256 ret
= sqfs_frag_lookup(get_unaligned_le32(®
->fragment
),
1261 if (fentry
->size
< 1 || fentry
->start
== 0x7FFFFFFF)
1264 datablk_count
= DIV_ROUND_UP(finfo
->size
, le32_to_cpu(blksz
));
1267 finfo
->blk_sizes
= malloc(datablk_count
* sizeof(u32
));
1268 if (!finfo
->blk_sizes
)
1271 return datablk_count
;
1274 static int sqfs_get_lregfile_info(struct squashfs_lreg_inode
*lreg
,
1275 struct squashfs_file_info
*finfo
,
1276 struct squashfs_fragment_block_entry
*fentry
,
1279 int datablk_count
= 0, ret
;
1281 finfo
->size
= get_unaligned_le64(&lreg
->file_size
);
1282 finfo
->offset
= get_unaligned_le32(&lreg
->offset
);
1283 finfo
->start
= get_unaligned_le64(&lreg
->start_block
);
1284 finfo
->frag
= SQFS_IS_FRAGMENTED(get_unaligned_le32(&lreg
->fragment
));
1286 if (finfo
->frag
&& finfo
->offset
== 0xFFFFFFFF)
1289 if (finfo
->size
< 1 || finfo
->start
== 0x7FFFFFFF)
1293 datablk_count
= finfo
->size
/ le32_to_cpu(blksz
);
1294 ret
= sqfs_frag_lookup(get_unaligned_le32(&lreg
->fragment
),
1299 if (fentry
->size
< 1 || fentry
->start
== 0x7FFFFFFF)
1302 datablk_count
= DIV_ROUND_UP(finfo
->size
, le32_to_cpu(blksz
));
1305 finfo
->blk_sizes
= malloc(datablk_count
* sizeof(u32
));
1306 if (!finfo
->blk_sizes
)
1309 return datablk_count
;
1312 int sqfs_read(const char *filename
, void *buf
, loff_t offset
, loff_t len
,
1315 char *dir
= NULL
, *fragment_block
, *datablock
= NULL
;
1316 char *fragment
= NULL
, *file
= NULL
, *resolved
, *data
;
1317 u64 start
, n_blks
, table_size
, data_offset
, table_offset
, sparse_size
;
1318 int ret
, j
, i_number
, datablk_count
= 0;
1319 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
1320 struct squashfs_fragment_block_entry frag_entry
;
1321 struct squashfs_file_info finfo
= {0};
1322 struct squashfs_symlink_inode
*symlink
;
1323 struct fs_dir_stream
*dirsp
= NULL
;
1324 struct squashfs_dir_stream
*dirs
;
1325 struct squashfs_lreg_inode
*lreg
;
1326 struct squashfs_base_inode
*base
;
1327 struct squashfs_reg_inode
*reg
;
1328 unsigned long dest_len
;
1329 struct fs_dirent
*dent
;
1330 unsigned char *ipos
;
1336 * TODO: implement reading at an offset in file
1338 printf("Error: reading at a specific offset in a squashfs file is not supported yet.\n");
1343 * sqfs_opendir will uncompress inode and directory tables, and will
1344 * return a pointer to the directory that contains the requested file.
1346 sqfs_split_path(&file
, &dir
, filename
);
1347 ret
= sqfs_opendir(dir
, &dirsp
);
1352 dirs
= (struct squashfs_dir_stream
*)dirsp
;
1354 /* For now, only regular files are able to be loaded */
1355 while (!sqfs_readdir(dirsp
, &dent
)) {
1356 ret
= strcmp(dent
->name
, file
);
1365 printf("File not found.\n");
1371 i_number
= dirs
->dir_header
->inode_number
+ dirs
->entry
->inode_offset
;
1372 ipos
= sqfs_find_inode(dirs
->inode_table
, i_number
, sblk
->inodes
,
1375 base
= (struct squashfs_base_inode
*)ipos
;
1376 switch (get_unaligned_le16(&base
->inode_type
)) {
1378 reg
= (struct squashfs_reg_inode
*)ipos
;
1379 datablk_count
= sqfs_get_regfile_info(reg
, &finfo
, &frag_entry
,
1381 if (datablk_count
< 0) {
1386 memcpy(finfo
.blk_sizes
, ipos
+ sizeof(*reg
),
1387 datablk_count
* sizeof(u32
));
1389 case SQFS_LREG_TYPE
:
1390 lreg
= (struct squashfs_lreg_inode
*)ipos
;
1391 datablk_count
= sqfs_get_lregfile_info(lreg
, &finfo
,
1394 if (datablk_count
< 0) {
1399 memcpy(finfo
.blk_sizes
, ipos
+ sizeof(*lreg
),
1400 datablk_count
* sizeof(u32
));
1402 case SQFS_SYMLINK_TYPE
:
1403 case SQFS_LSYMLINK_TYPE
:
1404 symlink
= (struct squashfs_symlink_inode
*)ipos
;
1405 resolved
= sqfs_resolve_symlink(symlink
, filename
);
1406 ret
= sqfs_read(resolved
, buf
, offset
, len
, actread
);
1409 case SQFS_BLKDEV_TYPE
:
1410 case SQFS_CHRDEV_TYPE
:
1411 case SQFS_LBLKDEV_TYPE
:
1412 case SQFS_LCHRDEV_TYPE
:
1413 case SQFS_FIFO_TYPE
:
1414 case SQFS_SOCKET_TYPE
:
1415 case SQFS_LFIFO_TYPE
:
1416 case SQFS_LSOCKET_TYPE
:
1418 printf("Unsupported entry type\n");
1423 /* If the user specifies a length, check its sanity */
1425 if (len
> finfo
.size
) {
1435 if (datablk_count
) {
1436 data_offset
= finfo
.start
;
1437 datablock
= malloc(get_unaligned_le32(&sblk
->block_size
));
1444 for (j
= 0; j
< datablk_count
; j
++) {
1447 start
= lldiv(data_offset
, ctxt
.cur_dev
->blksz
);
1448 table_size
= SQFS_BLOCK_SIZE(finfo
.blk_sizes
[j
]);
1449 table_offset
= data_offset
- (start
* ctxt
.cur_dev
->blksz
);
1450 n_blks
= DIV_ROUND_UP(table_size
+ table_offset
,
1451 ctxt
.cur_dev
->blksz
);
1453 /* Don't load any data for sparse blocks */
1454 if (finfo
.blk_sizes
[j
] == 0) {
1460 data_buffer
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
1467 ret
= sqfs_disk_read(start
, n_blks
, data_buffer
);
1470 * Possible causes: too many data blocks or too large
1471 * SquashFS block size. Tip: re-compile the SquashFS
1472 * image with mksquashfs's -b <block_size> option.
1474 printf("Error: too many data blocks to be read.\n");
1478 data
= data_buffer
+ table_offset
;
1482 if (finfo
.blk_sizes
[j
] == 0) {
1483 /* This is a sparse block */
1484 sparse_size
= get_unaligned_le32(&sblk
->block_size
);
1485 if ((*actread
+ sparse_size
) > len
)
1486 sparse_size
= len
- *actread
;
1487 memset(buf
+ *actread
, 0, sparse_size
);
1488 *actread
+= sparse_size
;
1489 } else if (SQFS_COMPRESSED_BLOCK(finfo
.blk_sizes
[j
])) {
1490 dest_len
= get_unaligned_le32(&sblk
->block_size
);
1491 ret
= sqfs_decompress(&ctxt
, datablock
, &dest_len
,
1496 if ((*actread
+ dest_len
) > len
)
1497 dest_len
= len
- *actread
;
1498 memcpy(buf
+ *actread
, datablock
, dest_len
);
1499 *actread
+= dest_len
;
1501 if ((*actread
+ table_size
) > len
)
1502 table_size
= len
- *actread
;
1503 memcpy(buf
+ *actread
, data
, table_size
);
1504 *actread
+= table_size
;
1507 data_offset
+= table_size
;
1509 if (*actread
>= len
)
1514 * There is no need to continue if the file is not fragmented.
1521 start
= lldiv(frag_entry
.start
, ctxt
.cur_dev
->blksz
);
1522 table_size
= SQFS_BLOCK_SIZE(frag_entry
.size
);
1523 table_offset
= frag_entry
.start
- (start
* ctxt
.cur_dev
->blksz
);
1524 n_blks
= DIV_ROUND_UP(table_size
+ table_offset
, ctxt
.cur_dev
->blksz
);
1526 fragment
= malloc_cache_aligned(n_blks
* ctxt
.cur_dev
->blksz
);
1533 ret
= sqfs_disk_read(start
, n_blks
, fragment
);
1537 /* File compressed and fragmented */
1538 if (finfo
.frag
&& finfo
.comp
) {
1539 dest_len
= get_unaligned_le32(&sblk
->block_size
);
1540 fragment_block
= malloc(dest_len
);
1541 if (!fragment_block
) {
1546 ret
= sqfs_decompress(&ctxt
, fragment_block
, &dest_len
,
1547 (void *)fragment
+ table_offset
,
1550 free(fragment_block
);
1554 memcpy(buf
+ *actread
, &fragment_block
[finfo
.offset
], finfo
.size
- *actread
);
1555 *actread
= finfo
.size
;
1557 free(fragment_block
);
1559 } else if (finfo
.frag
&& !finfo
.comp
) {
1560 fragment_block
= (void *)fragment
+ table_offset
;
1562 memcpy(buf
+ *actread
, &fragment_block
[finfo
.offset
], finfo
.size
- *actread
);
1563 *actread
= finfo
.size
;
1571 free(finfo
.blk_sizes
);
1572 sqfs_closedir(dirsp
);
1577 int sqfs_size(const char *filename
, loff_t
*size
)
1579 struct squashfs_super_block
*sblk
= ctxt
.sblk
;
1580 struct squashfs_symlink_inode
*symlink
;
1581 struct fs_dir_stream
*dirsp
= NULL
;
1582 struct squashfs_base_inode
*base
;
1583 struct squashfs_dir_stream
*dirs
;
1584 struct squashfs_lreg_inode
*lreg
;
1585 struct squashfs_reg_inode
*reg
;
1586 char *dir
, *file
, *resolved
;
1587 struct fs_dirent
*dent
;
1588 unsigned char *ipos
;
1591 sqfs_split_path(&file
, &dir
, filename
);
1593 * sqfs_opendir will uncompress inode and directory tables, and will
1594 * return a pointer to the directory that contains the requested file.
1596 ret
= sqfs_opendir(dir
, &dirsp
);
1602 dirs
= (struct squashfs_dir_stream
*)dirsp
;
1604 while (!sqfs_readdir(dirsp
, &dent
)) {
1605 ret
= strcmp(dent
->name
, file
);
1613 printf("File not found.\n");
1619 i_number
= dirs
->dir_header
->inode_number
+ dirs
->entry
->inode_offset
;
1620 ipos
= sqfs_find_inode(dirs
->inode_table
, i_number
, sblk
->inodes
,
1625 base
= (struct squashfs_base_inode
*)ipos
;
1626 switch (get_unaligned_le16(&base
->inode_type
)) {
1628 reg
= (struct squashfs_reg_inode
*)ipos
;
1629 *size
= get_unaligned_le32(®
->file_size
);
1631 case SQFS_LREG_TYPE
:
1632 lreg
= (struct squashfs_lreg_inode
*)ipos
;
1633 *size
= get_unaligned_le64(&lreg
->file_size
);
1635 case SQFS_SYMLINK_TYPE
:
1636 case SQFS_LSYMLINK_TYPE
:
1637 symlink
= (struct squashfs_symlink_inode
*)ipos
;
1638 resolved
= sqfs_resolve_symlink(symlink
, filename
);
1639 ret
= sqfs_size(resolved
, size
);
1642 case SQFS_BLKDEV_TYPE
:
1643 case SQFS_CHRDEV_TYPE
:
1644 case SQFS_LBLKDEV_TYPE
:
1645 case SQFS_LCHRDEV_TYPE
:
1646 case SQFS_FIFO_TYPE
:
1647 case SQFS_SOCKET_TYPE
:
1648 case SQFS_LFIFO_TYPE
:
1649 case SQFS_LSOCKET_TYPE
:
1651 printf("Unable to recover entry's size.\n");
1661 sqfs_closedir(dirsp
);
1666 int sqfs_exists(const char *filename
)
1668 struct fs_dir_stream
*dirsp
= NULL
;
1669 struct squashfs_dir_stream
*dirs
;
1671 struct fs_dirent
*dent
;
1674 sqfs_split_path(&file
, &dir
, filename
);
1676 * sqfs_opendir will uncompress inode and directory tables, and will
1677 * return a pointer to the directory that contains the requested file.
1679 ret
= sqfs_opendir(dir
, &dirsp
);
1685 dirs
= (struct squashfs_dir_stream
*)dirsp
;
1687 while (!sqfs_readdir(dirsp
, &dent
)) {
1688 ret
= strcmp(dent
->name
, file
);
1695 sqfs_closedir(dirsp
);
1704 void sqfs_close(void)
1706 sqfs_decompressor_cleanup(&ctxt
);
1709 ctxt
.cur_dev
= NULL
;
1712 void sqfs_closedir(struct fs_dir_stream
*dirs
)
1714 struct squashfs_dir_stream
*sqfs_dirs
;
1719 sqfs_dirs
= (struct squashfs_dir_stream
*)dirs
;
1720 free(sqfs_dirs
->inode_table
);
1721 free(sqfs_dirs
->dir_table
);
1722 free(sqfs_dirs
->dir_header
);