blob: 5b21c89fb593a868d353c0e9e516354ae259cae7 [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
plougherfd57dfe2009-03-30 01:17:52 +0000920 data_cache = realloc(data_cache, cache_size +
921 realloc_size);
922 if(data_cache == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000923 goto failed;
924 }
925 cache_size += realloc_size;
926 }
927
928 cache_bytes += req_size;
929
plougherac28cd12010-02-24 02:25:03 +0000930 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000931
932failed:
933 BAD_ERROR("Out of memory in inode table reallocation!\n");
934}
935
936
plougher8a8c4102009-03-29 22:28:49 +0000937int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000938{
939 int res, count;
940
941 for(count = 0; count < bytes; count += res) {
942 res = read(fd, buff + count, bytes - count);
943 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000944 if(res == 0)
945 goto bytes_read;
946 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000947 ERROR("Read failed because %s\n",
948 strerror(errno));
949 return -1;
950 } else
951 res = 0;
952 }
953 }
954
955bytes_read:
956 return count;
957}
958
959
plougher3306cb22010-06-18 04:22:44 +0000960int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000961{
962 off_t off = byte;
963
plougher1d065e92010-06-18 03:58:27 +0000964 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000965 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000966
plougher5507dd92006-11-06 00:43:10 +0000967 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000968 if(lseek(fd, off, SEEK_SET) == -1) {
969 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000970 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000971 goto failed;
972 }
plougher1f413c82005-11-18 00:02:14 +0000973
plougher1d065e92010-06-18 03:58:27 +0000974 if(read_bytes(fd, buff, bytes) < bytes) {
975 ERROR("Read on destination failed\n");
976 goto failed;
977 }
978
plougher5507dd92006-11-06 00:43:10 +0000979 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000980 return 1;
981
982failed:
983 pthread_mutex_unlock(&pos_mutex);
984 return 0;
plougher1f413c82005-11-18 00:02:14 +0000985}
986
987
plougher628e7682009-03-29 22:12:24 +0000988int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000989{
990 int res, count;
991
992 for(count = 0; count < bytes; count += res) {
993 res = write(fd, buff + count, bytes - count);
994 if(res == -1) {
995 if(errno != EINTR) {
996 ERROR("Write failed because %s\n",
997 strerror(errno));
998 return -1;
999 }
1000 res = 0;
1001 }
1002 }
1003
1004 return 0;
1005}
1006
1007
1008void write_destination(int fd, long long byte, int bytes, char *buff)
plougher1f413c82005-11-18 00:02:14 +00001009{
1010 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +00001011
plougher5507dd92006-11-06 00:43:10 +00001012 if(interrupted < 2)
1013 pthread_mutex_lock(&pos_mutex);
1014
plougher91fbb302008-05-06 02:29:36 +00001015 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +00001016 BAD_ERROR("Lseek on destination failed because %s\n",
1017 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00001018
plougher0dd6f122009-03-29 21:43:57 +00001019 if(write_bytes(fd, buff, bytes) == -1)
1020 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +00001021
1022 if(interrupted < 2)
1023 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +00001024}
1025
1026
1027long long write_inodes()
1028{
1029 unsigned short c_byte;
1030 int avail_bytes;
1031 char *datap = data_cache;
1032 long long start_bytes = bytes;
1033
1034 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001035 if(inode_size - inode_bytes <
1036 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +00001037 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +00001038 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +00001039 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001040 BAD_ERROR("Out of memory in inode table "
1041 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001042 }
1043 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +00001044 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +00001045 }
plougherfd57dfe2009-03-30 01:17:52 +00001046 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
1047 SQUASHFS_METADATA_SIZE : cache_bytes;
1048 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
1049 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001050 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +00001051 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +00001052 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
1053 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001054 datap += avail_bytes;
1055 cache_bytes -= avail_bytes;
1056 }
1057
plougher0dd6f122009-03-29 21:43:57 +00001058 write_destination(fd, bytes, inode_bytes, (char *) inode_table);
plougher1f413c82005-11-18 00:02:14 +00001059 bytes += inode_bytes;
1060
1061 return start_bytes;
1062}
1063
1064
1065long long write_directories()
1066{
1067 unsigned short c_byte;
1068 int avail_bytes;
1069 char *directoryp = directory_data_cache;
1070 long long start_bytes = bytes;
1071
1072 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001073 if(directory_size - directory_bytes <
1074 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
1075 directory_table = realloc(directory_table,
1076 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1077 + 2));
1078 if(directory_table == NULL) {
1079 BAD_ERROR("Out of memory in directory table "
1080 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001081 }
1082 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
1083 }
plougherfd57dfe2009-03-30 01:17:52 +00001084 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1085 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001086 c_byte = mangle(directory_table + directory_bytes +
1087 BLOCK_OFFSET, directoryp, avail_bytes,
1088 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001089 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1090 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001091 SQUASHFS_SWAP_SHORTS(&c_byte,
1092 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001093 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1094 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001095 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001096 directoryp += avail_bytes;
1097 directory_cache_bytes -= avail_bytes;
1098 }
plougher0dd6f122009-03-29 21:43:57 +00001099 write_destination(fd, bytes, directory_bytes, (char *) directory_table);
plougher1f413c82005-11-18 00:02:14 +00001100 bytes += directory_bytes;
1101
1102 return start_bytes;
1103}
1104
1105
plougher1b899fc2008-08-07 01:24:06 +00001106long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001107{
plougher1b899fc2008-08-07 01:24:06 +00001108 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001109 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001110 int i;
1111
plougher1b899fc2008-08-07 01:24:06 +00001112 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001113 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001114 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001115 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001116 }
1117
plougher3a4a1b32010-07-20 00:58:11 +00001118 return generic_write_table(id_bytes, (char *) p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001119}
1120
1121
plougher1b899fc2008-08-07 01:24:06 +00001122struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001123{
plougher1b899fc2008-08-07 01:24:06 +00001124 int hash = ID_HASH(id);
1125 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001126
plougher1b899fc2008-08-07 01:24:06 +00001127 for(; entry; entry = entry->next)
1128 if(entry->id == id)
1129 break;
plougher1f413c82005-11-18 00:02:14 +00001130
plougher1b899fc2008-08-07 01:24:06 +00001131 return entry;
plougher1f413c82005-11-18 00:02:14 +00001132}
1133
1134
plougher1b899fc2008-08-07 01:24:06 +00001135struct id *create_id(unsigned int id)
1136{
1137 int hash = ID_HASH(id);
1138 struct id *entry = malloc(sizeof(struct id));
1139 if(entry == NULL)
1140 BAD_ERROR("Out of memory in create_id\n");
1141 entry->id = id;
1142 entry->index = id_count ++;
1143 entry->flags = 0;
1144 entry->next = id_hash_table[hash];
1145 id_hash_table[hash] = entry;
1146 id_table[entry->index] = entry;
1147 return entry;
1148}
1149
1150
1151unsigned int get_uid(unsigned int uid)
1152{
1153 struct id *entry = get_id(uid);
1154
1155 if(entry == NULL) {
1156 if(id_count == SQUASHFS_IDS)
1157 BAD_ERROR("Out of uids!\n");
1158 entry = create_id(uid);
1159 }
1160
1161 if((entry->flags & ISA_UID) == 0) {
1162 entry->flags |= ISA_UID;
1163 uid_count ++;
1164 }
1165
1166 return entry->index;
1167}
1168
1169
1170unsigned int get_guid(unsigned int guid)
1171{
1172 struct id *entry = get_id(guid);
1173
1174 if(entry == NULL) {
1175 if(id_count == SQUASHFS_IDS)
1176 BAD_ERROR("Out of gids!\n");
1177 entry = create_id(guid);
1178 }
1179
1180 if((entry->flags & ISA_GID) == 0) {
1181 entry->flags |= ISA_GID;
1182 guid_count ++;
1183 }
1184
1185 return entry->index;
1186}
1187
1188
plougher3c6bdb52010-05-01 02:30:59 +00001189int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1190 struct dir_ent *dir_ent, int type, long long byte_size,
1191 long long start_block, unsigned int offset, unsigned int *block_list,
1192 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001193{
1194 struct stat *buf = &dir_ent->inode->buf;
1195 squashfs_inode_header inode_header;
plougherac28cd12010-02-24 02:25:03 +00001196 squashfs_base_inode_header *base = &inode_header.base;
1197 void *inode;
plougher1f413c82005-11-18 00:02:14 +00001198 char *filename = dir_ent->pathname;
1199 int nlink = dir_ent->inode->nlink;
plougher3c6bdb52010-05-01 02:30:59 +00001200 int inode_number = type == SQUASHFS_DIR_TYPE ?
1201 dir_ent->inode->inode_number :
plougherfd57dfe2009-03-30 01:17:52 +00001202 dir_ent->inode->inode_number + dir_inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001203 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001204
ploughere6e0e1b2010-05-12 17:17:06 +00001205 switch(type) {
1206 case SQUASHFS_FILE_TYPE:
1207 if(dir_ent->inode->nlink > 1 ||
1208 byte_size >= (1LL << 32) ||
1209 start_block >= (1LL << 32) ||
1210 sparse || IS_XATTR(xattr))
1211 type = SQUASHFS_LREG_TYPE;
1212 break;
1213 case SQUASHFS_DIR_TYPE:
1214 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1215 type = SQUASHFS_LDIR_TYPE;
1216 break;
1217 case SQUASHFS_SYMLINK_TYPE:
1218 if(IS_XATTR(xattr))
1219 type = SQUASHFS_LSYMLINK_TYPE;
1220 break;
1221 case SQUASHFS_BLKDEV_TYPE:
1222 if(IS_XATTR(xattr))
1223 type = SQUASHFS_LBLKDEV_TYPE;
1224 break;
1225 case SQUASHFS_CHRDEV_TYPE:
1226 if(IS_XATTR(xattr))
1227 type = SQUASHFS_LCHRDEV_TYPE;
1228 break;
plougherc5d69322010-05-12 19:28:38 +00001229 case SQUASHFS_FIFO_TYPE:
1230 if(IS_XATTR(xattr))
1231 type = SQUASHFS_LFIFO_TYPE;
1232 break;
1233 case SQUASHFS_SOCKET_TYPE:
1234 if(IS_XATTR(xattr))
1235 type = SQUASHFS_LSOCKET_TYPE;
1236 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001237 }
1238
plougher1f413c82005-11-18 00:02:14 +00001239 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001240 base->uid = get_uid((unsigned int) global_uid == -1 ?
1241 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001242 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001243 base->guid = get_guid((unsigned int) global_gid == -1 ?
1244 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001245 base->mtime = buf->st_mtime;
1246 base->inode_number = inode_number;
1247
1248 if(type == SQUASHFS_FILE_TYPE) {
1249 int i;
plougherac28cd12010-02-24 02:25:03 +00001250 squashfs_reg_inode_header *reg = &inode_header.reg;
1251 size_t off = offsetof(squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001252
1253 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001254 reg->file_size = byte_size;
1255 reg->start_block = start_block;
1256 reg->fragment = fragment->index;
1257 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001258 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1259 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001260 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1261 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001262 start_block, offset, fragment->index, fragment->offset,
1263 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001264 for(i = 0; i < offset; i++)
1265 TRACE("Block %d, size %d\n", i, block_list[i]);
1266 }
1267 else if(type == SQUASHFS_LREG_TYPE) {
1268 int i;
plougherac28cd12010-02-24 02:25:03 +00001269 squashfs_lreg_inode_header *reg = &inode_header.lreg;
1270 size_t off = offsetof(squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001271
1272 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001273 reg->nlink = nlink;
1274 reg->file_size = byte_size;
1275 reg->start_block = start_block;
1276 reg->fragment = fragment->index;
1277 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001278 if(sparse && sparse >= byte_size)
1279 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001280 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001281 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001282 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1283 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001284 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001285 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1286 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001287 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001288 for(i = 0; i < offset; i++)
1289 TRACE("Block %d, size %d\n", i, block_list[i]);
1290 }
1291 else if(type == SQUASHFS_LDIR_TYPE) {
1292 int i;
1293 unsigned char *p;
plougherac28cd12010-02-24 02:25:03 +00001294 squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001295 struct cached_dir_index *index = dir_in->index;
1296 unsigned int i_count = dir_in->i_count;
1297 unsigned int i_size = dir_in->i_size;
1298
1299 if(byte_size >= 1 << 27)
1300 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1301
1302 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001303 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001304 dir->nlink = dir_ent->dir->directory_count + 2;
1305 dir->file_size = byte_size;
1306 dir->offset = offset;
1307 dir->start_block = start_block;
1308 dir->i_count = i_count;
plougherfd57dfe2009-03-30 01:17:52 +00001309 dir->parent_inode = dir_ent->our_dir ?
1310 dir_ent->our_dir->dir_ent->inode->inode_number :
1311 dir_inode_no + inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001312 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001313
plougherac28cd12010-02-24 02:25:03 +00001314 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
1315 p = inode + offsetof(squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001316 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001317 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
1318 p += offsetof(squashfs_dir_index, name);
1319 memcpy(p, index[i].name, index[i].index.size + 1);
1320 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001321 }
plougher50b31762009-03-31 04:14:46 +00001322 TRACE("Long directory inode, file_size %lld, start_block "
1323 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1324 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001325 }
1326 else if(type == SQUASHFS_DIR_TYPE) {
1327 squashfs_dir_inode_header *dir = &inode_header.dir;
1328
1329 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001330 dir->nlink = dir_ent->dir->directory_count + 2;
1331 dir->file_size = byte_size;
1332 dir->offset = offset;
1333 dir->start_block = start_block;
plougherfd57dfe2009-03-30 01:17:52 +00001334 dir->parent_inode = dir_ent->our_dir ?
1335 dir_ent->our_dir->dir_ent->inode->inode_number :
1336 dir_inode_no + inode_no;
plougherac28cd12010-02-24 02:25:03 +00001337 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001338 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001339 "offset 0x%x, nlink %d\n", byte_size, start_block,
1340 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001341 }
1342 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
1343 squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001344 unsigned int major = major(buf->st_rdev);
1345 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001346
plougher5b398502008-10-04 23:22:03 +00001347 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001348 ERROR("Major %d out of range in device node %s, "
1349 "truncating to %d\n", major, filename,
1350 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001351 major &= 0xfff;
1352 }
1353 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001354 ERROR("Minor %d out of range in device node %s, "
1355 "truncating to %d\n", minor, filename,
1356 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001357 minor &= 0xfffff;
1358 }
plougher1f413c82005-11-18 00:02:14 +00001359 inode = get_inode(sizeof(*dev));
1360 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001361 dev->rdev = (major << 8) | (minor & 0xff) |
1362 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001363 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001364 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001365 }
ploughere6e0e1b2010-05-12 17:17:06 +00001366 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
1367 squashfs_ldev_inode_header *dev = &inode_header.ldev;
1368 unsigned int major = major(buf->st_rdev);
1369 unsigned int minor = minor(buf->st_rdev);
1370
1371 if(major > 0xfff) {
1372 ERROR("Major %d out of range in device node %s, "
1373 "truncating to %d\n", major, filename,
1374 major & 0xfff);
1375 major &= 0xfff;
1376 }
1377 if(minor > 0xfffff) {
1378 ERROR("Minor %d out of range in device node %s, "
1379 "truncating to %d\n", minor, filename,
1380 minor & 0xfffff);
1381 minor &= 0xfffff;
1382 }
1383 inode = get_inode(sizeof(*dev));
1384 dev->nlink = nlink;
1385 dev->rdev = (major << 8) | (minor & 0xff) |
1386 ((minor & ~0xff) << 12);
1387 dev->xattr = xattr;
1388 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1389 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1390 }
plougher1f413c82005-11-18 00:02:14 +00001391 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougherac28cd12010-02-24 02:25:03 +00001392 squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001393 int byte;
1394 char buff[65536];
plougherac28cd12010-02-24 02:25:03 +00001395 size_t off = offsetof(squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001396
1397 if((byte = readlink(filename, buff, 65536)) == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001398 ERROR("Failed to read symlink %s, creating empty "
1399 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001400 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001401 }
1402
1403 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001404 ERROR("Symlink %s is greater than 65536 bytes! "
1405 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001406 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001407 }
1408
1409 inode = get_inode(sizeof(*symlink) + byte);
1410 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001411 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001412 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1413 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001414 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1415 nlink);
plougher1f413c82005-11-18 00:02:14 +00001416 }
ploughere6e0e1b2010-05-12 17:17:06 +00001417 else if(type == SQUASHFS_LSYMLINK_TYPE) {
1418 squashfs_symlink_inode_header *symlink = &inode_header.symlink;
1419 int byte;
1420 char buff[65536];
1421 size_t off = offsetof(squashfs_symlink_inode_header, symlink);
1422
1423 if((byte = readlink(filename, buff, 65536)) == -1) {
1424 ERROR("Failed to read symlink %s, creating empty "
1425 "symlink\n", filename);
1426 byte = 0;
1427 }
1428
1429 if(byte == 65536) {
1430 ERROR("Symlink %s is greater than 65536 bytes! "
1431 "Creating empty symlink\n", filename);
1432 byte = 0;
1433 }
1434
1435 inode = get_inode(sizeof(*symlink) + byte +
1436 sizeof(unsigned int));
1437 symlink->nlink = nlink;
1438 symlink->symlink_size = byte;
1439 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1440 strncpy(inode + off, buff, byte);
1441 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1442 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1443 nlink);
1444 }
plougher1f413c82005-11-18 00:02:14 +00001445 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
1446 squashfs_ipc_inode_header *ipc = &inode_header.ipc;
1447
1448 inode = get_inode(sizeof(*ipc));
1449 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001450 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001451 TRACE("ipc inode, type %s, nlink %d\n", type ==
1452 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001453 }
1454 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
1455 squashfs_lipc_inode_header *ipc = &inode_header.lipc;
1456
1457 inode = get_inode(sizeof(*ipc));
1458 ipc->nlink = nlink;
1459 ipc->xattr = xattr;
1460 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1461 TRACE("ipc inode, type %s, nlink %d\n", type ==
1462 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001463 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001464 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001465
1466 *i_no = MKINODE(inode);
1467 inode_count ++;
1468
plougherfd57dfe2009-03-30 01:17:52 +00001469 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1470 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001471
1472 return TRUE;
1473}
1474
1475
plougher43244f22009-04-05 02:04:51 +00001476void scan3_init_dir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001477{
plougher8cb05cd2005-12-11 23:32:35 +00001478 if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001479 BAD_ERROR("Out of memory allocating directory buffer\n");
1480 }
1481
1482 dir->size = SQUASHFS_METADATA_SIZE;
1483 dir->p = dir->index_count_p = dir->buff;
1484 dir->entry_count = 256;
1485 dir->entry_count_p = NULL;
1486 dir->index = NULL;
1487 dir->i_count = dir->i_size = 0;
1488}
1489
1490
plougher50b31762009-03-31 04:14:46 +00001491void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1492 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001493{
plougher8cb05cd2005-12-11 23:32:35 +00001494 unsigned char *buff;
plougherac28cd12010-02-24 02:25:03 +00001495 squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001496 unsigned int start_block = inode >> 16;
1497 unsigned int offset = inode & 0xffff;
1498 unsigned int size;
plougherac28cd12010-02-24 02:25:03 +00001499 size_t name_off = offsetof(squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001500
1501 if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
1502 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001503 ERROR("Filename is greater than %d characters, truncating! ..."
1504 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001505 }
1506
plougher50b31762009-03-31 04:14:46 +00001507 if(dir->p + sizeof(squashfs_dir_entry) + size +
1508 sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001509 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1510 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001511 BAD_ERROR("Out of memory reallocating directory buffer"
1512 "\n");
plougher1f413c82005-11-18 00:02:14 +00001513 }
1514
1515 dir->p = (dir->p - dir->buff) + buff;
1516 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001517 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1518 buff);
plougher1f413c82005-11-18 00:02:14 +00001519 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1520 dir->buff = buff;
1521 }
1522
plougherfd57dfe2009-03-30 01:17:52 +00001523 if(dir->entry_count == 256 || start_block != dir->start_block ||
1524 ((dir->entry_count_p != NULL) &&
1525 ((dir->p + sizeof(squashfs_dir_entry) + size -
1526 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001527 ((long long) inode_number - dir->inode_number) > 32767
1528 || ((long long) inode_number - dir->inode_number)
1529 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001530 if(dir->entry_count_p) {
1531 squashfs_dir_header dir_header;
1532
plougherfd57dfe2009-03-30 01:17:52 +00001533 if((dir->p + sizeof(squashfs_dir_entry) + size -
1534 dir->index_count_p) >
1535 SQUASHFS_METADATA_SIZE) {
1536 if(dir->i_count % I_COUNT_SIZE == 0) {
1537 dir->index = realloc(dir->index,
1538 (dir->i_count + I_COUNT_SIZE) *
1539 sizeof(struct cached_dir_index));
1540 if(dir->index == NULL)
1541 BAD_ERROR("Out of memory in "
1542 "directory index table "
1543 "reallocation!\n");
1544 }
1545 dir->index[dir->i_count].index.index =
1546 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001547 dir->index[dir->i_count].index.size = size - 1;
1548 dir->index[dir->i_count++].name = name;
plougher50b31762009-03-31 04:14:46 +00001549 dir->i_size += sizeof(squashfs_dir_index) +
1550 size;
plougher1f413c82005-11-18 00:02:14 +00001551 dir->index_count_p = dir->p;
1552 }
1553
1554 dir_header.count = dir->entry_count - 1;
1555 dir_header.start_block = dir->start_block;
1556 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001557 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001558 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001559
1560 }
1561
1562
1563 dir->entry_count_p = dir->p;
1564 dir->start_block = start_block;
1565 dir->entry_count = 0;
1566 dir->inode_number = inode_number;
1567 dir->p += sizeof(squashfs_dir_header);
1568 }
1569
plougher1f413c82005-11-18 00:02:14 +00001570 idir.offset = offset;
1571 idir.type = type;
1572 idir.size = size - 1;
1573 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001574 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1575 strncpy((char *) dir->p + name_off, name, size);
plougher1f413c82005-11-18 00:02:14 +00001576 dir->p += sizeof(squashfs_dir_entry) + size;
1577 dir->entry_count ++;
1578}
1579
1580
plougherfd57dfe2009-03-30 01:17:52 +00001581void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1582 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001583{
1584 unsigned int dir_size = dir->p - dir->buff;
1585 int data_space = (directory_cache_size - directory_cache_bytes);
1586 unsigned int directory_block, directory_offset, i_count, index;
1587 unsigned short c_byte;
1588
1589 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001590 int realloc_size = directory_cache_size == 0 ?
1591 ((dir_size + SQUASHFS_METADATA_SIZE) &
1592 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001593
plougherfd57dfe2009-03-30 01:17:52 +00001594 directory_data_cache = realloc(directory_data_cache,
1595 directory_cache_size + realloc_size);
1596 if(directory_data_cache == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001597 goto failed;
1598 }
1599 directory_cache_size += realloc_size;
1600 }
1601
1602 if(dir_size) {
1603 squashfs_dir_header dir_header;
1604
1605 dir_header.count = dir->entry_count - 1;
1606 dir_header.start_block = dir->start_block;
1607 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001608 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001609 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1610 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001611 }
1612 directory_offset = directory_cache_bytes;
1613 directory_block = directory_bytes;
1614 directory_cache_bytes += dir_size;
1615 i_count = 0;
1616 index = SQUASHFS_METADATA_SIZE - directory_offset;
1617
1618 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001619 while(i_count < dir->i_count &&
1620 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001621 dir->index[i_count++].index.start_block =
1622 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001623 index += SQUASHFS_METADATA_SIZE;
1624
1625 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1626 break;
1627
plougherfd57dfe2009-03-30 01:17:52 +00001628 if((directory_size - directory_bytes) <
1629 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher50b31762009-03-31 04:14:46 +00001630 directory_table = realloc(directory_table,
1631 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1632 + 2);
plougherfd57dfe2009-03-30 01:17:52 +00001633 if(directory_table == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001634 goto failed;
1635 }
1636 directory_size += SQUASHFS_METADATA_SIZE << 1;
1637 }
1638
plougher50b31762009-03-31 04:14:46 +00001639 c_byte = mangle(directory_table + directory_bytes +
1640 BLOCK_OFFSET, directory_data_cache,
1641 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1642 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001643 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1644 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001645 SQUASHFS_SWAP_SHORTS(&c_byte,
1646 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001647 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1648 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001649 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougherfd57dfe2009-03-30 01:17:52 +00001650 memcpy(directory_data_cache, directory_data_cache +
1651 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1652 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001653 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1654 }
1655
plougher3c6bdb52010-05-01 02:30:59 +00001656 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1657 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1658 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001659
1660#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001661 {
plougher1f413c82005-11-18 00:02:14 +00001662 unsigned char *dirp;
1663 int count;
1664
1665 TRACE("Directory contents of inode 0x%llx\n", *inode);
1666 dirp = dir->buff;
1667 while(dirp < dir->p) {
1668 char buffer[SQUASHFS_NAME_LEN + 1];
1669 squashfs_dir_entry idir, *idirp;
plougher1f288f62009-02-21 03:05:52 +00001670 squashfs_dir_header dirh;
plougher360514a2009-03-30 03:01:38 +00001671 SQUASHFS_SWAP_DIR_HEADER((squashfs_dir_header *) dirp,
1672 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001673 count = dirh.count + 1;
plougher1f413c82005-11-18 00:02:14 +00001674 dirp += sizeof(squashfs_dir_header);
1675
plougher50b31762009-03-31 04:14:46 +00001676 TRACE("\tStart block 0x%x, count %d\n",
1677 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001678
1679 while(count--) {
1680 idirp = (squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001681 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001682 strncpy(buffer, idirp->name, idir.size + 1);
1683 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001684 TRACE("\t\tname %s, inode offset 0x%x, type "
1685 "%d\n", buffer, idir.offset, idir.type);
1686 dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001687 }
1688 }
1689 }
1690#endif
1691 dir_count ++;
1692
plougher29e37092007-04-15 01:24:51 +00001693 return;
plougher1f413c82005-11-18 00:02:14 +00001694
1695failed:
1696 BAD_ERROR("Out of memory in directory table reallocation!\n");
1697}
1698
1699
plougher76c64082008-03-08 01:32:23 +00001700struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001701{
plougher5507dd92006-11-06 00:43:10 +00001702 squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001703 int res, size;
plougher76c64082008-03-08 01:32:23 +00001704 long long start_block;
1705 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001706
plougher76c64082008-03-08 01:32:23 +00001707 if(fragment->index == SQUASHFS_INVALID_FRAG)
1708 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001709
plougher76c64082008-03-08 01:32:23 +00001710 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001711 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001712 return buffer;
plougher76c64082008-03-08 01:32:23 +00001713
plougherfd57dfe2009-03-30 01:17:52 +00001714 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1715 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001716
plougher76c64082008-03-08 01:32:23 +00001717 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001718
1719 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001720 disk_fragment = &fragment_table[fragment->index];
1721 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001722 start_block = disk_fragment->start_block;
1723 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001724
plougher0f464442008-03-31 00:27:56 +00001725 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001726 int error;
plougher76c64082008-03-08 01:32:23 +00001727 char *data;
plougher1f413c82005-11-18 00:02:14 +00001728
plougher76c64082008-03-08 01:32:23 +00001729 if(compressed_buffer)
1730 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001731 else
1732 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001733
ploughera175ce22009-07-30 04:43:27 +00001734 res = comp->uncompress(buffer->data, data, size, block_size,
1735 &error);
1736 if(res == -1)
1737 BAD_ERROR("%s uncompress failed with error code %d\n",
1738 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001739 } else if(compressed_buffer)
1740 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001741 else {
1742 res = read_fs_bytes(fd, start_block, size, buffer->data);
1743 if(res == 0)
1744 EXIT_MKSQUASHFS();
1745 }
plougher1f413c82005-11-18 00:02:14 +00001746
plougher03859fa2009-03-31 03:18:18 +00001747 cache_block_put(compressed_buffer);
1748
plougher76c64082008-03-08 01:32:23 +00001749 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001750}
1751
plougher2ea89142008-03-11 01:34:19 +00001752
1753struct frag_locked {
1754 struct file_buffer *buffer;
1755 int c_byte;
1756 int fragment;
1757 struct frag_locked *fragment_prev;
1758 struct frag_locked *fragment_next;
1759};
1760
1761int fragments_locked = FALSE;
1762struct frag_locked *frag_locked_list = NULL;
1763
1764INSERT_LIST(fragment, struct frag_locked)
1765REMOVE_LIST(fragment, struct frag_locked)
1766
plougher4e8484a2008-03-15 23:30:16 +00001767int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001768{
plougher4e8484a2008-03-15 23:30:16 +00001769 int count;
plougher5507dd92006-11-06 00:43:10 +00001770 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001771 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001772 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001773 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001774 return count;
plougher2ea89142008-03-11 01:34:19 +00001775}
1776
1777
1778void unlock_fragments()
1779{
1780 struct frag_locked *entry;
1781 int compressed_size;
1782
1783 pthread_mutex_lock(&fragment_mutex);
1784 while(frag_locked_list) {
1785 entry = frag_locked_list;
1786 remove_fragment_list(&frag_locked_list, entry);
1787 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1788 fragment_table[entry->fragment].size = entry->c_byte;
1789 fragment_table[entry->fragment].start_block = bytes;
1790 entry->buffer->block = bytes;
1791 bytes += compressed_size;
1792 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001793 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001794 TRACE("fragment_locked writing fragment %d, compressed size %d"
1795 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001796 free(entry);
1797 }
1798 fragments_locked = FALSE;
1799 pthread_mutex_unlock(&fragment_mutex);
1800}
1801
1802
plougherb7a66812010-07-21 01:06:59 +00001803void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001804 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001805{
1806 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1807 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001808 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001809 entry->buffer = write_buffer;
1810 entry->c_byte = c_byte;
1811 entry->fragment = fragment;
1812 entry->fragment_prev = entry->fragment_next = NULL;
1813 pthread_mutex_lock(&fragment_mutex);
1814 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001815 pthread_mutex_unlock(&fragment_mutex);
1816}
1817
1818
plougher1f413c82005-11-18 00:02:14 +00001819void write_fragment()
1820{
plougher1f413c82005-11-18 00:02:14 +00001821 if(fragment_size == 0)
1822 return;
1823
plougher5507dd92006-11-06 00:43:10 +00001824 pthread_mutex_lock(&fragment_mutex);
1825 if(fragments % FRAG_SIZE == 0) {
plougher50b31762009-03-31 04:14:46 +00001826 fragment_table = realloc(fragment_table, (fragments +
1827 FRAG_SIZE) * sizeof(squashfs_fragment_entry));
plougher17b269c2009-03-30 01:33:07 +00001828 if(fragment_table == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001829 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001830 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001831 }
1832 }
1833 fragment_data->size = fragment_size;
1834 fragment_data->block = fragments;
plougher2ea89142008-03-11 01:34:19 +00001835 fragment_table[fragments].unused = 0;
plougher5507dd92006-11-06 00:43:10 +00001836 fragments_outstanding ++;
1837 queue_put(to_frag, fragment_data);
plougher1f413c82005-11-18 00:02:14 +00001838 fragments ++;
1839 fragment_size = 0;
plougher5507dd92006-11-06 00:43:10 +00001840 pthread_mutex_unlock(&fragment_mutex);
1841}
1842
ploughereb6eac92008-02-26 01:50:48 +00001843
plougher1f413c82005-11-18 00:02:14 +00001844static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
plougher5507dd92006-11-06 00:43:10 +00001845struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer)
plougher1f413c82005-11-18 00:02:14 +00001846{
1847 struct fragment *ffrg;
plougher5507dd92006-11-06 00:43:10 +00001848
plougher1f413c82005-11-18 00:02:14 +00001849
plougher5507dd92006-11-06 00:43:10 +00001850 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001851 return &empty_fragment;
1852
plougher5507dd92006-11-06 00:43:10 +00001853 if(fragment_size + file_buffer->size > block_size)
plougher1f413c82005-11-18 00:02:14 +00001854 write_fragment();
1855
ploughera2968ef2009-03-03 10:46:00 +00001856 if((ffrg = malloc(sizeof(struct fragment))) == NULL)
plougher1f413c82005-11-18 00:02:14 +00001857 BAD_ERROR("Out of memory in fragment block allocation!\n");
1858
plougher5507dd92006-11-06 00:43:10 +00001859 if(fragment_size == 0)
plougher76c64082008-03-08 01:32:23 +00001860 fragment_data = cache_get(fragment_buffer, fragments, 1);
plougher5507dd92006-11-06 00:43:10 +00001861
plougher1f413c82005-11-18 00:02:14 +00001862 ffrg->index = fragments;
1863 ffrg->offset = fragment_size;
plougher5507dd92006-11-06 00:43:10 +00001864 ffrg->size = file_buffer->size;
plougher17b269c2009-03-30 01:33:07 +00001865 memcpy(fragment_data->data + fragment_size, file_buffer->data,
1866 file_buffer->size);
plougher5507dd92006-11-06 00:43:10 +00001867 fragment_size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001868
1869 return ffrg;
1870}
1871
1872
ploughere6e0e1b2010-05-12 17:17:06 +00001873long long generic_write_table(int length, char *buffer, int length2,
1874 char *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001875{
plougher17b269c2009-03-30 01:33:07 +00001876 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1877 SQUASHFS_METADATA_SIZE;
plougher0e453652006-11-06 01:49:35 +00001878 long long list[meta_blocks], start_bytes;
plougherbadfac62007-11-12 03:29:41 +00001879 int compressed_size, i;
plougher1f413c82005-11-18 00:02:14 +00001880 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001881 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1882
plougher82ab2332009-04-21 00:21:21 +00001883#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001884 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001885 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001886#endif
plougher1f413c82005-11-18 00:02:14 +00001887
1888 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001889 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1890 SQUASHFS_METADATA_SIZE : length;
1891 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1892 SQUASHFS_METADATA_SIZE , avail_bytes,
1893 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001894 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001895 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001896 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1897 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001898 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1899 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001900 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001901 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001902 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001903 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001904 }
1905
ploughere6e0e1b2010-05-12 17:17:06 +00001906 start_bytes = bytes;
1907 if(length2) {
1908 write_destination(fd, bytes, length2, (char *) buffer2);
1909 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001910 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001911 }
1912
plougher1f288f62009-02-21 03:05:52 +00001913 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
plougher0dd6f122009-03-29 21:43:57 +00001914 write_destination(fd, bytes, sizeof(list), (char *) list);
plougher1f413c82005-11-18 00:02:14 +00001915 bytes += sizeof(list);
plougher10f7d572010-07-20 02:14:04 +00001916 total_bytes += sizeof(list);
plougher1f413c82005-11-18 00:02:14 +00001917
plougher40d8b952010-02-12 16:26:32 +00001918 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1919 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001920
plougher1f413c82005-11-18 00:02:14 +00001921 return start_bytes;
1922}
1923
1924
plougher0e453652006-11-06 01:49:35 +00001925long long write_fragment_table()
1926{
1927 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougherac28cd12010-02-24 02:25:03 +00001928 squashfs_fragment_entry p[fragments];
plougher0e453652006-11-06 01:49:35 +00001929 int i;
1930
plougher17b269c2009-03-30 01:33:07 +00001931 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1932 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001933 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001934 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1935 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001936 fragment_table[i].size);
plougherac28cd12010-02-24 02:25:03 +00001937 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p + i);
plougher0e453652006-11-06 01:49:35 +00001938 }
1939
ploughere6e0e1b2010-05-12 17:17:06 +00001940 return generic_write_table(frag_bytes, (char *) p, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001941}
1942
1943
plougher1f413c82005-11-18 00:02:14 +00001944char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001945char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001946{
plougher1d065e92010-06-18 03:58:27 +00001947 int res;
1948
1949 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
1950 if(res == 0)
1951 EXIT_MKSQUASHFS();
1952
plougher1f413c82005-11-18 00:02:14 +00001953 return read_from_file_buffer;
1954}
1955
1956
plougher1b899fc2008-08-07 01:24:06 +00001957char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
1958char *read_from_disk2(long long start, unsigned int avail_bytes)
1959{
plougher1d065e92010-06-18 03:58:27 +00001960 int res;
1961
1962 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
1963 if(res == 0)
1964 EXIT_MKSQUASHFS();
1965
plougher1b899fc2008-08-07 01:24:06 +00001966 return read_from_file_buffer2;
1967}
1968
1969
plougher1f413c82005-11-18 00:02:14 +00001970/*
1971 * Compute 16 bit BSD checksum over the data
1972 */
plougher5507dd92006-11-06 00:43:10 +00001973unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00001974{
plougher5507dd92006-11-06 00:43:10 +00001975 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00001976
plougher5507dd92006-11-06 00:43:10 +00001977 while(bytes --) {
1978 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1979 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00001980 }
1981
1982 return chksum;
1983}
1984
1985
plougher17b269c2009-03-30 01:33:07 +00001986unsigned short get_checksum_disk(long long start, long long l,
1987 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00001988{
1989 unsigned short chksum = 0;
1990 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00001991 struct file_buffer *write_buffer;
1992 int i;
plougher5507dd92006-11-06 00:43:10 +00001993
plougher57e6d182008-05-06 23:51:29 +00001994 for(i = 0; l; i++) {
1995 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
1996 if(bytes == 0) /* sparse block */
1997 continue;
1998 write_buffer = cache_lookup(writer_buffer, start);
1999 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002000 chksum = get_checksum(write_buffer->data, bytes,
2001 chksum);
plougher57e6d182008-05-06 23:51:29 +00002002 cache_block_put(write_buffer);
2003 } else
plougher50b31762009-03-31 04:14:46 +00002004 chksum = get_checksum(read_from_disk(start, bytes),
2005 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002006 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002007 start += bytes;
2008 }
2009
2010 return chksum;
2011}
2012
2013
plougher5507dd92006-11-06 00:43:10 +00002014unsigned short get_checksum_mem(char *buff, int bytes)
2015{
2016 return get_checksum(buff, bytes, 0);
2017}
2018
2019
2020unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2021{
2022 if(file_buffer == NULL)
2023 return 0;
2024 else
2025 return get_checksum(file_buffer->data, file_buffer->size, 0);
2026}
2027
2028
plougher5507dd92006-11-06 00:43:10 +00002029#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002030void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002031 unsigned int *block_listp, int blocks, unsigned int fragment,
2032 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002033{
2034 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002035 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002036 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002037
plougher5507dd92006-11-06 00:43:10 +00002038 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002039 return;
2040
plougher5507dd92006-11-06 00:43:10 +00002041 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2042 if(file_size != dupl_ptr->file_size)
2043 continue;
2044 if(blocks != 0 && start != dupl_ptr->start)
2045 continue;
2046 if(fragment != dupl_ptr->fragment->index)
2047 continue;
plougher17b269c2009-03-30 01:33:07 +00002048 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2049 dupl_ptr->fragment->offset || bytes !=
2050 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002051 continue;
2052 return;
2053 }
2054
ploughera2968ef2009-03-03 10:46:00 +00002055 if((frg = malloc(sizeof(struct fragment))) == NULL)
plougher1f413c82005-11-18 00:02:14 +00002056 BAD_ERROR("Out of memory in fragment block allocation!\n");
2057
2058 frg->index = fragment;
2059 frg->offset = offset;
2060 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002061
plougher5507dd92006-11-06 00:43:10 +00002062 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2063}
plougher1f413c82005-11-18 00:02:14 +00002064
plougher1f413c82005-11-18 00:02:14 +00002065
plougher5507dd92006-11-06 00:43:10 +00002066int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002067{
plougher5507dd92006-11-06 00:43:10 +00002068 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002069
2070 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002071 if(dupl_ptr->file_size == file_size)
2072 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002073
plougher5507dd92006-11-06 00:43:10 +00002074 return FALSE;
2075}
2076
2077
2078int pre_duplicate_frag(long long file_size, unsigned short checksum)
2079{
2080 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2081
2082 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002083 if(file_size == dupl_ptr->file_size && file_size ==
2084 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002085 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002086 struct file_buffer *frag_buffer =
2087 get_fragment(dupl_ptr->fragment);
2088 dupl_ptr->checksum =
2089 get_checksum_disk(dupl_ptr->start,
2090 dupl_ptr->bytes, dupl_ptr->block_list);
2091 dupl_ptr->fragment_checksum =
2092 get_checksum_mem(frag_buffer->data +
2093 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002094 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002095 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002096 }
plougher5507dd92006-11-06 00:43:10 +00002097 if(dupl_ptr->fragment_checksum == checksum)
2098 return TRUE;
2099 }
plougher1f413c82005-11-18 00:02:14 +00002100
plougher5507dd92006-11-06 00:43:10 +00002101 return FALSE;
2102}
2103
2104
plougher17b269c2009-03-30 01:33:07 +00002105struct file_info *add_non_dup(long long file_size, long long bytes,
2106 unsigned int *block_list, long long start, struct fragment *fragment,
2107 unsigned short checksum, unsigned short fragment_checksum,
2108 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002109{
2110 struct file_info *dupl_ptr;
2111
ploughera2968ef2009-03-03 10:46:00 +00002112 if((dupl_ptr = malloc(sizeof(struct file_info))) == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002113 BAD_ERROR("Out of memory in dup_files allocation!\n");
2114 }
2115
2116 dupl_ptr->file_size = file_size;
2117 dupl_ptr->bytes = bytes;
2118 dupl_ptr->block_list = block_list;
2119 dupl_ptr->start = start;
2120 dupl_ptr->fragment = fragment;
2121 dupl_ptr->checksum = checksum;
2122 dupl_ptr->fragment_checksum = fragment_checksum;
2123 dupl_ptr->checksum_flag = checksum_flag;
2124 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2125 dupl[DUP_HASH(file_size)] = dupl_ptr;
2126 dup_files ++;
2127
2128 return dupl_ptr;
2129}
2130
2131
plougher17b269c2009-03-30 01:33:07 +00002132struct file_info *duplicate(long long file_size, long long bytes,
2133 unsigned int **block_list, long long *start, struct fragment **fragment,
2134 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2135 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002136{
2137 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2138 int frag_bytes = file_buffer ? file_buffer->size : 0;
2139
2140 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002141 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2142 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002143 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002144 int block;
2145
plougher17b269c2009-03-30 01:33:07 +00002146 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2147 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002148 continue;
2149
plougher5507dd92006-11-06 00:43:10 +00002150 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002151 checksum = get_checksum_disk(*start, bytes,
2152 *block_list);
2153 fragment_checksum =
2154 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002155 checksum_flag = TRUE;
2156 }
2157
2158 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002159 struct file_buffer *frag_buffer =
2160 get_fragment(dupl_ptr->fragment);
2161 dupl_ptr->checksum =
2162 get_checksum_disk(dupl_ptr->start,
2163 dupl_ptr->bytes, dupl_ptr->block_list);
2164 dupl_ptr->fragment_checksum =
2165 get_checksum_mem(frag_buffer->data +
2166 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002167 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002168 dupl_ptr->checksum_flag = TRUE;
2169 }
2170
plougher17b269c2009-03-30 01:33:07 +00002171 if(checksum != dupl_ptr->checksum ||
2172 fragment_checksum !=
2173 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002174 continue;
2175
plougher1b899fc2008-08-07 01:24:06 +00002176 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002177 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002178 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2179 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002180 struct file_buffer *target_buffer = NULL;
2181 struct file_buffer *dup_buffer = NULL;
2182 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002183 int res;
plougher5507dd92006-11-06 00:43:10 +00002184
plougher1b899fc2008-08-07 01:24:06 +00002185 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002186 continue;
plougher17b269c2009-03-30 01:33:07 +00002187 target_buffer = cache_lookup(writer_buffer,
2188 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002189 if(target_buffer)
2190 target_data = target_buffer->data;
2191 else
plougher50b31762009-03-31 04:14:46 +00002192 target_data =
2193 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002194 size);
plougher5507dd92006-11-06 00:43:10 +00002195
plougher360514a2009-03-30 03:01:38 +00002196 dup_buffer = cache_lookup(writer_buffer,
2197 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002198 if(dup_buffer)
2199 dup_data = dup_buffer->data;
2200 else
plougher360514a2009-03-30 03:01:38 +00002201 dup_data = read_from_disk2(dup_start,
2202 size);
plougher1b899fc2008-08-07 01:24:06 +00002203
2204 res = memcmp(target_data, dup_data, size);
2205 cache_block_put(target_buffer);
2206 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002207 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002208 break;
plougher1b899fc2008-08-07 01:24:06 +00002209 target_start += size;
2210 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002211 }
2212 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002213 struct file_buffer *frag_buffer =
2214 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002215
plougher17b269c2009-03-30 01:33:07 +00002216 if(frag_bytes == 0 ||
2217 memcmp(file_buffer->data,
2218 frag_buffer->data +
2219 dupl_ptr->fragment->offset,
2220 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002221 TRACE("Found duplicate file, start "
2222 "0x%llx, size %lld, checksum "
2223 "0x%x, fragment %d, size %d, "
2224 "offset %d, checksum 0x%x\n",
2225 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002226 dupl_ptr->bytes,
2227 dupl_ptr->checksum,
2228 dupl_ptr->fragment->index,
2229 frag_bytes,
2230 dupl_ptr->fragment->offset,
2231 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002232 *block_list = dupl_ptr->block_list;
2233 *start = dupl_ptr->start;
2234 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002235 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002236 return 0;
2237 }
plougher76c64082008-03-08 01:32:23 +00002238 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002239 }
2240 }
2241
2242
plougher17b269c2009-03-30 01:33:07 +00002243 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2244 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002245}
2246
2247
plougher00d08172009-09-03 10:17:44 +00002248static int seq = 0;
2249void reader_read_process(struct dir_ent *dir_ent)
2250{
2251 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002252 int status, res, byte, count = 0;
2253 int file = get_pseudo_file(dir_ent->inode->pseudo_id)->fd;
2254 int child = get_pseudo_file(dir_ent->inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002255 long long bytes = 0;
2256
2257 while(1) {
2258 file_buffer = cache_get(reader_buffer, 0, 0);
2259 file_buffer->sequence = seq ++;
2260
2261 byte = read_bytes(file, file_buffer->data, block_size);
2262 if(byte == -1)
2263 goto read_err;
2264
2265 file_buffer->size = byte;
2266 file_buffer->file_size = -1;
2267 file_buffer->block = count ++;
2268 file_buffer->error = FALSE;
2269 file_buffer->fragment = FALSE;
2270 bytes += byte;
2271
2272 if(byte == 0)
2273 break;
2274
plougher286b6b32009-09-19 03:29:27 +00002275 /*
2276 * Update estimated_uncompressed block count. This is done
2277 * on every block rather than waiting for all blocks to be
2278 * read incase write_file_process() is running in parallel
2279 * with this. Otherwise cur uncompressed block count may
2280 * get ahead of the total uncompressed block count.
2281 */
2282 estimated_uncompressed ++;
2283
plougher00d08172009-09-03 10:17:44 +00002284 if(prev_buffer)
2285 queue_put(from_reader, prev_buffer);
2286 prev_buffer = file_buffer;
2287 }
2288
plougher54d67292009-09-19 03:26:27 +00002289 /*
2290 * Update inode file size now that the size of the dynamic pseudo file
2291 * is known. This is needed for the -info option.
2292 */
2293 dir_ent->inode->buf.st_size = bytes;
2294
plougherba674e82009-09-10 03:50:00 +00002295 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002296 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002297 goto read_err;
2298
plougher00d08172009-09-03 10:17:44 +00002299 if(prev_buffer == NULL)
2300 prev_buffer = file_buffer;
2301 else {
2302 cache_block_put(file_buffer);
2303 seq --;
2304 }
2305 prev_buffer->file_size = bytes;
2306 prev_buffer->fragment = !no_fragments &&
2307 (count == 2 || always_use_fragments) && (byte < block_size);
2308 queue_put(from_reader, prev_buffer);
2309
2310 return;
2311
2312read_err:
2313 if(prev_buffer) {
2314 cache_block_put(file_buffer);
2315 seq --;
2316 file_buffer = prev_buffer;
2317 }
2318 file_buffer->error = TRUE;
2319 queue_put(from_deflate, file_buffer);
2320}
2321
2322
plougher5507dd92006-11-06 00:43:10 +00002323void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002324{
plougher018d2b32007-04-23 03:01:48 +00002325 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002326 struct file_buffer *file_buffer;
plougher018d2b32007-04-23 03:01:48 +00002327 int blocks, byte, count, expected, file, frag_block;
2328 long long bytes, read_size;
plougher5507dd92006-11-06 00:43:10 +00002329
plougher018d2b32007-04-23 03:01:48 +00002330 if(dir_ent->inode->read)
plougher5507dd92006-11-06 00:43:10 +00002331 return;
2332
plougher018d2b32007-04-23 03:01:48 +00002333 dir_ent->inode->read = TRUE;
2334again:
2335 bytes = 0;
2336 count = 0;
2337 file_buffer = NULL;
2338 read_size = buf->st_size;
2339 blocks = (read_size + block_size - 1) >> block_log;
2340 frag_block = !no_fragments && (always_use_fragments ||
2341 (read_size < block_size)) ? read_size >> block_log : -1;
2342
plougher5507dd92006-11-06 00:43:10 +00002343 if((file = open(dir_ent->pathname, O_RDONLY)) == -1)
2344 goto read_err;
2345
plougher018d2b32007-04-23 03:01:48 +00002346 do {
plougher110799c2009-03-30 01:50:40 +00002347 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002348 block_size ? block_size :
2349 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002350
2351 if(file_buffer)
2352 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002353 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002354 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002355
plougher110799c2009-03-30 01:50:40 +00002356 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2357 block_size);
plougher018d2b32007-04-23 03:01:48 +00002358
plougher018d2b32007-04-23 03:01:48 +00002359 file_buffer->file_size = read_size;
2360
2361 if(byte != expected)
2362 goto restat;
2363
2364 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002365 file_buffer->error = FALSE;
plougher1b899fc2008-08-07 01:24:06 +00002366 file_buffer->fragment = (file_buffer->block == frag_block);
plougher018d2b32007-04-23 03:01:48 +00002367
2368 bytes += byte;
2369 count ++;
2370 } while(count < blocks);
2371
2372 if(read_size != bytes)
2373 goto restat;
2374
2375 if(expected == block_size) {
2376 char buffer;
2377
plougher1179b5f2009-03-30 00:33:19 +00002378 if(read_bytes(file, &buffer, 1) == 1)
plougher018d2b32007-04-23 03:01:48 +00002379 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002380 }
2381
plougher1b899fc2008-08-07 01:24:06 +00002382 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002383
plougher5507dd92006-11-06 00:43:10 +00002384 close(file);
plougher5507dd92006-11-06 00:43:10 +00002385
2386 return;
2387
2388read_err:
plougher0f464442008-03-31 00:27:56 +00002389 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002390 file_buffer->sequence = seq ++;
plougher018d2b32007-04-23 03:01:48 +00002391read_err2:
plougher5507dd92006-11-06 00:43:10 +00002392 file_buffer->error = TRUE;
2393 queue_put(from_deflate, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002394 return;
2395restat:
2396 fstat(file, &buf2);
2397 close(file);
2398 if(read_size != buf2.st_size) {
2399 memcpy(buf, &buf2, sizeof(struct stat));
2400 file_buffer->error = 2;
2401 queue_put(from_deflate, file_buffer);
2402 goto again;
2403 }
2404 goto read_err2;
plougher5507dd92006-11-06 00:43:10 +00002405}
2406
2407
2408void reader_scan(struct dir_info *dir) {
2409 int i;
2410
2411 for(i = 0; i < dir->count; i++) {
2412 struct dir_ent *dir_ent = dir->list[i];
2413 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002414 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002415 continue;
2416
plougherb3977eb2010-05-02 02:08:48 +00002417 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002418 reader_read_process(dir_ent);
2419 continue;
2420 }
2421
plougher5507dd92006-11-06 00:43:10 +00002422 switch(buf->st_mode & S_IFMT) {
2423 case S_IFREG:
2424 reader_read_file(dir_ent);
2425 break;
2426 case S_IFDIR:
2427 reader_scan(dir_ent->dir);
2428 break;
2429 }
2430 }
2431}
2432
2433
2434void *reader(void *arg)
2435{
2436 int oldstate;
2437
2438 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2439 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2440
2441 if(!sorted)
2442 reader_scan(queue_get(to_reader));
2443 else {
2444 int i;
2445 struct priority_entry *entry;
2446
2447 queue_get(to_reader);
2448 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002449 for(entry = priority_list[i]; entry;
2450 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002451 reader_read_file(entry->dir);
2452 }
rloughere4873e02007-11-08 17:50:42 +00002453
plougher5aa18162007-12-13 12:15:21 +00002454 thread[0] = 0;
2455
rloughere4873e02007-11-08 17:50:42 +00002456 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002457}
2458
2459
2460void *writer(void *arg)
2461{
2462 int write_error = FALSE;
2463 int oldstate;
2464
2465 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2466 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2467
2468 while(1) {
2469 struct file_buffer *file_buffer = queue_get(to_writer);
2470 off_t off;
2471
2472 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002473 queue_put(from_writer,
2474 write_error ? (void *) &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002475 continue;
2476 }
2477
2478 off = file_buffer->block;
2479
2480 pthread_mutex_lock(&pos_mutex);
2481
2482 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002483 ERROR("Lseek on destination failed because %s\n",
2484 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002485 write_error = TRUE;
2486 }
2487
plougher110799c2009-03-30 01:50:40 +00002488 if(!write_error && write_bytes(fd, file_buffer->data,
2489 file_buffer->size) == -1) {
2490 ERROR("Write on destination failed because %s\n",
2491 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002492 write_error = TRUE;
2493 }
2494 pthread_mutex_unlock(&pos_mutex);
2495
ploughereb6eac92008-02-26 01:50:48 +00002496 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002497 }
2498}
2499
2500
plougher5b09fd42007-08-06 10:28:41 +00002501int all_zero(struct file_buffer *file_buffer)
2502{
2503 int i;
2504 long entries = file_buffer->size / sizeof(long);
2505 long *p = (long *) file_buffer->data;
2506
2507 for(i = 0; i < entries && p[i] == 0; i++);
2508
2509 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002510 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002511 i < file_buffer->size && file_buffer->data[i] == 0;
2512 i++);
plougher5b09fd42007-08-06 10:28:41 +00002513
2514 return i == file_buffer->size;
2515 }
2516
2517 return 0;
2518}
2519
2520
plougher5507dd92006-11-06 00:43:10 +00002521void *deflator(void *arg)
2522{
plougher7b8ee502009-07-29 07:54:30 +00002523 void *stream = NULL;
plougher5507dd92006-11-06 00:43:10 +00002524 int oldstate;
2525
2526 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2527 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2528
2529 while(1) {
2530 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002531 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002532
plougher1b899fc2008-08-07 01:24:06 +00002533 if(sparse_files && all_zero(file_buffer)) {
2534 file_buffer->c_byte = 0;
2535 queue_put(from_deflate, file_buffer);
2536 } else if(file_buffer->fragment) {
2537 file_buffer->c_byte = file_buffer->size;
2538 queue_put(from_deflate, file_buffer);
2539 } else {
2540 write_buffer = cache_get(writer_buffer, 0, 0);
plougher50b31762009-03-31 04:14:46 +00002541 write_buffer->c_byte = mangle2(&stream,
2542 write_buffer->data, file_buffer->data,
2543 file_buffer->size, block_size, noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002544 write_buffer->sequence = file_buffer->sequence;
2545 write_buffer->file_size = file_buffer->file_size;
2546 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002547 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2548 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002549 write_buffer->fragment = FALSE;
2550 write_buffer->error = FALSE;
2551 cache_block_put(file_buffer);
2552 queue_put(from_deflate, write_buffer);
2553 }
plougher5507dd92006-11-06 00:43:10 +00002554 }
2555}
2556
2557
2558void *frag_deflator(void *arg)
2559{
plougher7b8ee502009-07-29 07:54:30 +00002560 void *stream = NULL;
plougher5507dd92006-11-06 00:43:10 +00002561 int oldstate;
2562
2563 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2564 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2565
2566 while(1) {
2567 int c_byte, compressed_size;
2568 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002569 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002570 cache_get(writer_buffer, file_buffer->block +
2571 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002572
plougher110799c2009-03-30 01:50:40 +00002573 c_byte = mangle2(&stream, write_buffer->data, file_buffer->data,
2574 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002575 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002576 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002577 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002578 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002579 fragment_table[file_buffer->block].size = c_byte;
2580 fragment_table[file_buffer->block].start_block = bytes;
2581 write_buffer->block = bytes;
2582 bytes += compressed_size;
2583 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002584 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002585 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002586 TRACE("Writing fragment %lld, uncompressed size %d, "
2587 "compressed size %d\n", file_buffer->block,
2588 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002589 } else {
2590 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002591 add_pending_fragment(write_buffer, c_byte,
2592 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002593 }
ploughereb6eac92008-02-26 01:50:48 +00002594 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002595 }
2596}
2597
2598
2599#define HASH_ENTRIES 256
2600#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2601struct file_buffer *block_hash[HASH_ENTRIES];
2602
2603void push_buffer(struct file_buffer *file_buffer)
2604{
plougher0f464442008-03-31 00:27:56 +00002605 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002606
2607 file_buffer->next = block_hash[hash];
2608 block_hash[hash] = file_buffer;
2609}
2610
2611
2612struct file_buffer *get_file_buffer(struct queue *queue)
2613{
plougher0f464442008-03-31 00:27:56 +00002614 static unsigned int sequence = 0;
2615 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002616 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2617
2618 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002619 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002620 break;
2621
2622 if(file_buffer) {
2623 if(prev)
2624 prev->next = file_buffer->next;
2625 else
2626 block_hash[hash] = file_buffer->next;
2627 } else {
2628 while(1) {
2629 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002630 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002631 break;
2632 push_buffer(file_buffer);
2633 }
2634 }
2635
plougher0f464442008-03-31 00:27:56 +00002636 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002637
2638 return file_buffer;
2639}
2640
2641
plougher91fbb302008-05-06 02:29:36 +00002642void *progress_thrd(void *arg)
plougher35a10602008-04-21 02:58:16 +00002643{
2644 struct timeval timeval;
2645 struct timespec timespec;
2646 struct itimerval itimerval;
2647 struct winsize winsize;
2648
2649 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
plougher01b43282009-03-30 18:21:37 +00002650 if(isatty(STDOUT_FILENO))
2651 printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
2652 "columns\n");
plougher35a10602008-04-21 02:58:16 +00002653 columns = 80;
2654 } else
2655 columns = winsize.ws_col;
2656 signal(SIGWINCH, sigwinch_handler);
2657 signal(SIGALRM, sigalrm_handler);
2658
2659 itimerval.it_value.tv_sec = 0;
2660 itimerval.it_value.tv_usec = 250000;
2661 itimerval.it_interval.tv_sec = 0;
2662 itimerval.it_interval.tv_usec = 250000;
2663 setitimer(ITIMER_REAL, &itimerval, NULL);
2664
plougher35a10602008-04-21 02:58:16 +00002665 pthread_cond_init(&progress_wait, NULL);
2666
plougher91fbb302008-05-06 02:29:36 +00002667 pthread_mutex_lock(&progress_mutex);
2668
plougher35a10602008-04-21 02:58:16 +00002669 while(1) {
plougher35a10602008-04-21 02:58:16 +00002670 gettimeofday(&timeval, NULL);
2671 timespec.tv_sec = timeval.tv_sec;
2672 if(timeval.tv_usec + 250000 > 999999)
2673 timespec.tv_sec++;
plougher50b31762009-03-31 04:14:46 +00002674 timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
2675 1000;
2676 pthread_cond_timedwait(&progress_wait, &progress_mutex,
2677 &timespec);
plougher43bb7e92008-08-17 17:16:09 +00002678 if(progress_enabled && estimated_uncompressed)
plougher110799c2009-03-30 01:50:40 +00002679 progress_bar(cur_uncompressed, estimated_uncompressed,
2680 columns);
plougher35a10602008-04-21 02:58:16 +00002681 }
2682}
2683
2684
plougher91fbb302008-05-06 02:29:36 +00002685void enable_progress_bar()
2686{
2687 pthread_mutex_lock(&progress_mutex);
2688 progress_enabled = TRUE;
2689 pthread_mutex_unlock(&progress_mutex);
2690}
2691
2692
2693void disable_progress_bar()
2694{
2695 pthread_mutex_lock(&progress_mutex);
2696 progress_enabled = FALSE;
2697 pthread_mutex_unlock(&progress_mutex);
2698}
2699
2700
rloughere4873e02007-11-08 17:50:42 +00002701void progress_bar(long long current, long long max, int columns)
plougher02bc3bc2007-02-25 12:12:01 +00002702{
plougher35a10602008-04-21 02:58:16 +00002703 char rotate_list[] = { '|', '/', '-', '\\' };
plougherf3f95e42010-03-08 01:32:20 +00002704 int max_digits, used, hashes, spaces;
plougher898763d2009-03-29 22:54:55 +00002705 static int tty = -1;
plougher02bc3bc2007-02-25 12:12:01 +00002706
plougherf3f95e42010-03-08 01:32:20 +00002707 if(max == 0)
2708 return;
2709
2710 max_digits = floor(log10(max)) + 1;
2711 used = max_digits * 2 + 11;
2712 hashes = (current * (columns - used)) / max;
2713 spaces = columns - used - hashes;
2714
ploughere9e01392009-03-29 22:48:42 +00002715 if((current > max) || (columns - used < 0))
plougher02bc3bc2007-02-25 12:12:01 +00002716 return;
2717
plougher898763d2009-03-29 22:54:55 +00002718 if(tty == -1)
2719 tty = isatty(STDOUT_FILENO);
2720 if(!tty) {
2721 static long long previous = -1;
2722
2723 /* Updating much more frequently than this results in huge
2724 * log files. */
2725 if((current % 100) != 0 && current != max)
2726 return;
2727 /* Don't update just to rotate the spinner. */
2728 if(current == previous)
2729 return;
2730 previous = current;
2731 }
2732
plougher02bc3bc2007-02-25 12:12:01 +00002733 printf("\r[");
2734
2735 while (hashes --)
2736 putchar('=');
2737
plougher35a10602008-04-21 02:58:16 +00002738 putchar(rotate_list[rotate]);
2739
plougher02bc3bc2007-02-25 12:12:01 +00002740 while(spaces --)
2741 putchar(' ');
2742
2743 printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2744 printf(" %3lld%%", current * 100 / max);
2745 fflush(stdout);
2746}
2747
2748
plougher110799c2009-03-30 01:50:40 +00002749void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2750 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002751{
2752 file_count ++;
2753 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002754 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2755 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002756}
2757
2758
plougher50b31762009-03-31 04:14:46 +00002759void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2760 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002761 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002762{
plougher5507dd92006-11-06 00:43:10 +00002763 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002764 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002765 unsigned int *block_listp = NULL;
2766 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002767
plougher50b31762009-03-31 04:14:46 +00002768 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2769 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002770
plougher5507dd92006-11-06 00:43:10 +00002771 if(dupl_ptr) {
2772 *duplicate_file = FALSE;
2773 fragment = get_and_fill_fragment(file_buffer);
2774 dupl_ptr->fragment = fragment;
2775 } else
2776 *duplicate_file = TRUE;
2777
ploughereb6eac92008-02-26 01:50:48 +00002778 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002779
2780 total_bytes += size;
2781 file_count ++;
2782
plougher35a10602008-04-21 02:58:16 +00002783 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002784
plougherc1ace522010-05-01 03:00:45 +00002785 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002786 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002787}
2788
2789
plougher110799c2009-03-30 01:50:40 +00002790void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2791 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002792{
2793 struct fragment *fragment;
2794 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002795
2796 checksum = get_checksum_mem_buffer(file_buffer);
2797
plougher29e37092007-04-15 01:24:51 +00002798 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002799 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2800 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002801 return;
2802 }
plougher5507dd92006-11-06 00:43:10 +00002803
2804 fragment = get_and_fill_fragment(file_buffer);
2805
ploughereb6eac92008-02-26 01:50:48 +00002806 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002807
2808 if(duplicate_checking)
2809 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2810
2811 total_bytes += size;
2812 file_count ++;
2813
2814 *duplicate_file = FALSE;
2815
plougher35a10602008-04-21 02:58:16 +00002816 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002817
plougherc1ace522010-05-01 03:00:45 +00002818 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002819 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002820
plougher018d2b32007-04-23 03:01:48 +00002821 return;
plougher5507dd92006-11-06 00:43:10 +00002822}
2823
2824
plougher00d08172009-09-03 10:17:44 +00002825int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2826 struct file_buffer *read_buffer, int *duplicate_file)
2827{
2828 long long read_size, file_bytes, start;
2829 struct fragment *fragment;
2830 unsigned int *block_list = NULL;
2831 int block = 0, status;
2832 long long sparse = 0;
2833 struct file_buffer *fragment_buffer = NULL;
2834
2835 *duplicate_file = FALSE;
2836
2837 lock_fragments();
2838
2839 file_bytes = 0;
2840 start = bytes;
2841 while (1) {
2842 read_size = read_buffer->file_size;
2843 if(read_buffer->fragment && read_buffer->c_byte)
2844 fragment_buffer = read_buffer;
2845 else {
2846 block_list = realloc(block_list, (block + 1) *
2847 sizeof(unsigned int));
2848 if(block_list == NULL)
2849 BAD_ERROR("Out of memory allocating block_list"
2850 "\n");
2851 block_list[block ++] = read_buffer->c_byte;
2852 if(read_buffer->c_byte) {
2853 read_buffer->block = bytes;
2854 bytes += read_buffer->size;
2855 cache_rehash(read_buffer, read_buffer->block);
2856 file_bytes += read_buffer->size;
2857 queue_put(to_writer, read_buffer);
2858 } else {
2859 sparse += read_buffer->size;
2860 cache_block_put(read_buffer);
2861 }
2862 }
plougher286b6b32009-09-19 03:29:27 +00002863 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002864
2865 if(read_size != -1)
2866 break;
2867
2868 read_buffer = get_file_buffer(from_deflate);
2869 if(read_buffer->error)
2870 goto read_err;
2871 }
2872
2873 unlock_fragments();
2874 fragment = get_and_fill_fragment(fragment_buffer);
2875 cache_block_put(fragment_buffer);
2876
2877 if(duplicate_checking)
2878 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2879 0, 0, FALSE);
2880 file_count ++;
2881 total_bytes += read_size;
2882
plougherc1ace522010-05-01 03:00:45 +00002883 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2884 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002885
2886 if(duplicate_checking == FALSE)
2887 free(block_list);
2888
2889 return 0;
2890
2891read_err:
plougher286b6b32009-09-19 03:29:27 +00002892 cur_uncompressed -= block;
plougher00d08172009-09-03 10:17:44 +00002893 status = read_buffer->error;
2894 bytes = start;
2895 if(!block_device) {
2896 int res;
2897
2898 queue_put(to_writer, NULL);
2899 if(queue_get(from_writer) != 0)
2900 EXIT_MKSQUASHFS();
2901 res = ftruncate(fd, bytes);
2902 if(res != 0)
2903 BAD_ERROR("Failed to truncate dest file because %s\n",
2904 strerror(errno));
2905 }
2906 unlock_fragments();
2907 free(block_list);
2908 cache_block_put(read_buffer);
2909 return status;
2910}
2911
2912
plougher110799c2009-03-30 01:50:40 +00002913int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002914 long long read_size, struct file_buffer *read_buffer,
2915 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002916{
plougher23377982007-11-12 04:04:48 +00002917 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002918 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002919 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002920 int block, status;
2921 int blocks = (read_size + block_size - 1) >> block_log;
2922 long long sparse = 0;
2923 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002924
plougher29e37092007-04-15 01:24:51 +00002925 *duplicate_file = FALSE;
2926
plougher5507dd92006-11-06 00:43:10 +00002927 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
2928 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002929
plougher2ea89142008-03-11 01:34:19 +00002930 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002931
plougher5507dd92006-11-06 00:43:10 +00002932 file_bytes = 0;
2933 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002934 for(block = 0; block < blocks;) {
2935 if(read_buffer->fragment && read_buffer->c_byte) {
2936 fragment_buffer = read_buffer;
2937 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002938 } else {
plougher1b899fc2008-08-07 01:24:06 +00002939 block_list[block] = read_buffer->c_byte;
2940 if(read_buffer->c_byte) {
2941 read_buffer->block = bytes;
2942 bytes += read_buffer->size;
2943 cache_rehash(read_buffer, read_buffer->block);
2944 file_bytes += read_buffer->size;
2945 queue_put(to_writer, read_buffer);
2946 } else {
2947 sparse += read_buffer->size;
2948 cache_block_put(read_buffer);
2949 }
2950 }
2951 inc_progress_bar();
2952
2953 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002954 read_buffer = get_file_buffer(from_deflate);
2955 if(read_buffer->error)
2956 goto read_err;
2957 }
plougher1f413c82005-11-18 00:02:14 +00002958 }
2959
plougher2ea89142008-03-11 01:34:19 +00002960 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00002961 fragment = get_and_fill_fragment(fragment_buffer);
2962 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002963
plougher1f413c82005-11-18 00:02:14 +00002964 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00002965 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2966 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002967 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002968 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002969
plougher360514a2009-03-30 03:01:38 +00002970 /*
2971 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002972 * a smaller block count on stat calls to sparse files. This is
2973 * to ensure intelligent applications like cp correctly handle the
2974 * file as a sparse file. If the file in the original filesystem isn't
2975 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002976 * report it as non-sparse on stat calls to preserve semantics
2977 */
plougher1b899fc2008-08-07 01:24:06 +00002978 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2979 sparse = 0;
2980
plougherc1ace522010-05-01 03:00:45 +00002981 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2982 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002983
plougher5507dd92006-11-06 00:43:10 +00002984 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002985 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002986
plougher018d2b32007-04-23 03:01:48 +00002987 return 0;
plougher1f413c82005-11-18 00:02:14 +00002988
2989read_err:
plougher018d2b32007-04-23 03:01:48 +00002990 cur_uncompressed -= block;
2991 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002992 bytes = start;
2993 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00002994 int res;
2995
plougher5507dd92006-11-06 00:43:10 +00002996 queue_put(to_writer, NULL);
2997 if(queue_get(from_writer) != 0)
2998 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00002999 res = ftruncate(fd, bytes);
3000 if(res != 0)
3001 BAD_ERROR("Failed to truncate dest file because %s\n",
3002 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003003 }
plougher2ea89142008-03-11 01:34:19 +00003004 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003005 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003006 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003007 return status;
plougher1f413c82005-11-18 00:02:14 +00003008}
3009
3010
plougher110799c2009-03-30 01:50:40 +00003011int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003012 long long read_size, struct file_buffer *read_buffer,
3013 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003014{
plougher29e37092007-04-15 01:24:51 +00003015 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003016 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003017 struct fragment *fragment;
3018 struct file_info *dupl_ptr;
3019 int blocks = (read_size + block_size - 1) >> block_log;
3020 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003021 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003022 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003023 long long sparse = 0;
3024 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003025
plougher50b31762009-03-31 04:14:46 +00003026 block_list = malloc(blocks * sizeof(unsigned int));
3027 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003028 BAD_ERROR("Out of memory allocating block_list\n");
3029 block_listp = block_list;
3030
plougher50b31762009-03-31 04:14:46 +00003031 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3032 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003033 BAD_ERROR("Out of memory allocating file block list\n");
3034
plougher4e8484a2008-03-15 23:30:16 +00003035 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003036
3037 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003038 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003039 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3040 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003041
3042 for(block = 0; block < blocks;) {
3043 if(read_buffer->fragment && read_buffer->c_byte) {
3044 fragment_buffer = read_buffer;
3045 blocks = read_size >> block_log;
3046 } else {
3047 block_list[block] = read_buffer->c_byte;
3048
3049 if(read_buffer->c_byte) {
3050 read_buffer->block = bytes;
3051 bytes += read_buffer->size;
3052 file_bytes += read_buffer->size;
3053 cache_rehash(read_buffer, read_buffer->block);
3054 if(block < thresh) {
3055 buffer_list[block] = NULL;
3056 queue_put(to_writer, read_buffer);
3057 } else
3058 buffer_list[block] = read_buffer;
3059 } else {
3060 buffer_list[block] = NULL;
3061 sparse += read_buffer->size;
3062 cache_block_put(read_buffer);
3063 }
3064 }
3065 inc_progress_bar();
3066
3067 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003068 read_buffer = get_file_buffer(from_deflate);
3069 if(read_buffer->error)
3070 goto read_err;
3071 }
plougher5507dd92006-11-06 00:43:10 +00003072 }
3073
plougher110799c2009-03-30 01:50:40 +00003074 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3075 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003076
3077 if(dupl_ptr) {
3078 *duplicate_file = FALSE;
3079 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003080 if(buffer_list[block])
3081 queue_put(to_writer, buffer_list[block]);
3082 fragment = get_and_fill_fragment(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003083 dupl_ptr->fragment = fragment;
3084 } else {
3085 *duplicate_file = TRUE;
3086 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003087 cache_block_put(buffer_list[block]);
3088 bytes = start;
3089 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003090 int res;
3091
plougher1b899fc2008-08-07 01:24:06 +00003092 queue_put(to_writer, NULL);
3093 if(queue_get(from_writer) != 0)
3094 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003095 res = ftruncate(fd, bytes);
3096 if(res != 0)
3097 BAD_ERROR("Failed to truncate dest file because"
3098 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003099 }
plougher5507dd92006-11-06 00:43:10 +00003100 }
3101
plougher2ea89142008-03-11 01:34:19 +00003102 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003103 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003104 free(buffer_list);
3105 file_count ++;
3106 total_bytes += read_size;
3107
plougher360514a2009-03-30 03:01:38 +00003108 /*
3109 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003110 * a smaller block count on stat calls to sparse files. This is
3111 * to ensure intelligent applications like cp correctly handle the
3112 * file as a sparse file. If the file in the original filesystem isn't
3113 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003114 * report it as non-sparse on stat calls to preserve semantics
3115 */
plougher1b899fc2008-08-07 01:24:06 +00003116 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3117 sparse = 0;
3118
plougherc1ace522010-05-01 03:00:45 +00003119 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3120 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003121
plougher5507dd92006-11-06 00:43:10 +00003122 if(*duplicate_file == TRUE)
3123 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003124
plougher018d2b32007-04-23 03:01:48 +00003125 return 0;
plougher5507dd92006-11-06 00:43:10 +00003126
3127read_err:
plougher018d2b32007-04-23 03:01:48 +00003128 cur_uncompressed -= block;
3129 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003130 bytes = start;
3131 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003132 int res;
3133
plougher5507dd92006-11-06 00:43:10 +00003134 queue_put(to_writer, NULL);
3135 if(queue_get(from_writer) != 0)
3136 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003137 res = ftruncate(fd, bytes);
3138 if(res != 0)
3139 BAD_ERROR("Failed to truncate dest file because %s\n",
3140 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003141 }
plougher2ea89142008-03-11 01:34:19 +00003142 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003143 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003144 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003145 free(buffer_list);
3146 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003147 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003148 return status;
plougher5507dd92006-11-06 00:43:10 +00003149}
3150
3151
plougher110799c2009-03-30 01:50:40 +00003152void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3153 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003154{
plougher018d2b32007-04-23 03:01:48 +00003155 int status;
3156 struct file_buffer *read_buffer;
3157 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003158
plougher018d2b32007-04-23 03:01:48 +00003159again:
3160 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003161
plougher23377982007-11-12 04:04:48 +00003162 status = read_buffer->error;
3163 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003164 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003165 goto file_err;
3166 }
3167
3168 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003169
plougher00d08172009-09-03 10:17:44 +00003170 if(read_size == -1)
3171 status = write_file_process(inode, dir_ent, read_buffer,
3172 duplicate_file);
3173 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003174 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003175 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003176 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003177 write_file_frag(inode, dir_ent, read_size, read_buffer,
3178 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003179 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003180 status = write_file_blocks_dup(inode, dir_ent, read_size,
3181 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003182 else
plougher50b31762009-03-31 04:14:46 +00003183 status = write_file_blocks(inode, dir_ent, read_size,
3184 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003185
plougher018d2b32007-04-23 03:01:48 +00003186file_err:
3187 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003188 ERROR("File %s changed size while reading filesystem, "
3189 "attempting to re-read\n", dir_ent->pathname);
plougher018d2b32007-04-23 03:01:48 +00003190 goto again;
3191 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003192 ERROR("Failed to read file %s, creating empty file\n",
3193 dir_ent->pathname);
plougher29e37092007-04-15 01:24:51 +00003194 write_file_empty(inode, dir_ent, duplicate_file);
3195 }
plougher5507dd92006-11-06 00:43:10 +00003196}
3197
3198
plougher44d54ef2010-02-08 22:13:49 +00003199#define BUFF_SIZE 8192
3200char b_buffer[BUFF_SIZE];
plougher1f413c82005-11-18 00:02:14 +00003201char *name;
3202char *basename_r();
3203
3204char *getbase(char *pathname)
3205{
3206 char *result;
3207
3208 if(*pathname != '/') {
plougher44d54ef2010-02-08 22:13:49 +00003209 result = getcwd(b_buffer, BUFF_SIZE);
3210 if(result == NULL)
3211 return NULL;
3212 strcat(strcat(b_buffer, "/"), pathname);
plougher1f413c82005-11-18 00:02:14 +00003213 } else
3214 strcpy(b_buffer, pathname);
3215 name = b_buffer;
3216 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3217 return NULL;
3218 else
3219 return result;
3220}
3221
3222
3223char *basename_r()
3224{
3225 char *s;
3226 char *p;
3227 int n = 1;
3228
3229 for(;;) {
3230 s = name;
3231 if(*name == '\0')
3232 return NULL;
3233 if(*name != '/') {
3234 while(*name != '\0' && *name != '/') name++;
3235 n = name - s;
3236 }
3237 while(*name == '/') name++;
3238 if(strncmp(s, ".", n) == 0)
3239 continue;
plougher110799c2009-03-30 01:50:40 +00003240 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3241 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003242 s[n] = '\0';
3243 return s;
3244 }
3245 if(strcmp(p, "..") == 0)
3246 continue;
3247 return p;
3248 }
3249}
3250
3251
3252struct inode_info *lookup_inode(struct stat *buf)
3253{
3254 int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3255 struct inode_info *inode = inode_info[inode_hash];
3256
3257 while(inode != NULL) {
3258 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3259 inode->nlink ++;
3260 return inode;
3261 }
3262 inode = inode->next;
3263 }
3264
3265 if((inode = malloc(sizeof(struct inode_info))) == NULL)
plougher50b31762009-03-31 04:14:46 +00003266 BAD_ERROR("Out of memory in inode hash table entry allocation"
3267 "\n");
plougher1f413c82005-11-18 00:02:14 +00003268
3269 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003270 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003271 inode->root_entry = FALSE;
plougher00d08172009-09-03 10:17:44 +00003272 inode->pseudo_file = FALSE;
plougher1f413c82005-11-18 00:02:14 +00003273 inode->inode = SQUASHFS_INVALID_BLK;
3274 inode->nlink = 1;
plougherdc86c3c2007-12-05 02:15:10 +00003275
3276 if((buf->st_mode & S_IFMT) == S_IFREG)
plougher110799c2009-03-30 01:50:40 +00003277 estimated_uncompressed += (buf->st_size + block_size - 1) >>
3278 block_log;
plougherdc86c3c2007-12-05 02:15:10 +00003279
plougher1f413c82005-11-18 00:02:14 +00003280 if((buf->st_mode & S_IFMT) == S_IFDIR)
3281 inode->inode_number = dir_inode_no ++;
3282 else
3283 inode->inode_number = inode_no ++;
3284
3285 inode->next = inode_info[inode_hash];
3286 inode_info[inode_hash] = inode;
3287
3288 return inode;
3289}
3290
3291
plougher110799c2009-03-30 01:50:40 +00003292inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
ploughera326c182009-08-29 05:41:45 +00003293 struct inode_info *inode_info, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003294{
plougher110799c2009-03-30 01:50:40 +00003295 if((dir->count % DIR_ENTRIES) == 0) {
3296 dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) *
3297 sizeof(struct dir_ent *));
3298 if(dir->list == NULL)
plougher1f413c82005-11-18 00:02:14 +00003299 BAD_ERROR("Out of memory in add_dir_entry\n");
plougher110799c2009-03-30 01:50:40 +00003300 }
plougher1f413c82005-11-18 00:02:14 +00003301
3302 if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL)
3303 BAD_ERROR("Out of memory in linux_opendir\n");
3304
3305 if(sub_dir)
3306 sub_dir->dir_ent = dir->list[dir->count];
3307 dir->list[dir->count]->name = strdup(name);
plougher110799c2009-03-30 01:50:40 +00003308 dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) :
3309 NULL;
plougher1f413c82005-11-18 00:02:14 +00003310 dir->list[dir->count]->inode = inode_info;
3311 dir->list[dir->count]->dir = sub_dir;
ploughera326c182009-08-29 05:41:45 +00003312 dir->list[dir->count++]->our_dir = dir;
plougher1f413c82005-11-18 00:02:14 +00003313 dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
3314}
3315
3316
3317int compare_name(const void *ent1_ptr, const void *ent2_ptr)
3318{
3319 struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
3320 struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
3321
3322 return strcmp(ent1->name, ent2->name);
3323}
3324
3325
3326void sort_directory(struct dir_info *dir)
3327{
3328 qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
3329
3330 if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
3331 dir->dir_is_ldir = FALSE;
3332}
3333
3334
3335struct dir_info *scan1_opendir(char *pathname)
3336{
plougher1f413c82005-11-18 00:02:14 +00003337 struct dir_info *dir;
3338
3339 if((dir = malloc(sizeof(struct dir_info))) == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003340 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003341
3342 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3343 free(dir);
3344 return NULL;
3345 }
3346 dir->pathname = strdup(pathname);
plougher360514a2009-03-30 03:01:38 +00003347 dir->count = dir->directory_count = dir->current_count = dir->byte_count
3348 = 0;
plougher1f413c82005-11-18 00:02:14 +00003349 dir->dir_is_ldir = TRUE;
3350 dir->list = NULL;
3351
3352 return dir;
3353}
3354
3355
3356int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3357{
3358 int i, n, pass;
3359 char *basename;
3360 static int index = 0;
3361
3362 if(dir->count < old_root_entries)
3363 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003364 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003365 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003366 add_dir_entry(old_root_entry[i].name, "", NULL,
3367 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003368 }
3369
3370 while(index < source) {
3371 if((basename = getbase(source_path[index])) == NULL) {
plougher110799c2009-03-30 01:50:40 +00003372 ERROR("Bad source directory %s - skipping ...\n",
3373 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003374 index ++;
3375 continue;
3376 }
3377 strcpy(dir_name, basename);
3378 pass = 1;
3379 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003380 for(n = 0; n < dir->count &&
3381 strcmp(dir->list[n]->name, dir_name) != 0; n++);
plougher1f413c82005-11-18 00:02:14 +00003382 if(n == dir->count)
3383 break;
plougher50b31762009-03-31 04:14:46 +00003384 ERROR("Source directory entry %s already used! - trying"
3385 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003386 sprintf(dir_name, "%s_%d", basename, pass++);
3387 ERROR("%s\n", dir_name);
3388 }
3389 strcpy(pathname, source_path[index ++]);
3390 return 1;
3391 }
3392 return 0;
3393}
3394
3395
3396int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3397{
3398 struct dirent *d_name;
3399 int i, pass;
3400
3401 if(dir->count < old_root_entries)
3402 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003403 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003404 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003405 add_dir_entry(old_root_entry[i].name, "", NULL,
3406 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003407 }
3408
3409 if((d_name = readdir(dir->linuxdir)) != NULL) {
3410 strcpy(dir_name, d_name->d_name);
3411 pass = 1;
3412 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003413 for(i = 0; i < dir->count &&
3414 strcmp(dir->list[i]->name, dir_name) != 0; i++);
plougher1f413c82005-11-18 00:02:14 +00003415 if(i == dir->count)
3416 break;
plougher50b31762009-03-31 04:14:46 +00003417 ERROR("Source directory entry %s already used! - trying"
3418 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003419 sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
3420 ERROR("%s\n", dir_name);
3421 }
plougher110799c2009-03-30 01:50:40 +00003422 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3423 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003424 return 1;
3425 }
3426
3427 return 0;
3428}
3429
3430
3431int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3432{
3433 struct dirent *d_name;
3434
3435 if((d_name = readdir(dir->linuxdir)) != NULL) {
3436 strcpy(dir_name, d_name->d_name);
plougher110799c2009-03-30 01:50:40 +00003437 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3438 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003439 return 1;
3440 }
3441
3442 return 0;
3443}
3444
3445
plougher43244f22009-04-05 02:04:51 +00003446struct dir_ent *scan2_readdir(struct dir_info *dir_info)
3447{
3448 int current_count;
3449
3450 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003451 if(dir_info->list[current_count]->inode->root_entry)
plougher43244f22009-04-05 02:04:51 +00003452 continue;
3453 else
3454 return dir_info->list[current_count];
3455 return NULL;
3456}
3457
3458
3459struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3460{
3461 int i;
3462
3463 for(i = 0; i < dir->count; i++)
3464 if(strcmp(dir->list[i]->name, name) == 0)
3465 return dir->list[i];
3466
3467 return NULL;
3468}
3469
3470
3471struct dir_ent *scan3_readdir(struct directory *dir, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003472{
3473 int current_count;
3474
3475 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003476 if(dir_info->list[current_count]->inode->root_entry)
3477 add_dir(dir_info->list[current_count]->inode->inode,
3478 dir_info->list[current_count]->inode->inode_number,
plougher110799c2009-03-30 01:50:40 +00003479 dir_info->list[current_count]->name,
ploughera326c182009-08-29 05:41:45 +00003480 dir_info->list[current_count]->inode->type, dir);
plougher1f413c82005-11-18 00:02:14 +00003481 else
3482 return dir_info->list[current_count];
plougher43244f22009-04-05 02:04:51 +00003483 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003484}
3485
3486
3487void scan1_freedir(struct dir_info *dir)
3488{
plougherfbed12b2006-02-07 12:45:53 +00003489 if(dir->pathname[0] != '\0')
3490 closedir(dir->linuxdir);
plougherb087fc12010-05-01 04:53:28 +00003491 free(dir->pathname);
3492 dir->pathname = NULL;
plougher1f413c82005-11-18 00:02:14 +00003493}
3494
3495
plougher43244f22009-04-05 02:04:51 +00003496void scan2_freedir(struct dir_info *dir)
3497{
3498 dir->current_count = 0;
plougherb087fc12010-05-01 04:53:28 +00003499 if(dir->pathname) {
3500 free(dir->pathname);
3501 dir->pathname = NULL;
3502 }
plougher43244f22009-04-05 02:04:51 +00003503}
3504
3505
3506void scan3_freedir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00003507{
3508 if(dir->index)
3509 free(dir->index);
3510 free(dir->buff);
3511}
3512
3513
plougher110799c2009-03-30 01:50:40 +00003514void dir_scan(squashfs_inode *inode, char *pathname,
3515 int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00003516{
plougher0e453652006-11-06 01:49:35 +00003517 struct stat buf;
plougher8f8e1a12007-10-18 02:50:21 +00003518 struct dir_info *dir_info = dir_scan1(pathname, paths, _readdir);
plougher1f413c82005-11-18 00:02:14 +00003519 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003520
3521 if(dir_info == NULL)
3522 return;
3523
plougher43244f22009-04-05 02:04:51 +00003524 dir_scan2(dir_info, pseudo);
3525
plougher1f413c82005-11-18 00:02:14 +00003526 if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL)
3527 BAD_ERROR("Out of memory in dir_scan\n");
3528
plougher1f413c82005-11-18 00:02:14 +00003529 if(pathname[0] == '\0') {
plougher110799c2009-03-30 01:50:40 +00003530 /*
3531 *dummy top level directory, if multiple sources specified on
3532 * command line
3533 */
plougher43244f22009-04-05 02:04:51 +00003534 memset(&buf, 0, sizeof(buf));
plougher0e453652006-11-06 01:49:35 +00003535 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3536 buf.st_uid = getuid();
3537 buf.st_gid = getgid();
3538 buf.st_mtime = time(NULL);
3539 buf.st_dev = 0;
3540 buf.st_ino = 0;
3541 } else if(lstat(pathname, &buf) == -1) {
plougher110799c2009-03-30 01:50:40 +00003542 ERROR("Cannot stat dir/file %s because %s, ignoring", pathname,
3543 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003544 return;
3545 }
plougher0e453652006-11-06 01:49:35 +00003546
3547 dir_ent->inode = lookup_inode(&buf);
3548 if(root_inode_number) {
3549 dir_ent->inode->inode_number = root_inode_number;
3550 dir_inode_no --;
3551 }
3552 dir_ent->name = dir_ent->pathname = strdup(pathname);
3553 dir_ent->dir = dir_info;
3554 dir_ent->our_dir = NULL;
plougher0e453652006-11-06 01:49:35 +00003555 dir_info->dir_ent = dir_ent;
3556
plougher1d1c6bb2010-07-21 03:03:13 +00003557 if(sorted) {
3558 int res = generate_file_priorities(dir_info, 0,
plougher110799c2009-03-30 01:50:40 +00003559 &dir_info->dir_ent->inode->buf);
plougher1d1c6bb2010-07-21 03:03:13 +00003560
3561 if(res == FALSE)
3562 BAD_ERROR("generate_file_priorities failed\n");
3563 }
plougher5507dd92006-11-06 00:43:10 +00003564 queue_put(to_reader, dir_info);
3565 if(sorted)
plougher117b2ea2006-02-09 09:23:56 +00003566 sort_files_and_write(dir_info);
plougher91fbb302008-05-06 02:29:36 +00003567 if(progress)
3568 enable_progress_bar();
plougher43244f22009-04-05 02:04:51 +00003569 dir_scan3(inode, dir_info);
plougher0e453652006-11-06 01:49:35 +00003570 dir_ent->inode->inode = *inode;
3571 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003572}
3573
3574
plougher110799c2009-03-30 01:50:40 +00003575struct dir_info *dir_scan1(char *pathname, struct pathnames *paths,
3576 int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00003577{
3578 struct dir_info *dir, *sub_dir;
3579 struct stat buf;
3580 char filename[8192], dir_name[8192];
plougherf9039c92007-10-22 03:54:16 +00003581 struct pathnames *new;
plougher1f413c82005-11-18 00:02:14 +00003582
3583 if((dir = scan1_opendir(pathname)) == NULL) {
3584 ERROR("Could not open %s, skipping...\n", pathname);
3585 goto error;
3586 }
3587
3588 while(_readdir(filename, dir_name, dir) != FALSE) {
3589
3590 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
3591 continue;
3592
3593 if(lstat(filename, &buf) == -1) {
plougher110799c2009-03-30 01:50:40 +00003594 ERROR("Cannot stat dir/file %s because %s, ignoring",
3595 filename, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003596 continue;
3597 }
plougher29e37092007-04-15 01:24:51 +00003598
3599 if((buf.st_mode & S_IFMT) != S_IFREG &&
3600 (buf.st_mode & S_IFMT) != S_IFDIR &&
3601 (buf.st_mode & S_IFMT) != S_IFLNK &&
3602 (buf.st_mode & S_IFMT) != S_IFCHR &&
3603 (buf.st_mode & S_IFMT) != S_IFBLK &&
3604 (buf.st_mode & S_IFMT) != S_IFIFO &&
3605 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003606 ERROR("File %s has unrecognised filetype %d, ignoring"
3607 "\n", filename, buf.st_mode & S_IFMT);
plougher29e37092007-04-15 01:24:51 +00003608 continue;
3609 }
3610
plougher8f8e1a12007-10-18 02:50:21 +00003611 if(old_exclude) {
3612 if(old_excluded(filename, &buf))
3613 continue;
3614 } else {
3615 if(excluded(paths, dir_name, &new))
3616 continue;
3617 }
plougher1f413c82005-11-18 00:02:14 +00003618
3619 if((buf.st_mode & S_IFMT) == S_IFDIR) {
plougher110799c2009-03-30 01:50:40 +00003620 sub_dir = dir_scan1(filename, new, scan1_readdir);
3621 if(sub_dir == NULL)
plougher1f413c82005-11-18 00:02:14 +00003622 continue;
3623 dir->directory_count ++;
3624 } else
3625 sub_dir = NULL;
3626
plougher110799c2009-03-30 01:50:40 +00003627 add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf),
ploughera326c182009-08-29 05:41:45 +00003628 dir);
plougher1f413c82005-11-18 00:02:14 +00003629 }
3630
3631 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003632
3633error:
3634 return dir;
3635}
3636
plougher2ea89142008-03-11 01:34:19 +00003637
plougher43244f22009-04-05 02:04:51 +00003638struct dir_info *dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
3639{
3640 struct dir_info *sub_dir;
3641 struct dir_ent *dir_ent;
3642 struct pseudo_entry *pseudo_ent;
3643 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003644 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003645
3646 if(dir == NULL && (dir = scan1_opendir("")) == NULL)
3647 return NULL;
3648
3649 while((dir_ent = scan2_readdir(dir)) != NULL) {
3650 struct inode_info *inode_info = dir_ent->inode;
3651 struct stat *buf = &inode_info->buf;
3652 char *name = dir_ent->name;
3653
3654 if((buf->st_mode & S_IFMT) == S_IFDIR)
3655 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
3656 }
3657
3658 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3659 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherb34f9f62009-04-26 02:08:42 +00003660 if(pseudo_ent->dev->type == 's') {
3661 struct stat *buf;
3662 if(dir_ent == NULL) {
3663 ERROR("Pseudo set file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003664 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003665 pseudo_ent->pathname);
3666 continue;
3667 }
ploughera326c182009-08-29 05:41:45 +00003668 if(dir_ent->inode->root_entry) {
plougherb34f9f62009-04-26 02:08:42 +00003669 ERROR("Pseudo set file \"%s\" is a pre-existing"
3670 " file in the filesystem being appended"
3671 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003672 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003673 continue;
3674 }
3675 buf = &dir_ent->inode->buf;
3676 buf->st_mode = (buf->st_mode & S_IFMT) |
3677 pseudo_ent->dev->mode;
3678 buf->st_uid = pseudo_ent->dev->uid;
3679 buf->st_gid = pseudo_ent->dev->gid;
3680 continue;
3681 }
3682
plougher43244f22009-04-05 02:04:51 +00003683 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003684 if(dir_ent->inode->root_entry)
3685 ERROR("Pseudo file \"%s\" is a pre-existing"
3686 " file in the filesystem being appended"
3687 " to. Ignoring.\n",
3688 pseudo_ent->pathname);
3689 else
3690 ERROR("Pseudo file \"%s\" exists in source "
3691 "filesystem \"%s\"\n. Ignoring, "
3692 "exclude it (-e/-ef) to override.\n",
3693 pseudo_ent->pathname,
3694 dir_ent->pathname);
plougher43244f22009-04-05 02:04:51 +00003695 continue;
3696 }
3697
3698 if(pseudo_ent->dev->type == 'd') {
3699 sub_dir = dir_scan2(NULL, pseudo_ent->pseudo);
3700 if(sub_dir == NULL) {
3701 ERROR("Could not create pseudo directory \"%s\""
3702 ", skipping...\n",
3703 pseudo_ent->pathname);
3704 continue;
3705 }
3706 dir->directory_count ++;
3707 } else
3708 sub_dir = NULL;
3709
3710 memset(&buf, 0, sizeof(buf));
3711 buf.st_mode = pseudo_ent->dev->mode;
3712 buf.st_uid = pseudo_ent->dev->uid;
3713 buf.st_gid = pseudo_ent->dev->gid;
3714 buf.st_rdev = makedev(pseudo_ent->dev->major,
3715 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003716 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003717 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003718
plougher4ab7e512009-05-05 02:35:58 +00003719 if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003720#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003721 struct stat buf2;
3722 int res = stat(pseudo_ent->dev->filename, &buf2);
plougherb85e9ad2010-05-02 01:46:12 +00003723 struct inode_info *inode;
plougher4ab7e512009-05-05 02:35:58 +00003724 if(res == -1) {
3725 ERROR("Stat on pseudo file \"%s\" failed, "
3726 "skipping...", pseudo_ent->pathname);
3727 continue;
3728 }
3729 buf.st_size = buf2.st_size;
plougherb85e9ad2010-05-02 01:46:12 +00003730 inode = lookup_inode(&buf);
3731 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003732 add_dir_entry(pseudo_ent->name,
plougherb85e9ad2010-05-02 01:46:12 +00003733 pseudo_ent->dev->filename, sub_dir, inode,
3734 dir);
plougher00d08172009-09-03 10:17:44 +00003735#else
3736 struct inode_info *inode = lookup_inode(&buf);
plougherba674e82009-09-10 03:50:00 +00003737 inode->pseudo_id = pseudo_ent->dev->pseudo_id;
plougherb85e9ad2010-05-02 01:46:12 +00003738 inode->pseudo_file = PSEUDO_FILE_PROCESS;
plougher00d08172009-09-03 10:17:44 +00003739 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
3740 sub_dir, inode, dir);
3741#endif
plougherb85e9ad2010-05-02 01:46:12 +00003742 } else {
3743 struct inode_info *inode = lookup_inode(&buf);
3744 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003745 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
plougherb85e9ad2010-05-02 01:46:12 +00003746 sub_dir, inode, dir);
3747 }
plougher43244f22009-04-05 02:04:51 +00003748 }
3749
3750 scan2_freedir(dir);
3751 sort_directory(dir);
3752
3753 return dir;
3754}
3755
3756
3757void dir_scan3(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003758{
3759 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00003760 int duplicate_file;
ploughere4e92092010-05-01 04:51:50 +00003761 char *pathname = dir_info->dir_ent->pathname;
plougher1f413c82005-11-18 00:02:14 +00003762 struct directory dir;
3763 struct dir_ent *dir_ent;
3764
plougher43244f22009-04-05 02:04:51 +00003765 scan3_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003766
plougher43244f22009-04-05 02:04:51 +00003767 while((dir_ent = scan3_readdir(&dir, dir_info)) != NULL) {
plougher1f413c82005-11-18 00:02:14 +00003768 struct inode_info *inode_info = dir_ent->inode;
3769 struct stat *buf = &inode_info->buf;
3770 char *filename = dir_ent->pathname;
3771 char *dir_name = dir_ent->name;
plougher50b31762009-03-31 04:14:46 +00003772 unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR)
3773 ? dir_ent->inode->inode_number :
plougher110799c2009-03-30 01:50:40 +00003774 dir_ent->inode->inode_number + dir_inode_no;
plougher1f413c82005-11-18 00:02:14 +00003775
3776 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3777 switch(buf->st_mode & S_IFMT) {
3778 case S_IFREG:
3779 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00003780 write_file(inode, dir_ent,
3781 &duplicate_file);
3782 INFO("file %s, uncompressed size %lld "
3783 "bytes %s\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003784 (long long) buf->st_size,
3785 duplicate_file ? "DUPLICATE" :
3786 "");
plougher1f413c82005-11-18 00:02:14 +00003787 break;
3788
3789 case S_IFDIR:
3790 squashfs_type = SQUASHFS_DIR_TYPE;
plougher43244f22009-04-05 02:04:51 +00003791 dir_scan3(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003792 break;
3793
3794 case S_IFLNK:
3795 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003796 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003797 squashfs_type, 0, 0, 0, NULL,
3798 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003799 INFO("symbolic link %s inode 0x%llx\n",
3800 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003801 sym_count ++;
3802 break;
3803
3804 case S_IFCHR:
3805 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003806 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003807 squashfs_type, 0, 0, 0, NULL,
3808 NULL, NULL, 0);
3809 INFO("character device %s inode 0x%llx"
3810 "\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003811 dev_count ++;
3812 break;
3813
3814 case S_IFBLK:
3815 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003816 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003817 squashfs_type, 0, 0, 0, NULL,
3818 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003819 INFO("block device %s inode 0x%llx\n",
3820 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003821 dev_count ++;
3822 break;
3823
3824 case S_IFIFO:
3825 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003826 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003827 squashfs_type, 0, 0, 0, NULL,
3828 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003829 INFO("fifo %s inode 0x%llx\n",dir_name,
3830 *inode);
plougher1f413c82005-11-18 00:02:14 +00003831 fifo_count ++;
3832 break;
3833
3834 case S_IFSOCK:
3835 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003836 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003837 squashfs_type, 0, 0, 0, NULL,
3838 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003839 INFO("unix domain socket %s inode "
3840 "0x%llx\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003841 sock_count ++;
3842 break;
3843
plougher23377982007-11-12 04:04:48 +00003844 default:
plougherb3604122009-03-30 02:07:20 +00003845 BAD_ERROR("%s unrecognised file type, "
3846 "mode is %x\n", filename,
3847 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00003848 }
3849 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00003850 dir_ent->inode->type = squashfs_type;
3851 } else {
3852 *inode = dir_ent->inode->inode;
3853 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00003854 switch(squashfs_type) {
3855 case SQUASHFS_FILE_TYPE:
3856 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00003857 INFO("file %s, uncompressed "
3858 "size %lld bytes LINK"
3859 "\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003860 (long long)
plougher50b31762009-03-31 04:14:46 +00003861 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00003862 break;
3863 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00003864 INFO("symbolic link %s inode 0x%llx "
3865 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003866 break;
3867 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003868 INFO("character device %s inode 0x%llx "
3869 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003870 break;
plougher5507dd92006-11-06 00:43:10 +00003871 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003872 INFO("block device %s inode 0x%llx "
3873 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003874 break;
3875 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00003876 INFO("fifo %s inode 0x%llx LINK\n",
3877 dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003878 break;
3879 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00003880 INFO("unix domain socket %s inode "
3881 "0x%llx LINK\n", dir_name,
3882 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003883 break;
3884 }
plougher1f413c82005-11-18 00:02:14 +00003885 }
3886
plougher29e37092007-04-15 01:24:51 +00003887 add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00003888 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00003889 }
3890
plougher29e37092007-04-15 01:24:51 +00003891 write_dir(inode, dir_info, &dir);
plougher1f413c82005-11-18 00:02:14 +00003892 INFO("directory %s inode 0x%llx\n", pathname, *inode);
3893
plougher43244f22009-04-05 02:04:51 +00003894 scan3_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003895}
3896
3897
3898unsigned int slog(unsigned int block)
3899{
3900 int i;
3901
plougher4c99cb72007-06-14 21:46:31 +00003902 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00003903 if(block == (1 << i))
3904 return i;
3905 return 0;
3906}
3907
3908
plougher8f8e1a12007-10-18 02:50:21 +00003909int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00003910{
3911 int i;
3912
3913 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00003914 if((exclude_paths[i].st_dev == buf->st_dev) &&
3915 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00003916 return TRUE;
3917 return FALSE;
3918}
3919
3920
3921#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00003922 if(exclude % EXCLUDE_SIZE == 0) { \
3923 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
3924 * sizeof(struct exclude_info)); \
3925 if(exclude_paths == NULL) \
3926 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
3927 } \
3928 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00003929 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00003930int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00003931{
3932 int i;
plougher91fbb302008-05-06 02:29:36 +00003933 char filename[4096];
plougher1f413c82005-11-18 00:02:14 +00003934 struct stat buf;
3935
plougherb3604122009-03-30 02:07:20 +00003936 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
3937 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00003938 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00003939 ERROR("Cannot stat exclude dir/file %s because %s, "
3940 "ignoring", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003941 return TRUE;
3942 }
3943 ADD_ENTRY(buf);
3944 return TRUE;
3945 }
3946
3947 for(i = 0; i < source; i++) {
3948 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
3949 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00003950 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00003951 ERROR("Cannot stat exclude dir/file %s because "
plougher50b31762009-03-31 04:14:46 +00003952 "%s, ignoring", filename,
3953 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003954 continue;
3955 }
3956 ADD_ENTRY(buf);
3957 }
3958 return TRUE;
3959}
3960
3961
plougherb3604122009-03-30 02:07:20 +00003962void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
3963 int type)
plougher1f413c82005-11-18 00:02:14 +00003964{
plougherb3604122009-03-30 02:07:20 +00003965 old_root_entry = realloc(old_root_entry,
3966 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
3967 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00003968 BAD_ERROR("Out of memory in old root directory entries "
3969 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00003970
ploughera326c182009-08-29 05:41:45 +00003971 old_root_entry[old_root_entries].name = strdup(name);
3972 old_root_entry[old_root_entries].inode.inode = inode;
3973 old_root_entry[old_root_entries].inode.inode_number = inode_number;
3974 old_root_entry[old_root_entries].inode.type = type;
3975 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00003976}
3977
3978
plougher5507dd92006-11-06 00:43:10 +00003979void initialise_threads()
3980{
3981 int i;
3982 sigset_t sigmask, old_mask;
3983
3984 sigemptyset(&sigmask);
3985 sigaddset(&sigmask, SIGINT);
3986 sigaddset(&sigmask, SIGQUIT);
3987 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
3988 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
3989
3990 signal(SIGUSR1, sigusr1_handler);
3991
3992 if(processors == -1) {
3993#ifndef linux
3994 int mib[2];
3995 size_t len = sizeof(processors);
3996
3997 mib[0] = CTL_HW;
3998#ifdef HW_AVAILCPU
3999 mib[1] = HW_AVAILCPU;
4000#else
4001 mib[1] = HW_NCPU;
4002#endif
4003
4004 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004005 ERROR("Failed to get number of available processors. "
4006 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004007 processors = 1;
4008 }
4009#else
4010 processors = get_nprocs();
4011#endif
4012 }
4013
plougher91fbb302008-05-06 02:29:36 +00004014 if((thread = malloc((2 + processors * 2) * sizeof(pthread_t))) == NULL)
plougher5507dd92006-11-06 00:43:10 +00004015 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004016 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004017 frag_deflator_thread = &deflator_thread[processors];
4018
4019 to_reader = queue_init(1);
4020 from_reader = queue_init(reader_buffer_size);
4021 to_writer = queue_init(writer_buffer_size);
4022 from_writer = queue_init(1);
4023 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004024 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004025 reader_buffer = cache_init(block_size, reader_buffer_size);
4026 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004027 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004028 pthread_create(&thread[0], NULL, reader, NULL);
4029 pthread_create(&thread[1], NULL, writer, NULL);
plougher91fbb302008-05-06 02:29:36 +00004030 pthread_create(&progress_thread, NULL, progress_thrd, NULL);
plougher5507dd92006-11-06 00:43:10 +00004031 pthread_mutex_init(&fragment_mutex, NULL);
4032 pthread_cond_init(&fragment_waiting, NULL);
4033
4034 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004035 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4036 0)
plougher5507dd92006-11-06 00:43:10 +00004037 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004038 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4039 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004040 BAD_ERROR("Failed to create thread\n");
4041 }
4042
4043 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4044 processors == 1 ? "" : "s");
4045
4046 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4047 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4048}
4049
4050
plougher0e453652006-11-06 01:49:35 +00004051long long write_inode_lookup_table()
4052{
4053 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher02bc3bc2007-02-25 12:12:01 +00004054
4055 if(inode_count == sinode_count)
4056 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004057
plougher360514a2009-03-30 03:01:38 +00004058 inode_lookup_table = realloc(inode_lookup_table, lookup_bytes);
4059 if(inode_lookup_table == NULL)
plougher0e453652006-11-06 01:49:35 +00004060 BAD_ERROR("Out of memory in write_inode_table\n");
4061
plougher0e453652006-11-06 01:49:35 +00004062 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4063 struct inode_info *inode = inode_info[i];
4064
4065 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004066
4067 inode_number = inode->type == SQUASHFS_DIR_TYPE ?
plougher360514a2009-03-30 03:01:38 +00004068 inode->inode_number : inode->inode_number +
4069 dir_inode_no;
plougher0e453652006-11-06 01:49:35 +00004070
plougher360514a2009-03-30 03:01:38 +00004071 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4072 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004073
plougher0e453652006-11-06 01:49:35 +00004074 }
4075 }
4076
plougher02bc3bc2007-02-25 12:12:01 +00004077skip_inode_hash_table:
plougher50b31762009-03-31 04:14:46 +00004078 return generic_write_table(lookup_bytes, (char *) inode_lookup_table,
plougher85c56262010-07-20 01:00:57 +00004079 0, NULL, noI);
plougher0e453652006-11-06 01:49:35 +00004080}
4081
plougher2ea89142008-03-11 01:34:19 +00004082
plougher8f8e1a12007-10-18 02:50:21 +00004083char *get_component(char *target, char *targname)
4084{
4085 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004086 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004087
4088 while(*target != '/' && *target!= '\0')
4089 *targname ++ = *target ++;
4090
4091 *targname = '\0';
4092
4093 return target;
4094}
4095
4096
4097void free_path(struct pathname *paths)
4098{
4099 int i;
4100
4101 for(i = 0; i < paths->names; i++) {
4102 if(paths->name[i].paths)
4103 free_path(paths->name[i].paths);
4104 free(paths->name[i].name);
4105 if(paths->name[i].preg) {
4106 regfree(paths->name[i].preg);
4107 free(paths->name[i].preg);
4108 }
4109 }
4110
4111 free(paths);
4112}
4113
4114
4115struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4116{
4117 char targname[1024];
4118 int i, error;
4119
4120 target = get_component(target, targname);
4121
4122 if(paths == NULL) {
4123 if((paths = malloc(sizeof(struct pathname))) == NULL)
4124 BAD_ERROR("failed to allocate paths\n");
4125
4126 paths->names = 0;
4127 paths->name = NULL;
4128 }
4129
4130 for(i = 0; i < paths->names; i++)
4131 if(strcmp(paths->name[i].name, targname) == 0)
4132 break;
4133
4134 if(i == paths->names) {
4135 /* allocate new name entry */
4136 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004137 paths->name = realloc(paths->name, (i + 1) *
4138 sizeof(struct path_entry));
plougher8f8e1a12007-10-18 02:50:21 +00004139 paths->name[i].name = strdup(targname);
4140 paths->name[i].paths = NULL;
4141 if(use_regex) {
4142 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004143 if(paths->name[i].preg == NULL)
4144 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004145 error = regcomp(paths->name[i].preg, targname,
4146 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004147 if(error) {
plougher8f8e1a12007-10-18 02:50:21 +00004148 char str[1024];
4149
4150 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004151 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004152 "because %s\n", targname, alltarget,
4153 str);
plougher8f8e1a12007-10-18 02:50:21 +00004154 }
4155 } else
4156 paths->name[i].preg = NULL;
4157
4158 if(target[0] == '\0')
4159 /* at leaf pathname component */
4160 paths->name[i].paths = NULL;
4161 else
4162 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004163 paths->name[i].paths = add_path(NULL, target,
4164 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004165 } else {
4166 /* existing matching entry */
4167 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004168 /* No sub-directory which means this is the leaf
4169 * component of a pre-existing exclude which subsumes
4170 * the exclude currently being added, in which case stop
4171 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004172 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004173 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004174 * from more specific excludes, delete as they're
4175 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004176 free_path(paths->name[i].paths);
4177 paths->name[i].paths = NULL;
4178 } else
4179 /* recurse adding child components */
4180 add_path(paths->name[i].paths, target, alltarget);
4181 }
4182
4183 return paths;
4184}
plougher2ea89142008-03-11 01:34:19 +00004185
4186
plougher05e50ef2007-10-23 12:34:20 +00004187void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004188{
plougher05e50ef2007-10-23 12:34:20 +00004189
plougherb3604122009-03-30 02:07:20 +00004190 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4191 strncmp(target, "../", 3) == 0)
4192 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4193 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004194 else if(strncmp(target, "... ", 4) == 0)
4195 stickypath = add_path(stickypath, target + 4, target + 4);
4196 else
4197 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004198}
4199
4200
4201void display_path(int depth, struct pathname *paths)
4202{
4203 int i, n;
4204
4205 if(paths == NULL)
4206 return;
4207
4208 for(i = 0; i < paths->names; i++) {
4209 for(n = 0; n < depth; n++)
4210 printf("\t");
4211 printf("%d: %s\n", depth, paths->name[i].name);
4212 display_path(depth + 1, paths->name[i].paths);
4213 }
4214}
4215
4216
4217void display_path2(struct pathname *paths, char *string)
4218{
4219 int i;
4220 char path[1024];
4221
4222 if(paths == NULL) {
4223 printf("%s\n", string);
4224 return;
4225 }
4226
4227 for(i = 0; i < paths->names; i++) {
4228 strcat(strcat(strcpy(path, string), "/"), paths->name[i].name);
4229 display_path2(paths->name[i].paths, path);
4230 }
4231}
4232
4233
plougherf9039c92007-10-22 03:54:16 +00004234struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004235{
ploughera2968ef2009-03-03 10:46:00 +00004236 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004237 if(new == NULL)
4238 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004239 new->count = 0;
4240 return new;
4241}
4242
4243
4244struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4245{
4246 if(paths->count % PATHS_ALLOC_SIZE == 0)
plougherb3604122009-03-30 02:07:20 +00004247 paths = realloc(paths, sizeof(struct pathnames *) +
4248 (paths->count + PATHS_ALLOC_SIZE) *
4249 sizeof(struct pathname *));
plougherf9039c92007-10-22 03:54:16 +00004250
4251 paths->path[paths->count++] = path;
4252 return paths;
4253}
4254
4255
4256void free_subdir(struct pathnames *paths)
4257{
4258 free(paths);
4259}
4260
4261
4262int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4263{
4264 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004265
plougherf9039c92007-10-22 03:54:16 +00004266 if(paths == NULL) {
4267 *new = NULL;
4268 return FALSE;
4269 }
plougher8f8e1a12007-10-18 02:50:21 +00004270
plougherf9039c92007-10-22 03:54:16 +00004271
4272 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004273 if(stickypath)
4274 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004275
4276 for(n = 0; n < paths->count; n++) {
4277 struct pathname *path = paths->path[n];
4278
4279 for(i = 0; i < path->names; i++) {
4280 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004281 regexec(path->name[i].preg, name, (size_t) 0,
4282 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004283 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004284 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4285 0;
plougherf9039c92007-10-22 03:54:16 +00004286
4287 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004288 /* match on a leaf component, any subdirectories
4289 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004290 res = TRUE;
4291 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004292 }
4293
plougherf9039c92007-10-22 03:54:16 +00004294 if(match)
plougherb3604122009-03-30 02:07:20 +00004295 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004296 * subdirectories to the new set of
4297 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004298 *new = add_subdir(*new, path->name[i].paths);
4299 }
4300 }
4301
4302 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004303 /* no matching names found, return empty new search set
4304 */
plougherf9039c92007-10-22 03:54:16 +00004305 res = FALSE;
4306 goto empty_set;
4307 }
4308
4309 /* one or more matches with sub-directories found (no leaf matches).
4310 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004311 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004312
4313empty_set:
4314 free_subdir(*new);
4315 *new = NULL;
4316 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004317}
4318
4319
plougher99ac0cc2007-10-29 03:17:10 +00004320#define RECOVER_ID "Squashfs recovery file v1.0\n"
4321#define RECOVER_ID_SIZE 28
4322
4323void write_recovery_data(squashfs_super_block *sBlk)
4324{
plougher1d065e92010-06-18 03:58:27 +00004325 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004326 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004327 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004328 char header[] = RECOVER_ID;
4329
4330 if(recover == FALSE) {
4331 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004332 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004333 return;
4334 }
4335
4336 if((metadata = malloc(bytes)) == NULL)
plougher50b31762009-03-31 04:14:46 +00004337 BAD_ERROR("Failed to alloc metadata buffer in "
4338 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004339
plougher1d065e92010-06-18 03:58:27 +00004340 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4341 if(res == 0)
4342 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004343
plougherb3604122009-03-30 02:07:20 +00004344 sprintf(recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004345 getbase(destination_file), pid);
plougherb3604122009-03-30 02:07:20 +00004346 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4347 if(recoverfd == -1)
4348 BAD_ERROR("Failed to create recovery file, because %s. "
4349 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004350
plougher628e7682009-03-29 22:12:24 +00004351 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004352 BAD_ERROR("Failed to write recovery file, because %s\n",
4353 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004354
plougher628e7682009-03-29 22:12:24 +00004355 if(write_bytes(recoverfd, sBlk, sizeof(squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004356 BAD_ERROR("Failed to write recovery file, because %s\n",
4357 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004358
plougher628e7682009-03-29 22:12:24 +00004359 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004360 BAD_ERROR("Failed to write recovery file, because %s\n",
4361 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004362
4363 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004364 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004365
4366 printf("Recovery file \"%s\" written\n", recovery_file);
4367 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004368 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4369 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004370 printf("to restore filesystem\n\n");
4371}
4372
4373
4374void read_recovery_data(char *recovery_file, char *destination_file)
4375{
4376 int fd, recoverfd, bytes;
4377 squashfs_super_block orig_sBlk, sBlk;
4378 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004379 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004380 struct stat buf;
4381 char header[] = RECOVER_ID;
4382 char header2[RECOVER_ID_SIZE];
4383
4384 if((recoverfd = open(recovery_file, O_RDONLY)) == -1)
plougherb3604122009-03-30 02:07:20 +00004385 BAD_ERROR("Failed to open recovery file because %s\n",
4386 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004387
4388 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004389 BAD_ERROR("Failed to stat destination file, because %s\n",
4390 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004391
4392 if((fd = open(destination_file, O_RDWR)) == -1)
plougherb3604122009-03-30 02:07:20 +00004393 BAD_ERROR("Failed to open destination file because %s\n",
4394 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004395
plougher8a8c4102009-03-29 22:28:49 +00004396 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4397 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004398 BAD_ERROR("Failed to read recovery file, because %s\n",
4399 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004400 if(res < RECOVER_ID_SIZE)
4401 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004402 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4403 BAD_ERROR("Not a recovery file\n");
4404
plougher8a8c4102009-03-29 22:28:49 +00004405 res = read_bytes(recoverfd, &sBlk, sizeof(squashfs_super_block));
4406 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004407 BAD_ERROR("Failed to read recovery file, because %s\n",
4408 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004409 if(res < sizeof(squashfs_super_block))
4410 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004411
plougher3306cb22010-06-18 04:22:44 +00004412 res = read_fs_bytes(fd, 0, sizeof(squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004413 if(res == 0)
4414 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004415
plougherb3604122009-03-30 02:07:20 +00004416 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
4417 sizeof(squashfs_super_block) - 4) != 0)
4418 BAD_ERROR("Recovery file and destination file do not seem to "
4419 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004420
4421 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4422
4423 if((metadata = malloc(bytes)) == NULL)
plougherb3604122009-03-30 02:07:20 +00004424 BAD_ERROR("Failed to alloc metadata buffer in "
4425 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004426
plougher8a8c4102009-03-29 22:28:49 +00004427 res = read_bytes(recoverfd, metadata, bytes);
4428 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004429 BAD_ERROR("Failed to read recovery file, because %s\n",
4430 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004431 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004432 BAD_ERROR("Recovery file appears to be truncated\n");
4433
plougher0dd6f122009-03-29 21:43:57 +00004434 write_destination(fd, 0, sizeof(squashfs_super_block), (char *) &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004435
plougher0dd6f122009-03-29 21:43:57 +00004436 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004437
4438 close(recoverfd);
4439 close(fd);
4440
plougherb3604122009-03-30 02:07:20 +00004441 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4442 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004443
4444 exit(0);
4445}
4446
4447
plougher1f413c82005-11-18 00:02:14 +00004448#define VERSION() \
plougherfdee12a2010-07-19 17:50:28 +00004449 printf("mksquashfs version 4.1-CVS (2010/07/19)\n");\
plougher16111452010-07-22 05:12:18 +00004450 printf("copyright (C) 2010 Phillip Lougher "\
4451 "<phillip@lougher.demon.co.uk>\n\n"); \
4452 printf("This program is free software; you can redistribute it and/or"\
4453 "\n");\
4454 printf("modify it under the terms of the GNU General Public License"\
4455 "\n");\
4456 printf("as published by the Free Software Foundation; either version "\
4457 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004458 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004459 printf("This program is distributed in the hope that it will be "\
4460 "useful,\n");\
4461 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4462 "of\n");\
4463 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4464 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004465 printf("GNU General Public License for more details.\n");
4466int main(int argc, char *argv[])
4467{
plougher324978d2006-02-27 04:53:29 +00004468 struct stat buf, source_buf;
plougher1f413c82005-11-18 00:02:14 +00004469 int i;
4470 squashfs_super_block sBlk;
4471 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004472 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004473 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004474 int readb_mbytes = READER_BUFFER_DEFAULT,
4475 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4476 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
plougherf11dfd62009-01-26 03:56:07 +00004477 int s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00004478
plougher91fbb302008-05-06 02:29:36 +00004479 pthread_mutex_init(&progress_mutex, NULL);
plougher1f413c82005-11-18 00:02:14 +00004480 block_log = slog(block_size);
4481 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
4482 VERSION();
4483 exit(0);
4484 }
4485 for(i = 1; i < argc && argv[i][0] != '-'; i++);
4486 if(i < 3)
4487 goto printOptions;
4488 source_path = argv + 1;
4489 source = i - 2;
4490 for(; i < argc; i++) {
plougherae9dcd82009-08-01 02:59:38 +00004491 if(strcmp(argv[i], "-comp") == 0) {
4492 if(++i == argc) {
4493 ERROR("%s: -comp missing compression type\n",
4494 argv[0]);
4495 exit(1);
4496 }
4497 comp_name = argv[i];
4498 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00004499 if(++i == argc) {
4500 ERROR("%s: -pf missing filename\n", argv[0]);
4501 exit(1);
4502 }
plougher620b7172009-09-10 04:17:48 +00004503 if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004504 exit(1);
plougher43244f22009-04-05 02:04:51 +00004505 } else if(strcmp(argv[i], "-p") == 0) {
4506 if(++i == argc) {
4507 ERROR("%s: -p missing pseudo file definition\n",
4508 argv[0]);
4509 exit(1);
4510 }
plougher620b7172009-09-10 04:17:48 +00004511 if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004512 exit(1);
plougher43244f22009-04-05 02:04:51 +00004513 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00004514 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00004515 ERROR("%s: -recover missing recovery file\n",
4516 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00004517 exit(1);
4518 }
4519 read_recovery_data(argv[i], argv[source + 1]);
4520 } else if(strcmp(argv[i], "-no-recovery") == 0)
4521 recover = FALSE;
4522 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00004523 old_exclude = FALSE;
4524 use_regex = FALSE;
4525 } else if(strcmp(argv[i], "-regex") == 0) {
4526 old_exclude = FALSE;
4527 use_regex = TRUE;
4528 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00004529 sparse_files = FALSE;
4530 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00004531 progress = FALSE;
4532 else if(strcmp(argv[i], "-no-exports") == 0)
4533 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00004534 else if(strcmp(argv[i], "-processors") == 0) {
plougher360514a2009-03-30 03:01:38 +00004535 if((++i == argc) || (processors =
4536 strtol(argv[i], &b, 10), *b != '\0')) {
4537 ERROR("%s: -processors missing or invalid "
4538 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004539 exit(1);
4540 }
4541 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00004542 ERROR("%s: -processors should be 1 or larger\n",
4543 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004544 exit(1);
4545 }
plougher0e453652006-11-06 01:49:35 +00004546 } else if(strcmp(argv[i], "-read-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004547 if((++i == argc) || (readb_mbytes =
4548 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004549 ERROR("%s: -read-queue missing or invalid "
4550 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004551 exit(1);
4552 }
4553 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00004554 ERROR("%s: -read-queue should be 1 megabyte or "
4555 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004556 exit(1);
4557 }
plougher0e453652006-11-06 01:49:35 +00004558 } else if(strcmp(argv[i], "-write-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004559 if((++i == argc) || (writeb_mbytes =
4560 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004561 ERROR("%s: -write-queue missing or invalid "
4562 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004563 exit(1);
4564 }
4565 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004566 ERROR("%s: -write-queue should be 1 megabyte "
4567 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004568 exit(1);
4569 }
plougher217bad82008-04-05 11:36:41 +00004570 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004571 if((++i == argc) ||
4572 (fragmentb_mbytes =
4573 strtol(argv[i], &b, 10), *b != '\0')) {
4574 ERROR("%s: -fragment-queue missing or invalid "
4575 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004576 exit(1);
4577 }
4578 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004579 ERROR("%s: -fragment-queue should be 1 "
4580 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004581 exit(1);
4582 }
plougher5507dd92006-11-06 00:43:10 +00004583 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00004584 if(++i == argc) {
4585 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004586 exit(1);
4587 }
plougher4c99cb72007-06-14 21:46:31 +00004588 block_size = strtol(argv[i], &b, 10);
4589 if(*b == 'm' || *b == 'M')
4590 block_size *= 1048576;
4591 else if(*b == 'k' || *b == 'K')
4592 block_size *= 1024;
4593 else if(*b != '\0') {
4594 ERROR("%s: -b invalid block size\n", argv[0]);
4595 exit(1);
4596 }
plougher1f413c82005-11-18 00:02:14 +00004597 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00004598 ERROR("%s: -b block size not power of two or "
4599 "not between 4096 and 1Mbyte\n",
4600 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004601 exit(1);
4602 }
4603 } else if(strcmp(argv[i], "-ef") == 0) {
4604 if(++i == argc) {
4605 ERROR("%s: -ef missing filename\n", argv[0]);
4606 exit(1);
4607 }
plougher9b5bf8c2006-03-20 18:43:33 +00004608 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00004609 duplicate_checking = FALSE;
4610
4611 else if(strcmp(argv[i], "-no-fragments") == 0)
4612 no_fragments = TRUE;
4613
4614 else if(strcmp(argv[i], "-always-use-fragments") == 0)
4615 always_use_fragments = TRUE;
4616
4617 else if(strcmp(argv[i], "-sort") == 0) {
4618 if(++i == argc) {
4619 ERROR("%s: -sort missing filename\n", argv[0]);
4620 exit(1);
4621 }
4622 } else if(strcmp(argv[i], "-all-root") == 0 ||
4623 strcmp(argv[i], "-root-owned") == 0)
4624 global_uid = global_gid = 0;
4625
4626 else if(strcmp(argv[i], "-force-uid") == 0) {
4627 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004628 ERROR("%s: -force-uid missing uid or user\n",
4629 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004630 exit(1);
4631 }
4632 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004633 if(global_uid < 0 || global_uid >
4634 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004635 ERROR("%s: -force-uid uid out of range"
4636 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004637 exit(1);
4638 }
4639 } else {
4640 struct passwd *uid = getpwnam(argv[i]);
4641 if(uid)
4642 global_uid = uid->pw_uid;
4643 else {
plougher360514a2009-03-30 03:01:38 +00004644 ERROR("%s: -force-uid invalid uid or "
4645 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004646 exit(1);
4647 }
4648 }
4649 } else if(strcmp(argv[i], "-force-gid") == 0) {
4650 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00004651 ERROR("%s: -force-gid missing gid or group\n",
4652 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004653 exit(1);
4654 }
4655 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004656 if(global_gid < 0 || global_gid >
4657 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004658 ERROR("%s: -force-gid gid out of range"
4659 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004660 exit(1);
4661 }
4662 } else {
4663 struct group *gid = getgrnam(argv[i]);
4664 if(gid)
4665 global_gid = gid->gr_gid;
4666 else {
plougher360514a2009-03-30 03:01:38 +00004667 ERROR("%s: -force-gid invalid gid or "
4668 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004669 exit(1);
4670 }
4671 }
4672 } else if(strcmp(argv[i], "-noI") == 0 ||
4673 strcmp(argv[i], "-noInodeCompression") == 0)
4674 noI = TRUE;
4675
4676 else if(strcmp(argv[i], "-noD") == 0 ||
4677 strcmp(argv[i], "-noDataCompression") == 0)
4678 noD = TRUE;
4679
4680 else if(strcmp(argv[i], "-noF") == 0 ||
4681 strcmp(argv[i], "-noFragmentCompression") == 0)
4682 noF = TRUE;
4683
plougherb99d7832010-05-19 01:57:34 +00004684 else if(strcmp(argv[i], "-noX") == 0 ||
4685 strcmp(argv[i], "-noXattrCompression") == 0)
4686 noX = TRUE;
4687
plougherce564c62010-05-19 03:01:49 +00004688 else if(strcmp(argv[i], "-no-xattrs") == 0)
4689 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00004690
plougher1f413c82005-11-18 00:02:14 +00004691 else if(strcmp(argv[i], "-nopad") == 0)
4692 nopad = TRUE;
4693
plougher91fbb302008-05-06 02:29:36 +00004694 else if(strcmp(argv[i], "-info") == 0) {
4695 silent = FALSE;
4696 progress = FALSE;
4697 }
plougher1f413c82005-11-18 00:02:14 +00004698
4699 else if(strcmp(argv[i], "-e") == 0)
4700 break;
4701
4702 else if(strcmp(argv[i], "-noappend") == 0)
4703 delete = TRUE;
4704
4705 else if(strcmp(argv[i], "-keep-as-directory") == 0)
4706 keep_as_directory = TRUE;
4707
4708 else if(strcmp(argv[i], "-root-becomes") == 0) {
4709 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004710 ERROR("%s: -root-becomes: missing name\n",
4711 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004712 exit(1);
4713 }
4714 root_name = argv[i];
4715 } else if(strcmp(argv[i], "-version") == 0) {
4716 VERSION();
4717 } else {
4718 ERROR("%s: invalid option\n\n", argv[0]);
4719printOptions:
plougher360514a2009-03-30 03:01:38 +00004720 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
4721 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00004722 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00004723 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00004724 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00004725 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00004726 ERROR("-b <block_size>\t\tset data block to "
4727 "<block_size>. Default %d bytes\n",
4728 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00004729 ERROR("-no-exports\t\tdon't make the filesystem "
4730 "exportable via NFS\n");
4731 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher16111452010-07-22 05:12:18 +00004732 ERROR("-no-xattrs\t\tdon't detect extended "
4733 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00004734 ERROR("-noI\t\t\tdo not compress inode table\n");
4735 ERROR("-noD\t\t\tdo not compress data blocks\n");
4736 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00004737 ERROR("-noX\t\t\tdo not compress extended "
4738 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00004739 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00004740 ERROR("-always-use-fragments\tuse fragment blocks for "
4741 "files larger than block size\n");
4742 ERROR("-no-duplicates\t\tdo not perform duplicate "
4743 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00004744 ERROR("-all-root\t\tmake all files owned by root\n");
4745 ERROR("-force-uid uid\t\tset all file uids to uid\n");
4746 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00004747 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
4748 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00004749 ERROR("-keep-as-directory\tif one source directory is "
4750 "specified, create a root\n");
4751 ERROR("\t\t\tdirectory containing that directory, "
4752 "rather than the\n");
4753 ERROR("\t\t\tcontents of the directory\n");
4754 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00004755 ERROR("-p <pseudo-definition>\tAdd pseudo file "
4756 "definition\n");
4757 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
4758 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00004759 ERROR("-sort <sort_file>\tsort files according to "
4760 "priorities in <sort_file>. One\n");
4761 ERROR("\t\t\tfile or dir with priority per line. "
4762 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00004763 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00004764 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
4765 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00004766 ERROR("-wildcards\t\tAllow extended shell wildcards "
4767 "(globbing) to be used in\n\t\t\texclude "
4768 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00004769 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
4770 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00004771 ERROR("\nFilesystem append options:\n");
4772 ERROR("-noappend\t\tdo not append to existing "
4773 "filesystem\n");
4774 ERROR("-root-becomes <name>\twhen appending source "
4775 "files/directories, make the\n");
4776 ERROR("\t\t\toriginal root become a subdirectory in "
4777 "the new root\n");
4778 ERROR("\t\t\tcalled <name>, rather than adding the new "
4779 "source items\n");
4780 ERROR("\t\t\tto the original root\n");
4781 ERROR("\nMksquashfs runtime options:\n");
4782 ERROR("-version\t\tprint version, licence and "
4783 "copyright message\n");
4784 ERROR("-recover <name>\t\trecover filesystem data "
4785 "using recovery file <name>\n");
4786 ERROR("-no-recovery\t\tdon't generate a recovery "
4787 "file\n");
4788 ERROR("-info\t\t\tprint files written to filesystem\n");
4789 ERROR("-no-progress\t\tdon't display the progress "
4790 "bar\n");
4791 ERROR("-processors <number>\tUse <number> processors."
4792 " By default will use number of\n");
4793 ERROR("\t\t\tprocessors available\n");
4794 ERROR("-read-queue <size>\tSet input queue to <size> "
4795 "Mbytes. Default %d Mbytes\n",
4796 READER_BUFFER_DEFAULT);
4797 ERROR("-write-queue <size>\tSet output queue to <size> "
4798 "Mbytes. Default %d Mbytes\n",
4799 WRITER_BUFFER_DEFAULT);
4800 ERROR("-fragment-queue <size>\tSet fagment queue to "
4801 "<size> Mbytes. Default %d Mbytes\n",
4802 FRAGMENT_BUFFER_DEFAULT);
4803 ERROR("\nMiscellaneous options:\n");
4804 ERROR("-root-owned\t\talternative name for -all-root"
4805 "\n");
4806 ERROR("-noInodeCompression\talternative name for -noI"
4807 "\n");
4808 ERROR("-noDataCompression\talternative name for -noD"
4809 "\n");
4810 ERROR("-noFragmentCompression\talternative name for "
4811 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00004812 ERROR("-noXattrCompression\talternative name for "
4813 "-noX\n");
plougher43664872009-12-08 18:02:54 +00004814 ERROR("\nCompressors available:\n");
4815 display_compressors("", COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00004816 exit(1);
4817 }
4818 }
4819
plougher5507dd92006-11-06 00:43:10 +00004820 reader_buffer_size = readb_mbytes << (20 - block_log);
4821 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher76c64082008-03-08 01:32:23 +00004822 fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004823
plougher91fbb302008-05-06 02:29:36 +00004824 for(i = 0; i < source; i++)
4825 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00004826 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00004827 "because %s\n", source_path[i],
4828 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00004829 EXIT_MKSQUASHFS();
4830 }
plougher324978d2006-02-27 04:53:29 +00004831
4832 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00004833 if(stat(argv[source + 1], &buf) == -1) {
4834 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00004835 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00004836 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00004837 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00004838 perror("Could not create destination file");
4839 exit(1);
4840 }
4841 delete = TRUE;
4842 } else {
4843 perror("Could not stat destination file");
4844 exit(1);
4845 }
4846
4847 } else {
4848 if(S_ISBLK(buf.st_mode)) {
4849 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00004850 perror("Could not open block device as "
4851 "destination");
plougher1f413c82005-11-18 00:02:14 +00004852 exit(1);
4853 }
4854 block_device = 1;
4855
4856 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00004857 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
4858 O_RDWR);
4859 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00004860 perror("Could not open regular file for "
4861 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00004862 exit(1);
4863 }
plougher44d54ef2010-02-08 22:13:49 +00004864 }
plougher1f413c82005-11-18 00:02:14 +00004865 else {
4866 ERROR("Destination not block device or regular file\n");
4867 exit(1);
4868 }
4869
plougher324978d2006-02-27 04:53:29 +00004870 }
plougher1f413c82005-11-18 00:02:14 +00004871
plougher4c99cb72007-06-14 21:46:31 +00004872 signal(SIGTERM, sighandler2);
4873 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00004874
plougher16111452010-07-22 05:12:18 +00004875 /*
4876 * process the exclude files - must be done afer destination file has
4877 * been possibly created
4878 */
plougher1f413c82005-11-18 00:02:14 +00004879 for(i = source + 2; i < argc; i++)
4880 if(strcmp(argv[i], "-ef") == 0) {
4881 FILE *fd;
4882 char filename[16385];
4883 if((fd = fopen(argv[++i], "r")) == NULL) {
4884 perror("Could not open exclude file...");
plougher324978d2006-02-27 04:53:29 +00004885 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00004886 }
4887 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
plougher8f8e1a12007-10-18 02:50:21 +00004888 if(old_exclude)
4889 old_add_exclude(filename);
4890 else
plougher05e50ef2007-10-23 12:34:20 +00004891 add_exclude(filename);
plougher1f413c82005-11-18 00:02:14 +00004892 fclose(fd);
4893 } else if(strcmp(argv[i], "-e") == 0)
4894 break;
plougher8b9a7f62009-08-01 22:52:45 +00004895 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00004896 strcmp(argv[i], "-sort") == 0 ||
4897 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00004898 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00004899 i++;
4900
4901 if(i != argc) {
4902 if(++i == argc) {
4903 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00004904 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00004905 }
plougher8f8e1a12007-10-18 02:50:21 +00004906 while(i < argc)
4907 if(old_exclude)
4908 old_add_exclude(argv[i++]);
4909 else
plougher05e50ef2007-10-23 12:34:20 +00004910 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00004911 }
4912
4913 /* process the sort files - must be done afer the exclude files */
4914 for(i = source + 2; i < argc; i++)
4915 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00004916 int res = read_sort_file(argv[++i], source,
4917 source_path);
4918 if(res == FALSE)
4919 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00004920 sorted ++;
4921 } else if(strcmp(argv[i], "-e") == 0)
4922 break;
plougher8b9a7f62009-08-01 22:52:45 +00004923 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00004924 strcmp(argv[i], "-ef") == 0 ||
4925 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00004926 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00004927 i++;
4928
plougher62d5b5c2008-08-16 01:49:42 +00004929#ifdef SQUASHFS_TRACE
4930 progress = FALSE;
4931#endif
4932
plougher4c99cb72007-06-14 21:46:31 +00004933 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00004934 comp = read_super(fd, &sBlk, argv[source + 1]);
4935 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00004936 ERROR("Failed to read existing filesystem - will not "
4937 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00004938 ERROR("To force Mksquashfs to write to this block "
4939 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00004940 EXIT_MKSQUASHFS();
4941 }
plougher1f413c82005-11-18 00:02:14 +00004942
plougher1f413c82005-11-18 00:02:14 +00004943 block_log = slog(block_size = sBlk.block_size);
plougher4c99cb72007-06-14 21:46:31 +00004944 s_minor = sBlk.s_minor;
plougher1f413c82005-11-18 00:02:14 +00004945 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
4946 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
4947 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00004948 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
4949 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
4950 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00004951 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
ploughera175ce22009-07-30 04:43:27 +00004952 } else {
4953 comp = lookup_compressor(comp_name);
plougher394fe0d2009-08-04 04:27:12 +00004954 if(!comp->supported) {
plougherfbfb2f42009-08-03 02:33:25 +00004955 ERROR("FATAL_ERROR: Compressor \"%s\" is not "
4956 "supported!\n", comp_name);
plougher13df1782009-08-29 01:05:34 +00004957 ERROR("Compressors available:\n");
plougher764dab52009-08-24 18:28:04 +00004958 display_compressors("", COMP_DEFAULT);
plougherfbfb2f42009-08-03 02:33:25 +00004959 EXIT_MKSQUASHFS();
plougher394fe0d2009-08-04 04:27:12 +00004960 }
plougher4c99cb72007-06-14 21:46:31 +00004961 }
4962
4963 initialise_threads();
4964
4965 if(delete) {
plougherdf6d8f02009-03-20 03:10:00 +00004966 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher360514a2009-03-30 03:01:38 +00004967 SQUASHFS_MAJOR, s_minor, argv[source + 1], block_size);
plougher4c99cb72007-06-14 21:46:31 +00004968 bytes = sizeof(squashfs_super_block);
4969 } else {
plougher360514a2009-03-30 03:01:38 +00004970 unsigned int last_directory_block, inode_dir_offset,
4971 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00004972 inode_dir_start_block, uncompressed_data,
4973 compressed_data, inode_dir_inode_number,
4974 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00004975 unsigned int root_inode_start =
4976 SQUASHFS_INODE_BLK(sBlk.root_inode),
4977 root_inode_offset =
4978 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00004979
plougher360514a2009-03-30 03:01:38 +00004980 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
4981 &data_cache, &directory_table,
4982 &directory_data_cache, &last_directory_block,
4983 &inode_dir_offset, &inode_dir_file_size,
4984 &root_inode_size, &inode_dir_start_block,
4985 &file_count, &sym_count, &dev_count, &dir_count,
4986 &fifo_count, &sock_count, &total_bytes,
4987 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00004988 &inode_dir_inode_number,
4989 &inode_dir_parent_inode, add_old_root_entry,
4990 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00004991 ERROR("Failed to read existing filesystem - will not "
4992 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00004993 ERROR("To force Mksquashfs to write to this block "
4994 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00004995 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00004996 }
4997 if((fragments = sBlk.fragments))
plougher360514a2009-03-30 03:01:38 +00004998 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00004999 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
5000 * sizeof(squashfs_fragment_entry));
plougher1f413c82005-11-18 00:02:14 +00005001
plougher50b31762009-03-31 04:14:46 +00005002 printf("Appending to existing %d.%d filesystem on %s, block "
5003 "size %d\n", SQUASHFS_MAJOR, s_minor, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005004 block_size);
5005 printf("All -b, -noI, -noD, -noF, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005006 "-always-use-fragments,\n-exportable and -comp options "
5007 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005008 printf("\nIf appending is not wanted, please re-run with "
5009 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005010
plougher360514a2009-03-30 03:01:38 +00005011 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5012 ~(SQUASHFS_METADATA_SIZE - 1);
5013 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5014 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005015
5016 /* save original filesystem state for restoring ... */
5017 sfragments = fragments;
5018 sbytes = bytes;
5019 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005020 scache_bytes = root_inode_offset + root_inode_size;
5021 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005022 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005023 if(sdata_cache == NULL)
5024 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005025 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005026 if(sdirectory_data_cache == NULL)
5027 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005028 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005029 memcpy(sdirectory_data_cache, directory_data_cache +
5030 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005031 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005032 stotal_bytes = total_bytes;
5033 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005034 stotal_directory_bytes = total_directory_bytes +
5035 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005036 sfile_count = file_count;
5037 ssym_count = sym_count;
5038 sdev_count = dev_count;
5039 sdir_count = dir_count + 1;
5040 sfifo_count = fifo_count;
5041 ssock_count = sock_count;
5042 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005043 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005044 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005045 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005046 BAD_ERROR("Failed to save xattrs from existing "
5047 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005048 restore = TRUE;
5049 if(setjmp(env))
5050 goto restore_filesystem;
5051 signal(SIGTERM, sighandler);
5052 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005053 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005054
plougher360514a2009-03-30 03:01:38 +00005055 /*
5056 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005057 * original filesystem. The filesystem state differs depending
5058 * on whether we're appending to the original root directory, or
5059 * if the original root directory becomes a sub-directory
5060 * (root-becomes specified on command line, here root_name !=
5061 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005062 */
5063 inode_bytes = inode_size = root_inode_start;
5064 directory_size = last_directory_block;
5065 cache_size = root_inode_offset + root_inode_size;
5066 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5067 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005068 sdirectory_bytes = last_directory_block;
5069 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005070 root_inode_number = inode_dir_parent_inode;
5071 dir_inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005072 directory_bytes = last_directory_block;
5073 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005074 memmove(directory_data_cache, directory_data_cache +
5075 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005076 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005077 add_old_root_entry(root_name, sBlk.root_inode,
5078 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005079 total_directory_bytes += compressed_data;
5080 dir_count ++;
5081 } else {
plougher360514a2009-03-30 03:01:38 +00005082 sdirectory_compressed_bytes = last_directory_block -
5083 inode_dir_start_block;
5084 sdirectory_compressed =
5085 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005086 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005087 BAD_ERROR("Out of memory in save filesystem "
5088 "state\n");
plougher360514a2009-03-30 03:01:38 +00005089 memcpy(sdirectory_compressed, directory_table +
5090 inode_dir_start_block,
5091 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005092 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005093 root_inode_number = inode_dir_inode_number;
plougher778e9362006-02-01 09:32:31 +00005094 dir_inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005095 directory_bytes = inode_dir_start_block;
5096 directory_cache_bytes = inode_dir_offset;
5097 cache_bytes = root_inode_offset;
5098 }
5099
plougher360514a2009-03-30 03:01:38 +00005100 inode_count = file_count + dir_count + sym_count + dev_count +
5101 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005102
5103 /*
5104 * The default use freelist before growing cache policy behaves
5105 * poorly with appending - with many deplicates the caches
5106 * do not grow due to the fact that large queues of outstanding
5107 * fragments/writer blocks do not occur, leading to small caches
5108 * and un-uncessary performance loss to frequent cache
5109 * replacement in the small caches. Therefore with appending
5110 * change the policy to grow the caches before reusing blocks
5111 * from the freelist
5112 */
5113 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005114 }
5115
plougher05e50ef2007-10-23 12:34:20 +00005116 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005117 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005118 if(path)
5119 paths = add_subdir(paths, path);
5120 if(stickypath)
5121 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005122 }
5123
plougher360514a2009-03-30 03:01:38 +00005124 if(delete && !keep_as_directory && source == 1 &&
5125 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005126 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005127 else if(!keep_as_directory && source == 1 &&
5128 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005129 dir_scan(&inode, source_path[0], scan1_single_readdir);
5130 else
5131 dir_scan(&inode, "", scan1_encomp_readdir);
5132 sBlk.root_inode = inode;
5133 sBlk.inodes = inode_count;
5134 sBlk.s_magic = SQUASHFS_MAGIC;
5135 sBlk.s_major = SQUASHFS_MAJOR;
plougher4c99cb72007-06-14 21:46:31 +00005136 sBlk.s_minor = s_minor;
plougher1f413c82005-11-18 00:02:14 +00005137 sBlk.block_size = block_size;
5138 sBlk.block_log = block_log;
plougher360514a2009-03-30 03:01:38 +00005139 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, no_fragments,
5140 always_use_fragments, duplicate_checking, exportable);
plougher1f413c82005-11-18 00:02:14 +00005141 sBlk.mkfs_time = time(NULL);
5142
5143restore_filesystem:
plougher43bb7e92008-08-17 17:16:09 +00005144 if(progress && estimated_uncompressed) {
plougherc9b11db2008-05-06 23:59:15 +00005145 disable_progress_bar();
5146 progress_bar(cur_uncompressed, estimated_uncompressed, columns);
5147 }
5148
plougher1f413c82005-11-18 00:02:14 +00005149 write_fragment();
5150 sBlk.fragments = fragments;
plougher5507dd92006-11-06 00:43:10 +00005151 if(interrupted < 2) {
plougher2ea89142008-03-11 01:34:19 +00005152 unlock_fragments();
5153 pthread_mutex_lock(&fragment_mutex);
5154 while(fragments_outstanding) {
5155 pthread_mutex_unlock(&fragment_mutex);
5156 sched_yield();
5157 pthread_mutex_lock(&fragment_mutex);
5158 }
plougher5507dd92006-11-06 00:43:10 +00005159 queue_put(to_writer, NULL);
5160 if(queue_get(from_writer) != 0)
5161 EXIT_MKSQUASHFS();
5162 }
5163
ploughere6e0e1b2010-05-12 17:17:06 +00005164 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005165 sBlk.inode_table_start = write_inodes();
5166 sBlk.directory_table_start = write_directories();
5167 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005168 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5169 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005170 sBlk.id_table_start = write_id_table();
5171 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005172
plougher0e453652006-11-06 01:49:35 +00005173 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005174 TRACE("sBlk->directory_table_start 0x%llx\n",
5175 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005176 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5177 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005178 TRACE("sBlk->lookup_table_start 0x%llx\n",
5179 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005180
plougher1f413c82005-11-18 00:02:14 +00005181 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005182
plougher8c4b7b92009-07-30 04:47:52 +00005183 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005184
plougher1f288f62009-02-21 03:05:52 +00005185 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher360514a2009-03-30 03:01:38 +00005186 write_destination(fd, SQUASHFS_START, sizeof(squashfs_super_block),
5187 (char *) &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005188
5189 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005190 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005191 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005192 }
5193
plougher99ac0cc2007-10-29 03:17:10 +00005194 close(fd);
5195
plougher11e7b1b2009-09-11 12:10:58 +00005196 delete_pseudo_files();
5197
plougher99ac0cc2007-10-29 03:17:10 +00005198 if(recovery_file[0] != '\0')
5199 unlink(recovery_file);
5200
plougher10f7d572010-07-20 02:14:04 +00005201 total_bytes += total_inode_bytes + total_directory_bytes +
plougher747e7262010-07-19 18:10:54 +00005202 sizeof(squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005203
plougher62542fb2009-08-06 08:43:08 +00005204 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5205 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5206 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005207 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005208 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5209 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005210 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5211 "compressed");
plougher50b31762009-03-31 04:14:46 +00005212 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5213 "not ");
plougher360514a2009-03-30 03:01:38 +00005214 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5215 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005216 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5217 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5218 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5219 inode_bytes, inode_bytes / 1024.0);
5220 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005221 ((float) inode_bytes / total_inode_bytes) * 100.0,
5222 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005223 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5224 directory_bytes, directory_bytes / 1024.0);
5225 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005226 ((float) directory_bytes / total_directory_bytes) * 100.0,
5227 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005228 if(total_xattr_bytes) {
5229 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5230 xattr_bytes, xattr_bytes / 1024.0);
5231 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5232 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5233 total_xattr_bytes);
5234 }
plougher1f413c82005-11-18 00:02:14 +00005235 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005236 printf("Number of duplicate files found %d\n", file_count -
5237 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005238 else
5239 printf("No duplicate files removed\n");
5240 printf("Number of inodes %d\n", inode_count);
5241 printf("Number of files %d\n", file_count);
5242 if(!no_fragments)
5243 printf("Number of fragments %d\n", fragments);
5244 printf("Number of symbolic links %d\n", sym_count);
5245 printf("Number of device nodes %d\n", dev_count);
5246 printf("Number of fifo nodes %d\n", fifo_count);
5247 printf("Number of socket nodes %d\n", sock_count);
5248 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005249 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005250 printf("Number of uids %d\n", uid_count);
5251
plougher1b899fc2008-08-07 01:24:06 +00005252 for(i = 0; i < id_count; i++) {
5253 if(id_table[i]->flags & ISA_UID) {
5254 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005255 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5256 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005257 }
plougher1f413c82005-11-18 00:02:14 +00005258 }
5259
5260 printf("Number of gids %d\n", guid_count);
5261
plougher1b899fc2008-08-07 01:24:06 +00005262 for(i = 0; i < id_count; i++) {
5263 if(id_table[i]->flags & ISA_GID) {
5264 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005265 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5266 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005267 }
plougher1f413c82005-11-18 00:02:14 +00005268 }
plougher99ac0cc2007-10-29 03:17:10 +00005269
plougher1f413c82005-11-18 00:02:14 +00005270 return 0;
5271}