1/*
2 * Unsquash a squashfs filesystem.  This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2009, 2010
6 * Phillip Lougher <phillip@lougher.demon.co.uk>
7 *
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.
12 *
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.
17 *
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.
21 *
22 * unsquashfs.h
23 */
24
25#define TRUE 1
26#define FALSE 0
27#include <stdio.h>
28#include <sys/types.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <errno.h>
34#include <string.h>
35#include <sys/mman.h>
36#include <utime.h>
37#include <pwd.h>
38#include <grp.h>
39#include <time.h>
40#include <regex.h>
41#include <fnmatch.h>
42#include <signal.h>
43#include <pthread.h>
44#include <math.h>
45#include <sys/ioctl.h>
46#include <sys/time.h>
47
48#ifndef linux
49#define __BYTE_ORDER BYTE_ORDER
50#define __BIG_ENDIAN BIG_ENDIAN
51#define __LITTLE_ENDIAN LITTLE_ENDIAN
52#else
53#include <endian.h>
54#endif
55
56#include "squashfs_fs.h"
57
58#ifdef SQUASHFS_TRACE
59#define TRACE(s, args...) \
60		do { \
61			pthread_mutex_lock(&screen_mutex); \
62			if(progress_enabled) \
63				printf("\n"); \
64			printf("unsquashfs: "s, ## args); \
65			pthread_mutex_unlock(&screen_mutex);\
66		} while(0)
67#else
68#define TRACE(s, args...)
69#endif
70
71#define ERROR(s, args...) \
72		do { \
73			pthread_mutex_lock(&screen_mutex); \
74			if(progress_enabled) \
75				fprintf(stderr, "\n"); \
76			fprintf(stderr, s, ## args); \
77			pthread_mutex_unlock(&screen_mutex);\
78		} while(0)
79
80#define EXIT_UNSQUASH(s, args...) \
81		do { \
82			pthread_mutex_lock(&screen_mutex); \
83			fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \
84			pthread_mutex_unlock(&screen_mutex);\
85			exit(1); \
86		} while(0)
87
88#define CALCULATE_HASH(start)	(start & 0xffff)
89
90/*
91 * Unified superblock containing fields for all superblocks
92 */
93struct super_block {
94	struct squashfs_super_block s;
95	/* fields only used by squashfs 3 and earlier layouts */
96	unsigned int		no_uids;
97	unsigned int		no_guids;
98	long long		uid_start;
99	long long		guid_start;
100};
101
102struct hash_table_entry {
103	long long	start;
104	int		bytes;
105	struct hash_table_entry *next;
106};
107
108struct inode {
109	int blocks;
110	char *block_ptr;
111	long long data;
112	int fragment;
113	int frag_bytes;
114	gid_t gid;
115	int inode_number;
116	int mode;
117	int offset;
118	long long start;
119	char *symlink;
120	time_t time;
121	int type;
122	uid_t uid;
123	char sparse;
124	unsigned int xattr;
125};
126
127typedef struct squashfs_operations {
128	struct dir *(*squashfs_opendir)(unsigned int block_start,
129		unsigned int offset, struct inode **i);
130	void (*read_fragment)(unsigned int fragment, long long *start_block,
131		int *size);
132	int (*read_fragment_table)();
133	void (*read_block_list)(unsigned int *block_list, char *block_ptr,
134		int blocks);
135	struct inode *(*read_inode)(unsigned int start_block,
136		unsigned int offset);
137	int (*read_uids_guids)();
138} squashfs_operations;
139
140struct test {
141	int mask;
142	int value;
143	int position;
144	char mode;
145};
146
147
148/* Cache status struct.  Caches are used to keep
149  track of memory buffers passed between different threads */
150struct cache {
151	int	max_buffers;
152	int	count;
153	int	buffer_size;
154	int	wait_free;
155	int	wait_pending;
156	pthread_mutex_t	mutex;
157	pthread_cond_t wait_for_free;
158	pthread_cond_t wait_for_pending;
159	struct cache_entry *free_list;
160	struct cache_entry *hash_table[65536];
161};
162
163/* struct describing a cache entry passed between threads */
164struct cache_entry {
165	struct cache *cache;
166	long long block;
167	int	size;
168	int	used;
169	int error;
170	int	pending;
171	struct cache_entry *hash_next;
172	struct cache_entry *hash_prev;
173	struct cache_entry *free_next;
174	struct cache_entry *free_prev;
175	char *data;
176};
177
178/* struct describing queues used to pass data between threads */
179struct queue {
180	int	size;
181	int	readp;
182	int	writep;
183	pthread_mutex_t	mutex;
184	pthread_cond_t empty;
185	pthread_cond_t full;
186	void **data;
187};
188
189/* default size of fragment buffer in Mbytes */
190#define FRAGMENT_BUFFER_DEFAULT 256
191/* default size of data buffer in Mbytes */
192#define DATA_BUFFER_DEFAULT 256
193
194#define DIR_ENT_SIZE	16
195
196struct dir_ent	{
197	char		name[SQUASHFS_NAME_LEN + 1];
198	unsigned int	start_block;
199	unsigned int	offset;
200	unsigned int	type;
201};
202
203struct dir {
204	int		dir_count;
205	int 		cur_entry;
206	unsigned int	mode;
207	uid_t		uid;
208	gid_t		guid;
209	unsigned int	mtime;
210	unsigned int xattr;
211	struct dir_ent	*dirs;
212};
213
214struct file_entry {
215	int offset;
216	int size;
217	struct cache_entry *buffer;
218};
219
220
221struct squashfs_file {
222	int fd;
223	int blocks;
224	long long file_size;
225	int mode;
226	uid_t uid;
227	gid_t gid;
228	time_t time;
229	char *pathname;
230	char sparse;
231	unsigned int xattr;
232};
233
234struct path_entry {
235	char *name;
236	regex_t *preg;
237	struct pathname *paths;
238};
239
240struct pathname {
241	int names;
242	struct path_entry *name;
243};
244
245struct pathnames {
246	int count;
247	struct pathname *path[0];
248};
249#define PATHS_ALLOC_SIZE 10
250
251/* globals */
252extern struct super_block sBlk;
253extern squashfs_operations s_ops;
254extern int swap;
255extern char *inode_table, *directory_table;
256extern struct hash_table_entry *inode_table_hash[65536],
257	*directory_table_hash[65536];
258extern unsigned int *uid_table, *guid_table;
259extern pthread_mutex_t screen_mutex;
260extern int progress_enabled;
261extern int inode_number;
262extern int lookup_type[];
263extern int fd;
264
265/* unsquashfs.c */
266extern int lookup_entry(struct hash_table_entry **, long long);
267extern int read_fs_bytes(int fd, long long, int, void *);
268extern int read_block(int, long long, long long *, void *);
269
270/* unsquash-1.c */
271extern void read_block_list_1(unsigned int *, char *, int);
272extern int read_fragment_table_1();
273extern struct inode *read_inode_1(unsigned int, unsigned int);
274extern struct dir *squashfs_opendir_1(unsigned int, unsigned int,
275	struct inode **);
276extern int read_uids_guids_1();
277
278/* unsquash-2.c */
279extern void read_block_list_2(unsigned int *, char *, int);
280extern int read_fragment_table_2();
281extern void read_fragment_2(unsigned int, long long *, int *);
282extern struct inode *read_inode_2(unsigned int, unsigned int);
283
284/* unsquash-3.c */
285extern int read_fragment_table_3();
286extern void read_fragment_3(unsigned int, long long *, int *);
287extern struct inode *read_inode_3(unsigned int, unsigned int);
288extern struct dir *squashfs_opendir_3(unsigned int, unsigned int,
289	struct inode **);
290
291/* unsquash-4.c */
292extern int read_fragment_table_4();
293extern void read_fragment_4(unsigned int, long long *, int *);
294extern struct inode *read_inode_4(unsigned int, unsigned int);
295extern struct dir *squashfs_opendir_4(unsigned int, unsigned int,
296	struct inode **);
297extern int read_uids_guids_4();
298