Joao Marcos Costa | 29da374 | 2020-07-30 15:33:47 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * Copyright (C) 2020 Bootlin |
| 4 | * |
| 5 | * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com> |
| 6 | */ |
| 7 | |
| 8 | #ifndef SQFS_FILESYSTEM_H |
| 9 | #define SQFS_FILESYSTEM_H |
| 10 | |
| 11 | #include <asm/unaligned.h> |
Joao Marcos Costa | 29da374 | 2020-07-30 15:33:47 +0200 | [diff] [blame] | 12 | #include <fs.h> |
Joao Marcos Costa | 877576c | 2020-08-18 17:17:21 +0200 | [diff] [blame] | 13 | #include <part.h> |
| 14 | #include <stdint.h> |
Joao Marcos Costa | 29da374 | 2020-07-30 15:33:47 +0200 | [diff] [blame] | 15 | |
| 16 | #define SQFS_UNCOMPRESSED_DATA 0x0002 |
| 17 | #define SQFS_MAGIC_NUMBER 0x73717368 |
| 18 | /* The three first members of squashfs_dir_index make a total of 12 bytes */ |
| 19 | #define SQFS_DIR_INDEX_BASE_LENGTH 12 |
| 20 | /* size of metadata (inode and directory) blocks */ |
| 21 | #define SQFS_METADATA_BLOCK_SIZE 8192 |
| 22 | /* Max. number of fragment entries in a metadata block is 512 */ |
| 23 | #define SQFS_MAX_ENTRIES 512 |
| 24 | /* Metadata blocks start by a 2-byte length header */ |
| 25 | #define SQFS_HEADER_SIZE 2 |
| 26 | #define SQFS_LREG_INODE_MIN_SIZE 56 |
| 27 | #define SQFS_DIR_HEADER_SIZE 12 |
| 28 | #define SQFS_MISC_ENTRY_TYPE -1 |
| 29 | #define SQFS_EMPTY_FILE_SIZE 3 |
| 30 | #define SQFS_STOP_READDIR 1 |
| 31 | #define SQFS_EMPTY_DIR -1 |
| 32 | /* |
| 33 | * A directory entry object has a fixed length of 8 bytes, corresponding to its |
| 34 | * first four members, plus the size of the entry name, which is equal to |
| 35 | * 'entry_name' + 1 bytes. |
| 36 | */ |
| 37 | #define SQFS_ENTRY_BASE_LENGTH 8 |
| 38 | /* Inode types */ |
| 39 | #define SQFS_DIR_TYPE 1 |
| 40 | #define SQFS_REG_TYPE 2 |
| 41 | #define SQFS_SYMLINK_TYPE 3 |
| 42 | #define SQFS_BLKDEV_TYPE 4 |
| 43 | #define SQFS_CHRDEV_TYPE 5 |
| 44 | #define SQFS_FIFO_TYPE 6 |
| 45 | #define SQFS_SOCKET_TYPE 7 |
| 46 | #define SQFS_LDIR_TYPE 8 |
| 47 | #define SQFS_LREG_TYPE 9 |
| 48 | #define SQFS_LSYMLINK_TYPE 10 |
| 49 | #define SQFS_LBLKDEV_TYPE 11 |
| 50 | #define SQFS_LCHRDEV_TYPE 12 |
| 51 | #define SQFS_LFIFO_TYPE 13 |
| 52 | #define SQFS_LSOCKET_TYPE 14 |
| 53 | |
| 54 | struct squashfs_super_block { |
| 55 | __le32 s_magic; |
| 56 | __le32 inodes; |
| 57 | __le32 mkfs_time; |
| 58 | __le32 block_size; |
| 59 | __le32 fragments; |
| 60 | __le16 compression; |
| 61 | __le16 block_log; |
| 62 | __le16 flags; |
| 63 | __le16 no_ids; |
| 64 | __le16 s_major; |
| 65 | __le16 s_minor; |
| 66 | __le64 root_inode; |
| 67 | __le64 bytes_used; |
| 68 | __le64 id_table_start; |
| 69 | __le64 xattr_id_table_start; |
| 70 | __le64 inode_table_start; |
| 71 | __le64 directory_table_start; |
| 72 | __le64 fragment_table_start; |
| 73 | __le64 export_table_start; |
| 74 | }; |
| 75 | |
Joao Marcos Costa | 877576c | 2020-08-18 17:17:21 +0200 | [diff] [blame] | 76 | struct squashfs_ctxt { |
| 77 | struct disk_partition cur_part_info; |
| 78 | struct blk_desc *cur_dev; |
| 79 | struct squashfs_super_block *sblk; |
Joao Marcos Costa | b1fa6b8 | 2020-08-18 17:17:23 +0200 | [diff] [blame] | 80 | #if IS_ENABLED(CONFIG_ZSTD) |
| 81 | void *zstd_workspace; |
| 82 | #endif |
Joao Marcos Costa | 877576c | 2020-08-18 17:17:21 +0200 | [diff] [blame] | 83 | }; |
| 84 | |
Joao Marcos Costa | 29da374 | 2020-07-30 15:33:47 +0200 | [diff] [blame] | 85 | struct squashfs_directory_index { |
| 86 | u32 index; |
| 87 | u32 start; |
| 88 | u32 size; |
| 89 | char name[0]; |
| 90 | }; |
| 91 | |
| 92 | struct squashfs_base_inode { |
| 93 | __le16 inode_type; |
| 94 | __le16 mode; |
| 95 | __le16 uid; |
| 96 | __le16 guid; |
| 97 | __le32 mtime; |
| 98 | __le32 inode_number; |
| 99 | }; |
| 100 | |
| 101 | struct squashfs_ipc_inode { |
| 102 | __le16 inode_type; |
| 103 | __le16 mode; |
| 104 | __le16 uid; |
| 105 | __le16 guid; |
| 106 | __le32 mtime; |
| 107 | __le32 inode_number; |
| 108 | __le32 nlink; |
| 109 | }; |
| 110 | |
| 111 | struct squashfs_lipc_inode { |
| 112 | __le16 inode_type; |
| 113 | __le16 mode; |
| 114 | __le16 uid; |
| 115 | __le16 guid; |
| 116 | __le32 mtime; |
| 117 | __le32 inode_number; |
| 118 | __le32 nlink; |
| 119 | __le32 xattr; |
| 120 | }; |
| 121 | |
| 122 | struct squashfs_dev_inode { |
| 123 | __le16 inode_type; |
| 124 | __le16 mode; |
| 125 | __le16 uid; |
| 126 | __le16 guid; |
| 127 | __le32 mtime; |
| 128 | __le32 inode_number; |
| 129 | __le32 nlink; |
| 130 | __le32 rdev; |
| 131 | }; |
| 132 | |
| 133 | struct squashfs_ldev_inode { |
| 134 | __le16 inode_type; |
| 135 | __le16 mode; |
| 136 | __le16 uid; |
| 137 | __le16 guid; |
| 138 | __le32 mtime; |
| 139 | __le32 inode_number; |
| 140 | __le32 nlink; |
| 141 | __le32 rdev; |
| 142 | __le32 xattr; |
| 143 | }; |
| 144 | |
| 145 | struct squashfs_symlink_inode { |
| 146 | __le16 inode_type; |
| 147 | __le16 mode; |
| 148 | __le16 uid; |
| 149 | __le16 guid; |
| 150 | __le32 mtime; |
| 151 | __le32 inode_number; |
| 152 | __le32 nlink; |
| 153 | __le32 symlink_size; |
| 154 | char symlink[0]; |
| 155 | }; |
| 156 | |
| 157 | struct squashfs_reg_inode { |
| 158 | __le16 inode_type; |
| 159 | __le16 mode; |
| 160 | __le16 uid; |
| 161 | __le16 guid; |
| 162 | __le32 mtime; |
| 163 | __le32 inode_number; |
| 164 | __le32 start_block; |
| 165 | __le32 fragment; |
| 166 | __le32 offset; |
| 167 | __le32 file_size; |
| 168 | __le32 block_list[0]; |
| 169 | }; |
| 170 | |
| 171 | struct squashfs_lreg_inode { |
| 172 | __le16 inode_type; |
| 173 | __le16 mode; |
| 174 | __le16 uid; |
| 175 | __le16 guid; |
| 176 | __le32 mtime; |
| 177 | __le32 inode_number; |
| 178 | __le64 start_block; |
| 179 | __le64 file_size; |
| 180 | __le64 sparse; |
| 181 | __le32 nlink; |
| 182 | __le32 fragment; |
| 183 | __le32 offset; |
| 184 | __le32 xattr; |
| 185 | __le32 block_list[0]; |
| 186 | }; |
| 187 | |
| 188 | struct squashfs_dir_inode { |
| 189 | __le16 inode_type; |
| 190 | __le16 mode; |
| 191 | __le16 uid; |
| 192 | __le16 guid; |
| 193 | __le32 mtime; |
| 194 | __le32 inode_number; |
| 195 | __le32 start_block; |
| 196 | __le32 nlink; |
| 197 | __le16 file_size; |
| 198 | __le16 offset; |
| 199 | __le32 parent_inode; |
| 200 | }; |
| 201 | |
| 202 | struct squashfs_ldir_inode { |
| 203 | __le16 inode_type; |
| 204 | __le16 mode; |
| 205 | __le16 uid; |
| 206 | __le16 guid; |
| 207 | __le32 mtime; |
| 208 | __le32 inode_number; |
| 209 | __le32 nlink; |
| 210 | __le32 file_size; |
| 211 | __le32 start_block; |
| 212 | __le32 parent_inode; |
| 213 | __le16 i_count; |
| 214 | __le16 offset; |
| 215 | __le32 xattr; |
| 216 | struct squashfs_directory_index index[0]; |
| 217 | }; |
| 218 | |
| 219 | union squashfs_inode { |
| 220 | struct squashfs_base_inode *base; |
| 221 | struct squashfs_dev_inode *dev; |
| 222 | struct squashfs_ldev_inode *ldev; |
| 223 | struct squashfs_symlink_inode *symlink; |
| 224 | struct squashfs_reg_inode *reg; |
| 225 | struct squashfs_lreg_inode *lreg; |
| 226 | struct squashfs_dir_inode *dir; |
| 227 | struct squashfs_ldir_inode *ldir; |
| 228 | struct squashfs_ipc_inode *ipc; |
| 229 | struct squashfs_lipc_inode *lipc; |
| 230 | }; |
| 231 | |
| 232 | struct squashfs_directory_entry { |
| 233 | u16 offset; |
Campbell Suter | 4e8f02d | 2021-04-30 16:45:46 +1200 | [diff] [blame] | 234 | s16 inode_offset; |
Joao Marcos Costa | 29da374 | 2020-07-30 15:33:47 +0200 | [diff] [blame] | 235 | u16 type; |
| 236 | u16 name_size; |
| 237 | char name[0]; |
| 238 | }; |
| 239 | |
| 240 | struct squashfs_directory_header { |
| 241 | u32 count; |
| 242 | u32 start; |
| 243 | u32 inode_number; |
| 244 | }; |
| 245 | |
| 246 | struct squashfs_fragment_block_entry { |
| 247 | u64 start; |
| 248 | u32 size; |
| 249 | u32 _unused; |
| 250 | }; |
| 251 | |
| 252 | struct squashfs_dir_stream { |
| 253 | struct fs_dir_stream fs_dirs; |
| 254 | struct fs_dirent dentp; |
| 255 | /* |
| 256 | * 'size' is the uncompressed size of the entire listing, including |
| 257 | * headers. 'entry_count' is the number of entries following a |
| 258 | * specific header. Both variables are decremented in sqfs_readdir() so |
| 259 | * the function knows when the end of the directory is reached. |
| 260 | */ |
| 261 | size_t size; |
| 262 | int entry_count; |
| 263 | /* SquashFS structures */ |
| 264 | struct squashfs_directory_header *dir_header; |
| 265 | struct squashfs_directory_entry *entry; |
| 266 | /* |
| 267 | * 'table' points to a position into the directory table. Both 'table' |
| 268 | * and 'inode' are defined for the first time in sqfs_opendir(). |
| 269 | * 'table's value changes in sqfs_readdir(). |
| 270 | */ |
| 271 | unsigned char *table; |
| 272 | union squashfs_inode i; |
| 273 | struct squashfs_dir_inode i_dir; |
| 274 | struct squashfs_ldir_inode i_ldir; |
| 275 | /* |
| 276 | * References to the tables' beginnings. They are assigned in |
| 277 | * sqfs_opendir() and freed in sqfs_closedir(). |
| 278 | */ |
| 279 | unsigned char *inode_table; |
| 280 | unsigned char *dir_table; |
| 281 | }; |
| 282 | |
| 283 | struct squashfs_file_info { |
| 284 | /* File size in bytes (uncompressed) */ |
| 285 | size_t size; |
| 286 | /* Reference to list of data blocks's sizes */ |
| 287 | u32 *blk_sizes; |
| 288 | /* Offset into the fragment block */ |
| 289 | u32 offset; |
| 290 | /* Offset in which the data blocks begin */ |
| 291 | u64 start; |
| 292 | /* Is file fragmented? */ |
| 293 | bool frag; |
| 294 | /* Compressed fragment */ |
| 295 | bool comp; |
| 296 | }; |
| 297 | |
| 298 | void *sqfs_find_inode(void *inode_table, int inode_number, __le32 inode_count, |
| 299 | __le32 block_size); |
| 300 | |
| 301 | int sqfs_dir_offset(void *dir_i, u32 *m_list, int m_count); |
| 302 | |
| 303 | int sqfs_read_metablock(unsigned char *file_mapping, int offset, |
| 304 | bool *compressed, u32 *data_size); |
| 305 | |
| 306 | bool sqfs_is_empty_dir(void *dir_i); |
| 307 | |
| 308 | bool sqfs_is_dir(u16 type); |
| 309 | |
| 310 | #endif /* SQFS_FILESYSTEM_H */ |