1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
|
#ifndef UNSQUASHFS_H
#define UNSQUASHFS_H
/*
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2013, 2014, 2019, 2021, 2022, 2023
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* unsquashfs.h
*/
#define TRUE 1
#define FALSE 0
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <utime.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <regex.h>
#include <signal.h>
#include <pthread.h>
#include <math.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "endian_compat.h"
#include "squashfs_fs.h"
#include "unsquashfs_error.h"
#define TABLE_HASH(start) (start & 0xffff)
/*
* Unified superblock containing fields for all superblocks
*/
struct super_block {
struct squashfs_super_block s;
/* fields only used by squashfs 3 and earlier layouts */
unsigned int no_uids;
unsigned int no_guids;
long long uid_start;
long long guid_start;
/* fields only used by squashfs 4 */
unsigned int xattr_ids;
};
struct hash_table_entry {
long long start;
int length;
void *buffer;
long long next_index;
struct hash_table_entry *next;
};
struct inode {
int blocks;
long long block_start;
unsigned int block_offset;
long long data;
unsigned int fragment;
int frag_bytes;
gid_t gid;
unsigned int inode_number;
int mode;
int offset;
long long start;
char *symlink;
time_t time;
int type;
uid_t uid;
char sparse;
unsigned int xattr;
};
typedef struct squashfs_operations {
struct dir *(*opendir)(unsigned int block_start,
unsigned int offset, struct inode **i);
void (*read_fragment)(unsigned int fragment, long long *start_block,
int *size);
void (*read_block_list)(unsigned int *block_list, long long start,
unsigned int offset, int blocks);
struct inode *(*read_inode)(unsigned int start_block,
unsigned int offset);
int (*read_filesystem_tables)();
void (*stat)(char *);
} squashfs_operations;
struct test {
int mask;
int value;
int position;
char mode;
};
/* Cache status struct. Caches are used to keep
track of memory buffers passed between different threads */
struct cache {
int max_buffers;
int count;
int used;
int buffer_size;
int wait_free;
int wait_pending;
pthread_mutex_t mutex;
pthread_cond_t wait_for_free;
pthread_cond_t wait_for_pending;
struct cache_entry *free_list;
struct cache_entry *hash_table[65536];
};
/* struct describing a cache entry passed between threads */
struct cache_entry {
struct cache *cache;
long long block;
int size;
int used;
int error;
int pending;
struct cache_entry *hash_next;
struct cache_entry *hash_prev;
struct cache_entry *free_next;
struct cache_entry *free_prev;
char *data;
};
/* struct describing queues used to pass data between threads */
struct queue {
int size;
int readp;
int writep;
pthread_mutex_t mutex;
pthread_cond_t empty;
pthread_cond_t full;
void **data;
};
/* default size of fragment buffer in Mbytes */
#define FRAGMENT_BUFFER_DEFAULT 256
/* default size of data buffer in Mbytes */
#define DATA_BUFFER_DEFAULT 256
#define DIR_ENT_SIZE 16
struct dir_ent {
char *name;
unsigned int start_block;
unsigned int offset;
unsigned int type;
struct dir_ent *next;
};
struct dir {
int dir_count;
unsigned int mode;
uid_t uid;
gid_t guid;
unsigned int mtime;
unsigned int xattr;
struct dir_ent *dirs;
struct dir_ent *cur_entry;
};
struct file_entry {
int offset;
int size;
struct cache_entry *buffer;
};
struct squashfs_file {
int fd;
int blocks;
long long file_size;
int mode;
uid_t uid;
gid_t gid;
time_t time;
char *pathname;
char sparse;
unsigned int xattr;
};
struct path_entry {
char *name;
int type;
regex_t *preg;
struct pathname *paths;
};
struct pathname {
int names;
struct path_entry *name;
};
struct pathnames {
int count;
struct pathname *path[0];
};
#define PATHS_ALLOC_SIZE 10
#define PATH_TYPE_LINK 1
#define PATH_TYPE_EXTRACT 2
#define PATH_TYPE_EXCLUDE 4
struct directory_level {
unsigned int start_block;
unsigned int offset;
char *name;
};
struct symlink {
char *pathname;
struct symlink *next;
};
struct directory_stack {
int size;
unsigned int type;
unsigned int start_block;
unsigned int offset;
char *name;
struct directory_level *stack;
struct symlink *symlink;
};
#define MAX_FOLLOW_SYMLINKS 256
/* These macros implement a bit-table to track whether directories have been
* already visited. This is to trap corrupted filesystems which have multiple
* links to the same directory, which is invalid, and which may also create
* a directory loop, where Unsquashfs will endlessly recurse until either
* the pathname is too large (extracting), or the stack overflows.
*
* Each index entry is 8 Kbytes, and tracks 65536 inode numbers. The index is
* allocated on demand because Unsquashfs may not walk the complete filesystem.
*/
#define INUMBER_INDEXES(INODES) ((((INODES) - 1) >> 16) + 1)
#define INUMBER_INDEX(NUMBER) ((NUMBER) >> 16)
#define INUMBER_OFFSET(NUMBER) (((NUMBER) & 0xffff) >> 5)
#define INUMBER_BIT(NUMBER) (1 << ((NUMBER) & 0x1f))
#define INUMBER_BYTES 8192
/* These macros implement a lookup table to track creation of (non-directory)
* inodes, and to discover if a hard-link to a previously created file should
* be made.
*
* Each index entry is 32 Kbytes, and tracks 4096 inode numbers. The index is
* allocated on demand because Unsquashfs may not walk the complete filesystem.
*/
#define LOOKUP_INDEXES(INODES) ((((INODES) - 1) >> 12) + 1)
#define LOOKUP_INDEX(NUMBER) ((NUMBER) >> 12)
#define LOOKUP_OFFSET(NUMBER) ((NUMBER) & 0xfff)
#define LOOKUP_BYTES 32768
#define LOOKUP_OFFSETS 4096
/* Maximum transfer size for Linux read() call on both 32-bit and 64-bit systems.
* See READ(2) */
#define MAXIMUM_READ_SIZE 0x7ffff000
/* globals */
extern struct super_block sBlk;
extern int swap;
extern struct hash_table_entry *directory_table_hash[65536];
extern pthread_mutex_t screen_mutex;
extern int progress_enabled;
extern int inode_number;
extern int lookup_type[];
extern int fd;
extern int no_xattrs;
extern struct queue *to_reader, *to_inflate, *to_writer;
extern struct cache *fragment_cache, *data_cache;
extern struct compressor *comp;
extern int use_localtime;
extern unsigned int timeval;
extern int time_opt;
/* unsquashfs.c */
extern int read_inode_data(void *, long long *, unsigned int *, int);
extern int read_directory_data(void *, long long *, unsigned int *, int);
extern int read_fs_bytes(int fd, long long, long long, void *);
extern int read_block(int, long long, long long *, int, void *);
extern void enable_progress_bar();
extern void disable_progress_bar();
extern void dump_queue(struct queue *);
extern void dump_cache(struct cache *);
extern int write_bytes(int, char *, int);
/* unsquash-1.c */
int read_super_1(squashfs_operations **, void *);
/* unsquash-2.c */
int read_super_2(squashfs_operations **, void *);
/* unsquash-3.c */
int read_super_3(char *, squashfs_operations **, void *);
/* unsquash-4.c */
int read_super_4(squashfs_operations **);
/* unsquash-123.c */
extern int read_ids(int, long long, long long, unsigned int **);
/* unsquash-34.c */
extern long long *alloc_index_table(int);
extern int inumber_lookup(unsigned int);
extern void free_inumber_table();
extern char *lookup(unsigned int);
extern void insert_lookup(unsigned int, char *);
extern void free_lookup_table(int);
/* unsquash-1234.c */
extern int check_name(char *, int);
extern void squashfs_closedir(struct dir *);
extern int check_directory(struct dir *);
/* unsquash-12.c */
extern void sort_directory(struct dir_ent **, int);
/* date.c */
extern int exec_date(char *, unsigned int *);
#endif
|