123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2020 Bootlin
- *
- * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
- */
- #include <asm/unaligned.h>
- #include <errno.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "sqfs_decompressor.h"
- #include "sqfs_filesystem.h"
- #include "sqfs_utils.h"
- int sqfs_inode_size(struct squashfs_base_inode *inode, u32 blk_size)
- {
- switch (get_unaligned_le16(&inode->inode_type)) {
- case SQFS_DIR_TYPE:
- return sizeof(struct squashfs_dir_inode);
- case SQFS_REG_TYPE: {
- struct squashfs_reg_inode *reg =
- (struct squashfs_reg_inode *)inode;
- u32 fragment = get_unaligned_le32(®->fragment);
- u32 file_size = get_unaligned_le32(®->file_size);
- unsigned int blk_list_size;
- if (SQFS_IS_FRAGMENTED(fragment))
- blk_list_size = file_size / blk_size;
- else
- blk_list_size = DIV_ROUND_UP(file_size, blk_size);
- return sizeof(*reg) + blk_list_size * sizeof(u32);
- }
- case SQFS_LDIR_TYPE: {
- struct squashfs_ldir_inode *ldir =
- (struct squashfs_ldir_inode *)inode;
- u16 i_count = get_unaligned_le16(&ldir->i_count);
- unsigned int index_list_size = 0, l = 0;
- struct squashfs_directory_index *di;
- u32 sz;
- if (i_count == 0)
- return sizeof(*ldir);
- di = ldir->index;
- while (l < i_count + 1) {
- sz = get_unaligned_le32(&di->size) + 1;
- index_list_size += sz;
- di = (void *)di + sizeof(*di) + sz;
- l++;
- }
- return sizeof(*ldir) + index_list_size +
- (i_count + 1) * SQFS_DIR_INDEX_BASE_LENGTH;
- }
- case SQFS_LREG_TYPE: {
- struct squashfs_lreg_inode *lreg =
- (struct squashfs_lreg_inode *)inode;
- u32 fragment = get_unaligned_le32(&lreg->fragment);
- u64 file_size = get_unaligned_le64(&lreg->file_size);
- unsigned int blk_list_size;
- if (fragment == 0xFFFFFFFF)
- blk_list_size = DIV_ROUND_UP(file_size, blk_size);
- else
- blk_list_size = file_size / blk_size;
- return sizeof(*lreg) + blk_list_size * sizeof(u32);
- }
- case SQFS_SYMLINK_TYPE:
- case SQFS_LSYMLINK_TYPE: {
- struct squashfs_symlink_inode *symlink =
- (struct squashfs_symlink_inode *)inode;
- return sizeof(*symlink) +
- get_unaligned_le32(&symlink->symlink_size);
- }
- case SQFS_BLKDEV_TYPE:
- case SQFS_CHRDEV_TYPE:
- return sizeof(struct squashfs_dev_inode);
- case SQFS_LBLKDEV_TYPE:
- case SQFS_LCHRDEV_TYPE:
- return sizeof(struct squashfs_ldev_inode);
- case SQFS_FIFO_TYPE:
- case SQFS_SOCKET_TYPE:
- return sizeof(struct squashfs_ipc_inode);
- case SQFS_LFIFO_TYPE:
- case SQFS_LSOCKET_TYPE:
- return sizeof(struct squashfs_lipc_inode);
- default:
- printf("Error while searching inode: unknown type.\n");
- return -EINVAL;
- }
- }
- /*
- * Given the uncompressed inode table, the inode to be found and the number of
- * inodes in the table, return inode position in case of success.
- */
- void *sqfs_find_inode(void *inode_table, int inode_number, __le32 inode_count,
- __le32 block_size)
- {
- struct squashfs_base_inode *base;
- unsigned int offset = 0, k;
- int sz;
- if (!inode_table) {
- printf("%s: Invalid pointer to inode table.\n", __func__);
- return NULL;
- }
- for (k = 0; k < le32_to_cpu(inode_count); k++) {
- base = inode_table + offset;
- if (get_unaligned_le32(&base->inode_number) == inode_number)
- return inode_table + offset;
- sz = sqfs_inode_size(base, le32_to_cpu(block_size));
- if (sz < 0)
- return NULL;
- offset += sz;
- }
- printf("Inode not found.\n");
- return NULL;
- }
- int sqfs_read_metablock(unsigned char *file_mapping, int offset,
- bool *compressed, u32 *data_size)
- {
- unsigned char *data;
- u16 header;
- data = file_mapping + offset;
- header = get_unaligned((u16 *)data);
- *compressed = SQFS_COMPRESSED_METADATA(header);
- *data_size = SQFS_METADATA_SIZE(header);
- if (*data_size > SQFS_METADATA_BLOCK_SIZE) {
- printf("Invalid metatada block size: %d bytes.\n", *data_size);
- return -EINVAL;
- }
- return 0;
- }
|