blob: 5b60e8baa09ca9f699d572edf5a6d38c9ad9bf9f [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 *
Phillip Lougher43cc4282012-01-25 00:25:56 +00005 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
6 * 2012
plougherf6cd3372007-08-19 03:33:23 +00007 * Phillip Lougher <phillip@lougher.demon.co.uk>
plougher1f413c82005-11-18 00:02:14 +00008 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2,
12 * or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * mksquashfs.c
24 */
25
plougher324978d2006-02-27 04:53:29 +000026#define FALSE 0
plougher1f413c82005-11-18 00:02:14 +000027#define TRUE 1
plougher8cb05cd2005-12-11 23:32:35 +000028
plougher1f413c82005-11-18 00:02:14 +000029#include <pwd.h>
30#include <grp.h>
31#include <time.h>
32#include <unistd.h>
33#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000034#include <stddef.h>
plougher35a10602008-04-21 02:58:16 +000035#include <sys/time.h>
plougher1f413c82005-11-18 00:02:14 +000036#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <dirent.h>
41#include <string.h>
plougher1f413c82005-11-18 00:02:14 +000042#include <stdlib.h>
43#include <signal.h>
44#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000045#include <sys/ioctl.h>
46#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000047#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000048#include <pthread.h>
plougher02bc3bc2007-02-25 12:12:01 +000049#include <math.h>
plougher8f8e1a12007-10-18 02:50:21 +000050#include <regex.h>
51#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000052#include <sys/wait.h>
plougher1f413c82005-11-18 00:02:14 +000053
plougher68853292005-12-27 02:47:04 +000054#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000055#define __BYTE_ORDER BYTE_ORDER
56#define __BIG_ENDIAN BIG_ENDIAN
57#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000058#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000059#else
60#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000061#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000062#endif
63
plougher1f413c82005-11-18 00:02:14 +000064#ifdef SQUASHFS_TRACE
plougher16111452010-07-22 05:12:18 +000065#define TRACE(s, args...) \
66 do { \
67 if(progress_enabled) \
68 printf("\n"); \
69 printf("mksquashfs: "s, ## args); \
70 } while(0)
plougher1f413c82005-11-18 00:02:14 +000071#else
72#define TRACE(s, args...)
73#endif
74
plougher16111452010-07-22 05:12:18 +000075#define INFO(s, args...) \
76 do {\
77 if(!silent)\
78 printf("mksquashfs: "s, ## args);\
79 } while(0)
80
81#define ERROR(s, args...) \
82 do {\
83 pthread_mutex_lock(&progress_mutex); \
84 if(progress_enabled) \
85 fprintf(stderr, "\n"); \
86 fprintf(stderr, s, ## args);\
87 pthread_mutex_unlock(&progress_mutex); \
88 } while(0)
89
90#define EXIT_MKSQUASHFS() \
91 do {\
92 if(restore)\
93 restorefs();\
94 if(delete && destination_file && !block_device)\
95 unlink(destination_file);\
96 exit(1);\
97 } while(0)
98
99#define BAD_ERROR(s, args...) \
100 do {\
101 pthread_mutex_lock(&progress_mutex); \
102 if(progress_enabled) \
103 fprintf(stderr, "\n"); \
104 fprintf(stderr, "FATAL ERROR:" s, ##args);\
105 pthread_mutex_unlock(&progress_mutex); \
106 EXIT_MKSQUASHFS();\
107 } while(0)
plougher1f413c82005-11-18 00:02:14 +0000108
plougher860c1f32010-08-11 01:37:17 +0000109#include "squashfs_fs.h"
plougher860c1f32010-08-11 01:37:17 +0000110#include "squashfs_swap.h"
111#include "mksquashfs.h"
112#include "sort.h"
113#include "pseudo.h"
114#include "compressor.h"
115#include "xattr.h"
Phillip Lougher4bcb7f82011-08-28 03:18:26 +0100116#include "action.h"
plougher860c1f32010-08-11 01:37:17 +0000117
plougher324978d2006-02-27 04:53:29 +0000118int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000119int fd;
plougher02bc3bc2007-02-25 12:12:01 +0000120int cur_uncompressed = 0, estimated_uncompressed = 0;
121int columns;
plougher1f413c82005-11-18 00:02:14 +0000122
123/* filesystem flags for building */
plougher3d7e5182010-12-25 01:49:42 +0000124int comp_opts = FALSE;
plougher30281c82010-08-25 05:06:11 +0000125int no_xattrs = XATTR_DEF, noX = 0;
plougher1f413c82005-11-18 00:02:14 +0000126int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
plougher6d89ac22010-05-19 02:59:23 +0000127int noI = 0, noD = 0;
plougher1f288f62009-02-21 03:05:52 +0000128int silent = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000129long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +0000130int exportable = TRUE;
131int progress = TRUE;
plougher91fbb302008-05-06 02:29:36 +0000132int progress_enabled = FALSE;
plougher8dcc6992007-08-17 19:32:52 +0000133int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +0000134int old_exclude = TRUE;
135int use_regex = FALSE;
plougher801ba6a2010-02-01 03:12:59 +0000136int first_freelist = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000137
138/* superblock attributes */
139int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +0000140unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +0000141int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
142 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +0000143
144/* write position within data section */
145long long bytes = 0, total_bytes = 0;
146
147/* in memory directory table - possibly compressed */
148char *directory_table = NULL;
149unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
150
151/* cached directory table */
152char *directory_data_cache = NULL;
153unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
154
155/* in memory inode table - possibly compressed */
156char *inode_table = NULL;
157unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
158
159/* cached inode table */
160char *data_cache = NULL;
161unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
162
plougher0e453652006-11-06 01:49:35 +0000163/* inode lookup table */
164squashfs_inode *inode_lookup_table = NULL;
165
plougher1f413c82005-11-18 00:02:14 +0000166/* in memory directory data */
167#define I_COUNT_SIZE 128
168#define DIR_ENTRIES 32
169#define INODE_HASH_SIZE 65536
170#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
171#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
172
173struct cached_dir_index {
plougher2bd2b722010-12-31 10:52:15 +0000174 struct squashfs_dir_index index;
175 char *name;
plougher1f413c82005-11-18 00:02:14 +0000176};
177
178struct directory {
179 unsigned int start_block;
180 unsigned int size;
181 unsigned char *buff;
182 unsigned char *p;
183 unsigned int entry_count;
184 unsigned char *entry_count_p;
185 unsigned int i_count;
186 unsigned int i_size;
187 struct cached_dir_index *index;
188 unsigned char *index_count_p;
189 unsigned int inode_number;
190};
191
plougher1f413c82005-11-18 00:02:14 +0000192struct inode_info *inode_info[INODE_HASH_SIZE];
193
194/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000195struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000196int dup_files = 0;
197
plougher8f8e1a12007-10-18 02:50:21 +0000198/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000199/* list of exclude dirs/files */
200struct exclude_info {
201 dev_t st_dev;
202 ino_t st_ino;
203};
204
205#define EXCLUDE_SIZE 8192
206int exclude = 0;
207struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000208int old_excluded(char *filename, struct stat *buf);
209
210struct path_entry {
211 char *name;
212 regex_t *preg;
213 struct pathname *paths;
214};
215
216struct pathname {
217 int names;
218 struct path_entry *name;
219};
220
plougherf9039c92007-10-22 03:54:16 +0000221struct pathnames {
222 int count;
223 struct pathname *path[0];
224};
225#define PATHS_ALLOC_SIZE 10
226
227struct pathnames *paths = NULL;
228struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000229struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000230int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000231
232/* fragment block data structures */
233int fragments = 0;
plougher76c64082008-03-08 01:32:23 +0000234
plougher1f413c82005-11-18 00:02:14 +0000235struct fragment {
236 unsigned int index;
237 int offset;
238 int size;
239};
plougher76c64082008-03-08 01:32:23 +0000240
plougher1f413c82005-11-18 00:02:14 +0000241#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000242#define FRAG_INDEX (1LL << 32)
243
plougher8ed84b92010-12-31 10:37:24 +0000244struct squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000245int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000246
plougher1f413c82005-11-18 00:02:14 +0000247/* current inode number for directories and non directories */
248unsigned int dir_inode_no = 1;
249unsigned int inode_no = 0;
plougherdf70c3e2006-01-27 09:34:13 +0000250unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000251
252/* list of source dirs/files */
253int source = 0;
254char **source_path;
255
256/* list of root directory entries read from original filesystem */
257int old_root_entries = 0;
258struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000259 char *name;
260 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000261};
262struct old_root_entry_info *old_root_entry;
263
264/* in memory file info */
265struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000266 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000267 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000268 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000269 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000270 long long start;
271 unsigned int *block_list;
272 struct file_info *next;
273 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000274 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000275};
276
277/* count of how many times SIGINT or SIGQUIT has been sent */
278int interrupted = 0;
279
plougher875bfef2010-08-12 23:48:41 +0000280/* flag if we're restoring existing filesystem */
281int restoring = 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;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100315 struct file_buffer *hash_next;
316 struct file_buffer *hash_prev;
317 struct file_buffer *free_next;
318 struct file_buffer *free_prev;
319 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000320 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000321 long long index;
322 long long block;
plougher0f464442008-03-31 00:27:56 +0000323 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000324 int size;
325 int c_byte;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100326 char keep;
327 char used;
328 char fragment;
329 char error;
Phillip Lougher63f531f2011-09-10 04:03:32 +0100330 char noD;
plougher76c64082008-03-08 01:32:23 +0000331 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000332};
333
ploughereb6eac92008-02-26 01:50:48 +0000334
plougher5507dd92006-11-06 00:43:10 +0000335/* struct describing queues used to pass data between threads */
336struct queue {
337 int size;
338 int readp;
339 int writep;
340 pthread_mutex_t mutex;
341 pthread_cond_t empty;
342 pthread_cond_t full;
343 void **data;
344};
345
plougher1b899fc2008-08-07 01:24:06 +0000346
347/* in memory uid tables */
348#define ID_ENTRIES 256
349#define ID_HASH(id) (id & (ID_ENTRIES - 1))
350#define ISA_UID 1
351#define ISA_GID 2
352struct id {
353 unsigned int id;
354 int index;
355 char flags;
356 struct id *next;
plougher5507dd92006-11-06 00:43:10 +0000357};
plougher1b899fc2008-08-07 01:24:06 +0000358struct id *id_hash_table[ID_ENTRIES];
359struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
360unsigned int uid_count = 0, guid_count = 0;
361unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000362
ploughereb6eac92008-02-26 01:50:48 +0000363struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougherfd57dfe2009-03-30 01:17:52 +0000364struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
365 *to_frag;
plougher91fbb302008-05-06 02:29:36 +0000366pthread_t *thread, *deflator_thread, *frag_deflator_thread, progress_thread;
plougher5507dd92006-11-06 00:43:10 +0000367pthread_mutex_t fragment_mutex;
368pthread_cond_t fragment_waiting;
369pthread_mutex_t pos_mutex;
plougher35a10602008-04-21 02:58:16 +0000370pthread_mutex_t progress_mutex;
371pthread_cond_t progress_wait;
372int rotate = 0;
plougher43244f22009-04-05 02:04:51 +0000373struct pseudo *pseudo = NULL;
plougher5507dd92006-11-06 00:43:10 +0000374
375/* user options that control parallelisation */
376int processors = -1;
377/* default size of output buffer in Mbytes */
378#define WRITER_BUFFER_DEFAULT 512
379/* default size of input buffer in Mbytes */
380#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000381/* default size of fragment buffer in Mbytes */
382#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000383int writer_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000384
plougherc5d59872010-11-22 01:36:01 +0000385/* compression operations */
ploughera175ce22009-07-30 04:43:27 +0000386static struct compressor *comp;
plougherc5d59872010-11-22 01:36:01 +0000387int compressor_opts_parsed = 0;
plougher13fdddf2010-11-24 01:23:41 +0000388void *stream = NULL;
plougher7b8ee502009-07-29 07:54:30 +0000389
plougher860c1f32010-08-11 01:37:17 +0000390/* xattr stats */
391unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
392
plougher49b57a92009-03-31 03:23:05 +0000393char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000394void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
395 int type);
plougher64e83fd2010-12-31 21:21:26 +0000396extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
ploughera175ce22009-07-30 04:43:27 +0000397 char *source);
plougherfd57dfe2009-03-30 01:17:52 +0000398extern long long read_filesystem(char *root_name, int fd,
plougher64e83fd2010-12-31 21:21:26 +0000399 struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
plougherfd57dfe2009-03-30 01:17:52 +0000400 char **cdirectory_table, char **directory_data_cache,
401 unsigned int *last_directory_block, unsigned int *inode_dir_offset,
402 unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
403 unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
404 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
405 long long *uncompressed_file, unsigned int *uncompressed_inode,
plougher50b31762009-03-31 04:14:46 +0000406 unsigned int *uncompressed_directory,
407 unsigned int *inode_dir_inode_number,
408 unsigned int *inode_dir_parent_inode,
plougherfd57dfe2009-03-30 01:17:52 +0000409 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher8ed84b92010-12-31 10:37:24 +0000410 struct squashfs_fragment_entry **fragment_table,
plougherfd57dfe2009-03-30 01:17:52 +0000411 squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000412extern int read_sort_file(char *filename, int source, char *source_path[]);
413extern void sort_files_and_write(struct dir_info *dir);
plougherfd57dfe2009-03-30 01:17:52 +0000414struct file_info *duplicate(long long file_size, long long bytes,
415 unsigned int **block_list, long long *start, struct fragment **fragment,
416 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
417 unsigned short fragment_checksum, int checksum_flag);
418struct dir_info *dir_scan1(char *, struct pathnames *, int (_readdir)(char *,
Phillip Lougher0b5a1242011-12-25 03:22:42 +0000419 char *, struct dir_info *), int);
420struct dir_info *dir_scan2(struct dir_info *dir, struct pseudo *pseudo, int);
plougher43244f22009-04-05 02:04:51 +0000421void dir_scan3(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000422struct file_info *add_non_dup(long long file_size, long long bytes,
423 unsigned int *block_list, long long start, struct fragment *fragment,
424 unsigned short checksum, unsigned short fragment_checksum,
425 int checksum_flag);
plougher1d1c6bb2010-07-21 03:03:13 +0000426extern int generate_file_priorities(struct dir_info *dir, int priority,
plougherfd57dfe2009-03-30 01:17:52 +0000427 struct stat *buf);
plougher5507dd92006-11-06 00:43:10 +0000428extern struct priority_entry *priority_list[65536];
plougher35a10602008-04-21 02:58:16 +0000429void progress_bar(long long current, long long max, int columns);
ploughera0a49c32010-08-11 01:47:59 +0000430long long generic_write_table(int, void *, int, void *, int);
plougherca61d1c2010-07-20 18:32:32 +0000431void restorefs();
plougher5507dd92006-11-06 00:43:10 +0000432
433
plougher5507dd92006-11-06 00:43:10 +0000434struct queue *queue_init(int size)
435{
436 struct queue *queue = malloc(sizeof(struct queue));
437
438 if(queue == NULL)
plougherca61d1c2010-07-20 18:32:32 +0000439 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000440
plougher0d55d9e2010-12-16 04:50:21 +0000441 queue->data = malloc(sizeof(void *) * (size + 1));
442 if(queue->data == NULL) {
plougher5507dd92006-11-06 00:43:10 +0000443 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
plougher875bfef2010-08-12 23:48:41 +0000754 if(restoring++)
755 /*
plougher5b290d22010-08-12 23:52:21 +0000756 * Recursive failure when trying to restore filesystem!
757 * Nothing to do except to exit, otherwise we'll just appear
plougher875bfef2010-08-12 23:48:41 +0000758 * to hang. The user should be able to restore from the
plougher5b290d22010-08-12 23:52:21 +0000759 * recovery file (which is why it was added, in case of
760 * catastrophic failure in Mksquashfs)
plougher875bfef2010-08-12 23:48:41 +0000761 */
762 exit(1);
763
plougher1f413c82005-11-18 00:02:14 +0000764 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000765
plougher91fbb302008-05-06 02:29:36 +0000766 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000767 if(thread[i])
768 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000769 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000770 waitforthread(i);
771 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000772 bytes = sbytes;
773 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000774 memcpy(directory_data_cache, sdirectory_data_cache,
775 sdirectory_cache_bytes);
776 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000777 inode_bytes = sinode_bytes;
778 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000779 memcpy(directory_table + directory_bytes, sdirectory_compressed,
780 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000781 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000782 total_bytes = stotal_bytes;
783 total_inode_bytes = stotal_inode_bytes;
784 total_directory_bytes = stotal_directory_bytes;
785 inode_count = sinode_count;
786 file_count = sfile_count;
787 sym_count = ssym_count;
788 dev_count = sdev_count;
789 dir_count = sdir_count;
790 fifo_count = sfifo_count;
791 sock_count = ssock_count;
792 dup_files = sdup_files;
793 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000794 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000795 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000796 longjmp(env, 1);
797}
798
799
800void sighandler()
801{
plougher5507dd92006-11-06 00:43:10 +0000802 if(++interrupted > 2)
803 return;
804 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000805 restorefs();
806 else {
807 ERROR("Interrupting will restore original filesystem!\n");
808 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000809 }
810}
811
812
plougher324978d2006-02-27 04:53:29 +0000813void sighandler2()
814{
815 EXIT_MKSQUASHFS();
816}
817
818
plougher5507dd92006-11-06 00:43:10 +0000819void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000820{
plougher5507dd92006-11-06 00:43:10 +0000821 int i;
822 sigset_t sigmask;
823 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000824
plougher5507dd92006-11-06 00:43:10 +0000825 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
826 thread[i] = (pthread_t) 0;
827
plougher07966f72007-11-14 10:54:45 +0000828 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000829
830 sigemptyset(&sigmask);
831 sigaddset(&sigmask, SIGINT);
832 sigaddset(&sigmask, SIGQUIT);
833 sigaddset(&sigmask, SIGUSR1);
834 while(1) {
835 sigsuspend(&sigmask);
836 TRACE("After wait in sigusr1_handler :(\n");
837 }
838}
839
840
plougher02bc3bc2007-02-25 12:12:01 +0000841void sigwinch_handler()
842{
843 struct winsize winsize;
844
845 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
plougher1d878662009-03-29 23:02:00 +0000846 if(isatty(STDOUT_FILENO))
plougherfd57dfe2009-03-30 01:17:52 +0000847 printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
848 "columns\n");
plougher02bc3bc2007-02-25 12:12:01 +0000849 columns = 80;
850 } else
851 columns = winsize.ws_col;
852}
853
854
plougher35a10602008-04-21 02:58:16 +0000855void sigalrm_handler()
856{
857 rotate = (rotate + 1) % 4;
858}
859
860
plougher13fdddf2010-11-24 01:23:41 +0000861int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000862 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000863{
plougher7b8ee502009-07-29 07:54:30 +0000864 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000865
plougher7b8ee502009-07-29 07:54:30 +0000866 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000867 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
868 &error);
plougher7b8ee502009-07-29 07:54:30 +0000869 if(c_byte == -1)
870 BAD_ERROR("mangle2:: %s compress failed with error "
871 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000872 }
873
plougher7b8ee502009-07-29 07:54:30 +0000874 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000875 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000876 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
877 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000878 }
879
plougher7b8ee502009-07-29 07:54:30 +0000880 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000881}
882
883
plougher7b8ee502009-07-29 07:54:30 +0000884int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000885 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000886{
plougher13fdddf2010-11-24 01:23:41 +0000887 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000888 data_block);
plougher5507dd92006-11-06 00:43:10 +0000889}
890
891
plougherac28cd12010-02-24 02:25:03 +0000892void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000893{
894 int data_space;
895 unsigned short c_byte;
896
897 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000898 if((inode_size - inode_bytes) <
899 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000900 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000901 (SQUASHFS_METADATA_SIZE << 1) + 2);
plougher1eb2a662010-07-26 17:30:50 +0000902 if(it == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000903 goto failed;
904 }
plougher1eb2a662010-07-26 17:30:50 +0000905 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000906 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
907 }
908
plougherfd57dfe2009-03-30 01:17:52 +0000909 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000910 data_cache, SQUASHFS_METADATA_SIZE,
911 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000912 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000913 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000914 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
915 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000916 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000917 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000918 cache_bytes -= SQUASHFS_METADATA_SIZE;
919 }
920
921 data_space = (cache_size - cache_bytes);
922 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000923 int realloc_size = cache_size == 0 ?
924 ((req_size + SQUASHFS_METADATA_SIZE) &
925 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
926 data_space;
plougher1f413c82005-11-18 00:02:14 +0000927
plougher17248ca2010-07-27 00:24:35 +0000928 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000929 realloc_size);
plougher17248ca2010-07-27 00:24:35 +0000930 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000931 goto failed;
932 }
933 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000934 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000935 }
936
937 cache_bytes += req_size;
938
plougherac28cd12010-02-24 02:25:03 +0000939 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000940
941failed:
942 BAD_ERROR("Out of memory in inode table reallocation!\n");
943}
944
945
plougher8a8c4102009-03-29 22:28:49 +0000946int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000947{
948 int res, count;
949
950 for(count = 0; count < bytes; count += res) {
951 res = read(fd, buff + count, bytes - count);
952 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000953 if(res == 0)
954 goto bytes_read;
955 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000956 ERROR("Read failed because %s\n",
957 strerror(errno));
958 return -1;
959 } else
960 res = 0;
961 }
962 }
963
964bytes_read:
965 return count;
966}
967
968
plougher3306cb22010-06-18 04:22:44 +0000969int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000970{
971 off_t off = byte;
972
plougher1d065e92010-06-18 03:58:27 +0000973 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000974 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000975
plougher5507dd92006-11-06 00:43:10 +0000976 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000977 if(lseek(fd, off, SEEK_SET) == -1) {
978 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000979 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000980 goto failed;
981 }
plougher1f413c82005-11-18 00:02:14 +0000982
plougher1d065e92010-06-18 03:58:27 +0000983 if(read_bytes(fd, buff, bytes) < bytes) {
984 ERROR("Read on destination failed\n");
985 goto failed;
986 }
987
plougher5507dd92006-11-06 00:43:10 +0000988 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000989 return 1;
990
991failed:
992 pthread_mutex_unlock(&pos_mutex);
993 return 0;
plougher1f413c82005-11-18 00:02:14 +0000994}
995
996
plougher628e7682009-03-29 22:12:24 +0000997int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000998{
999 int res, count;
1000
1001 for(count = 0; count < bytes; count += res) {
1002 res = write(fd, buff + count, bytes - count);
1003 if(res == -1) {
1004 if(errno != EINTR) {
1005 ERROR("Write failed because %s\n",
1006 strerror(errno));
1007 return -1;
1008 }
1009 res = 0;
1010 }
1011 }
1012
1013 return 0;
1014}
1015
1016
plougher29e2ace2010-12-31 08:50:00 +00001017void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +00001018{
1019 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +00001020
plougher875bfef2010-08-12 23:48:41 +00001021 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +00001022 pthread_mutex_lock(&pos_mutex);
1023
plougher91fbb302008-05-06 02:29:36 +00001024 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +00001025 BAD_ERROR("Lseek on destination failed because %s\n",
1026 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00001027
plougher0dd6f122009-03-29 21:43:57 +00001028 if(write_bytes(fd, buff, bytes) == -1)
1029 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +00001030
plougher875bfef2010-08-12 23:48:41 +00001031 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +00001032 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +00001033}
1034
1035
1036long long write_inodes()
1037{
1038 unsigned short c_byte;
1039 int avail_bytes;
1040 char *datap = data_cache;
1041 long long start_bytes = bytes;
1042
1043 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001044 if(inode_size - inode_bytes <
1045 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +00001046 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +00001047 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +00001048 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001049 BAD_ERROR("Out of memory in inode table "
1050 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001051 }
1052 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +00001053 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +00001054 }
plougherfd57dfe2009-03-30 01:17:52 +00001055 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
1056 SQUASHFS_METADATA_SIZE : cache_bytes;
1057 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
1058 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001059 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +00001060 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +00001061 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
1062 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001063 datap += avail_bytes;
1064 cache_bytes -= avail_bytes;
1065 }
1066
plougher29e2ace2010-12-31 08:50:00 +00001067 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +00001068 bytes += inode_bytes;
1069
1070 return start_bytes;
1071}
1072
1073
1074long long write_directories()
1075{
1076 unsigned short c_byte;
1077 int avail_bytes;
1078 char *directoryp = directory_data_cache;
1079 long long start_bytes = bytes;
1080
1081 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001082 if(directory_size - directory_bytes <
1083 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001084 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001085 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1086 + 2));
plougher79d665a2010-07-27 00:19:23 +00001087 if(dt == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001088 BAD_ERROR("Out of memory in directory table "
1089 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001090 }
1091 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001092 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001093 }
plougherfd57dfe2009-03-30 01:17:52 +00001094 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1095 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001096 c_byte = mangle(directory_table + directory_bytes +
1097 BLOCK_OFFSET, directoryp, avail_bytes,
1098 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001099 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1100 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001101 SQUASHFS_SWAP_SHORTS(&c_byte,
1102 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001103 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1104 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001105 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001106 directoryp += avail_bytes;
1107 directory_cache_bytes -= avail_bytes;
1108 }
plougher29e2ace2010-12-31 08:50:00 +00001109 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +00001110 bytes += directory_bytes;
1111
1112 return start_bytes;
1113}
1114
1115
plougher1b899fc2008-08-07 01:24:06 +00001116long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001117{
plougher1b899fc2008-08-07 01:24:06 +00001118 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001119 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001120 int i;
1121
plougher1b899fc2008-08-07 01:24:06 +00001122 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001123 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001124 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001125 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001126 }
1127
ploughera0a49c32010-08-11 01:47:59 +00001128 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001129}
1130
1131
plougher1b899fc2008-08-07 01:24:06 +00001132struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001133{
plougher1b899fc2008-08-07 01:24:06 +00001134 int hash = ID_HASH(id);
1135 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001136
plougher1b899fc2008-08-07 01:24:06 +00001137 for(; entry; entry = entry->next)
1138 if(entry->id == id)
1139 break;
plougher1f413c82005-11-18 00:02:14 +00001140
plougher1b899fc2008-08-07 01:24:06 +00001141 return entry;
plougher1f413c82005-11-18 00:02:14 +00001142}
1143
1144
plougher1b899fc2008-08-07 01:24:06 +00001145struct id *create_id(unsigned int id)
1146{
1147 int hash = ID_HASH(id);
1148 struct id *entry = malloc(sizeof(struct id));
1149 if(entry == NULL)
1150 BAD_ERROR("Out of memory in create_id\n");
1151 entry->id = id;
1152 entry->index = id_count ++;
1153 entry->flags = 0;
1154 entry->next = id_hash_table[hash];
1155 id_hash_table[hash] = entry;
1156 id_table[entry->index] = entry;
1157 return entry;
1158}
1159
1160
1161unsigned int get_uid(unsigned int uid)
1162{
1163 struct id *entry = get_id(uid);
1164
1165 if(entry == NULL) {
1166 if(id_count == SQUASHFS_IDS)
1167 BAD_ERROR("Out of uids!\n");
1168 entry = create_id(uid);
1169 }
1170
1171 if((entry->flags & ISA_UID) == 0) {
1172 entry->flags |= ISA_UID;
1173 uid_count ++;
1174 }
1175
1176 return entry->index;
1177}
1178
1179
1180unsigned int get_guid(unsigned int guid)
1181{
1182 struct id *entry = get_id(guid);
1183
1184 if(entry == NULL) {
1185 if(id_count == SQUASHFS_IDS)
1186 BAD_ERROR("Out of gids!\n");
1187 entry = create_id(guid);
1188 }
1189
1190 if((entry->flags & ISA_GID) == 0) {
1191 entry->flags |= ISA_GID;
1192 guid_count ++;
1193 }
1194
1195 return entry->index;
1196}
1197
1198
plougher3c6bdb52010-05-01 02:30:59 +00001199int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1200 struct dir_ent *dir_ent, int type, long long byte_size,
1201 long long start_block, unsigned int offset, unsigned int *block_list,
1202 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001203{
1204 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +00001205 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +00001206 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +00001207 void *inode;
plougher1f413c82005-11-18 00:02:14 +00001208 char *filename = dir_ent->pathname;
1209 int nlink = dir_ent->inode->nlink;
plougher3c6bdb52010-05-01 02:30:59 +00001210 int inode_number = type == SQUASHFS_DIR_TYPE ?
1211 dir_ent->inode->inode_number :
plougherfd57dfe2009-03-30 01:17:52 +00001212 dir_ent->inode->inode_number + dir_inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001213 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001214
ploughere6e0e1b2010-05-12 17:17:06 +00001215 switch(type) {
1216 case SQUASHFS_FILE_TYPE:
1217 if(dir_ent->inode->nlink > 1 ||
1218 byte_size >= (1LL << 32) ||
1219 start_block >= (1LL << 32) ||
1220 sparse || IS_XATTR(xattr))
1221 type = SQUASHFS_LREG_TYPE;
1222 break;
1223 case SQUASHFS_DIR_TYPE:
1224 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1225 type = SQUASHFS_LDIR_TYPE;
1226 break;
1227 case SQUASHFS_SYMLINK_TYPE:
1228 if(IS_XATTR(xattr))
1229 type = SQUASHFS_LSYMLINK_TYPE;
1230 break;
1231 case SQUASHFS_BLKDEV_TYPE:
1232 if(IS_XATTR(xattr))
1233 type = SQUASHFS_LBLKDEV_TYPE;
1234 break;
1235 case SQUASHFS_CHRDEV_TYPE:
1236 if(IS_XATTR(xattr))
1237 type = SQUASHFS_LCHRDEV_TYPE;
1238 break;
plougherc5d69322010-05-12 19:28:38 +00001239 case SQUASHFS_FIFO_TYPE:
1240 if(IS_XATTR(xattr))
1241 type = SQUASHFS_LFIFO_TYPE;
1242 break;
1243 case SQUASHFS_SOCKET_TYPE:
1244 if(IS_XATTR(xattr))
1245 type = SQUASHFS_LSOCKET_TYPE;
1246 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001247 }
1248
plougher1f413c82005-11-18 00:02:14 +00001249 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001250 base->uid = get_uid((unsigned int) global_uid == -1 ?
1251 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001252 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001253 base->guid = get_guid((unsigned int) global_gid == -1 ?
1254 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001255 base->mtime = buf->st_mtime;
1256 base->inode_number = inode_number;
1257
1258 if(type == SQUASHFS_FILE_TYPE) {
1259 int i;
plougher8701ed62010-12-31 20:38:38 +00001260 struct squashfs_reg_inode_header *reg = &inode_header.reg;
1261 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001262
1263 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001264 reg->file_size = byte_size;
1265 reg->start_block = start_block;
1266 reg->fragment = fragment->index;
1267 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001268 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1269 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001270 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1271 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001272 start_block, offset, fragment->index, fragment->offset,
1273 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001274 for(i = 0; i < offset; i++)
1275 TRACE("Block %d, size %d\n", i, block_list[i]);
1276 }
1277 else if(type == SQUASHFS_LREG_TYPE) {
1278 int i;
plougher1e6ac4a2010-12-31 20:42:02 +00001279 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1280 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001281
1282 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001283 reg->nlink = nlink;
1284 reg->file_size = byte_size;
1285 reg->start_block = start_block;
1286 reg->fragment = fragment->index;
1287 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001288 if(sparse && sparse >= byte_size)
1289 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001290 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001291 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001292 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1293 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001294 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001295 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1296 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001297 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001298 for(i = 0; i < offset; i++)
1299 TRACE("Block %d, size %d\n", i, block_list[i]);
1300 }
1301 else if(type == SQUASHFS_LDIR_TYPE) {
1302 int i;
1303 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +00001304 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001305 struct cached_dir_index *index = dir_in->index;
1306 unsigned int i_count = dir_in->i_count;
1307 unsigned int i_size = dir_in->i_size;
1308
1309 if(byte_size >= 1 << 27)
1310 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1311
1312 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001313 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001314 dir->nlink = dir_ent->dir->directory_count + 2;
1315 dir->file_size = byte_size;
1316 dir->offset = offset;
1317 dir->start_block = start_block;
1318 dir->i_count = i_count;
plougherfd57dfe2009-03-30 01:17:52 +00001319 dir->parent_inode = dir_ent->our_dir ?
1320 dir_ent->our_dir->dir_ent->inode->inode_number :
1321 dir_inode_no + inode_no;
ploughere6e0e1b2010-05-12 17:17:06 +00001322 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001323
plougherac28cd12010-02-24 02:25:03 +00001324 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +00001325 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001326 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001327 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +00001328 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +00001329 memcpy(p, index[i].name, index[i].index.size + 1);
1330 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001331 }
plougher50b31762009-03-31 04:14:46 +00001332 TRACE("Long directory inode, file_size %lld, start_block "
1333 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1334 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001335 }
1336 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +00001337 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +00001338
1339 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001340 dir->nlink = dir_ent->dir->directory_count + 2;
1341 dir->file_size = byte_size;
1342 dir->offset = offset;
1343 dir->start_block = start_block;
plougherfd57dfe2009-03-30 01:17:52 +00001344 dir->parent_inode = dir_ent->our_dir ?
1345 dir_ent->our_dir->dir_ent->inode->inode_number :
1346 dir_inode_no + inode_no;
plougherac28cd12010-02-24 02:25:03 +00001347 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001348 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001349 "offset 0x%x, nlink %d\n", byte_size, start_block,
1350 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001351 }
1352 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +00001353 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001354 unsigned int major = major(buf->st_rdev);
1355 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001356
plougher5b398502008-10-04 23:22:03 +00001357 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001358 ERROR("Major %d out of range in device node %s, "
1359 "truncating to %d\n", major, filename,
1360 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001361 major &= 0xfff;
1362 }
1363 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001364 ERROR("Minor %d out of range in device node %s, "
1365 "truncating to %d\n", minor, filename,
1366 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001367 minor &= 0xfffff;
1368 }
plougher1f413c82005-11-18 00:02:14 +00001369 inode = get_inode(sizeof(*dev));
1370 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001371 dev->rdev = (major << 8) | (minor & 0xff) |
1372 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001373 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001374 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001375 }
ploughere6e0e1b2010-05-12 17:17:06 +00001376 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001377 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001378 unsigned int major = major(buf->st_rdev);
1379 unsigned int minor = minor(buf->st_rdev);
1380
1381 if(major > 0xfff) {
1382 ERROR("Major %d out of range in device node %s, "
1383 "truncating to %d\n", major, filename,
1384 major & 0xfff);
1385 major &= 0xfff;
1386 }
1387 if(minor > 0xfffff) {
1388 ERROR("Minor %d out of range in device node %s, "
1389 "truncating to %d\n", minor, filename,
1390 minor & 0xfffff);
1391 minor &= 0xfffff;
1392 }
1393 inode = get_inode(sizeof(*dev));
1394 dev->nlink = nlink;
1395 dev->rdev = (major << 8) | (minor & 0xff) |
1396 ((minor & ~0xff) << 12);
1397 dev->xattr = xattr;
1398 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1399 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1400 }
plougher1f413c82005-11-18 00:02:14 +00001401 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001402 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001403 int byte;
1404 char buff[65536];
plougher5ae6e952010-12-31 20:44:34 +00001405 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001406
plougher5cf38b82010-12-16 04:55:32 +00001407 byte = readlink(filename, buff, 65536);
1408 if(byte == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001409 ERROR("Failed to read symlink %s, creating empty "
1410 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001411 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001412 }
1413
1414 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001415 ERROR("Symlink %s is greater than 65536 bytes! "
1416 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001417 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001418 }
1419
1420 inode = get_inode(sizeof(*symlink) + byte);
1421 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001422 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001423 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1424 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001425 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1426 nlink);
plougher1f413c82005-11-18 00:02:14 +00001427 }
ploughere6e0e1b2010-05-12 17:17:06 +00001428 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001429 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001430 int byte;
1431 char buff[65536];
plougher5ae6e952010-12-31 20:44:34 +00001432 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001433
plougherdf2b9aa2010-12-16 04:56:23 +00001434 byte = readlink(filename, buff, 65536);
1435 if(byte == -1) {
ploughere6e0e1b2010-05-12 17:17:06 +00001436 ERROR("Failed to read symlink %s, creating empty "
1437 "symlink\n", filename);
1438 byte = 0;
1439 }
1440
1441 if(byte == 65536) {
1442 ERROR("Symlink %s is greater than 65536 bytes! "
1443 "Creating empty symlink\n", filename);
1444 byte = 0;
1445 }
1446
1447 inode = get_inode(sizeof(*symlink) + byte +
1448 sizeof(unsigned int));
1449 symlink->nlink = nlink;
1450 symlink->symlink_size = byte;
1451 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1452 strncpy(inode + off, buff, byte);
1453 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1454 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1455 nlink);
1456 }
plougher1f413c82005-11-18 00:02:14 +00001457 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001458 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001459
1460 inode = get_inode(sizeof(*ipc));
1461 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001462 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001463 TRACE("ipc inode, type %s, nlink %d\n", type ==
1464 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001465 }
1466 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001467 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001468
1469 inode = get_inode(sizeof(*ipc));
1470 ipc->nlink = nlink;
1471 ipc->xattr = xattr;
1472 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1473 TRACE("ipc inode, type %s, nlink %d\n", type ==
1474 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001475 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001476 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001477
1478 *i_no = MKINODE(inode);
1479 inode_count ++;
1480
plougherfd57dfe2009-03-30 01:17:52 +00001481 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1482 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001483
1484 return TRUE;
1485}
1486
1487
plougher43244f22009-04-05 02:04:51 +00001488void scan3_init_dir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001489{
plougher3bfd71e2010-12-16 04:58:33 +00001490 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
1491 if(dir->buff == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001492 BAD_ERROR("Out of memory allocating directory buffer\n");
1493 }
1494
1495 dir->size = SQUASHFS_METADATA_SIZE;
1496 dir->p = dir->index_count_p = dir->buff;
1497 dir->entry_count = 256;
1498 dir->entry_count_p = NULL;
1499 dir->index = NULL;
1500 dir->i_count = dir->i_size = 0;
1501}
1502
1503
plougher50b31762009-03-31 04:14:46 +00001504void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1505 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001506{
plougher8cb05cd2005-12-11 23:32:35 +00001507 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001508 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001509 unsigned int start_block = inode >> 16;
1510 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001511 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001512 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001513
plougher43d49082010-12-16 05:01:15 +00001514 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001515 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001516 ERROR("Filename is greater than %d characters, truncating! ..."
1517 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001518 }
1519
plougher9b393552010-12-31 20:55:43 +00001520 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001521 sizeof(struct squashfs_dir_header)
1522 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001523 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1524 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001525 BAD_ERROR("Out of memory reallocating directory buffer"
1526 "\n");
plougher1f413c82005-11-18 00:02:14 +00001527 }
1528
1529 dir->p = (dir->p - dir->buff) + buff;
1530 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001531 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1532 buff);
plougher1f413c82005-11-18 00:02:14 +00001533 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1534 dir->buff = buff;
1535 }
1536
plougherfd57dfe2009-03-30 01:17:52 +00001537 if(dir->entry_count == 256 || start_block != dir->start_block ||
1538 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001539 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001540 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001541 ((long long) inode_number - dir->inode_number) > 32767
1542 || ((long long) inode_number - dir->inode_number)
1543 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001544 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001545 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001546
plougher9b393552010-12-31 20:55:43 +00001547 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001548 dir->index_count_p) >
1549 SQUASHFS_METADATA_SIZE) {
1550 if(dir->i_count % I_COUNT_SIZE == 0) {
1551 dir->index = realloc(dir->index,
1552 (dir->i_count + I_COUNT_SIZE) *
1553 sizeof(struct cached_dir_index));
1554 if(dir->index == NULL)
1555 BAD_ERROR("Out of memory in "
1556 "directory index table "
1557 "reallocation!\n");
1558 }
1559 dir->index[dir->i_count].index.index =
1560 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001561 dir->index[dir->i_count].index.size = size - 1;
1562 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001563 dir->i_size += sizeof(struct squashfs_dir_index)
1564 + size;
plougher1f413c82005-11-18 00:02:14 +00001565 dir->index_count_p = dir->p;
1566 }
1567
1568 dir_header.count = dir->entry_count - 1;
1569 dir_header.start_block = dir->start_block;
1570 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001571 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001572 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001573
1574 }
1575
1576
1577 dir->entry_count_p = dir->p;
1578 dir->start_block = start_block;
1579 dir->entry_count = 0;
1580 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001581 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001582 }
1583
plougher1f413c82005-11-18 00:02:14 +00001584 idir.offset = offset;
1585 idir.type = type;
1586 idir.size = size - 1;
1587 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001588 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1589 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001590 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001591 dir->entry_count ++;
1592}
1593
1594
plougherfd57dfe2009-03-30 01:17:52 +00001595void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1596 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001597{
1598 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001599 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001600 unsigned int directory_block, directory_offset, i_count, index;
1601 unsigned short c_byte;
1602
1603 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001604 int realloc_size = directory_cache_size == 0 ?
1605 ((dir_size + SQUASHFS_METADATA_SIZE) &
1606 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001607
plougher17248ca2010-07-27 00:24:35 +00001608 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001609 directory_cache_size + realloc_size);
plougher17248ca2010-07-27 00:24:35 +00001610 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001611 goto failed;
1612 }
1613 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001614 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001615 }
1616
1617 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001618 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001619
1620 dir_header.count = dir->entry_count - 1;
1621 dir_header.start_block = dir->start_block;
1622 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001623 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001624 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1625 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001626 }
1627 directory_offset = directory_cache_bytes;
1628 directory_block = directory_bytes;
1629 directory_cache_bytes += dir_size;
1630 i_count = 0;
1631 index = SQUASHFS_METADATA_SIZE - directory_offset;
1632
1633 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001634 while(i_count < dir->i_count &&
1635 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001636 dir->index[i_count++].index.start_block =
1637 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001638 index += SQUASHFS_METADATA_SIZE;
1639
1640 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1641 break;
1642
plougherfd57dfe2009-03-30 01:17:52 +00001643 if((directory_size - directory_bytes) <
1644 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001645 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001646 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1647 + 2);
plougher79d665a2010-07-27 00:19:23 +00001648 if(dt == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001649 goto failed;
1650 }
1651 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001652 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001653 }
1654
plougher50b31762009-03-31 04:14:46 +00001655 c_byte = mangle(directory_table + directory_bytes +
1656 BLOCK_OFFSET, directory_data_cache,
1657 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1658 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001659 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1660 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001661 SQUASHFS_SWAP_SHORTS(&c_byte,
1662 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001663 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1664 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001665 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001666 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001667 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1668 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001669 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1670 }
1671
plougher3c6bdb52010-05-01 02:30:59 +00001672 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1673 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1674 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001675
1676#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001677 {
plougher1f413c82005-11-18 00:02:14 +00001678 unsigned char *dirp;
1679 int count;
1680
1681 TRACE("Directory contents of inode 0x%llx\n", *inode);
1682 dirp = dir->buff;
1683 while(dirp < dir->p) {
1684 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001685 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001686 struct squashfs_dir_header dirh;
1687 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001688 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001689 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001690 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001691
plougher50b31762009-03-31 04:14:46 +00001692 TRACE("\tStart block 0x%x, count %d\n",
1693 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001694
1695 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001696 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001697 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001698 strncpy(buffer, idirp->name, idir.size + 1);
1699 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001700 TRACE("\t\tname %s, inode offset 0x%x, type "
1701 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001702 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001703 1;
plougher1f413c82005-11-18 00:02:14 +00001704 }
1705 }
1706 }
1707#endif
1708 dir_count ++;
1709
plougher29e37092007-04-15 01:24:51 +00001710 return;
plougher1f413c82005-11-18 00:02:14 +00001711
1712failed:
1713 BAD_ERROR("Out of memory in directory table reallocation!\n");
1714}
1715
1716
plougher76c64082008-03-08 01:32:23 +00001717struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001718{
plougher8ed84b92010-12-31 10:37:24 +00001719 struct squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001720 int res, size;
plougher76c64082008-03-08 01:32:23 +00001721 long long start_block;
1722 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001723
plougher76c64082008-03-08 01:32:23 +00001724 if(fragment->index == SQUASHFS_INVALID_FRAG)
1725 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001726
plougher76c64082008-03-08 01:32:23 +00001727 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001728 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001729 return buffer;
plougher76c64082008-03-08 01:32:23 +00001730
plougherfd57dfe2009-03-30 01:17:52 +00001731 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1732 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001733
plougher76c64082008-03-08 01:32:23 +00001734 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001735
1736 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001737 disk_fragment = &fragment_table[fragment->index];
1738 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001739 start_block = disk_fragment->start_block;
1740 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001741
plougher0f464442008-03-31 00:27:56 +00001742 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001743 int error;
plougher76c64082008-03-08 01:32:23 +00001744 char *data;
plougher1f413c82005-11-18 00:02:14 +00001745
plougher76c64082008-03-08 01:32:23 +00001746 if(compressed_buffer)
1747 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001748 else
1749 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001750
plougherb48442b2010-12-31 07:57:54 +00001751 res = compressor_uncompress(comp, buffer->data, data, size,
1752 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001753 if(res == -1)
1754 BAD_ERROR("%s uncompress failed with error code %d\n",
1755 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001756 } else if(compressed_buffer)
1757 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001758 else {
1759 res = read_fs_bytes(fd, start_block, size, buffer->data);
1760 if(res == 0)
1761 EXIT_MKSQUASHFS();
1762 }
plougher1f413c82005-11-18 00:02:14 +00001763
plougher03859fa2009-03-31 03:18:18 +00001764 cache_block_put(compressed_buffer);
1765
plougher76c64082008-03-08 01:32:23 +00001766 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001767}
1768
plougher2ea89142008-03-11 01:34:19 +00001769
1770struct frag_locked {
1771 struct file_buffer *buffer;
1772 int c_byte;
1773 int fragment;
1774 struct frag_locked *fragment_prev;
1775 struct frag_locked *fragment_next;
1776};
1777
1778int fragments_locked = FALSE;
1779struct frag_locked *frag_locked_list = NULL;
1780
1781INSERT_LIST(fragment, struct frag_locked)
1782REMOVE_LIST(fragment, struct frag_locked)
1783
plougher4e8484a2008-03-15 23:30:16 +00001784int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001785{
plougher4e8484a2008-03-15 23:30:16 +00001786 int count;
plougher5507dd92006-11-06 00:43:10 +00001787 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001788 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001789 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001790 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001791 return count;
plougher2ea89142008-03-11 01:34:19 +00001792}
1793
1794
1795void unlock_fragments()
1796{
1797 struct frag_locked *entry;
1798 int compressed_size;
1799
1800 pthread_mutex_lock(&fragment_mutex);
1801 while(frag_locked_list) {
1802 entry = frag_locked_list;
1803 remove_fragment_list(&frag_locked_list, entry);
1804 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1805 fragment_table[entry->fragment].size = entry->c_byte;
1806 fragment_table[entry->fragment].start_block = bytes;
1807 entry->buffer->block = bytes;
1808 bytes += compressed_size;
1809 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001810 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001811 TRACE("fragment_locked writing fragment %d, compressed size %d"
1812 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001813 free(entry);
1814 }
1815 fragments_locked = FALSE;
1816 pthread_mutex_unlock(&fragment_mutex);
1817}
1818
1819
plougherb7a66812010-07-21 01:06:59 +00001820void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001821 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001822{
1823 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1824 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001825 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001826 entry->buffer = write_buffer;
1827 entry->c_byte = c_byte;
1828 entry->fragment = fragment;
1829 entry->fragment_prev = entry->fragment_next = NULL;
1830 pthread_mutex_lock(&fragment_mutex);
1831 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001832 pthread_mutex_unlock(&fragment_mutex);
1833}
1834
1835
Phillip Lougher04b7b532011-06-11 02:14:15 +01001836void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001837{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001838 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001839 return;
1840
plougher5507dd92006-11-06 00:43:10 +00001841 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001842 fragment_table[fragment->block].unused = 0;
1843 fragments_outstanding ++;
1844 queue_put(to_frag, fragment);
1845 pthread_mutex_unlock(&fragment_mutex);
1846}
1847
1848
1849struct file_buffer *allocate_fragment()
1850{
1851 struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
1852
1853 pthread_mutex_lock(&fragment_mutex);
1854
plougher5507dd92006-11-06 00:43:10 +00001855 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001856 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001857 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001858 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001859 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001860 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001861 }
plougherfa89c332010-07-27 00:27:15 +00001862 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001863 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001864
1865 fragment->size = 0;
1866 fragment->block = fragments ++;
1867
plougher5507dd92006-11-06 00:43:10 +00001868 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001869
1870 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001871}
1872
ploughereb6eac92008-02-26 01:50:48 +00001873
plougher1f413c82005-11-18 00:02:14 +00001874static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001875struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1876 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001877{
1878 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001879 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001880
plougher5507dd92006-11-06 00:43:10 +00001881 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001882 return &empty_fragment;
1883
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001884 fragment = eval_frag_actions(dir_ent);
1885
1886 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1887 write_fragment(*fragment);
1888 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001889 }
plougher1f413c82005-11-18 00:02:14 +00001890
ploughere7e6e832010-12-16 05:08:06 +00001891 ffrg = malloc(sizeof(struct fragment));
1892 if(ffrg == NULL)
plougher1f413c82005-11-18 00:02:14 +00001893 BAD_ERROR("Out of memory in fragment block allocation!\n");
1894
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001895 if(*fragment == NULL)
1896 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001897
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001898 ffrg->index = (*fragment)->block;
1899 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001900 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001901 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001902 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001903 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001904
1905 return ffrg;
1906}
1907
1908
ploughera0a49c32010-08-11 01:47:59 +00001909long long generic_write_table(int length, void *buffer, int length2,
1910 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001911{
plougher17b269c2009-03-30 01:33:07 +00001912 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1913 SQUASHFS_METADATA_SIZE;
plougher0e453652006-11-06 01:49:35 +00001914 long long list[meta_blocks], start_bytes;
plougherbadfac62007-11-12 03:29:41 +00001915 int compressed_size, i;
plougher1f413c82005-11-18 00:02:14 +00001916 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001917 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1918
plougher82ab2332009-04-21 00:21:21 +00001919#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001920 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001921 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001922#endif
plougher1f413c82005-11-18 00:02:14 +00001923
1924 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001925 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1926 SQUASHFS_METADATA_SIZE : length;
1927 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1928 SQUASHFS_METADATA_SIZE , avail_bytes,
1929 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001930 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001931 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001932 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1933 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001934 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1935 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001936 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001937 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001938 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001939 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001940 }
1941
ploughere6e0e1b2010-05-12 17:17:06 +00001942 start_bytes = bytes;
1943 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001944 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001945 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001946 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001947 }
1948
plougher1f288f62009-02-21 03:05:52 +00001949 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
plougher29e2ace2010-12-31 08:50:00 +00001950 write_destination(fd, bytes, sizeof(list), list);
plougher1f413c82005-11-18 00:02:14 +00001951 bytes += sizeof(list);
plougher10f7d572010-07-20 02:14:04 +00001952 total_bytes += sizeof(list);
plougher1f413c82005-11-18 00:02:14 +00001953
plougher40d8b952010-02-12 16:26:32 +00001954 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1955 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001956
plougher1f413c82005-11-18 00:02:14 +00001957 return start_bytes;
1958}
1959
1960
plougher0e453652006-11-06 01:49:35 +00001961long long write_fragment_table()
1962{
1963 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher8ed84b92010-12-31 10:37:24 +00001964 struct squashfs_fragment_entry p[fragments];
plougher0e453652006-11-06 01:49:35 +00001965 int i;
1966
plougher17b269c2009-03-30 01:33:07 +00001967 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1968 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001969 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001970 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1971 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001972 fragment_table[i].size);
plougherac28cd12010-02-24 02:25:03 +00001973 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p + i);
plougher0e453652006-11-06 01:49:35 +00001974 }
1975
ploughera0a49c32010-08-11 01:47:59 +00001976 return generic_write_table(frag_bytes, p, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001977}
1978
1979
plougher1f413c82005-11-18 00:02:14 +00001980char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001981char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001982{
plougher1d065e92010-06-18 03:58:27 +00001983 int res;
1984
1985 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
1986 if(res == 0)
1987 EXIT_MKSQUASHFS();
1988
plougher1f413c82005-11-18 00:02:14 +00001989 return read_from_file_buffer;
1990}
1991
1992
plougher1b899fc2008-08-07 01:24:06 +00001993char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
1994char *read_from_disk2(long long start, unsigned int avail_bytes)
1995{
plougher1d065e92010-06-18 03:58:27 +00001996 int res;
1997
1998 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
1999 if(res == 0)
2000 EXIT_MKSQUASHFS();
2001
plougher1b899fc2008-08-07 01:24:06 +00002002 return read_from_file_buffer2;
2003}
2004
2005
plougher1f413c82005-11-18 00:02:14 +00002006/*
2007 * Compute 16 bit BSD checksum over the data
2008 */
plougher5507dd92006-11-06 00:43:10 +00002009unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00002010{
plougher5507dd92006-11-06 00:43:10 +00002011 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00002012
plougher5507dd92006-11-06 00:43:10 +00002013 while(bytes --) {
2014 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
2015 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00002016 }
2017
2018 return chksum;
2019}
2020
2021
plougher17b269c2009-03-30 01:33:07 +00002022unsigned short get_checksum_disk(long long start, long long l,
2023 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00002024{
2025 unsigned short chksum = 0;
2026 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00002027 struct file_buffer *write_buffer;
2028 int i;
plougher5507dd92006-11-06 00:43:10 +00002029
plougher57e6d182008-05-06 23:51:29 +00002030 for(i = 0; l; i++) {
2031 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2032 if(bytes == 0) /* sparse block */
2033 continue;
2034 write_buffer = cache_lookup(writer_buffer, start);
2035 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002036 chksum = get_checksum(write_buffer->data, bytes,
2037 chksum);
plougher57e6d182008-05-06 23:51:29 +00002038 cache_block_put(write_buffer);
2039 } else
plougher50b31762009-03-31 04:14:46 +00002040 chksum = get_checksum(read_from_disk(start, bytes),
2041 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002042 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002043 start += bytes;
2044 }
2045
2046 return chksum;
2047}
2048
2049
plougher5507dd92006-11-06 00:43:10 +00002050unsigned short get_checksum_mem(char *buff, int bytes)
2051{
2052 return get_checksum(buff, bytes, 0);
2053}
2054
2055
2056unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2057{
2058 if(file_buffer == NULL)
2059 return 0;
2060 else
2061 return get_checksum(file_buffer->data, file_buffer->size, 0);
2062}
2063
2064
plougher5507dd92006-11-06 00:43:10 +00002065#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002066void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002067 unsigned int *block_listp, int blocks, unsigned int fragment,
2068 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002069{
2070 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002071 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002072 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002073
plougher5507dd92006-11-06 00:43:10 +00002074 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002075 return;
2076
plougher5507dd92006-11-06 00:43:10 +00002077 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2078 if(file_size != dupl_ptr->file_size)
2079 continue;
2080 if(blocks != 0 && start != dupl_ptr->start)
2081 continue;
2082 if(fragment != dupl_ptr->fragment->index)
2083 continue;
plougher17b269c2009-03-30 01:33:07 +00002084 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2085 dupl_ptr->fragment->offset || bytes !=
2086 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002087 continue;
2088 return;
2089 }
2090
plougher3bb279c2010-12-16 05:10:03 +00002091 frg = malloc(sizeof(struct fragment));
2092 if(frg == NULL)
plougher1f413c82005-11-18 00:02:14 +00002093 BAD_ERROR("Out of memory in fragment block allocation!\n");
2094
2095 frg->index = fragment;
2096 frg->offset = offset;
2097 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002098
plougher5507dd92006-11-06 00:43:10 +00002099 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2100}
plougher1f413c82005-11-18 00:02:14 +00002101
plougher1f413c82005-11-18 00:02:14 +00002102
plougher5507dd92006-11-06 00:43:10 +00002103int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002104{
plougher5507dd92006-11-06 00:43:10 +00002105 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002106
2107 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002108 if(dupl_ptr->file_size == file_size)
2109 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002110
plougher5507dd92006-11-06 00:43:10 +00002111 return FALSE;
2112}
2113
2114
2115int pre_duplicate_frag(long long file_size, unsigned short checksum)
2116{
2117 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2118
2119 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002120 if(file_size == dupl_ptr->file_size && file_size ==
2121 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002122 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002123 struct file_buffer *frag_buffer =
2124 get_fragment(dupl_ptr->fragment);
2125 dupl_ptr->checksum =
2126 get_checksum_disk(dupl_ptr->start,
2127 dupl_ptr->bytes, dupl_ptr->block_list);
2128 dupl_ptr->fragment_checksum =
2129 get_checksum_mem(frag_buffer->data +
2130 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002131 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002132 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002133 }
plougher5507dd92006-11-06 00:43:10 +00002134 if(dupl_ptr->fragment_checksum == checksum)
2135 return TRUE;
2136 }
plougher1f413c82005-11-18 00:02:14 +00002137
plougher5507dd92006-11-06 00:43:10 +00002138 return FALSE;
2139}
2140
2141
plougher17b269c2009-03-30 01:33:07 +00002142struct file_info *add_non_dup(long long file_size, long long bytes,
2143 unsigned int *block_list, long long start, struct fragment *fragment,
2144 unsigned short checksum, unsigned short fragment_checksum,
2145 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002146{
plougher51ef9ae2010-12-16 05:14:28 +00002147 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00002148
plougher51ef9ae2010-12-16 05:14:28 +00002149 if(dupl_ptr == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002150 BAD_ERROR("Out of memory in dup_files allocation!\n");
2151 }
2152
2153 dupl_ptr->file_size = file_size;
2154 dupl_ptr->bytes = bytes;
2155 dupl_ptr->block_list = block_list;
2156 dupl_ptr->start = start;
2157 dupl_ptr->fragment = fragment;
2158 dupl_ptr->checksum = checksum;
2159 dupl_ptr->fragment_checksum = fragment_checksum;
2160 dupl_ptr->checksum_flag = checksum_flag;
2161 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2162 dupl[DUP_HASH(file_size)] = dupl_ptr;
2163 dup_files ++;
2164
2165 return dupl_ptr;
2166}
2167
2168
plougher17b269c2009-03-30 01:33:07 +00002169struct file_info *duplicate(long long file_size, long long bytes,
2170 unsigned int **block_list, long long *start, struct fragment **fragment,
2171 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2172 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002173{
2174 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2175 int frag_bytes = file_buffer ? file_buffer->size : 0;
2176
2177 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002178 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2179 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002180 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002181 int block;
2182
plougher17b269c2009-03-30 01:33:07 +00002183 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2184 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002185 continue;
2186
plougher5507dd92006-11-06 00:43:10 +00002187 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002188 checksum = get_checksum_disk(*start, bytes,
2189 *block_list);
2190 fragment_checksum =
2191 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002192 checksum_flag = TRUE;
2193 }
2194
2195 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002196 struct file_buffer *frag_buffer =
2197 get_fragment(dupl_ptr->fragment);
2198 dupl_ptr->checksum =
2199 get_checksum_disk(dupl_ptr->start,
2200 dupl_ptr->bytes, dupl_ptr->block_list);
2201 dupl_ptr->fragment_checksum =
2202 get_checksum_mem(frag_buffer->data +
2203 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002204 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002205 dupl_ptr->checksum_flag = TRUE;
2206 }
2207
plougher17b269c2009-03-30 01:33:07 +00002208 if(checksum != dupl_ptr->checksum ||
2209 fragment_checksum !=
2210 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002211 continue;
2212
plougher1b899fc2008-08-07 01:24:06 +00002213 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002214 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002215 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2216 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002217 struct file_buffer *target_buffer = NULL;
2218 struct file_buffer *dup_buffer = NULL;
2219 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002220 int res;
plougher5507dd92006-11-06 00:43:10 +00002221
plougher1b899fc2008-08-07 01:24:06 +00002222 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002223 continue;
plougher17b269c2009-03-30 01:33:07 +00002224 target_buffer = cache_lookup(writer_buffer,
2225 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002226 if(target_buffer)
2227 target_data = target_buffer->data;
2228 else
plougher50b31762009-03-31 04:14:46 +00002229 target_data =
2230 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002231 size);
plougher5507dd92006-11-06 00:43:10 +00002232
plougher360514a2009-03-30 03:01:38 +00002233 dup_buffer = cache_lookup(writer_buffer,
2234 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002235 if(dup_buffer)
2236 dup_data = dup_buffer->data;
2237 else
plougher360514a2009-03-30 03:01:38 +00002238 dup_data = read_from_disk2(dup_start,
2239 size);
plougher1b899fc2008-08-07 01:24:06 +00002240
2241 res = memcmp(target_data, dup_data, size);
2242 cache_block_put(target_buffer);
2243 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002244 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002245 break;
plougher1b899fc2008-08-07 01:24:06 +00002246 target_start += size;
2247 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002248 }
2249 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002250 struct file_buffer *frag_buffer =
2251 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002252
plougher17b269c2009-03-30 01:33:07 +00002253 if(frag_bytes == 0 ||
2254 memcmp(file_buffer->data,
2255 frag_buffer->data +
2256 dupl_ptr->fragment->offset,
2257 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002258 TRACE("Found duplicate file, start "
2259 "0x%llx, size %lld, checksum "
2260 "0x%x, fragment %d, size %d, "
2261 "offset %d, checksum 0x%x\n",
2262 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002263 dupl_ptr->bytes,
2264 dupl_ptr->checksum,
2265 dupl_ptr->fragment->index,
2266 frag_bytes,
2267 dupl_ptr->fragment->offset,
2268 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002269 *block_list = dupl_ptr->block_list;
2270 *start = dupl_ptr->start;
2271 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002272 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002273 return 0;
2274 }
plougher76c64082008-03-08 01:32:23 +00002275 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002276 }
2277 }
2278
2279
plougher17b269c2009-03-30 01:33:07 +00002280 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2281 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002282}
2283
2284
Phillip Lougher2504b082011-09-07 02:28:45 +01002285inline int is_fragment(struct inode_info *inode)
2286{
2287 int file_size = inode->buf.st_size;
2288
Phillip Lougher63f531f2011-09-10 04:03:32 +01002289 /*
2290 * If this block is to be compressed differently to the
2291 * fragment compression then it cannot be a fragment
2292 */
2293 if(inode->noF != noF)
2294 return FALSE;
2295
Phillip Lougher2504b082011-09-07 02:28:45 +01002296 return !inode->no_fragments && (file_size < block_size ||
2297 (inode->always_use_fragments && file_size & (block_size - 1)));
2298}
2299
2300
plougher00d08172009-09-03 10:17:44 +00002301static int seq = 0;
2302void reader_read_process(struct dir_ent *dir_ent)
2303{
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002304 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002305 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002306 int status, res, byte, count = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002307 int file = get_pseudo_file(inode->pseudo_id)->fd;
2308 int child = get_pseudo_file(inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002309 long long bytes = 0;
2310
2311 while(1) {
2312 file_buffer = cache_get(reader_buffer, 0, 0);
2313 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002314 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002315
2316 byte = read_bytes(file, file_buffer->data, block_size);
2317 if(byte == -1)
2318 goto read_err;
2319
2320 file_buffer->size = byte;
2321 file_buffer->file_size = -1;
2322 file_buffer->block = count ++;
2323 file_buffer->error = FALSE;
2324 file_buffer->fragment = FALSE;
2325 bytes += byte;
2326
2327 if(byte == 0)
2328 break;
2329
plougher286b6b32009-09-19 03:29:27 +00002330 /*
2331 * Update estimated_uncompressed block count. This is done
2332 * on every block rather than waiting for all blocks to be
2333 * read incase write_file_process() is running in parallel
2334 * with this. Otherwise cur uncompressed block count may
2335 * get ahead of the total uncompressed block count.
2336 */
2337 estimated_uncompressed ++;
2338
plougher00d08172009-09-03 10:17:44 +00002339 if(prev_buffer)
2340 queue_put(from_reader, prev_buffer);
2341 prev_buffer = file_buffer;
2342 }
2343
plougher54d67292009-09-19 03:26:27 +00002344 /*
2345 * Update inode file size now that the size of the dynamic pseudo file
2346 * is known. This is needed for the -info option.
2347 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002348 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002349
plougherba674e82009-09-10 03:50:00 +00002350 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002351 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002352 goto read_err;
2353
plougher00d08172009-09-03 10:17:44 +00002354 if(prev_buffer == NULL)
2355 prev_buffer = file_buffer;
2356 else {
2357 cache_block_put(file_buffer);
2358 seq --;
2359 }
2360 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002361 prev_buffer->fragment = is_fragment(inode);
plougher00d08172009-09-03 10:17:44 +00002362 queue_put(from_reader, prev_buffer);
2363
2364 return;
2365
2366read_err:
2367 if(prev_buffer) {
2368 cache_block_put(file_buffer);
2369 seq --;
2370 file_buffer = prev_buffer;
2371 }
2372 file_buffer->error = TRUE;
2373 queue_put(from_deflate, file_buffer);
2374}
2375
2376
plougher5507dd92006-11-06 00:43:10 +00002377void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002378{
plougher018d2b32007-04-23 03:01:48 +00002379 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002380 struct file_buffer *file_buffer;
Phillip Lougher2504b082011-09-07 02:28:45 +01002381 int blocks, byte, count, expected, file;
plougher018d2b32007-04-23 03:01:48 +00002382 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002383 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002384
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002385 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002386 return;
2387
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002388 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002389again:
2390 bytes = 0;
2391 count = 0;
2392 file_buffer = NULL;
2393 read_size = buf->st_size;
2394 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002395
plougherc1d258e2010-12-16 05:16:45 +00002396 file = open(dir_ent->pathname, O_RDONLY);
2397 if(file == -1) {
plougher1e380702010-08-11 01:52:49 +00002398 file_buffer = cache_get(reader_buffer, 0, 0);
2399 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002400 goto read_err;
plougher1e380702010-08-11 01:52:49 +00002401 }
plougher5507dd92006-11-06 00:43:10 +00002402
plougher018d2b32007-04-23 03:01:48 +00002403 do {
plougher110799c2009-03-30 01:50:40 +00002404 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002405 block_size ? block_size :
2406 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002407
2408 if(file_buffer)
2409 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002410 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002411 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002412 file_buffer->noD = inode->noD;
plougher5507dd92006-11-06 00:43:10 +00002413
ploughera4c24ed2010-08-11 02:08:38 +00002414 /*
2415 * Always try to read block_size bytes from the file rather
2416 * than expected bytes (which will be less than the block_size
2417 * at the file tail) to check that the file hasn't grown
2418 * since being stated. If it is longer (or shorter) than
2419 * expected, then restat, and try again. Note the special
2420 * case where the file is an exact multiple of the block_size
2421 * is dealt with later.
2422 */
plougher110799c2009-03-30 01:50:40 +00002423 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2424 block_size);
plougher018d2b32007-04-23 03:01:48 +00002425
plougher018d2b32007-04-23 03:01:48 +00002426 file_buffer->file_size = read_size;
2427
ploughera4c24ed2010-08-11 02:08:38 +00002428 if(byte == -1)
2429 goto read_err;
2430
plougher018d2b32007-04-23 03:01:48 +00002431 if(byte != expected)
2432 goto restat;
2433
2434 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002435 file_buffer->error = FALSE;
Phillip Lougher2504b082011-09-07 02:28:45 +01002436 file_buffer->fragment = FALSE;
plougher018d2b32007-04-23 03:01:48 +00002437
2438 bytes += byte;
2439 count ++;
2440 } while(count < blocks);
2441
2442 if(read_size != bytes)
2443 goto restat;
2444
2445 if(expected == block_size) {
ploughera4c24ed2010-08-11 02:08:38 +00002446 /*
2447 * Special case where we've not tried to read past the end of
2448 * the file. We expect to get EOF, i.e. the file isn't larger
2449 * than we expect.
2450 */
plougher018d2b32007-04-23 03:01:48 +00002451 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002452 int res;
plougher018d2b32007-04-23 03:01:48 +00002453
ploughera4c24ed2010-08-11 02:08:38 +00002454 res = read_bytes(file, &buffer, 1);
2455 if(res == -1)
2456 goto read_err;
2457
2458 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002459 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002460 }
2461
Phillip Lougher2504b082011-09-07 02:28:45 +01002462 file_buffer->fragment = is_fragment(inode);
plougher1b899fc2008-08-07 01:24:06 +00002463 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002464
plougher5507dd92006-11-06 00:43:10 +00002465 close(file);
plougher5507dd92006-11-06 00:43:10 +00002466
2467 return;
2468
plougher018d2b32007-04-23 03:01:48 +00002469restat:
2470 fstat(file, &buf2);
2471 close(file);
2472 if(read_size != buf2.st_size) {
2473 memcpy(buf, &buf2, sizeof(struct stat));
2474 file_buffer->error = 2;
2475 queue_put(from_deflate, file_buffer);
2476 goto again;
2477 }
plougher1e380702010-08-11 01:52:49 +00002478read_err:
2479 file_buffer->error = TRUE;
2480 queue_put(from_deflate, file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002481}
2482
2483
2484void reader_scan(struct dir_info *dir) {
2485 int i;
2486
2487 for(i = 0; i < dir->count; i++) {
2488 struct dir_ent *dir_ent = dir->list[i];
2489 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002490 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002491 continue;
2492
plougherb3977eb2010-05-02 02:08:48 +00002493 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002494 reader_read_process(dir_ent);
2495 continue;
2496 }
2497
plougher5507dd92006-11-06 00:43:10 +00002498 switch(buf->st_mode & S_IFMT) {
2499 case S_IFREG:
2500 reader_read_file(dir_ent);
2501 break;
2502 case S_IFDIR:
2503 reader_scan(dir_ent->dir);
2504 break;
2505 }
2506 }
2507}
2508
2509
2510void *reader(void *arg)
2511{
2512 int oldstate;
2513
2514 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2515 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2516
2517 if(!sorted)
2518 reader_scan(queue_get(to_reader));
2519 else {
2520 int i;
2521 struct priority_entry *entry;
2522
2523 queue_get(to_reader);
2524 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002525 for(entry = priority_list[i]; entry;
2526 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002527 reader_read_file(entry->dir);
2528 }
rloughere4873e02007-11-08 17:50:42 +00002529
plougher5aa18162007-12-13 12:15:21 +00002530 thread[0] = 0;
2531
rloughere4873e02007-11-08 17:50:42 +00002532 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002533}
2534
2535
2536void *writer(void *arg)
2537{
2538 int write_error = FALSE;
2539 int oldstate;
2540
2541 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2542 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2543
2544 while(1) {
2545 struct file_buffer *file_buffer = queue_get(to_writer);
2546 off_t off;
2547
2548 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002549 queue_put(from_writer,
plougherc2a5ae12010-12-31 08:35:28 +00002550 write_error ? &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002551 continue;
2552 }
2553
2554 off = file_buffer->block;
2555
2556 pthread_mutex_lock(&pos_mutex);
2557
2558 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002559 ERROR("Lseek on destination failed because %s\n",
2560 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002561 write_error = TRUE;
2562 }
2563
plougher110799c2009-03-30 01:50:40 +00002564 if(!write_error && write_bytes(fd, file_buffer->data,
2565 file_buffer->size) == -1) {
2566 ERROR("Write on destination failed because %s\n",
2567 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002568 write_error = TRUE;
2569 }
2570 pthread_mutex_unlock(&pos_mutex);
2571
ploughereb6eac92008-02-26 01:50:48 +00002572 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002573 }
2574}
2575
2576
plougher5b09fd42007-08-06 10:28:41 +00002577int all_zero(struct file_buffer *file_buffer)
2578{
2579 int i;
2580 long entries = file_buffer->size / sizeof(long);
2581 long *p = (long *) file_buffer->data;
2582
2583 for(i = 0; i < entries && p[i] == 0; i++);
2584
2585 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002586 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002587 i < file_buffer->size && file_buffer->data[i] == 0;
2588 i++);
plougher5b09fd42007-08-06 10:28:41 +00002589
2590 return i == file_buffer->size;
2591 }
2592
2593 return 0;
2594}
2595
2596
plougher5507dd92006-11-06 00:43:10 +00002597void *deflator(void *arg)
2598{
plougher7b8ee502009-07-29 07:54:30 +00002599 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002600 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002601
2602 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2603 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2604
plougher13fdddf2010-11-24 01:23:41 +00002605 res = compressor_init(comp, &stream, block_size, 1);
2606 if(res)
2607 BAD_ERROR("deflator:: compressor_init failed\n");
2608
plougher5507dd92006-11-06 00:43:10 +00002609 while(1) {
2610 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002611 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002612
Phillip Lougher48854382011-09-09 03:36:55 +01002613 if(file_buffer->file_size == 0) {
2614 file_buffer->c_byte = 0;
2615 queue_put(from_deflate, file_buffer);
2616 } else if(sparse_files && all_zero(file_buffer)) {
plougher1b899fc2008-08-07 01:24:06 +00002617 file_buffer->c_byte = 0;
2618 queue_put(from_deflate, file_buffer);
2619 } else if(file_buffer->fragment) {
2620 file_buffer->c_byte = file_buffer->size;
2621 queue_put(from_deflate, file_buffer);
2622 } else {
2623 write_buffer = cache_get(writer_buffer, 0, 0);
plougher13fdddf2010-11-24 01:23:41 +00002624 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002625 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002626 file_buffer->size, block_size,
2627 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002628 write_buffer->sequence = file_buffer->sequence;
2629 write_buffer->file_size = file_buffer->file_size;
2630 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002631 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2632 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002633 write_buffer->fragment = FALSE;
2634 write_buffer->error = FALSE;
2635 cache_block_put(file_buffer);
2636 queue_put(from_deflate, write_buffer);
2637 }
plougher5507dd92006-11-06 00:43:10 +00002638 }
2639}
2640
2641
2642void *frag_deflator(void *arg)
2643{
plougher7b8ee502009-07-29 07:54:30 +00002644 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002645 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002646
2647 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2648 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2649
plougher13fdddf2010-11-24 01:23:41 +00002650 res = compressor_init(comp, &stream, block_size, 1);
2651 if(res)
2652 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2653
plougher5507dd92006-11-06 00:43:10 +00002654 while(1) {
2655 int c_byte, compressed_size;
2656 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002657 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002658 cache_get(writer_buffer, file_buffer->block +
2659 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002660
plougher13fdddf2010-11-24 01:23:41 +00002661 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002662 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002663 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002664 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002665 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002666 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002667 fragment_table[file_buffer->block].size = c_byte;
2668 fragment_table[file_buffer->block].start_block = bytes;
2669 write_buffer->block = bytes;
2670 bytes += compressed_size;
2671 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002672 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002673 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002674 TRACE("Writing fragment %lld, uncompressed size %d, "
2675 "compressed size %d\n", file_buffer->block,
2676 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002677 } else {
2678 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002679 add_pending_fragment(write_buffer, c_byte,
2680 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002681 }
ploughereb6eac92008-02-26 01:50:48 +00002682 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002683 }
2684}
2685
2686
2687#define HASH_ENTRIES 256
2688#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2689struct file_buffer *block_hash[HASH_ENTRIES];
2690
2691void push_buffer(struct file_buffer *file_buffer)
2692{
plougher0f464442008-03-31 00:27:56 +00002693 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002694
2695 file_buffer->next = block_hash[hash];
2696 block_hash[hash] = file_buffer;
2697}
2698
2699
2700struct file_buffer *get_file_buffer(struct queue *queue)
2701{
plougher0f464442008-03-31 00:27:56 +00002702 static unsigned int sequence = 0;
2703 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002704 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2705
2706 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002707 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002708 break;
2709
2710 if(file_buffer) {
2711 if(prev)
2712 prev->next = file_buffer->next;
2713 else
2714 block_hash[hash] = file_buffer->next;
2715 } else {
2716 while(1) {
2717 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002718 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002719 break;
2720 push_buffer(file_buffer);
2721 }
2722 }
2723
plougher0f464442008-03-31 00:27:56 +00002724 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002725
2726 return file_buffer;
2727}
2728
2729
plougher91fbb302008-05-06 02:29:36 +00002730void *progress_thrd(void *arg)
plougher35a10602008-04-21 02:58:16 +00002731{
2732 struct timeval timeval;
2733 struct timespec timespec;
2734 struct itimerval itimerval;
2735 struct winsize winsize;
2736
2737 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
plougher01b43282009-03-30 18:21:37 +00002738 if(isatty(STDOUT_FILENO))
2739 printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
2740 "columns\n");
plougher35a10602008-04-21 02:58:16 +00002741 columns = 80;
2742 } else
2743 columns = winsize.ws_col;
2744 signal(SIGWINCH, sigwinch_handler);
2745 signal(SIGALRM, sigalrm_handler);
2746
2747 itimerval.it_value.tv_sec = 0;
2748 itimerval.it_value.tv_usec = 250000;
2749 itimerval.it_interval.tv_sec = 0;
2750 itimerval.it_interval.tv_usec = 250000;
2751 setitimer(ITIMER_REAL, &itimerval, NULL);
2752
plougher35a10602008-04-21 02:58:16 +00002753 pthread_cond_init(&progress_wait, NULL);
2754
plougher91fbb302008-05-06 02:29:36 +00002755 pthread_mutex_lock(&progress_mutex);
2756
plougher35a10602008-04-21 02:58:16 +00002757 while(1) {
plougher35a10602008-04-21 02:58:16 +00002758 gettimeofday(&timeval, NULL);
2759 timespec.tv_sec = timeval.tv_sec;
2760 if(timeval.tv_usec + 250000 > 999999)
2761 timespec.tv_sec++;
plougher50b31762009-03-31 04:14:46 +00002762 timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
2763 1000;
2764 pthread_cond_timedwait(&progress_wait, &progress_mutex,
2765 &timespec);
plougher43bb7e92008-08-17 17:16:09 +00002766 if(progress_enabled && estimated_uncompressed)
plougher110799c2009-03-30 01:50:40 +00002767 progress_bar(cur_uncompressed, estimated_uncompressed,
2768 columns);
plougher35a10602008-04-21 02:58:16 +00002769 }
2770}
2771
2772
plougher91fbb302008-05-06 02:29:36 +00002773void enable_progress_bar()
2774{
2775 pthread_mutex_lock(&progress_mutex);
2776 progress_enabled = TRUE;
2777 pthread_mutex_unlock(&progress_mutex);
2778}
2779
2780
2781void disable_progress_bar()
2782{
2783 pthread_mutex_lock(&progress_mutex);
2784 progress_enabled = FALSE;
2785 pthread_mutex_unlock(&progress_mutex);
2786}
2787
2788
rloughere4873e02007-11-08 17:50:42 +00002789void progress_bar(long long current, long long max, int columns)
plougher02bc3bc2007-02-25 12:12:01 +00002790{
plougher35a10602008-04-21 02:58:16 +00002791 char rotate_list[] = { '|', '/', '-', '\\' };
plougherf3f95e42010-03-08 01:32:20 +00002792 int max_digits, used, hashes, spaces;
plougher898763d2009-03-29 22:54:55 +00002793 static int tty = -1;
plougher02bc3bc2007-02-25 12:12:01 +00002794
plougherf3f95e42010-03-08 01:32:20 +00002795 if(max == 0)
2796 return;
2797
2798 max_digits = floor(log10(max)) + 1;
2799 used = max_digits * 2 + 11;
2800 hashes = (current * (columns - used)) / max;
2801 spaces = columns - used - hashes;
2802
ploughere9e01392009-03-29 22:48:42 +00002803 if((current > max) || (columns - used < 0))
plougher02bc3bc2007-02-25 12:12:01 +00002804 return;
2805
plougher898763d2009-03-29 22:54:55 +00002806 if(tty == -1)
2807 tty = isatty(STDOUT_FILENO);
2808 if(!tty) {
2809 static long long previous = -1;
2810
2811 /* Updating much more frequently than this results in huge
2812 * log files. */
2813 if((current % 100) != 0 && current != max)
2814 return;
2815 /* Don't update just to rotate the spinner. */
2816 if(current == previous)
2817 return;
2818 previous = current;
2819 }
2820
plougher02bc3bc2007-02-25 12:12:01 +00002821 printf("\r[");
2822
2823 while (hashes --)
2824 putchar('=');
2825
plougher35a10602008-04-21 02:58:16 +00002826 putchar(rotate_list[rotate]);
2827
plougher02bc3bc2007-02-25 12:12:01 +00002828 while(spaces --)
2829 putchar(' ');
2830
2831 printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2832 printf(" %3lld%%", current * 100 / max);
2833 fflush(stdout);
2834}
2835
2836
plougher110799c2009-03-30 01:50:40 +00002837void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2838 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002839{
2840 file_count ++;
2841 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002842 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2843 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002844}
2845
2846
plougher50b31762009-03-31 04:14:46 +00002847void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2848 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002849 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002850{
plougher5507dd92006-11-06 00:43:10 +00002851 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002852 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002853 unsigned int *block_listp = NULL;
2854 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002855
plougher50b31762009-03-31 04:14:46 +00002856 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2857 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002858
plougher5507dd92006-11-06 00:43:10 +00002859 if(dupl_ptr) {
2860 *duplicate_file = FALSE;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002861 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002862 dupl_ptr->fragment = fragment;
2863 } else
2864 *duplicate_file = TRUE;
2865
ploughereb6eac92008-02-26 01:50:48 +00002866 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002867
2868 total_bytes += size;
2869 file_count ++;
2870
plougher35a10602008-04-21 02:58:16 +00002871 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002872
plougherc1ace522010-05-01 03:00:45 +00002873 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002874 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002875}
2876
2877
plougher110799c2009-03-30 01:50:40 +00002878void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2879 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002880{
2881 struct fragment *fragment;
2882 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002883
2884 checksum = get_checksum_mem_buffer(file_buffer);
2885
plougher29e37092007-04-15 01:24:51 +00002886 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002887 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2888 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002889 return;
2890 }
plougher5507dd92006-11-06 00:43:10 +00002891
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002892 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002893
ploughereb6eac92008-02-26 01:50:48 +00002894 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002895
2896 if(duplicate_checking)
2897 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2898
2899 total_bytes += size;
2900 file_count ++;
2901
2902 *duplicate_file = FALSE;
2903
plougher35a10602008-04-21 02:58:16 +00002904 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002905
plougherc1ace522010-05-01 03:00:45 +00002906 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002907 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002908
plougher018d2b32007-04-23 03:01:48 +00002909 return;
plougher5507dd92006-11-06 00:43:10 +00002910}
2911
2912
plougher00d08172009-09-03 10:17:44 +00002913int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2914 struct file_buffer *read_buffer, int *duplicate_file)
2915{
2916 long long read_size, file_bytes, start;
2917 struct fragment *fragment;
2918 unsigned int *block_list = NULL;
2919 int block = 0, status;
2920 long long sparse = 0;
2921 struct file_buffer *fragment_buffer = NULL;
2922
2923 *duplicate_file = FALSE;
2924
2925 lock_fragments();
2926
2927 file_bytes = 0;
2928 start = bytes;
2929 while (1) {
2930 read_size = read_buffer->file_size;
2931 if(read_buffer->fragment && read_buffer->c_byte)
2932 fragment_buffer = read_buffer;
2933 else {
2934 block_list = realloc(block_list, (block + 1) *
2935 sizeof(unsigned int));
2936 if(block_list == NULL)
2937 BAD_ERROR("Out of memory allocating block_list"
2938 "\n");
2939 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 }
plougher286b6b32009-09-19 03:29:27 +00002951 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002952
2953 if(read_size != -1)
2954 break;
2955
2956 read_buffer = get_file_buffer(from_deflate);
2957 if(read_buffer->error)
2958 goto read_err;
2959 }
2960
2961 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002962 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002963 cache_block_put(fragment_buffer);
2964
2965 if(duplicate_checking)
2966 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2967 0, 0, FALSE);
2968 file_count ++;
2969 total_bytes += read_size;
2970
plougherc1ace522010-05-01 03:00:45 +00002971 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2972 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002973
2974 if(duplicate_checking == FALSE)
2975 free(block_list);
2976
2977 return 0;
2978
2979read_err:
plougher286b6b32009-09-19 03:29:27 +00002980 cur_uncompressed -= block;
plougher00d08172009-09-03 10:17:44 +00002981 status = read_buffer->error;
2982 bytes = start;
2983 if(!block_device) {
2984 int res;
2985
2986 queue_put(to_writer, NULL);
2987 if(queue_get(from_writer) != 0)
2988 EXIT_MKSQUASHFS();
2989 res = ftruncate(fd, bytes);
2990 if(res != 0)
2991 BAD_ERROR("Failed to truncate dest file because %s\n",
2992 strerror(errno));
2993 }
2994 unlock_fragments();
2995 free(block_list);
2996 cache_block_put(read_buffer);
2997 return status;
2998}
2999
3000
plougher110799c2009-03-30 01:50:40 +00003001int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003002 long long read_size, struct file_buffer *read_buffer,
3003 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003004{
plougher23377982007-11-12 04:04:48 +00003005 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00003006 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00003007 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00003008 int block, status;
3009 int blocks = (read_size + block_size - 1) >> block_log;
3010 long long sparse = 0;
3011 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003012
plougher29e37092007-04-15 01:24:51 +00003013 *duplicate_file = FALSE;
3014
plougher87139622010-12-16 05:19:30 +00003015 block_list = malloc(blocks * sizeof(unsigned int));
3016 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003017 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00003018
plougher2ea89142008-03-11 01:34:19 +00003019 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00003020
plougher5507dd92006-11-06 00:43:10 +00003021 file_bytes = 0;
3022 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00003023 for(block = 0; block < blocks;) {
3024 if(read_buffer->fragment && read_buffer->c_byte) {
3025 fragment_buffer = read_buffer;
3026 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00003027 } else {
plougher1b899fc2008-08-07 01:24:06 +00003028 block_list[block] = read_buffer->c_byte;
3029 if(read_buffer->c_byte) {
3030 read_buffer->block = bytes;
3031 bytes += read_buffer->size;
3032 cache_rehash(read_buffer, read_buffer->block);
3033 file_bytes += read_buffer->size;
3034 queue_put(to_writer, read_buffer);
3035 } else {
3036 sparse += read_buffer->size;
3037 cache_block_put(read_buffer);
3038 }
3039 }
3040 inc_progress_bar();
3041
3042 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003043 read_buffer = get_file_buffer(from_deflate);
3044 if(read_buffer->error)
3045 goto read_err;
3046 }
plougher1f413c82005-11-18 00:02:14 +00003047 }
3048
plougher2ea89142008-03-11 01:34:19 +00003049 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003050 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher1b899fc2008-08-07 01:24:06 +00003051 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003052
plougher1f413c82005-11-18 00:02:14 +00003053 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00003054 add_non_dup(read_size, file_bytes, block_list, start, fragment,
3055 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00003056 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00003057 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00003058
plougher360514a2009-03-30 03:01:38 +00003059 /*
3060 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003061 * a smaller block count on stat calls to sparse files. This is
3062 * to ensure intelligent applications like cp correctly handle the
3063 * file as a sparse file. If the file in the original filesystem isn't
3064 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003065 * report it as non-sparse on stat calls to preserve semantics
3066 */
plougher1b899fc2008-08-07 01:24:06 +00003067 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3068 sparse = 0;
3069
plougherc1ace522010-05-01 03:00:45 +00003070 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
3071 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003072
plougher5507dd92006-11-06 00:43:10 +00003073 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00003074 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003075
plougher018d2b32007-04-23 03:01:48 +00003076 return 0;
plougher1f413c82005-11-18 00:02:14 +00003077
3078read_err:
plougher018d2b32007-04-23 03:01:48 +00003079 cur_uncompressed -= block;
3080 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003081 bytes = start;
3082 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00003083 int res;
3084
plougher5507dd92006-11-06 00:43:10 +00003085 queue_put(to_writer, NULL);
3086 if(queue_get(from_writer) != 0)
3087 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003088 res = ftruncate(fd, bytes);
3089 if(res != 0)
3090 BAD_ERROR("Failed to truncate dest file because %s\n",
3091 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003092 }
plougher2ea89142008-03-11 01:34:19 +00003093 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003094 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003095 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003096 return status;
plougher1f413c82005-11-18 00:02:14 +00003097}
3098
3099
plougher110799c2009-03-30 01:50:40 +00003100int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003101 long long read_size, struct file_buffer *read_buffer,
3102 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003103{
plougher29e37092007-04-15 01:24:51 +00003104 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003105 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003106 struct fragment *fragment;
3107 struct file_info *dupl_ptr;
3108 int blocks = (read_size + block_size - 1) >> block_log;
3109 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003110 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003111 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003112 long long sparse = 0;
3113 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003114
plougher50b31762009-03-31 04:14:46 +00003115 block_list = malloc(blocks * sizeof(unsigned int));
3116 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003117 BAD_ERROR("Out of memory allocating block_list\n");
3118 block_listp = block_list;
3119
plougher50b31762009-03-31 04:14:46 +00003120 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3121 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003122 BAD_ERROR("Out of memory allocating file block list\n");
3123
plougher4e8484a2008-03-15 23:30:16 +00003124 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003125
3126 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003127 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003128 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3129 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003130
3131 for(block = 0; block < blocks;) {
3132 if(read_buffer->fragment && read_buffer->c_byte) {
3133 fragment_buffer = read_buffer;
3134 blocks = read_size >> block_log;
3135 } else {
3136 block_list[block] = read_buffer->c_byte;
3137
3138 if(read_buffer->c_byte) {
3139 read_buffer->block = bytes;
3140 bytes += read_buffer->size;
3141 file_bytes += read_buffer->size;
3142 cache_rehash(read_buffer, read_buffer->block);
3143 if(block < thresh) {
3144 buffer_list[block] = NULL;
3145 queue_put(to_writer, read_buffer);
3146 } else
3147 buffer_list[block] = read_buffer;
3148 } else {
3149 buffer_list[block] = NULL;
3150 sparse += read_buffer->size;
3151 cache_block_put(read_buffer);
3152 }
3153 }
3154 inc_progress_bar();
3155
3156 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003157 read_buffer = get_file_buffer(from_deflate);
3158 if(read_buffer->error)
3159 goto read_err;
3160 }
plougher5507dd92006-11-06 00:43:10 +00003161 }
3162
plougher110799c2009-03-30 01:50:40 +00003163 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3164 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003165
3166 if(dupl_ptr) {
3167 *duplicate_file = FALSE;
3168 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003169 if(buffer_list[block])
3170 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003171 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00003172 dupl_ptr->fragment = fragment;
3173 } else {
3174 *duplicate_file = TRUE;
3175 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003176 cache_block_put(buffer_list[block]);
3177 bytes = start;
3178 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003179 int res;
3180
plougher1b899fc2008-08-07 01:24:06 +00003181 queue_put(to_writer, NULL);
3182 if(queue_get(from_writer) != 0)
3183 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003184 res = ftruncate(fd, bytes);
3185 if(res != 0)
3186 BAD_ERROR("Failed to truncate dest file because"
3187 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003188 }
plougher5507dd92006-11-06 00:43:10 +00003189 }
3190
plougher2ea89142008-03-11 01:34:19 +00003191 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003192 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003193 free(buffer_list);
3194 file_count ++;
3195 total_bytes += read_size;
3196
plougher360514a2009-03-30 03:01:38 +00003197 /*
3198 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003199 * a smaller block count on stat calls to sparse files. This is
3200 * to ensure intelligent applications like cp correctly handle the
3201 * file as a sparse file. If the file in the original filesystem isn't
3202 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003203 * report it as non-sparse on stat calls to preserve semantics
3204 */
plougher1b899fc2008-08-07 01:24:06 +00003205 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3206 sparse = 0;
3207
plougherc1ace522010-05-01 03:00:45 +00003208 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3209 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003210
plougher5507dd92006-11-06 00:43:10 +00003211 if(*duplicate_file == TRUE)
3212 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003213
plougher018d2b32007-04-23 03:01:48 +00003214 return 0;
plougher5507dd92006-11-06 00:43:10 +00003215
3216read_err:
plougher018d2b32007-04-23 03:01:48 +00003217 cur_uncompressed -= block;
3218 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003219 bytes = start;
3220 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003221 int res;
3222
plougher5507dd92006-11-06 00:43:10 +00003223 queue_put(to_writer, NULL);
3224 if(queue_get(from_writer) != 0)
3225 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003226 res = ftruncate(fd, bytes);
3227 if(res != 0)
3228 BAD_ERROR("Failed to truncate dest file because %s\n",
3229 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003230 }
plougher2ea89142008-03-11 01:34:19 +00003231 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003232 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003233 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003234 free(buffer_list);
3235 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003236 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003237 return status;
plougher5507dd92006-11-06 00:43:10 +00003238}
3239
3240
plougher110799c2009-03-30 01:50:40 +00003241void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3242 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003243{
plougher018d2b32007-04-23 03:01:48 +00003244 int status;
3245 struct file_buffer *read_buffer;
3246 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003247
plougher018d2b32007-04-23 03:01:48 +00003248again:
3249 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003250
plougher23377982007-11-12 04:04:48 +00003251 status = read_buffer->error;
3252 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003253 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003254 goto file_err;
3255 }
3256
3257 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003258
plougher00d08172009-09-03 10:17:44 +00003259 if(read_size == -1)
3260 status = write_file_process(inode, dir_ent, read_buffer,
3261 duplicate_file);
3262 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003263 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003264 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003265 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003266 write_file_frag(inode, dir_ent, read_size, read_buffer,
3267 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003268 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003269 status = write_file_blocks_dup(inode, dir_ent, read_size,
3270 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003271 else
plougher50b31762009-03-31 04:14:46 +00003272 status = write_file_blocks(inode, dir_ent, read_size,
3273 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003274
plougher018d2b32007-04-23 03:01:48 +00003275file_err:
3276 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003277 ERROR("File %s changed size while reading filesystem, "
3278 "attempting to re-read\n", dir_ent->pathname);
plougher018d2b32007-04-23 03:01:48 +00003279 goto again;
3280 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003281 ERROR("Failed to read file %s, creating empty file\n",
3282 dir_ent->pathname);
plougher29e37092007-04-15 01:24:51 +00003283 write_file_empty(inode, dir_ent, duplicate_file);
3284 }
plougher5507dd92006-11-06 00:43:10 +00003285}
3286
3287
plougher44d54ef2010-02-08 22:13:49 +00003288#define BUFF_SIZE 8192
3289char b_buffer[BUFF_SIZE];
plougher1f413c82005-11-18 00:02:14 +00003290char *name;
3291char *basename_r();
3292
3293char *getbase(char *pathname)
3294{
3295 char *result;
3296
3297 if(*pathname != '/') {
plougher44d54ef2010-02-08 22:13:49 +00003298 result = getcwd(b_buffer, BUFF_SIZE);
3299 if(result == NULL)
3300 return NULL;
3301 strcat(strcat(b_buffer, "/"), pathname);
plougher1f413c82005-11-18 00:02:14 +00003302 } else
3303 strcpy(b_buffer, pathname);
3304 name = b_buffer;
3305 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3306 return NULL;
3307 else
3308 return result;
3309}
3310
3311
3312char *basename_r()
3313{
3314 char *s;
3315 char *p;
3316 int n = 1;
3317
3318 for(;;) {
3319 s = name;
3320 if(*name == '\0')
3321 return NULL;
3322 if(*name != '/') {
3323 while(*name != '\0' && *name != '/') name++;
3324 n = name - s;
3325 }
3326 while(*name == '/') name++;
3327 if(strncmp(s, ".", n) == 0)
3328 continue;
plougher110799c2009-03-30 01:50:40 +00003329 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3330 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003331 s[n] = '\0';
3332 return s;
3333 }
3334 if(strcmp(p, "..") == 0)
3335 continue;
3336 return p;
3337 }
3338}
3339
3340
3341struct inode_info *lookup_inode(struct stat *buf)
3342{
3343 int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3344 struct inode_info *inode = inode_info[inode_hash];
3345
3346 while(inode != NULL) {
3347 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3348 inode->nlink ++;
3349 return inode;
3350 }
3351 inode = inode->next;
3352 }
3353
plougher288f6852010-12-16 05:22:55 +00003354 inode = malloc(sizeof(struct inode_info));
3355 if(inode == NULL)
plougher50b31762009-03-31 04:14:46 +00003356 BAD_ERROR("Out of memory in inode hash table entry allocation"
3357 "\n");
plougher1f413c82005-11-18 00:02:14 +00003358
3359 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003360 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003361 inode->root_entry = FALSE;
plougher00d08172009-09-03 10:17:44 +00003362 inode->pseudo_file = FALSE;
plougher1f413c82005-11-18 00:02:14 +00003363 inode->inode = SQUASHFS_INVALID_BLK;
3364 inode->nlink = 1;
plougherdc86c3c2007-12-05 02:15:10 +00003365
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003366 /*
3367 * Copy filesystem wide defaults into inode, these filesystem
3368 * wide defaults may be altered on an individual inode basis by
3369 * user specified actions
3370 *
3371 */
3372 inode->no_fragments = no_fragments;
3373 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003374 inode->noD = noD;
3375 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003376
plougherdc86c3c2007-12-05 02:15:10 +00003377 if((buf->st_mode & S_IFMT) == S_IFREG)
plougher110799c2009-03-30 01:50:40 +00003378 estimated_uncompressed += (buf->st_size + block_size - 1) >>
3379 block_log;
plougherdc86c3c2007-12-05 02:15:10 +00003380
plougher1f413c82005-11-18 00:02:14 +00003381 if((buf->st_mode & S_IFMT) == S_IFDIR)
3382 inode->inode_number = dir_inode_no ++;
3383 else
3384 inode->inode_number = inode_no ++;
3385
3386 inode->next = inode_info[inode_hash];
3387 inode_info[inode_hash] = inode;
3388
3389 return inode;
3390}
3391
3392
plougher110799c2009-03-30 01:50:40 +00003393inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
ploughera326c182009-08-29 05:41:45 +00003394 struct inode_info *inode_info, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003395{
plougher110799c2009-03-30 01:50:40 +00003396 if((dir->count % DIR_ENTRIES) == 0) {
3397 dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) *
3398 sizeof(struct dir_ent *));
3399 if(dir->list == NULL)
plougher1f413c82005-11-18 00:02:14 +00003400 BAD_ERROR("Out of memory in add_dir_entry\n");
plougher110799c2009-03-30 01:50:40 +00003401 }
plougher1f413c82005-11-18 00:02:14 +00003402
ploughere5dad792010-12-16 05:24:24 +00003403 dir->list[dir->count] = malloc(sizeof(struct dir_ent));
3404 if(dir->list[dir->count] == NULL)
plougher1f413c82005-11-18 00:02:14 +00003405 BAD_ERROR("Out of memory in linux_opendir\n");
3406
3407 if(sub_dir)
3408 sub_dir->dir_ent = dir->list[dir->count];
3409 dir->list[dir->count]->name = strdup(name);
plougher110799c2009-03-30 01:50:40 +00003410 dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) :
3411 NULL;
plougher1f413c82005-11-18 00:02:14 +00003412 dir->list[dir->count]->inode = inode_info;
3413 dir->list[dir->count]->dir = sub_dir;
ploughera326c182009-08-29 05:41:45 +00003414 dir->list[dir->count++]->our_dir = dir;
plougher9b393552010-12-31 20:55:43 +00003415 dir->byte_count += strlen(name) + sizeof(struct squashfs_dir_entry);
plougher1f413c82005-11-18 00:02:14 +00003416}
3417
3418
Phillip Lougherad0f9212011-12-31 00:55:51 +00003419inline void add_excluded(struct dir_info *dir)
3420{
3421 dir->excluded ++;
3422}
3423
3424
plougher1f413c82005-11-18 00:02:14 +00003425int compare_name(const void *ent1_ptr, const void *ent2_ptr)
3426{
3427 struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
3428 struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
3429
3430 return strcmp(ent1->name, ent2->name);
3431}
3432
3433
3434void sort_directory(struct dir_info *dir)
3435{
3436 qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
3437
3438 if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
3439 dir->dir_is_ldir = FALSE;
3440}
3441
3442
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003443struct dir_info *scan1_opendir(char *pathname, int depth)
plougher1f413c82005-11-18 00:02:14 +00003444{
plougher1f413c82005-11-18 00:02:14 +00003445 struct dir_info *dir;
3446
plougher6da792b2010-12-16 05:25:39 +00003447 dir = malloc(sizeof(struct dir_info));
3448 if(dir == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003449 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003450
3451 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3452 free(dir);
3453 return NULL;
3454 }
3455 dir->pathname = strdup(pathname);
Phillip Lougherded70fa2011-12-25 02:14:58 +00003456 dir->count = 0;
3457 dir->directory_count = 0;
3458 dir->current_count = 0;
3459 dir->byte_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003460 dir->dir_is_ldir = TRUE;
3461 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003462 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003463 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003464
3465 return dir;
3466}
3467
3468
3469int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3470{
plougher1f413c82005-11-18 00:02:14 +00003471 static int index = 0;
3472
plougher11266ba2010-12-16 05:34:30 +00003473 if(dir->count < old_root_entries) {
3474 int i;
3475
plougher1f413c82005-11-18 00:02:14 +00003476 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003477 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003478 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003479 add_dir_entry(old_root_entry[i].name, "", NULL,
3480 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003481 }
plougher11266ba2010-12-16 05:34:30 +00003482 }
plougher1f413c82005-11-18 00:02:14 +00003483
3484 while(index < source) {
plougher89fe2c72010-12-16 05:31:34 +00003485 char *basename = getbase(source_path[index]);
plougher1fae42c2010-12-16 05:37:43 +00003486 int n, pass = 1;
plougher89fe2c72010-12-16 05:31:34 +00003487
plougherb4116c32010-12-16 05:28:01 +00003488 if(basename == NULL) {
plougher110799c2009-03-30 01:50:40 +00003489 ERROR("Bad source directory %s - skipping ...\n",
3490 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003491 index ++;
3492 continue;
3493 }
3494 strcpy(dir_name, basename);
plougher1f413c82005-11-18 00:02:14 +00003495 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003496 for(n = 0; n < dir->count &&
3497 strcmp(dir->list[n]->name, dir_name) != 0; n++);
plougher1f413c82005-11-18 00:02:14 +00003498 if(n == dir->count)
3499 break;
plougher50b31762009-03-31 04:14:46 +00003500 ERROR("Source directory entry %s already used! - trying"
3501 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003502 sprintf(dir_name, "%s_%d", basename, pass++);
3503 ERROR("%s\n", dir_name);
3504 }
3505 strcpy(pathname, source_path[index ++]);
3506 return 1;
3507 }
3508 return 0;
3509}
3510
3511
3512int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3513{
3514 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003515 int i;
plougher1f413c82005-11-18 00:02:14 +00003516
plougher4925e172010-12-16 05:45:54 +00003517 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003518 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003519 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003520 dir->directory_count ++;
ploughera326c182009-08-29 05:41:45 +00003521 add_dir_entry(old_root_entry[i].name, "", NULL,
3522 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003523 }
plougher4925e172010-12-16 05:45:54 +00003524 }
plougher1f413c82005-11-18 00:02:14 +00003525
3526 if((d_name = readdir(dir->linuxdir)) != NULL) {
plougher4925e172010-12-16 05:45:54 +00003527 int pass = 1;
3528
plougher1f413c82005-11-18 00:02:14 +00003529 strcpy(dir_name, d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003530 for(;;) {
plougher110799c2009-03-30 01:50:40 +00003531 for(i = 0; i < dir->count &&
3532 strcmp(dir->list[i]->name, dir_name) != 0; i++);
plougher1f413c82005-11-18 00:02:14 +00003533 if(i == dir->count)
3534 break;
plougher50b31762009-03-31 04:14:46 +00003535 ERROR("Source directory entry %s already used! - trying"
3536 " ", dir_name);
plougher1f413c82005-11-18 00:02:14 +00003537 sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
3538 ERROR("%s\n", dir_name);
3539 }
plougher110799c2009-03-30 01:50:40 +00003540 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3541 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003542 return 1;
3543 }
3544
3545 return 0;
3546}
3547
3548
3549int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
3550{
plougher480d9bf2010-12-18 02:28:39 +00003551 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003552
plougher66578ce2010-12-16 05:47:46 +00003553 if(d_name != NULL) {
plougher1f413c82005-11-18 00:02:14 +00003554 strcpy(dir_name, d_name->d_name);
plougher110799c2009-03-30 01:50:40 +00003555 strcat(strcat(strcpy(pathname, dir->pathname), "/"),
3556 d_name->d_name);
plougher1f413c82005-11-18 00:02:14 +00003557 return 1;
3558 }
3559
3560 return 0;
3561}
3562
3563
plougher43244f22009-04-05 02:04:51 +00003564struct dir_ent *scan2_readdir(struct dir_info *dir_info)
3565{
3566 int current_count;
3567
3568 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003569 if(dir_info->list[current_count]->inode->root_entry)
plougher43244f22009-04-05 02:04:51 +00003570 continue;
3571 else
3572 return dir_info->list[current_count];
3573 return NULL;
3574}
3575
3576
3577struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3578{
3579 int i;
3580
3581 for(i = 0; i < dir->count; i++)
3582 if(strcmp(dir->list[i]->name, name) == 0)
3583 return dir->list[i];
3584
3585 return NULL;
3586}
3587
3588
3589struct dir_ent *scan3_readdir(struct directory *dir, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003590{
3591 int current_count;
3592
3593 while((current_count = dir_info->current_count++) < dir_info->count)
ploughera326c182009-08-29 05:41:45 +00003594 if(dir_info->list[current_count]->inode->root_entry)
3595 add_dir(dir_info->list[current_count]->inode->inode,
3596 dir_info->list[current_count]->inode->inode_number,
plougher110799c2009-03-30 01:50:40 +00003597 dir_info->list[current_count]->name,
ploughera326c182009-08-29 05:41:45 +00003598 dir_info->list[current_count]->inode->type, dir);
plougher1f413c82005-11-18 00:02:14 +00003599 else
3600 return dir_info->list[current_count];
plougher43244f22009-04-05 02:04:51 +00003601 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003602}
3603
3604
3605void scan1_freedir(struct dir_info *dir)
3606{
plougherfbed12b2006-02-07 12:45:53 +00003607 if(dir->pathname[0] != '\0')
3608 closedir(dir->linuxdir);
plougherb087fc12010-05-01 04:53:28 +00003609 free(dir->pathname);
3610 dir->pathname = NULL;
plougher1f413c82005-11-18 00:02:14 +00003611}
3612
3613
plougher43244f22009-04-05 02:04:51 +00003614void scan2_freedir(struct dir_info *dir)
3615{
3616 dir->current_count = 0;
plougherb087fc12010-05-01 04:53:28 +00003617 if(dir->pathname) {
3618 free(dir->pathname);
3619 dir->pathname = NULL;
3620 }
plougher43244f22009-04-05 02:04:51 +00003621}
3622
3623
3624void scan3_freedir(struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00003625{
3626 if(dir->index)
3627 free(dir->index);
3628 free(dir->buff);
3629}
3630
3631
plougher110799c2009-03-30 01:50:40 +00003632void dir_scan(squashfs_inode *inode, char *pathname,
3633 int (_readdir)(char *, char *, struct dir_info *))
plougher1f413c82005-11-18 00:02:14 +00003634{
plougher0e453652006-11-06 01:49:35 +00003635 struct stat buf;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003636 struct dir_info *dir_info = dir_scan1(pathname, paths, _readdir, 1);
plougher1f413c82005-11-18 00:02:14 +00003637 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003638
3639 if(dir_info == NULL)
3640 return;
3641
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003642 dir_scan2(dir_info, pseudo, 1);
plougher43244f22009-04-05 02:04:51 +00003643
plougher2e3bcbe2010-12-18 02:30:17 +00003644 dir_ent = malloc(sizeof(struct dir_ent));
3645 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003646 BAD_ERROR("Out of memory in dir_scan\n");
3647
plougher1f413c82005-11-18 00:02:14 +00003648 if(pathname[0] == '\0') {
plougher110799c2009-03-30 01:50:40 +00003649 /*
plougher1e4dbce2010-07-31 03:01:34 +00003650 * dummy top level directory, if multiple sources specified on
plougher110799c2009-03-30 01:50:40 +00003651 * command line
3652 */
plougher43244f22009-04-05 02:04:51 +00003653 memset(&buf, 0, sizeof(buf));
plougher0e453652006-11-06 01:49:35 +00003654 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3655 buf.st_uid = getuid();
3656 buf.st_gid = getgid();
3657 buf.st_mtime = time(NULL);
3658 buf.st_dev = 0;
3659 buf.st_ino = 0;
plougher1e4dbce2010-07-31 03:01:34 +00003660 dir_ent->inode = lookup_inode(&buf);
3661 dir_ent->inode->pseudo_file = PSEUDO_FILE_OTHER;
3662 } else {
3663 if(lstat(pathname, &buf) == -1) {
3664 ERROR("Cannot stat dir/file %s because %s, ignoring",
3665 pathname, strerror(errno));
3666 return;
3667 }
3668 dir_ent->inode = lookup_inode(&buf);
plougher1f413c82005-11-18 00:02:14 +00003669 }
plougher0e453652006-11-06 01:49:35 +00003670
plougher0e453652006-11-06 01:49:35 +00003671 if(root_inode_number) {
3672 dir_ent->inode->inode_number = root_inode_number;
3673 dir_inode_no --;
3674 }
3675 dir_ent->name = dir_ent->pathname = strdup(pathname);
3676 dir_ent->dir = dir_info;
3677 dir_ent->our_dir = NULL;
plougher0e453652006-11-06 01:49:35 +00003678 dir_info->dir_ent = dir_ent;
3679
plougher1d1c6bb2010-07-21 03:03:13 +00003680 if(sorted) {
3681 int res = generate_file_priorities(dir_info, 0,
plougher110799c2009-03-30 01:50:40 +00003682 &dir_info->dir_ent->inode->buf);
plougher1d1c6bb2010-07-21 03:03:13 +00003683
3684 if(res == FALSE)
3685 BAD_ERROR("generate_file_priorities failed\n");
3686 }
plougher5507dd92006-11-06 00:43:10 +00003687 queue_put(to_reader, dir_info);
3688 if(sorted)
plougher117b2ea2006-02-09 09:23:56 +00003689 sort_files_and_write(dir_info);
plougher91fbb302008-05-06 02:29:36 +00003690 if(progress)
3691 enable_progress_bar();
plougher43244f22009-04-05 02:04:51 +00003692 dir_scan3(inode, dir_info);
plougher0e453652006-11-06 01:49:35 +00003693 dir_ent->inode->inode = *inode;
3694 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003695}
3696
3697
plougher110799c2009-03-30 01:50:40 +00003698struct dir_info *dir_scan1(char *pathname, struct pathnames *paths,
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003699 int (_readdir)(char *, char *, struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003700{
plougher1f413c82005-11-18 00:02:14 +00003701 char filename[8192], dir_name[8192];
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003702 struct dir_info *dir = scan1_opendir(pathname, depth);
plougher1f413c82005-11-18 00:02:14 +00003703
plougher360b6e42010-12-18 02:40:28 +00003704 if(dir == NULL) {
plougher1f413c82005-11-18 00:02:14 +00003705 ERROR("Could not open %s, skipping...\n", pathname);
3706 goto error;
3707 }
3708
3709 while(_readdir(filename, dir_name, dir) != FALSE) {
plougher360b6e42010-12-18 02:40:28 +00003710 struct dir_info *sub_dir;
3711 struct stat buf;
3712 struct pathnames *new;
plougher1f413c82005-11-18 00:02:14 +00003713
3714 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
3715 continue;
3716
3717 if(lstat(filename, &buf) == -1) {
plougher110799c2009-03-30 01:50:40 +00003718 ERROR("Cannot stat dir/file %s because %s, ignoring",
3719 filename, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00003720 continue;
3721 }
plougher29e37092007-04-15 01:24:51 +00003722
3723 if((buf.st_mode & S_IFMT) != S_IFREG &&
3724 (buf.st_mode & S_IFMT) != S_IFDIR &&
3725 (buf.st_mode & S_IFMT) != S_IFLNK &&
3726 (buf.st_mode & S_IFMT) != S_IFCHR &&
3727 (buf.st_mode & S_IFMT) != S_IFBLK &&
3728 (buf.st_mode & S_IFMT) != S_IFIFO &&
3729 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003730 ERROR("File %s has unrecognised filetype %d, ignoring"
3731 "\n", filename, buf.st_mode & S_IFMT);
plougher29e37092007-04-15 01:24:51 +00003732 continue;
3733 }
3734
Phillip Lougherad0f9212011-12-31 00:55:51 +00003735 if((old_exclude && old_excluded(filename, &buf)) ||
3736 excluded(paths, dir_name, &new) ||
3737 eval_exclude_actions(dir_name, filename, &buf,
3738 depth)) {
3739 add_excluded(dir);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003740 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003741 }
plougher1f413c82005-11-18 00:02:14 +00003742
3743 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003744 sub_dir = dir_scan1(filename, new, scan1_readdir,
3745 depth + 1);
plougher110799c2009-03-30 01:50:40 +00003746 if(sub_dir == NULL)
plougher1f413c82005-11-18 00:02:14 +00003747 continue;
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003748
3749 if(eval_empty_actions(dir_name, filename, &buf, depth,
Phillip Lougher70228702011-12-31 19:49:22 +00003750 sub_dir)) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003751 add_excluded(dir);
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003752 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003753 }
3754
plougher1f413c82005-11-18 00:02:14 +00003755 dir->directory_count ++;
3756 } else
3757 sub_dir = NULL;
3758
plougher110799c2009-03-30 01:50:40 +00003759 add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf),
ploughera326c182009-08-29 05:41:45 +00003760 dir);
plougher1f413c82005-11-18 00:02:14 +00003761 }
3762
3763 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003764
3765error:
3766 return dir;
3767}
3768
plougher2ea89142008-03-11 01:34:19 +00003769
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003770struct dir_info *dir_scan2(struct dir_info *dir, struct pseudo *pseudo, int depth)
plougher43244f22009-04-05 02:04:51 +00003771{
3772 struct dir_info *sub_dir;
3773 struct dir_ent *dir_ent;
3774 struct pseudo_entry *pseudo_ent;
3775 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003776 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003777
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003778 if(dir == NULL && (dir = scan1_opendir("", depth)) == NULL)
plougher43244f22009-04-05 02:04:51 +00003779 return NULL;
3780
3781 while((dir_ent = scan2_readdir(dir)) != NULL) {
3782 struct inode_info *inode_info = dir_ent->inode;
3783 struct stat *buf = &inode_info->buf;
3784 char *name = dir_ent->name;
3785
Phillip Lougher89d757c2011-09-20 00:33:19 +01003786 eval_actions(dir_ent);
3787
plougher43244f22009-04-05 02:04:51 +00003788 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003789 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo),
3790 depth + 1);
plougher43244f22009-04-05 02:04:51 +00003791 }
3792
3793 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3794 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003795 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003796 struct stat *buf;
3797 if(dir_ent == NULL) {
plougherdcd66c52010-09-17 03:44:17 +00003798 ERROR("Pseudo modify file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003799 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003800 pseudo_ent->pathname);
3801 continue;
3802 }
ploughera326c182009-08-29 05:41:45 +00003803 if(dir_ent->inode->root_entry) {
plougherdcd66c52010-09-17 03:44:17 +00003804 ERROR("Pseudo modify file \"%s\" is a pre-existing"
plougherb34f9f62009-04-26 02:08:42 +00003805 " file in the filesystem being appended"
3806 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003807 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003808 continue;
3809 }
3810 buf = &dir_ent->inode->buf;
3811 buf->st_mode = (buf->st_mode & S_IFMT) |
3812 pseudo_ent->dev->mode;
3813 buf->st_uid = pseudo_ent->dev->uid;
3814 buf->st_gid = pseudo_ent->dev->gid;
3815 continue;
3816 }
3817
plougher43244f22009-04-05 02:04:51 +00003818 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003819 if(dir_ent->inode->root_entry)
3820 ERROR("Pseudo file \"%s\" is a pre-existing"
3821 " file in the filesystem being appended"
3822 " to. Ignoring.\n",
3823 pseudo_ent->pathname);
3824 else
3825 ERROR("Pseudo file \"%s\" exists in source "
plougherdcd66c52010-09-17 03:44:17 +00003826 "filesystem \"%s\".\nIgnoring, "
plougherf0dc2382010-05-01 23:55:06 +00003827 "exclude it (-e/-ef) to override.\n",
3828 pseudo_ent->pathname,
3829 dir_ent->pathname);
plougher43244f22009-04-05 02:04:51 +00003830 continue;
3831 }
3832
3833 if(pseudo_ent->dev->type == 'd') {
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003834 sub_dir = dir_scan2(NULL, pseudo_ent->pseudo, depth + 1);
plougher43244f22009-04-05 02:04:51 +00003835 if(sub_dir == NULL) {
3836 ERROR("Could not create pseudo directory \"%s\""
3837 ", skipping...\n",
3838 pseudo_ent->pathname);
3839 continue;
3840 }
3841 dir->directory_count ++;
3842 } else
3843 sub_dir = NULL;
3844
3845 memset(&buf, 0, sizeof(buf));
3846 buf.st_mode = pseudo_ent->dev->mode;
3847 buf.st_uid = pseudo_ent->dev->uid;
3848 buf.st_gid = pseudo_ent->dev->gid;
3849 buf.st_rdev = makedev(pseudo_ent->dev->major,
3850 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003851 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003852 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003853
plougher4ab7e512009-05-05 02:35:58 +00003854 if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003855#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003856 struct stat buf2;
3857 int res = stat(pseudo_ent->dev->filename, &buf2);
plougherb85e9ad2010-05-02 01:46:12 +00003858 struct inode_info *inode;
plougher4ab7e512009-05-05 02:35:58 +00003859 if(res == -1) {
3860 ERROR("Stat on pseudo file \"%s\" failed, "
3861 "skipping...", pseudo_ent->pathname);
3862 continue;
3863 }
3864 buf.st_size = buf2.st_size;
plougherb85e9ad2010-05-02 01:46:12 +00003865 inode = lookup_inode(&buf);
3866 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003867 add_dir_entry(pseudo_ent->name,
plougherb85e9ad2010-05-02 01:46:12 +00003868 pseudo_ent->dev->filename, sub_dir, inode,
3869 dir);
plougher00d08172009-09-03 10:17:44 +00003870#else
3871 struct inode_info *inode = lookup_inode(&buf);
plougherba674e82009-09-10 03:50:00 +00003872 inode->pseudo_id = pseudo_ent->dev->pseudo_id;
plougherb85e9ad2010-05-02 01:46:12 +00003873 inode->pseudo_file = PSEUDO_FILE_PROCESS;
plougher00d08172009-09-03 10:17:44 +00003874 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
3875 sub_dir, inode, dir);
3876#endif
plougherb85e9ad2010-05-02 01:46:12 +00003877 } else {
3878 struct inode_info *inode = lookup_inode(&buf);
3879 inode->pseudo_file = PSEUDO_FILE_OTHER;
plougher4ab7e512009-05-05 02:35:58 +00003880 add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
plougherb85e9ad2010-05-02 01:46:12 +00003881 sub_dir, inode, dir);
3882 }
plougher43244f22009-04-05 02:04:51 +00003883 }
3884
3885 scan2_freedir(dir);
3886 sort_directory(dir);
3887
3888 return dir;
3889}
3890
3891
3892void dir_scan3(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003893{
3894 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00003895 int duplicate_file;
ploughere4e92092010-05-01 04:51:50 +00003896 char *pathname = dir_info->dir_ent->pathname;
plougher1f413c82005-11-18 00:02:14 +00003897 struct directory dir;
3898 struct dir_ent *dir_ent;
3899
plougher43244f22009-04-05 02:04:51 +00003900 scan3_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003901
plougher43244f22009-04-05 02:04:51 +00003902 while((dir_ent = scan3_readdir(&dir, dir_info)) != NULL) {
plougher1f413c82005-11-18 00:02:14 +00003903 struct inode_info *inode_info = dir_ent->inode;
3904 struct stat *buf = &inode_info->buf;
3905 char *filename = dir_ent->pathname;
3906 char *dir_name = dir_ent->name;
plougher50b31762009-03-31 04:14:46 +00003907 unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR)
3908 ? dir_ent->inode->inode_number :
plougher110799c2009-03-30 01:50:40 +00003909 dir_ent->inode->inode_number + dir_inode_no;
plougher1f413c82005-11-18 00:02:14 +00003910
3911 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3912 switch(buf->st_mode & S_IFMT) {
3913 case S_IFREG:
3914 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00003915 write_file(inode, dir_ent,
3916 &duplicate_file);
3917 INFO("file %s, uncompressed size %lld "
3918 "bytes %s\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003919 (long long) buf->st_size,
3920 duplicate_file ? "DUPLICATE" :
3921 "");
plougher1f413c82005-11-18 00:02:14 +00003922 break;
3923
3924 case S_IFDIR:
3925 squashfs_type = SQUASHFS_DIR_TYPE;
plougher43244f22009-04-05 02:04:51 +00003926 dir_scan3(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003927 break;
3928
3929 case S_IFLNK:
3930 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003931 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003932 squashfs_type, 0, 0, 0, NULL,
3933 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003934 INFO("symbolic link %s inode 0x%llx\n",
3935 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003936 sym_count ++;
3937 break;
3938
3939 case S_IFCHR:
3940 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003941 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003942 squashfs_type, 0, 0, 0, NULL,
3943 NULL, NULL, 0);
3944 INFO("character device %s inode 0x%llx"
3945 "\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003946 dev_count ++;
3947 break;
3948
3949 case S_IFBLK:
3950 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003951 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003952 squashfs_type, 0, 0, 0, NULL,
3953 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003954 INFO("block device %s inode 0x%llx\n",
3955 dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003956 dev_count ++;
3957 break;
3958
3959 case S_IFIFO:
3960 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003961 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003962 squashfs_type, 0, 0, 0, NULL,
3963 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003964 INFO("fifo %s inode 0x%llx\n",dir_name,
3965 *inode);
plougher1f413c82005-11-18 00:02:14 +00003966 fifo_count ++;
3967 break;
3968
3969 case S_IFSOCK:
3970 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003971 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003972 squashfs_type, 0, 0, 0, NULL,
3973 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003974 INFO("unix domain socket %s inode "
3975 "0x%llx\n", dir_name, *inode);
plougher1f413c82005-11-18 00:02:14 +00003976 sock_count ++;
3977 break;
3978
plougher23377982007-11-12 04:04:48 +00003979 default:
plougherb3604122009-03-30 02:07:20 +00003980 BAD_ERROR("%s unrecognised file type, "
3981 "mode is %x\n", filename,
3982 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00003983 }
3984 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00003985 dir_ent->inode->type = squashfs_type;
3986 } else {
3987 *inode = dir_ent->inode->inode;
3988 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00003989 switch(squashfs_type) {
3990 case SQUASHFS_FILE_TYPE:
3991 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00003992 INFO("file %s, uncompressed "
3993 "size %lld bytes LINK"
3994 "\n", filename,
plougher82ab2332009-04-21 00:21:21 +00003995 (long long)
plougher50b31762009-03-31 04:14:46 +00003996 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00003997 break;
3998 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00003999 INFO("symbolic link %s inode 0x%llx "
4000 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004001 break;
4002 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004003 INFO("character device %s inode 0x%llx "
4004 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004005 break;
plougher5507dd92006-11-06 00:43:10 +00004006 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004007 INFO("block device %s inode 0x%llx "
4008 "LINK\n", dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004009 break;
4010 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00004011 INFO("fifo %s inode 0x%llx LINK\n",
4012 dir_name, *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004013 break;
4014 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00004015 INFO("unix domain socket %s inode "
4016 "0x%llx LINK\n", dir_name,
4017 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004018 break;
4019 }
plougher1f413c82005-11-18 00:02:14 +00004020 }
4021
plougher29e37092007-04-15 01:24:51 +00004022 add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00004023 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004024 }
4025
plougher29e37092007-04-15 01:24:51 +00004026 write_dir(inode, dir_info, &dir);
plougher1f413c82005-11-18 00:02:14 +00004027 INFO("directory %s inode 0x%llx\n", pathname, *inode);
4028
plougher43244f22009-04-05 02:04:51 +00004029 scan3_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004030}
4031
4032
4033unsigned int slog(unsigned int block)
4034{
4035 int i;
4036
plougher4c99cb72007-06-14 21:46:31 +00004037 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00004038 if(block == (1 << i))
4039 return i;
4040 return 0;
4041}
4042
4043
plougher8f8e1a12007-10-18 02:50:21 +00004044int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00004045{
4046 int i;
4047
4048 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00004049 if((exclude_paths[i].st_dev == buf->st_dev) &&
4050 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00004051 return TRUE;
4052 return FALSE;
4053}
4054
4055
4056#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00004057 if(exclude % EXCLUDE_SIZE == 0) { \
4058 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4059 * sizeof(struct exclude_info)); \
4060 if(exclude_paths == NULL) \
4061 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
4062 } \
4063 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00004064 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00004065int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00004066{
4067 int i;
plougher91fbb302008-05-06 02:29:36 +00004068 char filename[4096];
plougher1f413c82005-11-18 00:02:14 +00004069 struct stat buf;
4070
plougherb3604122009-03-30 02:07:20 +00004071 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4072 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00004073 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00004074 ERROR("Cannot stat exclude dir/file %s because %s, "
4075 "ignoring", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004076 return TRUE;
4077 }
4078 ADD_ENTRY(buf);
4079 return TRUE;
4080 }
4081
4082 for(i = 0; i < source; i++) {
4083 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
4084 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00004085 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00004086 ERROR("Cannot stat exclude dir/file %s because "
plougher50b31762009-03-31 04:14:46 +00004087 "%s, ignoring", filename,
4088 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004089 continue;
4090 }
4091 ADD_ENTRY(buf);
4092 }
4093 return TRUE;
4094}
4095
4096
plougherb3604122009-03-30 02:07:20 +00004097void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4098 int type)
plougher1f413c82005-11-18 00:02:14 +00004099{
plougherb3604122009-03-30 02:07:20 +00004100 old_root_entry = realloc(old_root_entry,
4101 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4102 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00004103 BAD_ERROR("Out of memory in old root directory entries "
4104 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00004105
ploughera326c182009-08-29 05:41:45 +00004106 old_root_entry[old_root_entries].name = strdup(name);
4107 old_root_entry[old_root_entries].inode.inode = inode;
4108 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4109 old_root_entry[old_root_entries].inode.type = type;
4110 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004111}
4112
4113
plougher5741d792010-09-04 03:20:50 +00004114void initialise_threads(int readb_mbytes, int writeb_mbytes,
4115 int fragmentb_mbytes)
plougher5507dd92006-11-06 00:43:10 +00004116{
4117 int i;
4118 sigset_t sigmask, old_mask;
plougher5741d792010-09-04 03:20:50 +00004119 int reader_buffer_size = readb_mbytes << (20 - block_log);
4120 int fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
4121
4122 /*
4123 * writer_buffer_size is global because it is needed in
4124 * write_file_blocks_dup()
4125 */
4126 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004127
4128 sigemptyset(&sigmask);
4129 sigaddset(&sigmask, SIGINT);
4130 sigaddset(&sigmask, SIGQUIT);
4131 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4132 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4133
4134 signal(SIGUSR1, sigusr1_handler);
4135
4136 if(processors == -1) {
4137#ifndef linux
4138 int mib[2];
4139 size_t len = sizeof(processors);
4140
4141 mib[0] = CTL_HW;
4142#ifdef HW_AVAILCPU
4143 mib[1] = HW_AVAILCPU;
4144#else
4145 mib[1] = HW_NCPU;
4146#endif
4147
4148 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004149 ERROR("Failed to get number of available processors. "
4150 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004151 processors = 1;
4152 }
4153#else
plougher9cc26b72010-08-17 01:05:55 +00004154 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004155#endif
4156 }
4157
plougherf2d2a842010-12-18 02:43:48 +00004158 thread = malloc((2 + processors * 2) * sizeof(pthread_t));
4159 if(thread == NULL)
plougher5507dd92006-11-06 00:43:10 +00004160 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004161 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004162 frag_deflator_thread = &deflator_thread[processors];
4163
4164 to_reader = queue_init(1);
4165 from_reader = queue_init(reader_buffer_size);
4166 to_writer = queue_init(writer_buffer_size);
4167 from_writer = queue_init(1);
4168 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004169 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004170 reader_buffer = cache_init(block_size, reader_buffer_size);
4171 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004172 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004173 pthread_create(&thread[0], NULL, reader, NULL);
4174 pthread_create(&thread[1], NULL, writer, NULL);
plougher91fbb302008-05-06 02:29:36 +00004175 pthread_create(&progress_thread, NULL, progress_thrd, NULL);
plougher5507dd92006-11-06 00:43:10 +00004176 pthread_mutex_init(&fragment_mutex, NULL);
4177 pthread_cond_init(&fragment_waiting, NULL);
4178
4179 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004180 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4181 0)
plougher5507dd92006-11-06 00:43:10 +00004182 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004183 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4184 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004185 BAD_ERROR("Failed to create thread\n");
4186 }
4187
4188 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4189 processors == 1 ? "" : "s");
4190
4191 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4192 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4193}
4194
4195
plougher0e453652006-11-06 01:49:35 +00004196long long write_inode_lookup_table()
4197{
4198 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004199 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004200
4201 if(inode_count == sinode_count)
4202 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004203
plougher44f03282010-07-27 00:31:36 +00004204 it = realloc(inode_lookup_table, lookup_bytes);
4205 if(it == NULL)
plougher0e453652006-11-06 01:49:35 +00004206 BAD_ERROR("Out of memory in write_inode_table\n");
plougher44f03282010-07-27 00:31:36 +00004207 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004208
plougher0e453652006-11-06 01:49:35 +00004209 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4210 struct inode_info *inode = inode_info[i];
4211
4212 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004213
4214 inode_number = inode->type == SQUASHFS_DIR_TYPE ?
plougher360514a2009-03-30 03:01:38 +00004215 inode->inode_number : inode->inode_number +
4216 dir_inode_no;
plougher0e453652006-11-06 01:49:35 +00004217
plougher360514a2009-03-30 03:01:38 +00004218 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4219 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004220
plougher0e453652006-11-06 01:49:35 +00004221 }
4222 }
4223
plougher02bc3bc2007-02-25 12:12:01 +00004224skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004225 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4226 noI);
plougher0e453652006-11-06 01:49:35 +00004227}
4228
plougher2ea89142008-03-11 01:34:19 +00004229
plougher8f8e1a12007-10-18 02:50:21 +00004230char *get_component(char *target, char *targname)
4231{
4232 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004233 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004234
4235 while(*target != '/' && *target!= '\0')
4236 *targname ++ = *target ++;
4237
4238 *targname = '\0';
4239
4240 return target;
4241}
4242
4243
4244void free_path(struct pathname *paths)
4245{
4246 int i;
4247
4248 for(i = 0; i < paths->names; i++) {
4249 if(paths->name[i].paths)
4250 free_path(paths->name[i].paths);
4251 free(paths->name[i].name);
4252 if(paths->name[i].preg) {
4253 regfree(paths->name[i].preg);
4254 free(paths->name[i].preg);
4255 }
4256 }
4257
4258 free(paths);
4259}
4260
4261
4262struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4263{
4264 char targname[1024];
4265 int i, error;
4266
4267 target = get_component(target, targname);
4268
4269 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004270 paths = malloc(sizeof(struct pathname));
4271 if(paths == NULL)
plougher8f8e1a12007-10-18 02:50:21 +00004272 BAD_ERROR("failed to allocate paths\n");
4273
4274 paths->names = 0;
4275 paths->name = NULL;
4276 }
4277
4278 for(i = 0; i < paths->names; i++)
4279 if(strcmp(paths->name[i].name, targname) == 0)
4280 break;
4281
4282 if(i == paths->names) {
4283 /* allocate new name entry */
4284 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004285 paths->name = realloc(paths->name, (i + 1) *
4286 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004287 if(paths->name == NULL)
4288 BAD_ERROR("Out of memory in add path\n");
plougher8f8e1a12007-10-18 02:50:21 +00004289 paths->name[i].name = strdup(targname);
4290 paths->name[i].paths = NULL;
4291 if(use_regex) {
4292 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004293 if(paths->name[i].preg == NULL)
4294 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004295 error = regcomp(paths->name[i].preg, targname,
4296 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004297 if(error) {
plougher8f8e1a12007-10-18 02:50:21 +00004298 char str[1024];
4299
4300 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004301 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004302 "because %s\n", targname, alltarget,
4303 str);
plougher8f8e1a12007-10-18 02:50:21 +00004304 }
4305 } else
4306 paths->name[i].preg = NULL;
4307
4308 if(target[0] == '\0')
4309 /* at leaf pathname component */
4310 paths->name[i].paths = NULL;
4311 else
4312 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004313 paths->name[i].paths = add_path(NULL, target,
4314 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004315 } else {
4316 /* existing matching entry */
4317 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004318 /* No sub-directory which means this is the leaf
4319 * component of a pre-existing exclude which subsumes
4320 * the exclude currently being added, in which case stop
4321 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004322 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004323 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004324 * from more specific excludes, delete as they're
4325 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004326 free_path(paths->name[i].paths);
4327 paths->name[i].paths = NULL;
4328 } else
4329 /* recurse adding child components */
4330 add_path(paths->name[i].paths, target, alltarget);
4331 }
4332
4333 return paths;
4334}
plougher2ea89142008-03-11 01:34:19 +00004335
4336
plougher05e50ef2007-10-23 12:34:20 +00004337void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004338{
plougher05e50ef2007-10-23 12:34:20 +00004339
plougherb3604122009-03-30 02:07:20 +00004340 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4341 strncmp(target, "../", 3) == 0)
4342 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4343 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004344 else if(strncmp(target, "... ", 4) == 0)
4345 stickypath = add_path(stickypath, target + 4, target + 4);
4346 else
4347 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004348}
4349
4350
4351void display_path(int depth, struct pathname *paths)
4352{
4353 int i, n;
4354
4355 if(paths == NULL)
4356 return;
4357
4358 for(i = 0; i < paths->names; i++) {
4359 for(n = 0; n < depth; n++)
4360 printf("\t");
4361 printf("%d: %s\n", depth, paths->name[i].name);
4362 display_path(depth + 1, paths->name[i].paths);
4363 }
4364}
4365
4366
4367void display_path2(struct pathname *paths, char *string)
4368{
4369 int i;
4370 char path[1024];
4371
4372 if(paths == NULL) {
4373 printf("%s\n", string);
4374 return;
4375 }
4376
4377 for(i = 0; i < paths->names; i++) {
4378 strcat(strcat(strcpy(path, string), "/"), paths->name[i].name);
4379 display_path2(paths->name[i].paths, path);
4380 }
4381}
4382
4383
plougherf9039c92007-10-22 03:54:16 +00004384struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004385{
ploughera2968ef2009-03-03 10:46:00 +00004386 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004387 if(new == NULL)
4388 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004389 new->count = 0;
4390 return new;
4391}
4392
4393
4394struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4395{
plougher6f2a8262010-07-27 00:37:19 +00004396 if(paths->count % PATHS_ALLOC_SIZE == 0) {
plougherb3604122009-03-30 02:07:20 +00004397 paths = realloc(paths, sizeof(struct pathnames *) +
4398 (paths->count + PATHS_ALLOC_SIZE) *
4399 sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004400 if(paths == NULL)
4401 BAD_ERROR("Out of memory in add_subdir\n");
4402 }
plougherf9039c92007-10-22 03:54:16 +00004403
4404 paths->path[paths->count++] = path;
4405 return paths;
4406}
4407
4408
4409void free_subdir(struct pathnames *paths)
4410{
4411 free(paths);
4412}
4413
4414
4415int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4416{
4417 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004418
plougherf9039c92007-10-22 03:54:16 +00004419 if(paths == NULL) {
4420 *new = NULL;
4421 return FALSE;
4422 }
plougher8f8e1a12007-10-18 02:50:21 +00004423
plougherf9039c92007-10-22 03:54:16 +00004424
4425 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004426 if(stickypath)
4427 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004428
4429 for(n = 0; n < paths->count; n++) {
4430 struct pathname *path = paths->path[n];
4431
4432 for(i = 0; i < path->names; i++) {
4433 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004434 regexec(path->name[i].preg, name, (size_t) 0,
4435 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004436 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004437 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4438 0;
plougherf9039c92007-10-22 03:54:16 +00004439
4440 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004441 /* match on a leaf component, any subdirectories
4442 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004443 res = TRUE;
4444 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004445 }
4446
plougherf9039c92007-10-22 03:54:16 +00004447 if(match)
plougherb3604122009-03-30 02:07:20 +00004448 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004449 * subdirectories to the new set of
4450 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004451 *new = add_subdir(*new, path->name[i].paths);
4452 }
4453 }
4454
4455 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004456 /* no matching names found, return empty new search set
4457 */
plougherf9039c92007-10-22 03:54:16 +00004458 res = FALSE;
4459 goto empty_set;
4460 }
4461
4462 /* one or more matches with sub-directories found (no leaf matches).
4463 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004464 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004465
4466empty_set:
4467 free_subdir(*new);
4468 *new = NULL;
4469 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004470}
4471
4472
plougher99ac0cc2007-10-29 03:17:10 +00004473#define RECOVER_ID "Squashfs recovery file v1.0\n"
4474#define RECOVER_ID_SIZE 28
4475
plougher64e83fd2010-12-31 21:21:26 +00004476void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004477{
plougher1d065e92010-06-18 03:58:27 +00004478 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004479 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004480 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004481 char header[] = RECOVER_ID;
4482
4483 if(recover == FALSE) {
4484 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004485 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004486 return;
4487 }
4488
plougher1b879bc2010-12-18 02:49:42 +00004489 metadata = malloc(bytes);
4490 if(metadata == NULL)
plougher50b31762009-03-31 04:14:46 +00004491 BAD_ERROR("Failed to alloc metadata buffer in "
4492 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004493
plougher1d065e92010-06-18 03:58:27 +00004494 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4495 if(res == 0)
4496 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004497
plougherb3604122009-03-30 02:07:20 +00004498 sprintf(recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004499 getbase(destination_file), pid);
plougherb3604122009-03-30 02:07:20 +00004500 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4501 if(recoverfd == -1)
4502 BAD_ERROR("Failed to create recovery file, because %s. "
4503 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004504
plougher628e7682009-03-29 22:12:24 +00004505 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004506 BAD_ERROR("Failed to write recovery file, because %s\n",
4507 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004508
plougher64e83fd2010-12-31 21:21:26 +00004509 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004510 BAD_ERROR("Failed to write recovery file, because %s\n",
4511 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004512
plougher628e7682009-03-29 22:12:24 +00004513 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004514 BAD_ERROR("Failed to write recovery file, because %s\n",
4515 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004516
4517 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004518 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004519
4520 printf("Recovery file \"%s\" written\n", recovery_file);
4521 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004522 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4523 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004524 printf("to restore filesystem\n\n");
4525}
4526
4527
4528void read_recovery_data(char *recovery_file, char *destination_file)
4529{
4530 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004531 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004532 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004533 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004534 struct stat buf;
4535 char header[] = RECOVER_ID;
4536 char header2[RECOVER_ID_SIZE];
4537
plougher9e9d9dc2010-12-18 02:53:57 +00004538 recoverfd = open(recovery_file, O_RDONLY);
4539 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004540 BAD_ERROR("Failed to open recovery file because %s\n",
4541 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004542
4543 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004544 BAD_ERROR("Failed to stat destination file, because %s\n",
4545 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004546
plougher9e9d9dc2010-12-18 02:53:57 +00004547 fd = open(destination_file, O_RDWR);
4548 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004549 BAD_ERROR("Failed to open destination file because %s\n",
4550 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004551
plougher8a8c4102009-03-29 22:28:49 +00004552 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4553 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004554 BAD_ERROR("Failed to read recovery file, because %s\n",
4555 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004556 if(res < RECOVER_ID_SIZE)
4557 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004558 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4559 BAD_ERROR("Not a recovery file\n");
4560
plougher64e83fd2010-12-31 21:21:26 +00004561 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004562 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004563 BAD_ERROR("Failed to read recovery file, because %s\n",
4564 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004565 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004566 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004567
plougher64e83fd2010-12-31 21:21:26 +00004568 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004569 if(res == 0)
4570 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004571
plougherb3604122009-03-30 02:07:20 +00004572 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004573 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004574 BAD_ERROR("Recovery file and destination file do not seem to "
4575 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004576
4577 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4578
plougher9e9d9dc2010-12-18 02:53:57 +00004579 metadata = malloc(bytes);
4580 if(metadata == NULL)
plougherb3604122009-03-30 02:07:20 +00004581 BAD_ERROR("Failed to alloc metadata buffer in "
4582 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004583
plougher8a8c4102009-03-29 22:28:49 +00004584 res = read_bytes(recoverfd, metadata, bytes);
4585 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004586 BAD_ERROR("Failed to read recovery file, because %s\n",
4587 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004588 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004589 BAD_ERROR("Recovery file appears to be truncated\n");
4590
plougher64e83fd2010-12-31 21:21:26 +00004591 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004592
plougher0dd6f122009-03-29 21:43:57 +00004593 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004594
4595 close(recoverfd);
4596 close(fd);
4597
plougherb3604122009-03-30 02:07:20 +00004598 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4599 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004600
4601 exit(0);
4602}
4603
4604
plougher1f413c82005-11-18 00:02:14 +00004605#define VERSION() \
Phillip Lougher43cc4282012-01-25 00:25:56 +00004606 printf("mksquashfs version 4.2-CVS (2012/01/24)\n");\
Phillip Lougher78a0cc62011-02-20 04:45:36 +00004607 printf("copyright (C) 2011 Phillip Lougher "\
plougher16111452010-07-22 05:12:18 +00004608 "<phillip@lougher.demon.co.uk>\n\n"); \
4609 printf("This program is free software; you can redistribute it and/or"\
4610 "\n");\
4611 printf("modify it under the terms of the GNU General Public License"\
4612 "\n");\
4613 printf("as published by the Free Software Foundation; either version "\
4614 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004615 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004616 printf("This program is distributed in the hope that it will be "\
4617 "useful,\n");\
4618 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4619 "of\n");\
4620 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4621 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004622 printf("GNU General Public License for more details.\n");
4623int main(int argc, char *argv[])
4624{
plougher324978d2006-02-27 04:53:29 +00004625 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00004626 int res, i;
plougher64e83fd2010-12-31 21:21:26 +00004627 struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +00004628 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004629 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004630 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004631 int readb_mbytes = READER_BUFFER_DEFAULT,
4632 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4633 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
plougher1f413c82005-11-18 00:02:14 +00004634
plougher91fbb302008-05-06 02:29:36 +00004635 pthread_mutex_init(&progress_mutex, NULL);
plougher1f413c82005-11-18 00:02:14 +00004636 block_log = slog(block_size);
4637 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
4638 VERSION();
4639 exit(0);
4640 }
4641 for(i = 1; i < argc && argv[i][0] != '-'; i++);
4642 if(i < 3)
4643 goto printOptions;
4644 source_path = argv + 1;
4645 source = i - 2;
plougher4da4bd42010-11-21 05:01:54 +00004646 /*
4647 * lookup default compressor. Note the Makefile ensures the default
4648 * compressor has been built, and so we don't need to to check
4649 * for failure here
4650 */
plougher5c2adaf2010-11-22 01:00:15 +00004651 comp = lookup_compressor(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00004652 for(; i < argc; i++) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01004653 if(strcmp(argv[i], "-action") == 0) {
4654 if(++i == argc) {
4655 ERROR("%s: -action missing action\n",
4656 argv[0]);
4657 exit(1);
4658 }
4659 res = parse_action(argv[i]);
4660 if(res == 0)
4661 exit(1);
4662
4663 } else if(strcmp(argv[i], "-comp") == 0) {
plougherc5d59872010-11-22 01:36:01 +00004664 if(compressor_opts_parsed) {
4665 ERROR("%s: -comp must appear before -X options"
4666 "\n", argv[0]);
4667 exit(1);
4668 }
plougherae9dcd82009-08-01 02:59:38 +00004669 if(++i == argc) {
4670 ERROR("%s: -comp missing compression type\n",
4671 argv[0]);
4672 exit(1);
4673 }
plougher5c2adaf2010-11-22 01:00:15 +00004674 comp = lookup_compressor(argv[i]);
plougher4da4bd42010-11-21 05:01:54 +00004675 if(!comp->supported) {
plougherc5d59872010-11-22 01:36:01 +00004676 ERROR("%s: Compressor \"%s\" is not supported!"
4677 "\n", argv[0], argv[i]);
4678 ERROR("%s: Compressors available:\n", argv[0]);
plougher4da4bd42010-11-21 05:01:54 +00004679 display_compressors("", COMP_DEFAULT);
4680 exit(1);
4681 }
plougherb5576ea2010-11-22 01:06:53 +00004682
4683 } else if(strncmp(argv[i], "-X", 2) == 0) {
4684 int args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00004685 if(args < 0) {
4686 if(args == -1) {
4687 ERROR("%s: Unrecognised compressor"
4688 " option %s\n", argv[0],
4689 argv[i]);
4690 ERROR("%s: Did you forget to specify"
4691 " -comp, or specify it after"
4692 " the compressor specific"
4693 " option?\n", argv[0]);
4694 }
plougherb5576ea2010-11-22 01:06:53 +00004695 exit(1);
4696 }
4697 i += args;
plougherc5d59872010-11-22 01:36:01 +00004698 compressor_opts_parsed = 1;
plougherb5576ea2010-11-22 01:06:53 +00004699
plougherae9dcd82009-08-01 02:59:38 +00004700 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00004701 if(++i == argc) {
4702 ERROR("%s: -pf missing filename\n", argv[0]);
4703 exit(1);
4704 }
plougher620b7172009-09-10 04:17:48 +00004705 if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004706 exit(1);
plougher43244f22009-04-05 02:04:51 +00004707 } else if(strcmp(argv[i], "-p") == 0) {
4708 if(++i == argc) {
4709 ERROR("%s: -p missing pseudo file definition\n",
4710 argv[0]);
4711 exit(1);
4712 }
plougher620b7172009-09-10 04:17:48 +00004713 if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004714 exit(1);
plougher43244f22009-04-05 02:04:51 +00004715 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00004716 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00004717 ERROR("%s: -recover missing recovery file\n",
4718 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00004719 exit(1);
4720 }
4721 read_recovery_data(argv[i], argv[source + 1]);
4722 } else if(strcmp(argv[i], "-no-recovery") == 0)
4723 recover = FALSE;
4724 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00004725 old_exclude = FALSE;
4726 use_regex = FALSE;
4727 } else if(strcmp(argv[i], "-regex") == 0) {
4728 old_exclude = FALSE;
4729 use_regex = TRUE;
4730 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00004731 sparse_files = FALSE;
4732 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00004733 progress = FALSE;
4734 else if(strcmp(argv[i], "-no-exports") == 0)
4735 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00004736 else if(strcmp(argv[i], "-processors") == 0) {
plougher360514a2009-03-30 03:01:38 +00004737 if((++i == argc) || (processors =
4738 strtol(argv[i], &b, 10), *b != '\0')) {
4739 ERROR("%s: -processors missing or invalid "
4740 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004741 exit(1);
4742 }
4743 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00004744 ERROR("%s: -processors should be 1 or larger\n",
4745 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004746 exit(1);
4747 }
plougher0e453652006-11-06 01:49:35 +00004748 } else if(strcmp(argv[i], "-read-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004749 if((++i == argc) || (readb_mbytes =
4750 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004751 ERROR("%s: -read-queue missing or invalid "
4752 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004753 exit(1);
4754 }
4755 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00004756 ERROR("%s: -read-queue should be 1 megabyte or "
4757 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004758 exit(1);
4759 }
plougher0e453652006-11-06 01:49:35 +00004760 } else if(strcmp(argv[i], "-write-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004761 if((++i == argc) || (writeb_mbytes =
4762 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004763 ERROR("%s: -write-queue missing or invalid "
4764 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004765 exit(1);
4766 }
4767 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004768 ERROR("%s: -write-queue should be 1 megabyte "
4769 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004770 exit(1);
4771 }
plougher217bad82008-04-05 11:36:41 +00004772 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004773 if((++i == argc) ||
4774 (fragmentb_mbytes =
4775 strtol(argv[i], &b, 10), *b != '\0')) {
4776 ERROR("%s: -fragment-queue missing or invalid "
4777 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004778 exit(1);
4779 }
4780 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004781 ERROR("%s: -fragment-queue should be 1 "
4782 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004783 exit(1);
4784 }
plougher5507dd92006-11-06 00:43:10 +00004785 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00004786 if(++i == argc) {
4787 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004788 exit(1);
4789 }
plougher4c99cb72007-06-14 21:46:31 +00004790 block_size = strtol(argv[i], &b, 10);
4791 if(*b == 'm' || *b == 'M')
4792 block_size *= 1048576;
4793 else if(*b == 'k' || *b == 'K')
4794 block_size *= 1024;
4795 else if(*b != '\0') {
4796 ERROR("%s: -b invalid block size\n", argv[0]);
4797 exit(1);
4798 }
plougher1f413c82005-11-18 00:02:14 +00004799 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00004800 ERROR("%s: -b block size not power of two or "
4801 "not between 4096 and 1Mbyte\n",
4802 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004803 exit(1);
4804 }
4805 } else if(strcmp(argv[i], "-ef") == 0) {
4806 if(++i == argc) {
4807 ERROR("%s: -ef missing filename\n", argv[0]);
4808 exit(1);
4809 }
plougher9b5bf8c2006-03-20 18:43:33 +00004810 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00004811 duplicate_checking = FALSE;
4812
4813 else if(strcmp(argv[i], "-no-fragments") == 0)
4814 no_fragments = TRUE;
4815
4816 else if(strcmp(argv[i], "-always-use-fragments") == 0)
4817 always_use_fragments = TRUE;
4818
4819 else if(strcmp(argv[i], "-sort") == 0) {
4820 if(++i == argc) {
4821 ERROR("%s: -sort missing filename\n", argv[0]);
4822 exit(1);
4823 }
4824 } else if(strcmp(argv[i], "-all-root") == 0 ||
4825 strcmp(argv[i], "-root-owned") == 0)
4826 global_uid = global_gid = 0;
4827
4828 else if(strcmp(argv[i], "-force-uid") == 0) {
4829 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004830 ERROR("%s: -force-uid missing uid or user\n",
4831 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004832 exit(1);
4833 }
4834 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004835 if(global_uid < 0 || global_uid >
4836 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004837 ERROR("%s: -force-uid uid out of range"
4838 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004839 exit(1);
4840 }
4841 } else {
4842 struct passwd *uid = getpwnam(argv[i]);
4843 if(uid)
4844 global_uid = uid->pw_uid;
4845 else {
plougher360514a2009-03-30 03:01:38 +00004846 ERROR("%s: -force-uid invalid uid or "
4847 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004848 exit(1);
4849 }
4850 }
4851 } else if(strcmp(argv[i], "-force-gid") == 0) {
4852 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00004853 ERROR("%s: -force-gid missing gid or group\n",
4854 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004855 exit(1);
4856 }
4857 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004858 if(global_gid < 0 || global_gid >
4859 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004860 ERROR("%s: -force-gid gid out of range"
4861 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004862 exit(1);
4863 }
4864 } else {
4865 struct group *gid = getgrnam(argv[i]);
4866 if(gid)
4867 global_gid = gid->gr_gid;
4868 else {
plougher360514a2009-03-30 03:01:38 +00004869 ERROR("%s: -force-gid invalid gid or "
4870 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004871 exit(1);
4872 }
4873 }
4874 } else if(strcmp(argv[i], "-noI") == 0 ||
4875 strcmp(argv[i], "-noInodeCompression") == 0)
4876 noI = TRUE;
4877
4878 else if(strcmp(argv[i], "-noD") == 0 ||
4879 strcmp(argv[i], "-noDataCompression") == 0)
4880 noD = TRUE;
4881
4882 else if(strcmp(argv[i], "-noF") == 0 ||
4883 strcmp(argv[i], "-noFragmentCompression") == 0)
4884 noF = TRUE;
4885
plougherb99d7832010-05-19 01:57:34 +00004886 else if(strcmp(argv[i], "-noX") == 0 ||
4887 strcmp(argv[i], "-noXattrCompression") == 0)
4888 noX = TRUE;
4889
plougherce564c62010-05-19 03:01:49 +00004890 else if(strcmp(argv[i], "-no-xattrs") == 0)
4891 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00004892
plougher30281c82010-08-25 05:06:11 +00004893 else if(strcmp(argv[i], "-xattrs") == 0)
4894 no_xattrs = FALSE;
4895
plougher1f413c82005-11-18 00:02:14 +00004896 else if(strcmp(argv[i], "-nopad") == 0)
4897 nopad = TRUE;
4898
plougher91fbb302008-05-06 02:29:36 +00004899 else if(strcmp(argv[i], "-info") == 0) {
4900 silent = FALSE;
4901 progress = FALSE;
4902 }
plougher1f413c82005-11-18 00:02:14 +00004903
4904 else if(strcmp(argv[i], "-e") == 0)
4905 break;
4906
4907 else if(strcmp(argv[i], "-noappend") == 0)
4908 delete = TRUE;
4909
4910 else if(strcmp(argv[i], "-keep-as-directory") == 0)
4911 keep_as_directory = TRUE;
4912
4913 else if(strcmp(argv[i], "-root-becomes") == 0) {
4914 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004915 ERROR("%s: -root-becomes: missing name\n",
4916 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004917 exit(1);
4918 }
4919 root_name = argv[i];
4920 } else if(strcmp(argv[i], "-version") == 0) {
4921 VERSION();
4922 } else {
4923 ERROR("%s: invalid option\n\n", argv[0]);
4924printOptions:
plougher360514a2009-03-30 03:01:38 +00004925 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
4926 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00004927 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00004928 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00004929 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00004930 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00004931 ERROR("-b <block_size>\t\tset data block to "
4932 "<block_size>. Default %d bytes\n",
4933 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00004934 ERROR("-no-exports\t\tdon't make the filesystem "
4935 "exportable via NFS\n");
4936 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00004937 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00004938 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00004939 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00004940 "\n");
plougher1f413c82005-11-18 00:02:14 +00004941 ERROR("-noI\t\t\tdo not compress inode table\n");
4942 ERROR("-noD\t\t\tdo not compress data blocks\n");
4943 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00004944 ERROR("-noX\t\t\tdo not compress extended "
4945 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00004946 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00004947 ERROR("-always-use-fragments\tuse fragment blocks for "
4948 "files larger than block size\n");
4949 ERROR("-no-duplicates\t\tdo not perform duplicate "
4950 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00004951 ERROR("-all-root\t\tmake all files owned by root\n");
4952 ERROR("-force-uid uid\t\tset all file uids to uid\n");
4953 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00004954 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
4955 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00004956 ERROR("-keep-as-directory\tif one source directory is "
4957 "specified, create a root\n");
4958 ERROR("\t\t\tdirectory containing that directory, "
4959 "rather than the\n");
4960 ERROR("\t\t\tcontents of the directory\n");
4961 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00004962 ERROR("-p <pseudo-definition>\tAdd pseudo file "
4963 "definition\n");
4964 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
4965 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00004966 ERROR("-sort <sort_file>\tsort files according to "
4967 "priorities in <sort_file>. One\n");
4968 ERROR("\t\t\tfile or dir with priority per line. "
4969 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00004970 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00004971 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
4972 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00004973 ERROR("-wildcards\t\tAllow extended shell wildcards "
4974 "(globbing) to be used in\n\t\t\texclude "
4975 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00004976 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
4977 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00004978 ERROR("\nFilesystem append options:\n");
4979 ERROR("-noappend\t\tdo not append to existing "
4980 "filesystem\n");
4981 ERROR("-root-becomes <name>\twhen appending source "
4982 "files/directories, make the\n");
4983 ERROR("\t\t\toriginal root become a subdirectory in "
4984 "the new root\n");
4985 ERROR("\t\t\tcalled <name>, rather than adding the new "
4986 "source items\n");
4987 ERROR("\t\t\tto the original root\n");
4988 ERROR("\nMksquashfs runtime options:\n");
4989 ERROR("-version\t\tprint version, licence and "
4990 "copyright message\n");
4991 ERROR("-recover <name>\t\trecover filesystem data "
4992 "using recovery file <name>\n");
4993 ERROR("-no-recovery\t\tdon't generate a recovery "
4994 "file\n");
4995 ERROR("-info\t\t\tprint files written to filesystem\n");
4996 ERROR("-no-progress\t\tdon't display the progress "
4997 "bar\n");
4998 ERROR("-processors <number>\tUse <number> processors."
4999 " By default will use number of\n");
5000 ERROR("\t\t\tprocessors available\n");
5001 ERROR("-read-queue <size>\tSet input queue to <size> "
5002 "Mbytes. Default %d Mbytes\n",
5003 READER_BUFFER_DEFAULT);
5004 ERROR("-write-queue <size>\tSet output queue to <size> "
5005 "Mbytes. Default %d Mbytes\n",
5006 WRITER_BUFFER_DEFAULT);
plougher8bc376b2010-11-12 04:55:20 +00005007 ERROR("-fragment-queue <size>\tSet fragment queue to "
plougher37632562009-08-07 19:09:01 +00005008 "<size> Mbytes. Default %d Mbytes\n",
5009 FRAGMENT_BUFFER_DEFAULT);
5010 ERROR("\nMiscellaneous options:\n");
5011 ERROR("-root-owned\t\talternative name for -all-root"
5012 "\n");
5013 ERROR("-noInodeCompression\talternative name for -noI"
5014 "\n");
5015 ERROR("-noDataCompression\talternative name for -noD"
5016 "\n");
5017 ERROR("-noFragmentCompression\talternative name for "
5018 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005019 ERROR("-noXattrCompression\talternative name for "
5020 "-noX\n");
plougher4fb66822010-12-08 02:49:28 +00005021 ERROR("\nCompressors available and compressor specific "
5022 "options:\n");
5023 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005024 exit(1);
5025 }
5026 }
5027
plougherb747f4f2010-12-25 04:05:47 +00005028 /*
5029 * Some compressors may need the options to be checked for validity
5030 * once all the options have been processed
5031 */
5032 res = compressor_options_post(comp, block_size);
5033 if(res)
5034 EXIT_MKSQUASHFS();
5035
plougher91fbb302008-05-06 02:29:36 +00005036 for(i = 0; i < source; i++)
5037 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005038 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005039 "because %s\n", source_path[i],
5040 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005041 EXIT_MKSQUASHFS();
5042 }
plougher324978d2006-02-27 04:53:29 +00005043
5044 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005045 if(stat(argv[source + 1], &buf) == -1) {
5046 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005047 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005048 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005049 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005050 perror("Could not create destination file");
5051 exit(1);
5052 }
5053 delete = TRUE;
5054 } else {
5055 perror("Could not stat destination file");
5056 exit(1);
5057 }
5058
5059 } else {
5060 if(S_ISBLK(buf.st_mode)) {
5061 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005062 perror("Could not open block device as "
5063 "destination");
plougher1f413c82005-11-18 00:02:14 +00005064 exit(1);
5065 }
5066 block_device = 1;
5067
5068 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005069 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5070 O_RDWR);
5071 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005072 perror("Could not open regular file for "
5073 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005074 exit(1);
5075 }
plougher44d54ef2010-02-08 22:13:49 +00005076 }
plougher1f413c82005-11-18 00:02:14 +00005077 else {
5078 ERROR("Destination not block device or regular file\n");
5079 exit(1);
5080 }
5081
plougher324978d2006-02-27 04:53:29 +00005082 }
plougher1f413c82005-11-18 00:02:14 +00005083
plougher4c99cb72007-06-14 21:46:31 +00005084 signal(SIGTERM, sighandler2);
5085 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00005086
plougher16111452010-07-22 05:12:18 +00005087 /*
5088 * process the exclude files - must be done afer destination file has
5089 * been possibly created
5090 */
plougher1f413c82005-11-18 00:02:14 +00005091 for(i = source + 2; i < argc; i++)
5092 if(strcmp(argv[i], "-ef") == 0) {
5093 FILE *fd;
5094 char filename[16385];
5095 if((fd = fopen(argv[++i], "r")) == NULL) {
5096 perror("Could not open exclude file...");
plougher324978d2006-02-27 04:53:29 +00005097 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005098 }
5099 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
plougher8f8e1a12007-10-18 02:50:21 +00005100 if(old_exclude)
5101 old_add_exclude(filename);
5102 else
plougher05e50ef2007-10-23 12:34:20 +00005103 add_exclude(filename);
plougher1f413c82005-11-18 00:02:14 +00005104 fclose(fd);
5105 } else if(strcmp(argv[i], "-e") == 0)
5106 break;
plougher8b9a7f62009-08-01 22:52:45 +00005107 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005108 strcmp(argv[i], "-sort") == 0 ||
5109 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005110 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005111 i++;
5112
5113 if(i != argc) {
5114 if(++i == argc) {
5115 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005116 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005117 }
plougher8f8e1a12007-10-18 02:50:21 +00005118 while(i < argc)
5119 if(old_exclude)
5120 old_add_exclude(argv[i++]);
5121 else
plougher05e50ef2007-10-23 12:34:20 +00005122 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005123 }
5124
5125 /* process the sort files - must be done afer the exclude files */
5126 for(i = source + 2; i < argc; i++)
5127 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005128 int res = read_sort_file(argv[++i], source,
5129 source_path);
5130 if(res == FALSE)
5131 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005132 sorted ++;
5133 } else if(strcmp(argv[i], "-e") == 0)
5134 break;
plougher8b9a7f62009-08-01 22:52:45 +00005135 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005136 strcmp(argv[i], "-ef") == 0 ||
5137 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005138 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005139 i++;
5140
plougher62d5b5c2008-08-16 01:49:42 +00005141#ifdef SQUASHFS_TRACE
5142 progress = FALSE;
5143#endif
5144
plougher4c99cb72007-06-14 21:46:31 +00005145 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005146 comp = read_super(fd, &sBlk, argv[source + 1]);
5147 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005148 ERROR("Failed to read existing filesystem - will not "
5149 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005150 ERROR("To force Mksquashfs to write to this block "
5151 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005152 EXIT_MKSQUASHFS();
5153 }
plougher1f413c82005-11-18 00:02:14 +00005154
plougher1f413c82005-11-18 00:02:14 +00005155 block_log = slog(block_size = sBlk.block_size);
5156 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5157 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5158 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005159 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005160 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5161 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5162 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005163 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005164 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005165 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005166 }
5167
plougher5741d792010-09-04 03:20:50 +00005168 initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
plougher4c99cb72007-06-14 21:46:31 +00005169
plougher13fdddf2010-11-24 01:23:41 +00005170 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5171 if(res)
5172 BAD_ERROR("compressor_init failed\n");
5173
plougher4c99cb72007-06-14 21:46:31 +00005174 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005175 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005176 void *comp_data = compressor_dump_options(comp, block_size,
5177 &size);
plougher3d7e5182010-12-25 01:49:42 +00005178
plougherdf6d8f02009-03-20 03:10:00 +00005179 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005180 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005181
plougher871c72a2010-12-25 04:17:27 +00005182 /*
5183 * store any compressor specific options after the superblock,
5184 * and set the COMP_OPT flag to show that the filesystem has
5185 * compressor specfic options
5186 */
plougher3d7e5182010-12-25 01:49:42 +00005187 if(comp_data) {
5188 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5189
5190 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005191 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005192 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005193 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005194 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005195 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005196 + size;
5197 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005198 } else
plougher64e83fd2010-12-31 21:21:26 +00005199 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005200 } else {
plougher360514a2009-03-30 03:01:38 +00005201 unsigned int last_directory_block, inode_dir_offset,
5202 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005203 inode_dir_start_block, uncompressed_data,
5204 compressed_data, inode_dir_inode_number,
5205 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005206 unsigned int root_inode_start =
5207 SQUASHFS_INODE_BLK(sBlk.root_inode),
5208 root_inode_offset =
5209 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005210
plougher360514a2009-03-30 03:01:38 +00005211 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5212 &data_cache, &directory_table,
5213 &directory_data_cache, &last_directory_block,
5214 &inode_dir_offset, &inode_dir_file_size,
5215 &root_inode_size, &inode_dir_start_block,
5216 &file_count, &sym_count, &dev_count, &dir_count,
5217 &fifo_count, &sock_count, &total_bytes,
5218 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005219 &inode_dir_inode_number,
5220 &inode_dir_parent_inode, add_old_root_entry,
5221 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005222 ERROR("Failed to read existing filesystem - will not "
5223 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005224 ERROR("To force Mksquashfs to write to this block "
5225 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005226 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005227 }
plougher6f2a8262010-07-27 00:37:19 +00005228 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005229 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005230 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005231 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005232 if(fragment_table == NULL)
5233 BAD_ERROR("Out of memory in save filesystem state\n");
5234 }
plougher1f413c82005-11-18 00:02:14 +00005235
plougher50b31762009-03-31 04:14:46 +00005236 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005237 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005238 block_size);
plougher89c7a512010-12-15 08:35:51 +00005239 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005240 "-always-use-fragments,\n-exportable and -comp options "
5241 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005242 printf("\nIf appending is not wanted, please re-run with "
5243 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005244
plougher360514a2009-03-30 03:01:38 +00005245 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5246 ~(SQUASHFS_METADATA_SIZE - 1);
5247 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5248 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005249
5250 /* save original filesystem state for restoring ... */
5251 sfragments = fragments;
5252 sbytes = bytes;
5253 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005254 scache_bytes = root_inode_offset + root_inode_size;
5255 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005256 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005257 if(sdata_cache == NULL)
5258 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005259 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005260 if(sdirectory_data_cache == NULL)
5261 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005262 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005263 memcpy(sdirectory_data_cache, directory_data_cache +
5264 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005265 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005266 stotal_bytes = total_bytes;
5267 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005268 stotal_directory_bytes = total_directory_bytes +
5269 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005270 sfile_count = file_count;
5271 ssym_count = sym_count;
5272 sdev_count = dev_count;
5273 sdir_count = dir_count + 1;
5274 sfifo_count = fifo_count;
5275 ssock_count = sock_count;
5276 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005277 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005278 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005279 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005280 BAD_ERROR("Failed to save xattrs from existing "
5281 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005282 restore = TRUE;
5283 if(setjmp(env))
5284 goto restore_filesystem;
5285 signal(SIGTERM, sighandler);
5286 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005287 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005288
plougher360514a2009-03-30 03:01:38 +00005289 /*
5290 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005291 * original filesystem. The filesystem state differs depending
5292 * on whether we're appending to the original root directory, or
5293 * if the original root directory becomes a sub-directory
5294 * (root-becomes specified on command line, here root_name !=
5295 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005296 */
5297 inode_bytes = inode_size = root_inode_start;
5298 directory_size = last_directory_block;
5299 cache_size = root_inode_offset + root_inode_size;
5300 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5301 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005302 sdirectory_bytes = last_directory_block;
5303 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005304 root_inode_number = inode_dir_parent_inode;
5305 dir_inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005306 directory_bytes = last_directory_block;
5307 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005308 memmove(directory_data_cache, directory_data_cache +
5309 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005310 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005311 add_old_root_entry(root_name, sBlk.root_inode,
5312 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005313 total_directory_bytes += compressed_data;
5314 dir_count ++;
5315 } else {
plougher360514a2009-03-30 03:01:38 +00005316 sdirectory_compressed_bytes = last_directory_block -
5317 inode_dir_start_block;
5318 sdirectory_compressed =
5319 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005320 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005321 BAD_ERROR("Out of memory in save filesystem "
5322 "state\n");
plougher360514a2009-03-30 03:01:38 +00005323 memcpy(sdirectory_compressed, directory_table +
5324 inode_dir_start_block,
5325 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005326 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005327 root_inode_number = inode_dir_inode_number;
plougher778e9362006-02-01 09:32:31 +00005328 dir_inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005329 directory_bytes = inode_dir_start_block;
5330 directory_cache_bytes = inode_dir_offset;
5331 cache_bytes = root_inode_offset;
5332 }
5333
plougher360514a2009-03-30 03:01:38 +00005334 inode_count = file_count + dir_count + sym_count + dev_count +
5335 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005336
5337 /*
5338 * The default use freelist before growing cache policy behaves
5339 * poorly with appending - with many deplicates the caches
5340 * do not grow due to the fact that large queues of outstanding
5341 * fragments/writer blocks do not occur, leading to small caches
5342 * and un-uncessary performance loss to frequent cache
5343 * replacement in the small caches. Therefore with appending
5344 * change the policy to grow the caches before reusing blocks
5345 * from the freelist
5346 */
5347 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005348 }
5349
plougher05e50ef2007-10-23 12:34:20 +00005350 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005351 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005352 if(path)
5353 paths = add_subdir(paths, path);
5354 if(stickypath)
5355 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005356 }
5357
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005358 dump_actions();
5359
plougher360514a2009-03-30 03:01:38 +00005360 if(delete && !keep_as_directory && source == 1 &&
5361 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005362 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005363 else if(!keep_as_directory && source == 1 &&
5364 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005365 dir_scan(&inode, source_path[0], scan1_single_readdir);
5366 else
5367 dir_scan(&inode, "", scan1_encomp_readdir);
5368 sBlk.root_inode = inode;
5369 sBlk.inodes = inode_count;
5370 sBlk.s_magic = SQUASHFS_MAGIC;
5371 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005372 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005373 sBlk.block_size = block_size;
5374 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005375 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005376 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005377 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005378 sBlk.mkfs_time = time(NULL);
5379
5380restore_filesystem:
plougher43bb7e92008-08-17 17:16:09 +00005381 if(progress && estimated_uncompressed) {
plougherc9b11db2008-05-06 23:59:15 +00005382 disable_progress_bar();
5383 progress_bar(cur_uncompressed, estimated_uncompressed, columns);
5384 }
5385
plougher1f413c82005-11-18 00:02:14 +00005386 sBlk.fragments = fragments;
plougher875bfef2010-08-12 23:48:41 +00005387 if(!restoring) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005388 struct file_buffer **fragment = NULL;
5389 while((fragment = get_frag_action(fragment)))
5390 write_fragment(*fragment);
plougher2ea89142008-03-11 01:34:19 +00005391 unlock_fragments();
5392 pthread_mutex_lock(&fragment_mutex);
5393 while(fragments_outstanding) {
5394 pthread_mutex_unlock(&fragment_mutex);
5395 sched_yield();
5396 pthread_mutex_lock(&fragment_mutex);
5397 }
plougher5507dd92006-11-06 00:43:10 +00005398 queue_put(to_writer, NULL);
5399 if(queue_get(from_writer) != 0)
5400 EXIT_MKSQUASHFS();
5401 }
5402
ploughere6e0e1b2010-05-12 17:17:06 +00005403 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005404 sBlk.inode_table_start = write_inodes();
5405 sBlk.directory_table_start = write_directories();
5406 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005407 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5408 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005409 sBlk.id_table_start = write_id_table();
5410 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005411
plougher0e453652006-11-06 01:49:35 +00005412 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005413 TRACE("sBlk->directory_table_start 0x%llx\n",
5414 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005415 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5416 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005417 TRACE("sBlk->lookup_table_start 0x%llx\n",
5418 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005419
plougher1f413c82005-11-18 00:02:14 +00005420 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005421
plougher8c4b7b92009-07-30 04:47:52 +00005422 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005423
plougher1f288f62009-02-21 03:05:52 +00005424 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher29e2ace2010-12-31 08:50:00 +00005425 write_destination(fd, SQUASHFS_START, sizeof(sBlk), &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005426
5427 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005428 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005429 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005430 }
5431
plougher99ac0cc2007-10-29 03:17:10 +00005432 close(fd);
5433
plougher11e7b1b2009-09-11 12:10:58 +00005434 delete_pseudo_files();
5435
plougher99ac0cc2007-10-29 03:17:10 +00005436 if(recovery_file[0] != '\0')
5437 unlink(recovery_file);
5438
plougher10f7d572010-07-20 02:14:04 +00005439 total_bytes += total_inode_bytes + total_directory_bytes +
plougher64e83fd2010-12-31 21:21:26 +00005440 sizeof(struct squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005441
plougher62542fb2009-08-06 08:43:08 +00005442 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5443 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5444 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005445 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005446 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5447 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005448 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5449 "compressed");
plougher50b31762009-03-31 04:14:46 +00005450 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5451 "not ");
plougher360514a2009-03-30 03:01:38 +00005452 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5453 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005454 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5455 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5456 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5457 inode_bytes, inode_bytes / 1024.0);
5458 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005459 ((float) inode_bytes / total_inode_bytes) * 100.0,
5460 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005461 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5462 directory_bytes, directory_bytes / 1024.0);
5463 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005464 ((float) directory_bytes / total_directory_bytes) * 100.0,
5465 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005466 if(total_xattr_bytes) {
5467 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5468 xattr_bytes, xattr_bytes / 1024.0);
5469 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5470 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5471 total_xattr_bytes);
5472 }
plougher1f413c82005-11-18 00:02:14 +00005473 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005474 printf("Number of duplicate files found %d\n", file_count -
5475 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005476 else
5477 printf("No duplicate files removed\n");
5478 printf("Number of inodes %d\n", inode_count);
5479 printf("Number of files %d\n", file_count);
5480 if(!no_fragments)
5481 printf("Number of fragments %d\n", fragments);
5482 printf("Number of symbolic links %d\n", sym_count);
5483 printf("Number of device nodes %d\n", dev_count);
5484 printf("Number of fifo nodes %d\n", fifo_count);
5485 printf("Number of socket nodes %d\n", sock_count);
5486 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005487 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005488 printf("Number of uids %d\n", uid_count);
5489
plougher1b899fc2008-08-07 01:24:06 +00005490 for(i = 0; i < id_count; i++) {
5491 if(id_table[i]->flags & ISA_UID) {
5492 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005493 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5494 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005495 }
plougher1f413c82005-11-18 00:02:14 +00005496 }
5497
5498 printf("Number of gids %d\n", guid_count);
5499
plougher1b899fc2008-08-07 01:24:06 +00005500 for(i = 0; i < id_count; i++) {
5501 if(id_table[i]->flags & ISA_GID) {
5502 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005503 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5504 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005505 }
plougher1f413c82005-11-18 00:02:14 +00005506 }
plougher99ac0cc2007-10-29 03:17:10 +00005507
plougher1f413c82005-11-18 00:02:14 +00005508 return 0;
5509}