blob: daaeb1f41e3b602ed9e96a7d9ea3e16b47fabfd6 [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
plougher16111452010-07-22 05:12:18 +00002 * Create a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
plougher1f413c82005-11-18 00:02:14 +00004 *
plougher8d4404d2010-07-21 03:16:55 +00005 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
plougherf6cd3372007-08-19 03:33:23 +00006 * Phillip Lougher <phillip@lougher.demon.co.uk>
plougher1f413c82005-11-18 00:02:14 +00007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * mksquashfs.c
23 */
24
plougher324978d2006-02-27 04:53:29 +000025#define FALSE 0
plougher1f413c82005-11-18 00:02:14 +000026#define TRUE 1
plougher8cb05cd2005-12-11 23:32:35 +000027
plougher1f413c82005-11-18 00:02:14 +000028#include <pwd.h>
29#include <grp.h>
30#include <time.h>
31#include <unistd.h>
32#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000033#include <stddef.h>
plougher35a10602008-04-21 02:58:16 +000034#include <sys/time.h>
plougher1f413c82005-11-18 00:02:14 +000035#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <dirent.h>
40#include <string.h>
plougher1f413c82005-11-18 00:02:14 +000041#include <stdlib.h>
42#include <signal.h>
43#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000044#include <sys/ioctl.h>
45#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000046#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000047#include <pthread.h>
plougher02bc3bc2007-02-25 12:12:01 +000048#include <math.h>
plougher8f8e1a12007-10-18 02:50:21 +000049#include <regex.h>
50#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000051#include <sys/wait.h>
plougher1f413c82005-11-18 00:02:14 +000052
plougher68853292005-12-27 02:47:04 +000053#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000054#define __BYTE_ORDER BYTE_ORDER
55#define __BIG_ENDIAN BIG_ENDIAN
56#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000057#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000058#else
59#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000060#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000061#endif
62
plougher1b899fc2008-08-07 01:24:06 +000063#include "squashfs_fs.h"
plougher1f413c82005-11-18 00:02:14 +000064#include "global.h"
plougher3c6bdb52010-05-01 02:30:59 +000065#include "squashfs_swap.h"
plougherf5456bd2010-05-01 01:11:32 +000066#include "mksquashfs.h"
plougher117b2ea2006-02-09 09:23:56 +000067#include "sort.h"
plougher43244f22009-04-05 02:04:51 +000068#include "pseudo.h"
plougher7b8ee502009-07-29 07:54:30 +000069#include "compressor.h"
ploughere6e0e1b2010-05-12 17:17:06 +000070#include "xattr.h"
plougher1f413c82005-11-18 00:02:14 +000071
72#ifdef SQUASHFS_TRACE
plougher16111452010-07-22 05:12:18 +000073#define TRACE(s, args...) \
74 do { \
75 if(progress_enabled) \
76 printf("\n"); \
77 printf("mksquashfs: "s, ## args); \
78 } while(0)
plougher1f413c82005-11-18 00:02:14 +000079#else
80#define TRACE(s, args...)
81#endif
82
plougher16111452010-07-22 05:12:18 +000083#define INFO(s, args...) \
84 do {\
85 if(!silent)\
86 printf("mksquashfs: "s, ## args);\
87 } while(0)
88
89#define ERROR(s, args...) \
90 do {\
91 pthread_mutex_lock(&progress_mutex); \
92 if(progress_enabled) \
93 fprintf(stderr, "\n"); \
94 fprintf(stderr, s, ## args);\
95 pthread_mutex_unlock(&progress_mutex); \
96 } while(0)
97
98#define EXIT_MKSQUASHFS() \
99 do {\
100 if(restore)\
101 restorefs();\
102 if(delete && destination_file && !block_device)\
103 unlink(destination_file);\
104 exit(1);\
105 } while(0)
106
107#define BAD_ERROR(s, args...) \
108 do {\
109 pthread_mutex_lock(&progress_mutex); \
110 if(progress_enabled) \
111 fprintf(stderr, "\n"); \
112 fprintf(stderr, "FATAL ERROR:" s, ##args);\
113 pthread_mutex_unlock(&progress_mutex); \
114 EXIT_MKSQUASHFS();\
115 } while(0)
plougher1f413c82005-11-18 00:02:14 +0000116
plougher1b899fc2008-08-07 01:24:06 +0000117/* offset of data in compressed metadata blocks (allowing room for
118 * compressed size */
119#define BLOCK_OFFSET 2
plougher324978d2006-02-27 04:53:29 +0000120int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000121int fd;
plougher02bc3bc2007-02-25 12:12:01 +0000122int cur_uncompressed = 0, estimated_uncompressed = 0;
123int columns;
plougher1f413c82005-11-18 00:02:14 +0000124
125/* filesystem flags for building */
plougherce564c62010-05-19 03:01:49 +0000126int no_xattrs = 0, noX = 0;
plougher1f413c82005-11-18 00:02:14 +0000127int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
plougher6d89ac22010-05-19 02:59:23 +0000128int noI = 0, noD = 0;
plougher1f288f62009-02-21 03:05:52 +0000129int silent = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000130long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +0000131int exportable = TRUE;
132int progress = TRUE;
plougher91fbb302008-05-06 02:29:36 +0000133int progress_enabled = FALSE;
plougher8dcc6992007-08-17 19:32:52 +0000134int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +0000135int old_exclude = TRUE;
136int use_regex = FALSE;
plougher801ba6a2010-02-01 03:12:59 +0000137int first_freelist = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000138
139/* superblock attributes */
140int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +0000141unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +0000142int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
143 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +0000144
145/* write position within data section */
146long long bytes = 0, total_bytes = 0;
147
148/* in memory directory table - possibly compressed */
149char *directory_table = NULL;
150unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
151
152/* cached directory table */
153char *directory_data_cache = NULL;
154unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
155
156/* in memory inode table - possibly compressed */
157char *inode_table = NULL;
158unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
159
160/* cached inode table */
161char *data_cache = NULL;
162unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
163
plougher0e453652006-11-06 01:49:35 +0000164/* inode lookup table */
165squashfs_inode *inode_lookup_table = NULL;
166
plougher1f413c82005-11-18 00:02:14 +0000167/* in memory directory data */
168#define I_COUNT_SIZE 128
169#define DIR_ENTRIES 32
170#define INODE_HASH_SIZE 65536
171#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
172#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
173
174struct cached_dir_index {
175 squashfs_dir_index index;
176 char *name;
177};
178
179struct directory {
180 unsigned int start_block;
181 unsigned int size;
182 unsigned char *buff;
183 unsigned char *p;
184 unsigned int entry_count;
185 unsigned char *entry_count_p;
186 unsigned int i_count;
187 unsigned int i_size;
188 struct cached_dir_index *index;
189 unsigned char *index_count_p;
190 unsigned int inode_number;
191};
192
plougher1f413c82005-11-18 00:02:14 +0000193struct inode_info *inode_info[INODE_HASH_SIZE];
194
195/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000196struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000197int dup_files = 0;
198
plougher8f8e1a12007-10-18 02:50:21 +0000199/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000200/* list of exclude dirs/files */
201struct exclude_info {
202 dev_t st_dev;
203 ino_t st_ino;
204};
205
206#define EXCLUDE_SIZE 8192
207int exclude = 0;
208struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000209int old_excluded(char *filename, struct stat *buf);
210
211struct path_entry {
212 char *name;
213 regex_t *preg;
214 struct pathname *paths;
215};
216
217struct pathname {
218 int names;
219 struct path_entry *name;
220};
221
plougherf9039c92007-10-22 03:54:16 +0000222struct pathnames {
223 int count;
224 struct pathname *path[0];
225};
226#define PATHS_ALLOC_SIZE 10
227
228struct pathnames *paths = NULL;
229struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000230struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000231int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000232
233/* fragment block data structures */
234int fragments = 0;
plougher5507dd92006-11-06 00:43:10 +0000235struct file_buffer *fragment_data = NULL;
plougher1f413c82005-11-18 00:02:14 +0000236int fragment_size = 0;
plougher76c64082008-03-08 01:32:23 +0000237
plougher1f413c82005-11-18 00:02:14 +0000238struct fragment {
239 unsigned int index;
240 int offset;
241 int size;
242};
plougher76c64082008-03-08 01:32:23 +0000243
plougher1f413c82005-11-18 00:02:14 +0000244#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000245#define FRAG_INDEX (1LL << 32)
246
plougher1f413c82005-11-18 00:02:14 +0000247squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000248int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000249
plougher1f413c82005-11-18 00:02:14 +0000250/* current inode number for directories and non directories */
251unsigned int dir_inode_no = 1;
252unsigned int inode_no = 0;
plougherdf70c3e2006-01-27 09:34:13 +0000253unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000254
255/* list of source dirs/files */
256int source = 0;
257char **source_path;
258
259/* list of root directory entries read from original filesystem */
260int old_root_entries = 0;
261struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000262 char *name;
263 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000264};
265struct old_root_entry_info *old_root_entry;
266
267/* in memory file info */
268struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000269 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000270 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000271 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000272 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000273 long long start;
274 unsigned int *block_list;
275 struct file_info *next;
276 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000277 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000278};
279
280/* count of how many times SIGINT or SIGQUIT has been sent */
281int interrupted = 0;
282
plougherfd57dfe2009-03-30 01:17:52 +0000283/* restore orignal filesystem state if appending to existing filesystem is
284 * cancelled */
plougher1f413c82005-11-18 00:02:14 +0000285jmp_buf env;
plougherca2c93f2008-08-15 08:34:57 +0000286char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
plougher1f413c82005-11-18 00:02:14 +0000287
288long long sbytes, stotal_bytes;
289
290unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
plougherca2c93f2008-08-15 08:34:57 +0000291 sdirectory_cache_bytes, sdirectory_compressed_bytes,
plougher1f413c82005-11-18 00:02:14 +0000292 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000293 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000294 sdir_count, sfifo_count, ssock_count, sdup_files;
295int sfragments;
296int restore = 0;
plougher5507dd92006-11-06 00:43:10 +0000297int threads;
plougher1f413c82005-11-18 00:02:14 +0000298
299/* flag whether destination file is a block device */
300int block_device = 0;
301
302/* flag indicating whether files are sorted using sort list(s) */
303int sorted = 0;
304
plougher324978d2006-02-27 04:53:29 +0000305/* save destination file name for deleting on error */
306char *destination_file = NULL;
307
plougher99ac0cc2007-10-29 03:17:10 +0000308/* recovery file for abnormal exit on appending */
309char recovery_file[1024] = "";
310int recover = TRUE;
311
ploughereb6eac92008-02-26 01:50:48 +0000312/* struct describing a cache entry passed between threads */
plougher5507dd92006-11-06 00:43:10 +0000313struct file_buffer {
ploughereb6eac92008-02-26 01:50:48 +0000314 struct cache *cache;
plougher76c64082008-03-08 01:32:23 +0000315 int keep;
316 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000317 long long index;
318 long long block;
plougher0f464442008-03-31 00:27:56 +0000319 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000320 int size;
321 int c_byte;
322 int used;
plougher76c64082008-03-08 01:32:23 +0000323 int fragment;
ploughereb6eac92008-02-26 01:50:48 +0000324 int error;
325 struct file_buffer *hash_next;
326 struct file_buffer *hash_prev;
327 struct file_buffer *free_next;
328 struct file_buffer *free_prev;
329 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000330 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000331};
332
ploughereb6eac92008-02-26 01:50:48 +0000333
plougher5507dd92006-11-06 00:43:10 +0000334/* struct describing queues used to pass data between threads */
335struct queue {
336 int size;
337 int readp;
338 int writep;
339 pthread_mutex_t mutex;
340 pthread_cond_t empty;
341 pthread_cond_t full;
342 void **data;
343};
344
plougher1b899fc2008-08-07 01:24:06 +0000345
346/* in memory uid tables */
347#define ID_ENTRIES 256
348#define ID_HASH(id) (id & (ID_ENTRIES - 1))
349#define ISA_UID 1
350#define ISA_GID 2
351struct id {
352 unsigned int id;
353 int index;
354 char flags;
355 struct id *next;
plougher5507dd92006-11-06 00:43:10 +0000356};
plougher1b899fc2008-08-07 01:24:06 +0000357struct id *id_hash_table[ID_ENTRIES];
358struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
359unsigned int uid_count = 0, guid_count = 0;
360unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000361
ploughereb6eac92008-02-26 01:50:48 +0000362struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougherfd57dfe2009-03-30 01:17:52 +0000363struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
364 *to_frag;
plougher91fbb302008-05-06 02:29:36 +0000365pthread_t *thread, *deflator_thread, *frag_deflator_thread, progress_thread;
plougher5507dd92006-11-06 00:43:10 +0000366pthread_mutex_t fragment_mutex;
367pthread_cond_t fragment_waiting;
368pthread_mutex_t pos_mutex;
plougher35a10602008-04-21 02:58:16 +0000369pthread_mutex_t progress_mutex;
370pthread_cond_t progress_wait;
371int rotate = 0;
plougher43244f22009-04-05 02:04:51 +0000372struct pseudo *pseudo = NULL;
plougher5507dd92006-11-06 00:43:10 +0000373
374/* user options that control parallelisation */
375int processors = -1;
376/* default size of output buffer in Mbytes */
377#define WRITER_BUFFER_DEFAULT 512
378/* default size of input buffer in Mbytes */
379#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000380/* default size of fragment buffer in Mbytes */
381#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000382int writer_buffer_size;
383int reader_buffer_size;
plougher76c64082008-03-08 01:32:23 +0000384int fragment_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000385
plougher7b8ee502009-07-29 07:54:30 +0000386/* compression operations structure */
ploughera175ce22009-07-30 04:43:27 +0000387static struct compressor *comp;
plougher764dab52009-08-24 18:28:04 +0000388char *comp_name = COMP_DEFAULT;
plougher7b8ee502009-07-29 07:54:30 +0000389
plougher49b57a92009-03-31 03:23:05 +0000390char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000391void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
392 int type);
ploughera175ce22009-07-30 04:43:27 +0000393extern struct compressor *read_super(int fd, squashfs_super_block *sBlk,
394 char *source);
plougherfd57dfe2009-03-30 01:17:52 +0000395extern long long read_filesystem(char *root_name, int fd,
396 squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
397 char **cdirectory_table, char **directory_data_cache,
398 unsigned int *last_directory_block, unsigned int *inode_dir_offset,
399 unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
400 unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
401 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
402 long long *uncompressed_file, unsigned int *uncompressed_inode,
plougher50b31762009-03-31 04:14:46 +0000403 unsigned int *uncompressed_directory,
404 unsigned int *inode_dir_inode_number,
405 unsigned int *inode_dir_parent_inode,
plougherfd57dfe2009-03-30 01:17:52 +0000406 void (push_directory_entry)(char *, squashfs_inode, int, int),
407 squashfs_fragment_entry **fragment_table,
408 squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000409extern int read_sort_file(char *filename, int source, char *source_path[]);
410extern void sort_files_and_write(struct dir_info *dir);
plougherfd57dfe2009-03-30 01:17:52 +0000411struct file_info *duplicate(long long file_size, long long bytes,
412 unsigned int **block_list, long long *start, struct fragment **fragment,
413 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
414 unsigned short fragment_checksum, int checksum_flag);
415struct dir_info *dir_scan1(char *, struct pathnames *, int (_readdir)(char *,
416 char *, struct dir_info *));
plougher43244f22009-04-05 02:04:51 +0000417struct dir_info *dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
418void dir_scan3(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000419struct file_info *add_non_dup(long long file_size, long long bytes,
420 unsigned int *block_list, long long start, struct fragment *fragment,
421 unsigned short checksum, unsigned short fragment_checksum,
422 int checksum_flag);
plougher1d1c6bb2010-07-21 03:03:13 +0000423extern int generate_file_priorities(struct dir_info *dir, int priority,
plougherfd57dfe2009-03-30 01:17:52 +0000424 struct stat *buf);
plougher5507dd92006-11-06 00:43:10 +0000425extern struct priority_entry *priority_list[65536];
plougher35a10602008-04-21 02:58:16 +0000426void progress_bar(long long current, long long max, int columns);
ploughere6e0e1b2010-05-12 17:17:06 +0000427long long generic_write_table(int, char *, int, char *, int);
428extern long long write_xattrs();
429extern unsigned int xattr_bytes, total_xattr_bytes;
plougher21f63b32010-07-18 03:59:04 +0000430extern int save_xattrs();
431extern void restore_xattrs();
plougherca61d1c2010-07-20 18:32:32 +0000432void restorefs();
plougher5507dd92006-11-06 00:43:10 +0000433
434
plougher5507dd92006-11-06 00:43:10 +0000435struct queue *queue_init(int size)
436{
437 struct queue *queue = malloc(sizeof(struct queue));
438
439 if(queue == NULL)
plougherca61d1c2010-07-20 18:32:32 +0000440 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000441
442 if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
443 free(queue);
plougherca61d1c2010-07-20 18:32:32 +0000444 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000445 }
446
447 queue->size = size + 1;
448 queue->readp = queue->writep = 0;
449 pthread_mutex_init(&queue->mutex, NULL);
450 pthread_cond_init(&queue->empty, NULL);
451 pthread_cond_init(&queue->full, NULL);
452
453 return queue;
plougherca61d1c2010-07-20 18:32:32 +0000454
455failed:
456 BAD_ERROR("Out of memory in queue_init\n");
plougher5507dd92006-11-06 00:43:10 +0000457}
458
459
460void queue_put(struct queue *queue, void *data)
461{
462 int nextp;
463
464 pthread_mutex_lock(&queue->mutex);
465
466 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
467 pthread_cond_wait(&queue->full, &queue->mutex);
468
469 queue->data[queue->writep] = data;
470 queue->writep = nextp;
471 pthread_cond_signal(&queue->empty);
472 pthread_mutex_unlock(&queue->mutex);
473}
474
475
476void *queue_get(struct queue *queue)
477{
478 void *data;
479 pthread_mutex_lock(&queue->mutex);
480
481 while(queue->readp == queue->writep)
482 pthread_cond_wait(&queue->empty, &queue->mutex);
483
484 data = queue->data[queue->readp];
485 queue->readp = (queue->readp + 1) % queue->size;
486 pthread_cond_signal(&queue->full);
487 pthread_mutex_unlock(&queue->mutex);
488
489 return data;
490}
491
plougher1f413c82005-11-18 00:02:14 +0000492
ploughereb6eac92008-02-26 01:50:48 +0000493/* Cache status struct. Caches are used to keep
494 track of memory buffers passed between different threads */
495struct cache {
496 int max_buffers;
497 int count;
498 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000499 pthread_mutex_t mutex;
500 pthread_cond_t wait_for_free;
501 struct file_buffer *free_list;
502 struct file_buffer *hash_table[65536];
503};
504
505
plougher2ea89142008-03-11 01:34:19 +0000506#define INSERT_LIST(NAME, TYPE) \
507void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
508 if(*list) { \
509 entry->NAME##_next = *list; \
510 entry->NAME##_prev = (*list)->NAME##_prev; \
511 (*list)->NAME##_prev->NAME##_next = entry; \
512 (*list)->NAME##_prev = entry; \
513 } else { \
514 *list = entry; \
515 entry->NAME##_prev = entry->NAME##_next = entry; \
516 } \
517}
518
519
520#define REMOVE_LIST(NAME, TYPE) \
521void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
522 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
523 /* only this entry in the list */ \
524 *list = NULL; \
525 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
526 /* more than one entry in the list */ \
527 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
528 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
529 if(*list == entry) \
530 *list = entry->NAME##_next; \
531 } \
532 entry->NAME##_prev = entry->NAME##_next = NULL; \
533}
534
535
536#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000537
538
539/* Called with the cache mutex held */
540void insert_hash_table(struct cache *cache, struct file_buffer *entry)
541{
542 int hash = CALCULATE_HASH(entry->index);
543
544 entry->hash_next = cache->hash_table[hash];
545 cache->hash_table[hash] = entry;
546 entry->hash_prev = NULL;
547 if(entry->hash_next)
548 entry->hash_next->hash_prev = entry;
549}
550
551
552/* Called with the cache mutex held */
553void remove_hash_table(struct cache *cache, struct file_buffer *entry)
554{
555 if(entry->hash_prev)
556 entry->hash_prev->hash_next = entry->hash_next;
557 else
plougher50b31762009-03-31 04:14:46 +0000558 cache->hash_table[CALCULATE_HASH(entry->index)] =
559 entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000560 if(entry->hash_next)
561 entry->hash_next->hash_prev = entry->hash_prev;
562
563 entry->hash_prev = entry->hash_next = NULL;
564}
565
566
567/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000568INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000569
570/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000571REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000572
573
574struct cache *cache_init(int buffer_size, int max_buffers)
575{
576 struct cache *cache = malloc(sizeof(struct cache));
577
578 if(cache == NULL)
plougher9ca649c2010-07-21 00:46:11 +0000579 BAD_ERROR("Out of memory in cache_init\n");
ploughereb6eac92008-02-26 01:50:48 +0000580
581 cache->max_buffers = max_buffers;
582 cache->buffer_size = buffer_size;
583 cache->count = 0;
584 cache->free_list = NULL;
585 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000586 pthread_mutex_init(&cache->mutex, NULL);
587 pthread_cond_init(&cache->wait_for_free, NULL);
588
589 return cache;
590}
591
592
593struct file_buffer *cache_lookup(struct cache *cache, long long index)
594{
595 /* Lookup block in the cache, if found return with usage count
596 * incremented, if not found return NULL */
597 int hash = CALCULATE_HASH(index);
598 struct file_buffer *entry;
599
600 pthread_mutex_lock(&cache->mutex);
601
602 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
603 if(entry->index == index)
604 break;
605
606 if(entry) {
607 /* found the block in the cache, increment used count and
608 * if necessary remove from free list so it won't disappear
609 */
610 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000611 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000612 }
613
614 pthread_mutex_unlock(&cache->mutex);
615
616 return entry;
617}
618
619
plougher76c64082008-03-08 01:32:23 +0000620struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000621{
622 /* Get a free block out of the cache indexed on index. */
623 struct file_buffer *entry;
624
625 pthread_mutex_lock(&cache->mutex);
626
plougher76c64082008-03-08 01:32:23 +0000627 while(1) {
628 /* first try to get a block from the free list */
plougher801ba6a2010-02-01 03:12:59 +0000629 if(first_freelist && cache->free_list) {
plougher76c64082008-03-08 01:32:23 +0000630 /* a block on the free_list is a "keep" block */
631 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000632 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000633 remove_hash_table(cache, entry);
634 break;
plougher801ba6a2010-02-01 03:12:59 +0000635 } else if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000636 /* next try to allocate new block */
plougherfd57dfe2009-03-30 01:17:52 +0000637 entry = malloc(sizeof(struct file_buffer) +
638 cache->buffer_size);
plougher76c64082008-03-08 01:32:23 +0000639 if(entry == NULL)
640 goto failed;
641 entry->cache = cache;
642 entry->free_prev = entry->free_next = NULL;
643 cache->count ++;
644 break;
plougher801ba6a2010-02-01 03:12:59 +0000645 } else if(!first_freelist && cache->free_list) {
plougher2ea89142008-03-11 01:34:19 +0000646 /* a block on the free_list is a "keep" block */
647 entry = cache->free_list;
648 remove_free_list(&cache->free_list, entry);
649 remove_hash_table(cache, entry);
650 break;
plougher801ba6a2010-02-01 03:12:59 +0000651 } else
plougher76c64082008-03-08 01:32:23 +0000652 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000653 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000654 }
655
plougher76c64082008-03-08 01:32:23 +0000656 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000657 entry->used = 1;
658 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000659 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000660 if(keep) {
661 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000662 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000663 }
ploughereb6eac92008-02-26 01:50:48 +0000664 pthread_mutex_unlock(&cache->mutex);
665
666 return entry;
667
668failed:
669 pthread_mutex_unlock(&cache->mutex);
ploughercc6896d2010-07-21 00:56:25 +0000670 BAD_ERROR("Out of memory in cache_get\n");
ploughereb6eac92008-02-26 01:50:48 +0000671}
672
ploughereb6eac92008-02-26 01:50:48 +0000673
plougher0f464442008-03-31 00:27:56 +0000674void cache_rehash(struct file_buffer *entry, long long index)
675{
676 struct cache *cache = entry->cache;
677
678 pthread_mutex_lock(&cache->mutex);
679 if(entry->keep)
680 remove_hash_table(cache, entry);
681 entry->keep = TRUE;
682 entry->index = index;
683 insert_hash_table(cache, entry);
684 pthread_mutex_unlock(&cache->mutex);
685}
686
687
ploughereb6eac92008-02-26 01:50:48 +0000688void cache_block_put(struct file_buffer *entry)
689{
plougher76c64082008-03-08 01:32:23 +0000690 struct cache *cache;
691
ploughereb6eac92008-02-26 01:50:48 +0000692 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000693 * can be reused and if a keep block put onto the free list. As keep
plougher50b31762009-03-31 04:14:46 +0000694 * blocks remain accessible via the hash table they can be found
695 * getting a new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000696
697 if(entry == NULL)
698 return;
699
plougher76c64082008-03-08 01:32:23 +0000700 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000701
plougher76c64082008-03-08 01:32:23 +0000702 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000703
704 entry->used --;
705 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000706 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000707 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000708 else {
709 free(entry);
710 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000711 }
plougher76c64082008-03-08 01:32:23 +0000712
713 /* One or more threads may be waiting on this block */
714 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000715 }
716
plougher76c64082008-03-08 01:32:23 +0000717 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000718}
719
720
plougher50b31762009-03-31 04:14:46 +0000721#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
722 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000723
724
plougher35a10602008-04-21 02:58:16 +0000725inline void inc_progress_bar()
726{
727 cur_uncompressed ++;
728}
729
730
731inline void update_progress_bar()
732{
733 pthread_mutex_lock(&progress_mutex);
734 pthread_cond_signal(&progress_wait);
735 pthread_mutex_unlock(&progress_mutex);
736}
737
738
plougher5507dd92006-11-06 00:43:10 +0000739inline void waitforthread(int i)
740{
741 TRACE("Waiting for thread %d\n", i);
742 while(thread[i] != 0)
743 sched_yield();
744}
745
746
plougher1f413c82005-11-18 00:02:14 +0000747void restorefs()
748{
plougher5507dd92006-11-06 00:43:10 +0000749 int i;
750
plougher02bc3bc2007-02-25 12:12:01 +0000751 if(thread == NULL || thread[0] == 0)
752 return;
753
plougher1f413c82005-11-18 00:02:14 +0000754 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000755
plougher91fbb302008-05-06 02:29:36 +0000756 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000757 if(thread[i])
758 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000759 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000760 waitforthread(i);
761 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000762 bytes = sbytes;
763 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000764 memcpy(directory_data_cache, sdirectory_data_cache,
765 sdirectory_cache_bytes);
766 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000767 inode_bytes = sinode_bytes;
768 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000769 memcpy(directory_table + directory_bytes, sdirectory_compressed,
770 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000771 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000772 total_bytes = stotal_bytes;
773 total_inode_bytes = stotal_inode_bytes;
774 total_directory_bytes = stotal_directory_bytes;
775 inode_count = sinode_count;
776 file_count = sfile_count;
777 sym_count = ssym_count;
778 dev_count = sdev_count;
779 dir_count = sdir_count;
780 fifo_count = sfifo_count;
781 sock_count = ssock_count;
782 dup_files = sdup_files;
783 fragments = sfragments;
784 fragment_size = 0;
plougher1b899fc2008-08-07 01:24:06 +0000785 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000786 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000787 longjmp(env, 1);
788}
789
790
791void sighandler()
792{
plougher5507dd92006-11-06 00:43:10 +0000793 if(++interrupted > 2)
794 return;
795 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000796 restorefs();
797 else {
798 ERROR("Interrupting will restore original filesystem!\n");
799 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000800 }
801}
802
803
plougher324978d2006-02-27 04:53:29 +0000804void sighandler2()
805{
806 EXIT_MKSQUASHFS();
807}
808
809
plougher5507dd92006-11-06 00:43:10 +0000810void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000811{
plougher5507dd92006-11-06 00:43:10 +0000812 int i;
813 sigset_t sigmask;
814 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000815
plougher5507dd92006-11-06 00:43:10 +0000816 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
817 thread[i] = (pthread_t) 0;
818
plougher07966f72007-11-14 10:54:45 +0000819 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000820
821 sigemptyset(&sigmask);
822 sigaddset(&sigmask, SIGINT);
823 sigaddset(&sigmask, SIGQUIT);
824 sigaddset(&sigmask, SIGUSR1);
825 while(1) {
826 sigsuspend(&sigmask);
827 TRACE("After wait in sigusr1_handler :(\n");
828 }
829}
830
831
plougher02bc3bc2007-02-25 12:12:01 +0000832void sigwinch_handler()
833{
834 struct winsize winsize;
835
836 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
plougher1d878662009-03-29 23:02:00 +0000837 if(isatty(STDOUT_FILENO))
plougherfd57dfe2009-03-30 01:17:52 +0000838 printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
839 "columns\n");
plougher02bc3bc2007-02-25 12:12:01 +0000840 columns = 80;
841 } else
842 columns = winsize.ws_col;
843}
844
845
plougher35a10602008-04-21 02:58:16 +0000846void sigalrm_handler()
847{
848 rotate = (rotate + 1) % 4;
849}
850
851
plougher7b8ee502009-07-29 07:54:30 +0000852int mangle2(void **strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000853 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000854{
plougher7b8ee502009-07-29 07:54:30 +0000855 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000856
plougher7b8ee502009-07-29 07:54:30 +0000857 if(!uncompressed) {
858 c_byte = comp->compress(strm, d, s, size, block_size, &error);
859 if(c_byte == -1)
860 BAD_ERROR("mangle2:: %s compress failed with error "
861 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000862 }
863
plougher7b8ee502009-07-29 07:54:30 +0000864 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000865 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000866 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
867 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000868 }
869
plougher7b8ee502009-07-29 07:54:30 +0000870 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000871}
872
873
plougher7b8ee502009-07-29 07:54:30 +0000874int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000875 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000876{
plougher7b8ee502009-07-29 07:54:30 +0000877 static void *stream = NULL;
plougher5507dd92006-11-06 00:43:10 +0000878
plougher50b31762009-03-31 04:14:46 +0000879 return mangle2(&stream, d, s, size, block_size, uncompressed,
880 data_block);
plougher5507dd92006-11-06 00:43:10 +0000881}
882
883
plougherac28cd12010-02-24 02:25:03 +0000884void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000885{
886 int data_space;
887 unsigned short c_byte;
888
889 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000890 if((inode_size - inode_bytes) <
891 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000892 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000893 (SQUASHFS_METADATA_SIZE << 1) + 2);
plougher1eb2a662010-07-26 17:30:50 +0000894 if(it == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000895 goto failed;
896 }
plougher1eb2a662010-07-26 17:30:50 +0000897 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000898 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
899 }
900
plougherfd57dfe2009-03-30 01:17:52 +0000901 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000902 data_cache, SQUASHFS_METADATA_SIZE,
903 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000904 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000905 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000906 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
907 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougherfd57dfe2009-03-30 01:17:52 +0000908 memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
909 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000910 cache_bytes -= SQUASHFS_METADATA_SIZE;
911 }
912
913 data_space = (cache_size - cache_bytes);
914 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000915 int realloc_size = cache_size == 0 ?
916 ((req_size + SQUASHFS_METADATA_SIZE) &
917 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
918 data_space;
plougher1f413c82005-11-18 00:02:14 +0000919
plougher17248ca2010-07-27 00:24:35 +0000920 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000921 realloc_size);
plougher17248ca2010-07-27 00:24:35 +0000922 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000923 goto failed;
924 }
925 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000926 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000927 }
928
929 cache_bytes += req_size;
930
plougherac28cd12010-02-24 02:25:03 +0000931 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000932
933failed:
934 BAD_ERROR("Out of memory in inode table reallocation!\n");
935}
936
937
plougher8a8c4102009-03-29 22:28:49 +0000938int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000939{
940 int res, count;
941
942 for(count = 0; count < bytes; count += res) {
943 res = read(fd, buff + count, bytes - count);
944 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000945 if(res == 0)
946 goto bytes_read;
947 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000948 ERROR("Read failed because %s\n",
949 strerror(errno));
950 return -1;
951 } else
952 res = 0;
953 }
954 }
955
956bytes_read:
957 return count;
958}
959
960
plougher3306cb22010-06-18 04:22:44 +0000961int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000962{
963 off_t off = byte;
964
plougher1d065e92010-06-18 03:58:27 +0000965 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000966 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000967
plougher5507dd92006-11-06 00:43:10 +0000968 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000969 if(lseek(fd, off, SEEK_SET) == -1) {
970 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000971 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000972 goto failed;
973 }
plougher1f413c82005-11-18 00:02:14 +0000974
plougher1d065e92010-06-18 03:58:27 +0000975 if(read_bytes(fd, buff, bytes) < bytes) {
976 ERROR("Read on destination failed\n");
977 goto failed;
978 }
979
plougher5507dd92006-11-06 00:43:10 +0000980 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000981 return 1;
982
983failed:
984 pthread_mutex_unlock(&pos_mutex);
985 return 0;
plougher1f413c82005-11-18 00:02:14 +0000986}
987
988
plougher628e7682009-03-29 22:12:24 +0000989int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000990{
991 int res, count;
992
993 for(count = 0; count < bytes; count += res) {
994 res = write(fd, buff + count, bytes - count);
995 if(res == -1) {
996 if(errno != EINTR) {
997 ERROR("Write failed because %s\n",
998 strerror(errno));
999 return -1;
1000 }
1001 res = 0;
1002 }
1003 }
1004
1005 return 0;
1006}
1007
1008
1009void write_destination(int fd, long long byte, int bytes, char *buff)
plougher1f413c82005-11-18 00:02:14 +00001010{
1011 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +00001012
plougher5507dd92006-11-06 00:43:10 +00001013 if(interrupted < 2)
1014 pthread_mutex_lock(&pos_mutex);
1015
plougher91fbb302008-05-06 02:29:36 +00001016 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +00001017 BAD_ERROR("Lseek on destination failed because %s\n",
1018 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00001019
plougher0dd6f122009-03-29 21:43:57 +00001020 if(write_bytes(fd, buff, bytes) == -1)
1021 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +00001022
1023 if(interrupted < 2)
1024 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +00001025}
1026
1027
1028long long write_inodes()
1029{
1030 unsigned short c_byte;
1031 int avail_bytes;
1032 char *datap = data_cache;
1033 long long start_bytes = bytes;
1034
1035 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001036 if(inode_size - inode_bytes <
1037 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +00001038 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +00001039 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +00001040 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001041 BAD_ERROR("Out of memory in inode table "
1042 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001043 }
1044 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +00001045 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +00001046 }
plougherfd57dfe2009-03-30 01:17:52 +00001047 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
1048 SQUASHFS_METADATA_SIZE : cache_bytes;
1049 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
1050 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001051 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +00001052 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +00001053 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
1054 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001055 datap += avail_bytes;
1056 cache_bytes -= avail_bytes;
1057 }
1058
plougher0dd6f122009-03-29 21:43:57 +00001059 write_destination(fd, bytes, inode_bytes, (char *) inode_table);
plougher1f413c82005-11-18 00:02:14 +00001060 bytes += inode_bytes;
1061
1062 return start_bytes;
1063}
1064
1065
1066long long write_directories()
1067{
1068 unsigned short c_byte;
1069 int avail_bytes;
1070 char *directoryp = directory_data_cache;
1071 long long start_bytes = bytes;
1072
1073 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001074 if(directory_size - directory_bytes <
1075 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001076 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001077 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1078 + 2));
plougher79d665a2010-07-27 00:19:23 +00001079 if(dt == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001080 BAD_ERROR("Out of memory in directory table "
1081 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001082 }
1083 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001084 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001085 }
plougherfd57dfe2009-03-30 01:17:52 +00001086 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1087 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001088 c_byte = mangle(directory_table + directory_bytes +
1089 BLOCK_OFFSET, directoryp, avail_bytes,
1090 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001091 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1092 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001093 SQUASHFS_SWAP_SHORTS(&c_byte,
1094 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001095 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1096 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001097 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001098 directoryp += avail_bytes;
1099 directory_cache_bytes -= avail_bytes;
1100 }
plougher0dd6f122009-03-29 21:43:57 +00001101 write_destination(fd, bytes, directory_bytes, (char *) directory_table);
plougher1f413c82005-11-18 00:02:14 +00001102 bytes += directory_bytes;
1103
1104 return start_bytes;
1105}
1106
1107
plougher1b899fc2008-08-07 01:24:06 +00001108long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001109{
plougher1b899fc2008-08-07 01:24:06 +00001110 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001111 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001112 int i;
1113
plougher1b899fc2008-08-07 01:24:06 +00001114 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001115 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001116 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001117 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001118 }
1119
plougher3a4a1b32010-07-20 00:58:11 +00001120 return generic_write_table(id_bytes, (char *) p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001121}
1122
1123
plougher1b899fc2008-08-07 01:24:06 +00001124struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001125{
plougher1b899fc2008-08-07 01:24:06 +00001126 int hash = ID_HASH(id);
1127 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001128
plougher1b899fc2008-08-07 01:24:06 +00001129 for(; entry; entry = entry->next)
1130 if(entry->id == id)
1131 break;
plougher1f413c82005-11-18 00:02:14 +00001132
plougher1b899fc2008-08-07 01:24:06 +00001133 return entry;
plougher1f413c82005-11-18 00:02:14 +00001134}
1135
1136
plougher1b899fc2008-08-07 01:24:06 +00001137struct id *create_id(unsigned int id)
1138{
1139 int hash = ID_HASH(id);
1140 struct id *entry = malloc(sizeof(struct id));
1141 if(entry == NULL)
1142 BAD_ERROR("Out of memory in create_id\n");
1143 entry->id = id;
1144 entry->index = id_count ++;
1145 entry->flags = 0;
1146 entry->next = id_hash_table[hash];
1147 id_hash_table[hash] = entry;
1148 id_table[entry->index] = entry;
1149 return entry;
1150}
1151
1152
1153unsigned int get_uid(unsigned int uid)
1154{
1155 struct id *entry = get_id(uid);
1156
1157 if(entry == NULL) {
1158 if(id_count == SQUASHFS_IDS)
1159 BAD_ERROR("Out of uids!\n");
1160 entry = create_id(uid);
1161 }
1162
1163 if((entry->flags & ISA_UID) == 0) {
1164 entry->flags |= ISA_UID;
1165 uid_count ++;
1166 }
1167
1168 return entry->index;
1169}
1170
1171
1172unsigned int get_guid(unsigned int guid)
1173{
1174 struct id *entry = get_id(guid);
1175
1176 if(entry == NULL) {
1177 if(id_count == SQUASHFS_IDS)
1178 BAD_ERROR("Out of gids!\n");
1179 entry = create_id(guid);
1180 }
1181
1182 if((entry->flags & ISA_GID) == 0) {
1183 entry->flags |= ISA_GID;
1184 guid_count ++;
1185 }
1186
1187 return entry->index;
1188}
1189
1190
plougher3c6bdb52010-05-01 02:30:59 +00001191int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1192 struct dir_ent *dir_ent, int type, long long byte_size,
1193 long long start_block, unsigned int offset, unsigned int *block_list,
1194 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001195{
1196 struct stat *buf = &dir_ent->inode->buf;
1197 squashfs_inode_header inode_header;
plougherac28cd12010-02-24 02:25:03 +00001198 squashfs_base_inode_header *base = &inode_header.base;
1199 void *inode;
plougher1f413c82005-11-18 00:02:14 +00001200 char *filename = dir_ent->pathname;
1201 int nlink = dir_ent->inode->nlink;
plougher3c6bdb52010-05-01 02:30:59 +00001202 int inode_number = type == SQUASHFS_DIR_TYPE ?
1203 dir_ent->inode->inode_number :
plougherfd57dfe2009-03-30 01:17:52 +00001204 dir_ent->inode->inode_number + dir_inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001205 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001206
ploughere6e0e1b2010-05-12 17:17:06 +00001207 switch(type) {
1208 case SQUASHFS_FILE_TYPE:
1209 if(dir_ent->inode->nlink > 1 ||
1210 byte_size >= (1LL << 32) ||
1211 start_block >= (1LL << 32) ||
1212 sparse || IS_XATTR(xattr))
1213 type = SQUASHFS_LREG_TYPE;
1214 break;
1215 case SQUASHFS_DIR_TYPE:
1216 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1217 type = SQUASHFS_LDIR_TYPE;
1218 break;
1219 case SQUASHFS_SYMLINK_TYPE:
1220 if(IS_XATTR(xattr))
1221 type = SQUASHFS_LSYMLINK_TYPE;
1222 break;
1223 case SQUASHFS_BLKDEV_TYPE:
1224 if(IS_XATTR(xattr))
1225 type = SQUASHFS_LBLKDEV_TYPE;
1226 break;
1227 case SQUASHFS_CHRDEV_TYPE:
1228 if(IS_XATTR(xattr))
1229 type = SQUASHFS_LCHRDEV_TYPE;
1230 break;
plougherc5d69322010-05-12 19:28:38 +00001231 case SQUASHFS_FIFO_TYPE:
1232 if(IS_XATTR(xattr))
1233 type = SQUASHFS_LFIFO_TYPE;
1234 break;
1235 case SQUASHFS_SOCKET_TYPE:
1236 if(IS_XATTR(xattr))
1237 type = SQUASHFS_LSOCKET_TYPE;
1238 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001239 }
1240
plougher1f413c82005-11-18 00:02:14 +00001241 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001242 base->uid = get_uid((unsigned int) global_uid == -1 ?
1243 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001244 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001245 base->guid = get_guid((unsigned int) global_gid == -1 ?
1246 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001247 base->mtime = buf->st_mtime;
1248 base->inode_number = inode_number;
1249
1250 if(type == SQUASHFS_FILE_TYPE) {
1251 int i;
plougherac28cd12010-02-24 02:25:03 +00001252 squashfs_reg_inode_header *reg = &inode_header.reg;
1253 size_t off = offsetof(squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001254
1255 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001256 reg->file_size = byte_size;
1257 reg->start_block = start_block;
1258 reg->fragment = fragment->index;
1259 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001260 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1261 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001262 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1263 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001264 start_block, offset, fragment->index, fragment->offset,
1265 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001266 for(i = 0; i < offset; i++)
1267 TRACE("Block %d, size %d\n", i, block_list[i]);
1268 }
1269 else if(type == SQUASHFS_LREG_TYPE) {
1270 int i;
plougherac28cd12010-02-24 02:25:03 +00001271 squashfs_lreg_inode_header *reg = &inode_header.lreg;
1272 size_t off = offsetof(squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001273
1274 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001275 reg->nlink = nlink;
1276 reg->file_size = byte_size;
1277 reg->start_block = start_block;
1278 reg->fragment = fragment->index;
1279 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001280 if(sparse && sparse >= byte_size)
1281 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001282 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001283 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001284 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1285 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001286 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001287 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1288 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001289 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001290 for(i = 0; i < offset; i++)
1291 TRACE("Block %d, size %d\n", i, block_list[i]);
1292 }
1293 else if(type == SQUASHFS_LDIR_TYPE) {
1294 int i;
1295 unsigned char *p;
plougherac28cd12010-02-24 02:25:03 +00001296 squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001297 struct cached_dir_index *index = dir_in->index;
1298 unsigned int i_count = dir_in->i_count;
1299 unsigned int i_size = dir_in->i_size;
1300
1301 if(byte_size >= 1 << 27)
1302 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1303
1304 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001305 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001306 dir->nlink = dir_ent->dir->directory_count + 2;
1307 dir->file_size = byte_size;
1308 dir->offset = offset;
1309 dir->start_block = start_block;
1310 dir->i_count = i_count;
plougherfd57dfe2009-03-30 01:17:52 +00001311 dir->parent_inode = dir_ent->our_dir ?
1312 dir_ent->our_dir->dir_ent->inode->inode_number :
1313 dir_inode_no + inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001314 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001315
plougherac28cd12010-02-24 02:25:03 +00001316 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
1317 p = inode + offsetof(squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001318 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001319 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
1320 p += offsetof(squashfs_dir_index, name);
1321 memcpy(p, index[i].name, index[i].index.size + 1);
1322 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001323 }
plougher50b31762009-03-31 04:14:46 +00001324 TRACE("Long directory inode, file_size %lld, start_block "
1325 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1326 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001327 }
1328 else if(type == SQUASHFS_DIR_TYPE) {
1329 squashfs_dir_inode_header *dir = &inode_header.dir;
1330
1331 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001332 dir->nlink = dir_ent->dir->directory_count + 2;
1333 dir->file_size = byte_size;
1334 dir->offset = offset;
1335 dir->start_block = start_block;
plougherfd57dfe2009-03-30 01:17:52 +00001336 dir->parent_inode = dir_ent->our_dir ?
1337 dir_ent->our_dir->dir_ent->inode->inode_number :
1338 dir_inode_no + inode_no;
plougherac28cd12010-02-24 02:25:03 +00001339 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001340 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001341 "offset 0x%x, nlink %d\n", byte_size, start_block,
1342 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001343 }
1344 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
1345 squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001346 unsigned int major = major(buf->st_rdev);
1347 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001348
plougher5b398502008-10-04 23:22:03 +00001349 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001350 ERROR("Major %d out of range in device node %s, "
1351 "truncating to %d\n", major, filename,
1352 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001353 major &= 0xfff;
1354 }
1355 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001356 ERROR("Minor %d out of range in device node %s, "
1357 "truncating to %d\n", minor, filename,
1358 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001359 minor &= 0xfffff;
1360 }
plougher1f413c82005-11-18 00:02:14 +00001361 inode = get_inode(sizeof(*dev));
1362 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001363 dev->rdev = (major << 8) | (minor & 0xff) |
1364 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001365 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001366 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001367 }
ploughere6e0e1b2010-05-12 17:17:06 +00001368 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
1369 squashfs_ldev_inode_header *dev = &inode_header.ldev;
1370 unsigned int major = major(buf->st_rdev);
1371 unsigned int minor = minor(buf->st_rdev);
1372
1373 if(major > 0xfff) {
1374 ERROR("Major %d out of range in device node %s, "
1375 "truncating to %d\n", major, filename,
1376 major & 0xfff);
1377 major &= 0xfff;
1378 }
1379 if(minor > 0xfffff) {
1380 ERROR("Minor %d out of range in device node %s, "
1381 "truncating to %d\n", minor, filename,
1382 minor & 0xfffff);
1383 minor &= 0xfffff;
1384 }
1385 inode = get_inode(sizeof(*dev));
1386 dev->nlink = nlink;
1387 dev->rdev = (major << 8) | (minor & 0xff) |
1388 ((minor & ~0xff) << 12);
1389 dev->xattr = xattr;
1390 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1391 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1392 }
plougher1f413c82005-11-18 00:02:14 +00001393 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougherac28cd12010-02-24 02:25:03 +00001394 squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001395 int byte;
1396 char buff[65536];
plougherac28cd12010-02-24 02:25:03 +00001397 size_t off = offsetof(squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001398
1399 if((byte = readlink(filename, buff, 65536)) == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001400 ERROR("Failed to read symlink %s, creating empty "
1401 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001402 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001403 }
1404
1405 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001406 ERROR("Symlink %s is greater than 65536 bytes! "
1407 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001408 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001409 }
1410
1411 inode = get_inode(sizeof(*symlink) + byte);
1412 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001413 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001414 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1415 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001416 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1417 nlink);
plougher1f413c82005-11-18 00:02:14 +00001418 }
ploughere6e0e1b2010-05-12 17:17:06 +00001419 else if(type == SQUASHFS_LSYMLINK_TYPE) {
1420 squashfs_symlink_inode_header *symlink = &inode_header.symlink;
1421 int byte;
1422 char buff[65536];
1423 size_t off = offsetof(squashfs_symlink_inode_header, symlink);
1424
1425 if((byte = readlink(filename, buff, 65536)) == -1) {
1426 ERROR("Failed to read symlink %s, creating empty "
1427 "symlink\n", filename);
1428 byte = 0;
1429 }
1430
1431 if(byte == 65536) {
1432 ERROR("Symlink %s is greater than 65536 bytes! "
1433 "Creating empty symlink\n", filename);
1434 byte = 0;
1435 }
1436
1437 inode = get_inode(sizeof(*symlink) + byte +
1438 sizeof(unsigned int));
1439 symlink->nlink = nlink;
1440 symlink->symlink_size = byte;
1441 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1442 strncpy(inode + off, buff, byte);
1443 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1444 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1445 nlink);
1446 }
plougher1f413c82005-11-18 00:02:14 +00001447 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
1448 squashfs_ipc_inode_header *ipc = &inode_header.ipc;
1449
1450 inode = get_inode(sizeof(*ipc));
1451 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001452 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001453 TRACE("ipc inode, type %s, nlink %d\n", type ==
1454 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001455 }
1456 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
1457 squashfs_lipc_inode_header *ipc = &inode_header.lipc;
1458
1459 inode = get_inode(sizeof(*ipc));
1460 ipc->nlink = nlink;
1461 ipc->xattr = xattr;
1462 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1463 TRACE("ipc inode, type %s, nlink %d\n", type ==
1464 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001465 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001466 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001467
1468 *i_no = MKINODE(inode);
1469 inode_count ++;
1470
plougherfd57dfe2009-03-30 01:17:52 +00001471 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1472 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001473
1474 return TRUE;
1475}
1476
1477
plougher43244f22009-04-05 02:04:51 +00001478void scan3_init_dir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001479{
plougher8cb05cd2005-12-11 23:32:35 +00001480 if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001481 BAD_ERROR("Out of memory allocating directory buffer\n");
1482 }
1483
1484 dir->size = SQUASHFS_METADATA_SIZE;
1485 dir->p = dir->index_count_p = dir->buff;
1486 dir->entry_count = 256;
1487 dir->entry_count_p = NULL;
1488 dir->index = NULL;
1489 dir->i_count = dir->i_size = 0;
1490}
1491
1492
plougher50b31762009-03-31 04:14:46 +00001493void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1494 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001495{
plougher8cb05cd2005-12-11 23:32:35 +00001496 unsigned char *buff;
plougherac28cd12010-02-24 02:25:03 +00001497 squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001498 unsigned int start_block = inode >> 16;
1499 unsigned int offset = inode & 0xffff;
1500 unsigned int size;
plougherac28cd12010-02-24 02:25:03 +00001501 size_t name_off = offsetof(squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001502
1503 if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
1504 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001505 ERROR("Filename is greater than %d characters, truncating! ..."
1506 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001507 }
1508
plougher50b31762009-03-31 04:14:46 +00001509 if(dir->p + sizeof(squashfs_dir_entry) + size +
1510 sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001511 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1512 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001513 BAD_ERROR("Out of memory reallocating directory buffer"
1514 "\n");
plougher1f413c82005-11-18 00:02:14 +00001515 }
1516
1517 dir->p = (dir->p - dir->buff) + buff;
1518 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001519 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1520 buff);
plougher1f413c82005-11-18 00:02:14 +00001521 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1522 dir->buff = buff;
1523 }
1524
plougherfd57dfe2009-03-30 01:17:52 +00001525 if(dir->entry_count == 256 || start_block != dir->start_block ||
1526 ((dir->entry_count_p != NULL) &&
1527 ((dir->p + sizeof(squashfs_dir_entry) + size -
1528 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001529 ((long long) inode_number - dir->inode_number) > 32767
1530 || ((long long) inode_number - dir->inode_number)
1531 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001532 if(dir->entry_count_p) {
1533 squashfs_dir_header dir_header;
1534
plougherfd57dfe2009-03-30 01:17:52 +00001535 if((dir->p + sizeof(squashfs_dir_entry) + size -
1536 dir->index_count_p) >
1537 SQUASHFS_METADATA_SIZE) {
1538 if(dir->i_count % I_COUNT_SIZE == 0) {
1539 dir->index = realloc(dir->index,
1540 (dir->i_count + I_COUNT_SIZE) *
1541 sizeof(struct cached_dir_index));
1542 if(dir->index == NULL)
1543 BAD_ERROR("Out of memory in "
1544 "directory index table "
1545 "reallocation!\n");
1546 }
1547 dir->index[dir->i_count].index.index =
1548 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001549 dir->index[dir->i_count].index.size = size - 1;
1550 dir->index[dir->i_count++].name = name;
plougher50b31762009-03-31 04:14:46 +00001551 dir->i_size += sizeof(squashfs_dir_index) +
1552 size;
plougher1f413c82005-11-18 00:02:14 +00001553 dir->index_count_p = dir->p;
1554 }
1555
1556 dir_header.count = dir->entry_count - 1;
1557 dir_header.start_block = dir->start_block;
1558 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001559 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001560 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001561
1562 }
1563
1564
1565 dir->entry_count_p = dir->p;
1566 dir->start_block = start_block;
1567 dir->entry_count = 0;
1568 dir->inode_number = inode_number;
1569 dir->p += sizeof(squashfs_dir_header);
1570 }
1571
plougher1f413c82005-11-18 00:02:14 +00001572 idir.offset = offset;
1573 idir.type = type;
1574 idir.size = size - 1;
1575 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001576 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1577 strncpy((char *) dir->p + name_off, name, size);
plougher1f413c82005-11-18 00:02:14 +00001578 dir->p += sizeof(squashfs_dir_entry) + size;
1579 dir->entry_count ++;
1580}
1581
1582
plougherfd57dfe2009-03-30 01:17:52 +00001583void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1584 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001585{
1586 unsigned int dir_size = dir->p - dir->buff;
1587 int data_space = (directory_cache_size - directory_cache_bytes);
1588 unsigned int directory_block, directory_offset, i_count, index;
1589 unsigned short c_byte;
1590
1591 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001592 int realloc_size = directory_cache_size == 0 ?
1593 ((dir_size + SQUASHFS_METADATA_SIZE) &
1594 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001595
plougher17248ca2010-07-27 00:24:35 +00001596 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001597 directory_cache_size + realloc_size);
plougher17248ca2010-07-27 00:24:35 +00001598 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001599 goto failed;
1600 }
1601 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001602 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001603 }
1604
1605 if(dir_size) {
1606 squashfs_dir_header dir_header;
1607
1608 dir_header.count = dir->entry_count - 1;
1609 dir_header.start_block = dir->start_block;
1610 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001611 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001612 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1613 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001614 }
1615 directory_offset = directory_cache_bytes;
1616 directory_block = directory_bytes;
1617 directory_cache_bytes += dir_size;
1618 i_count = 0;
1619 index = SQUASHFS_METADATA_SIZE - directory_offset;
1620
1621 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001622 while(i_count < dir->i_count &&
1623 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001624 dir->index[i_count++].index.start_block =
1625 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001626 index += SQUASHFS_METADATA_SIZE;
1627
1628 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1629 break;
1630
plougherfd57dfe2009-03-30 01:17:52 +00001631 if((directory_size - directory_bytes) <
1632 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001633 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001634 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1635 + 2);
plougher79d665a2010-07-27 00:19:23 +00001636 if(dt == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001637 goto failed;
1638 }
1639 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001640 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001641 }
1642
plougher50b31762009-03-31 04:14:46 +00001643 c_byte = mangle(directory_table + directory_bytes +
1644 BLOCK_OFFSET, directory_data_cache,
1645 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1646 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001647 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1648 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001649 SQUASHFS_SWAP_SHORTS(&c_byte,
1650 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001651 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1652 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001653 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougherfd57dfe2009-03-30 01:17:52 +00001654 memcpy(directory_data_cache, directory_data_cache +
1655 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1656 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001657 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1658 }
1659
plougher3c6bdb52010-05-01 02:30:59 +00001660 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1661 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1662 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001663
1664#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001665 {
plougher1f413c82005-11-18 00:02:14 +00001666 unsigned char *dirp;
1667 int count;
1668
1669 TRACE("Directory contents of inode 0x%llx\n", *inode);
1670 dirp = dir->buff;
1671 while(dirp < dir->p) {
1672 char buffer[SQUASHFS_NAME_LEN + 1];
1673 squashfs_dir_entry idir, *idirp;
plougher1f288f62009-02-21 03:05:52 +00001674 squashfs_dir_header dirh;
plougher360514a2009-03-30 03:01:38 +00001675 SQUASHFS_SWAP_DIR_HEADER((squashfs_dir_header *) dirp,
1676 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001677 count = dirh.count + 1;
plougher1f413c82005-11-18 00:02:14 +00001678 dirp += sizeof(squashfs_dir_header);
1679
plougher50b31762009-03-31 04:14:46 +00001680 TRACE("\tStart block 0x%x, count %d\n",
1681 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001682
1683 while(count--) {
1684 idirp = (squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001685 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001686 strncpy(buffer, idirp->name, idir.size + 1);
1687 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001688 TRACE("\t\tname %s, inode offset 0x%x, type "
1689 "%d\n", buffer, idir.offset, idir.type);
1690 dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001691 }
1692 }
1693 }
1694#endif
1695 dir_count ++;
1696
plougher29e37092007-04-15 01:24:51 +00001697 return;
plougher1f413c82005-11-18 00:02:14 +00001698
1699failed:
1700 BAD_ERROR("Out of memory in directory table reallocation!\n");
1701}
1702
1703
plougher76c64082008-03-08 01:32:23 +00001704struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001705{
plougher5507dd92006-11-06 00:43:10 +00001706 squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001707 int res, size;
plougher76c64082008-03-08 01:32:23 +00001708 long long start_block;
1709 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001710
plougher76c64082008-03-08 01:32:23 +00001711 if(fragment->index == SQUASHFS_INVALID_FRAG)
1712 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001713
plougher76c64082008-03-08 01:32:23 +00001714 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001715 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001716 return buffer;
plougher76c64082008-03-08 01:32:23 +00001717
plougherfd57dfe2009-03-30 01:17:52 +00001718 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1719 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001720
plougher76c64082008-03-08 01:32:23 +00001721 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001722
1723 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001724 disk_fragment = &fragment_table[fragment->index];
1725 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001726 start_block = disk_fragment->start_block;
1727 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001728
plougher0f464442008-03-31 00:27:56 +00001729 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001730 int error;
plougher76c64082008-03-08 01:32:23 +00001731 char *data;
plougher1f413c82005-11-18 00:02:14 +00001732
plougher76c64082008-03-08 01:32:23 +00001733 if(compressed_buffer)
1734 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001735 else
1736 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001737
ploughera175ce22009-07-30 04:43:27 +00001738 res = comp->uncompress(buffer->data, data, size, block_size,
1739 &error);
1740 if(res == -1)
1741 BAD_ERROR("%s uncompress failed with error code %d\n",
1742 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001743 } else if(compressed_buffer)
1744 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001745 else {
1746 res = read_fs_bytes(fd, start_block, size, buffer->data);
1747 if(res == 0)
1748 EXIT_MKSQUASHFS();
1749 }
plougher1f413c82005-11-18 00:02:14 +00001750
plougher03859fa2009-03-31 03:18:18 +00001751 cache_block_put(compressed_buffer);
1752
plougher76c64082008-03-08 01:32:23 +00001753 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001754}
1755
plougher2ea89142008-03-11 01:34:19 +00001756
1757struct frag_locked {
1758 struct file_buffer *buffer;
1759 int c_byte;
1760 int fragment;
1761 struct frag_locked *fragment_prev;
1762 struct frag_locked *fragment_next;
1763};
1764
1765int fragments_locked = FALSE;
1766struct frag_locked *frag_locked_list = NULL;
1767
1768INSERT_LIST(fragment, struct frag_locked)
1769REMOVE_LIST(fragment, struct frag_locked)
1770
plougher4e8484a2008-03-15 23:30:16 +00001771int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001772{
plougher4e8484a2008-03-15 23:30:16 +00001773 int count;
plougher5507dd92006-11-06 00:43:10 +00001774 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001775 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001776 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001777 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001778 return count;
plougher2ea89142008-03-11 01:34:19 +00001779}
1780
1781
1782void unlock_fragments()
1783{
1784 struct frag_locked *entry;
1785 int compressed_size;
1786
1787 pthread_mutex_lock(&fragment_mutex);
1788 while(frag_locked_list) {
1789 entry = frag_locked_list;
1790 remove_fragment_list(&frag_locked_list, entry);
1791 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1792 fragment_table[entry->fragment].size = entry->c_byte;
1793 fragment_table[entry->fragment].start_block = bytes;
1794 entry->buffer->block = bytes;
1795 bytes += compressed_size;
1796 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001797 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001798 TRACE("fragment_locked writing fragment %d, compressed size %d"
1799 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001800 free(entry);
1801 }
1802 fragments_locked = FALSE;
1803 pthread_mutex_unlock(&fragment_mutex);
1804}
1805
1806
plougherb7a66812010-07-21 01:06:59 +00001807void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001808 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001809{
1810 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1811 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001812 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001813 entry->buffer = write_buffer;
1814 entry->c_byte = c_byte;
1815 entry->fragment = fragment;
1816 entry->fragment_prev = entry->fragment_next = NULL;
1817 pthread_mutex_lock(&fragment_mutex);
1818 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001819 pthread_mutex_unlock(&fragment_mutex);
1820}
1821
1822
plougher1f413c82005-11-18 00:02:14 +00001823void write_fragment()
1824{
plougher1f413c82005-11-18 00:02:14 +00001825 if(fragment_size == 0)
1826 return;
1827
plougher5507dd92006-11-06 00:43:10 +00001828 pthread_mutex_lock(&fragment_mutex);
1829 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001830 void *ft = realloc(fragment_table, (fragments +
plougher50b31762009-03-31 04:14:46 +00001831 FRAG_SIZE) * sizeof(squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001832 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001833 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001834 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001835 }
plougherfa89c332010-07-27 00:27:15 +00001836 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001837 }
1838 fragment_data->size = fragment_size;
1839 fragment_data->block = fragments;
plougher2ea89142008-03-11 01:34:19 +00001840 fragment_table[fragments].unused = 0;
plougher5507dd92006-11-06 00:43:10 +00001841 fragments_outstanding ++;
1842 queue_put(to_frag, fragment_data);
plougher1f413c82005-11-18 00:02:14 +00001843 fragments ++;
1844 fragment_size = 0;
plougher5507dd92006-11-06 00:43:10 +00001845 pthread_mutex_unlock(&fragment_mutex);
1846}
1847
ploughereb6eac92008-02-26 01:50:48 +00001848
plougher1f413c82005-11-18 00:02:14 +00001849static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
plougher5507dd92006-11-06 00:43:10 +00001850struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer)
plougher1f413c82005-11-18 00:02:14 +00001851{
1852 struct fragment *ffrg;
plougher5507dd92006-11-06 00:43:10 +00001853
plougher1f413c82005-11-18 00:02:14 +00001854
plougher5507dd92006-11-06 00:43:10 +00001855 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001856 return &empty_fragment;
1857
plougher5507dd92006-11-06 00:43:10 +00001858 if(fragment_size + file_buffer->size > block_size)
plougher1f413c82005-11-18 00:02:14 +00001859 write_fragment();
1860
ploughera2968ef2009-03-03 10:46:00 +00001861 if((ffrg = malloc(sizeof(struct fragment))) == NULL)
plougher1f413c82005-11-18 00:02:14 +00001862 BAD_ERROR("Out of memory in fragment block allocation!\n");
1863
plougher5507dd92006-11-06 00:43:10 +00001864 if(fragment_size == 0)
plougher76c64082008-03-08 01:32:23 +00001865 fragment_data = cache_get(fragment_buffer, fragments, 1);
plougher5507dd92006-11-06 00:43:10 +00001866
plougher1f413c82005-11-18 00:02:14 +00001867 ffrg->index = fragments;
1868 ffrg->offset = fragment_size;
plougher5507dd92006-11-06 00:43:10 +00001869 ffrg->size = file_buffer->size;
plougher17b269c2009-03-30 01:33:07 +00001870 memcpy(fragment_data->data + fragment_size, file_buffer->data,
1871 file_buffer->size);
plougher5507dd92006-11-06 00:43:10 +00001872 fragment_size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001873
1874 return ffrg;
1875}
1876
1877
ploughere6e0e1b2010-05-12 17:17:06 +00001878long long generic_write_table(int length, char *buffer, int length2,
1879 char *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001880{
plougher17b269c2009-03-30 01:33:07 +00001881 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1882 SQUASHFS_METADATA_SIZE;
plougher0e453652006-11-06 01:49:35 +00001883 long long list[meta_blocks], start_bytes;
plougherbadfac62007-11-12 03:29:41 +00001884 int compressed_size, i;
plougher1f413c82005-11-18 00:02:14 +00001885 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001886 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1887
plougher82ab2332009-04-21 00:21:21 +00001888#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001889 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001890 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001891#endif
plougher1f413c82005-11-18 00:02:14 +00001892
1893 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001894 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1895 SQUASHFS_METADATA_SIZE : length;
1896 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1897 SQUASHFS_METADATA_SIZE , avail_bytes,
1898 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001899 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001900 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001901 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1902 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001903 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1904 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001905 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001906 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001907 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001908 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001909 }
1910
ploughere6e0e1b2010-05-12 17:17:06 +00001911 start_bytes = bytes;
1912 if(length2) {
1913 write_destination(fd, bytes, length2, (char *) buffer2);
1914 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001915 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001916 }
1917
plougher1f288f62009-02-21 03:05:52 +00001918 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
plougher0dd6f122009-03-29 21:43:57 +00001919 write_destination(fd, bytes, sizeof(list), (char *) list);
plougher1f413c82005-11-18 00:02:14 +00001920 bytes += sizeof(list);
plougher10f7d572010-07-20 02:14:04 +00001921 total_bytes += sizeof(list);
plougher1f413c82005-11-18 00:02:14 +00001922
plougher40d8b952010-02-12 16:26:32 +00001923 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1924 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001925
plougher1f413c82005-11-18 00:02:14 +00001926 return start_bytes;
1927}
1928
1929
plougher0e453652006-11-06 01:49:35 +00001930long long write_fragment_table()
1931{
1932 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougherac28cd12010-02-24 02:25:03 +00001933 squashfs_fragment_entry p[fragments];
plougher0e453652006-11-06 01:49:35 +00001934 int i;
1935
plougher17b269c2009-03-30 01:33:07 +00001936 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1937 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001938 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001939 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1940 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001941 fragment_table[i].size);
plougherac28cd12010-02-24 02:25:03 +00001942 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p + i);
plougher0e453652006-11-06 01:49:35 +00001943 }
1944
ploughere6e0e1b2010-05-12 17:17:06 +00001945 return generic_write_table(frag_bytes, (char *) p, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001946}
1947
1948
plougher1f413c82005-11-18 00:02:14 +00001949char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001950char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001951{
plougher1d065e92010-06-18 03:58:27 +00001952 int res;
1953
1954 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
1955 if(res == 0)
1956 EXIT_MKSQUASHFS();
1957
plougher1f413c82005-11-18 00:02:14 +00001958 return read_from_file_buffer;
1959}
1960
1961
plougher1b899fc2008-08-07 01:24:06 +00001962char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
1963char *read_from_disk2(long long start, unsigned int avail_bytes)
1964{
plougher1d065e92010-06-18 03:58:27 +00001965 int res;
1966
1967 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
1968 if(res == 0)
1969 EXIT_MKSQUASHFS();
1970
plougher1b899fc2008-08-07 01:24:06 +00001971 return read_from_file_buffer2;
1972}
1973
1974
plougher1f413c82005-11-18 00:02:14 +00001975/*
1976 * Compute 16 bit BSD checksum over the data
1977 */
plougher5507dd92006-11-06 00:43:10 +00001978unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00001979{
plougher5507dd92006-11-06 00:43:10 +00001980 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00001981
plougher5507dd92006-11-06 00:43:10 +00001982 while(bytes --) {
1983 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1984 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00001985 }
1986
1987 return chksum;
1988}
1989
1990
plougher17b269c2009-03-30 01:33:07 +00001991unsigned short get_checksum_disk(long long start, long long l,
1992 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00001993{
1994 unsigned short chksum = 0;
1995 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00001996 struct file_buffer *write_buffer;
1997 int i;
plougher5507dd92006-11-06 00:43:10 +00001998
plougher57e6d182008-05-06 23:51:29 +00001999 for(i = 0; l; i++) {
2000 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2001 if(bytes == 0) /* sparse block */
2002 continue;
2003 write_buffer = cache_lookup(writer_buffer, start);
2004 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002005 chksum = get_checksum(write_buffer->data, bytes,
2006 chksum);
plougher57e6d182008-05-06 23:51:29 +00002007 cache_block_put(write_buffer);
2008 } else
plougher50b31762009-03-31 04:14:46 +00002009 chksum = get_checksum(read_from_disk(start, bytes),
2010 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002011 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002012 start += bytes;
2013 }
2014
2015 return chksum;
2016}
2017
2018
plougher5507dd92006-11-06 00:43:10 +00002019unsigned short get_checksum_mem(char *buff, int bytes)
2020{
2021 return get_checksum(buff, bytes, 0);
2022}
2023
2024
2025unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2026{
2027 if(file_buffer == NULL)
2028 return 0;
2029 else
2030 return get_checksum(file_buffer->data, file_buffer->size, 0);
2031}
2032
2033
plougher5507dd92006-11-06 00:43:10 +00002034#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002035void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002036 unsigned int *block_listp, int blocks, unsigned int fragment,
2037 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002038{
2039 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002040 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002041 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002042
plougher5507dd92006-11-06 00:43:10 +00002043 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002044 return;
2045
plougher5507dd92006-11-06 00:43:10 +00002046 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2047 if(file_size != dupl_ptr->file_size)
2048 continue;
2049 if(blocks != 0 && start != dupl_ptr->start)
2050 continue;
2051 if(fragment != dupl_ptr->fragment->index)
2052 continue;
plougher17b269c2009-03-30 01:33:07 +00002053 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2054 dupl_ptr->fragment->offset || bytes !=
2055 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002056 continue;
2057 return;
2058 }
2059
ploughera2968ef2009-03-03 10:46:00 +00002060 if((frg = malloc(sizeof(struct fragment))) == NULL)
plougher1f413c82005-11-18 00:02:14 +00002061 BAD_ERROR("Out of memory in fragment block allocation!\n");
2062
2063 frg->index = fragment;
2064 frg->offset = offset;
2065 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002066
plougher5507dd92006-11-06 00:43:10 +00002067 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2068}
plougher1f413c82005-11-18 00:02:14 +00002069
plougher1f413c82005-11-18 00:02:14 +00002070
plougher5507dd92006-11-06 00:43:10 +00002071int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002072{
plougher5507dd92006-11-06 00:43:10 +00002073 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002074
2075 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002076 if(dupl_ptr->file_size == file_size)
2077 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002078
plougher5507dd92006-11-06 00:43:10 +00002079 return FALSE;
2080}
2081
2082
2083int pre_duplicate_frag(long long file_size, unsigned short checksum)
2084{
2085 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2086
2087 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002088 if(file_size == dupl_ptr->file_size && file_size ==
2089 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002090 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002091 struct file_buffer *frag_buffer =
2092 get_fragment(dupl_ptr->fragment);
2093 dupl_ptr->checksum =
2094 get_checksum_disk(dupl_ptr->start,
2095 dupl_ptr->bytes, dupl_ptr->block_list);
2096 dupl_ptr->fragment_checksum =
2097 get_checksum_mem(frag_buffer->data +
2098 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002099 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002100 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002101 }
plougher5507dd92006-11-06 00:43:10 +00002102 if(dupl_ptr->fragment_checksum == checksum)
2103 return TRUE;
2104 }
plougher1f413c82005-11-18 00:02:14 +00002105
plougher5507dd92006-11-06 00:43:10 +00002106 return FALSE;
2107}
2108
2109
plougher17b269c2009-03-30 01:33:07 +00002110struct file_info *add_non_dup(long long file_size, long long bytes,
2111 unsigned int *block_list, long long start, struct fragment *fragment,
2112 unsigned short checksum, unsigned short fragment_checksum,
2113 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002114{
2115 struct file_info *dupl_ptr;
2116
ploughera2968ef2009-03-03 10:46:00 +00002117 if((dupl_ptr = malloc(sizeof(struct file_info))) == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002118 BAD_ERROR("Out of memory in dup_files allocation!\n");
2119 }
2120
2121 dupl_ptr->file_size = file_size;
2122 dupl_ptr->bytes = bytes;
2123 dupl_ptr->block_list = block_list;
2124 dupl_ptr->start = start;
2125 dupl_ptr->fragment = fragment;
2126 dupl_ptr->checksum = checksum;
2127 dupl_ptr->fragment_checksum = fragment_checksum;
2128 dupl_ptr->checksum_flag = checksum_flag;
2129 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2130 dupl[DUP_HASH(file_size)] = dupl_ptr;
2131 dup_files ++;
2132
2133 return dupl_ptr;
2134}
2135
2136
plougher17b269c2009-03-30 01:33:07 +00002137struct file_info *duplicate(long long file_size, long long bytes,
2138 unsigned int **block_list, long long *start, struct fragment **fragment,
2139 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2140 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002141{
2142 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2143 int frag_bytes = file_buffer ? file_buffer->size : 0;
2144
2145 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002146 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2147 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002148 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002149 int block;
2150
plougher17b269c2009-03-30 01:33:07 +00002151 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2152 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002153 continue;
2154
plougher5507dd92006-11-06 00:43:10 +00002155 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002156 checksum = get_checksum_disk(*start, bytes,
2157 *block_list);
2158 fragment_checksum =
2159 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002160 checksum_flag = TRUE;
2161 }
2162
2163 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002164 struct file_buffer *frag_buffer =
2165 get_fragment(dupl_ptr->fragment);
2166 dupl_ptr->checksum =
2167 get_checksum_disk(dupl_ptr->start,
2168 dupl_ptr->bytes, dupl_ptr->block_list);
2169 dupl_ptr->fragment_checksum =
2170 get_checksum_mem(frag_buffer->data +
2171 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002172 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002173 dupl_ptr->checksum_flag = TRUE;
2174 }
2175
plougher17b269c2009-03-30 01:33:07 +00002176 if(checksum != dupl_ptr->checksum ||
2177 fragment_checksum !=
2178 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002179 continue;
2180
plougher1b899fc2008-08-07 01:24:06 +00002181 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002182 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002183 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2184 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002185 struct file_buffer *target_buffer = NULL;
2186 struct file_buffer *dup_buffer = NULL;
2187 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002188 int res;
plougher5507dd92006-11-06 00:43:10 +00002189
plougher1b899fc2008-08-07 01:24:06 +00002190 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002191 continue;
plougher17b269c2009-03-30 01:33:07 +00002192 target_buffer = cache_lookup(writer_buffer,
2193 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002194 if(target_buffer)
2195 target_data = target_buffer->data;
2196 else
plougher50b31762009-03-31 04:14:46 +00002197 target_data =
2198 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002199 size);
plougher5507dd92006-11-06 00:43:10 +00002200
plougher360514a2009-03-30 03:01:38 +00002201 dup_buffer = cache_lookup(writer_buffer,
2202 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002203 if(dup_buffer)
2204 dup_data = dup_buffer->data;
2205 else
plougher360514a2009-03-30 03:01:38 +00002206 dup_data = read_from_disk2(dup_start,
2207 size);
plougher1b899fc2008-08-07 01:24:06 +00002208
2209 res = memcmp(target_data, dup_data, size);
2210 cache_block_put(target_buffer);
2211 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002212 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002213 break;
plougher1b899fc2008-08-07 01:24:06 +00002214 target_start += size;
2215 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002216 }
2217 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002218 struct file_buffer *frag_buffer =
2219 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002220
plougher17b269c2009-03-30 01:33:07 +00002221 if(frag_bytes == 0 ||
2222 memcmp(file_buffer->data,
2223 frag_buffer->data +
2224 dupl_ptr->fragment->offset,
2225 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002226 TRACE("Found duplicate file, start "
2227 "0x%llx, size %lld, checksum "
2228 "0x%x, fragment %d, size %d, "
2229 "offset %d, checksum 0x%x\n",
2230 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002231 dupl_ptr->bytes,
2232 dupl_ptr->checksum,
2233 dupl_ptr->fragment->index,
2234 frag_bytes,
2235 dupl_ptr->fragment->offset,
2236 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002237 *block_list = dupl_ptr->block_list;
2238 *start = dupl_ptr->start;
2239 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002240 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002241 return 0;
2242 }
plougher76c64082008-03-08 01:32:23 +00002243 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002244 }
2245 }
2246
2247
plougher17b269c2009-03-30 01:33:07 +00002248 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2249 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002250}
2251
2252
plougher00d08172009-09-03 10:17:44 +00002253static int seq = 0;
2254void reader_read_process(struct dir_ent *dir_ent)
2255{
2256 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002257 int status, res, byte, count = 0;
2258 int file = get_pseudo_file(dir_ent->inode->pseudo_id)->fd;
2259 int child = get_pseudo_file(dir_ent->inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002260 long long bytes = 0;
2261
2262 while(1) {
2263 file_buffer = cache_get(reader_buffer, 0, 0);
2264 file_buffer->sequence = seq ++;
2265
2266 byte = read_bytes(file, file_buffer->data, block_size);
2267 if(byte == -1)
2268 goto read_err;
2269
2270 file_buffer->size = byte;
2271 file_buffer->file_size = -1;
2272 file_buffer->block = count ++;
2273 file_buffer->error = FALSE;
2274 file_buffer->fragment = FALSE;
2275 bytes += byte;
2276
2277 if(byte == 0)
2278 break;
2279
plougher286b6b32009-09-19 03:29:27 +00002280 /*
2281 * Update estimated_uncompressed block count. This is done
2282 * on every block rather than waiting for all blocks to be
2283 * read incase write_file_process() is running in parallel
2284 * with this. Otherwise cur uncompressed block count may
2285 * get ahead of the total uncompressed block count.
2286 */
2287 estimated_uncompressed ++;
2288
plougher00d08172009-09-03 10:17:44 +00002289 if(prev_buffer)
2290 queue_put(from_reader, prev_buffer);
2291 prev_buffer = file_buffer;
2292 }
2293
plougher54d67292009-09-19 03:26:27 +00002294 /*
2295 * Update inode file size now that the size of the dynamic pseudo file
2296 * is known. This is needed for the -info option.
2297 */
2298 dir_ent->inode->buf.st_size = bytes;
2299
plougherba674e82009-09-10 03:50:00 +00002300 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002301 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002302 goto read_err;
2303
plougher00d08172009-09-03 10:17:44 +00002304 if(prev_buffer == NULL)
2305 prev_buffer = file_buffer;
2306 else {
2307 cache_block_put(file_buffer);
2308 seq --;
2309 }
2310 prev_buffer->file_size = bytes;
2311 prev_buffer->fragment = !no_fragments &&
2312 (count == 2 || always_use_fragments) && (byte < block_size);
2313 queue_put(from_reader, prev_buffer);
2314
2315 return;
2316
2317read_err:
2318 if(prev_buffer) {
2319 cache_block_put(file_buffer);
2320 seq --;
2321 file_buffer = prev_buffer;
2322 }
2323 file_buffer->error = TRUE;
2324 queue_put(from_deflate, file_buffer);
2325}
2326
2327
plougher5507dd92006-11-06 00:43:10 +00002328void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002329{
plougher018d2b32007-04-23 03:01:48 +00002330 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002331 struct file_buffer *file_buffer;
plougher018d2b32007-04-23 03:01:48 +00002332 int blocks, byte, count, expected, file, frag_block;
2333 long long bytes, read_size;
plougher5507dd92006-11-06 00:43:10 +00002334
plougher018d2b32007-04-23 03:01:48 +00002335 if(dir_ent->inode->read)
plougher5507dd92006-11-06 00:43:10 +00002336 return;
2337
plougher018d2b32007-04-23 03:01:48 +00002338 dir_ent->inode->read = TRUE;
2339again:
2340 bytes = 0;
2341 count = 0;
2342 file_buffer = NULL;
2343 read_size = buf->st_size;
2344 blocks = (read_size + block_size - 1) >> block_log;
2345 frag_block = !no_fragments && (always_use_fragments ||
2346 (read_size < block_size)) ? read_size >> block_log : -1;
2347
plougher5507dd92006-11-06 00:43:10 +00002348 if((file = open(dir_ent->pathname, O_RDONLY)) == -1)
2349 goto read_err;
2350
plougher018d2b32007-04-23 03:01:48 +00002351 do {
plougher110799c2009-03-30 01:50:40 +00002352 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002353 block_size ? block_size :
2354 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002355
2356 if(file_buffer)
2357 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002358 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002359 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002360
plougher110799c2009-03-30 01:50:40 +00002361 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2362 block_size);
plougher018d2b32007-04-23 03:01:48 +00002363
plougher018d2b32007-04-23 03:01:48 +00002364 file_buffer->file_size = read_size;
2365
2366 if(byte != expected)
2367 goto restat;
2368
2369 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002370 file_buffer->error = FALSE;
plougher1b899fc2008-08-07 01:24:06 +00002371 file_buffer->fragment = (file_buffer->block == frag_block);
plougher018d2b32007-04-23 03:01:48 +00002372
2373 bytes += byte;
2374 count ++;
2375 } while(count < blocks);
2376
2377 if(read_size != bytes)
2378 goto restat;
2379
2380 if(expected == block_size) {
2381 char buffer;
2382
plougher1179b5f2009-03-30 00:33:19 +00002383 if(read_bytes(file, &buffer, 1) == 1)
plougher018d2b32007-04-23 03:01:48 +00002384 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002385 }
2386
plougher1b899fc2008-08-07 01:24:06 +00002387 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002388
plougher5507dd92006-11-06 00:43:10 +00002389 close(file);
plougher5507dd92006-11-06 00:43:10 +00002390
2391 return;
2392
2393read_err:
plougher0f464442008-03-31 00:27:56 +00002394 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002395 file_buffer->sequence = seq ++;
plougher018d2b32007-04-23 03:01:48 +00002396read_err2:
plougher5507dd92006-11-06 00:43:10 +00002397 file_buffer->error = TRUE;
2398 queue_put(from_deflate, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002399 return;
2400restat:
2401 fstat(file, &buf2);
2402 close(file);
2403 if(read_size != buf2.st_size) {
2404 memcpy(buf, &buf2, sizeof(struct stat));
2405 file_buffer->error = 2;
2406 queue_put(from_deflate, file_buffer);
2407 goto again;
2408 }
2409 goto read_err2;
plougher5507dd92006-11-06 00:43:10 +00002410}
2411
2412
2413void reader_scan(struct dir_info *dir) {
2414 int i;
2415
2416 for(i = 0; i < dir->count; i++) {
2417 struct dir_ent *dir_ent = dir->list[i];
2418 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002419 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002420 continue;
2421
plougherb3977eb2010-05-02 02:08:48 +00002422 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002423 reader_read_process(dir_ent);
2424 continue;
2425 }
2426
plougher5507dd92006-11-06 00:43:10 +00002427 switch(buf->st_mode & S_IFMT) {
2428 case S_IFREG:
2429 reader_read_file(dir_ent);
2430 break;
2431 case S_IFDIR:
2432 reader_scan(dir_ent->dir);
2433 break;
2434 }
2435 }
2436}
2437
2438
2439void *reader(void *arg)
2440{
2441 int oldstate;
2442
2443 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2444 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2445
2446 if(!sorted)
2447 reader_scan(queue_get(to_reader));
2448 else {
2449 int i;
2450 struct priority_entry *entry;
2451
2452 queue_get(to_reader);
2453 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002454 for(entry = priority_list[i]; entry;
2455 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002456 reader_read_file(entry->dir);
2457 }
rloughere4873e02007-11-08 17:50:42 +00002458
plougher5aa18162007-12-13 12:15:21 +00002459 thread[0] = 0;
2460
rloughere4873e02007-11-08 17:50:42 +00002461 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002462}
2463
2464
2465void *writer(void *arg)
2466{
2467 int write_error = FALSE;
2468 int oldstate;
2469
2470 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2471 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2472
2473 while(1) {
2474 struct file_buffer *file_buffer = queue_get(to_writer);
2475 off_t off;
2476
2477 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002478 queue_put(from_writer,
2479 write_error ? (void *) &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002480 continue;
2481 }
2482
2483 off = file_buffer->block;
2484
2485 pthread_mutex_lock(&pos_mutex);
2486
2487 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002488 ERROR("Lseek on destination failed because %s\n",
2489 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002490 write_error = TRUE;
2491 }
2492
plougher110799c2009-03-30 01:50:40 +00002493 if(!write_error && write_bytes(fd, file_buffer->data,
2494 file_buffer->size) == -1) {
2495 ERROR("Write on destination failed because %s\n",
2496 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002497 write_error = TRUE;
2498 }
2499 pthread_mutex_unlock(&pos_mutex);
2500
ploughereb6eac92008-02-26 01:50:48 +00002501 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002502 }
2503}
2504
2505
plougher5b09fd42007-08-06 10:28:41 +00002506int all_zero(struct file_buffer *file_buffer)
2507{
2508 int i;
2509 long entries = file_buffer->size / sizeof(long);
2510 long *p = (long *) file_buffer->data;
2511
2512 for(i = 0; i < entries && p[i] == 0; i++);
2513
2514 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002515 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002516 i < file_buffer->size && file_buffer->data[i] == 0;
2517 i++);
plougher5b09fd42007-08-06 10:28:41 +00002518
2519 return i == file_buffer->size;
2520 }
2521
2522 return 0;
2523}
2524
2525
plougher5507dd92006-11-06 00:43:10 +00002526void *deflator(void *arg)
2527{
plougher7b8ee502009-07-29 07:54:30 +00002528 void *stream = NULL;
plougher5507dd92006-11-06 00:43:10 +00002529 int oldstate;
2530
2531 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2532 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2533
2534 while(1) {
2535 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002536 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002537
plougher1b899fc2008-08-07 01:24:06 +00002538 if(sparse_files && all_zero(file_buffer)) {
2539 file_buffer->c_byte = 0;
2540 queue_put(from_deflate, file_buffer);
2541 } else if(file_buffer->fragment) {
2542 file_buffer->c_byte = file_buffer->size;
2543 queue_put(from_deflate, file_buffer);
2544 } else {
2545 write_buffer = cache_get(writer_buffer, 0, 0);
plougher50b31762009-03-31 04:14:46 +00002546 write_buffer->c_byte = mangle2(&stream,
2547 write_buffer->data, file_buffer->data,
2548 file_buffer->size, block_size, noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002549 write_buffer->sequence = file_buffer->sequence;
2550 write_buffer->file_size = file_buffer->file_size;
2551 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002552 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2553 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002554 write_buffer->fragment = FALSE;
2555 write_buffer->error = FALSE;
2556 cache_block_put(file_buffer);
2557 queue_put(from_deflate, write_buffer);
2558 }
plougher5507dd92006-11-06 00:43:10 +00002559 }
2560}
2561
2562
2563void *frag_deflator(void *arg)
2564{
plougher7b8ee502009-07-29 07:54:30 +00002565 void *stream = NULL;
plougher5507dd92006-11-06 00:43:10 +00002566 int oldstate;
2567
2568 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2569 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2570
2571 while(1) {
2572 int c_byte, compressed_size;
2573 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002574 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002575 cache_get(writer_buffer, file_buffer->block +
2576 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002577
plougher110799c2009-03-30 01:50:40 +00002578 c_byte = mangle2(&stream, write_buffer->data, file_buffer->data,
2579 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002580 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002581 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002582 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002583 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002584 fragment_table[file_buffer->block].size = c_byte;
2585 fragment_table[file_buffer->block].start_block = bytes;
2586 write_buffer->block = bytes;
2587 bytes += compressed_size;
2588 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002589 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002590 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002591 TRACE("Writing fragment %lld, uncompressed size %d, "
2592 "compressed size %d\n", file_buffer->block,
2593 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002594 } else {
2595 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002596 add_pending_fragment(write_buffer, c_byte,
2597 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002598 }
ploughereb6eac92008-02-26 01:50:48 +00002599 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002600 }
2601}
2602
2603
2604#define HASH_ENTRIES 256
2605#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2606struct file_buffer *block_hash[HASH_ENTRIES];
2607
2608void push_buffer(struct file_buffer *file_buffer)
2609{
plougher0f464442008-03-31 00:27:56 +00002610 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002611
2612 file_buffer->next = block_hash[hash];
2613 block_hash[hash] = file_buffer;
2614}
2615
2616
2617struct file_buffer *get_file_buffer(struct queue *queue)
2618{
plougher0f464442008-03-31 00:27:56 +00002619 static unsigned int sequence = 0;
2620 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002621 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2622
2623 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002624 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002625 break;
2626
2627 if(file_buffer) {
2628 if(prev)
2629 prev->next = file_buffer->next;
2630 else
2631 block_hash[hash] = file_buffer->next;
2632 } else {
2633 while(1) {
2634 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002635 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002636 break;
2637 push_buffer(file_buffer);
2638 }
2639 }
2640
plougher0f464442008-03-31 00:27:56 +00002641 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002642
2643 return file_buffer;
2644}
2645
2646
plougher91fbb302008-05-06 02:29:36 +00002647void *progress_thrd(void *arg)
plougher35a10602008-04-21 02:58:16 +00002648{
2649 struct timeval timeval;
2650 struct timespec timespec;
2651 struct itimerval itimerval;
2652 struct winsize winsize;
2653
2654 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
plougher01b43282009-03-30 18:21:37 +00002655 if(isatty(STDOUT_FILENO))
2656 printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
2657 "columns\n");
plougher35a10602008-04-21 02:58:16 +00002658 columns = 80;
2659 } else
2660 columns = winsize.ws_col;
2661 signal(SIGWINCH, sigwinch_handler);
2662 signal(SIGALRM, sigalrm_handler);
2663
2664 itimerval.it_value.tv_sec = 0;
2665 itimerval.it_value.tv_usec = 250000;
2666 itimerval.it_interval.tv_sec = 0;
2667 itimerval.it_interval.tv_usec = 250000;
2668 setitimer(ITIMER_REAL, &itimerval, NULL);
2669
plougher35a10602008-04-21 02:58:16 +00002670 pthread_cond_init(&progress_wait, NULL);
2671
plougher91fbb302008-05-06 02:29:36 +00002672 pthread_mutex_lock(&progress_mutex);
2673
plougher35a10602008-04-21 02:58:16 +00002674 while(1) {
plougher35a10602008-04-21 02:58:16 +00002675 gettimeofday(&timeval, NULL);
2676 timespec.tv_sec = timeval.tv_sec;
2677 if(timeval.tv_usec + 250000 > 999999)
2678 timespec.tv_sec++;
plougher50b31762009-03-31 04:14:46 +00002679 timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
2680 1000;
2681 pthread_cond_timedwait(&progress_wait, &progress_mutex,
2682 &timespec);
plougher43bb7e92008-08-17 17:16:09 +00002683 if(progress_enabled && estimated_uncompressed)
plougher110799c2009-03-30 01:50:40 +00002684 progress_bar(cur_uncompressed, estimated_uncompressed,
2685 columns);
plougher35a10602008-04-21 02:58:16 +00002686 }
2687}
2688
2689
plougher91fbb302008-05-06 02:29:36 +00002690void enable_progress_bar()
2691{
2692 pthread_mutex_lock(&progress_mutex);
2693 progress_enabled = TRUE;
2694 pthread_mutex_unlock(&progress_mutex);
2695}
2696
2697
2698void disable_progress_bar()
2699{
2700 pthread_mutex_lock(&progress_mutex);
2701 progress_enabled = FALSE;
2702 pthread_mutex_unlock(&progress_mutex);
2703}
2704
2705
rloughere4873e02007-11-08 17:50:42 +00002706void progress_bar(long long current, long long max, int columns)
plougher02bc3bc2007-02-25 12:12:01 +00002707{
plougher35a10602008-04-21 02:58:16 +00002708 char rotate_list[] = { '|', '/', '-', '\\' };
plougherf3f95e42010-03-08 01:32:20 +00002709 int max_digits, used, hashes, spaces;
plougher898763d2009-03-29 22:54:55 +00002710 static int tty = -1;
plougher02bc3bc2007-02-25 12:12:01 +00002711
plougherf3f95e42010-03-08 01:32:20 +00002712 if(max == 0)
2713 return;
2714
2715 max_digits = floor(log10(max)) + 1;
2716 used = max_digits * 2 + 11;
2717 hashes = (current * (columns - used)) / max;
2718 spaces = columns - used - hashes;
2719
ploughere9e01392009-03-29 22:48:42 +00002720 if((current > max) || (columns - used < 0))
plougher02bc3bc2007-02-25 12:12:01 +00002721 return;
2722
plougher898763d2009-03-29 22:54:55 +00002723 if(tty == -1)
2724 tty = isatty(STDOUT_FILENO);
2725 if(!tty) {
2726 static long long previous = -1;
2727
2728 /* Updating much more frequently than this results in huge
2729 * log files. */
2730 if((current % 100) != 0 && current != max)
2731 return;
2732 /* Don't update just to rotate the spinner. */
2733 if(current == previous)
2734 return;
2735 previous = current;
2736 }
2737
plougher02bc3bc2007-02-25 12:12:01 +00002738 printf("\r[");
2739
2740 while (hashes --)
2741 putchar('=');
2742
plougher35a10602008-04-21 02:58:16 +00002743 putchar(rotate_list[rotate]);
2744
plougher02bc3bc2007-02-25 12:12:01 +00002745 while(spaces --)
2746 putchar(' ');
2747
2748 printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2749 printf(" %3lld%%", current * 100 / max);
2750 fflush(stdout);
2751}
2752
2753
plougher110799c2009-03-30 01:50:40 +00002754void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2755 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002756{
2757 file_count ++;
2758 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002759 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2760 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002761}
2762
2763
plougher50b31762009-03-31 04:14:46 +00002764void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2765 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002766 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002767{
plougher5507dd92006-11-06 00:43:10 +00002768 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002769 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002770 unsigned int *block_listp = NULL;
2771 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002772
plougher50b31762009-03-31 04:14:46 +00002773 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2774 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002775
plougher5507dd92006-11-06 00:43:10 +00002776 if(dupl_ptr) {
2777 *duplicate_file = FALSE;
2778 fragment = get_and_fill_fragment(file_buffer);
2779 dupl_ptr->fragment = fragment;
2780 } else
2781 *duplicate_file = TRUE;
2782
ploughereb6eac92008-02-26 01:50:48 +00002783 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002784
2785 total_bytes += size;
2786 file_count ++;
2787
plougher35a10602008-04-21 02:58:16 +00002788 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002789
plougherc1ace522010-05-01 03:00:45 +00002790 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002791 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002792}
2793
2794
plougher110799c2009-03-30 01:50:40 +00002795void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2796 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002797{
2798 struct fragment *fragment;
2799 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002800
2801 checksum = get_checksum_mem_buffer(file_buffer);
2802
plougher29e37092007-04-15 01:24:51 +00002803 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002804 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2805 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002806 return;
2807 }
plougher5507dd92006-11-06 00:43:10 +00002808
2809 fragment = get_and_fill_fragment(file_buffer);
2810
ploughereb6eac92008-02-26 01:50:48 +00002811 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002812
2813 if(duplicate_checking)
2814 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2815
2816 total_bytes += size;
2817 file_count ++;
2818
2819 *duplicate_file = FALSE;
2820
plougher35a10602008-04-21 02:58:16 +00002821 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002822
plougherc1ace522010-05-01 03:00:45 +00002823 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002824 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002825
plougher018d2b32007-04-23 03:01:48 +00002826 return;
plougher5507dd92006-11-06 00:43:10 +00002827}
2828
2829
plougher00d08172009-09-03 10:17:44 +00002830int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2831 struct file_buffer *read_buffer, int *duplicate_file)
2832{
2833 long long read_size, file_bytes, start;
2834 struct fragment *fragment;
2835 unsigned int *block_list = NULL;
2836 int block = 0, status;
2837 long long sparse = 0;
2838 struct file_buffer *fragment_buffer = NULL;
2839
2840 *duplicate_file = FALSE;
2841
2842 lock_fragments();
2843
2844 file_bytes = 0;
2845 start = bytes;
2846 while (1) {
2847 read_size = read_buffer->file_size;
2848 if(read_buffer->fragment && read_buffer->c_byte)
2849 fragment_buffer = read_buffer;
2850 else {
2851 block_list = realloc(block_list, (block + 1) *
2852 sizeof(unsigned int));
2853 if(block_list == NULL)
2854 BAD_ERROR("Out of memory allocating block_list"
2855 "\n");
2856 block_list[block ++] = read_buffer->c_byte;
2857 if(read_buffer->c_byte) {
2858 read_buffer->block = bytes;
2859 bytes += read_buffer->size;
2860 cache_rehash(read_buffer, read_buffer->block);
2861 file_bytes += read_buffer->size;
2862 queue_put(to_writer, read_buffer);
2863 } else {
2864 sparse += read_buffer->size;
2865 cache_block_put(read_buffer);
2866 }
2867 }
plougher286b6b32009-09-19 03:29:27 +00002868 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002869
2870 if(read_size != -1)
2871 break;
2872
2873 read_buffer = get_file_buffer(from_deflate);
2874 if(read_buffer->error)
2875 goto read_err;
2876 }
2877
2878 unlock_fragments();
2879 fragment = get_and_fill_fragment(fragment_buffer);
2880 cache_block_put(fragment_buffer);
2881
2882 if(duplicate_checking)
2883 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2884 0, 0, FALSE);
2885 file_count ++;
2886 total_bytes += read_size;
2887
plougherc1ace522010-05-01 03:00:45 +00002888 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2889 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002890
2891 if(duplicate_checking == FALSE)
2892 free(block_list);
2893
2894 return 0;
2895
2896read_err:
plougher286b6b32009-09-19 03:29:27 +00002897 cur_uncompressed -= block;
plougher00d08172009-09-03 10:17:44 +00002898 status = read_buffer->error;
2899 bytes = start;
2900 if(!block_device) {
2901 int res;
2902
2903 queue_put(to_writer, NULL);
2904 if(queue_get(from_writer) != 0)
2905 EXIT_MKSQUASHFS();
2906 res = ftruncate(fd, bytes);
2907 if(res != 0)
2908 BAD_ERROR("Failed to truncate dest file because %s\n",
2909 strerror(errno));
2910 }
2911 unlock_fragments();
2912 free(block_list);
2913 cache_block_put(read_buffer);
2914 return status;
2915}
2916
2917
plougher110799c2009-03-30 01:50:40 +00002918int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002919 long long read_size, struct file_buffer *read_buffer,
2920 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002921{
plougher23377982007-11-12 04:04:48 +00002922 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002923 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002924 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002925 int block, status;
2926 int blocks = (read_size + block_size - 1) >> block_log;
2927 long long sparse = 0;
2928 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002929
plougher29e37092007-04-15 01:24:51 +00002930 *duplicate_file = FALSE;
2931
plougher5507dd92006-11-06 00:43:10 +00002932 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
2933 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002934
plougher2ea89142008-03-11 01:34:19 +00002935 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002936
plougher5507dd92006-11-06 00:43:10 +00002937 file_bytes = 0;
2938 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002939 for(block = 0; block < blocks;) {
2940 if(read_buffer->fragment && read_buffer->c_byte) {
2941 fragment_buffer = read_buffer;
2942 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002943 } else {
plougher1b899fc2008-08-07 01:24:06 +00002944 block_list[block] = read_buffer->c_byte;
2945 if(read_buffer->c_byte) {
2946 read_buffer->block = bytes;
2947 bytes += read_buffer->size;
2948 cache_rehash(read_buffer, read_buffer->block);
2949 file_bytes += read_buffer->size;
2950 queue_put(to_writer, read_buffer);
2951 } else {
2952 sparse += read_buffer->size;
2953 cache_block_put(read_buffer);
2954 }
2955 }
2956 inc_progress_bar();
2957
2958 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002959 read_buffer = get_file_buffer(from_deflate);
2960 if(read_buffer->error)
2961 goto read_err;
2962 }
plougher1f413c82005-11-18 00:02:14 +00002963 }
2964
plougher2ea89142008-03-11 01:34:19 +00002965 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00002966 fragment = get_and_fill_fragment(fragment_buffer);
2967 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002968
plougher1f413c82005-11-18 00:02:14 +00002969 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00002970 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2971 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002972 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002973 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002974
plougher360514a2009-03-30 03:01:38 +00002975 /*
2976 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002977 * a smaller block count on stat calls to sparse files. This is
2978 * to ensure intelligent applications like cp correctly handle the
2979 * file as a sparse file. If the file in the original filesystem isn't
2980 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002981 * report it as non-sparse on stat calls to preserve semantics
2982 */
plougher1b899fc2008-08-07 01:24:06 +00002983 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2984 sparse = 0;
2985
plougherc1ace522010-05-01 03:00:45 +00002986 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2987 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002988
plougher5507dd92006-11-06 00:43:10 +00002989 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002990 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002991
plougher018d2b32007-04-23 03:01:48 +00002992 return 0;
plougher1f413c82005-11-18 00:02:14 +00002993
2994read_err:
plougher018d2b32007-04-23 03:01:48 +00002995 cur_uncompressed -= block;
2996 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002997 bytes = start;
2998 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00002999 int res;
3000
plougher5507dd92006-11-06 00:43:10 +00003001 queue_put(to_writer, NULL);
3002 if(queue_get(from_writer) != 0)
3003 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003004 res = ftruncate(fd, bytes);
3005 if(res != 0)
3006 BAD_ERROR("Failed to truncate dest file because %s\n",
3007 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003008 }
plougher2ea89142008-03-11 01:34:19 +00003009 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003010 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003011 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003012 return status;
plougher1f413c82005-11-18 00:02:14 +00003013}
3014
3015
plougher110799c2009-03-30 01:50:40 +00003016int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003017 long long read_size, struct file_buffer *read_buffer,
3018 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003019{
plougher29e37092007-04-15 01:24:51 +00003020 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003021 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003022 struct fragment *fragment;
3023 struct file_info *dupl_ptr;
3024 int blocks = (read_size + block_size - 1) >> block_log;
3025 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003026 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003027 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003028 long long sparse = 0;
3029 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003030
plougher50b31762009-03-31 04:14:46 +00003031 block_list = malloc(blocks * sizeof(unsigned int));
3032 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003033 BAD_ERROR("Out of memory allocating block_list\n");
3034 block_listp = block_list;
3035
plougher50b31762009-03-31 04:14:46 +00003036 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3037 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003038 BAD_ERROR("Out of memory allocating file block list\n");
3039
plougher4e8484a2008-03-15 23:30:16 +00003040 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003041
3042 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003043 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003044 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3045 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003046
3047 for(block = 0; block < blocks;) {
3048 if(read_buffer->fragment && read_buffer->c_byte) {
3049 fragment_buffer = read_buffer;
3050 blocks = read_size >> block_log;
3051 } else {
3052 block_list[block] = read_buffer->c_byte;
3053
3054 if(read_buffer->c_byte) {
3055 read_buffer->block = bytes;
3056 bytes += read_buffer->size;
3057 file_bytes += read_buffer->size;
3058 cache_rehash(read_buffer, read_buffer->block);
3059 if(block < thresh) {
3060 buffer_list[block] = NULL;
3061 queue_put(to_writer, read_buffer);
3062 } else
3063 buffer_list[block] = read_buffer;
3064 } else {
3065 buffer_list[block] = NULL;
3066 sparse += read_buffer->size;
3067 cache_block_put(read_buffer);
3068 }
3069 }
3070 inc_progress_bar();
3071
3072 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003073 read_buffer = get_file_buffer(from_deflate);
3074 if(read_buffer->error)
3075 goto read_err;
3076 }
plougher5507dd92006-11-06 00:43:10 +00003077 }
3078
plougher110799c2009-03-30 01:50:40 +00003079 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3080 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003081
3082 if(dupl_ptr) {
3083 *duplicate_file = FALSE;
3084 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003085 if(buffer_list[block])
3086 queue_put(to_writer, buffer_list[block]);
3087 fragment = get_and_fill_fragment(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003088 dupl_ptr->fragment = fragment;
3089 } else {
3090 *duplicate_file = TRUE;
3091 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003092 cache_block_put(buffer_list[block]);
3093 bytes = start;
3094 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003095 int res;
3096
plougher1b899fc2008-08-07 01:24:06 +00003097 queue_put(to_writer, NULL);
3098 if(queue_get(from_writer) != 0)
3099 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003100 res = ftruncate(fd, bytes);
3101 if(res != 0)
3102 BAD_ERROR("Failed to truncate dest file because"
3103 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003104 }
plougher5507dd92006-11-06 00:43:10 +00003105 }
3106
plougher2ea89142008-03-11 01:34:19 +00003107 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003108 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003109 free(buffer_list);
3110 file_count ++;
3111 total_bytes += read_size;
3112
plougher360514a2009-03-30 03:01:38 +00003113 /*
3114 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003115 * a smaller block count on stat calls to sparse files. This is
3116 * to ensure intelligent applications like cp correctly handle the
3117 * file as a sparse file. If the file in the original filesystem isn't
3118 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003119 * report it as non-sparse on stat calls to preserve semantics
3120 */
plougher1b899fc2008-08-07 01:24:06 +00003121 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3122 sparse = 0;
3123
plougherc1ace522010-05-01 03:00:45 +00003124 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3125 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003126
plougher5507dd92006-11-06 00:43:10 +00003127 if(*duplicate_file == TRUE)
3128 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003129
plougher018d2b32007-04-23 03:01:48 +00003130 return 0;
plougher5507dd92006-11-06 00:43:10 +00003131
3132read_err:
plougher018d2b32007-04-23 03:01:48 +00003133 cur_uncompressed -= block;
3134 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003135 bytes = start;
3136 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003137 int res;
3138
plougher5507dd92006-11-06 00:43:10 +00003139 queue_put(to_writer, NULL);
3140 if(queue_get(from_writer) != 0)
3141 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003142 res = ftruncate(fd, bytes);
3143 if(res != 0)
3144 BAD_ERROR("Failed to truncate dest file because %s\n",
3145 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003146 }
plougher2ea89142008-03-11 01:34:19 +00003147 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003148 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003149 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003150 free(buffer_list);
3151 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003152 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003153 return status;
plougher5507dd92006-11-06 00:43:10 +00003154}
3155
3156
plougher110799c2009-03-30 01:50:40 +00003157void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3158 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003159{
plougher018d2b32007-04-23 03:01:48 +00003160 int status;
3161 struct file_buffer *read_buffer;
3162 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003163
plougher018d2b32007-04-23 03:01:48 +00003164again:
3165 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003166
plougher23377982007-11-12 04:04:48 +00003167 status = read_buffer->error;
3168 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003169 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003170 goto file_err;
3171 }
3172
3173 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003174
plougher00d08172009-09-03 10:17:44 +00003175 if(read_size == -1)
3176 status = write_file_process(inode, dir_ent, read_buffer,
3177 duplicate_file);
3178 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003179 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003180 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003181 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003182 write_file_frag(inode, dir_ent, read_size, read_buffer,
3183 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003184 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003185 status = write_file_blocks_dup(inode, dir_ent, read_size,
3186 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003187 else
plougher50b31762009-03-31 04:14:46 +00003188 status = write_file_blocks(inode, dir_ent, read_size,
3189 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003190
plougher018d2b32007-04-23 03:01:48 +00003191file_err:
3192 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003193 ERROR("File %s changed size while reading filesystem, "
3194 "attempting to re-read\n", dir_ent->pathname);
plougher018d2b32007-04-23 03:01:48 +00003195 goto again;
3196 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003197 ERROR("Failed to read file %s, creating empty file\n",
3198 dir_ent->pathname);
plougher29e37092007-04-15 01:24:51 +00003199 write_file_empty(inode, dir_ent, duplicate_file);
3200 }
plougher5507dd92006-11-06 00:43:10 +00003201}
3202
3203
plougher44d54ef2010-02-08 22:13:49 +00003204#define BUFF_SIZE 8192
3205char b_buffer[BUFF_SIZE];
plougher1f413c82005-11-18 00:02:14 +00003206char *name;
3207char *basename_r();
3208
3209char *getbase(char *pathname)
3210{
3211 char *result;
3212
3213 if(*pathname != '/') {
plougher44d54ef2010-02-08 22:13:49 +00003214 result = getcwd(b_buffer, BUFF_SIZE);
3215 if(result == NULL)
3216 return NULL;
3217 strcat(strcat(b_buffer, "/"), pathname);
plougher1f413c82005-11-18 00:02:14 +00003218 } else
3219 strcpy(b_buffer, pathname);
3220 name = b_buffer;
3221 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3222 return NULL;
3223 else
3224 return result;
3225}
3226
3227
3228char *basename_r()
3229{
3230 char *s;
3231 char *p;
3232 int n = 1;
3233
3234 for(;;) {
3235 s = name;
3236 if(*name == '\0')
3237 return NULL;
3238 if(*name != '/') {
3239 while(*name != '\0' && *name != '/') name++;
3240 n = name - s;
3241 }
3242 while(*name == '/') name++;
3243 if(strncmp(s, ".", n) == 0)
3244 continue;
plougher110799c2009-03-30 01:50:40 +00003245 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3246 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003247 s[n] = '\0';
3248 return s;
3249 }
3250 if(strcmp(p, "..") == 0)
3251 continue;
3252 return p;
3253 }
3254}
3255
3256
3257struct inode_info *lookup_inode(struct stat *buf)
3258{
3259 int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3260 struct inode_info *inode = inode_info[inode_hash];
3261
3262 while(inode != NULL) {
3263 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3264 inode->nlink ++;
3265 return inode;
3266 }
3267 inode = inode->next;
3268 }
3269
3270 if((inode = malloc(sizeof(struct inode_info))) == NULL)
plougher50b31762009-03-31 04:14:46 +00003271 BAD_ERROR("Out of memory in inode hash table entry allocation"
3272 "\n");
plougher1f413c82005-11-18 00:02:14 +00003273
3274 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003275 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003276 inode->root_entry = FALSE;
plougher00d08172009-09-03 10:17:44 +00003277 inode->pseudo_file = FALSE;
plougher1f413c82005-11-18 00:02:14 +00003278 inode->inode = SQUASHFS_INVALID_BLK;
3279 inode->nlink = 1;
plougherdc86c3c2007-12-05 02:15:10 +00003280
3281 if((buf->st_mode & S_IFMT) == S_IFREG)
plougher110799c2009-03-30 01:50:40 +00003282 estimated_uncompressed += (buf->st_size + block_size - 1) >>
3283 block_log;
plougherdc86c3c2007-12-05 02:15:10 +00003284
plougher1f413c82005-11-18 00:02:14 +00003285 if((buf->st_mode & S_IFMT) == S_IFDIR)
3286 inode->inode_number = dir_inode_no ++;
3287 else
3288 inode->inode_number = inode_no ++;
3289
3290 inode->next = inode_info[inode_hash];
3291 inode_info[inode_hash] = inode;
3292
3293 return inode;
3294}
3295
3296
plougher110799c2009-03-30 01:50:40 +00003297inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
ploughera326c182009-08-29 05:41:45 +00003298 struct inode_info *inode_info, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003299{
plougher110799c2009-03-30 01:50:40 +00003300 if((dir->count % DIR_ENTRIES) == 0) {
3301 dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) *
3302 sizeof(struct dir_ent *));
3303 if(dir->list == NULL)
plougher1f413c82005-11-18 00:02:14 +00003304 BAD_ERROR("Out of memory in add_dir_entry\n");
plougher110799c2009-03-30 01:50:40 +00003305 }
plougher1f413c82005-11-18 00:02:14 +00003306
3307 if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL)
3308 BAD_ERROR("Out of memory in linux_opendir\n");
3309
3310 if(sub_dir)
3311 sub_dir->dir_ent = dir->list[dir->count];
3312 dir->list[dir->count]->name = strdup(name);
plougher110799c2009-03-30 01:50:40 +00003313 dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) :
3314 NULL;
plougher1f413c82005-11-18 00:02:14 +00003315 dir->list[dir->count]->inode = inode_info;
3316 dir->list[dir->count]->dir = sub_dir;
ploughera326c182009-08-29 05:41:45 +00003317 dir->list[dir->count++]->our_dir = dir;
plougher1f413c82005-11-18 00:02:14 +00003318 dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
3319}
3320
3321
3322int compare_name(const void *ent1_ptr, const void *ent2_ptr)
3323{
3324 struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
3325 struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
3326
3327 return strcmp(ent1->name, ent2->name);
3328}
3329
3330
3331void sort_directory(struct dir_info *dir)
3332{
3333 qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
3334
3335 if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
3336 dir->dir_is_ldir = FALSE;
3337}
3338
3339
3340struct dir_info *scan1_opendir(char *pathname)
3341{
plougher1f413c82005-11-18 00:02:14 +00003342 struct dir_info *dir;
3343
3344 if((dir = malloc(sizeof(struct dir_info))) == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003345 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003346
3347 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3348 free(dir);
3349 return NULL;
3350 }
3351 dir->pathname = strdup(pathname);
plougher360514a2009-03-30 03:01:38 +00003352 dir->count = dir->directory_count = dir->current_count = dir->byte_count
3353 = 0;
plougher1f413c82005-11-18 00:02:14 +00003354 dir->dir_is_ldir = TRUE;
3355 dir->list = NULL;
3356
3357 return dir;
3358}
3359
3360
3361int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3362{
3363 int i, n, pass;
3364 char *basename;
3365 static int index = 0;
3366
3367 if(dir->count < old_root_entries)
3368 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003369 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003370 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003371 add_dir_entry(old_root_entry[i].name, "", NULL,
3372 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003373 }
3374
3375 while(index < source) {
3376 if((basename = getbase(source_path[index])) == NULL) {
plougher110799c2009-03-30 01:50:40 +00003377 ERROR("Bad source directory %s - skipping ...\n",
3378 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003379 index ++;
3380 continue;
3381 }
3382 strcpy(dir_name, basename);
3383 pass = 1;
3384 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003385 for(n = 0; n < dir->count &&
3386 strcmp(dir->list[n]->name, dir_name) != 0; n++);
plougher1f413c82005-11-18 00:02:14 +00003387 if(n == dir->count)
3388 break;
plougher50b31762009-03-31 04:14:46 +00003389 ERROR("Source directory entry %s already used! - trying"
3390 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003391 sprintf(dir_name, "%s_%d", basename, pass++);
3392 ERROR("%s\n", dir_name);
3393 }
3394 strcpy(pathname, source_path[index ++]);
3395 return 1;
3396 }
3397 return 0;
3398}
3399
3400
3401int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3402{
3403 struct dirent *d_name;
3404 int i, pass;
3405
3406 if(dir->count < old_root_entries)
3407 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003408 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003409 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003410 add_dir_entry(old_root_entry[i].name, "", NULL,
3411 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003412 }
3413
3414 if((d_name = readdir(dir->linuxdir)) != NULL) {
3415 strcpy(dir_name, d_name->d_name);
3416 pass = 1;
3417 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003418 for(i = 0; i < dir->count &&
3419 strcmp(dir->list[i]->name, dir_name) != 0; i++);
plougher1f413c82005-11-18 00:02:14 +00003420 if(i == dir->count)
3421 break;
plougher50b31762009-03-31 04:14:46 +00003422 ERROR("Source directory entry %s already used! - trying"
3423 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003424 sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
3425 ERROR("%s\n", dir_name);
3426 }
plougher110799c2009-03-30 01:50:40 +00003427 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3428 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003429 return 1;
3430 }
3431
3432 return 0;
3433}
3434
3435
3436int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3437{
3438 struct dirent *d_name;
3439
3440 if((d_name = readdir(dir->linuxdir)) != NULL) {
3441 strcpy(dir_name, d_name->d_name);
plougher110799c2009-03-30 01:50:40 +00003442 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3443 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003444 return 1;
3445 }
3446
3447 return 0;
3448}
3449
3450
plougher43244f22009-04-05 02:04:51 +00003451struct dir_ent *scan2_readdir(struct dir_info *dir_info)
3452{
3453 int current_count;
3454
3455 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003456 if(dir_info->list[current_count]->inode->root_entry)
plougher43244f22009-04-05 02:04:51 +00003457 continue;
3458 else
3459 return dir_info->list[current_count];
3460 return NULL;
3461}
3462
3463
3464struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3465{
3466 int i;
3467
3468 for(i = 0; i < dir->count; i++)
3469 if(strcmp(dir->list[i]->name, name) == 0)
3470 return dir->list[i];
3471
3472 return NULL;
3473}
3474
3475
3476struct dir_ent *scan3_readdir(struct directory *dir, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003477{
3478 int current_count;
3479
3480 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003481 if(dir_info->list[current_count]->inode->root_entry)
3482 add_dir(dir_info->list[current_count]->inode->inode,
3483 dir_info->list[current_count]->inode->inode_number,
plougher110799c2009-03-30 01:50:40 +00003484 dir_info->list[current_count]->name,
ploughera326c182009-08-29 05:41:45 +00003485 dir_info->list[current_count]->inode->type, dir);
plougher1f413c82005-11-18 00:02:14 +00003486 else
3487 return dir_info->list[current_count];
plougher43244f22009-04-05 02:04:51 +00003488 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003489}
3490
3491
3492void scan1_freedir(struct dir_info *dir)
3493{
plougherfbed12b2006-02-07 12:45:53 +00003494 if(dir->pathname[0] != '\0')
3495 closedir(dir->linuxdir);
plougherb087fc12010-05-01 04:53:28 +00003496 free(dir->pathname);
3497 dir->pathname = NULL;
plougher1f413c82005-11-18 00:02:14 +00003498}
3499
3500
plougher43244f22009-04-05 02:04:51 +00003501void scan2_freedir(struct dir_info *dir)
3502{
3503 dir->current_count = 0;
plougherb087fc12010-05-01 04:53:28 +00003504 if(dir->pathname) {
3505 free(dir->pathname);
3506 dir->pathname = NULL;
3507 }
plougher43244f22009-04-05 02:04:51 +00003508}
3509
3510
3511void scan3_freedir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00003512{
3513 if(dir->index)
3514 free(dir->index);
3515 free(dir->buff);
3516}
3517
3518
plougher110799c2009-03-30 01:50:40 +00003519void dir_scan(squashfs_inode *inode, char *pathname,
3520 int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00003521{
plougher0e453652006-11-06 01:49:35 +00003522 struct stat buf;
plougher8f8e1a12007-10-18 02:50:21 +00003523 struct dir_info *dir_info = dir_scan1(pathname, paths, _readdir);
plougher1f413c82005-11-18 00:02:14 +00003524 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003525
3526 if(dir_info == NULL)
3527 return;
3528
plougher43244f22009-04-05 02:04:51 +00003529 dir_scan2(dir_info, pseudo);
3530
plougher1f413c82005-11-18 00:02:14 +00003531 if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL)
3532 BAD_ERROR("Out of memory in dir_scan\n");
3533
plougher1f413c82005-11-18 00:02:14 +00003534 if(pathname[0] == '\0') {
plougher110799c2009-03-30 01:50:40 +00003535 /*
plougher1e4dbce2010-07-31 03:01:34 +00003536 * dummy top level directory, if multiple sources specified on
plougher110799c2009-03-30 01:50:40 +00003537 * command line
3538 */
plougher43244f22009-04-05 02:04:51 +00003539 memset(&buf, 0, sizeof(buf));
plougher0e453652006-11-06 01:49:35 +00003540 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3541 buf.st_uid = getuid();
3542 buf.st_gid = getgid();
3543 buf.st_mtime = time(NULL);
3544 buf.st_dev = 0;
3545 buf.st_ino = 0;
plougher1e4dbce2010-07-31 03:01:34 +00003546 dir_ent->inode = lookup_inode(&buf);
3547 dir_ent->inode->pseudo_file = PSEUDO_FILE_OTHER;
3548 } else {
3549 if(lstat(pathname, &buf) == -1) {
3550 ERROR("Cannot stat dir/file %s because %s, ignoring",
3551 pathname, strerror(errno));
3552 return;
3553 }
3554 dir_ent->inode = lookup_inode(&buf);
plougher1f413c82005-11-18 00:02:14 +00003555 }
plougher0e453652006-11-06 01:49:35 +00003556
plougher0e453652006-11-06 01:49:35 +00003557 if(root_inode_number) {
3558 dir_ent->inode->inode_number = root_inode_number;
3559 dir_inode_no --;
3560 }
3561 dir_ent->name = dir_ent->pathname = strdup(pathname);
3562 dir_ent->dir = dir_info;
3563 dir_ent->our_dir = NULL;
plougher0e453652006-11-06 01:49:35 +00003564 dir_info->dir_ent = dir_ent;
3565
plougher1d1c6bb2010-07-21 03:03:13 +00003566 if(sorted) {
3567 int res = generate_file_priorities(dir_info, 0,
plougher110799c2009-03-30 01:50:40 +00003568 &dir_info->dir_ent->inode->buf);
plougher1d1c6bb2010-07-21 03:03:13 +00003569
3570 if(res == FALSE)
3571 BAD_ERROR("generate_file_priorities failed\n");
3572 }
plougher5507dd92006-11-06 00:43:10 +00003573 queue_put(to_reader, dir_info);
3574 if(sorted)
plougher117b2ea2006-02-09 09:23:56 +00003575 sort_files_and_write(dir_info);
plougher91fbb302008-05-06 02:29:36 +00003576 if(progress)
3577 enable_progress_bar();
plougher43244f22009-04-05 02:04:51 +00003578 dir_scan3(inode, dir_info);
plougher0e453652006-11-06 01:49:35 +00003579 dir_ent->inode->inode = *inode;
3580 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003581}
3582
3583
plougher110799c2009-03-30 01:50:40 +00003584struct dir_info *dir_scan1(char *pathname, struct pathnames *paths,
3585 int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00003586{
3587 struct dir_info *dir, *sub_dir;
3588 struct stat buf;
3589 char filename[8192], dir_name[8192];
plougherf9039c92007-10-22 03:54:16 +00003590 struct pathnames *new;
plougher1f413c82005-11-18 00:02:14 +00003591
3592 if((dir = scan1_opendir(pathname)) == NULL) {
3593 ERROR("Could not open %s, skipping...\n", pathname);
3594 goto error;
3595 }
3596
3597 while(_readdir(filename, dir_name, dir) != FALSE) {
3598
3599 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
3600 continue;
3601
3602 if(lstat(filename, &buf) == -1) {
plougher110799c2009-03-30 01:50:40 +00003603 ERROR("Cannot stat dir/file %s because %s, ignoring",
3604 filename, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003605 continue;
3606 }
plougher29e37092007-04-15 01:24:51 +00003607
3608 if((buf.st_mode & S_IFMT) != S_IFREG &&
3609 (buf.st_mode & S_IFMT) != S_IFDIR &&
3610 (buf.st_mode & S_IFMT) != S_IFLNK &&
3611 (buf.st_mode & S_IFMT) != S_IFCHR &&
3612 (buf.st_mode & S_IFMT) != S_IFBLK &&
3613 (buf.st_mode & S_IFMT) != S_IFIFO &&
3614 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003615 ERROR("File %s has unrecognised filetype %d, ignoring"
3616 "\n", filename, buf.st_mode & S_IFMT);
plougher29e37092007-04-15 01:24:51 +00003617 continue;
3618 }
3619
plougher8f8e1a12007-10-18 02:50:21 +00003620 if(old_exclude) {
3621 if(old_excluded(filename, &buf))
3622 continue;
3623 } else {
3624 if(excluded(paths, dir_name, &new))
3625 continue;
3626 }
plougher1f413c82005-11-18 00:02:14 +00003627
3628 if((buf.st_mode & S_IFMT) == S_IFDIR) {
plougher110799c2009-03-30 01:50:40 +00003629 sub_dir = dir_scan1(filename, new, scan1_readdir);
3630 if(sub_dir == NULL)
plougher1f413c82005-11-18 00:02:14 +00003631 continue;
3632 dir->directory_count ++;
3633 } else
3634 sub_dir = NULL;
3635
plougher110799c2009-03-30 01:50:40 +00003636 add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf),
ploughera326c182009-08-29 05:41:45 +00003637 dir);
plougher1f413c82005-11-18 00:02:14 +00003638 }
3639
3640 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003641
3642error:
3643 return dir;
3644}
3645
plougher2ea89142008-03-11 01:34:19 +00003646
plougher43244f22009-04-05 02:04:51 +00003647struct dir_info *dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
3648{
3649 struct dir_info *sub_dir;
3650 struct dir_ent *dir_ent;
3651 struct pseudo_entry *pseudo_ent;
3652 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003653 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003654
3655 if(dir == NULL && (dir = scan1_opendir("")) == NULL)
3656 return NULL;
3657
3658 while((dir_ent = scan2_readdir(dir)) != NULL) {
3659 struct inode_info *inode_info = dir_ent->inode;
3660 struct stat *buf = &inode_info->buf;
3661 char *name = dir_ent->name;
3662
3663 if((buf->st_mode & S_IFMT) == S_IFDIR)
3664 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
3665 }
3666
3667 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3668 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherb34f9f62009-04-26 02:08:42 +00003669 if(pseudo_ent->dev->type == 's') {
3670 struct stat *buf;
3671 if(dir_ent == NULL) {
3672 ERROR("Pseudo set file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003673 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003674 pseudo_ent->pathname);
3675 continue;
3676 }
ploughera326c182009-08-29 05:41:45 +00003677 if(dir_ent->inode->root_entry) {
plougherb34f9f62009-04-26 02:08:42 +00003678 ERROR("Pseudo set file \"%s\" is a pre-existing"
3679 " file in the filesystem being appended"
3680 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003681 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003682 continue;
3683 }
3684 buf = &dir_ent->inode->buf;
3685 buf->st_mode = (buf->st_mode & S_IFMT) |
3686 pseudo_ent->dev->mode;
3687 buf->st_uid = pseudo_ent->dev->uid;
3688 buf->st_gid = pseudo_ent->dev->gid;
3689 continue;
3690 }
3691
plougher43244f22009-04-05 02:04:51 +00003692 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003693 if(dir_ent->inode->root_entry)
3694 ERROR("Pseudo file \"%s\" is a pre-existing"
3695 " file in the filesystem being appended"
3696 " to. Ignoring.\n",
3697 pseudo_ent->pathname);
3698 else
3699 ERROR("Pseudo file \"%s\" exists in source "
3700 "filesystem \"%s\"\n. Ignoring, "
3701 "exclude it (-e/-ef) to override.\n",
3702 pseudo_ent->pathname,
3703 dir_ent->pathname);
plougher43244f22009-04-05 02:04:51 +00003704 continue;
3705 }
3706
3707 if(pseudo_ent->dev->type == 'd') {
3708 sub_dir = dir_scan2(NULL, pseudo_ent->pseudo);
3709 if(sub_dir == NULL) {
3710 ERROR("Could not create pseudo directory \"%s\""
3711 ", skipping...\n",
3712 pseudo_ent->pathname);
3713 continue;
3714 }
3715 dir->directory_count ++;
3716 } else
3717 sub_dir = NULL;
3718
3719 memset(&buf, 0, sizeof(buf));
3720 buf.st_mode = pseudo_ent->dev->mode;
3721 buf.st_uid = pseudo_ent->dev->uid;
3722 buf.st_gid = pseudo_ent->dev->gid;
3723 buf.st_rdev = makedev(pseudo_ent->dev->major,
3724 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003725 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003726 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003727
plougher4ab7e512009-05-05 02:35:58 +00003728 if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003729#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003730 struct stat buf2;
3731 int res = stat(pseudo_ent->dev->filename, &buf2);
plougherb85e9ad2010-05-02 01:46:12 +00003732 struct inode_info *inode;
plougher4ab7e512009-05-05 02:35:58 +00003733 if(res == -1) {
3734 ERROR("Stat on pseudo file \"%s\" failed, "
3735 "skipping...", pseudo_ent->pathname);
3736 continue;
3737 }
3738 buf.st_size = buf2.st_size;
plougherb85e9ad2010-05-02 01:46:12 +00003739 inode = lookup_inode(&buf);
3740 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003741 add_dir_entry(pseudo_ent->name,
plougherb85e9ad2010-05-02 01:46:12 +00003742 pseudo_ent->dev->filename, sub_dir, inode,
3743 dir);
plougher00d08172009-09-03 10:17:44 +00003744#else
3745 struct inode_info *inode = lookup_inode(&buf);
plougherba674e82009-09-10 03:50:00 +00003746 inode->pseudo_id = pseudo_ent->dev->pseudo_id;
plougherb85e9ad2010-05-02 01:46:12 +00003747 inode->pseudo_file = PSEUDO_FILE_PROCESS;
plougher00d08172009-09-03 10:17:44 +00003748 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
3749 sub_dir, inode, dir);
3750#endif
plougherb85e9ad2010-05-02 01:46:12 +00003751 } else {
3752 struct inode_info *inode = lookup_inode(&buf);
3753 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003754 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
plougherb85e9ad2010-05-02 01:46:12 +00003755 sub_dir, inode, dir);
3756 }
plougher43244f22009-04-05 02:04:51 +00003757 }
3758
3759 scan2_freedir(dir);
3760 sort_directory(dir);
3761
3762 return dir;
3763}
3764
3765
3766void dir_scan3(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003767{
3768 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00003769 int duplicate_file;
ploughere4e92092010-05-01 04:51:50 +00003770 char *pathname = dir_info->dir_ent->pathname;
plougher1f413c82005-11-18 00:02:14 +00003771 struct directory dir;
3772 struct dir_ent *dir_ent;
3773
plougher43244f22009-04-05 02:04:51 +00003774 scan3_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003775
plougher43244f22009-04-05 02:04:51 +00003776 while((dir_ent = scan3_readdir(&dir, dir_info)) != NULL) {
plougher1f413c82005-11-18 00:02:14 +00003777 struct inode_info *inode_info = dir_ent->inode;
3778 struct stat *buf = &inode_info->buf;
3779 char *filename = dir_ent->pathname;
3780 char *dir_name = dir_ent->name;
plougher50b31762009-03-31 04:14:46 +00003781 unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR)
3782 ? dir_ent->inode->inode_number :
plougher110799c2009-03-30 01:50:40 +00003783 dir_ent->inode->inode_number + dir_inode_no;
plougher1f413c82005-11-18 00:02:14 +00003784
3785 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3786 switch(buf->st_mode & S_IFMT) {
3787 case S_IFREG:
3788 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00003789 write_file(inode, dir_ent,
3790 &duplicate_file);
3791 INFO("file %s, uncompressed size %lld "
3792 "bytes %s\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003793 (long long) buf->st_size,
3794 duplicate_file ? "DUPLICATE" :
3795 "");
plougher1f413c82005-11-18 00:02:14 +00003796 break;
3797
3798 case S_IFDIR:
3799 squashfs_type = SQUASHFS_DIR_TYPE;
plougher43244f22009-04-05 02:04:51 +00003800 dir_scan3(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003801 break;
3802
3803 case S_IFLNK:
3804 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003805 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003806 squashfs_type, 0, 0, 0, NULL,
3807 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003808 INFO("symbolic link %s inode 0x%llx\n",
3809 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003810 sym_count ++;
3811 break;
3812
3813 case S_IFCHR:
3814 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003815 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003816 squashfs_type, 0, 0, 0, NULL,
3817 NULL, NULL, 0);
3818 INFO("character device %s inode 0x%llx"
3819 "\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003820 dev_count ++;
3821 break;
3822
3823 case S_IFBLK:
3824 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003825 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003826 squashfs_type, 0, 0, 0, NULL,
3827 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003828 INFO("block device %s inode 0x%llx\n",
3829 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003830 dev_count ++;
3831 break;
3832
3833 case S_IFIFO:
3834 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003835 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003836 squashfs_type, 0, 0, 0, NULL,
3837 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003838 INFO("fifo %s inode 0x%llx\n",dir_name,
3839 *inode);
plougher1f413c82005-11-18 00:02:14 +00003840 fifo_count ++;
3841 break;
3842
3843 case S_IFSOCK:
3844 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003845 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003846 squashfs_type, 0, 0, 0, NULL,
3847 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003848 INFO("unix domain socket %s inode "
3849 "0x%llx\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003850 sock_count ++;
3851 break;
3852
plougher23377982007-11-12 04:04:48 +00003853 default:
plougherb3604122009-03-30 02:07:20 +00003854 BAD_ERROR("%s unrecognised file type, "
3855 "mode is %x\n", filename,
3856 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00003857 }
3858 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00003859 dir_ent->inode->type = squashfs_type;
3860 } else {
3861 *inode = dir_ent->inode->inode;
3862 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00003863 switch(squashfs_type) {
3864 case SQUASHFS_FILE_TYPE:
3865 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00003866 INFO("file %s, uncompressed "
3867 "size %lld bytes LINK"
3868 "\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003869 (long long)
plougher50b31762009-03-31 04:14:46 +00003870 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00003871 break;
3872 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00003873 INFO("symbolic link %s inode 0x%llx "
3874 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003875 break;
3876 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003877 INFO("character device %s inode 0x%llx "
3878 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003879 break;
plougher5507dd92006-11-06 00:43:10 +00003880 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003881 INFO("block device %s inode 0x%llx "
3882 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003883 break;
3884 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00003885 INFO("fifo %s inode 0x%llx LINK\n",
3886 dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003887 break;
3888 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00003889 INFO("unix domain socket %s inode "
3890 "0x%llx LINK\n", dir_name,
3891 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003892 break;
3893 }
plougher1f413c82005-11-18 00:02:14 +00003894 }
3895
plougher29e37092007-04-15 01:24:51 +00003896 add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00003897 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00003898 }
3899
plougher29e37092007-04-15 01:24:51 +00003900 write_dir(inode, dir_info, &dir);
plougher1f413c82005-11-18 00:02:14 +00003901 INFO("directory %s inode 0x%llx\n", pathname, *inode);
3902
plougher43244f22009-04-05 02:04:51 +00003903 scan3_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003904}
3905
3906
3907unsigned int slog(unsigned int block)
3908{
3909 int i;
3910
plougher4c99cb72007-06-14 21:46:31 +00003911 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00003912 if(block == (1 << i))
3913 return i;
3914 return 0;
3915}
3916
3917
plougher8f8e1a12007-10-18 02:50:21 +00003918int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00003919{
3920 int i;
3921
3922 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00003923 if((exclude_paths[i].st_dev == buf->st_dev) &&
3924 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00003925 return TRUE;
3926 return FALSE;
3927}
3928
3929
3930#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00003931 if(exclude % EXCLUDE_SIZE == 0) { \
3932 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
3933 * sizeof(struct exclude_info)); \
3934 if(exclude_paths == NULL) \
3935 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
3936 } \
3937 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00003938 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00003939int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00003940{
3941 int i;
plougher91fbb302008-05-06 02:29:36 +00003942 char filename[4096];
plougher1f413c82005-11-18 00:02:14 +00003943 struct stat buf;
3944
plougherb3604122009-03-30 02:07:20 +00003945 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
3946 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00003947 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00003948 ERROR("Cannot stat exclude dir/file %s because %s, "
3949 "ignoring", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003950 return TRUE;
3951 }
3952 ADD_ENTRY(buf);
3953 return TRUE;
3954 }
3955
3956 for(i = 0; i < source; i++) {
3957 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
3958 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00003959 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00003960 ERROR("Cannot stat exclude dir/file %s because "
plougher50b31762009-03-31 04:14:46 +00003961 "%s, ignoring", filename,
3962 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003963 continue;
3964 }
3965 ADD_ENTRY(buf);
3966 }
3967 return TRUE;
3968}
3969
3970
plougherb3604122009-03-30 02:07:20 +00003971void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
3972 int type)
plougher1f413c82005-11-18 00:02:14 +00003973{
plougherb3604122009-03-30 02:07:20 +00003974 old_root_entry = realloc(old_root_entry,
3975 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
3976 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00003977 BAD_ERROR("Out of memory in old root directory entries "
3978 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00003979
ploughera326c182009-08-29 05:41:45 +00003980 old_root_entry[old_root_entries].name = strdup(name);
3981 old_root_entry[old_root_entries].inode.inode = inode;
3982 old_root_entry[old_root_entries].inode.inode_number = inode_number;
3983 old_root_entry[old_root_entries].inode.type = type;
3984 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00003985}
3986
3987
plougher5507dd92006-11-06 00:43:10 +00003988void initialise_threads()
3989{
3990 int i;
3991 sigset_t sigmask, old_mask;
3992
3993 sigemptyset(&sigmask);
3994 sigaddset(&sigmask, SIGINT);
3995 sigaddset(&sigmask, SIGQUIT);
3996 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
3997 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
3998
3999 signal(SIGUSR1, sigusr1_handler);
4000
4001 if(processors == -1) {
4002#ifndef linux
4003 int mib[2];
4004 size_t len = sizeof(processors);
4005
4006 mib[0] = CTL_HW;
4007#ifdef HW_AVAILCPU
4008 mib[1] = HW_AVAILCPU;
4009#else
4010 mib[1] = HW_NCPU;
4011#endif
4012
4013 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004014 ERROR("Failed to get number of available processors. "
4015 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004016 processors = 1;
4017 }
4018#else
4019 processors = get_nprocs();
4020#endif
4021 }
4022
plougher91fbb302008-05-06 02:29:36 +00004023 if((thread = malloc((2 + processors * 2) * sizeof(pthread_t))) == NULL)
plougher5507dd92006-11-06 00:43:10 +00004024 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004025 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004026 frag_deflator_thread = &deflator_thread[processors];
4027
4028 to_reader = queue_init(1);
4029 from_reader = queue_init(reader_buffer_size);
4030 to_writer = queue_init(writer_buffer_size);
4031 from_writer = queue_init(1);
4032 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004033 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004034 reader_buffer = cache_init(block_size, reader_buffer_size);
4035 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004036 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004037 pthread_create(&thread[0], NULL, reader, NULL);
4038 pthread_create(&thread[1], NULL, writer, NULL);
plougher91fbb302008-05-06 02:29:36 +00004039 pthread_create(&progress_thread, NULL, progress_thrd, NULL);
plougher5507dd92006-11-06 00:43:10 +00004040 pthread_mutex_init(&fragment_mutex, NULL);
4041 pthread_cond_init(&fragment_waiting, NULL);
4042
4043 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004044 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4045 0)
plougher5507dd92006-11-06 00:43:10 +00004046 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004047 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4048 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004049 BAD_ERROR("Failed to create thread\n");
4050 }
4051
4052 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4053 processors == 1 ? "" : "s");
4054
4055 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4056 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4057}
4058
4059
plougher0e453652006-11-06 01:49:35 +00004060long long write_inode_lookup_table()
4061{
4062 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004063 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004064
4065 if(inode_count == sinode_count)
4066 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004067
plougher44f03282010-07-27 00:31:36 +00004068 it = realloc(inode_lookup_table, lookup_bytes);
4069 if(it == NULL)
plougher0e453652006-11-06 01:49:35 +00004070 BAD_ERROR("Out of memory in write_inode_table\n");
plougher44f03282010-07-27 00:31:36 +00004071 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004072
plougher0e453652006-11-06 01:49:35 +00004073 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4074 struct inode_info *inode = inode_info[i];
4075
4076 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004077
4078 inode_number = inode->type == SQUASHFS_DIR_TYPE ?
plougher360514a2009-03-30 03:01:38 +00004079 inode->inode_number : inode->inode_number +
4080 dir_inode_no;
plougher0e453652006-11-06 01:49:35 +00004081
plougher360514a2009-03-30 03:01:38 +00004082 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4083 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004084
plougher0e453652006-11-06 01:49:35 +00004085 }
4086 }
4087
plougher02bc3bc2007-02-25 12:12:01 +00004088skip_inode_hash_table:
plougher50b31762009-03-31 04:14:46 +00004089 return generic_write_table(lookup_bytes, (char *) inode_lookup_table,
plougher85c56262010-07-20 01:00:57 +00004090 0, NULL, noI);
plougher0e453652006-11-06 01:49:35 +00004091}
4092
plougher2ea89142008-03-11 01:34:19 +00004093
plougher8f8e1a12007-10-18 02:50:21 +00004094char *get_component(char *target, char *targname)
4095{
4096 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004097 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004098
4099 while(*target != '/' && *target!= '\0')
4100 *targname ++ = *target ++;
4101
4102 *targname = '\0';
4103
4104 return target;
4105}
4106
4107
4108void free_path(struct pathname *paths)
4109{
4110 int i;
4111
4112 for(i = 0; i < paths->names; i++) {
4113 if(paths->name[i].paths)
4114 free_path(paths->name[i].paths);
4115 free(paths->name[i].name);
4116 if(paths->name[i].preg) {
4117 regfree(paths->name[i].preg);
4118 free(paths->name[i].preg);
4119 }
4120 }
4121
4122 free(paths);
4123}
4124
4125
4126struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4127{
4128 char targname[1024];
4129 int i, error;
4130
4131 target = get_component(target, targname);
4132
4133 if(paths == NULL) {
4134 if((paths = malloc(sizeof(struct pathname))) == NULL)
4135 BAD_ERROR("failed to allocate paths\n");
4136
4137 paths->names = 0;
4138 paths->name = NULL;
4139 }
4140
4141 for(i = 0; i < paths->names; i++)
4142 if(strcmp(paths->name[i].name, targname) == 0)
4143 break;
4144
4145 if(i == paths->names) {
4146 /* allocate new name entry */
4147 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004148 paths->name = realloc(paths->name, (i + 1) *
4149 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004150 if(paths->name == NULL)
4151 BAD_ERROR("Out of memory in add path\n");
plougher8f8e1a12007-10-18 02:50:21 +00004152 paths->name[i].name = strdup(targname);
4153 paths->name[i].paths = NULL;
4154 if(use_regex) {
4155 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004156 if(paths->name[i].preg == NULL)
4157 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004158 error = regcomp(paths->name[i].preg, targname,
4159 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004160 if(error) {
plougher8f8e1a12007-10-18 02:50:21 +00004161 char str[1024];
4162
4163 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004164 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004165 "because %s\n", targname, alltarget,
4166 str);
plougher8f8e1a12007-10-18 02:50:21 +00004167 }
4168 } else
4169 paths->name[i].preg = NULL;
4170
4171 if(target[0] == '\0')
4172 /* at leaf pathname component */
4173 paths->name[i].paths = NULL;
4174 else
4175 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004176 paths->name[i].paths = add_path(NULL, target,
4177 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004178 } else {
4179 /* existing matching entry */
4180 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004181 /* No sub-directory which means this is the leaf
4182 * component of a pre-existing exclude which subsumes
4183 * the exclude currently being added, in which case stop
4184 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004185 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004186 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004187 * from more specific excludes, delete as they're
4188 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004189 free_path(paths->name[i].paths);
4190 paths->name[i].paths = NULL;
4191 } else
4192 /* recurse adding child components */
4193 add_path(paths->name[i].paths, target, alltarget);
4194 }
4195
4196 return paths;
4197}
plougher2ea89142008-03-11 01:34:19 +00004198
4199
plougher05e50ef2007-10-23 12:34:20 +00004200void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004201{
plougher05e50ef2007-10-23 12:34:20 +00004202
plougherb3604122009-03-30 02:07:20 +00004203 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4204 strncmp(target, "../", 3) == 0)
4205 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4206 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004207 else if(strncmp(target, "... ", 4) == 0)
4208 stickypath = add_path(stickypath, target + 4, target + 4);
4209 else
4210 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004211}
4212
4213
4214void display_path(int depth, struct pathname *paths)
4215{
4216 int i, n;
4217
4218 if(paths == NULL)
4219 return;
4220
4221 for(i = 0; i < paths->names; i++) {
4222 for(n = 0; n < depth; n++)
4223 printf("\t");
4224 printf("%d: %s\n", depth, paths->name[i].name);
4225 display_path(depth + 1, paths->name[i].paths);
4226 }
4227}
4228
4229
4230void display_path2(struct pathname *paths, char *string)
4231{
4232 int i;
4233 char path[1024];
4234
4235 if(paths == NULL) {
4236 printf("%s\n", string);
4237 return;
4238 }
4239
4240 for(i = 0; i < paths->names; i++) {
4241 strcat(strcat(strcpy(path, string), "/"), paths->name[i].name);
4242 display_path2(paths->name[i].paths, path);
4243 }
4244}
4245
4246
plougherf9039c92007-10-22 03:54:16 +00004247struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004248{
ploughera2968ef2009-03-03 10:46:00 +00004249 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004250 if(new == NULL)
4251 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004252 new->count = 0;
4253 return new;
4254}
4255
4256
4257struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4258{
plougher6f2a8262010-07-27 00:37:19 +00004259 if(paths->count % PATHS_ALLOC_SIZE == 0) {
plougherb3604122009-03-30 02:07:20 +00004260 paths = realloc(paths, sizeof(struct pathnames *) +
4261 (paths->count + PATHS_ALLOC_SIZE) *
4262 sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004263 if(paths == NULL)
4264 BAD_ERROR("Out of memory in add_subdir\n");
4265 }
plougherf9039c92007-10-22 03:54:16 +00004266
4267 paths->path[paths->count++] = path;
4268 return paths;
4269}
4270
4271
4272void free_subdir(struct pathnames *paths)
4273{
4274 free(paths);
4275}
4276
4277
4278int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4279{
4280 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004281
plougherf9039c92007-10-22 03:54:16 +00004282 if(paths == NULL) {
4283 *new = NULL;
4284 return FALSE;
4285 }
plougher8f8e1a12007-10-18 02:50:21 +00004286
plougherf9039c92007-10-22 03:54:16 +00004287
4288 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004289 if(stickypath)
4290 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004291
4292 for(n = 0; n < paths->count; n++) {
4293 struct pathname *path = paths->path[n];
4294
4295 for(i = 0; i < path->names; i++) {
4296 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004297 regexec(path->name[i].preg, name, (size_t) 0,
4298 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004299 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004300 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4301 0;
plougherf9039c92007-10-22 03:54:16 +00004302
4303 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004304 /* match on a leaf component, any subdirectories
4305 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004306 res = TRUE;
4307 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004308 }
4309
plougherf9039c92007-10-22 03:54:16 +00004310 if(match)
plougherb3604122009-03-30 02:07:20 +00004311 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004312 * subdirectories to the new set of
4313 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004314 *new = add_subdir(*new, path->name[i].paths);
4315 }
4316 }
4317
4318 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004319 /* no matching names found, return empty new search set
4320 */
plougherf9039c92007-10-22 03:54:16 +00004321 res = FALSE;
4322 goto empty_set;
4323 }
4324
4325 /* one or more matches with sub-directories found (no leaf matches).
4326 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004327 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004328
4329empty_set:
4330 free_subdir(*new);
4331 *new = NULL;
4332 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004333}
4334
4335
plougher99ac0cc2007-10-29 03:17:10 +00004336#define RECOVER_ID "Squashfs recovery file v1.0\n"
4337#define RECOVER_ID_SIZE 28
4338
4339void write_recovery_data(squashfs_super_block *sBlk)
4340{
plougher1d065e92010-06-18 03:58:27 +00004341 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004342 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004343 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004344 char header[] = RECOVER_ID;
4345
4346 if(recover == FALSE) {
4347 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004348 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004349 return;
4350 }
4351
4352 if((metadata = malloc(bytes)) == NULL)
plougher50b31762009-03-31 04:14:46 +00004353 BAD_ERROR("Failed to alloc metadata buffer in "
4354 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004355
plougher1d065e92010-06-18 03:58:27 +00004356 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4357 if(res == 0)
4358 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004359
plougherb3604122009-03-30 02:07:20 +00004360 sprintf(recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004361 getbase(destination_file), pid);
plougherb3604122009-03-30 02:07:20 +00004362 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4363 if(recoverfd == -1)
4364 BAD_ERROR("Failed to create recovery file, because %s. "
4365 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004366
plougher628e7682009-03-29 22:12:24 +00004367 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004368 BAD_ERROR("Failed to write recovery file, because %s\n",
4369 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004370
plougher628e7682009-03-29 22:12:24 +00004371 if(write_bytes(recoverfd, sBlk, sizeof(squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004372 BAD_ERROR("Failed to write recovery file, because %s\n",
4373 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004374
plougher628e7682009-03-29 22:12:24 +00004375 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004376 BAD_ERROR("Failed to write recovery file, because %s\n",
4377 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004378
4379 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004380 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004381
4382 printf("Recovery file \"%s\" written\n", recovery_file);
4383 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004384 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4385 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004386 printf("to restore filesystem\n\n");
4387}
4388
4389
4390void read_recovery_data(char *recovery_file, char *destination_file)
4391{
4392 int fd, recoverfd, bytes;
4393 squashfs_super_block orig_sBlk, sBlk;
4394 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004395 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004396 struct stat buf;
4397 char header[] = RECOVER_ID;
4398 char header2[RECOVER_ID_SIZE];
4399
4400 if((recoverfd = open(recovery_file, O_RDONLY)) == -1)
plougherb3604122009-03-30 02:07:20 +00004401 BAD_ERROR("Failed to open recovery file because %s\n",
4402 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004403
4404 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004405 BAD_ERROR("Failed to stat destination file, because %s\n",
4406 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004407
4408 if((fd = open(destination_file, O_RDWR)) == -1)
plougherb3604122009-03-30 02:07:20 +00004409 BAD_ERROR("Failed to open destination file because %s\n",
4410 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004411
plougher8a8c4102009-03-29 22:28:49 +00004412 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4413 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004414 BAD_ERROR("Failed to read recovery file, because %s\n",
4415 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004416 if(res < RECOVER_ID_SIZE)
4417 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004418 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4419 BAD_ERROR("Not a recovery file\n");
4420
plougher8a8c4102009-03-29 22:28:49 +00004421 res = read_bytes(recoverfd, &sBlk, sizeof(squashfs_super_block));
4422 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004423 BAD_ERROR("Failed to read recovery file, because %s\n",
4424 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004425 if(res < sizeof(squashfs_super_block))
4426 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004427
plougher3306cb22010-06-18 04:22:44 +00004428 res = read_fs_bytes(fd, 0, sizeof(squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004429 if(res == 0)
4430 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004431
plougherb3604122009-03-30 02:07:20 +00004432 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
4433 sizeof(squashfs_super_block) - 4) != 0)
4434 BAD_ERROR("Recovery file and destination file do not seem to "
4435 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004436
4437 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4438
4439 if((metadata = malloc(bytes)) == NULL)
plougherb3604122009-03-30 02:07:20 +00004440 BAD_ERROR("Failed to alloc metadata buffer in "
4441 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004442
plougher8a8c4102009-03-29 22:28:49 +00004443 res = read_bytes(recoverfd, metadata, bytes);
4444 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004445 BAD_ERROR("Failed to read recovery file, because %s\n",
4446 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004447 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004448 BAD_ERROR("Recovery file appears to be truncated\n");
4449
plougher0dd6f122009-03-29 21:43:57 +00004450 write_destination(fd, 0, sizeof(squashfs_super_block), (char *) &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004451
plougher0dd6f122009-03-29 21:43:57 +00004452 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004453
4454 close(recoverfd);
4455 close(fd);
4456
plougherb3604122009-03-30 02:07:20 +00004457 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4458 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004459
4460 exit(0);
4461}
4462
4463
plougher1f413c82005-11-18 00:02:14 +00004464#define VERSION() \
plougherfdee12a2010-07-19 17:50:28 +00004465 printf("mksquashfs version 4.1-CVS (2010/07/19)\n");\
plougher16111452010-07-22 05:12:18 +00004466 printf("copyright (C) 2010 Phillip Lougher "\
4467 "<phillip@lougher.demon.co.uk>\n\n"); \
4468 printf("This program is free software; you can redistribute it and/or"\
4469 "\n");\
4470 printf("modify it under the terms of the GNU General Public License"\
4471 "\n");\
4472 printf("as published by the Free Software Foundation; either version "\
4473 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004474 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004475 printf("This program is distributed in the hope that it will be "\
4476 "useful,\n");\
4477 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4478 "of\n");\
4479 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4480 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004481 printf("GNU General Public License for more details.\n");
4482int main(int argc, char *argv[])
4483{
plougher324978d2006-02-27 04:53:29 +00004484 struct stat buf, source_buf;
plougher1f413c82005-11-18 00:02:14 +00004485 int i;
4486 squashfs_super_block sBlk;
4487 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004488 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004489 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004490 int readb_mbytes = READER_BUFFER_DEFAULT,
4491 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4492 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
plougherf11dfd62009-01-26 03:56:07 +00004493 int s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00004494
plougher91fbb302008-05-06 02:29:36 +00004495 pthread_mutex_init(&progress_mutex, NULL);
plougher1f413c82005-11-18 00:02:14 +00004496 block_log = slog(block_size);
4497 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
4498 VERSION();
4499 exit(0);
4500 }
4501 for(i = 1; i < argc && argv[i][0] != '-'; i++);
4502 if(i < 3)
4503 goto printOptions;
4504 source_path = argv + 1;
4505 source = i - 2;
4506 for(; i < argc; i++) {
plougherae9dcd82009-08-01 02:59:38 +00004507 if(strcmp(argv[i], "-comp") == 0) {
4508 if(++i == argc) {
4509 ERROR("%s: -comp missing compression type\n",
4510 argv[0]);
4511 exit(1);
4512 }
4513 comp_name = argv[i];
4514 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00004515 if(++i == argc) {
4516 ERROR("%s: -pf missing filename\n", argv[0]);
4517 exit(1);
4518 }
plougher620b7172009-09-10 04:17:48 +00004519 if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004520 exit(1);
plougher43244f22009-04-05 02:04:51 +00004521 } else if(strcmp(argv[i], "-p") == 0) {
4522 if(++i == argc) {
4523 ERROR("%s: -p missing pseudo file definition\n",
4524 argv[0]);
4525 exit(1);
4526 }
plougher620b7172009-09-10 04:17:48 +00004527 if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004528 exit(1);
plougher43244f22009-04-05 02:04:51 +00004529 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00004530 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00004531 ERROR("%s: -recover missing recovery file\n",
4532 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00004533 exit(1);
4534 }
4535 read_recovery_data(argv[i], argv[source + 1]);
4536 } else if(strcmp(argv[i], "-no-recovery") == 0)
4537 recover = FALSE;
4538 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00004539 old_exclude = FALSE;
4540 use_regex = FALSE;
4541 } else if(strcmp(argv[i], "-regex") == 0) {
4542 old_exclude = FALSE;
4543 use_regex = TRUE;
4544 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00004545 sparse_files = FALSE;
4546 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00004547 progress = FALSE;
4548 else if(strcmp(argv[i], "-no-exports") == 0)
4549 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00004550 else if(strcmp(argv[i], "-processors") == 0) {
plougher360514a2009-03-30 03:01:38 +00004551 if((++i == argc) || (processors =
4552 strtol(argv[i], &b, 10), *b != '\0')) {
4553 ERROR("%s: -processors missing or invalid "
4554 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004555 exit(1);
4556 }
4557 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00004558 ERROR("%s: -processors should be 1 or larger\n",
4559 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004560 exit(1);
4561 }
plougher0e453652006-11-06 01:49:35 +00004562 } else if(strcmp(argv[i], "-read-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004563 if((++i == argc) || (readb_mbytes =
4564 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004565 ERROR("%s: -read-queue missing or invalid "
4566 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004567 exit(1);
4568 }
4569 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00004570 ERROR("%s: -read-queue should be 1 megabyte or "
4571 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004572 exit(1);
4573 }
plougher0e453652006-11-06 01:49:35 +00004574 } else if(strcmp(argv[i], "-write-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004575 if((++i == argc) || (writeb_mbytes =
4576 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004577 ERROR("%s: -write-queue missing or invalid "
4578 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004579 exit(1);
4580 }
4581 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004582 ERROR("%s: -write-queue should be 1 megabyte "
4583 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004584 exit(1);
4585 }
plougher217bad82008-04-05 11:36:41 +00004586 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004587 if((++i == argc) ||
4588 (fragmentb_mbytes =
4589 strtol(argv[i], &b, 10), *b != '\0')) {
4590 ERROR("%s: -fragment-queue missing or invalid "
4591 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004592 exit(1);
4593 }
4594 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004595 ERROR("%s: -fragment-queue should be 1 "
4596 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004597 exit(1);
4598 }
plougher5507dd92006-11-06 00:43:10 +00004599 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00004600 if(++i == argc) {
4601 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004602 exit(1);
4603 }
plougher4c99cb72007-06-14 21:46:31 +00004604 block_size = strtol(argv[i], &b, 10);
4605 if(*b == 'm' || *b == 'M')
4606 block_size *= 1048576;
4607 else if(*b == 'k' || *b == 'K')
4608 block_size *= 1024;
4609 else if(*b != '\0') {
4610 ERROR("%s: -b invalid block size\n", argv[0]);
4611 exit(1);
4612 }
plougher1f413c82005-11-18 00:02:14 +00004613 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00004614 ERROR("%s: -b block size not power of two or "
4615 "not between 4096 and 1Mbyte\n",
4616 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004617 exit(1);
4618 }
4619 } else if(strcmp(argv[i], "-ef") == 0) {
4620 if(++i == argc) {
4621 ERROR("%s: -ef missing filename\n", argv[0]);
4622 exit(1);
4623 }
plougher9b5bf8c2006-03-20 18:43:33 +00004624 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00004625 duplicate_checking = FALSE;
4626
4627 else if(strcmp(argv[i], "-no-fragments") == 0)
4628 no_fragments = TRUE;
4629
4630 else if(strcmp(argv[i], "-always-use-fragments") == 0)
4631 always_use_fragments = TRUE;
4632
4633 else if(strcmp(argv[i], "-sort") == 0) {
4634 if(++i == argc) {
4635 ERROR("%s: -sort missing filename\n", argv[0]);
4636 exit(1);
4637 }
4638 } else if(strcmp(argv[i], "-all-root") == 0 ||
4639 strcmp(argv[i], "-root-owned") == 0)
4640 global_uid = global_gid = 0;
4641
4642 else if(strcmp(argv[i], "-force-uid") == 0) {
4643 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004644 ERROR("%s: -force-uid missing uid or user\n",
4645 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004646 exit(1);
4647 }
4648 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004649 if(global_uid < 0 || global_uid >
4650 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004651 ERROR("%s: -force-uid uid out of range"
4652 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004653 exit(1);
4654 }
4655 } else {
4656 struct passwd *uid = getpwnam(argv[i]);
4657 if(uid)
4658 global_uid = uid->pw_uid;
4659 else {
plougher360514a2009-03-30 03:01:38 +00004660 ERROR("%s: -force-uid invalid uid or "
4661 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004662 exit(1);
4663 }
4664 }
4665 } else if(strcmp(argv[i], "-force-gid") == 0) {
4666 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00004667 ERROR("%s: -force-gid missing gid or group\n",
4668 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004669 exit(1);
4670 }
4671 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004672 if(global_gid < 0 || global_gid >
4673 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004674 ERROR("%s: -force-gid gid out of range"
4675 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004676 exit(1);
4677 }
4678 } else {
4679 struct group *gid = getgrnam(argv[i]);
4680 if(gid)
4681 global_gid = gid->gr_gid;
4682 else {
plougher360514a2009-03-30 03:01:38 +00004683 ERROR("%s: -force-gid invalid gid or "
4684 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004685 exit(1);
4686 }
4687 }
4688 } else if(strcmp(argv[i], "-noI") == 0 ||
4689 strcmp(argv[i], "-noInodeCompression") == 0)
4690 noI = TRUE;
4691
4692 else if(strcmp(argv[i], "-noD") == 0 ||
4693 strcmp(argv[i], "-noDataCompression") == 0)
4694 noD = TRUE;
4695
4696 else if(strcmp(argv[i], "-noF") == 0 ||
4697 strcmp(argv[i], "-noFragmentCompression") == 0)
4698 noF = TRUE;
4699
plougherb99d7832010-05-19 01:57:34 +00004700 else if(strcmp(argv[i], "-noX") == 0 ||
4701 strcmp(argv[i], "-noXattrCompression") == 0)
4702 noX = TRUE;
4703
plougherce564c62010-05-19 03:01:49 +00004704 else if(strcmp(argv[i], "-no-xattrs") == 0)
4705 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00004706
plougher1f413c82005-11-18 00:02:14 +00004707 else if(strcmp(argv[i], "-nopad") == 0)
4708 nopad = TRUE;
4709
plougher91fbb302008-05-06 02:29:36 +00004710 else if(strcmp(argv[i], "-info") == 0) {
4711 silent = FALSE;
4712 progress = FALSE;
4713 }
plougher1f413c82005-11-18 00:02:14 +00004714
4715 else if(strcmp(argv[i], "-e") == 0)
4716 break;
4717
4718 else if(strcmp(argv[i], "-noappend") == 0)
4719 delete = TRUE;
4720
4721 else if(strcmp(argv[i], "-keep-as-directory") == 0)
4722 keep_as_directory = TRUE;
4723
4724 else if(strcmp(argv[i], "-root-becomes") == 0) {
4725 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004726 ERROR("%s: -root-becomes: missing name\n",
4727 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004728 exit(1);
4729 }
4730 root_name = argv[i];
4731 } else if(strcmp(argv[i], "-version") == 0) {
4732 VERSION();
4733 } else {
4734 ERROR("%s: invalid option\n\n", argv[0]);
4735printOptions:
plougher360514a2009-03-30 03:01:38 +00004736 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
4737 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00004738 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00004739 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00004740 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00004741 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00004742 ERROR("-b <block_size>\t\tset data block to "
4743 "<block_size>. Default %d bytes\n",
4744 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00004745 ERROR("-no-exports\t\tdon't make the filesystem "
4746 "exportable via NFS\n");
4747 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher16111452010-07-22 05:12:18 +00004748 ERROR("-no-xattrs\t\tdon't detect extended "
4749 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00004750 ERROR("-noI\t\t\tdo not compress inode table\n");
4751 ERROR("-noD\t\t\tdo not compress data blocks\n");
4752 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00004753 ERROR("-noX\t\t\tdo not compress extended "
4754 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00004755 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00004756 ERROR("-always-use-fragments\tuse fragment blocks for "
4757 "files larger than block size\n");
4758 ERROR("-no-duplicates\t\tdo not perform duplicate "
4759 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00004760 ERROR("-all-root\t\tmake all files owned by root\n");
4761 ERROR("-force-uid uid\t\tset all file uids to uid\n");
4762 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00004763 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
4764 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00004765 ERROR("-keep-as-directory\tif one source directory is "
4766 "specified, create a root\n");
4767 ERROR("\t\t\tdirectory containing that directory, "
4768 "rather than the\n");
4769 ERROR("\t\t\tcontents of the directory\n");
4770 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00004771 ERROR("-p <pseudo-definition>\tAdd pseudo file "
4772 "definition\n");
4773 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
4774 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00004775 ERROR("-sort <sort_file>\tsort files according to "
4776 "priorities in <sort_file>. One\n");
4777 ERROR("\t\t\tfile or dir with priority per line. "
4778 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00004779 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00004780 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
4781 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00004782 ERROR("-wildcards\t\tAllow extended shell wildcards "
4783 "(globbing) to be used in\n\t\t\texclude "
4784 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00004785 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
4786 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00004787 ERROR("\nFilesystem append options:\n");
4788 ERROR("-noappend\t\tdo not append to existing "
4789 "filesystem\n");
4790 ERROR("-root-becomes <name>\twhen appending source "
4791 "files/directories, make the\n");
4792 ERROR("\t\t\toriginal root become a subdirectory in "
4793 "the new root\n");
4794 ERROR("\t\t\tcalled <name>, rather than adding the new "
4795 "source items\n");
4796 ERROR("\t\t\tto the original root\n");
4797 ERROR("\nMksquashfs runtime options:\n");
4798 ERROR("-version\t\tprint version, licence and "
4799 "copyright message\n");
4800 ERROR("-recover <name>\t\trecover filesystem data "
4801 "using recovery file <name>\n");
4802 ERROR("-no-recovery\t\tdon't generate a recovery "
4803 "file\n");
4804 ERROR("-info\t\t\tprint files written to filesystem\n");
4805 ERROR("-no-progress\t\tdon't display the progress "
4806 "bar\n");
4807 ERROR("-processors <number>\tUse <number> processors."
4808 " By default will use number of\n");
4809 ERROR("\t\t\tprocessors available\n");
4810 ERROR("-read-queue <size>\tSet input queue to <size> "
4811 "Mbytes. Default %d Mbytes\n",
4812 READER_BUFFER_DEFAULT);
4813 ERROR("-write-queue <size>\tSet output queue to <size> "
4814 "Mbytes. Default %d Mbytes\n",
4815 WRITER_BUFFER_DEFAULT);
4816 ERROR("-fragment-queue <size>\tSet fagment queue to "
4817 "<size> Mbytes. Default %d Mbytes\n",
4818 FRAGMENT_BUFFER_DEFAULT);
4819 ERROR("\nMiscellaneous options:\n");
4820 ERROR("-root-owned\t\talternative name for -all-root"
4821 "\n");
4822 ERROR("-noInodeCompression\talternative name for -noI"
4823 "\n");
4824 ERROR("-noDataCompression\talternative name for -noD"
4825 "\n");
4826 ERROR("-noFragmentCompression\talternative name for "
4827 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00004828 ERROR("-noXattrCompression\talternative name for "
4829 "-noX\n");
plougher43664872009-12-08 18:02:54 +00004830 ERROR("\nCompressors available:\n");
4831 display_compressors("", COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00004832 exit(1);
4833 }
4834 }
4835
plougher5507dd92006-11-06 00:43:10 +00004836 reader_buffer_size = readb_mbytes << (20 - block_log);
4837 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher76c64082008-03-08 01:32:23 +00004838 fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004839
plougher91fbb302008-05-06 02:29:36 +00004840 for(i = 0; i < source; i++)
4841 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00004842 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00004843 "because %s\n", source_path[i],
4844 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00004845 EXIT_MKSQUASHFS();
4846 }
plougher324978d2006-02-27 04:53:29 +00004847
4848 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00004849 if(stat(argv[source + 1], &buf) == -1) {
4850 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00004851 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00004852 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00004853 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00004854 perror("Could not create destination file");
4855 exit(1);
4856 }
4857 delete = TRUE;
4858 } else {
4859 perror("Could not stat destination file");
4860 exit(1);
4861 }
4862
4863 } else {
4864 if(S_ISBLK(buf.st_mode)) {
4865 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00004866 perror("Could not open block device as "
4867 "destination");
plougher1f413c82005-11-18 00:02:14 +00004868 exit(1);
4869 }
4870 block_device = 1;
4871
4872 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00004873 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
4874 O_RDWR);
4875 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00004876 perror("Could not open regular file for "
4877 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00004878 exit(1);
4879 }
plougher44d54ef2010-02-08 22:13:49 +00004880 }
plougher1f413c82005-11-18 00:02:14 +00004881 else {
4882 ERROR("Destination not block device or regular file\n");
4883 exit(1);
4884 }
4885
plougher324978d2006-02-27 04:53:29 +00004886 }
plougher1f413c82005-11-18 00:02:14 +00004887
plougher4c99cb72007-06-14 21:46:31 +00004888 signal(SIGTERM, sighandler2);
4889 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00004890
plougher16111452010-07-22 05:12:18 +00004891 /*
4892 * process the exclude files - must be done afer destination file has
4893 * been possibly created
4894 */
plougher1f413c82005-11-18 00:02:14 +00004895 for(i = source + 2; i < argc; i++)
4896 if(strcmp(argv[i], "-ef") == 0) {
4897 FILE *fd;
4898 char filename[16385];
4899 if((fd = fopen(argv[++i], "r")) == NULL) {
4900 perror("Could not open exclude file...");
plougher324978d2006-02-27 04:53:29 +00004901 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00004902 }
4903 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
plougher8f8e1a12007-10-18 02:50:21 +00004904 if(old_exclude)
4905 old_add_exclude(filename);
4906 else
plougher05e50ef2007-10-23 12:34:20 +00004907 add_exclude(filename);
plougher1f413c82005-11-18 00:02:14 +00004908 fclose(fd);
4909 } else if(strcmp(argv[i], "-e") == 0)
4910 break;
plougher8b9a7f62009-08-01 22:52:45 +00004911 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00004912 strcmp(argv[i], "-sort") == 0 ||
4913 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00004914 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00004915 i++;
4916
4917 if(i != argc) {
4918 if(++i == argc) {
4919 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00004920 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00004921 }
plougher8f8e1a12007-10-18 02:50:21 +00004922 while(i < argc)
4923 if(old_exclude)
4924 old_add_exclude(argv[i++]);
4925 else
plougher05e50ef2007-10-23 12:34:20 +00004926 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00004927 }
4928
4929 /* process the sort files - must be done afer the exclude files */
4930 for(i = source + 2; i < argc; i++)
4931 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00004932 int res = read_sort_file(argv[++i], source,
4933 source_path);
4934 if(res == FALSE)
4935 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00004936 sorted ++;
4937 } else if(strcmp(argv[i], "-e") == 0)
4938 break;
plougher8b9a7f62009-08-01 22:52:45 +00004939 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00004940 strcmp(argv[i], "-ef") == 0 ||
4941 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00004942 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00004943 i++;
4944
plougher62d5b5c2008-08-16 01:49:42 +00004945#ifdef SQUASHFS_TRACE
4946 progress = FALSE;
4947#endif
4948
plougher4c99cb72007-06-14 21:46:31 +00004949 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00004950 comp = read_super(fd, &sBlk, argv[source + 1]);
4951 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00004952 ERROR("Failed to read existing filesystem - will not "
4953 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00004954 ERROR("To force Mksquashfs to write to this block "
4955 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00004956 EXIT_MKSQUASHFS();
4957 }
plougher1f413c82005-11-18 00:02:14 +00004958
plougher1f413c82005-11-18 00:02:14 +00004959 block_log = slog(block_size = sBlk.block_size);
plougher4c99cb72007-06-14 21:46:31 +00004960 s_minor = sBlk.s_minor;
plougher1f413c82005-11-18 00:02:14 +00004961 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
4962 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
4963 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00004964 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
4965 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
4966 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00004967 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
ploughera175ce22009-07-30 04:43:27 +00004968 } else {
4969 comp = lookup_compressor(comp_name);
plougher394fe0d2009-08-04 04:27:12 +00004970 if(!comp->supported) {
plougherfbfb2f42009-08-03 02:33:25 +00004971 ERROR("FATAL_ERROR: Compressor \"%s\" is not "
4972 "supported!\n", comp_name);
plougher13df1782009-08-29 01:05:34 +00004973 ERROR("Compressors available:\n");
plougher764dab52009-08-24 18:28:04 +00004974 display_compressors("", COMP_DEFAULT);
plougherfbfb2f42009-08-03 02:33:25 +00004975 EXIT_MKSQUASHFS();
plougher394fe0d2009-08-04 04:27:12 +00004976 }
plougher4c99cb72007-06-14 21:46:31 +00004977 }
4978
4979 initialise_threads();
4980
4981 if(delete) {
plougherdf6d8f02009-03-20 03:10:00 +00004982 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher360514a2009-03-30 03:01:38 +00004983 SQUASHFS_MAJOR, s_minor, argv[source + 1], block_size);
plougher4c99cb72007-06-14 21:46:31 +00004984 bytes = sizeof(squashfs_super_block);
4985 } else {
plougher360514a2009-03-30 03:01:38 +00004986 unsigned int last_directory_block, inode_dir_offset,
4987 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00004988 inode_dir_start_block, uncompressed_data,
4989 compressed_data, inode_dir_inode_number,
4990 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00004991 unsigned int root_inode_start =
4992 SQUASHFS_INODE_BLK(sBlk.root_inode),
4993 root_inode_offset =
4994 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00004995
plougher360514a2009-03-30 03:01:38 +00004996 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
4997 &data_cache, &directory_table,
4998 &directory_data_cache, &last_directory_block,
4999 &inode_dir_offset, &inode_dir_file_size,
5000 &root_inode_size, &inode_dir_start_block,
5001 &file_count, &sym_count, &dev_count, &dir_count,
5002 &fifo_count, &sock_count, &total_bytes,
5003 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005004 &inode_dir_inode_number,
5005 &inode_dir_parent_inode, add_old_root_entry,
5006 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005007 ERROR("Failed to read existing filesystem - will not "
5008 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005009 ERROR("To force Mksquashfs to write to this block "
5010 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005011 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005012 }
plougher6f2a8262010-07-27 00:37:19 +00005013 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005014 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005015 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
5016 * sizeof(squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005017 if(fragment_table == NULL)
5018 BAD_ERROR("Out of memory in save filesystem state\n");
5019 }
plougher1f413c82005-11-18 00:02:14 +00005020
plougher50b31762009-03-31 04:14:46 +00005021 printf("Appending to existing %d.%d filesystem on %s, block "
5022 "size %d\n", SQUASHFS_MAJOR, s_minor, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005023 block_size);
5024 printf("All -b, -noI, -noD, -noF, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005025 "-always-use-fragments,\n-exportable and -comp options "
5026 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005027 printf("\nIf appending is not wanted, please re-run with "
5028 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005029
plougher360514a2009-03-30 03:01:38 +00005030 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5031 ~(SQUASHFS_METADATA_SIZE - 1);
5032 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5033 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005034
5035 /* save original filesystem state for restoring ... */
5036 sfragments = fragments;
5037 sbytes = bytes;
5038 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005039 scache_bytes = root_inode_offset + root_inode_size;
5040 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005041 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005042 if(sdata_cache == NULL)
5043 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005044 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005045 if(sdirectory_data_cache == NULL)
5046 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005047 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005048 memcpy(sdirectory_data_cache, directory_data_cache +
5049 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005050 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005051 stotal_bytes = total_bytes;
5052 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005053 stotal_directory_bytes = total_directory_bytes +
5054 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005055 sfile_count = file_count;
5056 ssym_count = sym_count;
5057 sdev_count = dev_count;
5058 sdir_count = dir_count + 1;
5059 sfifo_count = fifo_count;
5060 ssock_count = sock_count;
5061 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005062 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005063 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005064 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005065 BAD_ERROR("Failed to save xattrs from existing "
5066 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005067 restore = TRUE;
5068 if(setjmp(env))
5069 goto restore_filesystem;
5070 signal(SIGTERM, sighandler);
5071 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005072 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005073
plougher360514a2009-03-30 03:01:38 +00005074 /*
5075 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005076 * original filesystem. The filesystem state differs depending
5077 * on whether we're appending to the original root directory, or
5078 * if the original root directory becomes a sub-directory
5079 * (root-becomes specified on command line, here root_name !=
5080 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005081 */
5082 inode_bytes = inode_size = root_inode_start;
5083 directory_size = last_directory_block;
5084 cache_size = root_inode_offset + root_inode_size;
5085 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5086 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005087 sdirectory_bytes = last_directory_block;
5088 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005089 root_inode_number = inode_dir_parent_inode;
5090 dir_inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005091 directory_bytes = last_directory_block;
5092 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005093 memmove(directory_data_cache, directory_data_cache +
5094 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005095 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005096 add_old_root_entry(root_name, sBlk.root_inode,
5097 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005098 total_directory_bytes += compressed_data;
5099 dir_count ++;
5100 } else {
plougher360514a2009-03-30 03:01:38 +00005101 sdirectory_compressed_bytes = last_directory_block -
5102 inode_dir_start_block;
5103 sdirectory_compressed =
5104 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005105 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005106 BAD_ERROR("Out of memory in save filesystem "
5107 "state\n");
plougher360514a2009-03-30 03:01:38 +00005108 memcpy(sdirectory_compressed, directory_table +
5109 inode_dir_start_block,
5110 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005111 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005112 root_inode_number = inode_dir_inode_number;
plougher778e9362006-02-01 09:32:31 +00005113 dir_inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005114 directory_bytes = inode_dir_start_block;
5115 directory_cache_bytes = inode_dir_offset;
5116 cache_bytes = root_inode_offset;
5117 }
5118
plougher360514a2009-03-30 03:01:38 +00005119 inode_count = file_count + dir_count + sym_count + dev_count +
5120 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005121
5122 /*
5123 * The default use freelist before growing cache policy behaves
5124 * poorly with appending - with many deplicates the caches
5125 * do not grow due to the fact that large queues of outstanding
5126 * fragments/writer blocks do not occur, leading to small caches
5127 * and un-uncessary performance loss to frequent cache
5128 * replacement in the small caches. Therefore with appending
5129 * change the policy to grow the caches before reusing blocks
5130 * from the freelist
5131 */
5132 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005133 }
5134
plougher05e50ef2007-10-23 12:34:20 +00005135 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005136 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005137 if(path)
5138 paths = add_subdir(paths, path);
5139 if(stickypath)
5140 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005141 }
5142
plougher360514a2009-03-30 03:01:38 +00005143 if(delete && !keep_as_directory && source == 1 &&
5144 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005145 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005146 else if(!keep_as_directory && source == 1 &&
5147 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005148 dir_scan(&inode, source_path[0], scan1_single_readdir);
5149 else
5150 dir_scan(&inode, "", scan1_encomp_readdir);
5151 sBlk.root_inode = inode;
5152 sBlk.inodes = inode_count;
5153 sBlk.s_magic = SQUASHFS_MAGIC;
5154 sBlk.s_major = SQUASHFS_MAJOR;
plougher4c99cb72007-06-14 21:46:31 +00005155 sBlk.s_minor = s_minor;
plougher1f413c82005-11-18 00:02:14 +00005156 sBlk.block_size = block_size;
5157 sBlk.block_log = block_log;
plougher360514a2009-03-30 03:01:38 +00005158 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, no_fragments,
5159 always_use_fragments, duplicate_checking, exportable);
plougher1f413c82005-11-18 00:02:14 +00005160 sBlk.mkfs_time = time(NULL);
5161
5162restore_filesystem:
plougher43bb7e92008-08-17 17:16:09 +00005163 if(progress && estimated_uncompressed) {
plougherc9b11db2008-05-06 23:59:15 +00005164 disable_progress_bar();
5165 progress_bar(cur_uncompressed, estimated_uncompressed, columns);
5166 }
5167
plougher1f413c82005-11-18 00:02:14 +00005168 write_fragment();
5169 sBlk.fragments = fragments;
plougher5507dd92006-11-06 00:43:10 +00005170 if(interrupted < 2) {
plougher2ea89142008-03-11 01:34:19 +00005171 unlock_fragments();
5172 pthread_mutex_lock(&fragment_mutex);
5173 while(fragments_outstanding) {
5174 pthread_mutex_unlock(&fragment_mutex);
5175 sched_yield();
5176 pthread_mutex_lock(&fragment_mutex);
5177 }
plougher5507dd92006-11-06 00:43:10 +00005178 queue_put(to_writer, NULL);
5179 if(queue_get(from_writer) != 0)
5180 EXIT_MKSQUASHFS();
5181 }
5182
ploughere6e0e1b2010-05-12 17:17:06 +00005183 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005184 sBlk.inode_table_start = write_inodes();
5185 sBlk.directory_table_start = write_directories();
5186 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005187 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5188 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005189 sBlk.id_table_start = write_id_table();
5190 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005191
plougher0e453652006-11-06 01:49:35 +00005192 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005193 TRACE("sBlk->directory_table_start 0x%llx\n",
5194 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005195 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5196 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005197 TRACE("sBlk->lookup_table_start 0x%llx\n",
5198 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005199
plougher1f413c82005-11-18 00:02:14 +00005200 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005201
plougher8c4b7b92009-07-30 04:47:52 +00005202 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005203
plougher1f288f62009-02-21 03:05:52 +00005204 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher360514a2009-03-30 03:01:38 +00005205 write_destination(fd, SQUASHFS_START, sizeof(squashfs_super_block),
5206 (char *) &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005207
5208 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005209 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005210 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005211 }
5212
plougher99ac0cc2007-10-29 03:17:10 +00005213 close(fd);
5214
plougher11e7b1b2009-09-11 12:10:58 +00005215 delete_pseudo_files();
5216
plougher99ac0cc2007-10-29 03:17:10 +00005217 if(recovery_file[0] != '\0')
5218 unlink(recovery_file);
5219
plougher10f7d572010-07-20 02:14:04 +00005220 total_bytes += total_inode_bytes + total_directory_bytes +
plougher747e7262010-07-19 18:10:54 +00005221 sizeof(squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005222
plougher62542fb2009-08-06 08:43:08 +00005223 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5224 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5225 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005226 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005227 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5228 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005229 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5230 "compressed");
plougher50b31762009-03-31 04:14:46 +00005231 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5232 "not ");
plougher360514a2009-03-30 03:01:38 +00005233 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5234 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005235 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5236 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5237 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5238 inode_bytes, inode_bytes / 1024.0);
5239 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005240 ((float) inode_bytes / total_inode_bytes) * 100.0,
5241 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005242 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5243 directory_bytes, directory_bytes / 1024.0);
5244 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005245 ((float) directory_bytes / total_directory_bytes) * 100.0,
5246 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005247 if(total_xattr_bytes) {
5248 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5249 xattr_bytes, xattr_bytes / 1024.0);
5250 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5251 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5252 total_xattr_bytes);
5253 }
plougher1f413c82005-11-18 00:02:14 +00005254 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005255 printf("Number of duplicate files found %d\n", file_count -
5256 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005257 else
5258 printf("No duplicate files removed\n");
5259 printf("Number of inodes %d\n", inode_count);
5260 printf("Number of files %d\n", file_count);
5261 if(!no_fragments)
5262 printf("Number of fragments %d\n", fragments);
5263 printf("Number of symbolic links %d\n", sym_count);
5264 printf("Number of device nodes %d\n", dev_count);
5265 printf("Number of fifo nodes %d\n", fifo_count);
5266 printf("Number of socket nodes %d\n", sock_count);
5267 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005268 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005269 printf("Number of uids %d\n", uid_count);
5270
plougher1b899fc2008-08-07 01:24:06 +00005271 for(i = 0; i < id_count; i++) {
5272 if(id_table[i]->flags & ISA_UID) {
5273 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005274 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5275 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005276 }
plougher1f413c82005-11-18 00:02:14 +00005277 }
5278
5279 printf("Number of gids %d\n", guid_count);
5280
plougher1b899fc2008-08-07 01:24:06 +00005281 for(i = 0; i < id_count; i++) {
5282 if(id_table[i]->flags & ISA_GID) {
5283 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005284 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5285 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005286 }
plougher1f413c82005-11-18 00:02:14 +00005287 }
plougher99ac0cc2007-10-29 03:17:10 +00005288
plougher1f413c82005-11-18 00:02:14 +00005289 return 0;
5290}