311 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| /*
 | |
|  * Copyright (C) 2020 Bootlin
 | |
|  *
 | |
|  * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
 | |
|  */
 | |
| 
 | |
| #ifndef SQFS_FILESYSTEM_H
 | |
| #define SQFS_FILESYSTEM_H
 | |
| 
 | |
| #include <asm/unaligned.h>
 | |
| #include <fs.h>
 | |
| #include <part.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| #define SQFS_UNCOMPRESSED_DATA 0x0002
 | |
| #define SQFS_MAGIC_NUMBER 0x73717368
 | |
| /* The three first members of squashfs_dir_index make a total of 12 bytes */
 | |
| #define SQFS_DIR_INDEX_BASE_LENGTH 12
 | |
| /* size of metadata (inode and directory) blocks */
 | |
| #define SQFS_METADATA_BLOCK_SIZE 8192
 | |
| /* Max. number of fragment entries in a metadata block is 512 */
 | |
| #define SQFS_MAX_ENTRIES 512
 | |
| /* Metadata blocks start by a 2-byte length header */
 | |
| #define SQFS_HEADER_SIZE 2
 | |
| #define SQFS_LREG_INODE_MIN_SIZE 56
 | |
| #define SQFS_DIR_HEADER_SIZE 12
 | |
| #define SQFS_MISC_ENTRY_TYPE -1
 | |
| #define SQFS_EMPTY_FILE_SIZE 3
 | |
| #define SQFS_STOP_READDIR 1
 | |
| #define SQFS_EMPTY_DIR -1
 | |
| /*
 | |
|  * A directory entry object has a fixed length of 8 bytes, corresponding to its
 | |
|  * first four members, plus the size of the entry name, which is equal to
 | |
|  * 'entry_name' + 1 bytes.
 | |
|  */
 | |
| #define SQFS_ENTRY_BASE_LENGTH 8
 | |
| /* Inode types */
 | |
| #define SQFS_DIR_TYPE 1
 | |
| #define SQFS_REG_TYPE 2
 | |
| #define SQFS_SYMLINK_TYPE 3
 | |
| #define SQFS_BLKDEV_TYPE 4
 | |
| #define SQFS_CHRDEV_TYPE 5
 | |
| #define SQFS_FIFO_TYPE 6
 | |
| #define SQFS_SOCKET_TYPE 7
 | |
| #define SQFS_LDIR_TYPE 8
 | |
| #define SQFS_LREG_TYPE 9
 | |
| #define SQFS_LSYMLINK_TYPE 10
 | |
| #define SQFS_LBLKDEV_TYPE 11
 | |
| #define SQFS_LCHRDEV_TYPE 12
 | |
| #define SQFS_LFIFO_TYPE 13
 | |
| #define SQFS_LSOCKET_TYPE 14
 | |
| 
 | |
| struct squashfs_super_block {
 | |
| 	__le32 s_magic;
 | |
| 	__le32 inodes;
 | |
| 	__le32 mkfs_time;
 | |
| 	__le32 block_size;
 | |
| 	__le32 fragments;
 | |
| 	__le16 compression;
 | |
| 	__le16 block_log;
 | |
| 	__le16 flags;
 | |
| 	__le16 no_ids;
 | |
| 	__le16 s_major;
 | |
| 	__le16 s_minor;
 | |
| 	__le64 root_inode;
 | |
| 	__le64 bytes_used;
 | |
| 	__le64 id_table_start;
 | |
| 	__le64 xattr_id_table_start;
 | |
| 	__le64 inode_table_start;
 | |
| 	__le64 directory_table_start;
 | |
| 	__le64 fragment_table_start;
 | |
| 	__le64 export_table_start;
 | |
| };
 | |
| 
 | |
| struct squashfs_ctxt {
 | |
| 	struct disk_partition cur_part_info;
 | |
| 	struct blk_desc *cur_dev;
 | |
| 	struct squashfs_super_block *sblk;
 | |
| #if IS_ENABLED(CONFIG_ZSTD)
 | |
| 	void *zstd_workspace;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| struct squashfs_directory_index {
 | |
| 	u32 index;
 | |
| 	u32 start;
 | |
| 	u32 size;
 | |
| 	char name[0];
 | |
| };
 | |
| 
 | |
| struct squashfs_base_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| };
 | |
| 
 | |
| struct squashfs_ipc_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| };
 | |
| 
 | |
| struct squashfs_lipc_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| 	__le32 xattr;
 | |
| };
 | |
| 
 | |
| struct squashfs_dev_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| 	__le32 rdev;
 | |
| };
 | |
| 
 | |
| struct squashfs_ldev_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| 	__le32 rdev;
 | |
| 	__le32 xattr;
 | |
| };
 | |
| 
 | |
| struct squashfs_symlink_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| 	__le32 symlink_size;
 | |
| 	char symlink[0];
 | |
| };
 | |
| 
 | |
| struct squashfs_reg_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 start_block;
 | |
| 	__le32 fragment;
 | |
| 	__le32 offset;
 | |
| 	__le32 file_size;
 | |
| 	__le32 block_list[0];
 | |
| };
 | |
| 
 | |
| struct squashfs_lreg_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le64 start_block;
 | |
| 	__le64 file_size;
 | |
| 	__le64 sparse;
 | |
| 	__le32 nlink;
 | |
| 	__le32 fragment;
 | |
| 	__le32 offset;
 | |
| 	__le32 xattr;
 | |
| 	__le32 block_list[0];
 | |
| };
 | |
| 
 | |
| struct squashfs_dir_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 start_block;
 | |
| 	__le32 nlink;
 | |
| 	__le16 file_size;
 | |
| 	__le16 offset;
 | |
| 	__le32 parent_inode;
 | |
| };
 | |
| 
 | |
| struct squashfs_ldir_inode {
 | |
| 	__le16 inode_type;
 | |
| 	__le16 mode;
 | |
| 	__le16 uid;
 | |
| 	__le16 guid;
 | |
| 	__le32 mtime;
 | |
| 	__le32 inode_number;
 | |
| 	__le32 nlink;
 | |
| 	__le32 file_size;
 | |
| 	__le32 start_block;
 | |
| 	__le32 parent_inode;
 | |
| 	__le16 i_count;
 | |
| 	__le16 offset;
 | |
| 	__le32 xattr;
 | |
| 	struct squashfs_directory_index index[0];
 | |
| };
 | |
| 
 | |
| union squashfs_inode {
 | |
| 	struct squashfs_base_inode *base;
 | |
| 	struct squashfs_dev_inode *dev;
 | |
| 	struct squashfs_ldev_inode *ldev;
 | |
| 	struct squashfs_symlink_inode *symlink;
 | |
| 	struct squashfs_reg_inode *reg;
 | |
| 	struct squashfs_lreg_inode *lreg;
 | |
| 	struct squashfs_dir_inode *dir;
 | |
| 	struct squashfs_ldir_inode *ldir;
 | |
| 	struct squashfs_ipc_inode *ipc;
 | |
| 	struct squashfs_lipc_inode *lipc;
 | |
| };
 | |
| 
 | |
| struct squashfs_directory_entry {
 | |
| 	u16 offset;
 | |
| 	u16 inode_offset;
 | |
| 	u16 type;
 | |
| 	u16 name_size;
 | |
| 	char name[0];
 | |
| };
 | |
| 
 | |
| struct squashfs_directory_header {
 | |
| 	u32 count;
 | |
| 	u32 start;
 | |
| 	u32 inode_number;
 | |
| };
 | |
| 
 | |
| struct squashfs_fragment_block_entry {
 | |
| 	u64 start;
 | |
| 	u32 size;
 | |
| 	u32 _unused;
 | |
| };
 | |
| 
 | |
| struct squashfs_dir_stream {
 | |
| 	struct fs_dir_stream fs_dirs;
 | |
| 	struct fs_dirent dentp;
 | |
| 	/*
 | |
| 	 * 'size' is the uncompressed size of the entire listing, including
 | |
| 	 * headers. 'entry_count' is the number of entries following a
 | |
| 	 * specific header. Both variables are decremented in sqfs_readdir() so
 | |
| 	 * the function knows when the end of the directory is reached.
 | |
| 	 */
 | |
| 	size_t size;
 | |
| 	int entry_count;
 | |
| 	/* SquashFS structures */
 | |
| 	struct squashfs_directory_header *dir_header;
 | |
| 	struct squashfs_directory_entry *entry;
 | |
| 	/*
 | |
| 	 * 'table' points to a position into the directory table. Both 'table'
 | |
| 	 * and 'inode' are defined for the first time in sqfs_opendir().
 | |
| 	 * 'table's value changes in sqfs_readdir().
 | |
| 	 */
 | |
| 	unsigned char *table;
 | |
| 	union squashfs_inode i;
 | |
| 	struct squashfs_dir_inode i_dir;
 | |
| 	struct squashfs_ldir_inode i_ldir;
 | |
| 	/*
 | |
| 	 * References to the tables' beginnings. They are assigned in
 | |
| 	 * sqfs_opendir() and freed in sqfs_closedir().
 | |
| 	 */
 | |
| 	unsigned char *inode_table;
 | |
| 	unsigned char *dir_table;
 | |
| };
 | |
| 
 | |
| struct squashfs_file_info {
 | |
| 	/* File size in bytes (uncompressed) */
 | |
| 	size_t size;
 | |
| 	/* Reference to list of data blocks's sizes */
 | |
| 	u32 *blk_sizes;
 | |
| 	/* Offset into the fragment block */
 | |
| 	u32 offset;
 | |
| 	/* Offset in which the data blocks begin */
 | |
| 	u64 start;
 | |
| 	/* Is file fragmented? */
 | |
| 	bool frag;
 | |
| 	/* Compressed fragment */
 | |
| 	bool comp;
 | |
| };
 | |
| 
 | |
| void *sqfs_find_inode(void *inode_table, int inode_number, __le32 inode_count,
 | |
| 		      __le32 block_size);
 | |
| 
 | |
| int sqfs_dir_offset(void *dir_i, u32 *m_list, int m_count);
 | |
| 
 | |
| int sqfs_read_metablock(unsigned char *file_mapping, int offset,
 | |
| 			bool *compressed, u32 *data_size);
 | |
| 
 | |
| bool sqfs_is_empty_dir(void *dir_i);
 | |
| 
 | |
| bool sqfs_is_dir(u16 type);
 | |
| 
 | |
| #endif /* SQFS_FILESYSTEM_H */
 |