6 * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #define SQUASHFS_MAJOR 2
26 #define SQUASHFS_MINOR 0
27 #define SQUASHFS_MAGIC 0x73717368
28 #define SQUASHFS_MAGIC_SWAP 0x68737173
29 #define SQUASHFS_START 0
31 /* size of metadata (inode and directory) blocks */
32 #define SQUASHFS_METADATA_SIZE 8192
33 #define SQUASHFS_METADATA_LOG 13
35 /* default size of data blocks */
36 #define SQUASHFS_FILE_SIZE 65536
37 #define SQUASHFS_FILE_LOG 16
39 #define SQUASHFS_FILE_MAX_SIZE 65536
41 /* Max number of uids and gids */
42 #define SQUASHFS_UIDS 256
43 #define SQUASHFS_GUIDS 255
45 /* Max length of filename (not 255) */
46 #define SQUASHFS_NAME_LEN 256
48 #define SQUASHFS_INVALID ((long long) 0xffffffffffff)
49 #define SQUASHFS_INVALID_BLK ((long long) 0xffffffff)
50 #define SQUASHFS_USED_BLK ((long long) 0xfffffffe)
52 /* Filesystem flags */
53 #define SQUASHFS_NOI 0
54 #define SQUASHFS_NOD 1
55 #define SQUASHFS_CHECK 2
56 #define SQUASHFS_NOF 3
57 #define SQUASHFS_NO_FRAG 4
58 #define SQUASHFS_ALWAYS_FRAG 5
59 #define SQUASHFS_DUPLICATE 6
60 #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
61 #define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI)
62 #define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD)
63 #define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF)
64 #define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG)
65 #define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG)
66 #define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE)
67 #define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK)
68 #define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6))
70 /* Max number of types and file types */
71 #define SQUASHFS_DIR_TYPE 1
72 #define SQUASHFS_FILE_TYPE 2
73 #define SQUASHFS_SYMLINK_TYPE 3
74 #define SQUASHFS_BLKDEV_TYPE 4
75 #define SQUASHFS_CHRDEV_TYPE 5
76 #define SQUASHFS_FIFO_TYPE 6
77 #define SQUASHFS_SOCKET_TYPE 7
79 /* 1.0 filesystem type definitions */
80 #define SQUASHFS_TYPES 5
81 #define SQUASHFS_IPC_TYPE 0
83 /* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */
84 #define SQUASHFS_COMPRESSED_BIT (1 << 15)
85 #define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
86 (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
88 #define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
90 #define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
91 #define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \
92 (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
94 #define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
97 * Inode number ops. Inodes consist of a compressed block number, and an uncompressed
98 * offset within that block
100 #define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
101 #define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
102 #define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\
105 /* Compute 32 bit VFS inode number from squashfs inode number */
106 #define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1))
108 /* Translate between VFS mode and squashfs mode */
109 #define SQUASHFS_MODE(a) ((a) & 0xfff)
111 /* fragment and fragment table defines */
112 typedef unsigned int squashfs_fragment_index;
113 #define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry))
114 #define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE)
115 #define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE)
116 #define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE)
117 #define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index))
118 #define SQUASHFS_CACHED_FRAGMENTS 3
120 /* cached data constants for filesystem */
121 #define SQUASHFS_CACHED_BLKS 8
123 #define SQUASHFS_MAX_FILE_SIZE_LOG 32
124 #define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1))
126 #define SQUASHFS_MARKER_BYTE 0xff
129 * definitions for structures on disk
132 typedef unsigned int squashfs_block;
133 typedef long long squashfs_inode;
135 typedef unsigned int squashfs_uid;
137 typedef struct squashfs_super_block {
138 unsigned int s_magic;
140 unsigned int bytes_used;
141 unsigned int uid_start;
142 unsigned int guid_start;
143 unsigned int inode_table_start;
144 unsigned int directory_table_start;
145 unsigned int s_major:16;
146 unsigned int s_minor:16;
147 unsigned int block_size_1:16;
148 unsigned int block_log:16;
149 unsigned int flags:8;
150 unsigned int no_uids:8;
151 unsigned int no_guids:8;
152 unsigned int mkfs_time /* time of filesystem creation */;
153 squashfs_inode root_inode;
154 unsigned int block_size;
155 unsigned int fragments;
156 unsigned int fragment_table_start;
157 } __attribute__ ((packed)) squashfs_super_block;
160 unsigned int inode_type:4;
161 unsigned int mode:12; /* protection */
162 unsigned int uid:8; /* index into uid table */
163 unsigned int guid:8; /* index into guid table */
164 } __attribute__ ((packed)) squashfs_base_inode_header;
166 typedef squashfs_base_inode_header squashfs_ipc_inode_header;
169 unsigned int inode_type:4;
170 unsigned int mode:12; /* protection */
171 unsigned int uid:8; /* index into uid table */
172 unsigned int guid:8; /* index into guid table */
174 } __attribute__ ((packed)) squashfs_dev_inode_header;
177 unsigned int inode_type:4;
178 unsigned int mode:12; /* protection */
179 unsigned int uid:8; /* index into uid table */
180 unsigned int guid:8; /* index into guid table */
181 unsigned short symlink_size;
183 } __attribute__ ((packed)) squashfs_symlink_inode_header;
186 unsigned int inode_type:4;
187 unsigned int mode:12; /* protection */
188 unsigned int uid:8; /* index into uid table */
189 unsigned int guid:8; /* index into guid table */
191 squashfs_block start_block;
192 unsigned int fragment;
194 unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG;
195 unsigned short block_list[0];
196 } __attribute__ ((packed)) squashfs_reg_inode_header;
199 unsigned int inode_type:4;
200 unsigned int mode:12; /* protection */
201 unsigned int uid:8; /* index into uid table */
202 unsigned int guid:8; /* index into guid table */
203 unsigned int file_size:19;
204 unsigned int offset:13;
206 unsigned int start_block:24;
207 } __attribute__ ((packed)) squashfs_dir_inode_header;
210 squashfs_base_inode_header base;
211 squashfs_dev_inode_header dev;
212 squashfs_symlink_inode_header symlink;
213 squashfs_reg_inode_header reg;
214 squashfs_dir_inode_header dir;
215 squashfs_ipc_inode_header ipc;
216 } squashfs_inode_header;
219 unsigned int offset:13;
223 } __attribute__ ((packed)) squashfs_dir_entry;
226 unsigned int count:8;
227 unsigned int start_block:24;
228 } __attribute__ ((packed)) squashfs_dir_header;
232 unsigned int start_block;
234 } __attribute__ ((packed)) squashfs_fragment_entry;
236 extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
237 extern int squashfs_uncompress_init(void);
238 extern int squashfs_uncompress_exit(void);
241 * macros to convert each packed bitfield structure from little endian to big
242 * endian and vice versa. These are needed when creating or using a filesystem on a
243 * machine with different byte ordering to the target architecture.
247 #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
248 SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\
249 SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
250 SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
251 SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\
252 SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\
253 SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\
254 SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\
255 SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\
256 SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
257 SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
258 SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
259 SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
260 SQUASHFS_SWAP((s)->flags, d, 288, 8);\
261 SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
262 SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
263 SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
264 SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
265 SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
266 SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
267 SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\
270 #define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
271 SQUASHFS_MEMSET(s, d, n);\
272 SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
273 SQUASHFS_SWAP((s)->mode, d, 4, 12);\
274 SQUASHFS_SWAP((s)->uid, d, 16, 8);\
275 SQUASHFS_SWAP((s)->guid, d, 24, 8);\
278 #define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header))
280 #define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
281 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\
282 SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
285 #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
286 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\
287 SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
290 #define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
291 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\
292 SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
293 SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
294 SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
295 SQUASHFS_SWAP((s)->offset, d, 128, 32);\
296 SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\
299 #define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
300 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\
301 SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
302 SQUASHFS_SWAP((s)->offset, d, 51, 13);\
303 SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
304 SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
307 #define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
308 SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\
309 SQUASHFS_SWAP((s)->count, d, 0, 8);\
310 SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
313 #define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
314 SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\
315 SQUASHFS_SWAP((s)->offset, d, 0, 13);\
316 SQUASHFS_SWAP((s)->type, d, 13, 3);\
317 SQUASHFS_SWAP((s)->size, d, 16, 8);\
320 #define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
321 SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\
322 SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
323 SQUASHFS_SWAP((s)->size, d, 32, 32);\
326 #define SQUASHFS_SWAP_SHORTS(s, d, n) {\
329 SQUASHFS_MEMSET(s, d, n * 2);\
330 for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\
331 SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
334 #define SQUASHFS_SWAP_INTS(s, d, n) {\
337 SQUASHFS_MEMSET(s, d, n * 4);\
338 for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\
339 SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
342 #define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
345 SQUASHFS_MEMSET(s, d, n * bits / 8);\
346 for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\
347 SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
350 #define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
352 #ifdef SQUASHFS_1_0_COMPATIBILITY
354 unsigned int inode_type:4;
355 unsigned int mode:12; /* protection */
356 unsigned int uid:4; /* index into uid table */
357 unsigned int guid:4; /* index into guid table */
358 } __attribute__ ((packed)) squashfs_base_inode_header_1;
361 unsigned int inode_type:4;
362 unsigned int mode:12; /* protection */
363 unsigned int uid:4; /* index into uid table */
364 unsigned int guid:4; /* index into guid table */
366 unsigned int offset:4;
367 } __attribute__ ((packed)) squashfs_ipc_inode_header_1;
370 unsigned int inode_type:4;
371 unsigned int mode:12; /* protection */
372 unsigned int uid:4; /* index into uid table */
373 unsigned int guid:4; /* index into guid table */
375 } __attribute__ ((packed)) squashfs_dev_inode_header_1;
378 unsigned int inode_type:4;
379 unsigned int mode:12; /* protection */
380 unsigned int uid:4; /* index into uid table */
381 unsigned int guid:4; /* index into guid table */
382 unsigned short symlink_size;
384 } __attribute__ ((packed)) squashfs_symlink_inode_header_1;
387 unsigned int inode_type:4;
388 unsigned int mode:12; /* protection */
389 unsigned int uid:4; /* index into uid table */
390 unsigned int guid:4; /* index into guid table */
392 squashfs_block start_block;
393 unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG;
394 unsigned short block_list[0];
395 } __attribute__ ((packed)) squashfs_reg_inode_header_1;
398 unsigned int inode_type:4;
399 unsigned int mode:12; /* protection */
400 unsigned int uid:4; /* index into uid table */
401 unsigned int guid:4; /* index into guid table */
402 unsigned int file_size:19;
403 unsigned int offset:13;
405 unsigned int start_block:24;
406 } __attribute__ ((packed)) squashfs_dir_inode_header_1;
408 #define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
409 SQUASHFS_MEMSET(s, d, n);\
410 SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
411 SQUASHFS_SWAP((s)->mode, d, 4, 12);\
412 SQUASHFS_SWAP((s)->uid, d, 16, 4);\
413 SQUASHFS_SWAP((s)->guid, d, 20, 4);\
416 #define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
417 SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\
418 SQUASHFS_SWAP((s)->type, d, 24, 4);\
419 SQUASHFS_SWAP((s)->offset, d, 28, 4);\
422 #define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
423 SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\
424 SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
427 #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
428 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\
429 SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
432 #define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
433 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\
434 SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
435 SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
436 SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\
439 #define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
440 SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\
441 SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
442 SQUASHFS_SWAP((s)->offset, d, 43, 13);\
443 SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
444 SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
450 * macros used to swap each structure entry, taking into account
451 * bitfields and different bitfield placing conventions on differing architectures
453 #include <asm/byteorder.h>
455 /* convert from little endian to big endian */
456 #define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
458 /* convert from big endian to little endian */
459 #define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
462 #define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
464 int b_pos = pos % 8;\
465 unsigned long long val = 0;\
466 unsigned char *s = (unsigned char *)p + (pos / 8);\
467 unsigned char *d = ((unsigned char *) &val) + 7;\
468 for(bits = 0; bits < (tbits + b_pos); bits += 8) \
470 value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
472 #define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);