blob: 9153eddc6c341a3cc9ae3c905693037cd410cf04 [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
2 * Create a squashfs filesystem. This is a highly compressed read only filesystem.
3 *
plougher217bad82008-04-05 11:36:41 +00004 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
plougherf6cd3372007-08-19 03:33:23 +00005 * Phillip Lougher <phillip@lougher.demon.co.uk>
plougher1f413c82005-11-18 00:02:14 +00006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * mksquashfs.c
22 */
23
plougher324978d2006-02-27 04:53:29 +000024#define FALSE 0
plougher1f413c82005-11-18 00:02:14 +000025#define TRUE 1
plougher8cb05cd2005-12-11 23:32:35 +000026
plougher1f413c82005-11-18 00:02:14 +000027#include <pwd.h>
28#include <grp.h>
29#include <time.h>
30#include <unistd.h>
31#include <stdio.h>
plougher35a10602008-04-21 02:58:16 +000032#include <sys/time.h>
plougher1f413c82005-11-18 00:02:14 +000033#include <sys/types.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <dirent.h>
38#include <string.h>
39#include <zlib.h>
plougher1f413c82005-11-18 00:02:14 +000040#include <stdlib.h>
41#include <signal.h>
42#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000043#include <sys/ioctl.h>
44#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000045#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000046#include <pthread.h>
plougher02bc3bc2007-02-25 12:12:01 +000047#include <math.h>
plougher8f8e1a12007-10-18 02:50:21 +000048#include <regex.h>
49#include <fnmatch.h>
plougher1f413c82005-11-18 00:02:14 +000050
plougher68853292005-12-27 02:47:04 +000051#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000052#define __BYTE_ORDER BYTE_ORDER
53#define __BIG_ENDIAN BIG_ENDIAN
54#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000055#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000056#else
57#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000058#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000059#endif
60
plougher1f413c82005-11-18 00:02:14 +000061#include <squashfs_fs.h>
62#include "mksquashfs.h"
63#include "global.h"
plougher117b2ea2006-02-09 09:23:56 +000064#include "sort.h"
plougher1f413c82005-11-18 00:02:14 +000065
66#ifdef SQUASHFS_TRACE
plougher324978d2006-02-27 04:53:29 +000067#define TRACE(s, args...) do { \
plougher91fbb302008-05-06 02:29:36 +000068 pthread_mutex_lock(&progress_mutex); \
69 if(progress_enabled) \
70 printf("\n"); \
plougher324978d2006-02-27 04:53:29 +000071 printf("mksquashfs: "s, ## args); \
72 } while(0)
plougher1f413c82005-11-18 00:02:14 +000073#else
74#define TRACE(s, args...)
75#endif
76
plougher324978d2006-02-27 04:53:29 +000077#define INFO(s, args...) do {\
78 if(!silent)\
79 printf("mksquashfs: "s, ## args);\
80 } while(0)
81#define ERROR(s, args...) do {\
plougher91fbb302008-05-06 02:29:36 +000082 pthread_mutex_lock(&progress_mutex); \
83 if(progress_enabled) \
84 fprintf(stderr, "\n"); \
plougher324978d2006-02-27 04:53:29 +000085 fprintf(stderr, s, ## args);\
plougher91fbb302008-05-06 02:29:36 +000086 pthread_mutex_unlock(&progress_mutex); \
plougher324978d2006-02-27 04:53:29 +000087 } while(0)
88#define EXIT_MKSQUASHFS() do {\
89 if(restore)\
90 restorefs();\
91 if(delete && destination_file && !block_device)\
92 unlink(destination_file);\
93 exit(1);\
94 } while(0)
95#define BAD_ERROR(s, args...) do {\
plougher91fbb302008-05-06 02:29:36 +000096 pthread_mutex_lock(&progress_mutex); \
97 if(progress_enabled) \
98 fprintf(stderr, "\n"); \
plougher1f413c82005-11-18 00:02:14 +000099 fprintf(stderr, "FATAL ERROR:" s, ##args);\
plougher91fbb302008-05-06 02:29:36 +0000100 pthread_mutex_unlock(&progress_mutex); \
plougher1f413c82005-11-18 00:02:14 +0000101 EXIT_MKSQUASHFS();\
plougher324978d2006-02-27 04:53:29 +0000102 } while(0)
plougher1f413c82005-11-18 00:02:14 +0000103
plougher324978d2006-02-27 04:53:29 +0000104int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000105int fd;
plougher02bc3bc2007-02-25 12:12:01 +0000106int cur_uncompressed = 0, estimated_uncompressed = 0;
107int columns;
plougher1f413c82005-11-18 00:02:14 +0000108
109/* filesystem flags for building */
110int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
111int noI = 0, noD = 0, check_data = 0;
112int swap, silent = TRUE;
113long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +0000114int exportable = TRUE;
115int progress = TRUE;
plougher91fbb302008-05-06 02:29:36 +0000116int progress_enabled = FALSE;
plougher8dcc6992007-08-17 19:32:52 +0000117int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +0000118int old_exclude = TRUE;
119int use_regex = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000120
121/* superblock attributes */
122int block_size = SQUASHFS_FILE_SIZE, block_log;
123unsigned short uid_count = 0, guid_count = 0;
124squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
125int block_offset;
126int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
127
128/* write position within data section */
129long long bytes = 0, total_bytes = 0;
130
131/* in memory directory table - possibly compressed */
132char *directory_table = NULL;
133unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
134
135/* cached directory table */
136char *directory_data_cache = NULL;
137unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
138
139/* in memory inode table - possibly compressed */
140char *inode_table = NULL;
141unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
142
143/* cached inode table */
144char *data_cache = NULL;
145unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
146
plougher0e453652006-11-06 01:49:35 +0000147/* inode lookup table */
148squashfs_inode *inode_lookup_table = NULL;
149
plougher1f413c82005-11-18 00:02:14 +0000150/* in memory directory data */
151#define I_COUNT_SIZE 128
152#define DIR_ENTRIES 32
153#define INODE_HASH_SIZE 65536
154#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
155#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
156
157struct cached_dir_index {
158 squashfs_dir_index index;
159 char *name;
160};
161
162struct directory {
163 unsigned int start_block;
164 unsigned int size;
165 unsigned char *buff;
166 unsigned char *p;
167 unsigned int entry_count;
168 unsigned char *entry_count_p;
169 unsigned int i_count;
170 unsigned int i_size;
171 struct cached_dir_index *index;
172 unsigned char *index_count_p;
173 unsigned int inode_number;
174};
175
plougher1f413c82005-11-18 00:02:14 +0000176struct inode_info *inode_info[INODE_HASH_SIZE];
177
178/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000179struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000180int dup_files = 0;
181
plougher8f8e1a12007-10-18 02:50:21 +0000182/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000183/* list of exclude dirs/files */
184struct exclude_info {
185 dev_t st_dev;
186 ino_t st_ino;
187};
188
189#define EXCLUDE_SIZE 8192
190int exclude = 0;
191struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000192int old_excluded(char *filename, struct stat *buf);
193
194struct path_entry {
195 char *name;
196 regex_t *preg;
197 struct pathname *paths;
198};
199
200struct pathname {
201 int names;
202 struct path_entry *name;
203};
204
plougherf9039c92007-10-22 03:54:16 +0000205struct pathnames {
206 int count;
207 struct pathname *path[0];
208};
209#define PATHS_ALLOC_SIZE 10
210
211struct pathnames *paths = NULL;
212struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000213struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000214int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000215
216/* fragment block data structures */
217int fragments = 0;
plougher5507dd92006-11-06 00:43:10 +0000218struct file_buffer *fragment_data = NULL;
plougher1f413c82005-11-18 00:02:14 +0000219int fragment_size = 0;
plougher76c64082008-03-08 01:32:23 +0000220
plougher1f413c82005-11-18 00:02:14 +0000221struct fragment {
222 unsigned int index;
223 int offset;
224 int size;
225};
plougher76c64082008-03-08 01:32:23 +0000226
plougher1f413c82005-11-18 00:02:14 +0000227#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000228#define FRAG_INDEX (1LL << 32)
229
plougher1f413c82005-11-18 00:02:14 +0000230squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000231int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000232
plougher1f413c82005-11-18 00:02:14 +0000233/* current inode number for directories and non directories */
234unsigned int dir_inode_no = 1;
235unsigned int inode_no = 0;
plougherdf70c3e2006-01-27 09:34:13 +0000236unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000237
238/* list of source dirs/files */
239int source = 0;
240char **source_path;
241
242/* list of root directory entries read from original filesystem */
243int old_root_entries = 0;
244struct old_root_entry_info {
245 char name[SQUASHFS_NAME_LEN + 1];
246 squashfs_inode inode;
247 int type;
248 int inode_number;
249};
250struct old_root_entry_info *old_root_entry;
251
252/* in memory file info */
253struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000254 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000255 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000256 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000257 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000258 long long start;
259 unsigned int *block_list;
260 struct file_info *next;
261 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000262 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000263};
264
265/* count of how many times SIGINT or SIGQUIT has been sent */
266int interrupted = 0;
267
268/* restore orignal filesystem state if appending to existing filesystem is cancelled */
269jmp_buf env;
270char *sdata_cache, *sdirectory_data_cache;
271
272long long sbytes, stotal_bytes;
273
274unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
275 sdirectory_cache_bytes, suid_count, sguid_count,
276 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000277 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000278 sdir_count, sfifo_count, ssock_count, sdup_files;
279int sfragments;
280int restore = 0;
plougher5507dd92006-11-06 00:43:10 +0000281int threads;
plougher1f413c82005-11-18 00:02:14 +0000282
283/* flag whether destination file is a block device */
284int block_device = 0;
285
286/* flag indicating whether files are sorted using sort list(s) */
287int sorted = 0;
288
plougher324978d2006-02-27 04:53:29 +0000289/* save destination file name for deleting on error */
290char *destination_file = NULL;
291
plougher99ac0cc2007-10-29 03:17:10 +0000292/* recovery file for abnormal exit on appending */
293char recovery_file[1024] = "";
294int recover = TRUE;
295
ploughereb6eac92008-02-26 01:50:48 +0000296/* struct describing a cache entry passed between threads */
plougher5507dd92006-11-06 00:43:10 +0000297struct file_buffer {
ploughereb6eac92008-02-26 01:50:48 +0000298 struct cache *cache;
plougher76c64082008-03-08 01:32:23 +0000299 int keep;
300 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000301 long long index;
302 long long block;
plougher0f464442008-03-31 00:27:56 +0000303 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000304 int size;
305 int c_byte;
306 int used;
plougher76c64082008-03-08 01:32:23 +0000307 int fragment;
ploughereb6eac92008-02-26 01:50:48 +0000308 int error;
309 struct file_buffer *hash_next;
310 struct file_buffer *hash_prev;
311 struct file_buffer *free_next;
312 struct file_buffer *free_prev;
313 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000314 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000315};
316
ploughereb6eac92008-02-26 01:50:48 +0000317
plougher5507dd92006-11-06 00:43:10 +0000318/* struct describing queues used to pass data between threads */
319struct queue {
320 int size;
321 int readp;
322 int writep;
323 pthread_mutex_t mutex;
324 pthread_cond_t empty;
325 pthread_cond_t full;
326 void **data;
327};
328
329/* describes the list of blocks in a file which is a possible
330 duplicate. For each block, it indicates whether the block is
331 in memory or on disk */
332struct buffer_list {
333 long long start;
334 int size;
335 struct file_buffer *read_buffer;
336};
337
ploughereb6eac92008-02-26 01:50:48 +0000338struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougher5507dd92006-11-06 00:43:10 +0000339struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate, *to_frag;
plougher91fbb302008-05-06 02:29:36 +0000340pthread_t *thread, *deflator_thread, *frag_deflator_thread, progress_thread;
plougher5507dd92006-11-06 00:43:10 +0000341pthread_mutex_t fragment_mutex;
342pthread_cond_t fragment_waiting;
343pthread_mutex_t pos_mutex;
plougher35a10602008-04-21 02:58:16 +0000344pthread_mutex_t progress_mutex;
345pthread_cond_t progress_wait;
346int rotate = 0;
plougher5507dd92006-11-06 00:43:10 +0000347
348/* user options that control parallelisation */
349int processors = -1;
350/* default size of output buffer in Mbytes */
351#define WRITER_BUFFER_DEFAULT 512
352/* default size of input buffer in Mbytes */
353#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000354/* default size of fragment buffer in Mbytes */
355#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000356int writer_buffer_size;
357int reader_buffer_size;
plougher76c64082008-03-08 01:32:23 +0000358int fragment_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000359
plougherdf70c3e2006-01-27 09:34:13 +0000360void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type);
plougher1f413c82005-11-18 00:02:14 +0000361extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
362extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
plougherdf70c3e2006-01-27 09:34:13 +0000363 char **data_cache, char **cdirectory_table, char **directory_data_cache,
364 unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
365 unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
366 int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
367 unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
368 long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
369 unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
370 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher0e453652006-11-06 01:49:35 +0000371 squashfs_fragment_entry **fragment_table, squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000372extern int read_sort_file(char *filename, int source, char *source_path[]);
373extern void sort_files_and_write(struct dir_info *dir);
374struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, struct buffer_list *buffer_list, int blocks, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
plougherf9039c92007-10-22 03:54:16 +0000375struct dir_info *dir_scan1(char *, struct pathnames *, int (_readdir)(char *, char *, struct dir_info *));
plougher29e37092007-04-15 01:24:51 +0000376void dir_scan2(squashfs_inode *inode, struct dir_info *dir_info);
plougher5507dd92006-11-06 00:43:10 +0000377struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
378extern void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf);
379extern struct priority_entry *priority_list[65536];
plougher35a10602008-04-21 02:58:16 +0000380void progress_bar(long long current, long long max, int columns);
plougher5507dd92006-11-06 00:43:10 +0000381
382
plougher5507dd92006-11-06 00:43:10 +0000383struct queue *queue_init(int size)
384{
385 struct queue *queue = malloc(sizeof(struct queue));
386
387 if(queue == NULL)
388 return NULL;
389
390 if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
391 free(queue);
392 return NULL;
393 }
394
395 queue->size = size + 1;
396 queue->readp = queue->writep = 0;
397 pthread_mutex_init(&queue->mutex, NULL);
398 pthread_cond_init(&queue->empty, NULL);
399 pthread_cond_init(&queue->full, NULL);
400
401 return queue;
402}
403
404
405void queue_put(struct queue *queue, void *data)
406{
407 int nextp;
408
409 pthread_mutex_lock(&queue->mutex);
410
411 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
412 pthread_cond_wait(&queue->full, &queue->mutex);
413
414 queue->data[queue->writep] = data;
415 queue->writep = nextp;
416 pthread_cond_signal(&queue->empty);
417 pthread_mutex_unlock(&queue->mutex);
418}
419
420
421void *queue_get(struct queue *queue)
422{
423 void *data;
424 pthread_mutex_lock(&queue->mutex);
425
426 while(queue->readp == queue->writep)
427 pthread_cond_wait(&queue->empty, &queue->mutex);
428
429 data = queue->data[queue->readp];
430 queue->readp = (queue->readp + 1) % queue->size;
431 pthread_cond_signal(&queue->full);
432 pthread_mutex_unlock(&queue->mutex);
433
434 return data;
435}
436
plougher1f413c82005-11-18 00:02:14 +0000437
ploughereb6eac92008-02-26 01:50:48 +0000438/* Cache status struct. Caches are used to keep
439 track of memory buffers passed between different threads */
440struct cache {
441 int max_buffers;
442 int count;
443 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000444 pthread_mutex_t mutex;
445 pthread_cond_t wait_for_free;
446 struct file_buffer *free_list;
447 struct file_buffer *hash_table[65536];
448};
449
450
plougher2ea89142008-03-11 01:34:19 +0000451#define INSERT_LIST(NAME, TYPE) \
452void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
453 if(*list) { \
454 entry->NAME##_next = *list; \
455 entry->NAME##_prev = (*list)->NAME##_prev; \
456 (*list)->NAME##_prev->NAME##_next = entry; \
457 (*list)->NAME##_prev = entry; \
458 } else { \
459 *list = entry; \
460 entry->NAME##_prev = entry->NAME##_next = entry; \
461 } \
462}
463
464
465#define REMOVE_LIST(NAME, TYPE) \
466void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
467 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
468 /* only this entry in the list */ \
469 *list = NULL; \
470 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
471 /* more than one entry in the list */ \
472 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
473 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
474 if(*list == entry) \
475 *list = entry->NAME##_next; \
476 } \
477 entry->NAME##_prev = entry->NAME##_next = NULL; \
478}
479
480
481#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000482
483
484/* Called with the cache mutex held */
485void insert_hash_table(struct cache *cache, struct file_buffer *entry)
486{
487 int hash = CALCULATE_HASH(entry->index);
488
489 entry->hash_next = cache->hash_table[hash];
490 cache->hash_table[hash] = entry;
491 entry->hash_prev = NULL;
492 if(entry->hash_next)
493 entry->hash_next->hash_prev = entry;
494}
495
496
497/* Called with the cache mutex held */
498void remove_hash_table(struct cache *cache, struct file_buffer *entry)
499{
500 if(entry->hash_prev)
501 entry->hash_prev->hash_next = entry->hash_next;
502 else
plougher76c64082008-03-08 01:32:23 +0000503 cache->hash_table[CALCULATE_HASH(entry->index)] = entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000504 if(entry->hash_next)
505 entry->hash_next->hash_prev = entry->hash_prev;
506
507 entry->hash_prev = entry->hash_next = NULL;
508}
509
510
511/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000512INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000513
514/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000515REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000516
517
518struct cache *cache_init(int buffer_size, int max_buffers)
519{
520 struct cache *cache = malloc(sizeof(struct cache));
521
522 if(cache == NULL)
523 return NULL;
524
525 cache->max_buffers = max_buffers;
526 cache->buffer_size = buffer_size;
527 cache->count = 0;
528 cache->free_list = NULL;
529 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000530 pthread_mutex_init(&cache->mutex, NULL);
531 pthread_cond_init(&cache->wait_for_free, NULL);
532
533 return cache;
534}
535
536
537struct file_buffer *cache_lookup(struct cache *cache, long long index)
538{
539 /* Lookup block in the cache, if found return with usage count
540 * incremented, if not found return NULL */
541 int hash = CALCULATE_HASH(index);
542 struct file_buffer *entry;
543
544 pthread_mutex_lock(&cache->mutex);
545
546 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
547 if(entry->index == index)
548 break;
549
550 if(entry) {
551 /* found the block in the cache, increment used count and
552 * if necessary remove from free list so it won't disappear
553 */
554 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000555 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000556 }
557
558 pthread_mutex_unlock(&cache->mutex);
559
560 return entry;
561}
562
563
plougher217bad82008-04-05 11:36:41 +0000564#define GET_FREELIST 1
plougher2ea89142008-03-11 01:34:19 +0000565
plougher76c64082008-03-08 01:32:23 +0000566struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000567{
568 /* Get a free block out of the cache indexed on index. */
569 struct file_buffer *entry;
570
571 pthread_mutex_lock(&cache->mutex);
572
plougher76c64082008-03-08 01:32:23 +0000573 while(1) {
574 /* first try to get a block from the free list */
plougher2ea89142008-03-11 01:34:19 +0000575#ifdef GET_FREELIST
plougher76c64082008-03-08 01:32:23 +0000576 if(cache->free_list) {
577 /* a block on the free_list is a "keep" block */
578 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000579 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000580 remove_hash_table(cache, entry);
581 break;
plougher2ea89142008-03-11 01:34:19 +0000582 } else
583#endif
584 if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000585 /* next try to allocate new block */
586 entry = malloc(sizeof(struct file_buffer) + cache->buffer_size);
587 if(entry == NULL)
588 goto failed;
589 entry->cache = cache;
590 entry->free_prev = entry->free_next = NULL;
591 cache->count ++;
592 break;
593 } else
plougher2ea89142008-03-11 01:34:19 +0000594#ifndef GET_FREELIST
595 if(cache->free_list) {
596 /* a block on the free_list is a "keep" block */
597 entry = cache->free_list;
598 remove_free_list(&cache->free_list, entry);
599 remove_hash_table(cache, entry);
600 break;
601 }
602#endif
plougher76c64082008-03-08 01:32:23 +0000603 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000604 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000605 }
606
plougher76c64082008-03-08 01:32:23 +0000607 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000608 entry->used = 1;
609 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000610 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000611 if(keep) {
612 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000613 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000614 }
ploughereb6eac92008-02-26 01:50:48 +0000615 pthread_mutex_unlock(&cache->mutex);
616
617 return entry;
618
619failed:
620 pthread_mutex_unlock(&cache->mutex);
621 return NULL;
622}
623
ploughereb6eac92008-02-26 01:50:48 +0000624
plougher0f464442008-03-31 00:27:56 +0000625void cache_rehash(struct file_buffer *entry, long long index)
626{
627 struct cache *cache = entry->cache;
628
629 pthread_mutex_lock(&cache->mutex);
630 if(entry->keep)
631 remove_hash_table(cache, entry);
632 entry->keep = TRUE;
633 entry->index = index;
634 insert_hash_table(cache, entry);
635 pthread_mutex_unlock(&cache->mutex);
636}
637
638
ploughereb6eac92008-02-26 01:50:48 +0000639void cache_block_put(struct file_buffer *entry)
640{
plougher76c64082008-03-08 01:32:23 +0000641 struct cache *cache;
642
ploughereb6eac92008-02-26 01:50:48 +0000643 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000644 * can be reused and if a keep block put onto the free list. As keep
645 * blocks remain accessible via the hash table they can be found getting a
646 * new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000647
648 if(entry == NULL)
649 return;
650
plougher76c64082008-03-08 01:32:23 +0000651 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000652
plougher76c64082008-03-08 01:32:23 +0000653 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000654
655 entry->used --;
656 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000657 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000658 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000659 else {
660 free(entry);
661 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000662 }
plougher76c64082008-03-08 01:32:23 +0000663
664 /* One or more threads may be waiting on this block */
665 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000666 }
667
plougher76c64082008-03-08 01:32:23 +0000668 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000669}
670
671
plougher1f413c82005-11-18 00:02:14 +0000672#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
673
674
plougher35a10602008-04-21 02:58:16 +0000675inline void inc_progress_bar()
676{
677 cur_uncompressed ++;
678}
679
680
681inline void update_progress_bar()
682{
683 pthread_mutex_lock(&progress_mutex);
684 pthread_cond_signal(&progress_wait);
685 pthread_mutex_unlock(&progress_mutex);
686}
687
688
plougher5507dd92006-11-06 00:43:10 +0000689inline void waitforthread(int i)
690{
691 TRACE("Waiting for thread %d\n", i);
692 while(thread[i] != 0)
693 sched_yield();
694}
695
696
plougher1f413c82005-11-18 00:02:14 +0000697void restorefs()
698{
plougher5507dd92006-11-06 00:43:10 +0000699 int i;
700
plougher02bc3bc2007-02-25 12:12:01 +0000701 if(thread == NULL || thread[0] == 0)
702 return;
703
plougher1f413c82005-11-18 00:02:14 +0000704 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000705
plougher91fbb302008-05-06 02:29:36 +0000706 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000707 if(thread[i])
708 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000709 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000710 waitforthread(i);
711 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000712 bytes = sbytes;
713 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
714 memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
715 inode_bytes = sinode_bytes;
716 directory_bytes = sdirectory_bytes;
717 uid_count = suid_count;
718 guid_count = sguid_count;
719 total_bytes = stotal_bytes;
720 total_inode_bytes = stotal_inode_bytes;
721 total_directory_bytes = stotal_directory_bytes;
722 inode_count = sinode_count;
723 file_count = sfile_count;
724 sym_count = ssym_count;
725 dev_count = sdev_count;
726 dir_count = sdir_count;
727 fifo_count = sfifo_count;
728 sock_count = ssock_count;
729 dup_files = sdup_files;
730 fragments = sfragments;
731 fragment_size = 0;
732 longjmp(env, 1);
733}
734
735
736void sighandler()
737{
plougher5507dd92006-11-06 00:43:10 +0000738 if(++interrupted > 2)
739 return;
740 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000741 restorefs();
742 else {
743 ERROR("Interrupting will restore original filesystem!\n");
744 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000745 }
746}
747
748
plougher324978d2006-02-27 04:53:29 +0000749void sighandler2()
750{
751 EXIT_MKSQUASHFS();
752}
753
754
plougher5507dd92006-11-06 00:43:10 +0000755void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000756{
plougher5507dd92006-11-06 00:43:10 +0000757 int i;
758 sigset_t sigmask;
759 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000760
plougher5507dd92006-11-06 00:43:10 +0000761 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
762 thread[i] = (pthread_t) 0;
763
plougher07966f72007-11-14 10:54:45 +0000764 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000765
766 sigemptyset(&sigmask);
767 sigaddset(&sigmask, SIGINT);
768 sigaddset(&sigmask, SIGQUIT);
769 sigaddset(&sigmask, SIGUSR1);
770 while(1) {
771 sigsuspend(&sigmask);
772 TRACE("After wait in sigusr1_handler :(\n");
773 }
774}
775
776
plougher02bc3bc2007-02-25 12:12:01 +0000777void sigwinch_handler()
778{
779 struct winsize winsize;
780
781 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
782 printf("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n");
783 columns = 80;
784 } else
785 columns = winsize.ws_col;
786}
787
788
plougher35a10602008-04-21 02:58:16 +0000789void sigalrm_handler()
790{
791 rotate = (rotate + 1) % 4;
792}
793
794
plougher5507dd92006-11-06 00:43:10 +0000795unsigned int mangle2(z_stream **strm, char *d, char *s, int size, int block_size, int uncompressed, int data_block)
796{
797 unsigned long c_byte;
798 unsigned int res;
799 z_stream *stream = *strm;
800
801 if(uncompressed)
802 goto notcompressed;
803
804 if(stream == NULL) {
805 if((stream = *strm = malloc(sizeof(z_stream))) == NULL)
806 BAD_ERROR("mangle::compress failed, not enough memory\n");
807
808 stream->zalloc = Z_NULL;
809 stream->zfree = Z_NULL;
810 stream->opaque = 0;
811
812 if((res = deflateInit(stream, 9)) != Z_OK) {
813 if(res == Z_MEM_ERROR)
814 BAD_ERROR("zlib::compress failed, not enough memory\n");
815 else if(res == Z_STREAM_ERROR)
816 BAD_ERROR("zlib::compress failed, not a valid compression level\n");
817 else if(res == Z_VERSION_ERROR)
818 BAD_ERROR("zlib::compress failed, incorrect zlib version\n");
819 else
820 BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
821 }
822 } else if((res = deflateReset(stream)) != Z_OK) {
823 if(res == Z_STREAM_ERROR)
824 BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
plougher1f413c82005-11-18 00:02:14 +0000825 else
826 BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
plougher1f413c82005-11-18 00:02:14 +0000827 }
828
plougher5507dd92006-11-06 00:43:10 +0000829 stream->next_in = (unsigned char *) s;
830 stream->avail_in = size;
831 stream->next_out = (unsigned char *) d;
832 stream->avail_out = block_size;
833
834 res = deflate(stream, Z_FINISH);
835 if(res != Z_STREAM_END && res != Z_OK) {
836 if(res == Z_STREAM_ERROR)
837 BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
838 else if(res == Z_BUF_ERROR)
839 BAD_ERROR("zlib::compress failed, no progress possible\n");
840 else
841 BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
842 }
843
844 c_byte = stream->total_out;
845
846 if(res != Z_STREAM_END || c_byte >= size) {
847notcompressed:
plougher1f413c82005-11-18 00:02:14 +0000848 memcpy(d, s, size);
849 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
850 }
851
852 return (unsigned int) c_byte;
853}
854
855
plougher5507dd92006-11-06 00:43:10 +0000856unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
857{
858 static z_stream *stream = NULL;
859
860 return mangle2(&stream, d, s, size, block_size, uncompressed, data_block);
861}
862
863
plougher1f413c82005-11-18 00:02:14 +0000864squashfs_base_inode_header *get_inode(int req_size)
865{
866 int data_space;
867 unsigned short c_byte;
868
869 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
870 if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
871 if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
872 == NULL) {
873 goto failed;
874 }
875 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
876 }
877
878 c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
879 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000880 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougher1f413c82005-11-18 00:02:14 +0000881 if(!swap)
882 memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
883 else
884 SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
885 if(check_data)
886 *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
887 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
888 total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
889 memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
890 cache_bytes -= SQUASHFS_METADATA_SIZE;
891 }
892
893 data_space = (cache_size - cache_bytes);
894 if(data_space < req_size) {
895 int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
896
897 if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
898 goto failed;
899 }
900 cache_size += realloc_size;
901 }
902
903 cache_bytes += req_size;
904
905 return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
906
907failed:
908 BAD_ERROR("Out of memory in inode table reallocation!\n");
909}
910
911
912void read_bytes(int fd, long long byte, int bytes, char *buff)
913{
914 off_t off = byte;
915
plougher5507dd92006-11-06 00:43:10 +0000916 pthread_mutex_lock(&pos_mutex);
plougher91fbb302008-05-06 02:29:36 +0000917 if(lseek(fd, off, SEEK_SET) == -1)
918 BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
plougher1f413c82005-11-18 00:02:14 +0000919
plougher91fbb302008-05-06 02:29:36 +0000920 if(read(fd, buff, bytes) == -1)
921 BAD_ERROR("Read on destination failed because %s\n", strerror(errno));
plougher5507dd92006-11-06 00:43:10 +0000922 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000923}
924
925
926void write_bytes(int fd, long long byte, int bytes, char *buff)
927{
928 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000929
plougher5507dd92006-11-06 00:43:10 +0000930 if(interrupted < 2)
931 pthread_mutex_lock(&pos_mutex);
932
plougher91fbb302008-05-06 02:29:36 +0000933 if(lseek(fd, off, SEEK_SET) == -1)
934 BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
plougher1f413c82005-11-18 00:02:14 +0000935
plougher91fbb302008-05-06 02:29:36 +0000936 if(write(fd, buff, bytes) == -1)
937 BAD_ERROR("Write on destination failed because %s\n", strerror(errno));
plougher5507dd92006-11-06 00:43:10 +0000938
939 if(interrupted < 2)
940 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000941}
942
943
944long long write_inodes()
945{
946 unsigned short c_byte;
947 int avail_bytes;
948 char *datap = data_cache;
949 long long start_bytes = bytes;
950
951 while(cache_bytes) {
952 if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
953 if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
954 BAD_ERROR("Out of memory in inode table reallocation!\n");
955 }
956 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
957 }
958 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
959 c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000960 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougher1f413c82005-11-18 00:02:14 +0000961 if(!swap)
962 memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
963 else
964 SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
965 if(check_data)
966 *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
967 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
968 total_inode_bytes += avail_bytes + block_offset;
969 datap += avail_bytes;
970 cache_bytes -= avail_bytes;
971 }
972
973 write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
974 bytes += inode_bytes;
975
976 return start_bytes;
977}
978
979
980long long write_directories()
981{
982 unsigned short c_byte;
983 int avail_bytes;
984 char *directoryp = directory_data_cache;
985 long long start_bytes = bytes;
986
987 while(directory_cache_bytes) {
988 if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
989 if((directory_table = (char *) realloc(directory_table, directory_size +
990 ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
991 BAD_ERROR("Out of memory in directory table reallocation!\n");
992 }
993 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
994 }
995 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
996 c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000997 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
plougher1f413c82005-11-18 00:02:14 +0000998 if(!swap)
999 memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
1000 else
1001 SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
1002 if(check_data)
1003 *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
1004 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
1005 total_directory_bytes += avail_bytes + block_offset;
1006 directoryp += avail_bytes;
1007 directory_cache_bytes -= avail_bytes;
1008 }
1009 write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
1010 bytes += directory_bytes;
1011
1012 return start_bytes;
1013}
1014
1015
1016unsigned int get_uid(squashfs_uid uid)
1017{
1018 int i;
1019
1020 for(i = 0; (i < uid_count) && uids[i] != uid; i++);
1021 if(i == uid_count) {
1022 if(uid_count == SQUASHFS_UIDS) {
1023 ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
1024 i = 0;
1025 } else
1026 uids[uid_count++] = uid;
1027 }
1028
1029 return i;
1030}
1031
1032
1033unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
1034{
1035 int i;
1036
1037 if(uid == guid)
1038 return SQUASHFS_GUIDS;
1039
1040 for(i = 0; (i < guid_count) && guids[i] != guid; i++);
1041 if(i == guid_count) {
1042 if(guid_count == SQUASHFS_GUIDS) {
1043 ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
1044 return SQUASHFS_GUIDS;
1045 } else
1046 guids[guid_count++] = guid;
1047 }
1048
1049 return i;
1050}
1051
1052
plougher751d4972005-12-21 04:23:40 +00001053int create_inode(squashfs_inode *i_no, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in)
plougher1f413c82005-11-18 00:02:14 +00001054{
1055 struct stat *buf = &dir_ent->inode->buf;
1056 squashfs_inode_header inode_header;
1057 squashfs_base_inode_header *inode, *base = &inode_header.base;
1058 char *filename = dir_ent->pathname;
1059 int nlink = dir_ent->inode->nlink;
1060 int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
1061
1062 base->mode = SQUASHFS_MODE(buf->st_mode);
1063 base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid);
1064 base->inode_type = type;
1065 base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid);
1066 base->mtime = buf->st_mtime;
1067 base->inode_number = inode_number;
1068
1069 if(type == SQUASHFS_FILE_TYPE) {
1070 int i;
1071 squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
1072
1073 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
1074 inodep = (squashfs_reg_inode_header *) inode;
plougher1f413c82005-11-18 00:02:14 +00001075 reg->file_size = byte_size;
1076 reg->start_block = start_block;
1077 reg->fragment = fragment->index;
1078 reg->offset = fragment->offset;
1079 if(!swap) {
1080 memcpy(inodep, reg, sizeof(*reg));
1081 memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
1082 } else {
1083 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
1084 SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
1085 }
rlougher8f7d0b82007-11-08 15:33:29 +00001086 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d\n", byte_size,
plougher1f413c82005-11-18 00:02:14 +00001087 start_block, offset, fragment->index, fragment->offset, fragment->size);
1088 for(i = 0; i < offset; i++)
1089 TRACE("Block %d, size %d\n", i, block_list[i]);
1090 }
1091 else if(type == SQUASHFS_LREG_TYPE) {
1092 int i;
1093 squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep;
1094
1095 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
1096 inodep = (squashfs_lreg_inode_header *) inode;
plougher1f413c82005-11-18 00:02:14 +00001097 reg->nlink = nlink;
1098 reg->file_size = byte_size;
1099 reg->start_block = start_block;
1100 reg->fragment = fragment->index;
1101 reg->offset = fragment->offset;
1102 if(!swap) {
1103 memcpy(inodep, reg, sizeof(*reg));
1104 memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
1105 } else {
1106 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep);
1107 SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
1108 }
rlougher8f7d0b82007-11-08 15:33:29 +00001109 TRACE("Long file inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size,
plougher1f413c82005-11-18 00:02:14 +00001110 start_block, offset, fragment->index, fragment->offset, fragment->size, nlink);
1111 for(i = 0; i < offset; i++)
1112 TRACE("Block %d, size %d\n", i, block_list[i]);
1113 }
1114 else if(type == SQUASHFS_LDIR_TYPE) {
1115 int i;
1116 unsigned char *p;
1117 squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep;
1118 struct cached_dir_index *index = dir_in->index;
1119 unsigned int i_count = dir_in->i_count;
1120 unsigned int i_size = dir_in->i_size;
1121
1122 if(byte_size >= 1 << 27)
1123 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1124
1125 inode = get_inode(sizeof(*dir) + i_size);
1126 inodep = (squashfs_ldir_inode_header *) inode;
1127 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001128 dir->nlink = dir_ent->dir->directory_count + 2;
1129 dir->file_size = byte_size;
1130 dir->offset = offset;
1131 dir->start_block = start_block;
1132 dir->i_count = i_count;
1133 dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
1134
1135 if(!swap)
1136 memcpy(inode, dir, sizeof(*dir));
1137 else
1138 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
1139 p = (unsigned char *) inodep->index;
1140 for(i = 0; i < i_count; i++) {
1141 if(!swap)
1142 memcpy(p, &index[i].index, sizeof(squashfs_dir_index));
1143 else
1144 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
1145 memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1);
1146 p += sizeof(squashfs_dir_index) + index[i].index.size + 1;
1147 }
rlougher8f7d0b82007-11-08 15:33:29 +00001148 TRACE("Long directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
plougher1f413c82005-11-18 00:02:14 +00001149 start_block, offset, dir_ent->dir->directory_count + 2);
1150 }
1151 else if(type == SQUASHFS_DIR_TYPE) {
1152 squashfs_dir_inode_header *dir = &inode_header.dir;
1153
1154 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001155 dir->nlink = dir_ent->dir->directory_count + 2;
1156 dir->file_size = byte_size;
1157 dir->offset = offset;
1158 dir->start_block = start_block;
1159 dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
1160 if(!swap)
1161 memcpy(inode, dir, sizeof(*dir));
1162 else
1163 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001164 TRACE("Directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
plougher1f413c82005-11-18 00:02:14 +00001165 start_block, offset, dir_ent->dir->directory_count + 2);
1166 }
1167 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
1168 squashfs_dev_inode_header *dev = &inode_header.dev;
1169
1170 inode = get_inode(sizeof(*dev));
1171 dev->nlink = nlink;
1172 dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) |
1173 (minor(buf->st_rdev) & 0xff));
1174 if(!swap)
1175 memcpy(inode, dev, sizeof(*dev));
1176 else
1177 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001178 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001179 }
1180 else if(type == SQUASHFS_SYMLINK_TYPE) {
1181 squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
1182 int byte;
1183 char buff[65536];
1184
1185 if((byte = readlink(filename, buff, 65536)) == -1) {
rlougher8f7d0b82007-11-08 15:33:29 +00001186 ERROR("Failed to read symlink %s, creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001187 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001188 }
1189
1190 if(byte == 65536) {
rlougher8f7d0b82007-11-08 15:33:29 +00001191 ERROR("Symlink %s is greater than 65536 bytes! Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001192 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001193 }
1194
1195 inode = get_inode(sizeof(*symlink) + byte);
1196 symlink->nlink = nlink;
1197 inodep = (squashfs_symlink_inode_header *) inode;
1198 symlink->symlink_size = byte;
1199 if(!swap)
1200 memcpy(inode, symlink, sizeof(*symlink));
1201 else
1202 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1203 strncpy(inodep->symlink, buff, byte);
1204 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink);
1205 }
1206 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
1207 squashfs_ipc_inode_header *ipc = &inode_header.ipc;
1208
1209 inode = get_inode(sizeof(*ipc));
1210 ipc->nlink = nlink;
1211 if(!swap)
1212 memcpy(inode, ipc, sizeof(*ipc));
1213 else
1214 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
1215 TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
1216 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001217 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001218
1219 *i_no = MKINODE(inode);
1220 inode_count ++;
1221
1222 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid);
1223
1224 return TRUE;
1225}
1226
1227
1228void scan2_init_dir(struct directory *dir)
1229{
plougher8cb05cd2005-12-11 23:32:35 +00001230 if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001231 BAD_ERROR("Out of memory allocating directory buffer\n");
1232 }
1233
1234 dir->size = SQUASHFS_METADATA_SIZE;
1235 dir->p = dir->index_count_p = dir->buff;
1236 dir->entry_count = 256;
1237 dir->entry_count_p = NULL;
1238 dir->index = NULL;
1239 dir->i_count = dir->i_size = 0;
1240}
1241
1242
1243void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir)
1244{
plougher8cb05cd2005-12-11 23:32:35 +00001245 unsigned char *buff;
plougher1f413c82005-11-18 00:02:14 +00001246 squashfs_dir_entry idir, *idirp;
1247 unsigned int start_block = inode >> 16;
1248 unsigned int offset = inode & 0xffff;
1249 unsigned int size;
1250
1251 if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
1252 size = SQUASHFS_NAME_LEN;
1253 ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
1254 }
1255
1256 if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
plougher8cb05cd2005-12-11 23:32:35 +00001257 if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001258 BAD_ERROR("Out of memory reallocating directory buffer\n");
1259 }
1260
1261 dir->p = (dir->p - dir->buff) + buff;
1262 if(dir->entry_count_p)
1263 dir->entry_count_p = (dir->entry_count_p - dir->buff + buff);
1264 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1265 dir->buff = buff;
1266 }
1267
1268 if(dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long) inode_number - dir->inode_number) > 32767 || ((long long) inode_number - dir->inode_number) < - 32768) {
1269 if(dir->entry_count_p) {
1270 squashfs_dir_header dir_header;
1271
1272 if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) {
1273 if(dir->i_count % I_COUNT_SIZE == 0)
1274 if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL)
1275 BAD_ERROR("Out of memory in directory index table reallocation!\n");
1276 dir->index[dir->i_count].index.index = dir->p - dir->buff;
1277 dir->index[dir->i_count].index.size = size - 1;
1278 dir->index[dir->i_count++].name = name;
1279 dir->i_size += sizeof(squashfs_dir_index) + size;
1280 dir->index_count_p = dir->p;
1281 }
1282
1283 dir_header.count = dir->entry_count - 1;
1284 dir_header.start_block = dir->start_block;
1285 dir_header.inode_number = dir->inode_number;
1286 if(!swap)
1287 memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
1288 else
1289 SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
1290
1291 }
1292
1293
1294 dir->entry_count_p = dir->p;
1295 dir->start_block = start_block;
1296 dir->entry_count = 0;
1297 dir->inode_number = inode_number;
1298 dir->p += sizeof(squashfs_dir_header);
1299 }
1300
1301 idirp = (squashfs_dir_entry *) dir->p;
1302 idir.offset = offset;
1303 idir.type = type;
1304 idir.size = size - 1;
1305 idir.inode_number = ((long long) inode_number - dir->inode_number);
1306 if(!swap)
1307 memcpy(idirp, &idir, sizeof(idir));
1308 else
1309 SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
1310 strncpy(idirp->name, name, size);
1311 dir->p += sizeof(squashfs_dir_entry) + size;
1312 dir->entry_count ++;
1313}
1314
1315
plougher29e37092007-04-15 01:24:51 +00001316void write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001317{
1318 unsigned int dir_size = dir->p - dir->buff;
1319 int data_space = (directory_cache_size - directory_cache_bytes);
1320 unsigned int directory_block, directory_offset, i_count, index;
1321 unsigned short c_byte;
1322
1323 if(data_space < dir_size) {
1324 int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
1325
1326 if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
1327 goto failed;
1328 }
1329 directory_cache_size += realloc_size;
1330 }
1331
1332 if(dir_size) {
1333 squashfs_dir_header dir_header;
1334
1335 dir_header.count = dir->entry_count - 1;
1336 dir_header.start_block = dir->start_block;
1337 dir_header.inode_number = dir->inode_number;
1338 if(!swap)
1339 memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
1340 else
1341 SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
1342 memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
1343 }
1344 directory_offset = directory_cache_bytes;
1345 directory_block = directory_bytes;
1346 directory_cache_bytes += dir_size;
1347 i_count = 0;
1348 index = SQUASHFS_METADATA_SIZE - directory_offset;
1349
1350 while(1) {
1351 while(i_count < dir->i_count && dir->index[i_count].index.index < index)
1352 dir->index[i_count++].index.start_block = directory_bytes;
1353 index += SQUASHFS_METADATA_SIZE;
1354
1355 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1356 break;
1357
1358 if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
1359 if((directory_table = (char *) realloc(directory_table,
1360 directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
1361 goto failed;
1362 }
1363 directory_size += SQUASHFS_METADATA_SIZE << 1;
1364 }
1365
1366 c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
1367 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001368 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
plougher1f413c82005-11-18 00:02:14 +00001369 if(!swap)
1370 memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
1371 else
1372 SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
1373 if(check_data)
1374 *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
1375 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
1376 total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
1377 memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
1378 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1379 }
1380
plougher29e37092007-04-15 01:24:51 +00001381 if(dir_info->dir_is_ldir)
1382 create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir);
1383 else
1384 create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00001385
1386#ifdef SQUASHFS_TRACE
1387 if(!swap) {
1388 unsigned char *dirp;
1389 int count;
1390
1391 TRACE("Directory contents of inode 0x%llx\n", *inode);
1392 dirp = dir->buff;
1393 while(dirp < dir->p) {
1394 char buffer[SQUASHFS_NAME_LEN + 1];
1395 squashfs_dir_entry idir, *idirp;
1396 squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
1397 count = dirh->count + 1;
1398 dirp += sizeof(squashfs_dir_header);
1399
1400 TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
1401
1402 while(count--) {
1403 idirp = (squashfs_dir_entry *) dirp;
1404 memcpy((char *) &idir, (char *) idirp, sizeof(idir));
1405 strncpy(buffer, idirp->name, idir.size + 1);
1406 buffer[idir.size + 1] = '\0';
1407 TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
1408 idir.offset, idir.type);
1409 dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
1410 }
1411 }
1412 }
1413#endif
1414 dir_count ++;
1415
plougher29e37092007-04-15 01:24:51 +00001416 return;
plougher1f413c82005-11-18 00:02:14 +00001417
1418failed:
1419 BAD_ERROR("Out of memory in directory table reallocation!\n");
1420}
1421
1422
plougher76c64082008-03-08 01:32:23 +00001423struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001424{
plougher5507dd92006-11-06 00:43:10 +00001425 squashfs_fragment_entry *disk_fragment;
1426 int size;
plougher76c64082008-03-08 01:32:23 +00001427 long long start_block;
1428 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001429
plougher76c64082008-03-08 01:32:23 +00001430 if(fragment->index == SQUASHFS_INVALID_FRAG)
1431 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001432
plougher76c64082008-03-08 01:32:23 +00001433 buffer = cache_lookup(fragment_buffer, fragment->index);
1434 if(buffer) {
1435 //printf("get_fragment, fragment->index %d, buffer->index %lld, fragments %d\n", fragment->index, buffer->index, fragments);
1436 return buffer;
1437 }
1438
1439 compressed_buffer = cache_lookup(writer_buffer, fragment->index + FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001440
plougher76c64082008-03-08 01:32:23 +00001441#if 0
1442 if(compressed_buffer)
plougher2ea89142008-03-11 01:34:19 +00001443 //printf("get_fragment, fragment->index %d, compressed_buffer->index %lld\n", fragment->index, compressed_buffer->index - FRAG_INDEX);
plougher76c64082008-03-08 01:32:23 +00001444 else
plougher2ea89142008-03-11 01:34:19 +00001445 //printf("get_fragment, fragment->index %d, not in writer_buffer\n", fragment->index);
plougher76c64082008-03-08 01:32:23 +00001446#endif
plougher2ea89142008-03-11 01:34:19 +00001447
plougher76c64082008-03-08 01:32:23 +00001448 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001449
1450 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001451 disk_fragment = &fragment_table[fragment->index];
1452 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001453 start_block = disk_fragment->start_block;
1454 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001455
plougher0f464442008-03-31 00:27:56 +00001456 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1f413c82005-11-18 00:02:14 +00001457 int res;
plougher8cb05cd2005-12-11 23:32:35 +00001458 unsigned long bytes = block_size;
plougher76c64082008-03-08 01:32:23 +00001459 char *data;
plougher1f413c82005-11-18 00:02:14 +00001460 char cbuffer[block_size];
1461
plougher76c64082008-03-08 01:32:23 +00001462 if(compressed_buffer)
1463 data = compressed_buffer->data;
1464 else {
1465 data = cbuffer;
1466 read_bytes(fd, start_block, size, data);
1467 }
plougher1f413c82005-11-18 00:02:14 +00001468
plougher76c64082008-03-08 01:32:23 +00001469 if((res = uncompress((unsigned char *) buffer->data, &bytes, (const unsigned char *) data, size)) != Z_OK) {
plougher1f413c82005-11-18 00:02:14 +00001470 if(res == Z_MEM_ERROR)
1471 BAD_ERROR("zlib::uncompress failed, not enough memory\n");
1472 else if(res == Z_BUF_ERROR)
1473 BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n");
1474 else
1475 BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res);
1476 }
plougher76c64082008-03-08 01:32:23 +00001477 } else if(compressed_buffer)
1478 memcpy(buffer->data, compressed_buffer->data, size);
1479 else
1480 read_bytes(fd, start_block, size, buffer->data);
plougher1f413c82005-11-18 00:02:14 +00001481
plougher76c64082008-03-08 01:32:23 +00001482 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001483}
1484
plougher2ea89142008-03-11 01:34:19 +00001485
1486struct frag_locked {
1487 struct file_buffer *buffer;
1488 int c_byte;
1489 int fragment;
1490 struct frag_locked *fragment_prev;
1491 struct frag_locked *fragment_next;
1492};
1493
1494int fragments_locked = FALSE;
1495struct frag_locked *frag_locked_list = NULL;
1496
1497INSERT_LIST(fragment, struct frag_locked)
1498REMOVE_LIST(fragment, struct frag_locked)
1499
plougher4e8484a2008-03-15 23:30:16 +00001500int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001501{
plougher4e8484a2008-03-15 23:30:16 +00001502 int count;
plougher5507dd92006-11-06 00:43:10 +00001503 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001504 //printf("lock_fragments: fragments_outstanding %d\n", fragments_outstanding);
1505 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001506 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001507 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001508 return count;
plougher2ea89142008-03-11 01:34:19 +00001509}
1510
1511
1512void unlock_fragments()
1513{
1514 struct frag_locked *entry;
1515 int compressed_size;
1516
1517 pthread_mutex_lock(&fragment_mutex);
1518 while(frag_locked_list) {
1519 entry = frag_locked_list;
1520 remove_fragment_list(&frag_locked_list, entry);
1521 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1522 fragment_table[entry->fragment].size = entry->c_byte;
1523 fragment_table[entry->fragment].start_block = bytes;
1524 entry->buffer->block = bytes;
1525 bytes += compressed_size;
1526 fragments_outstanding --;
1527 pthread_mutex_unlock(&fragment_mutex);
1528 queue_put(to_writer, entry->buffer);
1529 pthread_mutex_lock(&fragment_mutex);
1530 TRACE("fragment_locked writing fragment %d, compressed size %d\n", entry->fragment, compressed_size);
1531 free(entry);
1532 }
1533 fragments_locked = FALSE;
1534 pthread_mutex_unlock(&fragment_mutex);
1535}
1536
1537
1538int add_pending_fragment(struct file_buffer *write_buffer, int c_byte, int fragment)
1539{
1540 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1541 if(entry == NULL)
1542 return FALSE;
1543 entry->buffer = write_buffer;
1544 entry->c_byte = c_byte;
1545 entry->fragment = fragment;
1546 entry->fragment_prev = entry->fragment_next = NULL;
1547 pthread_mutex_lock(&fragment_mutex);
1548 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001549 pthread_mutex_unlock(&fragment_mutex);
1550}
1551
1552
plougher1f413c82005-11-18 00:02:14 +00001553void write_fragment()
1554{
plougher1f413c82005-11-18 00:02:14 +00001555 if(fragment_size == 0)
1556 return;
1557
plougher5507dd92006-11-06 00:43:10 +00001558 pthread_mutex_lock(&fragment_mutex);
1559 if(fragments % FRAG_SIZE == 0) {
1560 if((fragment_table = (squashfs_fragment_entry *) realloc(fragment_table, (fragments + FRAG_SIZE) * sizeof(squashfs_fragment_entry))) == NULL) {
1561 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001562 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001563 }
1564 }
1565 fragment_data->size = fragment_size;
1566 fragment_data->block = fragments;
plougher2ea89142008-03-11 01:34:19 +00001567 fragment_table[fragments].unused = 0;
plougher5507dd92006-11-06 00:43:10 +00001568 fragments_outstanding ++;
1569 queue_put(to_frag, fragment_data);
plougher1f413c82005-11-18 00:02:14 +00001570 fragments ++;
1571 fragment_size = 0;
plougher5507dd92006-11-06 00:43:10 +00001572 pthread_mutex_unlock(&fragment_mutex);
1573}
1574
ploughereb6eac92008-02-26 01:50:48 +00001575
plougher1f413c82005-11-18 00:02:14 +00001576static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
plougher5507dd92006-11-06 00:43:10 +00001577struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer)
plougher1f413c82005-11-18 00:02:14 +00001578{
1579 struct fragment *ffrg;
plougher5507dd92006-11-06 00:43:10 +00001580
plougher1f413c82005-11-18 00:02:14 +00001581
plougher5507dd92006-11-06 00:43:10 +00001582 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001583 return &empty_fragment;
1584
plougher5507dd92006-11-06 00:43:10 +00001585 if(fragment_size + file_buffer->size > block_size)
plougher1f413c82005-11-18 00:02:14 +00001586 write_fragment();
1587
1588 if((ffrg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
1589 BAD_ERROR("Out of memory in fragment block allocation!\n");
1590
plougher5507dd92006-11-06 00:43:10 +00001591 if(fragment_size == 0)
plougher76c64082008-03-08 01:32:23 +00001592 fragment_data = cache_get(fragment_buffer, fragments, 1);
plougher5507dd92006-11-06 00:43:10 +00001593
plougher1f413c82005-11-18 00:02:14 +00001594 ffrg->index = fragments;
1595 ffrg->offset = fragment_size;
plougher5507dd92006-11-06 00:43:10 +00001596 ffrg->size = file_buffer->size;
1597 memcpy(fragment_data->data + fragment_size, file_buffer->data, file_buffer->size);
1598 fragment_size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001599
1600 return ffrg;
1601}
1602
1603
plougher0e453652006-11-06 01:49:35 +00001604long long generic_write_table(int length, char *buffer, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001605{
plougher0e453652006-11-06 01:49:35 +00001606 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE;
1607 long long list[meta_blocks], start_bytes;
plougherbadfac62007-11-12 03:29:41 +00001608 int compressed_size, i;
plougher1f413c82005-11-18 00:02:14 +00001609 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001610 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1611
1612 long long obytes = bytes;
plougher1f413c82005-11-18 00:02:14 +00001613
1614 for(i = 0; i < meta_blocks; i++) {
plougher0e453652006-11-06 01:49:35 +00001615 int avail_bytes = length > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : length;
1616 c_byte = mangle(cbuffer + block_offset, buffer + i * SQUASHFS_METADATA_SIZE , avail_bytes, SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougher1f413c82005-11-18 00:02:14 +00001617 if(!swap)
1618 memcpy(cbuffer, &c_byte, sizeof(unsigned short));
1619 else
1620 SQUASHFS_SWAP_SHORTS((&c_byte), cbuffer, 1);
1621 if(check_data)
1622 *((unsigned char *)(cbuffer + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
1623 list[i] = bytes;
1624 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
plougher0e453652006-11-06 01:49:35 +00001625 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes, compressed_size);
plougher1f413c82005-11-18 00:02:14 +00001626 write_bytes(fd, bytes, compressed_size, cbuffer);
1627 bytes += compressed_size;
plougher0e453652006-11-06 01:49:35 +00001628 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001629 }
1630
1631 if(!swap)
1632 write_bytes(fd, bytes, sizeof(list), (char *) list);
1633 else {
plougher0e453652006-11-06 01:49:35 +00001634 long long slist[meta_blocks];
1635 SQUASHFS_SWAP_LONG_LONGS(list, slist, meta_blocks);
plougher1f413c82005-11-18 00:02:14 +00001636 write_bytes(fd, bytes, sizeof(list), (char *) slist);
1637 }
1638
1639 start_bytes = bytes;
1640 bytes += sizeof(list);
1641
plougher0e453652006-11-06 01:49:35 +00001642 TRACE("total uncompressed %d compressed %lld\n", inode_count * sizeof(squashfs_inode), bytes - obytes);
1643
plougher1f413c82005-11-18 00:02:14 +00001644 return start_bytes;
1645}
1646
1647
plougher0e453652006-11-06 01:49:35 +00001648long long write_fragment_table()
1649{
1650 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
1651 char buffer[frag_bytes];
1652 squashfs_fragment_entry *p = (squashfs_fragment_entry *) buffer;
1653 int i;
1654
1655 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments, frag_bytes);
1656 for(i = 0; i < fragments; i++, p++) {
rlougher8f7d0b82007-11-08 15:33:29 +00001657 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size);
plougher0e453652006-11-06 01:49:35 +00001658 if(!swap)
1659 memcpy(p, &fragment_table[i], sizeof(squashfs_fragment_entry));
1660 else
1661 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p);
1662 }
1663
1664 return generic_write_table(frag_bytes, buffer, noF);
1665}
1666
1667
plougher1f413c82005-11-18 00:02:14 +00001668char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001669char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001670{
plougher5507dd92006-11-06 00:43:10 +00001671 read_bytes(fd, start, avail_bytes, read_from_file_buffer);
plougher1f413c82005-11-18 00:02:14 +00001672 return read_from_file_buffer;
1673}
1674
1675
1676/*
1677 * Compute 16 bit BSD checksum over the data
1678 */
plougher5507dd92006-11-06 00:43:10 +00001679unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00001680{
plougher5507dd92006-11-06 00:43:10 +00001681 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00001682
plougher5507dd92006-11-06 00:43:10 +00001683 while(bytes --) {
1684 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1685 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00001686 }
1687
1688 return chksum;
1689}
1690
1691
plougher57e6d182008-05-06 23:51:29 +00001692unsigned short get_checksum_disk(long long start, long long l, unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00001693{
1694 unsigned short chksum = 0;
1695 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00001696 struct file_buffer *write_buffer;
1697 int i;
plougher5507dd92006-11-06 00:43:10 +00001698
plougher57e6d182008-05-06 23:51:29 +00001699 for(i = 0; l; i++) {
1700 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
1701 if(bytes == 0) /* sparse block */
1702 continue;
1703 write_buffer = cache_lookup(writer_buffer, start);
1704 if(write_buffer) {
1705 chksum = get_checksum(write_buffer->data, bytes, chksum);
1706 cache_block_put(write_buffer);
1707 } else
1708 chksum = get_checksum(read_from_disk(start, bytes), bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00001709 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00001710 start += bytes;
1711 }
1712
1713 return chksum;
1714}
1715
1716
1717unsigned short get_checksum_buffer(struct buffer_list *buffer_list, unsigned int blocks)
1718{
1719 unsigned short chksum = 0;
1720 int block;
1721
1722 for(block = 0; block < blocks; block ++) {
1723 struct buffer_list *b = &buffer_list[block];
1724
1725 if(b->read_buffer)
1726 chksum = get_checksum(b->read_buffer->data, b->read_buffer->size, chksum);
plougherfbf9f752007-08-12 05:02:24 +00001727 else if(b->size != 0)
plougher5507dd92006-11-06 00:43:10 +00001728 chksum = get_checksum(read_from_disk(b->start, b->size), b->size, chksum);
1729 }
1730
1731 return chksum;
1732}
1733
1734
1735unsigned short get_checksum_mem(char *buff, int bytes)
1736{
1737 return get_checksum(buff, bytes, 0);
1738}
1739
1740
1741unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
1742{
1743 if(file_buffer == NULL)
1744 return 0;
1745 else
1746 return get_checksum(file_buffer->data, file_buffer->size, 0);
1747}
1748
1749
plougher5507dd92006-11-06 00:43:10 +00001750#define DUP_HASH(a) (a & 0xffff)
1751void add_file(long long start, long long file_size, long long file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00001752{
1753 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00001754 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00001755 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00001756
plougher5507dd92006-11-06 00:43:10 +00001757 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00001758 return;
1759
plougher5507dd92006-11-06 00:43:10 +00001760 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
1761 if(file_size != dupl_ptr->file_size)
1762 continue;
1763 if(blocks != 0 && start != dupl_ptr->start)
1764 continue;
1765 if(fragment != dupl_ptr->fragment->index)
1766 continue;
1767 if(fragment != SQUASHFS_INVALID_FRAG && (offset != dupl_ptr->fragment->offset || bytes != dupl_ptr->fragment->size))
1768 continue;
1769 return;
1770 }
1771
plougher1f413c82005-11-18 00:02:14 +00001772 if((frg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
1773 BAD_ERROR("Out of memory in fragment block allocation!\n");
1774
1775 frg->index = fragment;
1776 frg->offset = offset;
1777 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00001778
plougher5507dd92006-11-06 00:43:10 +00001779 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
1780}
plougher1f413c82005-11-18 00:02:14 +00001781
plougher1f413c82005-11-18 00:02:14 +00001782
plougher5507dd92006-11-06 00:43:10 +00001783int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00001784{
plougher5507dd92006-11-06 00:43:10 +00001785 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00001786
1787 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00001788 if(dupl_ptr->file_size == file_size)
1789 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00001790
plougher5507dd92006-11-06 00:43:10 +00001791 return FALSE;
1792}
1793
1794
1795int pre_duplicate_frag(long long file_size, unsigned short checksum)
1796{
1797 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
1798
1799 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
1800 if(dupl_ptr->file_size == file_size) {
1801 if(dupl_ptr->checksum_flag == FALSE) {
plougher76c64082008-03-08 01:32:23 +00001802 struct file_buffer *frag_buffer = get_fragment(dupl_ptr->fragment);
plougher57e6d182008-05-06 23:51:29 +00001803 dupl_ptr->checksum = get_checksum_disk(dupl_ptr->start, dupl_ptr->bytes, dupl_ptr->block_list);
plougher76c64082008-03-08 01:32:23 +00001804 dupl_ptr->fragment_checksum = get_checksum_mem(frag_buffer->data + dupl_ptr->fragment->offset, file_size);
1805 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00001806 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00001807 }
plougher5507dd92006-11-06 00:43:10 +00001808 if(dupl_ptr->fragment_checksum == checksum)
1809 return TRUE;
1810 }
plougher1f413c82005-11-18 00:02:14 +00001811
plougher5507dd92006-11-06 00:43:10 +00001812 return FALSE;
1813}
1814
1815
1816struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag)
1817{
1818 struct file_info *dupl_ptr;
1819
1820 if((dupl_ptr = (struct file_info *) malloc(sizeof(struct file_info))) == NULL) {
1821 BAD_ERROR("Out of memory in dup_files allocation!\n");
1822 }
1823
1824 dupl_ptr->file_size = file_size;
1825 dupl_ptr->bytes = bytes;
1826 dupl_ptr->block_list = block_list;
1827 dupl_ptr->start = start;
1828 dupl_ptr->fragment = fragment;
1829 dupl_ptr->checksum = checksum;
1830 dupl_ptr->fragment_checksum = fragment_checksum;
1831 dupl_ptr->checksum_flag = checksum_flag;
1832 dupl_ptr->next = dupl[DUP_HASH(file_size)];
1833 dupl[DUP_HASH(file_size)] = dupl_ptr;
1834 dup_files ++;
1835
1836 return dupl_ptr;
1837}
1838
1839
plougher4c99cb72007-06-14 21:46:31 +00001840char buffer2[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001841struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, struct buffer_list *buffer_list, int blocks, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag)
1842{
1843 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
1844 int frag_bytes = file_buffer ? file_buffer->size : 0;
1845
1846 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
1847 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00001848 long long dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00001849 int block;
1850
plougher7354cb72007-11-26 02:16:45 +00001851 if(memcmp(*block_list, dupl_ptr->block_list, blocks * sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00001852 continue;
1853
plougher5507dd92006-11-06 00:43:10 +00001854 if(checksum_flag == FALSE) {
1855 checksum = get_checksum_buffer(buffer_list, blocks);
1856 fragment_checksum = get_checksum_mem_buffer(file_buffer);
1857 checksum_flag = TRUE;
1858 }
1859
1860 if(dupl_ptr->checksum_flag == FALSE) {
plougher76c64082008-03-08 01:32:23 +00001861 struct file_buffer *frag_buffer = get_fragment(dupl_ptr->fragment);
plougher57e6d182008-05-06 23:51:29 +00001862 dupl_ptr->checksum = get_checksum_disk(dupl_ptr->start, dupl_ptr->bytes, dupl_ptr->block_list);
plougher76c64082008-03-08 01:32:23 +00001863 dupl_ptr->fragment_checksum = get_checksum_mem(frag_buffer->data + dupl_ptr->fragment->offset, frag_bytes);
1864 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00001865 dupl_ptr->checksum_flag = TRUE;
1866 }
1867
1868 if(checksum != dupl_ptr->checksum || fragment_checksum != dupl_ptr->fragment_checksum)
1869 continue;
1870
1871 for(block = 0; block < blocks; block ++) {
1872 struct buffer_list *b = &buffer_list[block];
plougher0f464442008-03-31 00:27:56 +00001873 struct file_buffer *write_buffer;
1874 char *buffer, *data;
1875 int res;
plougher5507dd92006-11-06 00:43:10 +00001876
1877 if(b->read_buffer)
1878 buffer = b->read_buffer->data;
plougherfbf9f752007-08-12 05:02:24 +00001879 else if(b->size)
plougher5507dd92006-11-06 00:43:10 +00001880 buffer = read_from_disk(b->start, b->size);
plougherfbf9f752007-08-12 05:02:24 +00001881 else
1882 continue;
plougher5507dd92006-11-06 00:43:10 +00001883
plougher0f464442008-03-31 00:27:56 +00001884 write_buffer = cache_lookup(writer_buffer, dup_start);
1885 if(write_buffer)
1886 data = write_buffer->data;
1887 else {
1888 read_bytes(fd, dup_start, b->size, buffer2);
1889 data = buffer2;
1890 }
1891 res = memcmp(buffer, data, b->size);
1892 if(write_buffer)
1893 cache_block_put(write_buffer);
1894 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00001895 break;
1896 dup_start += b->size;
1897 }
1898 if(block == blocks) {
plougher76c64082008-03-08 01:32:23 +00001899 struct file_buffer *frag_buffer = get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00001900
plougher76c64082008-03-08 01:32:23 +00001901 if(frag_bytes == 0 || memcmp(file_buffer->data, frag_buffer->data + dupl_ptr->fragment->offset, frag_bytes) == 0) {
plougherf9c72b12006-01-23 13:52:40 +00001902 TRACE("Found duplicate file, start 0x%llx, size %lld, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start,
plougher1f413c82005-11-18 00:02:14 +00001903 dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum);
1904 *block_list = dupl_ptr->block_list;
1905 *start = dupl_ptr->start;
1906 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00001907 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00001908 return 0;
1909 }
plougher76c64082008-03-08 01:32:23 +00001910 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00001911 }
1912 }
1913
1914
plougher5507dd92006-11-06 00:43:10 +00001915 return add_non_dup(file_size, bytes, *block_list, *start, *fragment, checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00001916}
1917
1918
plougher5507dd92006-11-06 00:43:10 +00001919void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001920{
plougher018d2b32007-04-23 03:01:48 +00001921 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00001922 struct file_buffer *file_buffer;
ploughereb6eac92008-02-26 01:50:48 +00001923 static int index = 0;
plougher018d2b32007-04-23 03:01:48 +00001924 int blocks, byte, count, expected, file, frag_block;
1925 long long bytes, read_size;
plougher5507dd92006-11-06 00:43:10 +00001926
plougher018d2b32007-04-23 03:01:48 +00001927 if(dir_ent->inode->read)
plougher5507dd92006-11-06 00:43:10 +00001928 return;
1929
plougher018d2b32007-04-23 03:01:48 +00001930 dir_ent->inode->read = TRUE;
1931again:
1932 bytes = 0;
1933 count = 0;
1934 file_buffer = NULL;
1935 read_size = buf->st_size;
1936 blocks = (read_size + block_size - 1) >> block_log;
1937 frag_block = !no_fragments && (always_use_fragments ||
1938 (read_size < block_size)) ? read_size >> block_log : -1;
1939
plougher5507dd92006-11-06 00:43:10 +00001940 if((file = open(dir_ent->pathname, O_RDONLY)) == -1)
1941 goto read_err;
1942
plougher018d2b32007-04-23 03:01:48 +00001943 do {
1944 expected = read_size - ((long long) count * block_size) > block_size ? block_size : read_size - ((long long) count * block_size);
1945
1946 if(file_buffer)
1947 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00001948 file_buffer = cache_get(reader_buffer, 0, 0);
1949 file_buffer->sequence = index ++;
plougher5507dd92006-11-06 00:43:10 +00001950
plougher018d2b32007-04-23 03:01:48 +00001951 byte = file_buffer->size = read(file, file_buffer->data, block_size);
1952
plougher018d2b32007-04-23 03:01:48 +00001953 file_buffer->file_size = read_size;
1954
1955 if(byte != expected)
1956 goto restat;
1957
1958 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00001959 file_buffer->error = FALSE;
plougher018d2b32007-04-23 03:01:48 +00001960
1961 bytes += byte;
1962 count ++;
1963 } while(count < blocks);
1964
1965 if(read_size != bytes)
1966 goto restat;
1967
1968 if(expected == block_size) {
1969 char buffer;
1970
1971 if(read(file, &buffer, 1) == 1)
1972 goto restat;
plougher5507dd92006-11-06 00:43:10 +00001973 }
1974
plougher23377982007-11-12 04:04:48 +00001975 file_buffer->fragment = (file_buffer->block == frag_block);
1976
1977 if(file_buffer->fragment)
plougher018d2b32007-04-23 03:01:48 +00001978 queue_put(from_deflate, file_buffer);
1979 else
1980 queue_put(from_reader, file_buffer);
1981
plougher5507dd92006-11-06 00:43:10 +00001982 close(file);
plougher5507dd92006-11-06 00:43:10 +00001983
1984 return;
1985
1986read_err:
plougher0f464442008-03-31 00:27:56 +00001987 file_buffer = cache_get(reader_buffer, 0, 0);
1988 file_buffer->sequence = index ++;
plougher018d2b32007-04-23 03:01:48 +00001989read_err2:
plougher5507dd92006-11-06 00:43:10 +00001990 file_buffer->error = TRUE;
1991 queue_put(from_deflate, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00001992 return;
1993restat:
1994 fstat(file, &buf2);
1995 close(file);
1996 if(read_size != buf2.st_size) {
1997 memcpy(buf, &buf2, sizeof(struct stat));
1998 file_buffer->error = 2;
1999 queue_put(from_deflate, file_buffer);
2000 goto again;
2001 }
2002 goto read_err2;
plougher5507dd92006-11-06 00:43:10 +00002003}
2004
2005
2006void reader_scan(struct dir_info *dir) {
2007 int i;
2008
2009 for(i = 0; i < dir->count; i++) {
2010 struct dir_ent *dir_ent = dir->list[i];
2011 struct stat *buf = &dir_ent->inode->buf;
2012 if(dir_ent->data)
2013 continue;
2014
2015 switch(buf->st_mode & S_IFMT) {
2016 case S_IFREG:
2017 reader_read_file(dir_ent);
2018 break;
2019 case S_IFDIR:
2020 reader_scan(dir_ent->dir);
2021 break;
2022 }
2023 }
2024}
2025
2026
2027void *reader(void *arg)
2028{
2029 int oldstate;
2030
2031 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2032 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2033
2034 if(!sorted)
2035 reader_scan(queue_get(to_reader));
2036 else {
2037 int i;
2038 struct priority_entry *entry;
2039
2040 queue_get(to_reader);
2041 for(i = 65535; i >= 0; i--)
2042 for(entry = priority_list[i]; entry; entry = entry->next)
2043 reader_read_file(entry->dir);
2044 }
rloughere4873e02007-11-08 17:50:42 +00002045
plougher5aa18162007-12-13 12:15:21 +00002046 thread[0] = 0;
2047
rloughere4873e02007-11-08 17:50:42 +00002048 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002049}
2050
2051
2052void *writer(void *arg)
2053{
2054 int write_error = FALSE;
2055 int oldstate;
2056
2057 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2058 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2059
2060 while(1) {
2061 struct file_buffer *file_buffer = queue_get(to_writer);
2062 off_t off;
2063
2064 if(file_buffer == NULL) {
2065 queue_put(from_writer, write_error ? (void *) &write_error : NULL);
2066 continue;
2067 }
2068
2069 off = file_buffer->block;
2070
2071 pthread_mutex_lock(&pos_mutex);
2072
2073 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher91fbb302008-05-06 02:29:36 +00002074 ERROR("Lseek on destination failed because %s\n", strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002075 write_error = TRUE;
2076 }
2077
2078 if(!write_error && write(fd, file_buffer->data, file_buffer->size) == -1) {
plougher91fbb302008-05-06 02:29:36 +00002079 ERROR("Write on destination failed because %s\n", strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002080 write_error = TRUE;
2081 }
2082 pthread_mutex_unlock(&pos_mutex);
2083
ploughereb6eac92008-02-26 01:50:48 +00002084 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002085 }
2086}
2087
2088
plougher5b09fd42007-08-06 10:28:41 +00002089int all_zero(struct file_buffer *file_buffer)
2090{
2091 int i;
2092 long entries = file_buffer->size / sizeof(long);
2093 long *p = (long *) file_buffer->data;
2094
2095 for(i = 0; i < entries && p[i] == 0; i++);
2096
2097 if(i == entries) {
2098 for(i = file_buffer->size & ~(sizeof(long) - 1); i < file_buffer->size &&
2099 file_buffer->data[i] == 0; i++);
2100
2101 return i == file_buffer->size;
2102 }
2103
2104 return 0;
2105}
2106
2107
plougher5507dd92006-11-06 00:43:10 +00002108void *deflator(void *arg)
2109{
2110 z_stream *stream = NULL;
2111 int oldstate;
2112
2113 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2114 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2115
2116 while(1) {
2117 struct file_buffer *file_buffer = queue_get(from_reader);
plougher0f464442008-03-31 00:27:56 +00002118 struct file_buffer *write_buffer = cache_get(writer_buffer, 0, 0);
plougher5507dd92006-11-06 00:43:10 +00002119
plougher5b09fd42007-08-06 10:28:41 +00002120 if(sparse_files && all_zero(file_buffer))
2121 write_buffer->c_byte = 0;
2122 else
2123 write_buffer->c_byte = mangle2(&stream, write_buffer->data, file_buffer->data, file_buffer->size, block_size, noD, 1);
plougher0f464442008-03-31 00:27:56 +00002124 write_buffer->sequence = file_buffer->sequence;
plougher018d2b32007-04-23 03:01:48 +00002125 write_buffer->file_size = file_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00002126 write_buffer->block = file_buffer->block;
plougher5507dd92006-11-06 00:43:10 +00002127 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK(write_buffer->c_byte);
2128 write_buffer->fragment = FALSE;
2129 write_buffer->error = FALSE;
ploughereb6eac92008-02-26 01:50:48 +00002130 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002131 queue_put(from_deflate, write_buffer);
2132 }
2133}
2134
2135
2136void *frag_deflator(void *arg)
2137{
2138 z_stream *stream = NULL;
2139 int oldstate;
2140
2141 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2142 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2143
2144 while(1) {
2145 int c_byte, compressed_size;
2146 struct file_buffer *file_buffer = queue_get(to_frag);
plougher76c64082008-03-08 01:32:23 +00002147 struct file_buffer *write_buffer = cache_get(writer_buffer, file_buffer->block + FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002148
2149 c_byte = mangle2(&stream, write_buffer->data, file_buffer->data, file_buffer->size, block_size, noF, 1);
2150 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002151 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002152 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002153 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002154 fragment_table[file_buffer->block].size = c_byte;
2155 fragment_table[file_buffer->block].start_block = bytes;
2156 write_buffer->block = bytes;
2157 bytes += compressed_size;
2158 fragments_outstanding --;
2159 pthread_mutex_unlock(&fragment_mutex);
2160 queue_put(to_writer, write_buffer);
2161 TRACE("Writing fragment %lld, uncompressed size %d, compressed size %d\n", file_buffer->block, file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002162 } else {
2163 pthread_mutex_unlock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002164 add_pending_fragment(write_buffer, c_byte, file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002165 }
ploughereb6eac92008-02-26 01:50:48 +00002166 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002167 }
2168}
2169
2170
2171#define HASH_ENTRIES 256
2172#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2173struct file_buffer *block_hash[HASH_ENTRIES];
2174
2175void push_buffer(struct file_buffer *file_buffer)
2176{
plougher0f464442008-03-31 00:27:56 +00002177 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002178
2179 file_buffer->next = block_hash[hash];
2180 block_hash[hash] = file_buffer;
2181}
2182
2183
2184struct file_buffer *get_file_buffer(struct queue *queue)
2185{
plougher0f464442008-03-31 00:27:56 +00002186 static unsigned int sequence = 0;
2187 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002188 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2189
2190 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002191 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002192 break;
2193
2194 if(file_buffer) {
2195 if(prev)
2196 prev->next = file_buffer->next;
2197 else
2198 block_hash[hash] = file_buffer->next;
2199 } else {
2200 while(1) {
2201 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002202 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002203 break;
2204 push_buffer(file_buffer);
2205 }
2206 }
2207
plougher0f464442008-03-31 00:27:56 +00002208 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002209
2210 return file_buffer;
2211}
2212
2213
plougher91fbb302008-05-06 02:29:36 +00002214void *progress_thrd(void *arg)
plougher35a10602008-04-21 02:58:16 +00002215{
2216 struct timeval timeval;
2217 struct timespec timespec;
2218 struct itimerval itimerval;
2219 struct winsize winsize;
2220
2221 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
2222 printf("TIOCGWINZ ioctl failed, defaulting to 80 columns\n");
2223 columns = 80;
2224 } else
2225 columns = winsize.ws_col;
2226 signal(SIGWINCH, sigwinch_handler);
2227 signal(SIGALRM, sigalrm_handler);
2228
2229 itimerval.it_value.tv_sec = 0;
2230 itimerval.it_value.tv_usec = 250000;
2231 itimerval.it_interval.tv_sec = 0;
2232 itimerval.it_interval.tv_usec = 250000;
2233 setitimer(ITIMER_REAL, &itimerval, NULL);
2234
plougher35a10602008-04-21 02:58:16 +00002235 pthread_cond_init(&progress_wait, NULL);
2236
plougher91fbb302008-05-06 02:29:36 +00002237 pthread_mutex_lock(&progress_mutex);
2238
plougher35a10602008-04-21 02:58:16 +00002239 while(1) {
plougher35a10602008-04-21 02:58:16 +00002240 gettimeofday(&timeval, NULL);
2241 timespec.tv_sec = timeval.tv_sec;
2242 if(timeval.tv_usec + 250000 > 999999)
2243 timespec.tv_sec++;
2244 timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) * 1000;
2245 pthread_cond_timedwait(&progress_wait, &progress_mutex, &timespec);
plougher91fbb302008-05-06 02:29:36 +00002246 if(progress_enabled)
2247 progress_bar(cur_uncompressed, estimated_uncompressed, columns);
plougher35a10602008-04-21 02:58:16 +00002248 }
2249}
2250
2251
plougher91fbb302008-05-06 02:29:36 +00002252void enable_progress_bar()
2253{
2254 pthread_mutex_lock(&progress_mutex);
2255 progress_enabled = TRUE;
2256 pthread_mutex_unlock(&progress_mutex);
2257}
2258
2259
2260void disable_progress_bar()
2261{
2262 pthread_mutex_lock(&progress_mutex);
2263 progress_enabled = FALSE;
2264 pthread_mutex_unlock(&progress_mutex);
2265}
2266
2267
rloughere4873e02007-11-08 17:50:42 +00002268void progress_bar(long long current, long long max, int columns)
plougher02bc3bc2007-02-25 12:12:01 +00002269{
plougher35a10602008-04-21 02:58:16 +00002270 char rotate_list[] = { '|', '/', '-', '\\' };
plougher02bc3bc2007-02-25 12:12:01 +00002271 int max_digits = ceil(log10(max));
plougher35a10602008-04-21 02:58:16 +00002272 int used = max_digits * 2 + 11;
plougher02bc3bc2007-02-25 12:12:01 +00002273 int hashes = (current * (columns - used)) / max;
2274 int spaces = columns - used - hashes;
2275
plougher35a10602008-04-21 02:58:16 +00002276 if(current > max) {
2277 printf("%lld %lld\n", current, max);
2278 return;
2279 }
2280
plougher02bc3bc2007-02-25 12:12:01 +00002281 if(!progress || columns - used < 0)
2282 return;
2283
2284 printf("\r[");
2285
2286 while (hashes --)
2287 putchar('=');
2288
plougher35a10602008-04-21 02:58:16 +00002289 putchar(rotate_list[rotate]);
2290
plougher02bc3bc2007-02-25 12:12:01 +00002291 while(spaces --)
2292 putchar(' ');
2293
2294 printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2295 printf(" %3lld%%", current * 100 / max);
2296 fflush(stdout);
2297}
2298
2299
plougher29e37092007-04-15 01:24:51 +00002300void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002301{
2302 file_count ++;
2303 *duplicate_file = FALSE;
plougher29e37092007-04-15 01:24:51 +00002304 if(dir_ent->inode->nlink == 1)
2305 create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0, NULL, &empty_fragment, NULL);
2306 else
plougher5507dd92006-11-06 00:43:10 +00002307 create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, 0, 0, 0, NULL, &empty_fragment, NULL);
2308}
2309
2310
plougher29e37092007-04-15 01:24:51 +00002311void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent, int size, int *duplicate_file, struct file_buffer *file_buffer, unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002312{
plougher5507dd92006-11-06 00:43:10 +00002313 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002314 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002315 unsigned int *block_listp = NULL;
2316 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002317
plougher5507dd92006-11-06 00:43:10 +00002318 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment, file_buffer, NULL, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002319
plougher5507dd92006-11-06 00:43:10 +00002320 if(dupl_ptr) {
2321 *duplicate_file = FALSE;
2322 fragment = get_and_fill_fragment(file_buffer);
2323 dupl_ptr->fragment = fragment;
2324 } else
2325 *duplicate_file = TRUE;
2326
ploughereb6eac92008-02-26 01:50:48 +00002327 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002328
2329 total_bytes += size;
2330 file_count ++;
2331
plougher35a10602008-04-21 02:58:16 +00002332 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002333
plougher29e37092007-04-15 01:24:51 +00002334 if(dir_ent->inode->nlink == 1)
2335 create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, size, 0, 0, NULL, fragment, NULL);
2336 else
plougher5507dd92006-11-06 00:43:10 +00002337 create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, size, 0, 0, NULL, fragment, NULL);
2338}
2339
2340
plougher018d2b32007-04-23 03:01:48 +00002341void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size, struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002342{
2343 struct fragment *fragment;
2344 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002345
2346 checksum = get_checksum_mem_buffer(file_buffer);
2347
plougher29e37092007-04-15 01:24:51 +00002348 if(pre_duplicate_frag(size, checksum)) {
2349 write_file_frag_dup(inode, dir_ent, size, duplicate_file, file_buffer, checksum);
2350 return;
2351 }
plougher5507dd92006-11-06 00:43:10 +00002352
2353 fragment = get_and_fill_fragment(file_buffer);
2354
ploughereb6eac92008-02-26 01:50:48 +00002355 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002356
2357 if(duplicate_checking)
2358 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2359
2360 total_bytes += size;
2361 file_count ++;
2362
2363 *duplicate_file = FALSE;
2364
plougher35a10602008-04-21 02:58:16 +00002365 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002366
plougher29e37092007-04-15 01:24:51 +00002367 if(dir_ent->inode->nlink == 1)
2368 create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, size, 0, 0, NULL, fragment, NULL);
2369 else
plougher5507dd92006-11-06 00:43:10 +00002370 create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, size, 0, 0, NULL, fragment, NULL);
plougher29e37092007-04-15 01:24:51 +00002371
plougher018d2b32007-04-23 03:01:48 +00002372 return;
plougher5507dd92006-11-06 00:43:10 +00002373}
2374
2375
plougher018d2b32007-04-23 03:01:48 +00002376int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent, long long read_size, struct file_buffer *reader_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002377{
plougher29e37092007-04-15 01:24:51 +00002378 int block;
plougher23377982007-11-12 04:04:48 +00002379 unsigned int frag_bytes;
2380 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002381 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002382 int blocks = (read_size + block_size - 1) >> block_log;
2383 unsigned int *block_list;
2384 struct file_buffer *read_buffer;
plougher018d2b32007-04-23 03:01:48 +00002385 int status;
plougher5507dd92006-11-06 00:43:10 +00002386
plougher29e37092007-04-15 01:24:51 +00002387 *duplicate_file = FALSE;
2388
plougher5507dd92006-11-06 00:43:10 +00002389 if(!no_fragments && always_use_fragments) {
2390 blocks = read_size >> block_log;
plougher1f413c82005-11-18 00:02:14 +00002391 frag_bytes = read_size % block_size;
2392 } else
2393 frag_bytes = 0;
2394
plougher5507dd92006-11-06 00:43:10 +00002395 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
2396 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002397
plougher2ea89142008-03-11 01:34:19 +00002398 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002399
plougher5507dd92006-11-06 00:43:10 +00002400 file_bytes = 0;
2401 start = bytes;
2402 for(block = 0; block < blocks; block ++) {
plougher018d2b32007-04-23 03:01:48 +00002403 if(reader_buffer) {
2404 read_buffer = reader_buffer;
2405 reader_buffer = NULL;
2406 } else {
2407 read_buffer = get_file_buffer(from_deflate);
2408 if(read_buffer->error)
2409 goto read_err;
2410 }
plougher1f413c82005-11-18 00:02:14 +00002411
plougher5507dd92006-11-06 00:43:10 +00002412 block_list[block] = read_buffer->c_byte;
plougher5b09fd42007-08-06 10:28:41 +00002413 if(read_buffer->c_byte) {
plougher341e1802007-08-13 05:12:38 +00002414 read_buffer->block = bytes;
plougher5b09fd42007-08-06 10:28:41 +00002415 bytes += read_buffer->size;
plougher0f464442008-03-31 00:27:56 +00002416 cache_rehash(read_buffer, read_buffer->block);
plougher5b09fd42007-08-06 10:28:41 +00002417 file_bytes += read_buffer->size;
plougher5b09fd42007-08-06 10:28:41 +00002418 queue_put(to_writer, read_buffer);
2419 } else
ploughereb6eac92008-02-26 01:50:48 +00002420 cache_block_put(read_buffer);
plougher35a10602008-04-21 02:58:16 +00002421 inc_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00002422 }
2423
plougher5507dd92006-11-06 00:43:10 +00002424 if(frag_bytes != 0) {
2425 read_buffer = get_file_buffer(from_deflate);
plougher5507dd92006-11-06 00:43:10 +00002426 if(read_buffer->error)
2427 goto read_err;
plougher35a10602008-04-21 02:58:16 +00002428 inc_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00002429 } else
2430 read_buffer = NULL;
2431
plougher2ea89142008-03-11 01:34:19 +00002432 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00002433 fragment = get_and_fill_fragment(read_buffer);
ploughereb6eac92008-02-26 01:50:48 +00002434 cache_block_put(read_buffer);
plougher5507dd92006-11-06 00:43:10 +00002435
plougher1f413c82005-11-18 00:02:14 +00002436 if(duplicate_checking)
plougher5507dd92006-11-06 00:43:10 +00002437 add_non_dup(read_size, file_bytes, block_list, start, fragment, 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002438 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002439 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002440
plougher1f413c82005-11-18 00:02:14 +00002441 if(dir_ent->inode->nlink == 1 && read_size < ((long long) (1<<30) - 1))
plougher29e37092007-04-15 01:24:51 +00002442 create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_list, fragment, NULL);
plougher1f413c82005-11-18 00:02:14 +00002443 else
plougher29e37092007-04-15 01:24:51 +00002444 create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size, start, blocks, block_list, fragment, NULL);
2445
plougher5507dd92006-11-06 00:43:10 +00002446 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002447 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002448
plougher018d2b32007-04-23 03:01:48 +00002449 return 0;
plougher1f413c82005-11-18 00:02:14 +00002450
2451read_err:
plougher018d2b32007-04-23 03:01:48 +00002452 cur_uncompressed -= block;
2453 status = read_buffer->error;
plougher5507dd92006-11-06 00:43:10 +00002454 if(block) {
2455 queue_put(to_writer, NULL);
2456 if(queue_get(from_writer) != 0)
2457 EXIT_MKSQUASHFS();
2458 bytes = start;
2459 if(!block_device)
2460 ftruncate(fd, bytes);
2461 }
plougher2ea89142008-03-11 01:34:19 +00002462 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00002463 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00002464 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002465 return status;
plougher1f413c82005-11-18 00:02:14 +00002466}
2467
2468
plougher018d2b32007-04-23 03:01:48 +00002469int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent, long long read_size, struct file_buffer *reader_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002470{
plougher29e37092007-04-15 01:24:51 +00002471 int block, thresh;
plougher23377982007-11-12 04:04:48 +00002472 unsigned int frag_bytes;
2473 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002474 struct fragment *fragment;
2475 struct file_info *dupl_ptr;
2476 int blocks = (read_size + block_size - 1) >> block_log;
2477 unsigned int *block_list, *block_listp;
2478 struct file_buffer *read_buffer;
plougher5507dd92006-11-06 00:43:10 +00002479 struct buffer_list *buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00002480 int status, num_locked_fragments;
plougher5507dd92006-11-06 00:43:10 +00002481
2482 if(!no_fragments && always_use_fragments) {
2483 blocks = read_size >> block_log;
2484 frag_bytes = read_size % block_size;
2485 } else
2486 frag_bytes = 0;
2487
2488 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
2489 BAD_ERROR("Out of memory allocating block_list\n");
2490 block_listp = block_list;
2491
2492 if((buffer_list = malloc(blocks * sizeof(struct buffer_list))) == NULL)
2493 BAD_ERROR("Out of memory allocating file block list\n");
2494
plougher4e8484a2008-03-15 23:30:16 +00002495 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00002496
2497 file_bytes = 0;
2498 start = bytes;
plougher4e8484a2008-03-15 23:30:16 +00002499 thresh = blocks > (writer_buffer_size - num_locked_fragments) ? blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher5507dd92006-11-06 00:43:10 +00002500 for(block = 0; block < blocks; block ++) {
plougher018d2b32007-04-23 03:01:48 +00002501 if(reader_buffer) {
2502 read_buffer = reader_buffer;
2503 reader_buffer = NULL;
2504 } else {
2505 read_buffer = get_file_buffer(from_deflate);
2506 if(read_buffer->error)
2507 goto read_err;
2508 }
plougher5507dd92006-11-06 00:43:10 +00002509
2510 block_list[block] = read_buffer->c_byte;
plougher7354cb72007-11-26 02:16:45 +00002511 buffer_list[block].start = bytes;
2512 buffer_list[block].size = read_buffer->size;
plougher5507dd92006-11-06 00:43:10 +00002513
plougher5b09fd42007-08-06 10:28:41 +00002514 if(read_buffer->c_byte) {
2515 read_buffer->block = bytes;
2516 bytes += read_buffer->size;
plougher0f464442008-03-31 00:27:56 +00002517 cache_rehash(read_buffer, read_buffer->block);
plougher5b09fd42007-08-06 10:28:41 +00002518 file_bytes += read_buffer->size;
2519 if(block < thresh) {
2520 buffer_list[block].read_buffer = NULL;
2521 queue_put(to_writer, read_buffer);
2522 } else
2523 buffer_list[block].read_buffer = read_buffer;
2524 } else {
plougher5507dd92006-11-06 00:43:10 +00002525 buffer_list[block].read_buffer = NULL;
ploughereb6eac92008-02-26 01:50:48 +00002526 cache_block_put(read_buffer);
plougher5b09fd42007-08-06 10:28:41 +00002527 }
plougher35a10602008-04-21 02:58:16 +00002528 inc_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00002529 }
2530
2531 if(frag_bytes != 0) {
2532 read_buffer = get_file_buffer(from_deflate);
plougher5507dd92006-11-06 00:43:10 +00002533 if(read_buffer->error)
2534 goto read_err;
2535 } else
2536 read_buffer = NULL;
2537
plougher5507dd92006-11-06 00:43:10 +00002538 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &start, &fragment, read_buffer, buffer_list, blocks, 0, 0, FALSE);
2539
2540 if(dupl_ptr) {
2541 *duplicate_file = FALSE;
2542 for(block = thresh; block < blocks; block ++)
plougher7354cb72007-11-26 02:16:45 +00002543 if(buffer_list[block].read_buffer)
2544 queue_put(to_writer, buffer_list[block].read_buffer);
plougher5507dd92006-11-06 00:43:10 +00002545 fragment = get_and_fill_fragment(read_buffer);
2546 dupl_ptr->fragment = fragment;
2547 } else {
2548 *duplicate_file = TRUE;
2549 for(block = thresh; block < blocks; block ++)
ploughereb6eac92008-02-26 01:50:48 +00002550 cache_block_put(buffer_list[block].read_buffer);
plougher5507dd92006-11-06 00:43:10 +00002551 bytes = buffer_list[0].start;
2552 if(thresh && !block_device)
2553 ftruncate(fd, bytes);
2554 }
2555
plougher2ea89142008-03-11 01:34:19 +00002556 unlock_fragments();
ploughereb6eac92008-02-26 01:50:48 +00002557 cache_block_put(read_buffer);
plougher5507dd92006-11-06 00:43:10 +00002558 free(buffer_list);
2559 file_count ++;
2560 total_bytes += read_size;
2561
2562 if(dir_ent->inode->nlink == 1 && read_size < ((long long) (1<<30) - 1))
plougher29e37092007-04-15 01:24:51 +00002563 create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
plougher5507dd92006-11-06 00:43:10 +00002564 else
plougher29e37092007-04-15 01:24:51 +00002565 create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
2566
plougher5507dd92006-11-06 00:43:10 +00002567 if(*duplicate_file == TRUE)
2568 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002569
plougher018d2b32007-04-23 03:01:48 +00002570 return 0;
plougher5507dd92006-11-06 00:43:10 +00002571
2572read_err:
plougher018d2b32007-04-23 03:01:48 +00002573 cur_uncompressed -= block;
2574 status = read_buffer->error;
plougher5507dd92006-11-06 00:43:10 +00002575 if(block && thresh) {
2576 queue_put(to_writer, NULL);
2577 if(queue_get(from_writer) != 0)
2578 EXIT_MKSQUASHFS();
2579 bytes = start;
2580 if(!block_device)
2581 ftruncate(fd, bytes);
2582 }
plougher2ea89142008-03-11 01:34:19 +00002583 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00002584 for(blocks = thresh; blocks < block; blocks ++)
ploughereb6eac92008-02-26 01:50:48 +00002585 cache_block_put(buffer_list[blocks].read_buffer);
plougher5507dd92006-11-06 00:43:10 +00002586 free(buffer_list);
2587 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00002588 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002589 return status;
plougher5507dd92006-11-06 00:43:10 +00002590}
2591
2592
plougher018d2b32007-04-23 03:01:48 +00002593void write_file(squashfs_inode *inode, struct dir_ent *dir_ent, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002594{
plougher018d2b32007-04-23 03:01:48 +00002595 int status;
2596 struct file_buffer *read_buffer;
2597 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00002598
plougher018d2b32007-04-23 03:01:48 +00002599again:
2600 read_buffer = get_file_buffer(from_deflate);
plougher23377982007-11-12 04:04:48 +00002601 status = read_buffer->error;
2602 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00002603 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002604 goto file_err;
2605 }
2606
2607 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00002608
plougher018d2b32007-04-23 03:01:48 +00002609 if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00002610 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00002611 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002612 } else if(!no_fragments && (read_size < block_size))
2613 write_file_frag(inode, dir_ent, read_size, read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00002614 else if(pre_duplicate(read_size))
plougher018d2b32007-04-23 03:01:48 +00002615 status = write_file_blocks_dup(inode, dir_ent, read_size, read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00002616 else
plougher018d2b32007-04-23 03:01:48 +00002617 status = write_file_blocks(inode, dir_ent, read_size, read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00002618
plougher018d2b32007-04-23 03:01:48 +00002619file_err:
2620 if(status == 2) {
2621 ERROR("File %s changed size while reading filesystem, attempting to re-read\n", dir_ent->pathname);
2622 goto again;
2623 } else if(status == 1) {
plougher29e37092007-04-15 01:24:51 +00002624 ERROR("Failed to read file %s, creating empty file\n", dir_ent->pathname);
2625 write_file_empty(inode, dir_ent, duplicate_file);
2626 }
plougher5507dd92006-11-06 00:43:10 +00002627}
2628
2629
plougher1f413c82005-11-18 00:02:14 +00002630char b_buffer[8192];
2631char *name;
2632char *basename_r();
2633
2634char *getbase(char *pathname)
2635{
2636 char *result;
2637
2638 if(*pathname != '/') {
2639 result = getenv("PWD");
2640 strcat(strcat(strcpy(b_buffer, result), "/"), pathname);
2641 } else
2642 strcpy(b_buffer, pathname);
2643 name = b_buffer;
2644 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
2645 return NULL;
2646 else
2647 return result;
2648}
2649
2650
2651char *basename_r()
2652{
2653 char *s;
2654 char *p;
2655 int n = 1;
2656
2657 for(;;) {
2658 s = name;
2659 if(*name == '\0')
2660 return NULL;
2661 if(*name != '/') {
2662 while(*name != '\0' && *name != '/') name++;
2663 n = name - s;
2664 }
2665 while(*name == '/') name++;
2666 if(strncmp(s, ".", n) == 0)
2667 continue;
2668 if((*name == '\0') || (strncmp(s, "..", n) == 0) || ((p = basename_r()) == NULL)) {
2669 s[n] = '\0';
2670 return s;
2671 }
2672 if(strcmp(p, "..") == 0)
2673 continue;
2674 return p;
2675 }
2676}
2677
2678
2679struct inode_info *lookup_inode(struct stat *buf)
2680{
2681 int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
2682 struct inode_info *inode = inode_info[inode_hash];
2683
2684 while(inode != NULL) {
2685 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
2686 inode->nlink ++;
2687 return inode;
2688 }
2689 inode = inode->next;
2690 }
2691
2692 if((inode = malloc(sizeof(struct inode_info))) == NULL)
2693 BAD_ERROR("Out of memory in inode hash table entry allocation\n");
2694
2695 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00002696 inode->read = FALSE;
plougher1f413c82005-11-18 00:02:14 +00002697 inode->inode = SQUASHFS_INVALID_BLK;
2698 inode->nlink = 1;
plougherdc86c3c2007-12-05 02:15:10 +00002699
2700 if((buf->st_mode & S_IFMT) == S_IFREG)
2701 estimated_uncompressed += (buf->st_size + block_size - 1) >> block_log;
2702
plougher1f413c82005-11-18 00:02:14 +00002703 if((buf->st_mode & S_IFMT) == S_IFDIR)
2704 inode->inode_number = dir_inode_no ++;
2705 else
2706 inode->inode_number = inode_no ++;
2707
2708 inode->next = inode_info[inode_hash];
2709 inode_info[inode_hash] = inode;
2710
2711 return inode;
2712}
2713
2714
2715inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir)
2716{
2717 if((dir->count % DIR_ENTRIES) == 0)
2718 if((dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) * sizeof(struct dir_ent *))) == NULL)
2719 BAD_ERROR("Out of memory in add_dir_entry\n");
2720
2721 if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL)
2722 BAD_ERROR("Out of memory in linux_opendir\n");
2723
2724 if(sub_dir)
2725 sub_dir->dir_ent = dir->list[dir->count];
2726 dir->list[dir->count]->name = strdup(name);
2727 dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) : NULL;
2728 dir->list[dir->count]->inode = inode_info;
2729 dir->list[dir->count]->dir = sub_dir;
2730 dir->list[dir->count]->our_dir = dir;
2731 dir->list[dir->count++]->data = data;
2732 dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
2733}
2734
2735
2736int compare_name(const void *ent1_ptr, const void *ent2_ptr)
2737{
2738 struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
2739 struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
2740
2741 return strcmp(ent1->name, ent2->name);
2742}
2743
2744
2745void sort_directory(struct dir_info *dir)
2746{
2747 qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
2748
2749 if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
2750 dir->dir_is_ldir = FALSE;
2751}
2752
2753
2754struct dir_info *scan1_opendir(char *pathname)
2755{
plougher1f413c82005-11-18 00:02:14 +00002756 struct dir_info *dir;
2757
2758 if((dir = malloc(sizeof(struct dir_info))) == NULL)
2759 return NULL;
2760
2761 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
2762 free(dir);
2763 return NULL;
2764 }
2765 dir->pathname = strdup(pathname);
2766 dir->count = dir->directory_count = dir->current_count = dir->byte_count = 0;
2767 dir->dir_is_ldir = TRUE;
2768 dir->list = NULL;
2769
2770 return dir;
2771}
2772
2773
2774int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
2775{
2776 int i, n, pass;
2777 char *basename;
2778 static int index = 0;
2779
2780 if(dir->count < old_root_entries)
2781 for(i = 0; i < old_root_entries; i++) {
2782 if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
2783 dir->directory_count ++;
2784 add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
2785 }
2786
2787 while(index < source) {
2788 if((basename = getbase(source_path[index])) == NULL) {
2789 ERROR("Bad source directory %s - skipping ...\n", source_path[index]);
2790 index ++;
2791 continue;
2792 }
2793 strcpy(dir_name, basename);
2794 pass = 1;
2795 for(;;) {
2796 for(n = 0; n < dir->count && strcmp(dir->list[n]->name, dir_name) != 0; n++);
2797 if(n == dir->count)
2798 break;
2799 ERROR("Source directory entry %s already used! - trying ", dir_name);
2800 sprintf(dir_name, "%s_%d", basename, pass++);
2801 ERROR("%s\n", dir_name);
2802 }
2803 strcpy(pathname, source_path[index ++]);
2804 return 1;
2805 }
2806 return 0;
2807}
2808
2809
2810int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
2811{
2812 struct dirent *d_name;
2813 int i, pass;
2814
2815 if(dir->count < old_root_entries)
2816 for(i = 0; i < old_root_entries; i++) {
2817 if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
2818 dir->directory_count ++;
2819 add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
2820 }
2821
2822 if((d_name = readdir(dir->linuxdir)) != NULL) {
2823 strcpy(dir_name, d_name->d_name);
2824 pass = 1;
2825 for(;;) {
2826 for(i = 0; i < dir->count && strcmp(dir->list[i]->name, dir_name) != 0; i++);
2827 if(i == dir->count)
2828 break;
2829 ERROR("Source directory entry %s already used! - trying ", dir_name);
2830 sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
2831 ERROR("%s\n", dir_name);
2832 }
2833 strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
2834 return 1;
2835 }
2836
2837 return 0;
2838}
2839
2840
2841int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
2842{
2843 struct dirent *d_name;
2844
2845 if((d_name = readdir(dir->linuxdir)) != NULL) {
2846 strcpy(dir_name, d_name->d_name);
2847 strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00002848 return 1;
2849 }
2850
2851 return 0;
2852}
2853
2854
2855struct dir_ent *scan2_readdir(struct directory *dir, struct dir_info *dir_info)
2856{
2857 int current_count;
2858
2859 while((current_count = dir_info->current_count++) < dir_info->count)
2860 if(dir_info->list[current_count]->data)
2861 add_dir(dir_info->list[current_count]->data->inode, dir_info->list[current_count]->data->inode_number,
2862 dir_info->list[current_count]->name, dir_info->list[current_count]->data->type, dir);
2863 else
2864 return dir_info->list[current_count];
2865 return FALSE;
2866}
2867
2868
2869void scan1_freedir(struct dir_info *dir)
2870{
plougherfbed12b2006-02-07 12:45:53 +00002871 if(dir->pathname[0] != '\0')
2872 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00002873}
2874
2875
2876void scan2_freedir(struct directory *dir)
2877{
2878 if(dir->index)
2879 free(dir->index);
2880 free(dir->buff);
2881}
2882
2883
2884void dir_scan(squashfs_inode *inode, char *pathname, int (_readdir)(char *, char *, struct dir_info *))
2885{
plougher0e453652006-11-06 01:49:35 +00002886 struct stat buf;
plougher8f8e1a12007-10-18 02:50:21 +00002887 struct dir_info *dir_info = dir_scan1(pathname, paths, _readdir);
plougher1f413c82005-11-18 00:02:14 +00002888 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00002889
2890 if(dir_info == NULL)
2891 return;
2892
2893 if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL)
2894 BAD_ERROR("Out of memory in dir_scan\n");
2895
plougher1f413c82005-11-18 00:02:14 +00002896 if(pathname[0] == '\0') {
2897 /* dummy top level directory, if multiple sources specified on command line */
plougher0e453652006-11-06 01:49:35 +00002898 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
2899 buf.st_uid = getuid();
2900 buf.st_gid = getgid();
2901 buf.st_mtime = time(NULL);
2902 buf.st_dev = 0;
2903 buf.st_ino = 0;
2904 } else if(lstat(pathname, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00002905 ERROR("Cannot stat dir/file %s because %s, ignoring", pathname, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00002906 return;
2907 }
plougher0e453652006-11-06 01:49:35 +00002908
2909 dir_ent->inode = lookup_inode(&buf);
2910 if(root_inode_number) {
2911 dir_ent->inode->inode_number = root_inode_number;
2912 dir_inode_no --;
2913 }
2914 dir_ent->name = dir_ent->pathname = strdup(pathname);
2915 dir_ent->dir = dir_info;
2916 dir_ent->our_dir = NULL;
2917 dir_ent->data = NULL;
2918 dir_info->dir_ent = dir_ent;
2919
plougher117b2ea2006-02-09 09:23:56 +00002920 if(sorted)
plougher5507dd92006-11-06 00:43:10 +00002921 generate_file_priorities(dir_info, 0, &dir_info->dir_ent->inode->buf);
2922 queue_put(to_reader, dir_info);
2923 if(sorted)
plougher117b2ea2006-02-09 09:23:56 +00002924 sort_files_and_write(dir_info);
plougher91fbb302008-05-06 02:29:36 +00002925 if(progress)
2926 enable_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00002927 dir_scan2(inode, dir_info);
plougher0e453652006-11-06 01:49:35 +00002928 dir_ent->inode->inode = *inode;
2929 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00002930}
2931
2932
plougherf9039c92007-10-22 03:54:16 +00002933struct dir_info *dir_scan1(char *pathname, struct pathnames *paths, int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00002934{
2935 struct dir_info *dir, *sub_dir;
2936 struct stat buf;
2937 char filename[8192], dir_name[8192];
plougherf9039c92007-10-22 03:54:16 +00002938 struct pathnames *new;
plougher1f413c82005-11-18 00:02:14 +00002939
2940 if((dir = scan1_opendir(pathname)) == NULL) {
2941 ERROR("Could not open %s, skipping...\n", pathname);
2942 goto error;
2943 }
2944
2945 while(_readdir(filename, dir_name, dir) != FALSE) {
2946
2947 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
2948 continue;
2949
2950 if(lstat(filename, &buf) == -1) {
plougher29e37092007-04-15 01:24:51 +00002951 ERROR("Cannot stat dir/file %s because %s, ignoring", filename, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00002952 continue;
2953 }
plougher29e37092007-04-15 01:24:51 +00002954
2955 if((buf.st_mode & S_IFMT) != S_IFREG &&
2956 (buf.st_mode & S_IFMT) != S_IFDIR &&
2957 (buf.st_mode & S_IFMT) != S_IFLNK &&
2958 (buf.st_mode & S_IFMT) != S_IFCHR &&
2959 (buf.st_mode & S_IFMT) != S_IFBLK &&
2960 (buf.st_mode & S_IFMT) != S_IFIFO &&
2961 (buf.st_mode & S_IFMT) != S_IFSOCK) {
2962 ERROR("File %s has unrecognised filetype %d, ignoring\n", filename, buf.st_mode & S_IFMT);
2963 continue;
2964 }
2965
plougher8f8e1a12007-10-18 02:50:21 +00002966 if(old_exclude) {
2967 if(old_excluded(filename, &buf))
2968 continue;
2969 } else {
2970 if(excluded(paths, dir_name, &new))
2971 continue;
2972 }
plougher1f413c82005-11-18 00:02:14 +00002973
2974 if((buf.st_mode & S_IFMT) == S_IFDIR) {
plougher8f8e1a12007-10-18 02:50:21 +00002975 if((sub_dir = dir_scan1(filename, new, scan1_readdir)) == NULL)
plougher1f413c82005-11-18 00:02:14 +00002976 continue;
2977 dir->directory_count ++;
2978 } else
2979 sub_dir = NULL;
2980
2981 add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf), NULL, dir);
2982 }
2983
2984 scan1_freedir(dir);
2985 sort_directory(dir);
2986
2987error:
2988 return dir;
2989}
2990
plougher2ea89142008-03-11 01:34:19 +00002991
plougher29e37092007-04-15 01:24:51 +00002992void dir_scan2(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00002993{
2994 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00002995 int duplicate_file;
2996 char *pathname = dir_info->pathname;
2997 struct directory dir;
2998 struct dir_ent *dir_ent;
2999
3000 scan2_init_dir(&dir);
3001
3002 while((dir_ent = scan2_readdir(&dir, dir_info)) != NULL) {
3003 struct inode_info *inode_info = dir_ent->inode;
3004 struct stat *buf = &inode_info->buf;
3005 char *filename = dir_ent->pathname;
3006 char *dir_name = dir_ent->name;
3007 unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
3008
3009 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3010 switch(buf->st_mode & S_IFMT) {
3011 case S_IFREG:
3012 squashfs_type = SQUASHFS_FILE_TYPE;
plougher018d2b32007-04-23 03:01:48 +00003013 write_file(inode, dir_ent, &duplicate_file);
plougher04b0d5f2006-02-10 00:42:06 +00003014 INFO("file %s, uncompressed size %lld bytes %s\n", filename, buf->st_size, duplicate_file ? "DUPLICATE" : "");
plougher1f413c82005-11-18 00:02:14 +00003015 break;
3016
3017 case S_IFDIR:
3018 squashfs_type = SQUASHFS_DIR_TYPE;
plougher29e37092007-04-15 01:24:51 +00003019 dir_scan2(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003020 break;
3021
3022 case S_IFLNK:
3023 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher29e37092007-04-15 01:24:51 +00003024 create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00003025 INFO("symbolic link %s inode 0x%llx\n", dir_name, *inode);
3026 sym_count ++;
3027 break;
3028
3029 case S_IFCHR:
3030 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher29e37092007-04-15 01:24:51 +00003031 create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00003032 INFO("character device %s inode 0x%llx\n", dir_name, *inode);
3033 dev_count ++;
3034 break;
3035
3036 case S_IFBLK:
3037 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher29e37092007-04-15 01:24:51 +00003038 create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00003039 INFO("block device %s inode 0x%llx\n", dir_name, *inode);
3040 dev_count ++;
3041 break;
3042
3043 case S_IFIFO:
3044 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher29e37092007-04-15 01:24:51 +00003045 create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00003046 INFO("fifo %s inode 0x%llx\n", dir_name, *inode);
3047 fifo_count ++;
3048 break;
3049
3050 case S_IFSOCK:
3051 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher29e37092007-04-15 01:24:51 +00003052 create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
plougher1f413c82005-11-18 00:02:14 +00003053 INFO("unix domain socket %s inode 0x%llx\n", dir_name, *inode);
3054 sock_count ++;
3055 break;
3056
plougher23377982007-11-12 04:04:48 +00003057 default:
3058 BAD_ERROR("%s unrecognised file type, mode is %x\n", filename, buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00003059 }
3060 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00003061 dir_ent->inode->type = squashfs_type;
3062 } else {
3063 *inode = dir_ent->inode->inode;
3064 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00003065 switch(squashfs_type) {
3066 case SQUASHFS_FILE_TYPE:
3067 if(!sorted)
3068 INFO("file %s, uncompressed size %lld bytes LINK\n", filename, buf->st_size);
3069 break;
3070 case SQUASHFS_SYMLINK_TYPE:
3071 INFO("symbolic link %s inode 0x%llx LINK\n", dir_name, *inode);
3072 break;
3073 case SQUASHFS_CHRDEV_TYPE:
3074 INFO("character device %s inode 0x%llx LINK\n", dir_name, *inode);
3075 break;
plougher5507dd92006-11-06 00:43:10 +00003076 case SQUASHFS_BLKDEV_TYPE:
plougher04b0d5f2006-02-10 00:42:06 +00003077 INFO("block device %s inode 0x%llx LINK\n", dir_name, *inode);
3078 break;
3079 case SQUASHFS_FIFO_TYPE:
3080 INFO("fifo %s inode 0x%llx LINK\n", dir_name, *inode);
3081 break;
3082 case SQUASHFS_SOCKET_TYPE:
3083 INFO("unix domain socket %s inode 0x%llx LINK\n", dir_name, *inode);
3084 break;
3085 }
plougher1f413c82005-11-18 00:02:14 +00003086 }
3087
plougher29e37092007-04-15 01:24:51 +00003088 add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00003089 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00003090 }
3091
plougher29e37092007-04-15 01:24:51 +00003092 write_dir(inode, dir_info, &dir);
plougher1f413c82005-11-18 00:02:14 +00003093 INFO("directory %s inode 0x%llx\n", pathname, *inode);
3094
3095 scan2_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003096}
3097
3098
3099unsigned int slog(unsigned int block)
3100{
3101 int i;
3102
plougher4c99cb72007-06-14 21:46:31 +00003103 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00003104 if(block == (1 << i))
3105 return i;
3106 return 0;
3107}
3108
3109
plougher8f8e1a12007-10-18 02:50:21 +00003110int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00003111{
3112 int i;
3113
3114 for(i = 0; i < exclude; i++)
3115 if((exclude_paths[i].st_dev == buf->st_dev) && (exclude_paths[i].st_ino == buf->st_ino))
3116 return TRUE;
3117 return FALSE;
3118}
3119
3120
3121#define ADD_ENTRY(buf) \
3122 if(exclude % EXCLUDE_SIZE == 0) {\
3123 if((exclude_paths = (struct exclude_info *) realloc(exclude_paths, (exclude + EXCLUDE_SIZE) * sizeof(struct exclude_info))) == NULL)\
3124 BAD_ERROR("Out of memory in exclude dir/file table\n");\
3125 }\
3126 exclude_paths[exclude].st_dev = buf.st_dev;\
3127 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00003128int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00003129{
3130 int i;
plougher91fbb302008-05-06 02:29:36 +00003131 char filename[4096];
plougher1f413c82005-11-18 00:02:14 +00003132 struct stat buf;
3133
3134 if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
3135 if(lstat(path, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00003136 ERROR("Cannot stat exclude dir/file %s because %s, ignoring", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003137 return TRUE;
3138 }
3139 ADD_ENTRY(buf);
3140 return TRUE;
3141 }
3142
3143 for(i = 0; i < source; i++) {
3144 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
3145 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00003146 if(!(errno == ENOENT || errno == ENOTDIR))
3147 ERROR("Cannot stat exclude dir/file %s because %s, ignoring", filename, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003148 continue;
3149 }
3150 ADD_ENTRY(buf);
3151 }
3152 return TRUE;
3153}
3154
3155
plougherdf70c3e2006-01-27 09:34:13 +00003156void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type)
plougher1f413c82005-11-18 00:02:14 +00003157{
3158 if((old_root_entry = (struct old_root_entry_info *) realloc(old_root_entry, sizeof(struct old_root_entry_info)
3159 * (old_root_entries + 1))) == NULL)
3160 BAD_ERROR("Out of memory in old root directory entries reallocation\n");
3161
3162 strcpy(old_root_entry[old_root_entries].name, name);
3163 old_root_entry[old_root_entries].inode = inode;
plougherdf70c3e2006-01-27 09:34:13 +00003164 old_root_entry[old_root_entries].inode_number = inode_number;
plougher1f413c82005-11-18 00:02:14 +00003165 old_root_entry[old_root_entries++].type = type;
3166}
3167
3168
plougher5507dd92006-11-06 00:43:10 +00003169void initialise_threads()
3170{
3171 int i;
3172 sigset_t sigmask, old_mask;
3173
3174 sigemptyset(&sigmask);
3175 sigaddset(&sigmask, SIGINT);
3176 sigaddset(&sigmask, SIGQUIT);
3177 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
3178 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
3179
3180 signal(SIGUSR1, sigusr1_handler);
3181
3182 if(processors == -1) {
3183#ifndef linux
3184 int mib[2];
3185 size_t len = sizeof(processors);
3186
3187 mib[0] = CTL_HW;
3188#ifdef HW_AVAILCPU
3189 mib[1] = HW_AVAILCPU;
3190#else
3191 mib[1] = HW_NCPU;
3192#endif
3193
3194 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
3195 ERROR("Failed to get number of available processors. Defaulting to 1\n");
3196 processors = 1;
3197 }
3198#else
3199 processors = get_nprocs();
3200#endif
3201 }
3202
plougher91fbb302008-05-06 02:29:36 +00003203 if((thread = malloc((2 + processors * 2) * sizeof(pthread_t))) == NULL)
plougher5507dd92006-11-06 00:43:10 +00003204 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00003205 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00003206 frag_deflator_thread = &deflator_thread[processors];
3207
3208 to_reader = queue_init(1);
3209 from_reader = queue_init(reader_buffer_size);
3210 to_writer = queue_init(writer_buffer_size);
3211 from_writer = queue_init(1);
3212 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00003213 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00003214 reader_buffer = cache_init(block_size, reader_buffer_size);
3215 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00003216 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00003217 pthread_create(&thread[0], NULL, reader, NULL);
3218 pthread_create(&thread[1], NULL, writer, NULL);
plougher91fbb302008-05-06 02:29:36 +00003219 pthread_create(&progress_thread, NULL, progress_thrd, NULL);
plougher5507dd92006-11-06 00:43:10 +00003220 pthread_mutex_init(&fragment_mutex, NULL);
3221 pthread_cond_init(&fragment_waiting, NULL);
3222
3223 for(i = 0; i < processors; i++) {
3224 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) != 0 )
3225 BAD_ERROR("Failed to create thread\n");
3226 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator, NULL) != 0)
3227 BAD_ERROR("Failed to create thread\n");
3228 }
3229
3230 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
3231 processors == 1 ? "" : "s");
3232
3233 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
3234 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
3235}
3236
3237
plougher0e453652006-11-06 01:49:35 +00003238long long write_inode_lookup_table()
3239{
3240 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher02bc3bc2007-02-25 12:12:01 +00003241
3242 if(inode_count == sinode_count)
3243 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00003244
3245 if((inode_lookup_table = realloc(inode_lookup_table, lookup_bytes)) == NULL)
3246 BAD_ERROR("Out of memory in write_inode_table\n");
3247
plougher0e453652006-11-06 01:49:35 +00003248 for(i = 0; i < INODE_HASH_SIZE; i ++) {
3249 struct inode_info *inode = inode_info[i];
3250
3251 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00003252
3253 inode_number = inode->type == SQUASHFS_DIR_TYPE ?
3254 inode->inode_number : inode->inode_number + dir_inode_no;
3255
3256 if(!swap)
3257 memcpy(&inode_lookup_table[inode_number - 1], &inode->inode, sizeof(squashfs_inode));
3258 else
3259 SQUASHFS_SWAP_LONG_LONGS((&inode->inode), &inode_lookup_table[inode_number - 1], 1);
3260
plougher0e453652006-11-06 01:49:35 +00003261 }
3262 }
3263
plougher02bc3bc2007-02-25 12:12:01 +00003264skip_inode_hash_table:
plougher0e453652006-11-06 01:49:35 +00003265 return generic_write_table(lookup_bytes, (char *) inode_lookup_table, 0);
3266}
3267
plougher2ea89142008-03-11 01:34:19 +00003268
plougher8f8e1a12007-10-18 02:50:21 +00003269char *get_component(char *target, char *targname)
3270{
3271 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00003272 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00003273
3274 while(*target != '/' && *target!= '\0')
3275 *targname ++ = *target ++;
3276
3277 *targname = '\0';
3278
3279 return target;
3280}
3281
3282
3283void free_path(struct pathname *paths)
3284{
3285 int i;
3286
3287 for(i = 0; i < paths->names; i++) {
3288 if(paths->name[i].paths)
3289 free_path(paths->name[i].paths);
3290 free(paths->name[i].name);
3291 if(paths->name[i].preg) {
3292 regfree(paths->name[i].preg);
3293 free(paths->name[i].preg);
3294 }
3295 }
3296
3297 free(paths);
3298}
3299
3300
3301struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
3302{
3303 char targname[1024];
3304 int i, error;
3305
3306 target = get_component(target, targname);
3307
3308 if(paths == NULL) {
3309 if((paths = malloc(sizeof(struct pathname))) == NULL)
3310 BAD_ERROR("failed to allocate paths\n");
3311
3312 paths->names = 0;
3313 paths->name = NULL;
3314 }
3315
3316 for(i = 0; i < paths->names; i++)
3317 if(strcmp(paths->name[i].name, targname) == 0)
3318 break;
3319
3320 if(i == paths->names) {
3321 /* allocate new name entry */
3322 paths->names ++;
3323 paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry));
3324 paths->name[i].name = strdup(targname);
3325 paths->name[i].paths = NULL;
3326 if(use_regex) {
3327 paths->name[i].preg = malloc(sizeof(regex_t));
plougher23377982007-11-12 04:04:48 +00003328 error = regcomp(paths->name[i].preg, targname, REG_EXTENDED|REG_NOSUB);
3329 if(error) {
plougher8f8e1a12007-10-18 02:50:21 +00003330 char str[1024];
3331
3332 regerror(error, paths->name[i].preg, str, 1024);
3333 BAD_ERROR("invalid regex %s in export %s, because %s\n", targname, alltarget, str);
3334 }
3335 } else
3336 paths->name[i].preg = NULL;
3337
3338 if(target[0] == '\0')
3339 /* at leaf pathname component */
3340 paths->name[i].paths = NULL;
3341 else
3342 /* recurse adding child components */
3343 paths->name[i].paths = add_path(NULL, target, alltarget);
3344 } else {
3345 /* existing matching entry */
3346 if(paths->name[i].paths == NULL) {
3347 /* No sub-directory which means this is the leaf component of a
3348 pre-existing exclude which subsumes the exclude currently
3349 being added, in which case stop adding components */
3350 } else if(target[0] == '\0') {
3351 /* at leaf pathname component and child components exist from more
3352 specific excludes, delete as they're subsumed by this exclude
3353 */
3354 free_path(paths->name[i].paths);
3355 paths->name[i].paths = NULL;
3356 } else
3357 /* recurse adding child components */
3358 add_path(paths->name[i].paths, target, alltarget);
3359 }
3360
3361 return paths;
3362}
plougher2ea89142008-03-11 01:34:19 +00003363
3364
plougher05e50ef2007-10-23 12:34:20 +00003365void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00003366{
plougher05e50ef2007-10-23 12:34:20 +00003367
3368 if(target[0] == '/' || strncmp(target, "./", 2) == 0 || strncmp(target, "../", 3) == 0)
3369 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with -wildcards or -regex options\n");
3370 else if(strncmp(target, "... ", 4) == 0)
3371 stickypath = add_path(stickypath, target + 4, target + 4);
3372 else
3373 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00003374}
3375
3376
3377void display_path(int depth, struct pathname *paths)
3378{
3379 int i, n;
3380
3381 if(paths == NULL)
3382 return;
3383
3384 for(i = 0; i < paths->names; i++) {
3385 for(n = 0; n < depth; n++)
3386 printf("\t");
3387 printf("%d: %s\n", depth, paths->name[i].name);
3388 display_path(depth + 1, paths->name[i].paths);
3389 }
3390}
3391
3392
3393void display_path2(struct pathname *paths, char *string)
3394{
3395 int i;
3396 char path[1024];
3397
3398 if(paths == NULL) {
3399 printf("%s\n", string);
3400 return;
3401 }
3402
3403 for(i = 0; i < paths->names; i++) {
3404 strcat(strcat(strcpy(path, string), "/"), paths->name[i].name);
3405 display_path2(paths->name[i].paths, path);
3406 }
3407}
3408
3409
plougherf9039c92007-10-22 03:54:16 +00003410struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00003411{
plougherf9039c92007-10-22 03:54:16 +00003412 struct pathnames *new = malloc(sizeof(struct pathnames *));
3413 new->count = 0;
3414 return new;
3415}
3416
3417
3418struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
3419{
3420 if(paths->count % PATHS_ALLOC_SIZE == 0)
3421 paths = realloc(paths, sizeof(struct pathnames *) + (paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
3422
3423 paths->path[paths->count++] = path;
3424 return paths;
3425}
3426
3427
3428void free_subdir(struct pathnames *paths)
3429{
3430 free(paths);
3431}
3432
3433
3434int excluded(struct pathnames *paths, char *name, struct pathnames **new)
3435{
3436 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00003437
plougherf9039c92007-10-22 03:54:16 +00003438 if(paths == NULL) {
3439 *new = NULL;
3440 return FALSE;
3441 }
plougher8f8e1a12007-10-18 02:50:21 +00003442
plougherf9039c92007-10-22 03:54:16 +00003443
3444 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00003445 if(stickypath)
3446 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00003447
3448 for(n = 0; n < paths->count; n++) {
3449 struct pathname *path = paths->path[n];
3450
3451 for(i = 0; i < path->names; i++) {
3452 int match = use_regex ?
3453 regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 :
3454 fnmatch(path->name[i].name, name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
3455
3456 if(match && path->name[i].paths == NULL) {
3457 /* match on a leaf component, any subdirectories in the
3458 * filesystem should be excluded */
3459 res = TRUE;
3460 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00003461 }
3462
plougherf9039c92007-10-22 03:54:16 +00003463 if(match)
3464 /* match on a non-leaf component, add any subdirectories to
3465 * the new set of subdirectories to scan for this name */
3466 *new = add_subdir(*new, path->name[i].paths);
3467 }
3468 }
3469
3470 if((*new)->count == 0) {
3471 /* no matching names found, return empty new search set */
3472 res = FALSE;
3473 goto empty_set;
3474 }
3475
3476 /* one or more matches with sub-directories found (no leaf matches).
3477 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00003478 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00003479
3480empty_set:
3481 free_subdir(*new);
3482 *new = NULL;
3483 return res;
plougher8f8e1a12007-10-18 02:50:21 +00003484}
3485
3486
plougher99ac0cc2007-10-29 03:17:10 +00003487#define RECOVER_ID "Squashfs recovery file v1.0\n"
3488#define RECOVER_ID_SIZE 28
3489
3490void write_recovery_data(squashfs_super_block *sBlk)
3491{
3492 int recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
3493 pid_t pid = getpid();
3494 char *metadata;
3495 char header[] = RECOVER_ID;
3496
3497 if(recover == FALSE) {
3498 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00003499 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00003500 return;
3501 }
3502
3503 if((metadata = malloc(bytes)) == NULL)
3504 BAD_ERROR("Failed to alloc metadata buffer in write_recovery_data\n");
3505
3506 read_bytes(fd, sBlk->inode_table_start, bytes, metadata);
3507
plougher32259792007-11-01 06:50:53 +00003508 sprintf(recovery_file, "squashfs_recovery_%s_%d", getbase(destination_file), pid);
plougher99ac0cc2007-10-29 03:17:10 +00003509 if((recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1)
3510 BAD_ERROR("Failed to create recovery file, because %s. Aborting\n", strerror(errno));
3511
3512 if(write(recoverfd, header, RECOVER_ID_SIZE) == -1)
3513 BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno));
3514
3515 if(write(recoverfd, sBlk, sizeof(squashfs_super_block)) == -1)
3516 BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno));
3517
3518 if(write(recoverfd, metadata, bytes) == -1)
3519 BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno));
3520
3521 close(recoverfd);
3522 free(metadata);
3523
3524 printf("Recovery file \"%s\" written\n", recovery_file);
3525 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
3526 printf("mksquashfs dummy %s -recover %s\n", destination_file, recovery_file);
3527 printf("to restore filesystem\n\n");
3528}
3529
3530
3531void read_recovery_data(char *recovery_file, char *destination_file)
3532{
3533 int fd, recoverfd, bytes;
3534 squashfs_super_block orig_sBlk, sBlk;
3535 char *metadata;
3536 int readbytes;
3537 struct stat buf;
3538 char header[] = RECOVER_ID;
3539 char header2[RECOVER_ID_SIZE];
3540
3541 if((recoverfd = open(recovery_file, O_RDONLY)) == -1)
3542 BAD_ERROR("Failed to open recovery file because %s\n", strerror(errno));
3543
3544 if(stat(destination_file, &buf) == -1)
3545 BAD_ERROR("Failed to stat destination file, because %s\n", strerror(errno));
3546
3547 if((fd = open(destination_file, O_RDWR)) == -1)
3548 BAD_ERROR("Failed to open destination file because %s\n", strerror(errno));
3549
3550 if(read(recoverfd, header2, RECOVER_ID_SIZE) == -1)
3551 BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno));
3552 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
3553 BAD_ERROR("Not a recovery file\n");
3554
3555 if(read(recoverfd, &sBlk, sizeof(squashfs_super_block)) == -1)
3556 BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno));
3557
3558 read_bytes(fd, 0, sizeof(squashfs_super_block), (char *) &orig_sBlk);
3559
3560 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4, sizeof(squashfs_super_block) - 4) != 0)
3561 BAD_ERROR("Recovery file and destination file do not seem to match\n");
3562
3563 bytes = sBlk.bytes_used - sBlk.inode_table_start;
3564
3565 if((metadata = malloc(bytes)) == NULL)
3566 BAD_ERROR("Failed to alloc metadata buffer in read_recovery_data\n");
3567
3568 if((readbytes = read(recoverfd, metadata, bytes)) == -1)
3569 BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno));
3570
3571 if(readbytes != bytes)
3572 BAD_ERROR("Recovery file appears to be truncated\n");
3573
3574 write_bytes(fd, 0, sizeof(squashfs_super_block), (char *) &sBlk);
3575
3576 write_bytes(fd, sBlk.inode_table_start, bytes, metadata);
3577
3578 close(recoverfd);
3579 close(fd);
3580
3581 printf("Successfully wrote recovery file \"%s\". Exiting\n", recovery_file);
3582
3583 exit(0);
3584}
3585
3586
plougher1f413c82005-11-18 00:02:14 +00003587#define VERSION() \
plougher57e6d182008-05-06 23:51:29 +00003588 printf("mksquashfs version 3.3-CVS (2008/05/05)\n");\
plougher91fbb302008-05-06 02:29:36 +00003589 printf("copyright (C) 2008 Phillip Lougher <phillip@lougher.demon.co.uk>\n\n"); \
plougher76c64082008-03-08 01:32:23 +00003590 printf("This program is free software; you can redistribute it and/or\n");\
plougher1f413c82005-11-18 00:02:14 +00003591 printf("modify it under the terms of the GNU General Public License\n");\
3592 printf("as published by the Free Software Foundation; either version 2,\n");\
3593 printf("or (at your option) any later version.\n\n");\
3594 printf("This program is distributed in the hope that it will be useful,\n");\
3595 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
3596 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\
3597 printf("GNU General Public License for more details.\n");
3598int main(int argc, char *argv[])
3599{
plougher324978d2006-02-27 04:53:29 +00003600 struct stat buf, source_buf;
plougher1f413c82005-11-18 00:02:14 +00003601 int i;
3602 squashfs_super_block sBlk;
3603 char *b, *root_name = NULL;
plougher324978d2006-02-27 04:53:29 +00003604 int be, nopad = FALSE, keep_as_directory = FALSE, orig_be;
plougher1f413c82005-11-18 00:02:14 +00003605 squashfs_inode inode;
plougher76c64082008-03-08 01:32:23 +00003606 int readb_mbytes = READER_BUFFER_DEFAULT, writeb_mbytes = WRITER_BUFFER_DEFAULT, fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
plougher4c99cb72007-06-14 21:46:31 +00003607 int s_minor;
plougher1f413c82005-11-18 00:02:14 +00003608
3609#if __BYTE_ORDER == __BIG_ENDIAN
3610 be = TRUE;
3611#else
3612 be = FALSE;
3613#endif
3614
plougher91fbb302008-05-06 02:29:36 +00003615 pthread_mutex_init(&progress_mutex, NULL);
plougher1f413c82005-11-18 00:02:14 +00003616 block_log = slog(block_size);
3617 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
3618 VERSION();
3619 exit(0);
3620 }
3621 for(i = 1; i < argc && argv[i][0] != '-'; i++);
3622 if(i < 3)
3623 goto printOptions;
3624 source_path = argv + 1;
3625 source = i - 2;
3626 for(; i < argc; i++) {
plougher99ac0cc2007-10-29 03:17:10 +00003627 if(strcmp(argv[i], "-recover") == 0) {
3628 if(++i == argc) {
3629 ERROR("%s: -recover missing recovery file\n", argv[0]);
3630 exit(1);
3631 }
3632 read_recovery_data(argv[i], argv[source + 1]);
3633 } else if(strcmp(argv[i], "-no-recovery") == 0)
3634 recover = FALSE;
3635 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00003636 old_exclude = FALSE;
3637 use_regex = FALSE;
3638 } else if(strcmp(argv[i], "-regex") == 0) {
3639 old_exclude = FALSE;
3640 use_regex = TRUE;
3641 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00003642 sparse_files = FALSE;
3643 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00003644 progress = FALSE;
3645 else if(strcmp(argv[i], "-no-exports") == 0)
3646 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00003647 else if(strcmp(argv[i], "-processors") == 0) {
plougher5507dd92006-11-06 00:43:10 +00003648 if((++i == argc) || (processors = strtol(argv[i], &b, 10), *b != '\0')) {
3649 ERROR("%s: -processors missing or invalid processor number\n", argv[0]);
3650 exit(1);
3651 }
3652 if(processors < 1) {
3653 ERROR("%s: -processors should be 1 or larger\n", argv[0]);
3654 exit(1);
3655 }
plougher0e453652006-11-06 01:49:35 +00003656 } else if(strcmp(argv[i], "-read-queue") == 0) {
plougher5507dd92006-11-06 00:43:10 +00003657 if((++i == argc) || (readb_mbytes = strtol(argv[i], &b, 10), *b != '\0')) {
plougher0e453652006-11-06 01:49:35 +00003658 ERROR("%s: -read-queue missing or invalid queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00003659 exit(1);
3660 }
3661 if(readb_mbytes < 1) {
plougher0e453652006-11-06 01:49:35 +00003662 ERROR("%s: -read-queue should be 1 megabyte or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00003663 exit(1);
3664 }
plougher0e453652006-11-06 01:49:35 +00003665 } else if(strcmp(argv[i], "-write-queue") == 0) {
plougher5507dd92006-11-06 00:43:10 +00003666 if((++i == argc) || (writeb_mbytes = strtol(argv[i], &b, 10), *b != '\0')) {
plougher0e453652006-11-06 01:49:35 +00003667 ERROR("%s: -write-queue missing or invalid queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00003668 exit(1);
3669 }
3670 if(writeb_mbytes < 1) {
plougher0e453652006-11-06 01:49:35 +00003671 ERROR("%s: -write-queue should be 1 megabyte or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00003672 exit(1);
3673 }
plougher217bad82008-04-05 11:36:41 +00003674 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
3675 if((++i == argc) || (fragmentb_mbytes = strtol(argv[i], &b, 10), *b != '\0')) {
3676 ERROR("%s: -fragment-queue missing or invalid queue size\n", argv[0]);
3677 exit(1);
3678 }
3679 if(fragmentb_mbytes < 1) {
3680 ERROR("%s: -fragment-queue should be 1 megabyte or larger\n", argv[0]);
3681 exit(1);
3682 }
plougher5507dd92006-11-06 00:43:10 +00003683 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00003684 if(++i == argc) {
3685 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00003686 exit(1);
3687 }
plougher4c99cb72007-06-14 21:46:31 +00003688 block_size = strtol(argv[i], &b, 10);
3689 if(*b == 'm' || *b == 'M')
3690 block_size *= 1048576;
3691 else if(*b == 'k' || *b == 'K')
3692 block_size *= 1024;
3693 else if(*b != '\0') {
3694 ERROR("%s: -b invalid block size\n", argv[0]);
3695 exit(1);
3696 }
plougher1f413c82005-11-18 00:02:14 +00003697 if((block_log = slog(block_size)) == 0) {
plougher4c99cb72007-06-14 21:46:31 +00003698 ERROR("%s: -b block size not power of two or not between 4096 and 1Mbyte\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00003699 exit(1);
3700 }
3701 } else if(strcmp(argv[i], "-ef") == 0) {
3702 if(++i == argc) {
3703 ERROR("%s: -ef missing filename\n", argv[0]);
3704 exit(1);
3705 }
plougher9b5bf8c2006-03-20 18:43:33 +00003706 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00003707 duplicate_checking = FALSE;
3708
3709 else if(strcmp(argv[i], "-no-fragments") == 0)
3710 no_fragments = TRUE;
3711
3712 else if(strcmp(argv[i], "-always-use-fragments") == 0)
3713 always_use_fragments = TRUE;
3714
3715 else if(strcmp(argv[i], "-sort") == 0) {
3716 if(++i == argc) {
3717 ERROR("%s: -sort missing filename\n", argv[0]);
3718 exit(1);
3719 }
3720 } else if(strcmp(argv[i], "-all-root") == 0 ||
3721 strcmp(argv[i], "-root-owned") == 0)
3722 global_uid = global_gid = 0;
3723
3724 else if(strcmp(argv[i], "-force-uid") == 0) {
3725 if(++i == argc) {
3726 ERROR("%s: -force-uid missing uid or user\n", argv[0]);
3727 exit(1);
3728 }
3729 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
3730 if(global_uid < 0 || global_uid > (((long long) 1 << 32) - 1)) {
3731 ERROR("%s: -force-uid uid out of range\n", argv[0]);
3732 exit(1);
3733 }
3734 } else {
3735 struct passwd *uid = getpwnam(argv[i]);
3736 if(uid)
3737 global_uid = uid->pw_uid;
3738 else {
3739 ERROR("%s: -force-uid invalid uid or unknown user\n", argv[0]);
3740 exit(1);
3741 }
3742 }
3743 } else if(strcmp(argv[i], "-force-gid") == 0) {
3744 if(++i == argc) {
3745 ERROR("%s: -force-gid missing gid or group\n", argv[0]);
3746 exit(1);
3747 }
3748 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
3749 if(global_gid < 0 || global_gid > (((long long) 1 << 32) - 1)) {
3750 ERROR("%s: -force-gid gid out of range\n", argv[0]);
3751 exit(1);
3752 }
3753 } else {
3754 struct group *gid = getgrnam(argv[i]);
3755 if(gid)
3756 global_gid = gid->gr_gid;
3757 else {
3758 ERROR("%s: -force-gid invalid gid or unknown group\n", argv[0]);
3759 exit(1);
3760 }
3761 }
3762 } else if(strcmp(argv[i], "-noI") == 0 ||
3763 strcmp(argv[i], "-noInodeCompression") == 0)
3764 noI = TRUE;
3765
3766 else if(strcmp(argv[i], "-noD") == 0 ||
3767 strcmp(argv[i], "-noDataCompression") == 0)
3768 noD = TRUE;
3769
3770 else if(strcmp(argv[i], "-noF") == 0 ||
3771 strcmp(argv[i], "-noFragmentCompression") == 0)
3772 noF = TRUE;
3773
3774 else if(strcmp(argv[i], "-nopad") == 0)
3775 nopad = TRUE;
3776
3777 else if(strcmp(argv[i], "-check_data") == 0)
3778 check_data = TRUE;
3779
plougher91fbb302008-05-06 02:29:36 +00003780 else if(strcmp(argv[i], "-info") == 0) {
3781 silent = FALSE;
3782 progress = FALSE;
3783 }
plougher1f413c82005-11-18 00:02:14 +00003784 else if(strcmp(argv[i], "-be") == 0)
3785 be = TRUE;
3786
3787 else if(strcmp(argv[i], "-le") == 0)
3788 be = FALSE;
3789
3790 else if(strcmp(argv[i], "-e") == 0)
3791 break;
3792
3793 else if(strcmp(argv[i], "-noappend") == 0)
3794 delete = TRUE;
3795
3796 else if(strcmp(argv[i], "-keep-as-directory") == 0)
3797 keep_as_directory = TRUE;
3798
3799 else if(strcmp(argv[i], "-root-becomes") == 0) {
3800 if(++i == argc) {
3801 ERROR("%s: -root-becomes: missing name\n", argv[0]);
3802 exit(1);
3803 }
3804 root_name = argv[i];
3805 } else if(strcmp(argv[i], "-version") == 0) {
3806 VERSION();
3807 } else {
3808 ERROR("%s: invalid option\n\n", argv[0]);
3809printOptions:
3810 ERROR("SYNTAX:%s source1 source2 ... dest [options] [-e list of exclude\ndirs/files]\n", argv[0]);
3811 ERROR("\nOptions are\n");
3812 ERROR("-version\t\tprint version, licence and copyright message\n");
plougher99ac0cc2007-10-29 03:17:10 +00003813 ERROR("-recover <name>\t\trecover filesystem data using recovery file <name>\n");
3814 ERROR("-no-recovery\t\tdon't generate a recovery file\n");
plougher1f413c82005-11-18 00:02:14 +00003815 ERROR("-info\t\t\tprint files written to filesystem\n");
plougher02bc3bc2007-02-25 12:12:01 +00003816 ERROR("-no-exports\t\tdon't make the filesystem exportable via NFS\n");
3817 ERROR("-no-progress\t\tdon't display the progress bar\n");
plougher1f54edc2007-08-12 23:13:36 +00003818 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher1f413c82005-11-18 00:02:14 +00003819 ERROR("-b <block_size>\t\tset data block to <block_size>. Default %d bytes\n", SQUASHFS_FILE_SIZE);
plougher5507dd92006-11-06 00:43:10 +00003820 ERROR("-processors <number>\tUse <number> processors. By default will use number of\n\t\t\tprocessors available\n");
3821 ERROR("-read-queue <size>\tSet input queue to <size> Mbytes. Default %d Mbytes\n", READER_BUFFER_DEFAULT);
3822 ERROR("-write-queue <size>\tSet output queue to <size> Mbytes. Default %d Mbytes\n", WRITER_BUFFER_DEFAULT);
plougher217bad82008-04-05 11:36:41 +00003823 ERROR("-fragment-queue <size>\tSet fagment queue to <size> Mbytes. Default %d Mbytes\n", FRAGMENT_BUFFER_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00003824 ERROR("-noI\t\t\tdo not compress inode table\n");
3825 ERROR("-noD\t\t\tdo not compress data blocks\n");
3826 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
3827 ERROR("-no-fragments\t\tdo not use fragments\n");
3828 ERROR("-always-use-fragments\tuse fragment blocks for files larger than block size\n");
3829 ERROR("-no-duplicates\t\tdo not perform duplicate checking\n");
3830 ERROR("-noappend\t\tdo not append to existing filesystem\n");
3831 ERROR("-keep-as-directory\tif one source directory is specified, create a root\n");
3832 ERROR("\t\t\tdirectory containing that directory, rather than the\n");
3833 ERROR("\t\t\tcontents of the directory\n");
3834 ERROR("-root-becomes <name>\twhen appending source files/directories, make the\n");
3835 ERROR("\t\t\toriginal root become a subdirectory in the new root\n");
3836 ERROR("\t\t\tcalled <name>, rather than adding the new source items\n");
3837 ERROR("\t\t\tto the original root\n");
3838 ERROR("-all-root\t\tmake all files owned by root\n");
3839 ERROR("-force-uid uid\t\tset all file uids to uid\n");
3840 ERROR("-force-gid gid\t\tset all file gids to gid\n");
3841 ERROR("-le\t\t\tcreate a little endian filesystem\n");
3842 ERROR("-be\t\t\tcreate a big endian filesystem\n");
3843 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple of 4K\n");
3844 ERROR("-check_data\t\tadd checkdata for greater filesystem checks\n");
3845 ERROR("-root-owned\t\talternative name for -all-root\n");
3846 ERROR("-noInodeCompression\talternative name for -noI\n");
3847 ERROR("-noDataCompression\talternative name for -noD\n");
3848 ERROR("-noFragmentCompression\talternative name for -noF\n");
3849 ERROR("-sort <sort_file>\tsort files according to priorities in <sort_file>. One\n");
3850 ERROR("\t\t\tfile or dir with priority per line. Priority -32768 to\n");
3851 ERROR("\t\t\t32767, default priority 0\n");
3852 ERROR("-ef <exclude_file>\tlist of exclude dirs/files. One per line\n");
plougher934a9ed2007-10-19 00:21:10 +00003853 ERROR("-wildcards\t\tAllow extended shell wildcards (globbing) to be used in\n\t\t\texclude dirs/files\n");
3854 ERROR("-regex\t\t\tAllow POSIX regular expressions to be used in exclude\n\t\t\tdirs/files\n");
plougher1f413c82005-11-18 00:02:14 +00003855 exit(1);
3856 }
3857 }
3858
plougher5507dd92006-11-06 00:43:10 +00003859 reader_buffer_size = readb_mbytes << (20 - block_log);
3860 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher76c64082008-03-08 01:32:23 +00003861 fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00003862
plougher1f54edc2007-08-12 23:13:36 +00003863 if(block_size <= 65536 && sparse_files == FALSE)
plougher4c99cb72007-06-14 21:46:31 +00003864 s_minor = 0;
3865 else
3866 s_minor = SQUASHFS_MINOR;
3867
plougher91fbb302008-05-06 02:29:36 +00003868 for(i = 0; i < source; i++)
3869 if(lstat(source_path[i], &source_buf) == -1) {
3870 fprintf(stderr, "Cannot stat source directory \"%s\" because %s\n", source_path[i], strerror(errno));
3871 EXIT_MKSQUASHFS();
3872 }
plougher324978d2006-02-27 04:53:29 +00003873
3874 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00003875 if(stat(argv[source + 1], &buf) == -1) {
3876 if(errno == ENOENT) { /* Does not exist */
3877 if((fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) {
3878 perror("Could not create destination file");
3879 exit(1);
3880 }
3881 delete = TRUE;
3882 } else {
3883 perror("Could not stat destination file");
3884 exit(1);
3885 }
3886
3887 } else {
3888 if(S_ISBLK(buf.st_mode)) {
3889 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
3890 perror("Could not open block device as destination");
3891 exit(1);
3892 }
3893 block_device = 1;
3894
3895 } else if(S_ISREG(buf.st_mode)) {
3896 if((fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | O_RDWR)) == -1) {
3897 perror("Could not open regular file for writing as destination");
3898 exit(1);
3899 }
3900 }
3901 else {
3902 ERROR("Destination not block device or regular file\n");
3903 exit(1);
3904 }
3905
plougher324978d2006-02-27 04:53:29 +00003906 }
plougher1f413c82005-11-18 00:02:14 +00003907
plougher4c99cb72007-06-14 21:46:31 +00003908 signal(SIGTERM, sighandler2);
3909 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00003910
3911 /* process the exclude files - must be done afer destination file has been possibly created */
3912 for(i = source + 2; i < argc; i++)
3913 if(strcmp(argv[i], "-ef") == 0) {
3914 FILE *fd;
3915 char filename[16385];
3916 if((fd = fopen(argv[++i], "r")) == NULL) {
3917 perror("Could not open exclude file...");
plougher324978d2006-02-27 04:53:29 +00003918 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00003919 }
3920 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
plougher8f8e1a12007-10-18 02:50:21 +00003921 if(old_exclude)
3922 old_add_exclude(filename);
3923 else
plougher05e50ef2007-10-23 12:34:20 +00003924 add_exclude(filename);
plougher1f413c82005-11-18 00:02:14 +00003925 fclose(fd);
3926 } else if(strcmp(argv[i], "-e") == 0)
3927 break;
3928 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-sort") == 0)
3929 i++;
3930
3931 if(i != argc) {
3932 if(++i == argc) {
3933 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00003934 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00003935 }
plougher8f8e1a12007-10-18 02:50:21 +00003936 while(i < argc)
3937 if(old_exclude)
3938 old_add_exclude(argv[i++]);
3939 else
plougher05e50ef2007-10-23 12:34:20 +00003940 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00003941 }
3942
3943 /* process the sort files - must be done afer the exclude files */
3944 for(i = source + 2; i < argc; i++)
3945 if(strcmp(argv[i], "-sort") == 0) {
3946 read_sort_file(argv[++i], source, source_path);
3947 sorted ++;
3948 } else if(strcmp(argv[i], "-e") == 0)
3949 break;
3950 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0)
3951 i++;
3952
plougher4c99cb72007-06-14 21:46:31 +00003953 if(!delete) {
3954 if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) {
3955 ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
ploughereac18532007-10-29 05:26:06 +00003956 ERROR("To force Mksquashfs to write to this block device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00003957 EXIT_MKSQUASHFS();
3958 }
plougher1f413c82005-11-18 00:02:14 +00003959
3960 be = orig_be;
3961 block_log = slog(block_size = sBlk.block_size);
plougher4c99cb72007-06-14 21:46:31 +00003962 s_minor = sBlk.s_minor;
plougher1f413c82005-11-18 00:02:14 +00003963 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
3964 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
3965 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
3966 check_data = SQUASHFS_CHECK_DATA(sBlk.flags);
3967 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
3968 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
3969 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00003970 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00003971 }
3972
3973 initialise_threads();
3974
3975 if(delete) {
3976 printf("Creating %s %d.%d filesystem on %s, block size %d.\n",
3977 be ? "big endian" : "little endian", SQUASHFS_MAJOR, s_minor, argv[source + 1], block_size);
3978 bytes = sizeof(squashfs_super_block);
3979 } else {
3980 unsigned int last_directory_block, inode_dir_offset, inode_dir_file_size, root_inode_size,
3981 inode_dir_start_block, uncompressed_data, compressed_data, inode_dir_inode_number,
3982 inode_dir_parent_inode;
3983 unsigned int root_inode_start = SQUASHFS_INODE_BLK(sBlk.root_inode), root_inode_offset =
3984 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
3985
plougher1f413c82005-11-18 00:02:14 +00003986 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &data_cache,
3987 &directory_table, &directory_data_cache, &last_directory_block, &inode_dir_offset,
3988 &inode_dir_file_size, &root_inode_size, &inode_dir_start_block,
3989 &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count,
3990 (squashfs_uid *) uids, &uid_count, (squashfs_uid *) guids, &guid_count,
plougherdf70c3e2006-01-27 09:34:13 +00003991 &total_bytes, &total_inode_bytes, &total_directory_bytes, &inode_dir_inode_number,
plougher0e453652006-11-06 01:49:35 +00003992 &inode_dir_parent_inode, add_old_root_entry, &fragment_table, &inode_lookup_table)) == 0) {
plougher1f413c82005-11-18 00:02:14 +00003993 ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
ploughereac18532007-10-29 05:26:06 +00003994 ERROR("To force Mksquashfs to write to this block device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00003995 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00003996 }
3997 if((fragments = sBlk.fragments))
3998 fragment_table = (squashfs_fragment_entry *) realloc((char *) fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(squashfs_fragment_entry));
3999
4000 printf("Appending to existing %s %d.%d filesystem on %s, block size %d\n", be ? "big endian" :
plougher4c99cb72007-06-14 21:46:31 +00004001 "little endian", SQUASHFS_MAJOR, s_minor, argv[source + 1], block_size);
plougher0e453652006-11-06 01:49:35 +00004002 printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments and -exportable options ignored\n");
plougher1f413c82005-11-18 00:02:14 +00004003 printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n");
4004
plougher23377982007-11-12 04:04:48 +00004005 compressed_data = (inode_dir_offset + inode_dir_file_size) & ~(SQUASHFS_METADATA_SIZE - 1);
4006 uncompressed_data = (inode_dir_offset + inode_dir_file_size) & (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00004007
4008 /* save original filesystem state for restoring ... */
4009 sfragments = fragments;
4010 sbytes = bytes;
4011 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00004012 scache_bytes = root_inode_offset + root_inode_size;
4013 sdirectory_cache_bytes = uncompressed_data;
4014 sdata_cache = (char *)malloc(scache_bytes);
4015 sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00004016 memcpy(sdata_cache, data_cache, scache_bytes);
4017 memcpy(sdirectory_data_cache, directory_data_cache + compressed_data, sdirectory_cache_bytes);
4018 sinode_bytes = root_inode_start;
4019 sdirectory_bytes = last_directory_block;
4020 suid_count = uid_count;
4021 sguid_count = guid_count;
4022 stotal_bytes = total_bytes;
4023 stotal_inode_bytes = total_inode_bytes;
4024 stotal_directory_bytes = total_directory_bytes + compressed_data;
4025 sfile_count = file_count;
4026 ssym_count = sym_count;
4027 sdev_count = dev_count;
4028 sdir_count = dir_count + 1;
4029 sfifo_count = fifo_count;
4030 ssock_count = sock_count;
4031 sdup_files = dup_files;
plougher99ac0cc2007-10-29 03:17:10 +00004032 write_recovery_data(&sBlk);
plougher1f413c82005-11-18 00:02:14 +00004033 restore = TRUE;
4034 if(setjmp(env))
4035 goto restore_filesystem;
4036 signal(SIGTERM, sighandler);
4037 signal(SIGINT, sighandler);
4038 write_bytes(fd, SQUASHFS_START, 4, "\0\0\0\0");
4039
4040 /* set the filesystem state up to be able to append to the original filesystem. The filesystem state
4041 * differs depending on whether we're appending to the original root directory, or if the original
4042 * root directory becomes a sub-directory (root-becomes specified on command line, here root_name != NULL)
4043 */
4044 inode_bytes = inode_size = root_inode_start;
4045 directory_size = last_directory_block;
4046 cache_size = root_inode_offset + root_inode_size;
4047 directory_cache_size = inode_dir_offset + inode_dir_file_size;
4048 if(root_name) {
plougherdf70c3e2006-01-27 09:34:13 +00004049 root_inode_number = inode_dir_parent_inode;
4050 dir_inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00004051 directory_bytes = last_directory_block;
4052 directory_cache_bytes = uncompressed_data;
4053 memmove(directory_data_cache, directory_data_cache + compressed_data, uncompressed_data);
4054 cache_bytes = root_inode_offset + root_inode_size;
plougherdf70c3e2006-01-27 09:34:13 +00004055 add_old_root_entry(root_name, sBlk.root_inode, inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00004056 total_directory_bytes += compressed_data;
4057 dir_count ++;
4058 } else {
plougherdf70c3e2006-01-27 09:34:13 +00004059 root_inode_number = inode_dir_inode_number;
plougher778e9362006-02-01 09:32:31 +00004060 dir_inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00004061 directory_bytes = inode_dir_start_block;
4062 directory_cache_bytes = inode_dir_offset;
4063 cache_bytes = root_inode_offset;
4064 }
4065
4066 inode_count = file_count + dir_count + sym_count + dev_count + fifo_count + sock_count;
4067 }
4068
4069#if __BYTE_ORDER == __BIG_ENDIAN
4070 swap = !be;
4071#else
4072 swap = be;
4073#endif
4074
4075 block_offset = check_data ? 3 : 2;
4076
plougher05e50ef2007-10-23 12:34:20 +00004077 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00004078 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00004079 if(path)
4080 paths = add_subdir(paths, path);
4081 if(stickypath)
4082 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004083 }
4084
plougher324978d2006-02-27 04:53:29 +00004085 if(delete && !keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00004086 dir_scan(&inode, source_path[0], scan1_readdir);
plougher324978d2006-02-27 04:53:29 +00004087 else if(!keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00004088 dir_scan(&inode, source_path[0], scan1_single_readdir);
4089 else
4090 dir_scan(&inode, "", scan1_encomp_readdir);
4091 sBlk.root_inode = inode;
4092 sBlk.inodes = inode_count;
4093 sBlk.s_magic = SQUASHFS_MAGIC;
4094 sBlk.s_major = SQUASHFS_MAJOR;
plougher4c99cb72007-06-14 21:46:31 +00004095 sBlk.s_minor = s_minor;
plougher1f413c82005-11-18 00:02:14 +00004096 sBlk.block_size = block_size;
4097 sBlk.block_log = block_log;
plougher0e453652006-11-06 01:49:35 +00004098 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, check_data, noF, no_fragments, always_use_fragments, duplicate_checking, exportable);
plougher1f413c82005-11-18 00:02:14 +00004099 sBlk.mkfs_time = time(NULL);
4100
4101restore_filesystem:
plougher91fbb302008-05-06 02:29:36 +00004102 disable_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004103 write_fragment();
4104 sBlk.fragments = fragments;
plougher5507dd92006-11-06 00:43:10 +00004105 if(interrupted < 2) {
plougher2ea89142008-03-11 01:34:19 +00004106 unlock_fragments();
4107 pthread_mutex_lock(&fragment_mutex);
4108 while(fragments_outstanding) {
4109 pthread_mutex_unlock(&fragment_mutex);
4110 sched_yield();
4111 pthread_mutex_lock(&fragment_mutex);
4112 }
plougher5507dd92006-11-06 00:43:10 +00004113 queue_put(to_writer, NULL);
4114 if(queue_get(from_writer) != 0)
4115 EXIT_MKSQUASHFS();
4116 }
4117
plougher1f413c82005-11-18 00:02:14 +00004118 sBlk.inode_table_start = write_inodes();
4119 sBlk.directory_table_start = write_directories();
4120 sBlk.fragment_table_start = write_fragment_table();
plougher0e453652006-11-06 01:49:35 +00004121 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() : SQUASHFS_INVALID_BLK;
plougher1f413c82005-11-18 00:02:14 +00004122
plougher0e453652006-11-06 01:49:35 +00004123 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
4124 TRACE("sBlk->directory_table_start 0x%llx\n", sBlk.directory_table_start);
4125 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
4126 if(exportable)
4127 TRACE("sBlk->lookup_table_start 0x%llx\n", sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00004128
plougher23377982007-11-12 04:04:48 +00004129 sBlk.no_uids = uid_count;
4130 if(sBlk.no_uids) {
plougher1f413c82005-11-18 00:02:14 +00004131 if(!swap)
4132 write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids);
4133 else {
4134 squashfs_uid uids_copy[uid_count];
4135
4136 SQUASHFS_SWAP_DATA(uids, uids_copy, uid_count, sizeof(squashfs_uid) * 8);
4137 write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids_copy);
4138 }
4139 sBlk.uid_start = bytes;
4140 bytes += uid_count * sizeof(squashfs_uid);
4141 } else
4142 sBlk.uid_start = 0;
4143
plougher23377982007-11-12 04:04:48 +00004144 sBlk.no_guids = guid_count;
4145 if(sBlk.no_guids) {
plougher1f413c82005-11-18 00:02:14 +00004146 if(!swap)
4147 write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids);
4148 else {
4149 squashfs_uid guids_copy[guid_count];
4150
4151 SQUASHFS_SWAP_DATA(guids, guids_copy, guid_count, sizeof(squashfs_uid) * 8);
4152 write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids_copy);
4153 }
4154 sBlk.guid_start = bytes;
4155 bytes += guid_count * sizeof(squashfs_uid);
4156 } else
4157 sBlk.guid_start = 0;
4158
4159 sBlk.bytes_used = bytes;
4160
plougher1f413c82005-11-18 00:02:14 +00004161 if(!swap)
4162 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk);
4163 else {
4164 squashfs_super_block sBlk_copy;
4165
4166 SQUASHFS_SWAP_SUPER_BLOCK((&sBlk), &sBlk_copy);
4167 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_copy);
4168 }
4169
4170 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00004171 char temp[4096] = {0};
plougher1f413c82005-11-18 00:02:14 +00004172 write_bytes(fd, bytes, 4096 - i, temp);
4173 }
4174
plougher99ac0cc2007-10-29 03:17:10 +00004175 close(fd);
4176
4177 if(recovery_file[0] != '\0')
4178 unlink(recovery_file);
4179
plougher1f413c82005-11-18 00:02:14 +00004180 total_bytes += total_inode_bytes + total_directory_bytes + uid_count
4181 * sizeof(unsigned short) + guid_count * sizeof(unsigned short) +
4182 sizeof(squashfs_super_block);
4183
plougher0e453652006-11-06 01:49:35 +00004184 printf("\n%s%s filesystem, data block size %d, %s data, %s metadata, %s fragments, duplicates are %sremoved\n",
4185 exportable ? "Exportable " : "", be ? "Big endian" : "Little endian", block_size,
4186 noD ? "uncompressed" : "compressed", noI ? "uncompressed" : "compressed",
4187 no_fragments ? "no" : noF ? "uncompressed" : "compressed", duplicate_checking ? "" : "not ");
plougher1f413c82005-11-18 00:02:14 +00004188 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0));
4189 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
4190 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
4191 printf("Inode table size %d bytes (%.2f Kbytes)\n",
4192 inode_bytes, inode_bytes / 1024.0);
4193 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
4194 ((float) inode_bytes / total_inode_bytes) * 100.0, total_inode_bytes);
4195 printf("Directory table size %d bytes (%.2f Kbytes)\n",
4196 directory_bytes, directory_bytes / 1024.0);
4197 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
4198 ((float) directory_bytes / total_directory_bytes) * 100.0, total_directory_bytes);
4199 if(duplicate_checking)
4200 printf("Number of duplicate files found %d\n", file_count - dup_files);
4201 else
4202 printf("No duplicate files removed\n");
4203 printf("Number of inodes %d\n", inode_count);
4204 printf("Number of files %d\n", file_count);
4205 if(!no_fragments)
4206 printf("Number of fragments %d\n", fragments);
4207 printf("Number of symbolic links %d\n", sym_count);
4208 printf("Number of device nodes %d\n", dev_count);
4209 printf("Number of fifo nodes %d\n", fifo_count);
4210 printf("Number of socket nodes %d\n", sock_count);
4211 printf("Number of directories %d\n", dir_count);
4212 printf("Number of uids %d\n", uid_count);
4213
4214 for(i = 0; i < uid_count; i++) {
plougher29e37092007-04-15 01:24:51 +00004215 int uid = uids[i];
4216 struct passwd *user = getpwuid(uid);
plougher1f413c82005-11-18 00:02:14 +00004217 printf("\t%s (%d)\n", user == NULL ? "unknown" : user->pw_name, uids[i]);
4218 }
4219
4220 printf("Number of gids %d\n", guid_count);
4221
4222 for(i = 0; i < guid_count; i++) {
4223 struct group *group = getgrgid(guids[i]);
4224 printf("\t%s (%d)\n", group == NULL ? "unknown" : group->gr_name, guids[i]);
4225 }
plougher99ac0cc2007-10-29 03:17:10 +00004226
plougher1f413c82005-11-18 00:02:14 +00004227 return 0;
4228}