blob: 9a662eea0113f0c380e9060399f3b7d0665bde43 [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,
Phillip Loughercc064952014-01-03 04:26:34 +00006 * 2012, 2013, 2014
Phillip Lougher83d42a32012-10-31 23:42:22 +00007 * Phillip Lougher <phillip@squashfs.org.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
Phillip Lougherfe2c7352012-12-23 06:55:41 +000028#define MAX_LINE 16384
plougher8cb05cd2005-12-11 23:32:35 +000029
plougher1f413c82005-11-18 00:02:14 +000030#include <pwd.h>
31#include <grp.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000035#include <stddef.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/types.h>
plougher1f413c82005-11-18 00:02:14 +000046#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000047#include <pthread.h>
plougher8f8e1a12007-10-18 02:50:21 +000048#include <regex.h>
49#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000050#include <sys/wait.h>
Phillip Lougher94c1fe02012-11-28 03:32:36 +000051#include <limits.h>
Phillip Lougherb22336d2012-12-20 18:44:22 +000052#include <ctype.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
plougher860c1f32010-08-11 01:37:17 +000064#include "squashfs_fs.h"
plougher860c1f32010-08-11 01:37:17 +000065#include "squashfs_swap.h"
66#include "mksquashfs.h"
67#include "sort.h"
68#include "pseudo.h"
69#include "compressor.h"
70#include "xattr.h"
Phillip Lougher4bcb7f82011-08-28 03:18:26 +010071#include "action.h"
Phillip Lougher2477d0d2012-10-24 21:49:28 +010072#include "error.h"
Phillip Lougher9a0e8bb2013-03-10 02:39:24 +000073#include "progressbar.h"
Phillip Lougher2e9fab12013-04-09 03:26:33 +010074#include "info.h"
Phillip Lougher71f39642013-04-09 04:43:21 +010075#include "caches-queues-lists.h"
Phillip Lougher1bbd0cc2013-04-19 04:03:00 +010076#include "read_fs.h"
Phillip Lougher0d67c9d2013-04-19 05:06:50 +010077#include "restore.h"
Phillip Lougher9de84ac2014-02-20 05:18:48 +000078#include "process_fragments.h"
plougher860c1f32010-08-11 01:37:17 +000079
plougher324978d2006-02-27 04:53:29 +000080int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +000081int fd;
Phillip Loughera709bff2013-03-28 17:48:31 +000082struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +000083
84/* filesystem flags for building */
plougher3d7e5182010-12-25 01:49:42 +000085int comp_opts = FALSE;
Phillip Lougher434d50c2014-01-21 03:05:36 +000086int no_xattrs = XATTR_DEF;
87int noX = FALSE;
88int duplicate_checking = TRUE;
89int noF = FALSE;
90int no_fragments = FALSE;
91int always_use_fragments = FALSE;
92int noI = FALSE;
93int noD = FALSE;
plougher1f288f62009-02-21 03:05:52 +000094int silent = TRUE;
plougher02bc3bc2007-02-25 12:12:01 +000095int exportable = TRUE;
plougher8dcc6992007-08-17 19:32:52 +000096int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +000097int old_exclude = TRUE;
98int use_regex = FALSE;
Phillip Loughera709bff2013-03-28 17:48:31 +000099int nopad = FALSE;
Phillip Lougher85776df2014-01-31 03:10:46 +0000100int exit_on_error = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000101
Phillip Lougher434d50c2014-01-21 03:05:36 +0000102long long global_uid = -1, global_gid = -1;
103
plougher1f413c82005-11-18 00:02:14 +0000104/* superblock attributes */
105int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +0000106unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +0000107int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
108 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +0000109
110/* write position within data section */
111long long bytes = 0, total_bytes = 0;
112
113/* in memory directory table - possibly compressed */
114char *directory_table = NULL;
115unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
116
117/* cached directory table */
118char *directory_data_cache = NULL;
119unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
120
121/* in memory inode table - possibly compressed */
122char *inode_table = NULL;
123unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
124
125/* cached inode table */
126char *data_cache = NULL;
127unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
128
plougher0e453652006-11-06 01:49:35 +0000129/* inode lookup table */
130squashfs_inode *inode_lookup_table = NULL;
131
plougher1f413c82005-11-18 00:02:14 +0000132/* in memory directory data */
133#define I_COUNT_SIZE 128
134#define DIR_ENTRIES 32
135#define INODE_HASH_SIZE 65536
136#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
137#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
138
139struct cached_dir_index {
plougher2bd2b722010-12-31 10:52:15 +0000140 struct squashfs_dir_index index;
141 char *name;
plougher1f413c82005-11-18 00:02:14 +0000142};
143
144struct directory {
145 unsigned int start_block;
146 unsigned int size;
147 unsigned char *buff;
148 unsigned char *p;
149 unsigned int entry_count;
150 unsigned char *entry_count_p;
151 unsigned int i_count;
152 unsigned int i_size;
153 struct cached_dir_index *index;
154 unsigned char *index_count_p;
155 unsigned int inode_number;
156};
157
plougher1f413c82005-11-18 00:02:14 +0000158struct inode_info *inode_info[INODE_HASH_SIZE];
159
160/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000161struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000162int dup_files = 0;
163
plougher8f8e1a12007-10-18 02:50:21 +0000164/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000165/* list of exclude dirs/files */
166struct exclude_info {
167 dev_t st_dev;
168 ino_t st_ino;
169};
170
171#define EXCLUDE_SIZE 8192
172int exclude = 0;
173struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000174int old_excluded(char *filename, struct stat *buf);
175
176struct path_entry {
177 char *name;
178 regex_t *preg;
179 struct pathname *paths;
180};
181
182struct pathname {
183 int names;
184 struct path_entry *name;
185};
186
plougherf9039c92007-10-22 03:54:16 +0000187struct pathnames {
188 int count;
189 struct pathname *path[0];
190};
191#define PATHS_ALLOC_SIZE 10
192
193struct pathnames *paths = NULL;
194struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000195struct pathname *stickypath = NULL;
Phillip Lougherb2abb1c2013-01-09 04:51:21 +0000196int excluded(char *name, struct pathnames *paths, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000197
plougher1f413c82005-11-18 00:02:14 +0000198int fragments = 0;
plougher76c64082008-03-08 01:32:23 +0000199
plougher1f413c82005-11-18 00:02:14 +0000200#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000201
plougher8ed84b92010-12-31 10:37:24 +0000202struct squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000203int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000204
Phillip Lougher7ffdf2a2013-04-14 02:53:30 +0100205int fragments_locked = FALSE;
Phillip Lougher7ffdf2a2013-04-14 02:53:30 +0100206
plougher1f413c82005-11-18 00:02:14 +0000207/* current inode number for directories and non directories */
Phillip Lougher539c2b12012-07-30 20:14:52 +0100208unsigned int inode_no = 1;
plougherdf70c3e2006-01-27 09:34:13 +0000209unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000210
211/* list of source dirs/files */
212int source = 0;
213char **source_path;
214
215/* list of root directory entries read from original filesystem */
216int old_root_entries = 0;
217struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000218 char *name;
219 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000220};
221struct old_root_entry_info *old_root_entry;
222
plougherfd57dfe2009-03-30 01:17:52 +0000223/* restore orignal filesystem state if appending to existing filesystem is
224 * cancelled */
Phillip Lougher3794e342014-04-10 02:15:45 +0100225int appending = FALSE;
plougherca2c93f2008-08-15 08:34:57 +0000226char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
plougher1f413c82005-11-18 00:02:14 +0000227
228long long sbytes, stotal_bytes;
229
230unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
plougherca2c93f2008-08-15 08:34:57 +0000231 sdirectory_cache_bytes, sdirectory_compressed_bytes,
plougher1f413c82005-11-18 00:02:14 +0000232 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000233 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000234 sdir_count, sfifo_count, ssock_count, sdup_files;
235int sfragments;
plougher5507dd92006-11-06 00:43:10 +0000236int threads;
plougher1f413c82005-11-18 00:02:14 +0000237
238/* flag whether destination file is a block device */
Phillip Lougher434d50c2014-01-21 03:05:36 +0000239int block_device = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000240
241/* flag indicating whether files are sorted using sort list(s) */
Phillip Lougher434d50c2014-01-21 03:05:36 +0000242int sorted = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000243
plougher324978d2006-02-27 04:53:29 +0000244/* save destination file name for deleting on error */
245char *destination_file = NULL;
246
plougher99ac0cc2007-10-29 03:17:10 +0000247/* recovery file for abnormal exit on appending */
Phillip Lougheraf4c9232012-11-15 03:46:28 +0000248char *recovery_file = NULL;
plougher99ac0cc2007-10-29 03:17:10 +0000249int recover = TRUE;
250
plougher1b899fc2008-08-07 01:24:06 +0000251struct id *id_hash_table[ID_ENTRIES];
252struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
253unsigned int uid_count = 0, guid_count = 0;
254unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000255
Phillip Lougher943acad2014-04-17 03:31:01 +0100256struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
257struct cache *bwriter_buffer, *fwriter_buffer;
Phillip Loughercf478e92013-05-29 02:38:41 +0100258struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
Phillip Lougher9de84ac2014-02-20 05:18:48 +0000259 *to_frag, *locked_fragment, *to_process_frag;
Phillip Lougher0e1656d2013-05-20 03:47:24 +0100260struct seq_queue *to_main;
Phillip Lougher0280d992014-01-27 05:54:07 +0000261pthread_t reader_thread, writer_thread, main_thread;
Phillip Lougher9de84ac2014-02-20 05:18:48 +0000262pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
Phillip Loughercf135d32013-04-08 03:43:25 +0100263pthread_t *restore_thread = NULL;
Phillip Lougher94e658f2014-03-13 02:59:04 +0000264pthread_mutex_t fragment_mutex = PTHREAD_MUTEX_INITIALIZER;
Phillip Lougherea8cb652014-03-13 02:57:19 +0000265pthread_mutex_t pos_mutex = PTHREAD_MUTEX_INITIALIZER;
Phillip Lougher8bb17b02014-03-30 23:59:55 +0100266pthread_mutex_t dup_mutex = PTHREAD_MUTEX_INITIALIZER;
plougher5507dd92006-11-06 00:43:10 +0000267
268/* user options that control parallelisation */
269int processors = -1;
Phillip Lougherc3af83a2014-04-21 21:38:16 +0100270int bwriter_size;
plougher5507dd92006-11-06 00:43:10 +0000271
plougherc5d59872010-11-22 01:36:01 +0000272/* compression operations */
Phillip Lougher8bb17b02014-03-30 23:59:55 +0100273struct compressor *comp = NULL;
Phillip Lougher434d50c2014-01-21 03:05:36 +0000274int compressor_opt_parsed = FALSE;
plougher13fdddf2010-11-24 01:23:41 +0000275void *stream = NULL;
plougher7b8ee502009-07-29 07:54:30 +0000276
plougher860c1f32010-08-11 01:37:17 +0000277/* xattr stats */
278unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
279
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +0000280/* fragment to file mapping used when appending */
281int append_fragments = 0;
282struct append_file **file_mapping;
283
Phillip Lougher8bb17b02014-03-30 23:59:55 +0100284static char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000285void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
286 int type);
plougherfd57dfe2009-03-30 01:17:52 +0000287struct file_info *duplicate(long long file_size, long long bytes,
288 unsigned int **block_list, long long *start, struct fragment **fragment,
289 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
Phillip Lougherc6424dc2014-03-13 02:01:28 +0000290 int checksum_flag);
Phillip Lougherb38c1722012-02-09 23:26:19 +0000291struct dir_info *dir_scan1(char *, char *, struct pathnames *,
Phillip Lougher494479f2012-02-03 15:45:41 +0000292 struct dir_ent *(_readdir)(struct dir_info *), int);
Phillip Lougher24eeb772012-10-13 01:56:24 +0100293void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
Phillip Lougher23d83622012-10-14 02:35:22 +0100294void dir_scan3(struct dir_info *root, struct dir_info *dir);
295void dir_scan4(struct dir_info *dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +0000296void dir_scan5(struct dir_info *dir);
297void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000298struct file_info *add_non_dup(long long file_size, long long bytes,
299 unsigned int *block_list, long long start, struct fragment *fragment,
300 unsigned short checksum, unsigned short fragment_checksum,
Phillip Lougherc6424dc2014-03-13 02:01:28 +0000301 int checksum_flag, int checksum_frag_flag);
ploughera0a49c32010-08-11 01:47:59 +0000302long long generic_write_table(int, void *, int, void *, int);
plougherca61d1c2010-07-20 18:32:32 +0000303void restorefs();
Phillip Lougher1eae83d2012-09-26 02:12:45 +0100304struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
Phillip Loughera709bff2013-03-28 17:48:31 +0000305void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +0000306unsigned short get_checksum_mem(char *buff, int bytes);
Phillip Lougher285a2fd2014-06-10 21:51:52 +0100307void check_usable_phys_mem(int total_mem);
plougher5507dd92006-11-06 00:43:10 +0000308
309
Phillip Lougher9b7c3c22013-03-10 02:29:42 +0000310void prep_exit()
Phillip Lougher838d2962012-10-23 03:29:30 +0100311{
Phillip Loughercf135d32013-04-08 03:43:25 +0100312 if(restore_thread) {
313 if(pthread_self() == *restore_thread) {
314 /*
315 * Recursive failure when trying to restore filesystem!
316 * Nothing to do except to exit, otherwise we'll just
317 * appear to hang. The user should be able to restore
318 * from the recovery file (which is why it was added, in
319 * case of catastrophic failure in Mksquashfs)
320 */
321 exit(1);
322 } else {
323 /* signal the restore thread to restore */
Phillip Lougher8c740812014-01-30 01:56:17 +0000324 pthread_kill(*restore_thread, SIGUSR1);
Phillip Loughercf135d32013-04-08 03:43:25 +0100325 pthread_exit(NULL);
326 }
Phillip Lougher3794e342014-04-10 02:15:45 +0100327 } else if(delete) {
328 if(destination_file && !block_device)
329 unlink(destination_file);
330 } else if(recovery_file)
331 unlink(recovery_file);
Phillip Lougher838d2962012-10-23 03:29:30 +0100332}
333
334
Phillip Loughere1668fe2012-12-30 05:48:12 +0000335int add_overflow(int a, int b)
336{
337 return (INT_MAX - a) < b;
338}
339
340
341int shift_overflow(int a, int shift)
342{
343 return (INT_MAX >> shift) < a;
344}
345
346
347int multiply_overflow(int a, int multiplier)
348{
349 return (INT_MAX / multiplier) < a;
350}
351
352
Phillip Lougher57e2f692014-05-05 23:50:24 +0100353int multiply_overflowll(long long a, int multiplier)
354{
355 return (LLONG_MAX / multiplier) < a;
356}
357
358
plougher50b31762009-03-31 04:14:46 +0000359#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
360 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000361
362
363void restorefs()
364{
365 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000366
plougher1f413c82005-11-18 00:02:14 +0000367 bytes = sbytes;
368 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000369 memcpy(directory_data_cache, sdirectory_data_cache,
370 sdirectory_cache_bytes);
371 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000372 inode_bytes = sinode_bytes;
373 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000374 memcpy(directory_table + directory_bytes, sdirectory_compressed,
375 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000376 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000377 total_bytes = stotal_bytes;
378 total_inode_bytes = stotal_inode_bytes;
379 total_directory_bytes = stotal_directory_bytes;
380 inode_count = sinode_count;
381 file_count = sfile_count;
382 sym_count = ssym_count;
383 dev_count = sdev_count;
384 dir_count = sdir_count;
385 fifo_count = sfifo_count;
386 sock_count = ssock_count;
387 dup_files = sdup_files;
388 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000389 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000390 restore_xattrs();
Phillip Loughera709bff2013-03-28 17:48:31 +0000391 write_filesystem_tables(&sBlk, nopad);
392 exit(1);
plougher1f413c82005-11-18 00:02:14 +0000393}
394
395
Phillip Lougherb8ec5202013-03-28 20:14:37 +0000396void sighandler()
plougher324978d2006-02-27 04:53:29 +0000397{
398 EXIT_MKSQUASHFS();
399}
400
401
plougher13fdddf2010-11-24 01:23:41 +0000402int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000403 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000404{
plougher7b8ee502009-07-29 07:54:30 +0000405 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000406
plougher7b8ee502009-07-29 07:54:30 +0000407 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000408 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
409 &error);
plougher7b8ee502009-07-29 07:54:30 +0000410 if(c_byte == -1)
411 BAD_ERROR("mangle2:: %s compress failed with error "
412 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000413 }
414
plougher7b8ee502009-07-29 07:54:30 +0000415 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000416 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000417 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
418 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000419 }
420
plougher7b8ee502009-07-29 07:54:30 +0000421 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000422}
423
424
plougher7b8ee502009-07-29 07:54:30 +0000425int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000426 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000427{
plougher13fdddf2010-11-24 01:23:41 +0000428 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000429 data_block);
plougher5507dd92006-11-06 00:43:10 +0000430}
431
432
plougherac28cd12010-02-24 02:25:03 +0000433void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000434{
435 int data_space;
436 unsigned short c_byte;
437
438 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000439 if((inode_size - inode_bytes) <
440 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000441 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000442 (SQUASHFS_METADATA_SIZE << 1) + 2);
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000443 if(it == NULL)
444 MEM_ERROR();
plougher1eb2a662010-07-26 17:30:50 +0000445 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000446 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
447 }
448
plougherfd57dfe2009-03-30 01:17:52 +0000449 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000450 data_cache, SQUASHFS_METADATA_SIZE,
451 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000452 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000453 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000454 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
455 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000456 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000457 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000458 cache_bytes -= SQUASHFS_METADATA_SIZE;
459 }
460
461 data_space = (cache_size - cache_bytes);
462 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000463 int realloc_size = cache_size == 0 ?
464 ((req_size + SQUASHFS_METADATA_SIZE) &
465 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
466 data_space;
plougher1f413c82005-11-18 00:02:14 +0000467
plougher17248ca2010-07-27 00:24:35 +0000468 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000469 realloc_size);
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000470 if(dc == NULL)
471 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +0000472 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000473 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000474 }
475
476 cache_bytes += req_size;
477
plougherac28cd12010-02-24 02:25:03 +0000478 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000479}
480
481
plougher8a8c4102009-03-29 22:28:49 +0000482int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000483{
484 int res, count;
485
486 for(count = 0; count < bytes; count += res) {
487 res = read(fd, buff + count, bytes - count);
488 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000489 if(res == 0)
490 goto bytes_read;
491 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000492 ERROR("Read failed because %s\n",
493 strerror(errno));
494 return -1;
495 } else
496 res = 0;
497 }
498 }
499
500bytes_read:
501 return count;
502}
503
504
plougher3306cb22010-06-18 04:22:44 +0000505int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000506{
507 off_t off = byte;
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100508 int res = 1;
plougher1f413c82005-11-18 00:02:14 +0000509
plougher1d065e92010-06-18 03:58:27 +0000510 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000511 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000512
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100513 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
plougher5507dd92006-11-06 00:43:10 +0000514 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000515 if(lseek(fd, off, SEEK_SET) == -1) {
Phillip Lougher1d3177a2013-02-06 21:48:58 +0000516 ERROR("read_fs_bytes: Lseek on destination failed because %s, "
517 "offset=0x%llx\n", strerror(errno), off);
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100518 res = 0;
Phillip Lougher041cf6d2013-07-20 04:20:40 +0100519 } else if(read_bytes(fd, buff, bytes) < bytes) {
plougher1d065e92010-06-18 03:58:27 +0000520 ERROR("Read on destination failed\n");
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100521 res = 0;
plougher1d065e92010-06-18 03:58:27 +0000522 }
523
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100524 pthread_cleanup_pop(1);
525 return res;
plougher1f413c82005-11-18 00:02:14 +0000526}
527
528
plougher628e7682009-03-29 22:12:24 +0000529int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000530{
531 int res, count;
532
533 for(count = 0; count < bytes; count += res) {
534 res = write(fd, buff + count, bytes - count);
535 if(res == -1) {
536 if(errno != EINTR) {
537 ERROR("Write failed because %s\n",
538 strerror(errno));
539 return -1;
540 }
541 res = 0;
542 }
543 }
544
545 return 0;
546}
547
548
plougher29e2ace2010-12-31 08:50:00 +0000549void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000550{
551 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000552
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100553 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
554 pthread_mutex_lock(&pos_mutex);
plougher5507dd92006-11-06 00:43:10 +0000555
Phillip Loughera0c23462013-02-12 03:30:12 +0000556 if(lseek(fd, off, SEEK_SET) == -1) {
557 ERROR("write_destination: Lseek on destination "
Phillip Lougher1d3177a2013-02-06 21:48:58 +0000558 "failed because %s, offset=0x%llx\n", strerror(errno),
559 off);
Phillip Loughera0c23462013-02-12 03:30:12 +0000560 BAD_ERROR("Probably out of space on output %s\n",
561 block_device ? "block device" : "filesystem");
562 }
plougher1f413c82005-11-18 00:02:14 +0000563
plougher0dd6f122009-03-29 21:43:57 +0000564 if(write_bytes(fd, buff, bytes) == -1)
Phillip Loughere8b536f2013-02-12 22:01:21 +0000565 BAD_ERROR("Failed to write to output %s\n",
566 block_device ? "block device" : "filesystem");
Phillip Lougherfd74d9a2013-03-31 22:49:50 +0100567
568 pthread_cleanup_pop(1);
plougher1f413c82005-11-18 00:02:14 +0000569}
570
571
572long long write_inodes()
573{
574 unsigned short c_byte;
575 int avail_bytes;
576 char *datap = data_cache;
577 long long start_bytes = bytes;
578
579 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000580 if(inode_size - inode_bytes <
581 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +0000582 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000583 ((SQUASHFS_METADATA_SIZE << 1) + 2));
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000584 if(it == NULL)
585 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +0000586 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +0000587 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000588 }
plougherfd57dfe2009-03-30 01:17:52 +0000589 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
590 SQUASHFS_METADATA_SIZE : cache_bytes;
591 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
592 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000593 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000594 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000595 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
596 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +0000597 datap += avail_bytes;
598 cache_bytes -= avail_bytes;
599 }
600
plougher29e2ace2010-12-31 08:50:00 +0000601 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +0000602 bytes += inode_bytes;
603
604 return start_bytes;
605}
606
607
608long long write_directories()
609{
610 unsigned short c_byte;
611 int avail_bytes;
612 char *directoryp = directory_data_cache;
613 long long start_bytes = bytes;
614
615 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000616 if(directory_size - directory_bytes <
617 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +0000618 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +0000619 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
620 + 2));
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000621 if(dt == NULL)
622 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +0000623 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +0000624 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +0000625 }
plougherfd57dfe2009-03-30 01:17:52 +0000626 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
627 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +0000628 c_byte = mangle(directory_table + directory_bytes +
629 BLOCK_OFFSET, directoryp, avail_bytes,
630 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +0000631 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
632 c_byte);
plougherac28cd12010-02-24 02:25:03 +0000633 SQUASHFS_SWAP_SHORTS(&c_byte,
634 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +0000635 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
636 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +0000637 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +0000638 directoryp += avail_bytes;
639 directory_cache_bytes -= avail_bytes;
640 }
plougher29e2ace2010-12-31 08:50:00 +0000641 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +0000642 bytes += directory_bytes;
643
644 return start_bytes;
645}
646
647
plougher1b899fc2008-08-07 01:24:06 +0000648long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +0000649{
plougher1b899fc2008-08-07 01:24:06 +0000650 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +0000651 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +0000652 int i;
653
plougher1b899fc2008-08-07 01:24:06 +0000654 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +0000655 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +0000656 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +0000657 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +0000658 }
659
ploughera0a49c32010-08-11 01:47:59 +0000660 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +0000661}
662
663
plougher1b899fc2008-08-07 01:24:06 +0000664struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +0000665{
plougher1b899fc2008-08-07 01:24:06 +0000666 int hash = ID_HASH(id);
667 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +0000668
plougher1b899fc2008-08-07 01:24:06 +0000669 for(; entry; entry = entry->next)
670 if(entry->id == id)
671 break;
plougher1f413c82005-11-18 00:02:14 +0000672
plougher1b899fc2008-08-07 01:24:06 +0000673 return entry;
plougher1f413c82005-11-18 00:02:14 +0000674}
675
676
plougher1b899fc2008-08-07 01:24:06 +0000677struct id *create_id(unsigned int id)
678{
679 int hash = ID_HASH(id);
680 struct id *entry = malloc(sizeof(struct id));
681 if(entry == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000682 MEM_ERROR();
plougher1b899fc2008-08-07 01:24:06 +0000683 entry->id = id;
684 entry->index = id_count ++;
685 entry->flags = 0;
686 entry->next = id_hash_table[hash];
687 id_hash_table[hash] = entry;
688 id_table[entry->index] = entry;
689 return entry;
690}
691
692
693unsigned int get_uid(unsigned int uid)
694{
695 struct id *entry = get_id(uid);
696
697 if(entry == NULL) {
698 if(id_count == SQUASHFS_IDS)
699 BAD_ERROR("Out of uids!\n");
700 entry = create_id(uid);
701 }
702
703 if((entry->flags & ISA_UID) == 0) {
704 entry->flags |= ISA_UID;
705 uid_count ++;
706 }
707
708 return entry->index;
709}
710
711
712unsigned int get_guid(unsigned int guid)
713{
714 struct id *entry = get_id(guid);
715
716 if(entry == NULL) {
717 if(id_count == SQUASHFS_IDS)
718 BAD_ERROR("Out of gids!\n");
719 entry = create_id(guid);
720 }
721
722 if((entry->flags & ISA_GID) == 0) {
723 entry->flags |= ISA_GID;
724 guid_count ++;
725 }
726
727 return entry->index;
728}
729
730
Phillip Lougher5ef51692012-11-19 03:35:39 +0000731#define ALLOC_SIZE 128
Phillip Lougher494479f2012-02-03 15:45:41 +0000732
Phillip Lougher5ef51692012-11-19 03:35:39 +0000733char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size)
734{
735 if(pathname == NULL) {
736 pathname = malloc(ALLOC_SIZE);
737 if(pathname == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000738 MEM_ERROR();
Phillip Lougher5ef51692012-11-19 03:35:39 +0000739 }
740
741 for(;;) {
742 int res = snprintf(pathname, *size, "%s/%s",
743 dir_ent->our_dir->pathname,
744 dir_ent->source_name ? : dir_ent->name);
745
746 if(res < 0)
747 BAD_ERROR("snprintf failed in pathname\n");
748 else if(res >= *size) {
749 /*
750 * pathname is too small to contain the result, so
751 * increase it and try again
752 */
753 *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
754 pathname = realloc(pathname, *size);
755 if(pathname == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000756 MEM_ERROR();
Phillip Lougher5ef51692012-11-19 03:35:39 +0000757 } else
758 break;
759 }
Phillip Lougher494479f2012-02-03 15:45:41 +0000760
761 return pathname;
762}
763
764
765char *pathname(struct dir_ent *dir_ent)
766{
Phillip Lougher5ef51692012-11-19 03:35:39 +0000767 static char *pathname = NULL;
768 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +0000769
Phillip Lougher5ef51692012-11-19 03:35:39 +0000770 if (dir_ent->nonstandard_pathname)
771 return dir_ent->nonstandard_pathname;
772
773 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +0000774}
775
776
777char *pathname_reader(struct dir_ent *dir_ent)
778{
Phillip Lougher5ef51692012-11-19 03:35:39 +0000779 static char *pathname = NULL;
780 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +0000781
Phillip Lougher5ef51692012-11-19 03:35:39 +0000782 if (dir_ent->nonstandard_pathname)
783 return dir_ent->nonstandard_pathname;
784
785 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +0000786}
787
788
Phillip Lougherb38c1722012-02-09 23:26:19 +0000789char *subpathname(struct dir_ent *dir_ent)
790{
Phillip Lougherd457ed32012-11-19 01:36:56 +0000791 static char *subpath = NULL;
792 static int size = ALLOC_SIZE;
793 int res;
Phillip Lougherb38c1722012-02-09 23:26:19 +0000794
Phillip Lougherd457ed32012-11-19 01:36:56 +0000795 if(subpath == NULL) {
796 subpath = malloc(ALLOC_SIZE);
797 if(subpath == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000798 MEM_ERROR();
Phillip Lougherd457ed32012-11-19 01:36:56 +0000799 }
800
801 for(;;) {
802 if(dir_ent->our_dir->subpath[0] != '\0')
803 res = snprintf(subpath, size, "%s/%s",
804 dir_ent->our_dir->subpath, dir_ent->name);
805 else
806 res = snprintf(subpath, size, "/%s", dir_ent->name);
807
808 if(res < 0)
809 BAD_ERROR("snprintf failed in subpathname\n");
810 else if(res >= size) {
811 /*
812 * subpath is too small to contain the result, so
813 * increase it and try again
814 */
815 size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
816 subpath = realloc(subpath, size);
817 if(subpath == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000818 MEM_ERROR();
Phillip Lougherd457ed32012-11-19 01:36:56 +0000819 } else
820 break;
Phillip Lougher90e08252012-10-05 04:33:35 +0100821 }
Phillip Lougherb38c1722012-02-09 23:26:19 +0000822
823 return subpath;
824}
825
826
Phillip Lougher539c2b12012-07-30 20:14:52 +0100827inline unsigned int get_inode_no(struct inode_info *inode)
Phillip Lougher53cef742012-07-25 05:12:50 +0100828{
Phillip Lougher539c2b12012-07-30 20:14:52 +0100829 return inode->inode_number;
Phillip Lougher53cef742012-07-25 05:12:50 +0100830}
831
832
Phillip Lougher539c2b12012-07-30 20:14:52 +0100833inline unsigned int get_parent_no(struct dir_info *dir)
Phillip Lougher53cef742012-07-25 05:12:50 +0100834{
Phillip Lougher1eae83d2012-09-26 02:12:45 +0100835 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
Phillip Lougher53cef742012-07-25 05:12:50 +0100836}
837
838
plougher3c6bdb52010-05-01 02:30:59 +0000839int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
840 struct dir_ent *dir_ent, int type, long long byte_size,
841 long long start_block, unsigned int offset, unsigned int *block_list,
842 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +0000843{
844 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +0000845 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +0000846 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +0000847 void *inode;
Phillip Lougher494479f2012-02-03 15:45:41 +0000848 char *filename = pathname(dir_ent);
plougher1f413c82005-11-18 00:02:14 +0000849 int nlink = dir_ent->inode->nlink;
ploughere6e0e1b2010-05-12 17:17:06 +0000850 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +0000851
ploughere6e0e1b2010-05-12 17:17:06 +0000852 switch(type) {
853 case SQUASHFS_FILE_TYPE:
854 if(dir_ent->inode->nlink > 1 ||
855 byte_size >= (1LL << 32) ||
856 start_block >= (1LL << 32) ||
857 sparse || IS_XATTR(xattr))
858 type = SQUASHFS_LREG_TYPE;
859 break;
860 case SQUASHFS_DIR_TYPE:
861 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
862 type = SQUASHFS_LDIR_TYPE;
863 break;
864 case SQUASHFS_SYMLINK_TYPE:
865 if(IS_XATTR(xattr))
866 type = SQUASHFS_LSYMLINK_TYPE;
867 break;
868 case SQUASHFS_BLKDEV_TYPE:
869 if(IS_XATTR(xattr))
870 type = SQUASHFS_LBLKDEV_TYPE;
871 break;
872 case SQUASHFS_CHRDEV_TYPE:
873 if(IS_XATTR(xattr))
874 type = SQUASHFS_LCHRDEV_TYPE;
875 break;
plougherc5d69322010-05-12 19:28:38 +0000876 case SQUASHFS_FIFO_TYPE:
877 if(IS_XATTR(xattr))
878 type = SQUASHFS_LFIFO_TYPE;
879 break;
880 case SQUASHFS_SOCKET_TYPE:
881 if(IS_XATTR(xattr))
882 type = SQUASHFS_LSOCKET_TYPE;
883 break;
ploughere6e0e1b2010-05-12 17:17:06 +0000884 }
885
plougher1f413c82005-11-18 00:02:14 +0000886 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +0000887 base->uid = get_uid((unsigned int) global_uid == -1 ?
888 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +0000889 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +0000890 base->guid = get_guid((unsigned int) global_gid == -1 ?
891 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +0000892 base->mtime = buf->st_mtime;
Phillip Lougher539c2b12012-07-30 20:14:52 +0100893 base->inode_number = get_inode_no(dir_ent->inode);
plougher1f413c82005-11-18 00:02:14 +0000894
895 if(type == SQUASHFS_FILE_TYPE) {
896 int i;
plougher8701ed62010-12-31 20:38:38 +0000897 struct squashfs_reg_inode_header *reg = &inode_header.reg;
898 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +0000899
900 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +0000901 reg->file_size = byte_size;
902 reg->start_block = start_block;
903 reg->fragment = fragment->index;
904 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +0000905 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
906 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +0000907 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
908 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +0000909 start_block, offset, fragment->index, fragment->offset,
910 fragment->size);
plougher1f413c82005-11-18 00:02:14 +0000911 for(i = 0; i < offset; i++)
912 TRACE("Block %d, size %d\n", i, block_list[i]);
913 }
914 else if(type == SQUASHFS_LREG_TYPE) {
915 int i;
plougher1e6ac4a2010-12-31 20:42:02 +0000916 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
917 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +0000918
919 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +0000920 reg->nlink = nlink;
921 reg->file_size = byte_size;
922 reg->start_block = start_block;
923 reg->fragment = fragment->index;
924 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +0000925 if(sparse && sparse >= byte_size)
926 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +0000927 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +0000928 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +0000929 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
930 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +0000931 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +0000932 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
933 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +0000934 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +0000935 for(i = 0; i < offset; i++)
936 TRACE("Block %d, size %d\n", i, block_list[i]);
937 }
938 else if(type == SQUASHFS_LDIR_TYPE) {
939 int i;
940 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +0000941 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +0000942 struct cached_dir_index *index = dir_in->index;
943 unsigned int i_count = dir_in->i_count;
944 unsigned int i_size = dir_in->i_size;
945
946 if(byte_size >= 1 << 27)
947 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
948
949 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +0000950 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +0000951 dir->nlink = dir_ent->dir->directory_count + 2;
952 dir->file_size = byte_size;
953 dir->offset = offset;
954 dir->start_block = start_block;
955 dir->i_count = i_count;
Phillip Lougher539c2b12012-07-30 20:14:52 +0100956 dir->parent_inode = get_parent_no(dir_ent->our_dir);
ploughere6e0e1b2010-05-12 17:17:06 +0000957 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +0000958
plougherac28cd12010-02-24 02:25:03 +0000959 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +0000960 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +0000961 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +0000962 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +0000963 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +0000964 memcpy(p, index[i].name, index[i].index.size + 1);
965 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +0000966 }
plougher50b31762009-03-31 04:14:46 +0000967 TRACE("Long directory inode, file_size %lld, start_block "
968 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
969 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +0000970 }
971 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +0000972 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +0000973
974 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +0000975 dir->nlink = dir_ent->dir->directory_count + 2;
976 dir->file_size = byte_size;
977 dir->offset = offset;
978 dir->start_block = start_block;
Phillip Lougher539c2b12012-07-30 20:14:52 +0100979 dir->parent_inode = get_parent_no(dir_ent->our_dir);
plougherac28cd12010-02-24 02:25:03 +0000980 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +0000981 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +0000982 "offset 0x%x, nlink %d\n", byte_size, start_block,
983 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +0000984 }
985 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +0000986 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +0000987 unsigned int major = major(buf->st_rdev);
988 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +0000989
plougher5b398502008-10-04 23:22:03 +0000990 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +0000991 ERROR("Major %d out of range in device node %s, "
992 "truncating to %d\n", major, filename,
993 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +0000994 major &= 0xfff;
995 }
996 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +0000997 ERROR("Minor %d out of range in device node %s, "
998 "truncating to %d\n", minor, filename,
999 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001000 minor &= 0xfffff;
1001 }
plougher1f413c82005-11-18 00:02:14 +00001002 inode = get_inode(sizeof(*dev));
1003 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001004 dev->rdev = (major << 8) | (minor & 0xff) |
1005 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001006 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001007 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001008 }
ploughere6e0e1b2010-05-12 17:17:06 +00001009 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001010 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001011 unsigned int major = major(buf->st_rdev);
1012 unsigned int minor = minor(buf->st_rdev);
1013
1014 if(major > 0xfff) {
1015 ERROR("Major %d out of range in device node %s, "
1016 "truncating to %d\n", major, filename,
1017 major & 0xfff);
1018 major &= 0xfff;
1019 }
1020 if(minor > 0xfffff) {
1021 ERROR("Minor %d out of range in device node %s, "
1022 "truncating to %d\n", minor, filename,
1023 minor & 0xfffff);
1024 minor &= 0xfffff;
1025 }
1026 inode = get_inode(sizeof(*dev));
1027 dev->nlink = nlink;
1028 dev->rdev = (major << 8) | (minor & 0xff) |
1029 ((minor & ~0xff) << 12);
1030 dev->xattr = xattr;
1031 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1032 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1033 }
plougher1f413c82005-11-18 00:02:14 +00001034 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001035 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001036 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001037 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001038 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001039
plougher5cf38b82010-12-16 04:55:32 +00001040 byte = readlink(filename, buff, 65536);
1041 if(byte == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00001042 ERROR_START("Failed to read symlink %s", filename);
1043 ERROR_EXIT(", creating empty symlink\n");
plougher29e37092007-04-15 01:24:51 +00001044 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001045 }
1046
1047 if(byte == 65536) {
Phillip Lougher85776df2014-01-31 03:10:46 +00001048 ERROR_START("Symlink %s is greater than 65536 bytes!",
1049 filename);
1050 ERROR_EXIT(" Creating empty symlink\n");
plougher29e37092007-04-15 01:24:51 +00001051 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001052 }
1053
1054 inode = get_inode(sizeof(*symlink) + byte);
1055 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001056 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001057 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1058 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001059 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1060 nlink);
plougher1f413c82005-11-18 00:02:14 +00001061 }
ploughere6e0e1b2010-05-12 17:17:06 +00001062 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001063 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001064 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001065 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001066 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001067
plougherdf2b9aa2010-12-16 04:56:23 +00001068 byte = readlink(filename, buff, 65536);
1069 if(byte == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00001070 ERROR_START("Failed to read symlink %s", filename);
1071 ERROR_EXIT(", creating empty symlink\n");
ploughere6e0e1b2010-05-12 17:17:06 +00001072 byte = 0;
1073 }
1074
1075 if(byte == 65536) {
Phillip Lougher85776df2014-01-31 03:10:46 +00001076 ERROR_START("Symlink %s is greater than 65536 bytes!",
1077 filename);
1078 ERROR_EXIT(" Creating empty symlink\n");
ploughere6e0e1b2010-05-12 17:17:06 +00001079 byte = 0;
1080 }
1081
1082 inode = get_inode(sizeof(*symlink) + byte +
1083 sizeof(unsigned int));
1084 symlink->nlink = nlink;
1085 symlink->symlink_size = byte;
1086 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1087 strncpy(inode + off, buff, byte);
1088 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1089 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1090 nlink);
1091 }
plougher1f413c82005-11-18 00:02:14 +00001092 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001093 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001094
1095 inode = get_inode(sizeof(*ipc));
1096 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001097 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001098 TRACE("ipc inode, type %s, nlink %d\n", type ==
1099 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001100 }
1101 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001102 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001103
1104 inode = get_inode(sizeof(*ipc));
1105 ipc->nlink = nlink;
1106 ipc->xattr = xattr;
1107 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1108 TRACE("ipc inode, type %s, nlink %d\n", type ==
1109 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001110 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001111 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001112
1113 *i_no = MKINODE(inode);
1114 inode_count ++;
1115
plougherfd57dfe2009-03-30 01:17:52 +00001116 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1117 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001118
1119 return TRUE;
1120}
1121
1122
plougher50b31762009-03-31 04:14:46 +00001123void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1124 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001125{
plougher8cb05cd2005-12-11 23:32:35 +00001126 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001127 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001128 unsigned int start_block = inode >> 16;
1129 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001130 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001131 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001132
plougher43d49082010-12-16 05:01:15 +00001133 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001134 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001135 ERROR("Filename is greater than %d characters, truncating! ..."
1136 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001137 }
1138
plougher9b393552010-12-31 20:55:43 +00001139 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001140 sizeof(struct squashfs_dir_header)
1141 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001142 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001143 if(buff == NULL)
1144 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001145
1146 dir->p = (dir->p - dir->buff) + buff;
1147 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001148 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1149 buff);
plougher1f413c82005-11-18 00:02:14 +00001150 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1151 dir->buff = buff;
1152 }
1153
plougherfd57dfe2009-03-30 01:17:52 +00001154 if(dir->entry_count == 256 || start_block != dir->start_block ||
1155 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001156 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001157 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001158 ((long long) inode_number - dir->inode_number) > 32767
1159 || ((long long) inode_number - dir->inode_number)
1160 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001161 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001162 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001163
plougher9b393552010-12-31 20:55:43 +00001164 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001165 dir->index_count_p) >
1166 SQUASHFS_METADATA_SIZE) {
1167 if(dir->i_count % I_COUNT_SIZE == 0) {
1168 dir->index = realloc(dir->index,
1169 (dir->i_count + I_COUNT_SIZE) *
1170 sizeof(struct cached_dir_index));
1171 if(dir->index == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001172 MEM_ERROR();
plougherfd57dfe2009-03-30 01:17:52 +00001173 }
1174 dir->index[dir->i_count].index.index =
1175 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001176 dir->index[dir->i_count].index.size = size - 1;
1177 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001178 dir->i_size += sizeof(struct squashfs_dir_index)
1179 + size;
plougher1f413c82005-11-18 00:02:14 +00001180 dir->index_count_p = dir->p;
1181 }
1182
1183 dir_header.count = dir->entry_count - 1;
1184 dir_header.start_block = dir->start_block;
1185 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001186 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001187 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001188
1189 }
1190
1191
1192 dir->entry_count_p = dir->p;
1193 dir->start_block = start_block;
1194 dir->entry_count = 0;
1195 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001196 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001197 }
1198
plougher1f413c82005-11-18 00:02:14 +00001199 idir.offset = offset;
1200 idir.type = type;
1201 idir.size = size - 1;
1202 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001203 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1204 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001205 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001206 dir->entry_count ++;
1207}
1208
1209
plougherfd57dfe2009-03-30 01:17:52 +00001210void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1211 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001212{
1213 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001214 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001215 unsigned int directory_block, directory_offset, i_count, index;
1216 unsigned short c_byte;
1217
1218 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001219 int realloc_size = directory_cache_size == 0 ?
1220 ((dir_size + SQUASHFS_METADATA_SIZE) &
1221 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001222
plougher17248ca2010-07-27 00:24:35 +00001223 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001224 directory_cache_size + realloc_size);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001225 if(dc == NULL)
1226 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001227 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001228 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001229 }
1230
1231 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001232 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001233
1234 dir_header.count = dir->entry_count - 1;
1235 dir_header.start_block = dir->start_block;
1236 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001237 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001238 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1239 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001240 }
1241 directory_offset = directory_cache_bytes;
1242 directory_block = directory_bytes;
1243 directory_cache_bytes += dir_size;
1244 i_count = 0;
1245 index = SQUASHFS_METADATA_SIZE - directory_offset;
1246
1247 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001248 while(i_count < dir->i_count &&
1249 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001250 dir->index[i_count++].index.start_block =
1251 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001252 index += SQUASHFS_METADATA_SIZE;
1253
1254 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1255 break;
1256
plougherfd57dfe2009-03-30 01:17:52 +00001257 if((directory_size - directory_bytes) <
1258 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001259 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001260 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1261 + 2);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001262 if(dt == NULL)
1263 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001264 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001265 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001266 }
1267
plougher50b31762009-03-31 04:14:46 +00001268 c_byte = mangle(directory_table + directory_bytes +
1269 BLOCK_OFFSET, directory_data_cache,
1270 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1271 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001272 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1273 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001274 SQUASHFS_SWAP_SHORTS(&c_byte,
1275 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001276 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1277 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001278 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001279 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001280 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1281 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001282 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1283 }
1284
plougher3c6bdb52010-05-01 02:30:59 +00001285 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1286 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1287 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001288
1289#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001290 {
plougher1f413c82005-11-18 00:02:14 +00001291 unsigned char *dirp;
1292 int count;
1293
1294 TRACE("Directory contents of inode 0x%llx\n", *inode);
1295 dirp = dir->buff;
1296 while(dirp < dir->p) {
1297 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001298 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001299 struct squashfs_dir_header dirh;
1300 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001301 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001302 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001303 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001304
plougher50b31762009-03-31 04:14:46 +00001305 TRACE("\tStart block 0x%x, count %d\n",
1306 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001307
1308 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001309 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001310 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001311 strncpy(buffer, idirp->name, idir.size + 1);
1312 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001313 TRACE("\t\tname %s, inode offset 0x%x, type "
1314 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001315 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001316 1;
plougher1f413c82005-11-18 00:02:14 +00001317 }
1318 }
1319 }
1320#endif
1321 dir_count ++;
plougher1f413c82005-11-18 00:02:14 +00001322}
1323
1324
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001325static struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001326{
plougher8ed84b92010-12-31 10:37:24 +00001327 struct squashfs_fragment_entry *disk_fragment;
plougher76c64082008-03-08 01:32:23 +00001328 struct file_buffer *buffer, *compressed_buffer;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001329 long long start_block;
1330 int res, size, index = fragment->index;
1331 char locked;
1332
1333 /*
1334 * Lookup fragment block in cache.
1335 * If the fragment block doesn't exist, then get the compressed version
1336 * from the writer cache or off disk, and decompress it.
1337 *
1338 * This routine has two things which complicate the code:
1339 *
1340 * 1. Multiple threads can simultaneously lookup/create the
1341 * same buffer. This means a buffer needs to be "locked"
1342 * when it is being filled in, to prevent other threads from
1343 * using it when it is not ready. This is because we now do
1344 * fragment duplicate checking in parallel.
1345 * 2. We have two caches which need to be checked for the
1346 * presence of fragment blocks: the normal fragment cache
1347 * and a "reserve" cache. The reserve cache is used to
1348 * prevent an unnecessary pipeline stall when the fragment cache
1349 * is full of fragments waiting to be compressed.
1350 */
plougher5507dd92006-11-06 00:43:10 +00001351
plougher76c64082008-03-08 01:32:23 +00001352 if(fragment->index == SQUASHFS_INVALID_FRAG)
1353 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001354
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001355 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1356 pthread_mutex_lock(&dup_mutex);
1357
1358again:
1359 buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
1360 if(buffer) {
1361 pthread_mutex_unlock(&dup_mutex);
1362 if(locked)
1363 /* got a buffer being filled in. Wait for it */
1364 cache_wait_unlock(buffer);
1365 goto finished;
1366 }
1367
1368 /* not in fragment cache, is it in the reserve cache? */
1369 buffer = cache_lookup_nowait(reserve_cache, index, &locked);
1370 if(buffer) {
1371 pthread_mutex_unlock(&dup_mutex);
1372 if(locked)
1373 /* got a buffer being filled in. Wait for it */
1374 cache_wait_unlock(buffer);
1375 goto finished;
1376 }
1377
1378 /* in neither cache, try to get it from the fragment cache */
1379 buffer = cache_get_nowait(fragment_buffer, index);
1380 if(!buffer) {
1381 /*
1382 * no room, get it from the reserve cache, this is
1383 * dimensioned so it will always have space (no more than
1384 * processors + 1 can have an outstanding reserve buffer)
1385 */
1386 buffer = cache_get_nowait(reserve_cache, index);
1387 if(!buffer) {
1388 /* failsafe */
1389 ERROR("no space in reserve cache\n");
1390 goto again;
1391 }
1392 }
1393
1394 pthread_mutex_unlock(&dup_mutex);
plougher76c64082008-03-08 01:32:23 +00001395
Phillip Lougher943acad2014-04-17 03:31:01 +01001396 compressed_buffer = cache_lookup(fwriter_buffer, index);
plougher5507dd92006-11-06 00:43:10 +00001397
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001398 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001399 pthread_mutex_lock(&fragment_mutex);
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001400 disk_fragment = &fragment_table[index];
plougher5507dd92006-11-06 00:43:10 +00001401 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001402 start_block = disk_fragment->start_block;
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001403 pthread_cleanup_pop(1);
plougher1f413c82005-11-18 00:02:14 +00001404
plougher0f464442008-03-31 00:27:56 +00001405 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001406 int error;
plougher76c64082008-03-08 01:32:23 +00001407 char *data;
plougher1f413c82005-11-18 00:02:14 +00001408
plougher76c64082008-03-08 01:32:23 +00001409 if(compressed_buffer)
1410 data = compressed_buffer->data;
Phillip Lougherac731382013-05-19 04:19:44 +01001411 else {
plougher49b57a92009-03-31 03:23:05 +00001412 data = read_from_disk(start_block, size);
Phillip Lougherac731382013-05-19 04:19:44 +01001413 if(data == NULL) {
1414 ERROR("Failed to read fragment from output"
1415 " filesystem\n");
1416 BAD_ERROR("Output filesystem corrupted?\n");
1417 }
1418 }
plougher1f413c82005-11-18 00:02:14 +00001419
plougherb48442b2010-12-31 07:57:54 +00001420 res = compressor_uncompress(comp, buffer->data, data, size,
1421 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001422 if(res == -1)
1423 BAD_ERROR("%s uncompress failed with error code %d\n",
1424 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001425 } else if(compressed_buffer)
1426 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001427 else {
1428 res = read_fs_bytes(fd, start_block, size, buffer->data);
Phillip Lougher94519382013-03-06 02:43:42 +00001429 if(res == 0) {
1430 ERROR("Failed to read fragment from output "
1431 "filesystem\n");
1432 BAD_ERROR("Output filesystem corrupted?\n");
1433 }
plougher1d065e92010-06-18 03:58:27 +00001434 }
plougher1f413c82005-11-18 00:02:14 +00001435
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001436 cache_unlock(buffer);
plougher03859fa2009-03-31 03:18:18 +00001437 cache_block_put(compressed_buffer);
1438
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001439finished:
1440 pthread_cleanup_pop(0);
1441
plougher76c64082008-03-08 01:32:23 +00001442 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001443}
1444
plougher2ea89142008-03-11 01:34:19 +00001445
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001446unsigned short get_fragment_checksum(struct file_info *file)
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001447{
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001448 struct file_buffer *frag_buffer;
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001449 struct append_file *append;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001450 int res, index = file->fragment->index;
1451 unsigned short checksum;
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001452
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001453 if(index == SQUASHFS_INVALID_FRAG)
1454 return 0;
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001455
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001456 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1457 pthread_mutex_lock(&dup_mutex);
1458 res = file->have_frag_checksum;
1459 checksum = file->fragment_checksum;
Phillip Lougherc4a8a792014-04-10 02:23:26 +01001460 pthread_cleanup_pop(1);
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001461
1462 if(res)
1463 return checksum;
1464
1465 frag_buffer = get_fragment(file->fragment);
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001466
Phillip Lougherc4a8a792014-04-10 02:23:26 +01001467 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1468
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001469 for(append = file_mapping[index]; append; append = append->next) {
1470 int offset = append->file->fragment->offset;
1471 int size = append->file->fragment->size;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001472 unsigned short cksum =
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001473 get_checksum_mem(frag_buffer->data + offset, size);
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001474
1475 if(file == append->file)
1476 checksum = cksum;
1477
1478 pthread_mutex_lock(&dup_mutex);
1479 append->file->fragment_checksum = cksum;
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001480 append->file->have_frag_checksum = TRUE;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001481 pthread_mutex_unlock(&dup_mutex);
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001482 }
1483
1484 cache_block_put(frag_buffer);
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001485 pthread_cleanup_pop(0);
1486
1487 return checksum;
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001488}
1489
1490
Phillip Lougher943acad2014-04-17 03:31:01 +01001491void lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001492{
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001493 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001494 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001495 fragments_locked = TRUE;
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001496 pthread_cleanup_pop(1);
plougher2ea89142008-03-11 01:34:19 +00001497}
1498
1499
1500void unlock_fragments()
1501{
Phillip Loughercd6cb7a2013-05-29 02:31:39 +01001502 int frg, size;
Phillip Lougher6164b5f2013-05-23 05:05:10 +01001503 struct file_buffer *write_buffer;
plougher2ea89142008-03-11 01:34:19 +00001504
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001505 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001506 pthread_mutex_lock(&fragment_mutex);
Phillip Lougher71ad9642013-05-25 05:03:48 +01001507
1508 /*
1509 * Note queue_empty() is inherently racy with respect to concurrent
1510 * queue get and pushes. We avoid this because we're holding the
1511 * fragment_mutex which ensures no other threads can be using the
1512 * queue at this time.
1513 */
Phillip Lougher6164b5f2013-05-23 05:05:10 +01001514 while(!queue_empty(locked_fragment)) {
1515 write_buffer = queue_get(locked_fragment);
Phillip Loughercd6cb7a2013-05-29 02:31:39 +01001516 frg = write_buffer->block;
1517 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size);
1518 fragment_table[frg].start_block = bytes;
Phillip Lougher6164b5f2013-05-23 05:05:10 +01001519 write_buffer->block = bytes;
Phillip Loughercd6cb7a2013-05-29 02:31:39 +01001520 bytes += size;
plougher2ea89142008-03-11 01:34:19 +00001521 fragments_outstanding --;
Phillip Lougher6164b5f2013-05-23 05:05:10 +01001522 queue_put(to_writer, write_buffer);
plougher50b31762009-03-31 04:14:46 +00001523 TRACE("fragment_locked writing fragment %d, compressed size %d"
Phillip Loughercd6cb7a2013-05-29 02:31:39 +01001524 "\n", frg, size);
plougher2ea89142008-03-11 01:34:19 +00001525 }
1526 fragments_locked = FALSE;
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001527 pthread_cleanup_pop(1);
plougher2ea89142008-03-11 01:34:19 +00001528}
1529
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001530/* Called with the fragment_mutex locked */
plougherb7a66812010-07-21 01:06:59 +00001531void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001532 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001533{
Phillip Lougher6164b5f2013-05-23 05:05:10 +01001534 fragment_table[fragment].size = c_byte;
1535 write_buffer->block = fragment;
1536
1537 queue_put(locked_fragment, write_buffer);
plougher5507dd92006-11-06 00:43:10 +00001538}
1539
1540
Phillip Lougher04b7b532011-06-11 02:14:15 +01001541void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001542{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001543 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001544 return;
1545
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001546 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001547 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001548 fragment_table[fragment->block].unused = 0;
1549 fragments_outstanding ++;
1550 queue_put(to_frag, fragment);
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001551 pthread_cleanup_pop(1);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001552}
1553
1554
1555struct file_buffer *allocate_fragment()
1556{
Phillip Lougher316ab632013-04-29 02:53:39 +01001557 struct file_buffer *fragment = cache_get(fragment_buffer, fragments);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001558
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001559 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001560 pthread_mutex_lock(&fragment_mutex);
1561
plougher5507dd92006-11-06 00:43:10 +00001562 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001563 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001564 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
Phillip Lougher9bfa0b82013-04-06 05:05:15 +01001565 if(ft == NULL)
1566 MEM_ERROR();
plougherfa89c332010-07-27 00:27:15 +00001567 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001568 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001569
1570 fragment->size = 0;
1571 fragment->block = fragments ++;
1572
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01001573 pthread_cleanup_pop(1);
1574
Phillip Lougherb9508be2011-06-13 02:25:51 +01001575 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001576}
1577
ploughereb6eac92008-02-26 01:50:48 +00001578
plougher1f413c82005-11-18 00:02:14 +00001579static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougherd2f045f2012-12-28 03:15:45 +00001580
1581
1582void free_fragment(struct fragment *fragment)
1583{
1584 if(fragment != &empty_fragment)
1585 free(fragment);
1586}
1587
1588
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001589struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1590 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001591{
1592 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001593 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001594
plougher5507dd92006-11-06 00:43:10 +00001595 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001596 return &empty_fragment;
1597
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001598 fragment = eval_frag_actions(dir_ent);
1599
1600 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1601 write_fragment(*fragment);
1602 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001603 }
plougher1f413c82005-11-18 00:02:14 +00001604
ploughere7e6e832010-12-16 05:08:06 +00001605 ffrg = malloc(sizeof(struct fragment));
1606 if(ffrg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001607 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001608
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001609 if(*fragment == NULL)
1610 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001611
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001612 ffrg->index = (*fragment)->block;
1613 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001614 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001615 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001616 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001617 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001618
1619 return ffrg;
1620}
1621
1622
ploughera0a49c32010-08-11 01:47:59 +00001623long long generic_write_table(int length, void *buffer, int length2,
1624 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001625{
plougher17b269c2009-03-30 01:33:07 +00001626 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1627 SQUASHFS_METADATA_SIZE;
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001628 long long *list, start_bytes;
Phillip Lougherc1305322012-11-02 22:28:02 +00001629 int compressed_size, i, list_size = meta_blocks * sizeof(long long);
plougher1f413c82005-11-18 00:02:14 +00001630 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001631 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1632
plougher82ab2332009-04-21 00:21:21 +00001633#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001634 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001635 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001636#endif
plougher1f413c82005-11-18 00:02:14 +00001637
Phillip Lougherc1305322012-11-02 22:28:02 +00001638 list = malloc(list_size);
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001639 if(list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001640 MEM_ERROR();
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001641
plougher1f413c82005-11-18 00:02:14 +00001642 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001643 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1644 SQUASHFS_METADATA_SIZE : length;
1645 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1646 SQUASHFS_METADATA_SIZE , avail_bytes,
1647 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001648 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001649 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001650 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1651 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001652 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1653 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001654 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001655 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001656 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001657 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001658 }
1659
ploughere6e0e1b2010-05-12 17:17:06 +00001660 start_bytes = bytes;
1661 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001662 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001663 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001664 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001665 }
1666
plougher1f288f62009-02-21 03:05:52 +00001667 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
Phillip Lougherc1305322012-11-02 22:28:02 +00001668 write_destination(fd, bytes, list_size, list);
1669 bytes += list_size;
1670 total_bytes += list_size;
plougher1f413c82005-11-18 00:02:14 +00001671
plougher40d8b952010-02-12 16:26:32 +00001672 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1673 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001674
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001675 free(list);
1676
plougher1f413c82005-11-18 00:02:14 +00001677 return start_bytes;
1678}
1679
1680
plougher0e453652006-11-06 01:49:35 +00001681long long write_fragment_table()
1682{
1683 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher0e453652006-11-06 01:49:35 +00001684 int i;
1685
plougher17b269c2009-03-30 01:33:07 +00001686 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1687 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001688 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001689 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1690 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001691 fragment_table[i].size);
Phillip Lougher162c24c2012-10-30 02:54:16 +00001692 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
plougher0e453652006-11-06 01:49:35 +00001693 }
1694
Phillip Lougher162c24c2012-10-30 02:54:16 +00001695 return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001696}
1697
1698
plougher1f413c82005-11-18 00:02:14 +00001699char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001700static char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001701{
plougher1d065e92010-06-18 03:58:27 +00001702 int res;
1703
1704 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
Phillip Lougherac731382013-05-19 04:19:44 +01001705 if(res == 0)
1706 return NULL;
plougher1d065e92010-06-18 03:58:27 +00001707
plougher1f413c82005-11-18 00:02:14 +00001708 return read_from_file_buffer;
1709}
1710
1711
plougher1b899fc2008-08-07 01:24:06 +00001712char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
1713char *read_from_disk2(long long start, unsigned int avail_bytes)
1714{
plougher1d065e92010-06-18 03:58:27 +00001715 int res;
1716
1717 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
Phillip Lougherac731382013-05-19 04:19:44 +01001718 if(res == 0)
1719 return NULL;
plougher1d065e92010-06-18 03:58:27 +00001720
plougher1b899fc2008-08-07 01:24:06 +00001721 return read_from_file_buffer2;
1722}
1723
1724
plougher1f413c82005-11-18 00:02:14 +00001725/*
1726 * Compute 16 bit BSD checksum over the data
1727 */
plougher5507dd92006-11-06 00:43:10 +00001728unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00001729{
plougher5507dd92006-11-06 00:43:10 +00001730 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00001731
plougher5507dd92006-11-06 00:43:10 +00001732 while(bytes --) {
1733 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1734 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00001735 }
1736
1737 return chksum;
1738}
1739
1740
plougher17b269c2009-03-30 01:33:07 +00001741unsigned short get_checksum_disk(long long start, long long l,
1742 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00001743{
1744 unsigned short chksum = 0;
1745 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00001746 struct file_buffer *write_buffer;
1747 int i;
plougher5507dd92006-11-06 00:43:10 +00001748
plougher57e6d182008-05-06 23:51:29 +00001749 for(i = 0; l; i++) {
1750 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
1751 if(bytes == 0) /* sparse block */
1752 continue;
Phillip Lougher943acad2014-04-17 03:31:01 +01001753 write_buffer = cache_lookup(bwriter_buffer, start);
plougher57e6d182008-05-06 23:51:29 +00001754 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00001755 chksum = get_checksum(write_buffer->data, bytes,
1756 chksum);
plougher57e6d182008-05-06 23:51:29 +00001757 cache_block_put(write_buffer);
Phillip Lougherac731382013-05-19 04:19:44 +01001758 } else {
1759 void *data = read_from_disk(start, bytes);
1760 if(data == NULL) {
1761 ERROR("Failed to checksum data from output"
1762 " filesystem\n");
1763 BAD_ERROR("Output filesystem corrupted?\n");
1764 }
1765
1766 chksum = get_checksum(data, bytes, chksum);
1767 }
1768
plougher5507dd92006-11-06 00:43:10 +00001769 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00001770 start += bytes;
1771 }
1772
1773 return chksum;
1774}
1775
1776
plougher5507dd92006-11-06 00:43:10 +00001777unsigned short get_checksum_mem(char *buff, int bytes)
1778{
1779 return get_checksum(buff, bytes, 0);
1780}
1781
1782
1783unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
1784{
1785 if(file_buffer == NULL)
1786 return 0;
1787 else
1788 return get_checksum(file_buffer->data, file_buffer->size, 0);
1789}
1790
1791
plougher5507dd92006-11-06 00:43:10 +00001792#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00001793void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00001794 unsigned int *block_listp, int blocks, unsigned int fragment,
1795 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00001796{
1797 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00001798 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00001799 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001800 struct append_file *append_file;
1801 struct file_info *file;
plougher058eae42006-01-30 14:27:44 +00001802
plougher5507dd92006-11-06 00:43:10 +00001803 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00001804 return;
1805
plougher5507dd92006-11-06 00:43:10 +00001806 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
1807 if(file_size != dupl_ptr->file_size)
1808 continue;
1809 if(blocks != 0 && start != dupl_ptr->start)
1810 continue;
1811 if(fragment != dupl_ptr->fragment->index)
1812 continue;
plougher17b269c2009-03-30 01:33:07 +00001813 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
1814 dupl_ptr->fragment->offset || bytes !=
1815 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00001816 continue;
1817 return;
1818 }
1819
plougher3bb279c2010-12-16 05:10:03 +00001820 frg = malloc(sizeof(struct fragment));
1821 if(frg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001822 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001823
1824 frg->index = fragment;
1825 frg->offset = offset;
1826 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00001827
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001828 file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00001829 FALSE, FALSE);
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00001830
1831 if(fragment == SQUASHFS_INVALID_FRAG)
1832 return;
1833
1834 append_file = malloc(sizeof(struct append_file));
1835 if(append_file == NULL)
1836 MEM_ERROR();
1837
1838 append_file->file = file;
1839 append_file->next = file_mapping[fragment];
1840 file_mapping[fragment] = append_file;
plougher5507dd92006-11-06 00:43:10 +00001841}
plougher1f413c82005-11-18 00:02:14 +00001842
plougher1f413c82005-11-18 00:02:14 +00001843
plougher5507dd92006-11-06 00:43:10 +00001844int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00001845{
plougher5507dd92006-11-06 00:43:10 +00001846 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00001847
1848 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00001849 if(dupl_ptr->file_size == file_size)
1850 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00001851
plougher5507dd92006-11-06 00:43:10 +00001852 return FALSE;
1853}
1854
1855
plougher17b269c2009-03-30 01:33:07 +00001856struct file_info *add_non_dup(long long file_size, long long bytes,
1857 unsigned int *block_list, long long start, struct fragment *fragment,
1858 unsigned short checksum, unsigned short fragment_checksum,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00001859 int checksum_flag, int checksum_frag_flag)
plougher5507dd92006-11-06 00:43:10 +00001860{
plougher51ef9ae2010-12-16 05:14:28 +00001861 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00001862
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001863 if(dupl_ptr == NULL)
1864 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00001865
1866 dupl_ptr->file_size = file_size;
1867 dupl_ptr->bytes = bytes;
1868 dupl_ptr->block_list = block_list;
1869 dupl_ptr->start = start;
1870 dupl_ptr->fragment = fragment;
1871 dupl_ptr->checksum = checksum;
1872 dupl_ptr->fragment_checksum = fragment_checksum;
Phillip Lougherc6424dc2014-03-13 02:01:28 +00001873 dupl_ptr->have_frag_checksum = checksum_frag_flag;
Phillip Lougher557cefa2014-02-05 04:36:05 +00001874 dupl_ptr->have_checksum = checksum_flag;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001875
1876 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1877 pthread_mutex_lock(&dup_mutex);
plougher5507dd92006-11-06 00:43:10 +00001878 dupl_ptr->next = dupl[DUP_HASH(file_size)];
1879 dupl[DUP_HASH(file_size)] = dupl_ptr;
1880 dup_files ++;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001881 pthread_cleanup_pop(1);
plougher5507dd92006-11-06 00:43:10 +00001882
1883 return dupl_ptr;
1884}
1885
1886
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001887struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put)
1888{
1889 struct file_info *dupl_ptr;
1890 struct file_buffer *buffer;
1891 struct file_info *dupl_start = file_buffer->dupl_start;
1892 long long file_size = file_buffer->file_size;
1893 unsigned short checksum = file_buffer->checksum;
1894 int res;
1895
1896 if(file_buffer->duplicate) {
1897 TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
1898 "checksum 0x%x\n", dupl_start->fragment->index,
1899 file_size, dupl_start->fragment->offset, checksum);
1900 *dont_put = TRUE;
1901 return dupl_start->fragment;
1902 } else {
1903 *dont_put = FALSE;
1904 dupl_ptr = dupl[DUP_HASH(file_size)];
1905 }
1906
1907 for(; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) {
1908 if(file_size == dupl_ptr->file_size && file_size ==
1909 dupl_ptr->fragment->size) {
1910 if(get_fragment_checksum(dupl_ptr) == checksum) {
1911 buffer = get_fragment(dupl_ptr->fragment);
1912 res = memcmp(file_buffer->data, buffer->data +
1913 dupl_ptr->fragment->offset, file_size);
1914 cache_block_put(buffer);
1915 if(res == 0)
1916 break;
1917 }
1918 }
1919 }
1920
1921 if(!dupl_ptr || dupl_ptr == dupl_start)
1922 return NULL;
1923
1924 TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
1925 "checksum 0x%x\n", dupl_ptr->fragment->index, file_size,
1926 dupl_ptr->fragment->offset, checksum);
1927
1928 return dupl_ptr->fragment;
1929}
1930
1931
plougher17b269c2009-03-30 01:33:07 +00001932struct file_info *duplicate(long long file_size, long long bytes,
1933 unsigned int **block_list, long long *start, struct fragment **fragment,
1934 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00001935 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00001936{
1937 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
1938 int frag_bytes = file_buffer ? file_buffer->size : 0;
Phillip Lougherc6424dc2014-03-13 02:01:28 +00001939 unsigned short fragment_checksum = file_buffer ?
1940 file_buffer->checksum : 0;
plougher5507dd92006-11-06 00:43:10 +00001941
1942 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00001943 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
1944 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00001945 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00001946 int block;
1947
plougher17b269c2009-03-30 01:33:07 +00001948 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
1949 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00001950 continue;
1951
plougher5507dd92006-11-06 00:43:10 +00001952 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00001953 checksum = get_checksum_disk(*start, bytes,
1954 *block_list);
plougher5507dd92006-11-06 00:43:10 +00001955 checksum_flag = TRUE;
1956 }
1957
Phillip Lougher557cefa2014-02-05 04:36:05 +00001958 if(!dupl_ptr->have_checksum) {
1959 dupl_ptr->checksum =
1960 get_checksum_disk(dupl_ptr->start,
1961 dupl_ptr->bytes, dupl_ptr->block_list);
1962 dupl_ptr->have_checksum = TRUE;
plougher5507dd92006-11-06 00:43:10 +00001963 }
1964
plougher17b269c2009-03-30 01:33:07 +00001965 if(checksum != dupl_ptr->checksum ||
1966 fragment_checksum !=
Phillip Lougher8bb17b02014-03-30 23:59:55 +01001967 get_fragment_checksum(dupl_ptr))
plougher5507dd92006-11-06 00:43:10 +00001968 continue;
1969
plougher1b899fc2008-08-07 01:24:06 +00001970 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00001971 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00001972 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
1973 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00001974 struct file_buffer *target_buffer = NULL;
1975 struct file_buffer *dup_buffer = NULL;
1976 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00001977 int res;
plougher5507dd92006-11-06 00:43:10 +00001978
plougher1b899fc2008-08-07 01:24:06 +00001979 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00001980 continue;
Phillip Lougher943acad2014-04-17 03:31:01 +01001981 target_buffer = cache_lookup(bwriter_buffer,
plougher17b269c2009-03-30 01:33:07 +00001982 target_start);
plougher1b899fc2008-08-07 01:24:06 +00001983 if(target_buffer)
1984 target_data = target_buffer->data;
Phillip Lougherac731382013-05-19 04:19:44 +01001985 else {
plougher50b31762009-03-31 04:14:46 +00001986 target_data =
1987 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00001988 size);
Phillip Lougherac731382013-05-19 04:19:44 +01001989 if(target_data == NULL) {
1990 ERROR("Failed to read data from"
1991 " output filesystem\n");
1992 BAD_ERROR("Output filesystem"
1993 " corrupted?\n");
1994 }
1995 }
plougher5507dd92006-11-06 00:43:10 +00001996
Phillip Lougher943acad2014-04-17 03:31:01 +01001997 dup_buffer = cache_lookup(bwriter_buffer,
plougher360514a2009-03-30 03:01:38 +00001998 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00001999 if(dup_buffer)
2000 dup_data = dup_buffer->data;
Phillip Lougherac731382013-05-19 04:19:44 +01002001 else {
plougher360514a2009-03-30 03:01:38 +00002002 dup_data = read_from_disk2(dup_start,
2003 size);
Phillip Lougherac731382013-05-19 04:19:44 +01002004 if(dup_data == NULL) {
2005 ERROR("Failed to read data from"
2006 " output filesystem\n");
2007 BAD_ERROR("Output filesystem"
2008 " corrupted?\n");
2009 }
2010 }
plougher1b899fc2008-08-07 01:24:06 +00002011
2012 res = memcmp(target_data, dup_data, size);
2013 cache_block_put(target_buffer);
2014 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002015 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002016 break;
plougher1b899fc2008-08-07 01:24:06 +00002017 target_start += size;
2018 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002019 }
2020 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002021 struct file_buffer *frag_buffer =
2022 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002023
plougher17b269c2009-03-30 01:33:07 +00002024 if(frag_bytes == 0 ||
2025 memcmp(file_buffer->data,
2026 frag_buffer->data +
2027 dupl_ptr->fragment->offset,
2028 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002029 TRACE("Found duplicate file, start "
2030 "0x%llx, size %lld, checksum "
2031 "0x%x, fragment %d, size %d, "
2032 "offset %d, checksum 0x%x\n",
2033 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002034 dupl_ptr->bytes,
2035 dupl_ptr->checksum,
2036 dupl_ptr->fragment->index,
2037 frag_bytes,
2038 dupl_ptr->fragment->offset,
2039 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002040 *block_list = dupl_ptr->block_list;
2041 *start = dupl_ptr->start;
2042 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002043 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002044 return 0;
2045 }
plougher76c64082008-03-08 01:32:23 +00002046 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002047 }
2048 }
2049
2050
plougher17b269c2009-03-30 01:33:07 +00002051 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00002052 checksum, fragment_checksum, checksum_flag, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002053}
2054
2055
Phillip Lougher2504b082011-09-07 02:28:45 +01002056inline int is_fragment(struct inode_info *inode)
2057{
2058 int file_size = inode->buf.st_size;
2059
Phillip Lougher63f531f2011-09-10 04:03:32 +01002060 /*
2061 * If this block is to be compressed differently to the
2062 * fragment compression then it cannot be a fragment
2063 */
2064 if(inode->noF != noF)
2065 return FALSE;
2066
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002067 return !inode->no_fragments && file_size && (file_size < block_size ||
Phillip Lougher2504b082011-09-07 02:28:45 +01002068 (inode->always_use_fragments && file_size & (block_size - 1)));
2069}
2070
2071
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002072void put_file_buffer(struct file_buffer *file_buffer)
2073{
2074 /*
Phillip Lougher9de84ac2014-02-20 05:18:48 +00002075 * Decide where to send the file buffer:
2076 * - compressible non-fragment blocks go to the deflate threads,
2077 * - fragments go to the process fragment threads,
2078 * - all others go directly to the main thread
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002079 */
2080 if(file_buffer->error) {
2081 file_buffer->fragment = 0;
Phillip Lougher0e1656d2013-05-20 03:47:24 +01002082 seq_queue_put(to_main, file_buffer);
Phillip Lougher9de84ac2014-02-20 05:18:48 +00002083 } else if (file_buffer->file_size == 0)
Phillip Lougher0e1656d2013-05-20 03:47:24 +01002084 seq_queue_put(to_main, file_buffer);
Phillip Lougher9de84ac2014-02-20 05:18:48 +00002085 else if(file_buffer->fragment)
2086 queue_put(to_process_frag, file_buffer);
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002087 else
Phillip Loughercf478e92013-05-29 02:38:41 +01002088 queue_put(to_deflate, file_buffer);
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002089}
2090
2091
plougher00d08172009-09-03 10:17:44 +00002092static int seq = 0;
2093void reader_read_process(struct dir_ent *dir_ent)
2094{
Phillip Loughera8c9ff22014-04-29 03:53:18 +01002095 long long bytes = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002096 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002097 struct file_buffer *prev_buffer = NULL, *file_buffer;
Phillip Loughera8c9ff22014-04-29 03:53:18 +01002098 int status, byte, res, child;
2099 int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child);
2100
2101 if(!file) {
2102 file_buffer = cache_get_nohash(reader_buffer);
2103 file_buffer->sequence = seq ++;
2104 goto read_err;
2105 }
plougher00d08172009-09-03 10:17:44 +00002106
2107 while(1) {
Phillip Lougher316ab632013-04-29 02:53:39 +01002108 file_buffer = cache_get_nohash(reader_buffer);
plougher00d08172009-09-03 10:17:44 +00002109 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002110 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002111
2112 byte = read_bytes(file, file_buffer->data, block_size);
2113 if(byte == -1)
Phillip Loughera8c9ff22014-04-29 03:53:18 +01002114 goto read_err2;
plougher00d08172009-09-03 10:17:44 +00002115
2116 file_buffer->size = byte;
2117 file_buffer->file_size = -1;
plougher00d08172009-09-03 10:17:44 +00002118 file_buffer->error = FALSE;
2119 file_buffer->fragment = FALSE;
2120 bytes += byte;
2121
2122 if(byte == 0)
2123 break;
2124
plougher286b6b32009-09-19 03:29:27 +00002125 /*
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002126 * Update progress bar size. This is done
plougher286b6b32009-09-19 03:29:27 +00002127 * on every block rather than waiting for all blocks to be
2128 * read incase write_file_process() is running in parallel
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002129 * with this. Otherwise the current progress bar position
2130 * may get ahead of the progress bar size.
plougher286b6b32009-09-19 03:29:27 +00002131 */
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002132 progress_bar_size(1);
plougher286b6b32009-09-19 03:29:27 +00002133
plougher00d08172009-09-03 10:17:44 +00002134 if(prev_buffer)
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002135 put_file_buffer(prev_buffer);
plougher00d08172009-09-03 10:17:44 +00002136 prev_buffer = file_buffer;
2137 }
2138
plougher54d67292009-09-19 03:26:27 +00002139 /*
2140 * Update inode file size now that the size of the dynamic pseudo file
2141 * is known. This is needed for the -info option.
2142 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002143 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002144
plougherba674e82009-09-10 03:50:00 +00002145 res = waitpid(child, &status, 0);
Phillip Loughera8c9ff22014-04-29 03:53:18 +01002146 close(file);
2147
plougherd87d8d12009-09-10 04:08:16 +00002148 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002149 goto read_err;
2150
plougher00d08172009-09-03 10:17:44 +00002151 if(prev_buffer == NULL)
2152 prev_buffer = file_buffer;
2153 else {
2154 cache_block_put(file_buffer);
2155 seq --;
2156 }
2157 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002158 prev_buffer->fragment = is_fragment(inode);
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002159 put_file_buffer(prev_buffer);
plougher00d08172009-09-03 10:17:44 +00002160
2161 return;
2162
Phillip Loughera8c9ff22014-04-29 03:53:18 +01002163read_err2:
2164 close(file);
plougher00d08172009-09-03 10:17:44 +00002165read_err:
2166 if(prev_buffer) {
2167 cache_block_put(file_buffer);
2168 seq --;
2169 file_buffer = prev_buffer;
2170 }
2171 file_buffer->error = TRUE;
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002172 put_file_buffer(file_buffer);
plougher00d08172009-09-03 10:17:44 +00002173}
2174
2175
plougher5507dd92006-11-06 00:43:10 +00002176void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002177{
plougher018d2b32007-04-23 03:01:48 +00002178 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002179 struct file_buffer *file_buffer;
Phillip Lougherce119e72014-03-11 04:14:00 +00002180 int blocks, file, res;
plougher018d2b32007-04-23 03:01:48 +00002181 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002182 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002183
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002184 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002185 return;
2186
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002187 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002188again:
2189 bytes = 0;
plougher018d2b32007-04-23 03:01:48 +00002190 read_size = buf->st_size;
2191 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002192
Phillip Lougher494479f2012-02-03 15:45:41 +00002193 file = open(pathname_reader(dir_ent), O_RDONLY);
plougherc1d258e2010-12-16 05:16:45 +00002194 if(file == -1) {
Phillip Lougher316ab632013-04-29 02:53:39 +01002195 file_buffer = cache_get_nohash(reader_buffer);
plougher1e380702010-08-11 01:52:49 +00002196 file_buffer->sequence = seq ++;
Phillip Lougher2302f692012-12-27 04:05:02 +00002197 goto read_err2;
plougher1e380702010-08-11 01:52:49 +00002198 }
plougher5507dd92006-11-06 00:43:10 +00002199
plougher018d2b32007-04-23 03:01:48 +00002200 do {
Phillip Lougher316ab632013-04-29 02:53:39 +01002201 file_buffer = cache_get_nohash(reader_buffer);
Phillip Lougherce119e72014-03-11 04:14:00 +00002202 file_buffer->file_size = read_size;
plougher00d08172009-09-03 10:17:44 +00002203 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002204 file_buffer->noD = inode->noD;
Phillip Lougherce119e72014-03-11 04:14:00 +00002205 file_buffer->error = FALSE;
plougher5507dd92006-11-06 00:43:10 +00002206
ploughera4c24ed2010-08-11 02:08:38 +00002207 /*
2208 * Always try to read block_size bytes from the file rather
2209 * than expected bytes (which will be less than the block_size
2210 * at the file tail) to check that the file hasn't grown
2211 * since being stated. If it is longer (or shorter) than
2212 * expected, then restat, and try again. Note the special
2213 * case where the file is an exact multiple of the block_size
2214 * is dealt with later.
2215 */
Phillip Lougherce119e72014-03-11 04:14:00 +00002216 file_buffer->size = read_bytes(file, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002217 block_size);
Phillip Lougherce119e72014-03-11 04:14:00 +00002218 if(file_buffer->size == -1)
ploughera4c24ed2010-08-11 02:08:38 +00002219 goto read_err;
2220
Phillip Lougherce119e72014-03-11 04:14:00 +00002221 bytes += file_buffer->size;
plougher018d2b32007-04-23 03:01:48 +00002222
Phillip Lougherce119e72014-03-11 04:14:00 +00002223 if(blocks > 1) {
2224 /* non-tail block should be exactly block_size */
2225 if(file_buffer->size < block_size)
2226 goto restat;
plougher018d2b32007-04-23 03:01:48 +00002227
Phillip Lougherce119e72014-03-11 04:14:00 +00002228 file_buffer->fragment = FALSE;
2229 put_file_buffer(file_buffer);
2230 }
Phillip Lougher8678d302014-03-02 03:02:19 +00002231 } while(-- blocks > 0);
plougher018d2b32007-04-23 03:01:48 +00002232
Phillip Lougherce119e72014-03-11 04:14:00 +00002233 /* Overall size including tail should match */
plougher018d2b32007-04-23 03:01:48 +00002234 if(read_size != bytes)
2235 goto restat;
2236
Phillip Lougher191dfcd2014-03-11 02:58:52 +00002237 if(read_size && read_size % block_size == 0) {
ploughera4c24ed2010-08-11 02:08:38 +00002238 /*
2239 * Special case where we've not tried to read past the end of
2240 * the file. We expect to get EOF, i.e. the file isn't larger
2241 * than we expect.
2242 */
plougher018d2b32007-04-23 03:01:48 +00002243 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002244 int res;
plougher018d2b32007-04-23 03:01:48 +00002245
ploughera4c24ed2010-08-11 02:08:38 +00002246 res = read_bytes(file, &buffer, 1);
2247 if(res == -1)
2248 goto read_err;
2249
2250 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002251 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002252 }
2253
Phillip Lougher2504b082011-09-07 02:28:45 +01002254 file_buffer->fragment = is_fragment(inode);
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002255 put_file_buffer(file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002256
plougher5507dd92006-11-06 00:43:10 +00002257 close(file);
plougher5507dd92006-11-06 00:43:10 +00002258
2259 return;
2260
plougher018d2b32007-04-23 03:01:48 +00002261restat:
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002262 res = fstat(file, &buf2);
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002263 if(res == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00002264 ERROR("Cannot stat dir/file %s because %s\n",
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002265 pathname_reader(dir_ent), strerror(errno));
2266 goto read_err;
2267 }
2268
plougher018d2b32007-04-23 03:01:48 +00002269 if(read_size != buf2.st_size) {
Phillip Lougher2302f692012-12-27 04:05:02 +00002270 close(file);
plougher018d2b32007-04-23 03:01:48 +00002271 memcpy(buf, &buf2, sizeof(struct stat));
2272 file_buffer->error = 2;
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002273 put_file_buffer(file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002274 goto again;
2275 }
plougher1e380702010-08-11 01:52:49 +00002276read_err:
Phillip Lougher2302f692012-12-27 04:05:02 +00002277 close(file);
2278read_err2:
plougher1e380702010-08-11 01:52:49 +00002279 file_buffer->error = TRUE;
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002280 put_file_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002281}
2282
2283
2284void reader_scan(struct dir_info *dir) {
Phillip Lougherbf338362012-08-22 05:24:36 +01002285 struct dir_ent *dir_ent = dir->list;
plougher5507dd92006-11-06 00:43:10 +00002286
Phillip Lougherbf338362012-08-22 05:24:36 +01002287 for(; dir_ent; dir_ent = dir_ent->next) {
plougher5507dd92006-11-06 00:43:10 +00002288 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002289 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002290 continue;
2291
plougherb3977eb2010-05-02 02:08:48 +00002292 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002293 reader_read_process(dir_ent);
2294 continue;
2295 }
2296
plougher5507dd92006-11-06 00:43:10 +00002297 switch(buf->st_mode & S_IFMT) {
2298 case S_IFREG:
2299 reader_read_file(dir_ent);
2300 break;
2301 case S_IFDIR:
2302 reader_scan(dir_ent->dir);
2303 break;
2304 }
2305 }
2306}
2307
2308
2309void *reader(void *arg)
2310{
plougher5507dd92006-11-06 00:43:10 +00002311 if(!sorted)
2312 reader_scan(queue_get(to_reader));
2313 else {
2314 int i;
2315 struct priority_entry *entry;
2316
2317 queue_get(to_reader);
2318 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002319 for(entry = priority_list[i]; entry;
2320 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002321 reader_read_file(entry->dir);
2322 }
rloughere4873e02007-11-08 17:50:42 +00002323
2324 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002325}
2326
2327
2328void *writer(void *arg)
2329{
plougher5507dd92006-11-06 00:43:10 +00002330 while(1) {
2331 struct file_buffer *file_buffer = queue_get(to_writer);
2332 off_t off;
2333
2334 if(file_buffer == NULL) {
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002335 queue_put(from_writer, NULL);
plougher5507dd92006-11-06 00:43:10 +00002336 continue;
2337 }
2338
2339 off = file_buffer->block;
2340
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01002341 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
plougher5507dd92006-11-06 00:43:10 +00002342 pthread_mutex_lock(&pos_mutex);
2343
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002344 if(lseek(fd, off, SEEK_SET) == -1) {
Phillip Lougherd23000c2013-02-06 22:05:45 +00002345 ERROR("writer: Lseek on destination failed because "
2346 "%s, offset=0x%llx\n", strerror(errno), off);
Phillip Lougher9bfa0b82013-04-06 05:05:15 +01002347 BAD_ERROR("Probably out of space on output "
Phillip Lougher3f4ccd22013-02-11 04:40:09 +00002348 "%s\n", block_device ? "block device" :
2349 "filesystem");
plougher5507dd92006-11-06 00:43:10 +00002350 }
2351
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002352 if(write_bytes(fd, file_buffer->data,
Phillip Lougher9bfa0b82013-04-06 05:05:15 +01002353 file_buffer->size) == -1)
2354 BAD_ERROR("Failed to write to output %s\n",
Phillip Loughere9df4552013-02-14 23:06:29 +00002355 block_device ? "block device" : "filesystem");
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01002356
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01002357 pthread_cleanup_pop(1);
2358
ploughereb6eac92008-02-26 01:50:48 +00002359 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002360 }
2361}
2362
2363
plougher5b09fd42007-08-06 10:28:41 +00002364int all_zero(struct file_buffer *file_buffer)
2365{
2366 int i;
2367 long entries = file_buffer->size / sizeof(long);
2368 long *p = (long *) file_buffer->data;
2369
2370 for(i = 0; i < entries && p[i] == 0; i++);
2371
2372 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002373 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002374 i < file_buffer->size && file_buffer->data[i] == 0;
2375 i++);
plougher5b09fd42007-08-06 10:28:41 +00002376
2377 return i == file_buffer->size;
2378 }
2379
2380 return 0;
2381}
2382
2383
plougher5507dd92006-11-06 00:43:10 +00002384void *deflator(void *arg)
2385{
Phillip Lougher943acad2014-04-17 03:31:01 +01002386 struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer);
plougher7b8ee502009-07-29 07:54:30 +00002387 void *stream = NULL;
Phillip Lougher3c838292013-03-26 04:24:53 +00002388 int res;
plougher5507dd92006-11-06 00:43:10 +00002389
plougher13fdddf2010-11-24 01:23:41 +00002390 res = compressor_init(comp, &stream, block_size, 1);
2391 if(res)
2392 BAD_ERROR("deflator:: compressor_init failed\n");
2393
plougher5507dd92006-11-06 00:43:10 +00002394 while(1) {
Phillip Loughercf478e92013-05-29 02:38:41 +01002395 struct file_buffer *file_buffer = queue_get(to_deflate);
plougher5507dd92006-11-06 00:43:10 +00002396
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002397 if(sparse_files && all_zero(file_buffer)) {
Phillip Lougher48854382011-09-09 03:36:55 +01002398 file_buffer->c_byte = 0;
Phillip Lougher0e1656d2013-05-20 03:47:24 +01002399 seq_queue_put(to_main, file_buffer);
plougher1b899fc2008-08-07 01:24:06 +00002400 } else {
plougher13fdddf2010-11-24 01:23:41 +00002401 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002402 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002403 file_buffer->size, block_size,
2404 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002405 write_buffer->sequence = file_buffer->sequence;
2406 write_buffer->file_size = file_buffer->file_size;
2407 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002408 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2409 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002410 write_buffer->fragment = FALSE;
2411 write_buffer->error = FALSE;
2412 cache_block_put(file_buffer);
Phillip Lougher0e1656d2013-05-20 03:47:24 +01002413 seq_queue_put(to_main, write_buffer);
Phillip Lougher943acad2014-04-17 03:31:01 +01002414 write_buffer = cache_get_nohash(bwriter_buffer);
plougher1b899fc2008-08-07 01:24:06 +00002415 }
plougher5507dd92006-11-06 00:43:10 +00002416 }
2417}
2418
2419
2420void *frag_deflator(void *arg)
2421{
plougher7b8ee502009-07-29 07:54:30 +00002422 void *stream = NULL;
Phillip Lougher3c838292013-03-26 04:24:53 +00002423 int res;
plougher5507dd92006-11-06 00:43:10 +00002424
plougher13fdddf2010-11-24 01:23:41 +00002425 res = compressor_init(comp, &stream, block_size, 1);
2426 if(res)
2427 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2428
Phillip Lougher53240e62013-04-30 23:51:29 +01002429 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
2430
plougher5507dd92006-11-06 00:43:10 +00002431 while(1) {
2432 int c_byte, compressed_size;
2433 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002434 struct file_buffer *write_buffer =
Phillip Lougher943acad2014-04-17 03:31:01 +01002435 cache_get(fwriter_buffer, file_buffer->block);
plougher5507dd92006-11-06 00:43:10 +00002436
plougher13fdddf2010-11-24 01:23:41 +00002437 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002438 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002439 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002440 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002441 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002442 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002443 fragment_table[file_buffer->block].size = c_byte;
2444 fragment_table[file_buffer->block].start_block = bytes;
2445 write_buffer->block = bytes;
2446 bytes += compressed_size;
2447 fragments_outstanding --;
Phillip Lougher39d7c4f2013-04-30 23:42:28 +01002448 pthread_mutex_unlock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002449 queue_put(to_writer, write_buffer);
plougher110799c2009-03-30 01:50:40 +00002450 TRACE("Writing fragment %lld, uncompressed size %d, "
2451 "compressed size %d\n", file_buffer->block,
2452 file_buffer->size, compressed_size);
Phillip Lougher39d7c4f2013-04-30 23:42:28 +01002453 } else {
plougher110799c2009-03-30 01:50:40 +00002454 add_pending_fragment(write_buffer, c_byte,
2455 file_buffer->block);
Phillip Lougher39d7c4f2013-04-30 23:42:28 +01002456 pthread_mutex_unlock(&fragment_mutex);
2457 }
ploughereb6eac92008-02-26 01:50:48 +00002458 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002459 }
Phillip Lougher53240e62013-04-30 23:51:29 +01002460
2461 pthread_cleanup_pop(0);
plougher5507dd92006-11-06 00:43:10 +00002462}
2463
2464
Phillip Lougherc6a1bc52013-05-20 04:08:42 +01002465struct file_buffer *get_file_buffer()
plougher5507dd92006-11-06 00:43:10 +00002466{
Phillip Lougherc6a1bc52013-05-20 04:08:42 +01002467 struct file_buffer *file_buffer = seq_queue_get(to_main);
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002468
Phillip Lougher4bb21cb2013-05-19 04:27:38 +01002469 return file_buffer;
plougher5507dd92006-11-06 00:43:10 +00002470}
2471
2472
plougher110799c2009-03-30 01:50:40 +00002473void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
Phillip Lougher948bf3a2014-03-02 02:23:54 +00002474 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002475{
2476 file_count ++;
2477 *duplicate_file = FALSE;
Phillip Lougher948bf3a2014-03-02 02:23:54 +00002478 cache_block_put(file_buffer);
plougherc1ace522010-05-01 03:00:45 +00002479 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2480 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002481}
2482
2483
Phillip Lougher8531f872014-03-01 03:22:41 +00002484void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher110799c2009-03-30 01:50:40 +00002485 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002486{
Phillip Lougher8531f872014-03-01 03:22:41 +00002487 int size = file_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00002488 struct fragment *fragment;
Phillip Lougherc6424dc2014-03-13 02:01:28 +00002489 unsigned short checksum = file_buffer->checksum;
Phillip Lougher8bb17b02014-03-30 23:59:55 +01002490 char dont_put;
plougher5507dd92006-11-06 00:43:10 +00002491
Phillip Lougher8bb17b02014-03-30 23:59:55 +01002492 fragment = frag_duplicate(file_buffer, &dont_put);
2493 *duplicate_file = !fragment;
2494 if(!fragment) {
2495 fragment = get_and_fill_fragment(file_buffer, dir_ent);
2496 if(duplicate_checking)
2497 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum,
2498 TRUE, TRUE);
plougher29e37092007-04-15 01:24:51 +00002499 }
plougher5507dd92006-11-06 00:43:10 +00002500
Phillip Lougher8bb17b02014-03-30 23:59:55 +01002501 if(dont_put)
2502 free(file_buffer);
2503 else
2504 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002505
2506 total_bytes += size;
2507 file_count ++;
2508
plougher35a10602008-04-21 02:58:16 +00002509 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002510
plougherc1ace522010-05-01 03:00:45 +00002511 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002512 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002513
Phillip Lougher8bb17b02014-03-30 23:59:55 +01002514 if(!duplicate_checking)
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002515 free_fragment(fragment);
plougher5507dd92006-11-06 00:43:10 +00002516}
2517
2518
plougher00d08172009-09-03 10:17:44 +00002519int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2520 struct file_buffer *read_buffer, int *duplicate_file)
2521{
2522 long long read_size, file_bytes, start;
2523 struct fragment *fragment;
2524 unsigned int *block_list = NULL;
2525 int block = 0, status;
2526 long long sparse = 0;
2527 struct file_buffer *fragment_buffer = NULL;
2528
2529 *duplicate_file = FALSE;
2530
2531 lock_fragments();
2532
2533 file_bytes = 0;
2534 start = bytes;
2535 while (1) {
2536 read_size = read_buffer->file_size;
Phillip Lougherb1ed0df2013-05-20 04:44:04 +01002537 if(read_buffer->fragment)
plougher00d08172009-09-03 10:17:44 +00002538 fragment_buffer = read_buffer;
2539 else {
2540 block_list = realloc(block_list, (block + 1) *
2541 sizeof(unsigned int));
2542 if(block_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002543 MEM_ERROR();
plougher00d08172009-09-03 10:17:44 +00002544 block_list[block ++] = read_buffer->c_byte;
2545 if(read_buffer->c_byte) {
2546 read_buffer->block = bytes;
2547 bytes += read_buffer->size;
Phillip Lougher84e20d72014-02-23 05:23:41 +00002548 cache_hash(read_buffer, read_buffer->block);
plougher00d08172009-09-03 10:17:44 +00002549 file_bytes += read_buffer->size;
2550 queue_put(to_writer, read_buffer);
2551 } else {
2552 sparse += read_buffer->size;
2553 cache_block_put(read_buffer);
2554 }
2555 }
plougher286b6b32009-09-19 03:29:27 +00002556 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002557
2558 if(read_size != -1)
2559 break;
2560
Phillip Lougherc6a1bc52013-05-20 04:08:42 +01002561 read_buffer = get_file_buffer();
plougher00d08172009-09-03 10:17:44 +00002562 if(read_buffer->error)
2563 goto read_err;
2564 }
2565
2566 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002567 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002568
2569 if(duplicate_checking)
2570 add_non_dup(read_size, file_bytes, block_list, start, fragment,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00002571 0, fragment_buffer ? fragment_buffer->checksum : 0,
2572 FALSE, TRUE);
2573 cache_block_put(fragment_buffer);
plougher00d08172009-09-03 10:17:44 +00002574 file_count ++;
2575 total_bytes += read_size;
2576
plougherc1ace522010-05-01 03:00:45 +00002577 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2578 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002579
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002580 if(duplicate_checking == FALSE) {
plougher00d08172009-09-03 10:17:44 +00002581 free(block_list);
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002582 free_fragment(fragment);
2583 }
plougher00d08172009-09-03 10:17:44 +00002584
2585 return 0;
2586
2587read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002588 dec_progress_bar(block);
plougher00d08172009-09-03 10:17:44 +00002589 status = read_buffer->error;
2590 bytes = start;
2591 if(!block_device) {
2592 int res;
2593
2594 queue_put(to_writer, NULL);
2595 if(queue_get(from_writer) != 0)
2596 EXIT_MKSQUASHFS();
2597 res = ftruncate(fd, bytes);
2598 if(res != 0)
2599 BAD_ERROR("Failed to truncate dest file because %s\n",
2600 strerror(errno));
2601 }
2602 unlock_fragments();
2603 free(block_list);
2604 cache_block_put(read_buffer);
2605 return status;
2606}
2607
2608
plougher110799c2009-03-30 01:50:40 +00002609int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
Phillip Lougher1807caa2014-03-01 03:28:33 +00002610 struct file_buffer *read_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002611{
plougher29e37092007-04-15 01:24:51 +00002612 int block, thresh;
Phillip Lougher1807caa2014-03-01 03:28:33 +00002613 long long read_size = read_buffer->file_size;
plougher1b899fc2008-08-07 01:24:06 +00002614 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00002615 struct fragment *fragment;
2616 struct file_info *dupl_ptr;
2617 int blocks = (read_size + block_size - 1) >> block_log;
2618 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00002619 struct file_buffer **buffer_list;
Phillip Lougher943acad2014-04-17 03:31:01 +01002620 int status;
plougher1b899fc2008-08-07 01:24:06 +00002621 long long sparse = 0;
2622 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002623
plougher50b31762009-03-31 04:14:46 +00002624 block_list = malloc(blocks * sizeof(unsigned int));
2625 if(block_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002626 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00002627 block_listp = block_list;
2628
plougher50b31762009-03-31 04:14:46 +00002629 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
2630 if(buffer_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002631 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00002632
Phillip Lougher943acad2014-04-17 03:31:01 +01002633 lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00002634
2635 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00002636 start = dup_start = bytes;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01002637 thresh = blocks > bwriter_size ? blocks - bwriter_size : 0;
plougher1b899fc2008-08-07 01:24:06 +00002638
2639 for(block = 0; block < blocks;) {
Phillip Lougherb1ed0df2013-05-20 04:44:04 +01002640 if(read_buffer->fragment) {
Phillip Lougher38cb1ab2013-01-13 21:20:09 +00002641 block_list[block] = 0;
Phillip Lougher19de5b62013-01-13 21:31:51 +00002642 buffer_list[block] = NULL;
plougher1b899fc2008-08-07 01:24:06 +00002643 fragment_buffer = read_buffer;
2644 blocks = read_size >> block_log;
2645 } else {
2646 block_list[block] = read_buffer->c_byte;
2647
2648 if(read_buffer->c_byte) {
2649 read_buffer->block = bytes;
2650 bytes += read_buffer->size;
2651 file_bytes += read_buffer->size;
Phillip Lougher84e20d72014-02-23 05:23:41 +00002652 cache_hash(read_buffer, read_buffer->block);
plougher1b899fc2008-08-07 01:24:06 +00002653 if(block < thresh) {
2654 buffer_list[block] = NULL;
2655 queue_put(to_writer, read_buffer);
2656 } else
2657 buffer_list[block] = read_buffer;
2658 } else {
2659 buffer_list[block] = NULL;
2660 sparse += read_buffer->size;
2661 cache_block_put(read_buffer);
2662 }
2663 }
2664 inc_progress_bar();
2665
2666 if(++block < blocks) {
Phillip Lougherc6a1bc52013-05-20 04:08:42 +01002667 read_buffer = get_file_buffer();
plougher018d2b32007-04-23 03:01:48 +00002668 if(read_buffer->error)
2669 goto read_err;
2670 }
plougher5507dd92006-11-06 00:43:10 +00002671 }
2672
plougher110799c2009-03-30 01:50:40 +00002673 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00002674 &fragment, fragment_buffer, blocks, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00002675
2676 if(dupl_ptr) {
2677 *duplicate_file = FALSE;
2678 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00002679 if(buffer_list[block])
2680 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002681 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002682 dupl_ptr->fragment = fragment;
2683 } else {
2684 *duplicate_file = TRUE;
2685 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00002686 cache_block_put(buffer_list[block]);
2687 bytes = start;
2688 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00002689 int res;
2690
plougher1b899fc2008-08-07 01:24:06 +00002691 queue_put(to_writer, NULL);
2692 if(queue_get(from_writer) != 0)
2693 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00002694 res = ftruncate(fd, bytes);
2695 if(res != 0)
2696 BAD_ERROR("Failed to truncate dest file because"
2697 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00002698 }
plougher5507dd92006-11-06 00:43:10 +00002699 }
2700
plougher2ea89142008-03-11 01:34:19 +00002701 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00002702 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002703 free(buffer_list);
2704 file_count ++;
2705 total_bytes += read_size;
2706
plougher360514a2009-03-30 03:01:38 +00002707 /*
2708 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002709 * a smaller block count on stat calls to sparse files. This is
2710 * to ensure intelligent applications like cp correctly handle the
2711 * file as a sparse file. If the file in the original filesystem isn't
2712 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002713 * report it as non-sparse on stat calls to preserve semantics
2714 */
plougher1b899fc2008-08-07 01:24:06 +00002715 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2716 sparse = 0;
2717
plougherc1ace522010-05-01 03:00:45 +00002718 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
2719 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002720
plougher5507dd92006-11-06 00:43:10 +00002721 if(*duplicate_file == TRUE)
2722 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002723
plougher018d2b32007-04-23 03:01:48 +00002724 return 0;
plougher5507dd92006-11-06 00:43:10 +00002725
2726read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002727 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00002728 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002729 bytes = start;
2730 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00002731 int res;
2732
plougher5507dd92006-11-06 00:43:10 +00002733 queue_put(to_writer, NULL);
2734 if(queue_get(from_writer) != 0)
2735 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00002736 res = ftruncate(fd, bytes);
2737 if(res != 0)
2738 BAD_ERROR("Failed to truncate dest file because %s\n",
2739 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002740 }
plougher2ea89142008-03-11 01:34:19 +00002741 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00002742 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00002743 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00002744 free(buffer_list);
2745 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00002746 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002747 return status;
plougher5507dd92006-11-06 00:43:10 +00002748}
2749
2750
Phillip Lougher75bd21d2014-03-02 03:33:56 +00002751int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
2752 struct file_buffer *read_buffer, int *dup)
2753{
2754 long long read_size = read_buffer->file_size;
2755 long long file_bytes, start;
2756 struct fragment *fragment;
2757 unsigned int *block_list;
2758 int block, status;
2759 int blocks = (read_size + block_size - 1) >> block_log;
2760 long long sparse = 0;
2761 struct file_buffer *fragment_buffer = NULL;
2762
2763 if(pre_duplicate(read_size))
2764 return write_file_blocks_dup(inode, dir_ent, read_buffer, dup);
2765
2766 *dup = FALSE;
2767
2768 block_list = malloc(blocks * sizeof(unsigned int));
2769 if(block_list == NULL)
2770 MEM_ERROR();
2771
2772 lock_fragments();
2773
2774 file_bytes = 0;
2775 start = bytes;
2776 for(block = 0; block < blocks;) {
2777 if(read_buffer->fragment) {
2778 block_list[block] = 0;
2779 fragment_buffer = read_buffer;
2780 blocks = read_size >> block_log;
2781 } else {
2782 block_list[block] = read_buffer->c_byte;
2783 if(read_buffer->c_byte) {
2784 read_buffer->block = bytes;
2785 bytes += read_buffer->size;
2786 cache_hash(read_buffer, read_buffer->block);
2787 file_bytes += read_buffer->size;
2788 queue_put(to_writer, read_buffer);
2789 } else {
2790 sparse += read_buffer->size;
2791 cache_block_put(read_buffer);
2792 }
2793 }
2794 inc_progress_bar();
2795
2796 if(++block < blocks) {
2797 read_buffer = get_file_buffer();
2798 if(read_buffer->error)
2799 goto read_err;
2800 }
2801 }
2802
2803 unlock_fragments();
2804 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
Phillip Lougher75bd21d2014-03-02 03:33:56 +00002805
2806 if(duplicate_checking)
2807 add_non_dup(read_size, file_bytes, block_list, start, fragment,
Phillip Lougherc6424dc2014-03-13 02:01:28 +00002808 0, fragment_buffer ? fragment_buffer->checksum : 0,
2809 FALSE, TRUE);
2810 cache_block_put(fragment_buffer);
Phillip Lougher75bd21d2014-03-02 03:33:56 +00002811 file_count ++;
2812 total_bytes += read_size;
2813
2814 /*
2815 * sparse count is needed to ensure squashfs correctly reports a
2816 * a smaller block count on stat calls to sparse files. This is
2817 * to ensure intelligent applications like cp correctly handle the
2818 * file as a sparse file. If the file in the original filesystem isn't
2819 * stored as a sparse file then still store it sparsely in squashfs, but
2820 * report it as non-sparse on stat calls to preserve semantics
2821 */
2822 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2823 sparse = 0;
2824
2825 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2826 blocks, block_list, fragment, NULL, sparse);
2827
2828 if(duplicate_checking == FALSE) {
2829 free(block_list);
2830 free_fragment(fragment);
2831 }
2832
2833 return 0;
2834
2835read_err:
2836 dec_progress_bar(block);
2837 status = read_buffer->error;
2838 bytes = start;
2839 if(!block_device) {
2840 int res;
2841
2842 queue_put(to_writer, NULL);
2843 if(queue_get(from_writer) != 0)
2844 EXIT_MKSQUASHFS();
2845 res = ftruncate(fd, bytes);
2846 if(res != 0)
2847 BAD_ERROR("Failed to truncate dest file because %s\n",
2848 strerror(errno));
2849 }
2850 unlock_fragments();
2851 free(block_list);
2852 cache_block_put(read_buffer);
2853 return status;
2854}
2855
2856
Phillip Lougherc3489132014-03-02 01:41:36 +00002857void write_file(squashfs_inode *inode, struct dir_ent *dir, int *dup)
plougher5507dd92006-11-06 00:43:10 +00002858{
plougher018d2b32007-04-23 03:01:48 +00002859 int status;
2860 struct file_buffer *read_buffer;
plougher5507dd92006-11-06 00:43:10 +00002861
plougher018d2b32007-04-23 03:01:48 +00002862again:
Phillip Lougherc6a1bc52013-05-20 04:08:42 +01002863 read_buffer = get_file_buffer();
Phillip Lougherc3489132014-03-02 01:41:36 +00002864 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002865
Phillip Lougherc3489132014-03-02 01:41:36 +00002866 if(status)
ploughereb6eac92008-02-26 01:50:48 +00002867 cache_block_put(read_buffer);
Phillip Lougherc3489132014-03-02 01:41:36 +00002868 else if(read_buffer->file_size == -1)
2869 status = write_file_process(inode, dir, read_buffer, dup);
Phillip Lougher948bf3a2014-03-02 02:23:54 +00002870 else if(read_buffer->file_size == 0)
2871 write_file_empty(inode, dir, read_buffer, dup);
2872 else if(read_buffer->fragment && read_buffer->c_byte)
Phillip Lougherc3489132014-03-02 01:41:36 +00002873 write_file_frag(inode, dir, read_buffer, dup);
plougher29e37092007-04-15 01:24:51 +00002874 else
Phillip Lougherc3489132014-03-02 01:41:36 +00002875 status = write_file_blocks(inode, dir, read_buffer, dup);
plougher5507dd92006-11-06 00:43:10 +00002876
plougher018d2b32007-04-23 03:01:48 +00002877 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00002878 ERROR("File %s changed size while reading filesystem, "
Phillip Lougherc3489132014-03-02 01:41:36 +00002879 "attempting to re-read\n", pathname(dir));
plougher018d2b32007-04-23 03:01:48 +00002880 goto again;
2881 } else if(status == 1) {
Phillip Lougherc3489132014-03-02 01:41:36 +00002882 ERROR_START("Failed to read file %s", pathname(dir));
Phillip Lougher85776df2014-01-31 03:10:46 +00002883 ERROR_EXIT(", creating empty file\n");
Phillip Lougher948bf3a2014-03-02 02:23:54 +00002884 write_file_empty(inode, dir, NULL, dup);
plougher29e37092007-04-15 01:24:51 +00002885 }
plougher5507dd92006-11-06 00:43:10 +00002886}
2887
2888
Phillip Lougher3f81a772012-12-04 05:07:24 +00002889#define BUFF_SIZE 512
plougher1f413c82005-11-18 00:02:14 +00002890char *name;
2891char *basename_r();
2892
2893char *getbase(char *pathname)
2894{
Phillip Lougher3f81a772012-12-04 05:07:24 +00002895 static char *b_buffer = NULL;
2896 static int b_size = BUFF_SIZE;
plougher1f413c82005-11-18 00:02:14 +00002897 char *result;
2898
Phillip Lougher3f81a772012-12-04 05:07:24 +00002899 if(b_buffer == NULL) {
2900 b_buffer = malloc(b_size);
2901 if(b_buffer == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002902 MEM_ERROR();
Phillip Lougher3f81a772012-12-04 05:07:24 +00002903 }
2904
2905 while(1) {
2906 if(*pathname != '/') {
2907 result = getcwd(b_buffer, b_size);
2908 if(result == NULL && errno != ERANGE)
2909 BAD_ERROR("Getcwd failed in getbase\n");
2910
2911 /* enough room for pathname + "/" + '\0' terminator? */
2912 if(result && strlen(pathname) + 2 <=
2913 b_size - strlen(b_buffer)) {
2914 strcat(strcat(b_buffer, "/"), pathname);
2915 break;
2916 }
2917 } else if(strlen(pathname) < b_size) {
2918 strcpy(b_buffer, pathname);
2919 break;
2920 }
2921
2922 /* Buffer not large enough, realloc and try again */
2923 b_buffer = realloc(b_buffer, b_size += BUFF_SIZE);
2924 if(b_buffer == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002925 MEM_ERROR();
Phillip Lougher3f81a772012-12-04 05:07:24 +00002926 }
2927
plougher1f413c82005-11-18 00:02:14 +00002928 name = b_buffer;
2929 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
2930 return NULL;
2931 else
2932 return result;
2933}
2934
2935
2936char *basename_r()
2937{
2938 char *s;
2939 char *p;
2940 int n = 1;
2941
2942 for(;;) {
2943 s = name;
2944 if(*name == '\0')
2945 return NULL;
2946 if(*name != '/') {
2947 while(*name != '\0' && *name != '/') name++;
2948 n = name - s;
2949 }
2950 while(*name == '/') name++;
2951 if(strncmp(s, ".", n) == 0)
2952 continue;
plougher110799c2009-03-30 01:50:40 +00002953 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
2954 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00002955 s[n] = '\0';
2956 return s;
2957 }
2958 if(strcmp(p, "..") == 0)
2959 continue;
2960 return p;
2961 }
2962}
2963
2964
Phillip Lougher81204c22012-07-25 03:30:30 +01002965struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
plougher1f413c82005-11-18 00:02:14 +00002966{
Phillip Lougherd6577802012-10-04 19:14:33 +01002967 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
2968 struct inode_info *inode;
plougher1f413c82005-11-18 00:02:14 +00002969
Phillip Lougherd6577802012-10-04 19:14:33 +01002970 /*
2971 * Look-up inode in hash table, if it already exists we have a
2972 * hard-link, so increment the nlink count and return it.
2973 * Don't do the look-up for directories because we don't hard-link
2974 * directories.
2975 */
2976 if ((buf->st_mode & S_IFMT) != S_IFDIR) {
2977 for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
2978 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
2979 inode->nlink ++;
2980 return inode;
2981 }
plougher1f413c82005-11-18 00:02:14 +00002982 }
plougher1f413c82005-11-18 00:02:14 +00002983 }
2984
plougher288f6852010-12-16 05:22:55 +00002985 inode = malloc(sizeof(struct inode_info));
2986 if(inode == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002987 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00002988
2989 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00002990 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00002991 inode->root_entry = FALSE;
Phillip Lougher81204c22012-07-25 03:30:30 +01002992 inode->pseudo_file = pseudo;
2993 inode->pseudo_id = id;
plougher1f413c82005-11-18 00:02:14 +00002994 inode->inode = SQUASHFS_INVALID_BLK;
2995 inode->nlink = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01002996 inode->inode_number = 0;
plougherdc86c3c2007-12-05 02:15:10 +00002997
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002998 /*
2999 * Copy filesystem wide defaults into inode, these filesystem
3000 * wide defaults may be altered on an individual inode basis by
3001 * user specified actions
3002 *
3003 */
3004 inode->no_fragments = no_fragments;
3005 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003006 inode->noD = noD;
3007 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003008
plougherdc86c3c2007-12-05 02:15:10 +00003009 if((buf->st_mode & S_IFMT) == S_IFREG)
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003010 progress_bar_size((buf->st_size + block_size - 1) >> block_log);
plougherdc86c3c2007-12-05 02:15:10 +00003011
Phillip Lougherd6577802012-10-04 19:14:33 +01003012 inode->next = inode_info[ino_hash];
3013 inode_info[ino_hash] = inode;
plougher1f413c82005-11-18 00:02:14 +00003014
3015 return inode;
3016}
3017
3018
Phillip Lougher81204c22012-07-25 03:30:30 +01003019inline struct inode_info *lookup_inode(struct stat *buf)
3020{
3021 return lookup_inode2(buf, 0, 0);
3022}
3023
3024
Phillip Lougher539c2b12012-07-30 20:14:52 +01003025inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3026{
3027 if (inode->inode_number == 0)
3028 inode->inode_number = use_this ? : inode_no ++;
3029}
3030
3031
Phillip Lougher494479f2012-02-03 15:45:41 +00003032inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3033 char *nonstandard_pathname, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003034{
Phillip Lougher494479f2012-02-03 15:45:41 +00003035 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3036 if(dir_ent == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003037 MEM_ERROR();
Phillip Lougher494479f2012-02-03 15:45:41 +00003038
3039 dir_ent->name = name;
3040 dir_ent->source_name = source_name;
3041 dir_ent->nonstandard_pathname = nonstandard_pathname;
3042 dir_ent->our_dir = dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003043 dir_ent->next = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003044
3045 return dir_ent;
3046}
3047
3048
3049inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3050 struct inode_info *inode_info)
3051{
3052 struct dir_info *dir = dir_ent->our_dir;
3053
plougher1f413c82005-11-18 00:02:14 +00003054 if(sub_dir)
Phillip Lougher494479f2012-02-03 15:45:41 +00003055 sub_dir->dir_ent = dir_ent;
3056 dir_ent->inode = inode_info;
3057 dir_ent->dir = sub_dir;
3058
Phillip Lougherbf338362012-08-22 05:24:36 +01003059 dir_ent->next = dir->list;
3060 dir->list = dir_ent;
3061 dir->count++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003062}
3063
3064
3065inline void add_dir_entry2(char *name, char *source_name,
3066 char *nonstandard_pathname, struct dir_info *sub_dir,
3067 struct inode_info *inode_info, struct dir_info *dir)
3068{
3069 struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3070 nonstandard_pathname, dir);
3071
3072
3073 add_dir_entry(dir_ent, sub_dir, inode_info);
plougher1f413c82005-11-18 00:02:14 +00003074}
3075
3076
Phillip Lougher10a4b572012-02-18 23:26:10 +00003077inline void free_dir_entry(struct dir_ent *dir_ent)
3078{
Phillip Loughereb92b192012-10-01 03:39:00 +01003079 if(dir_ent->name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003080 free(dir_ent->name);
3081
Phillip Loughereb92b192012-10-01 03:39:00 +01003082 if(dir_ent->source_name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003083 free(dir_ent->source_name);
3084
3085 free(dir_ent);
3086}
3087
3088
Phillip Lougherad0f9212011-12-31 00:55:51 +00003089inline void add_excluded(struct dir_info *dir)
3090{
3091 dir->excluded ++;
3092}
3093
3094
Phillip Lougherabc3b492012-07-29 02:53:35 +01003095void dir_scan(squashfs_inode *inode, char *pathname,
Phillip Lougherbae0e422014-01-19 23:42:11 +00003096 struct dir_ent *(_readdir)(struct dir_info *), int progress)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003097{
3098 struct stat buf;
3099 struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
3100 struct dir_ent *dir_ent;
3101
3102 if(dir_info == NULL)
3103 return;
3104
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003105 /*
3106 * Process most actions and any pseudo files
3107 */
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00003108 if(actions() || get_pseudo())
3109 dir_scan2(dir_info, get_pseudo());
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003110
Phillip Loughere92cb512012-11-15 02:22:28 +00003111 /*
3112 * Process move actions
3113 */
3114 if(move_actions()) {
3115 dir_scan3(dir_info, dir_info);
3116 do_move_actions();
3117 }
3118
Phillip Lougher71ae14e2012-11-15 02:27:50 +00003119 /*
3120 * Process empty actions
3121 */
3122 if(empty_actions())
3123 dir_scan4(dir_info);
3124
Phillip Loughereb69dad2012-11-15 03:34:02 +00003125 /*
3126 * Sort directories and compute the inode numbers
3127 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003128 dir_scan5(dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003129
Phillip Lougherd0fe1d52012-10-09 03:34:34 +01003130 dir_ent = create_dir_entry("", NULL, pathname,
Phillip Lougher1eae83d2012-09-26 02:12:45 +01003131 scan1_opendir("", "", 0));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003132
3133 if(pathname[0] == '\0') {
3134 /*
3135 * dummy top level directory, if multiple sources specified on
3136 * command line
3137 */
3138 memset(&buf, 0, sizeof(buf));
3139 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3140 buf.st_uid = getuid();
3141 buf.st_gid = getgid();
3142 buf.st_mtime = time(NULL);
3143 buf.st_dev = 0;
3144 buf.st_ino = 0;
3145 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3146 } else {
Phillip Lougher38a35ec2012-11-30 04:31:35 +00003147 if(lstat(pathname, &buf) == -1)
3148 /* source directory has disappeared? */
Phillip Lougherfe58b492012-12-15 01:27:07 +00003149 BAD_ERROR("Cannot stat source directory %s because %s\n",
Phillip Lougherabc3b492012-07-29 02:53:35 +01003150 pathname, strerror(errno));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003151 dir_ent->inode = lookup_inode(&buf);
3152 }
3153
Phillip Lougher539c2b12012-07-30 20:14:52 +01003154 alloc_inode_no(dir_ent->inode, root_inode_number);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003155 dir_ent->dir = dir_info;
3156 dir_info->dir_ent = dir_ent;
3157
Andy Lutomirski3f31dcf2012-09-21 18:08:08 -07003158 eval_actions(dir_ent);
3159
Phillip Lougher19b877d2013-02-23 11:15:38 +00003160 if(sorted)
3161 generate_file_priorities(dir_info, 0,
Phillip Lougherabc3b492012-07-29 02:53:35 +01003162 &dir_info->dir_ent->inode->buf);
Phillip Lougher3794e342014-04-10 02:15:45 +01003163
3164 if(appending) {
3165 sigset_t sigmask;
3166
3167 restore_thread = init_restore_thread();
3168 sigemptyset(&sigmask);
3169 sigaddset(&sigmask, SIGINT);
3170 sigaddset(&sigmask, SIGTERM);
3171 sigaddset(&sigmask, SIGUSR1);
3172 if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
3173 BAD_ERROR("Failed to set signal mask\n");
3174 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
3175 }
3176
Phillip Lougherabc3b492012-07-29 02:53:35 +01003177 queue_put(to_reader, dir_info);
Phillip Lougher3794e342014-04-10 02:15:45 +01003178
Phillip Lougherabc3b492012-07-29 02:53:35 +01003179 if(sorted)
3180 sort_files_and_write(dir_info);
Phillip Lougher3794e342014-04-10 02:15:45 +01003181
Phillip Lougherbae0e422014-01-19 23:42:11 +00003182 set_progressbar_state(progress);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003183 dir_scan6(inode, dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003184 dir_ent->inode->inode = *inode;
3185 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003186}
3187
3188
Phillip Lougherabc3b492012-07-29 02:53:35 +01003189/*
3190 * dir_scan1 routines...
Phillip Loughere8630be2012-11-11 02:24:24 +00003191 * These scan the source directories into memory for processing.
3192 * Exclude actions are processed here (in contrast to the other actions)
3193 * because they affect what is scanned.
Phillip Lougherabc3b492012-07-29 02:53:35 +01003194 */
Phillip Lougherb38c1722012-02-09 23:26:19 +00003195struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
plougher1f413c82005-11-18 00:02:14 +00003196{
plougher1f413c82005-11-18 00:02:14 +00003197 struct dir_info *dir;
3198
plougher6da792b2010-12-16 05:25:39 +00003199 dir = malloc(sizeof(struct dir_info));
3200 if(dir == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003201 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00003202
Phillip Lougher04ef2442013-01-09 06:03:50 +00003203 if(pathname[0] != '\0') {
3204 dir->linuxdir = opendir(pathname);
3205 if(dir->linuxdir == NULL) {
3206 free(dir);
3207 return NULL;
3208 }
plougher1f413c82005-11-18 00:02:14 +00003209 }
Phillip Lougher04ef2442013-01-09 06:03:50 +00003210
Phillip Lougher3cb5d6c2013-01-09 05:50:29 +00003211 dir->pathname = strdup(pathname);
3212 dir->subpath = strdup(subpath);
Phillip Lougherded70fa2011-12-25 02:14:58 +00003213 dir->count = 0;
3214 dir->directory_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003215 dir->dir_is_ldir = TRUE;
3216 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003217 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003218 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003219
3220 return dir;
3221}
3222
3223
Phillip Lougher494479f2012-02-03 15:45:41 +00003224struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003225{
plougher1f413c82005-11-18 00:02:14 +00003226 static int index = 0;
3227
plougher11266ba2010-12-16 05:34:30 +00003228 if(dir->count < old_root_entries) {
3229 int i;
3230
plougher1f413c82005-11-18 00:02:14 +00003231 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003232 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003233 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003234 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003235 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003236 }
plougher11266ba2010-12-16 05:34:30 +00003237 }
plougher1f413c82005-11-18 00:02:14 +00003238
3239 while(index < source) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003240 char *basename = NULL;
3241 char *dir_name = getbase(source_path[index]);
Phillip Lougherbf338362012-08-22 05:24:36 +01003242 int pass = 1, res;
plougher89fe2c72010-12-16 05:31:34 +00003243
Phillip Lougherc73ed322012-10-01 03:25:41 +01003244 if(dir_name == NULL) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003245 ERROR_START("Bad source directory %s",
plougher110799c2009-03-30 01:50:40 +00003246 source_path[index]);
Phillip Lougher85776df2014-01-31 03:10:46 +00003247 ERROR_EXIT(" - skipping ...\n");
plougher1f413c82005-11-18 00:02:14 +00003248 index ++;
3249 continue;
3250 }
Phillip Lougherc73ed322012-10-01 03:25:41 +01003251 dir_name = strdup(dir_name);
plougher1f413c82005-11-18 00:02:14 +00003252 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003253 struct dir_ent *dir_ent = dir->list;
3254
3255 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3256 dir_ent = dir_ent->next);
3257 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003258 break;
plougher50b31762009-03-31 04:14:46 +00003259 ERROR("Source directory entry %s already used! - trying"
3260 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003261 if(pass == 1)
3262 basename = dir_name;
3263 else
Phillip Lougherb38c1722012-02-09 23:26:19 +00003264 free(dir_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003265 res = asprintf(&dir_name, "%s_%d", basename, pass++);
3266 if(res == -1)
3267 BAD_ERROR("asprintf failed in "
3268 "scan1_encomp_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003269 ERROR("%s\n", dir_name);
3270 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00003271 return create_dir_entry(dir_name, basename,
3272 source_path[index ++], dir);
plougher1f413c82005-11-18 00:02:14 +00003273 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003274 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003275}
3276
3277
Phillip Lougher494479f2012-02-03 15:45:41 +00003278struct dir_ent *scan1_single_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003279{
3280 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003281 int i;
plougher1f413c82005-11-18 00:02:14 +00003282
plougher4925e172010-12-16 05:45:54 +00003283 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003284 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003285 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003286 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003287 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003288 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003289 }
plougher4925e172010-12-16 05:45:54 +00003290 }
plougher1f413c82005-11-18 00:02:14 +00003291
3292 if((d_name = readdir(dir->linuxdir)) != NULL) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003293 char *basename = NULL;
3294 char *dir_name = strdup(d_name->d_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003295 int pass = 1, res;
plougher4925e172010-12-16 05:45:54 +00003296
plougher1f413c82005-11-18 00:02:14 +00003297 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003298 struct dir_ent *dir_ent = dir->list;
3299
3300 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3301 dir_ent = dir_ent->next);
3302 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003303 break;
plougher50b31762009-03-31 04:14:46 +00003304 ERROR("Source directory entry %s already used! - trying"
3305 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003306 if (pass == 1)
3307 basename = dir_name;
3308 else
Phillip Lougher494479f2012-02-03 15:45:41 +00003309 free(dir_name);
3310 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3311 if(res == -1)
3312 BAD_ERROR("asprintf failed in "
3313 "scan1_single_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003314 ERROR("%s\n", dir_name);
3315 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003316 return create_dir_entry(dir_name, basename, NULL, dir);
plougher1f413c82005-11-18 00:02:14 +00003317 }
3318
Phillip Lougher494479f2012-02-03 15:45:41 +00003319 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003320}
3321
3322
Phillip Lougher494479f2012-02-03 15:45:41 +00003323struct dir_ent *scan1_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003324{
plougher480d9bf2010-12-18 02:28:39 +00003325 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003326
Phillip Lougher494479f2012-02-03 15:45:41 +00003327 return d_name ?
3328 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3329 NULL;
plougher1f413c82005-11-18 00:02:14 +00003330}
3331
3332
plougher1f413c82005-11-18 00:02:14 +00003333void scan1_freedir(struct dir_info *dir)
3334{
plougherfbed12b2006-02-07 12:45:53 +00003335 if(dir->pathname[0] != '\0')
3336 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003337}
3338
3339
Phillip Lougherb38c1722012-02-09 23:26:19 +00003340struct dir_info *dir_scan1(char *filename, char *subpath,
3341 struct pathnames *paths,
Phillip Lougher494479f2012-02-03 15:45:41 +00003342 struct dir_ent *(_readdir)(struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003343{
Phillip Lougherb38c1722012-02-09 23:26:19 +00003344 struct dir_info *dir = scan1_opendir(filename, subpath, depth);
Phillip Lougher494479f2012-02-03 15:45:41 +00003345 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003346
plougher360b6e42010-12-18 02:40:28 +00003347 if(dir == NULL) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003348 ERROR_START("Could not open %s", filename);
3349 ERROR_EXIT(", skipping...\n");
Phillip Lougher87db5672013-01-09 05:40:46 +00003350 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003351 }
3352
Phillip Lougher494479f2012-02-03 15:45:41 +00003353 while((dir_ent = _readdir(dir))) {
plougher360b6e42010-12-18 02:40:28 +00003354 struct dir_info *sub_dir;
3355 struct stat buf;
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00003356 struct pathnames *new = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003357 char *filename = pathname(dir_ent);
Phillip Lougher651d68d2013-01-13 05:38:13 +00003358 char *subpath = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003359 char *dir_name = dir_ent->name;
plougher1f413c82005-11-18 00:02:14 +00003360
Phillip Lougher494479f2012-02-03 15:45:41 +00003361 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003362 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003363 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003364 }
plougher1f413c82005-11-18 00:02:14 +00003365
3366 if(lstat(filename, &buf) == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003367 ERROR_START("Cannot stat dir/file %s because %s",
plougher110799c2009-03-30 01:50:40 +00003368 filename, strerror(errno));
Phillip Lougher85776df2014-01-31 03:10:46 +00003369 ERROR_EXIT(", ignoring\n");
Phillip Lougher10a4b572012-02-18 23:26:10 +00003370 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003371 continue;
3372 }
plougher29e37092007-04-15 01:24:51 +00003373
3374 if((buf.st_mode & S_IFMT) != S_IFREG &&
Phillip Loughere4ff36a2012-11-19 01:34:47 +00003375 (buf.st_mode & S_IFMT) != S_IFDIR &&
3376 (buf.st_mode & S_IFMT) != S_IFLNK &&
3377 (buf.st_mode & S_IFMT) != S_IFCHR &&
3378 (buf.st_mode & S_IFMT) != S_IFBLK &&
3379 (buf.st_mode & S_IFMT) != S_IFIFO &&
3380 (buf.st_mode & S_IFMT) != S_IFSOCK) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003381 ERROR_START("File %s has unrecognised filetype %d",
3382 filename, buf.st_mode & S_IFMT);
3383 ERROR_EXIT(", ignoring\n");
Phillip Lougher10a4b572012-02-18 23:26:10 +00003384 free_dir_entry(dir_ent);
plougher29e37092007-04-15 01:24:51 +00003385 continue;
3386 }
3387
Phillip Lougherad0f9212011-12-31 00:55:51 +00003388 if((old_exclude && old_excluded(filename, &buf)) ||
Phillip Lougher651d68d2013-01-13 05:38:13 +00003389 (!old_exclude && excluded(dir_name, paths, &new))) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003390 add_excluded(dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003391 free_dir_entry(dir_ent);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003392 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003393 }
plougher1f413c82005-11-18 00:02:14 +00003394
Phillip Lougher651d68d2013-01-13 05:38:13 +00003395 if(exclude_actions()) {
3396 subpath = subpathname(dir_ent);
3397
3398 if(eval_exclude_actions(dir_name, filename, subpath,
Phillip Lougheraa83ecb2014-07-12 02:47:15 +01003399 &buf, depth, dir_ent)) {
Phillip Lougher651d68d2013-01-13 05:38:13 +00003400 add_excluded(dir);
3401 free_dir_entry(dir_ent);
3402 continue;
3403 }
3404 }
3405
plougher1f413c82005-11-18 00:02:14 +00003406 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher651d68d2013-01-13 05:38:13 +00003407 if(subpath == NULL)
3408 subpath = subpathname(dir_ent);
3409
Phillip Lougherb38c1722012-02-09 23:26:19 +00003410 sub_dir = dir_scan1(filename, subpath, new,
3411 scan1_readdir, depth + 1);
Phillip Lougher494479f2012-02-03 15:45:41 +00003412 if(sub_dir == NULL) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003413 free_dir_entry(dir_ent);
Phillip Lougher205c1e02013-01-07 01:37:56 +00003414 free(new);
plougher1f413c82005-11-18 00:02:14 +00003415 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003416 }
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003417
plougher1f413c82005-11-18 00:02:14 +00003418 dir->directory_count ++;
3419 } else
3420 sub_dir = NULL;
3421
Phillip Lougher494479f2012-02-03 15:45:41 +00003422 add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
Phillip Lougher205c1e02013-01-07 01:37:56 +00003423 free(new);
plougher1f413c82005-11-18 00:02:14 +00003424 }
3425
3426 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003427
plougher1f413c82005-11-18 00:02:14 +00003428 return dir;
3429}
3430
plougher2ea89142008-03-11 01:34:19 +00003431
Phillip Lougherabc3b492012-07-29 02:53:35 +01003432/*
3433 * dir_scan2 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003434 * This processes most actions and any pseudo files
Phillip Lougherabc3b492012-07-29 02:53:35 +01003435 */
Phillip Lougherbf338362012-08-22 05:24:36 +01003436struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003437{
Phillip Lougherbf338362012-08-22 05:24:36 +01003438 if (dir_ent == NULL)
3439 dir_ent = dir->list;
3440 else
3441 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003442
Phillip Lougherbf338362012-08-22 05:24:36 +01003443 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3444
3445 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003446}
3447
3448
3449struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3450{
Phillip Lougherbf338362012-08-22 05:24:36 +01003451 struct dir_ent *dir_ent = dir->list;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003452
Phillip Lougherbf338362012-08-22 05:24:36 +01003453 for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3454 dir_ent = dir_ent->next);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003455
Phillip Lougherbf338362012-08-22 05:24:36 +01003456 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003457}
3458
3459
Phillip Lougher24eeb772012-10-13 01:56:24 +01003460void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
plougher43244f22009-04-05 02:04:51 +00003461{
Phillip Lougherbf338362012-08-22 05:24:36 +01003462 struct dir_ent *dir_ent = NULL;
plougher43244f22009-04-05 02:04:51 +00003463 struct pseudo_entry *pseudo_ent;
3464 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003465 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003466
Phillip Lougherbf338362012-08-22 05:24:36 +01003467 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
plougher43244f22009-04-05 02:04:51 +00003468 struct inode_info *inode_info = dir_ent->inode;
3469 struct stat *buf = &inode_info->buf;
3470 char *name = dir_ent->name;
3471
Phillip Lougher89d757c2011-09-20 00:33:19 +01003472 eval_actions(dir_ent);
3473
plougher43244f22009-04-05 02:04:51 +00003474 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher24eeb772012-10-13 01:56:24 +01003475 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
plougher43244f22009-04-05 02:04:51 +00003476 }
3477
3478 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3479 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003480 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003481 struct stat *buf;
3482 if(dir_ent == NULL) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003483 ERROR_START("Pseudo modify file \"%s\" does "
3484 "not exist in source filesystem.",
plougherb34f9f62009-04-26 02:08:42 +00003485 pseudo_ent->pathname);
Phillip Lougher85776df2014-01-31 03:10:46 +00003486 ERROR_EXIT(" Ignoring.\n");
plougherb34f9f62009-04-26 02:08:42 +00003487 continue;
3488 }
ploughera326c182009-08-29 05:41:45 +00003489 if(dir_ent->inode->root_entry) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003490 ERROR_START("Pseudo modify file \"%s\" is a "
3491 "pre-existing file in the filesystem "
3492 "being appended to. It cannot be "\
3493 "modified.", pseudo_ent->pathname);
3494 ERROR_EXIT(" Ignoring.\n");
plougherb34f9f62009-04-26 02:08:42 +00003495 continue;
3496 }
3497 buf = &dir_ent->inode->buf;
3498 buf->st_mode = (buf->st_mode & S_IFMT) |
3499 pseudo_ent->dev->mode;
3500 buf->st_uid = pseudo_ent->dev->uid;
3501 buf->st_gid = pseudo_ent->dev->gid;
3502 continue;
3503 }
3504
plougher43244f22009-04-05 02:04:51 +00003505 if(dir_ent) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003506 if(dir_ent->inode->root_entry) {
3507 ERROR_START("Pseudo file \"%s\" is a "
3508 "pre-existing file in the filesystem "
3509 "being appended to.",
plougherf0dc2382010-05-01 23:55:06 +00003510 pseudo_ent->pathname);
Phillip Lougher85776df2014-01-31 03:10:46 +00003511 ERROR_EXIT(" Ignoring.\n");
3512 } else {
3513 ERROR_START("Pseudo file \"%s\" exists in "
3514 "source filesystem \"%s\".",
plougherf0dc2382010-05-01 23:55:06 +00003515 pseudo_ent->pathname,
Phillip Lougher494479f2012-02-03 15:45:41 +00003516 pathname(dir_ent));
Phillip Lougher85776df2014-01-31 03:10:46 +00003517 ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to "
3518 "override.\n");
3519 }
plougher43244f22009-04-05 02:04:51 +00003520 continue;
3521 }
3522
plougher43244f22009-04-05 02:04:51 +00003523 memset(&buf, 0, sizeof(buf));
3524 buf.st_mode = pseudo_ent->dev->mode;
3525 buf.st_uid = pseudo_ent->dev->uid;
3526 buf.st_gid = pseudo_ent->dev->gid;
3527 buf.st_rdev = makedev(pseudo_ent->dev->major,
3528 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003529 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003530 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003531
Phillip Lougher5d579292012-10-13 01:37:16 +01003532 if(pseudo_ent->dev->type == 'd') {
3533 struct dir_ent *dir_ent =
3534 create_dir_entry(pseudo_ent->name, NULL,
3535 pseudo_ent->pathname, dir);
3536 char *subpath = strdup(subpathname(dir_ent));
3537 struct dir_info *sub_dir = scan1_opendir("", subpath,
Phillip Lougher24eeb772012-10-13 01:56:24 +01003538 dir->depth + 1);
Phillip Lougher5d579292012-10-13 01:37:16 +01003539 if(sub_dir == NULL) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003540 ERROR_START("Could not create pseudo directory "
3541 "\"%s\"", pseudo_ent->pathname);
3542 ERROR_EXIT(", skipping...\n");
Phillip Lougher5d579292012-10-13 01:37:16 +01003543 free(subpath);
3544 pseudo_ino --;
3545 continue;
3546 }
Phillip Lougher24eeb772012-10-13 01:56:24 +01003547 dir_scan2(sub_dir, pseudo_ent->pseudo);
Phillip Lougher5d579292012-10-13 01:37:16 +01003548 dir->directory_count ++;
3549 add_dir_entry(dir_ent, sub_dir,
3550 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3551 } else if(pseudo_ent->dev->type == 'f') {
Phillip Lougher494479f2012-02-03 15:45:41 +00003552 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003553 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003554 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3555 pseudo_ent->dev->pseudo_id), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003556 } else {
Phillip Lougher494479f2012-02-03 15:45:41 +00003557 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003558 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003559 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003560 }
plougher43244f22009-04-05 02:04:51 +00003561 }
plougher43244f22009-04-05 02:04:51 +00003562}
3563
3564
Phillip Lougherabc3b492012-07-29 02:53:35 +01003565/*
3566 * dir_scan3 routines...
Phillip Lougher23d83622012-10-14 02:35:22 +01003567 * This processes the move action
3568 */
3569void dir_scan3(struct dir_info *root, struct dir_info *dir)
3570{
3571 struct dir_ent *dir_ent = NULL;
3572
3573 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3574
3575 eval_move_actions(root, dir_ent);
3576
3577 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3578 dir_scan3(root, dir_ent->dir);
3579 }
3580}
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003581
3582
Phillip Lougher23d83622012-10-14 02:35:22 +01003583/*
3584 * dir_scan4 routines...
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003585 * This processes the empty action. This action has to be processed after
3586 * all other actions because the previous exclude and move actions and the
3587 * pseudo actions affect whether a directory is empty
3588 */
3589void dir_scan4(struct dir_info *dir)
3590{
3591 struct dir_ent *dir_ent = dir->list, *prev = NULL;
3592
3593 while(dir_ent) {
Phillip Lougher15e8f042012-11-16 00:57:39 +00003594 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3595 dir_scan4(dir_ent->dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003596
Phillip Lougher15e8f042012-11-16 00:57:39 +00003597 if(eval_empty_actions(dir_ent)) {
3598 struct dir_ent *tmp = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003599
Phillip Lougher15e8f042012-11-16 00:57:39 +00003600 /*
3601 * delete sub-directory, this is by definition
3602 * empty
3603 */
3604 free(dir_ent->dir->pathname);
3605 free(dir_ent->dir->subpath);
3606 free(dir_ent->dir);
3607
3608 /* remove dir_ent from list */
3609 dir_ent = dir_ent->next;
3610 if(prev)
3611 prev->next = dir_ent;
3612 else
3613 dir->list = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003614
Phillip Lougher15e8f042012-11-16 00:57:39 +00003615 /* free it */
3616 free_dir_entry(tmp);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003617
Phillip Lougher15e8f042012-11-16 00:57:39 +00003618 /* update counts */
3619 dir->directory_count --;
3620 dir->count --;
3621 add_excluded(dir);
3622 continue;
3623 }
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003624 }
Phillip Lougher15e8f042012-11-16 00:57:39 +00003625
3626 prev = dir_ent;
3627 dir_ent = dir_ent->next;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003628 }
3629}
3630
3631
3632/*
3633 * dir_scan5 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003634 * This sorts every directory and computes the inode numbers
3635 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003636
Phillip Lougher242242e2012-08-24 04:15:36 +01003637/*
3638 * Bottom up linked list merge sort.
3639 *
3640 * Qsort and other O(n log n) algorithms work well with arrays but not
3641 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand
3642 * is not ideal for arrays (as it needs an additonal n storage locations
3643 * as sorting is not done in place), but it is ideal for linked lists because
3644 * it doesn't require any extra storage,
3645 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003646void sort_directory(struct dir_info *dir)
3647{
Phillip Lougher242242e2012-08-24 04:15:36 +01003648 struct dir_ent *cur, *l1, *l2, *next;
3649 int len1, len2, stride = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003650
Phillip Lougherd3459a82014-04-18 01:37:54 +01003651 if(dir->list == NULL || dir->count < 2)
Phillip Lougherbf338362012-08-22 05:24:36 +01003652 return;
3653
Phillip Lougher242242e2012-08-24 04:15:36 +01003654 /*
3655 * We can consider our linked-list to be made up of stride length
3656 * sublists. Eacn iteration around this loop merges adjacent
3657 * stride length sublists into larger 2*stride sublists. We stop
3658 * when stride becomes equal to the entire list.
3659 *
3660 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
3661 * these 1 element sublists are merged into 2 element sublists, which
3662 * are then merged into 4 element sublists and so on.
3663 */
3664 do {
3665 l2 = dir->list; /* head of current linked list */
3666 cur = NULL; /* empty output list */
Phillip Lougherbf338362012-08-22 05:24:36 +01003667
Phillip Lougher242242e2012-08-24 04:15:36 +01003668 /*
3669 * Iterate through the linked list, merging adjacent sublists.
3670 * On each interation l2 points to the next sublist pair to be
3671 * merged (if there's only one sublist left this is simply added
3672 * to the output list)
3673 */
3674 while(l2) {
3675 l1 = l2;
3676 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
3677 len2 = stride;
Phillip Lougherbf338362012-08-22 05:24:36 +01003678
Phillip Lougher242242e2012-08-24 04:15:36 +01003679 /*
3680 * l1 points to first sublist.
3681 * l2 points to second sublist.
3682 * Merge them onto the output list
3683 */
3684 while(len1 && l2 && len2) {
3685 if(strcmp(l1->name, l2->name) <= 0) {
3686 next = l1;
3687 l1 = l1->next;
3688 len1 --;
3689 } else {
3690 next = l2;
3691 l2 = l2->next;
3692 len2 --;
3693 }
3694
3695 if(cur) {
3696 cur->next = next;
3697 cur = next;
3698 } else
3699 dir->list = cur = next;
3700 }
3701 /*
3702 * One sublist is now empty, copy the other one onto the
3703 * output list
3704 */
3705 for(; len1; len1 --, l1 = l1->next) {
3706 if(cur) {
3707 cur->next = l1;
3708 cur = l1;
3709 } else
3710 dir->list = cur = l1;
3711 }
3712 for(; l2 && len2; len2 --, l2 = l2->next) {
3713 if(cur) {
3714 cur->next = l2;
3715 cur = l2;
3716 } else
3717 dir->list = cur = l2;
3718 }
3719 }
3720 cur->next = NULL;
3721 stride = stride << 1;
3722 } while(stride < dir->count);
Phillip Lougher539c2b12012-07-30 20:14:52 +01003723}
3724
3725
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003726void dir_scan5(struct dir_info *dir)
Phillip Lougher539c2b12012-07-30 20:14:52 +01003727{
Phillip Lougher23d83622012-10-14 02:35:22 +01003728 struct dir_ent *dir_ent;
3729 unsigned int byte_count = 0;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003730
3731 sort_directory(dir);
3732
Phillip Lougher23d83622012-10-14 02:35:22 +01003733 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
3734 byte_count += strlen(dir_ent->name) +
3735 sizeof(struct squashfs_dir_entry);
3736
3737 if(dir_ent->inode->root_entry)
3738 continue;
3739
Phillip Lougher539c2b12012-07-30 20:14:52 +01003740 alloc_inode_no(dir_ent->inode, 0);
Phillip Lougher23d83622012-10-14 02:35:22 +01003741
Phillip Lougher539c2b12012-07-30 20:14:52 +01003742 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
Phillip Loughere69b5882012-11-19 01:31:09 +00003743 dir_scan5(dir_ent->dir);
Phillip Lougher539c2b12012-07-30 20:14:52 +01003744 }
Phillip Lougher23d83622012-10-14 02:35:22 +01003745
3746 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
3747 dir->dir_is_ldir = FALSE;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003748}
3749
3750
3751/*
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003752 * dir_scan6 routines...
Phillip Lougherabc3b492012-07-29 02:53:35 +01003753 * This generates the filesystem metadata and writes it out to the destination
3754 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003755void scan6_init_dir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003756{
3757 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003758 if(dir->buff == NULL)
3759 MEM_ERROR();
Phillip Lougherabc3b492012-07-29 02:53:35 +01003760
3761 dir->size = SQUASHFS_METADATA_SIZE;
3762 dir->p = dir->index_count_p = dir->buff;
3763 dir->entry_count = 256;
3764 dir->entry_count_p = NULL;
3765 dir->index = NULL;
3766 dir->i_count = dir->i_size = 0;
3767}
3768
3769
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003770struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
Phillip Lougherbf338362012-08-22 05:24:36 +01003771 struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003772{
Phillip Lougherbf338362012-08-22 05:24:36 +01003773 if (dir_ent == NULL)
3774 dir_ent = dir_info->list;
3775 else
3776 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003777
Phillip Lougherbf338362012-08-22 05:24:36 +01003778 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
3779 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
3780 dir_ent->name, dir_ent->inode->type, dir);
3781
3782 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003783}
3784
3785
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003786void scan6_freedir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003787{
3788 if(dir->index)
3789 free(dir->index);
3790 free(dir->buff);
3791}
3792
3793
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003794void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003795{
3796 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00003797 int duplicate_file;
plougher1f413c82005-11-18 00:02:14 +00003798 struct directory dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003799 struct dir_ent *dir_ent = NULL;
plougher1f413c82005-11-18 00:02:14 +00003800
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003801 scan6_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003802
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003803 while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
Phillip Lougher0a670882012-10-05 04:09:13 +01003804 struct stat *buf = &dir_ent->inode->buf;
plougher1f413c82005-11-18 00:02:14 +00003805
Phillip Lougher24551a82013-03-24 02:30:50 +00003806 update_info(dir_ent);
3807
plougher1f413c82005-11-18 00:02:14 +00003808 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3809 switch(buf->st_mode & S_IFMT) {
3810 case S_IFREG:
3811 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00003812 write_file(inode, dir_ent,
3813 &duplicate_file);
3814 INFO("file %s, uncompressed size %lld "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003815 "bytes %s\n",
3816 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00003817 (long long) buf->st_size,
3818 duplicate_file ? "DUPLICATE" :
3819 "");
plougher1f413c82005-11-18 00:02:14 +00003820 break;
3821
3822 case S_IFDIR:
3823 squashfs_type = SQUASHFS_DIR_TYPE;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003824 dir_scan6(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003825 break;
3826
3827 case S_IFLNK:
3828 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003829 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003830 squashfs_type, 0, 0, 0, NULL,
3831 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003832 INFO("symbolic link %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003833 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00003834 sym_count ++;
3835 break;
3836
3837 case S_IFCHR:
3838 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003839 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003840 squashfs_type, 0, 0, 0, NULL,
3841 NULL, NULL, 0);
3842 INFO("character device %s inode 0x%llx"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003843 "\n", subpathname(dir_ent),
3844 *inode);
plougher1f413c82005-11-18 00:02:14 +00003845 dev_count ++;
3846 break;
3847
3848 case S_IFBLK:
3849 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003850 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003851 squashfs_type, 0, 0, 0, NULL,
3852 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003853 INFO("block device %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003854 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00003855 dev_count ++;
3856 break;
3857
3858 case S_IFIFO:
3859 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003860 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003861 squashfs_type, 0, 0, 0, NULL,
3862 NULL, NULL, 0);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003863 INFO("fifo %s inode 0x%llx\n",
3864 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00003865 fifo_count ++;
3866 break;
3867
3868 case S_IFSOCK:
3869 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00003870 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00003871 squashfs_type, 0, 0, 0, NULL,
3872 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00003873 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003874 "0x%llx\n",
3875 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00003876 sock_count ++;
3877 break;
3878
plougher23377982007-11-12 04:04:48 +00003879 default:
plougherb3604122009-03-30 02:07:20 +00003880 BAD_ERROR("%s unrecognised file type, "
Phillip Lougher494479f2012-02-03 15:45:41 +00003881 "mode is %x\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003882 subpathname(dir_ent),
plougherb3604122009-03-30 02:07:20 +00003883 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00003884 }
3885 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00003886 dir_ent->inode->type = squashfs_type;
3887 } else {
3888 *inode = dir_ent->inode->inode;
3889 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00003890 switch(squashfs_type) {
3891 case SQUASHFS_FILE_TYPE:
3892 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00003893 INFO("file %s, uncompressed "
3894 "size %lld bytes LINK"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003895 "\n",
3896 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00003897 (long long)
plougher50b31762009-03-31 04:14:46 +00003898 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00003899 break;
3900 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00003901 INFO("symbolic link %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003902 "LINK\n", subpathname(dir_ent),
3903 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003904 break;
3905 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003906 INFO("character device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003907 "LINK\n", subpathname(dir_ent),
3908 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003909 break;
plougher5507dd92006-11-06 00:43:10 +00003910 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00003911 INFO("block device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003912 "LINK\n", subpathname(dir_ent),
3913 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003914 break;
3915 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00003916 INFO("fifo %s inode 0x%llx LINK\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003917 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003918 break;
3919 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00003920 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003921 "0x%llx LINK\n",
3922 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00003923 break;
3924 }
plougher1f413c82005-11-18 00:02:14 +00003925 }
3926
Phillip Lougher0366aec2012-10-05 04:06:04 +01003927 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
3928 squashfs_type, &dir);
plougher1f413c82005-11-18 00:02:14 +00003929 }
3930
plougher29e37092007-04-15 01:24:51 +00003931 write_dir(inode, dir_info, &dir);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003932 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
3933 *inode);
plougher1f413c82005-11-18 00:02:14 +00003934
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003935 scan6_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003936}
3937
3938
3939unsigned int slog(unsigned int block)
3940{
3941 int i;
3942
plougher4c99cb72007-06-14 21:46:31 +00003943 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00003944 if(block == (1 << i))
3945 return i;
3946 return 0;
3947}
3948
3949
plougher8f8e1a12007-10-18 02:50:21 +00003950int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00003951{
3952 int i;
3953
3954 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00003955 if((exclude_paths[i].st_dev == buf->st_dev) &&
3956 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00003957 return TRUE;
3958 return FALSE;
3959}
3960
3961
3962#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00003963 if(exclude % EXCLUDE_SIZE == 0) { \
3964 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
3965 * sizeof(struct exclude_info)); \
3966 if(exclude_paths == NULL) \
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003967 MEM_ERROR(); \
plougher360514a2009-03-30 03:01:38 +00003968 } \
3969 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00003970 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00003971int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00003972{
3973 int i;
Phillip Lougherdcb5af92012-11-30 03:05:31 +00003974 char *filename;
plougher1f413c82005-11-18 00:02:14 +00003975 struct stat buf;
3976
plougherb3604122009-03-30 02:07:20 +00003977 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
3978 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00003979 if(lstat(path, &buf) == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003980 ERROR_START("Cannot stat exclude dir/file %s because "
3981 "%s", path, strerror(errno));
3982 ERROR_EXIT(", ignoring\n");
plougher1f413c82005-11-18 00:02:14 +00003983 return TRUE;
3984 }
3985 ADD_ENTRY(buf);
3986 return TRUE;
3987 }
3988
3989 for(i = 0; i < source; i++) {
Phillip Lougherdcb5af92012-11-30 03:05:31 +00003990 int res = asprintf(&filename, "%s/%s", source_path[i], path);
3991 if(res == -1)
3992 BAD_ERROR("asprintf failed in old_add_exclude\n");
plougher1f413c82005-11-18 00:02:14 +00003993 if(lstat(filename, &buf) == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00003994 if(!(errno == ENOENT || errno == ENOTDIR)) {
3995 ERROR_START("Cannot stat exclude dir/file %s "
3996 "because %s", filename, strerror(errno));
3997 ERROR_EXIT(", ignoring\n");
3998 }
Phillip Lougherdcb5af92012-11-30 03:05:31 +00003999 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004000 continue;
4001 }
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004002 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004003 ADD_ENTRY(buf);
4004 }
4005 return TRUE;
4006}
4007
4008
plougherb3604122009-03-30 02:07:20 +00004009void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4010 int type)
plougher1f413c82005-11-18 00:02:14 +00004011{
plougherb3604122009-03-30 02:07:20 +00004012 old_root_entry = realloc(old_root_entry,
4013 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4014 if(old_root_entry == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004015 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00004016
ploughera326c182009-08-29 05:41:45 +00004017 old_root_entry[old_root_entries].name = strdup(name);
4018 old_root_entry[old_root_entries].inode.inode = inode;
4019 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4020 old_root_entry[old_root_entries].inode.type = type;
4021 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004022}
4023
4024
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004025void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq,
4026 int freelst, char *destination_file)
plougher5507dd92006-11-06 00:43:10 +00004027{
4028 int i;
4029 sigset_t sigmask, old_mask;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004030 int total_mem = readq;
Phillip Loughercf4c7bc2014-04-13 04:48:11 +01004031 int reader_size;
4032 int fragment_size;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004033 int fwriter_size;
plougher5741d792010-09-04 03:20:50 +00004034 /*
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004035 * bwriter_size is global because it is needed in
plougher5741d792010-09-04 03:20:50 +00004036 * write_file_blocks_dup()
4037 */
Phillip Loughere1668fe2012-12-30 05:48:12 +00004038
4039 /*
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004040 * Never allow the total size of the queues to be larger than
4041 * physical memory
4042 *
4043 * When adding together the possibly user supplied values, make
4044 * sure they've not been deliberately contrived to overflow an int
4045 */
4046 if(add_overflow(total_mem, fragq))
4047 BAD_ERROR("Queue sizes rediculously too large\n");
4048 total_mem += fragq;
4049 if(add_overflow(total_mem, bwriteq))
4050 BAD_ERROR("Queue sizes rediculously too large\n");
4051 total_mem += bwriteq;
4052 if(add_overflow(total_mem, fwriteq))
4053 BAD_ERROR("Queue sizes rediculously too large\n");
4054 total_mem += fwriteq;
4055
Phillip Lougher285a2fd2014-06-10 21:51:52 +01004056 check_usable_phys_mem(total_mem);
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004057
4058 /*
Phillip Loughere1668fe2012-12-30 05:48:12 +00004059 * convert from queue size in Mbytes to queue size in
4060 * blocks.
4061 *
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004062 * This isn't going to overflow an int unless there exists
4063 * systems with more than 8 Petabytes of RAM!
Phillip Loughere1668fe2012-12-30 05:48:12 +00004064 */
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004065 reader_size = readq << (20 - block_log);
4066 fragment_size = fragq << (20 - block_log);
4067 bwriter_size = bwriteq << (20 - block_log);
4068 fwriter_size = fwriteq << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004069
Phillip Lougher9391cb12013-03-20 05:16:10 +00004070 /*
4071 * setup signal handlers for the main thread, these cleanup
4072 * deleting the destination file, if appending the
4073 * handlers for SIGTERM and SIGINT will be replaced with handlers
4074 * allowing the user to press ^C twice to restore the existing
4075 * filesystem.
4076 *
Phillip Lougherdd343392013-03-31 23:29:03 +01004077 * SIGUSR1 is an internal signal, which is used by the sub-threads
Phillip Lougher9391cb12013-03-20 05:16:10 +00004078 * to tell the main thread to terminate, deleting the destination file,
4079 * or if necessary restoring the filesystem on appending
4080 */
Phillip Lougherb8ec5202013-03-28 20:14:37 +00004081 signal(SIGTERM, sighandler);
4082 signal(SIGINT, sighandler);
Phillip Lougherdd343392013-03-31 23:29:03 +01004083 signal(SIGUSR1, sighandler);
Phillip Lougher9391cb12013-03-20 05:16:10 +00004084
Phillip Lougher7538d742013-04-22 05:33:27 +01004085 /* block SIGQUIT and SIGHUP, these are handled by the info thread */
Phillip Lougher24551a82013-03-24 02:30:50 +00004086 sigemptyset(&sigmask);
4087 sigaddset(&sigmask, SIGQUIT);
Phillip Lougher7538d742013-04-22 05:33:27 +01004088 sigaddset(&sigmask, SIGHUP);
Phillip Lougherb1259f72013-06-06 03:10:15 +01004089 if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
Phillip Lougher24551a82013-03-24 02:30:50 +00004090 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4091
Phillip Lougher9391cb12013-03-20 05:16:10 +00004092 /*
4093 * temporarily block these signals, so the created sub-threads
4094 * will ignore them, ensuring the main thread handles them
4095 */
plougher5507dd92006-11-06 00:43:10 +00004096 sigemptyset(&sigmask);
4097 sigaddset(&sigmask, SIGINT);
Phillip Lougher9391cb12013-03-20 05:16:10 +00004098 sigaddset(&sigmask, SIGTERM);
Phillip Lougherdd343392013-03-31 23:29:03 +01004099 sigaddset(&sigmask, SIGUSR1);
Phillip Lougher8f8d2752013-03-26 04:38:38 +00004100 if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
plougher5507dd92006-11-06 00:43:10 +00004101 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4102
plougher5507dd92006-11-06 00:43:10 +00004103 if(processors == -1) {
4104#ifndef linux
4105 int mib[2];
4106 size_t len = sizeof(processors);
4107
4108 mib[0] = CTL_HW;
4109#ifdef HW_AVAILCPU
4110 mib[1] = HW_AVAILCPU;
4111#else
4112 mib[1] = HW_NCPU;
4113#endif
4114
4115 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
Phillip Lougher85776df2014-01-31 03:10:46 +00004116 ERROR_START("Failed to get number of available "
4117 "processors.");
4118 ERROR_EXIT(" Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004119 processors = 1;
4120 }
4121#else
plougher9cc26b72010-08-17 01:05:55 +00004122 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004123#endif
4124 }
4125
Phillip Lougher9de84ac2014-02-20 05:18:48 +00004126 if(multiply_overflow(processors, 3) ||
4127 multiply_overflow(processors * 3, sizeof(pthread_t)))
Phillip Loughere1668fe2012-12-30 05:48:12 +00004128 BAD_ERROR("Processors too large\n");
4129
Phillip Lougher9de84ac2014-02-20 05:18:48 +00004130 deflator_thread = malloc(processors * 3 * sizeof(pthread_t));
Phillip Lougher0280d992014-01-27 05:54:07 +00004131 if(deflator_thread == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004132 MEM_ERROR();
Phillip Loughere1668fe2012-12-30 05:48:12 +00004133
plougher5507dd92006-11-06 00:43:10 +00004134 frag_deflator_thread = &deflator_thread[processors];
Phillip Lougher9de84ac2014-02-20 05:18:48 +00004135 frag_thread = &frag_deflator_thread[processors];
plougher5507dd92006-11-06 00:43:10 +00004136
4137 to_reader = queue_init(1);
Phillip Loughercf4c7bc2014-04-13 04:48:11 +01004138 to_deflate = queue_init(reader_size);
4139 to_process_frag = queue_init(reader_size);
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004140 to_writer = queue_init(bwriter_size + fwriter_size);
plougher5507dd92006-11-06 00:43:10 +00004141 from_writer = queue_init(1);
Phillip Loughercf4c7bc2014-04-13 04:48:11 +01004142 to_frag = queue_init(fragment_size);
4143 locked_fragment = queue_init(fragment_size);
Phillip Lougher0e1656d2013-05-20 03:47:24 +01004144 to_main = seq_queue_init();
Phillip Loughercf4c7bc2014-04-13 04:48:11 +01004145 reader_buffer = cache_init(block_size, reader_size, 0, 0);
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004146 bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst);
4147 fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst);
Phillip Lougher1ac37152014-05-10 03:09:28 +01004148 fragment_buffer = cache_init(block_size, fragment_size, 1, 0);
4149 reserve_cache = cache_init(block_size, processors + 1, 1, 0);
Phillip Lougher0280d992014-01-27 05:54:07 +00004150 pthread_create(&reader_thread, NULL, reader, NULL);
4151 pthread_create(&writer_thread, NULL, writer, NULL);
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004152 init_progress_bar();
Phillip Lougher24551a82013-03-24 02:30:50 +00004153 init_info();
plougher5507dd92006-11-06 00:43:10 +00004154
4155 for(i = 0; i < processors; i++) {
Phillip Lougher943acad2014-04-17 03:31:01 +01004156 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL))
plougher5507dd92006-11-06 00:43:10 +00004157 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004158 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4159 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004160 BAD_ERROR("Failed to create thread\n");
Phillip Lougher8bb17b02014-03-30 23:59:55 +01004161 if(pthread_create(&frag_thread[i], NULL, frag_thrd,
4162 (void *) destination_file) != 0)
Phillip Lougher9de84ac2014-02-20 05:18:48 +00004163 BAD_ERROR("Failed to create thread\n");
plougher5507dd92006-11-06 00:43:10 +00004164 }
4165
Phillip Lougher0280d992014-01-27 05:54:07 +00004166 main_thread = pthread_self();
4167
plougher5507dd92006-11-06 00:43:10 +00004168 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4169 processors == 1 ? "" : "s");
4170
Phillip Lougher9391cb12013-03-20 05:16:10 +00004171 /* Restore the signal mask for the main thread */
Phillip Lougher8f8d2752013-03-26 04:38:38 +00004172 if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1)
plougher5507dd92006-11-06 00:43:10 +00004173 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4174}
4175
4176
plougher0e453652006-11-06 01:49:35 +00004177long long write_inode_lookup_table()
4178{
4179 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004180 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004181
4182 if(inode_count == sinode_count)
4183 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004184
plougher44f03282010-07-27 00:31:36 +00004185 it = realloc(inode_lookup_table, lookup_bytes);
4186 if(it == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004187 MEM_ERROR();
plougher44f03282010-07-27 00:31:36 +00004188 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004189
plougher0e453652006-11-06 01:49:35 +00004190 for(i = 0; i < INODE_HASH_SIZE; i ++) {
Phillip Lougherf2f83b62014-04-18 01:30:47 +01004191 struct inode_info *inode;
plougher0e453652006-11-06 01:49:35 +00004192
4193 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004194
Phillip Lougher539c2b12012-07-30 20:14:52 +01004195 inode_number = get_inode_no(inode);
plougher0e453652006-11-06 01:49:35 +00004196
Phillip Lougher9f595962014-07-07 04:37:47 +01004197 /* The empty action will produce orphaned inode
4198 * entries in the inode_info[] table. These
4199 * entries because they are orphaned will not be
4200 * allocated an inode number in dir_scan5(), so
4201 * skip any entries with the default dummy inode
4202 * number of 0 */
4203 if(inode_number == 0)
4204 continue;
4205
plougher360514a2009-03-30 03:01:38 +00004206 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4207 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004208
plougher0e453652006-11-06 01:49:35 +00004209 }
4210 }
4211
plougher02bc3bc2007-02-25 12:12:01 +00004212skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004213 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4214 noI);
plougher0e453652006-11-06 01:49:35 +00004215}
4216
plougher2ea89142008-03-11 01:34:19 +00004217
Phillip Lougher8e44e052012-11-26 02:58:35 +00004218char *get_component(char *target, char **targname)
plougher8f8e1a12007-10-18 02:50:21 +00004219{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004220 char *start;
4221
plougher8f8e1a12007-10-18 02:50:21 +00004222 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004223 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004224
Phillip Lougher8e44e052012-11-26 02:58:35 +00004225 start = target;
Phillip Lougher66d8b8e2014-04-20 21:01:33 +01004226 while(*target != '/' && *target != '\0')
Phillip Lougher8e44e052012-11-26 02:58:35 +00004227 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004228
Phillip Lougher8e44e052012-11-26 02:58:35 +00004229 *targname = strndup(start, target - start);
plougher8f8e1a12007-10-18 02:50:21 +00004230
Phillip Lougher66d8b8e2014-04-20 21:01:33 +01004231 while(*target == '/')
4232 target ++;
4233
plougher8f8e1a12007-10-18 02:50:21 +00004234 return target;
4235}
4236
4237
4238void free_path(struct pathname *paths)
4239{
4240 int i;
4241
4242 for(i = 0; i < paths->names; i++) {
4243 if(paths->name[i].paths)
4244 free_path(paths->name[i].paths);
4245 free(paths->name[i].name);
4246 if(paths->name[i].preg) {
4247 regfree(paths->name[i].preg);
4248 free(paths->name[i].preg);
4249 }
4250 }
4251
4252 free(paths);
4253}
4254
4255
4256struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4257{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004258 char *targname;
plougher8f8e1a12007-10-18 02:50:21 +00004259 int i, error;
4260
Phillip Lougher8e44e052012-11-26 02:58:35 +00004261 target = get_component(target, &targname);
plougher8f8e1a12007-10-18 02:50:21 +00004262
4263 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004264 paths = malloc(sizeof(struct pathname));
4265 if(paths == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004266 MEM_ERROR();
plougher8f8e1a12007-10-18 02:50:21 +00004267
4268 paths->names = 0;
4269 paths->name = NULL;
4270 }
4271
4272 for(i = 0; i < paths->names; i++)
4273 if(strcmp(paths->name[i].name, targname) == 0)
4274 break;
4275
4276 if(i == paths->names) {
4277 /* allocate new name entry */
4278 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004279 paths->name = realloc(paths->name, (i + 1) *
4280 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004281 if(paths->name == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004282 MEM_ERROR();
Phillip Lougher8e44e052012-11-26 02:58:35 +00004283 paths->name[i].name = targname;
plougher8f8e1a12007-10-18 02:50:21 +00004284 paths->name[i].paths = NULL;
4285 if(use_regex) {
4286 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004287 if(paths->name[i].preg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004288 MEM_ERROR();
plougherb3604122009-03-30 02:07:20 +00004289 error = regcomp(paths->name[i].preg, targname,
4290 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004291 if(error) {
Phillip Lougher62859d22012-11-30 05:53:56 +00004292 char str[1024]; /* overflow safe */
plougher8f8e1a12007-10-18 02:50:21 +00004293
4294 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004295 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004296 "because %s\n", targname, alltarget,
4297 str);
plougher8f8e1a12007-10-18 02:50:21 +00004298 }
4299 } else
4300 paths->name[i].preg = NULL;
4301
4302 if(target[0] == '\0')
4303 /* at leaf pathname component */
4304 paths->name[i].paths = NULL;
4305 else
4306 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004307 paths->name[i].paths = add_path(NULL, target,
4308 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004309 } else {
4310 /* existing matching entry */
Phillip Lougher8e44e052012-11-26 02:58:35 +00004311 free(targname);
4312
plougher8f8e1a12007-10-18 02:50:21 +00004313 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004314 /* No sub-directory which means this is the leaf
4315 * component of a pre-existing exclude which subsumes
4316 * the exclude currently being added, in which case stop
4317 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004318 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004319 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004320 * from more specific excludes, delete as they're
4321 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004322 free_path(paths->name[i].paths);
4323 paths->name[i].paths = NULL;
4324 } else
4325 /* recurse adding child components */
4326 add_path(paths->name[i].paths, target, alltarget);
4327 }
4328
4329 return paths;
4330}
plougher2ea89142008-03-11 01:34:19 +00004331
4332
plougher05e50ef2007-10-23 12:34:20 +00004333void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004334{
plougher05e50ef2007-10-23 12:34:20 +00004335
plougherb3604122009-03-30 02:07:20 +00004336 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4337 strncmp(target, "../", 3) == 0)
4338 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4339 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004340 else if(strncmp(target, "... ", 4) == 0)
4341 stickypath = add_path(stickypath, target + 4, target + 4);
4342 else
4343 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004344}
4345
4346
4347void display_path(int depth, struct pathname *paths)
4348{
4349 int i, n;
4350
4351 if(paths == NULL)
4352 return;
4353
4354 for(i = 0; i < paths->names; i++) {
4355 for(n = 0; n < depth; n++)
4356 printf("\t");
4357 printf("%d: %s\n", depth, paths->name[i].name);
4358 display_path(depth + 1, paths->name[i].paths);
4359 }
4360}
4361
4362
4363void display_path2(struct pathname *paths, char *string)
4364{
4365 int i;
Phillip Lougher91459c12012-11-30 05:24:44 +00004366 char *path;
plougher8f8e1a12007-10-18 02:50:21 +00004367
4368 if(paths == NULL) {
4369 printf("%s\n", string);
4370 return;
4371 }
4372
4373 for(i = 0; i < paths->names; i++) {
Phillip Lougher91459c12012-11-30 05:24:44 +00004374 int res = asprintf(&path, "%s/%s", string, paths->name[i].name);
4375 if(res == -1)
4376 BAD_ERROR("asprintf failed in display_path2\n");
plougher8f8e1a12007-10-18 02:50:21 +00004377 display_path2(paths->name[i].paths, path);
Phillip Lougher91459c12012-11-30 05:24:44 +00004378 free(path);
plougher8f8e1a12007-10-18 02:50:21 +00004379 }
4380}
4381
4382
plougherf9039c92007-10-22 03:54:16 +00004383struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4384{
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004385 int count = paths == NULL ? 0 : paths->count;
4386
4387 if(count % PATHS_ALLOC_SIZE == 0) {
4388 paths = realloc(paths, sizeof(struct pathnames) +
4389 (count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004390 if(paths == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004391 MEM_ERROR();
plougher6f2a8262010-07-27 00:37:19 +00004392 }
plougherf9039c92007-10-22 03:54:16 +00004393
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004394 paths->path[count] = path;
4395 paths->count = count + 1;
plougherf9039c92007-10-22 03:54:16 +00004396 return paths;
4397}
4398
4399
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004400int excluded_match(char *name, struct pathname *path, struct pathnames **new)
plougherf9039c92007-10-22 03:54:16 +00004401{
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004402 int i;
plougher8f8e1a12007-10-18 02:50:21 +00004403
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004404 for(i = 0; i < path->names; i++) {
4405 int match = use_regex ?
4406 regexec(path->name[i].preg, name, (size_t) 0,
plougher50b31762009-03-31 04:14:46 +00004407 NULL, 0) == 0 :
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004408 fnmatch(path->name[i].name, name,
4409 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
plougherf9039c92007-10-22 03:54:16 +00004410
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004411 if(match) {
4412 if(path->name[i].paths == NULL || new == NULL)
plougherb3604122009-03-30 02:07:20 +00004413 /* match on a leaf component, any subdirectories
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004414 * in the filesystem should be excluded */
4415 return TRUE;
4416 else
plougherb3604122009-03-30 02:07:20 +00004417 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004418 * subdirectories to the new set of
4419 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004420 *new = add_subdir(*new, path->name[i].paths);
4421 }
4422 }
4423
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004424 return FALSE;
4425}
4426
4427
4428int excluded(char *name, struct pathnames *paths, struct pathnames **new)
4429{
4430 int n;
4431
4432 if(stickypath && excluded_match(name, stickypath, NULL))
4433 return TRUE;
4434
4435 for(n = 0; paths && n < paths->count; n++) {
4436 int res = excluded_match(name, paths->path[n], new);
4437 if(res) {
4438 free(*new);
4439 *new = NULL;
4440 return TRUE;
4441 }
plougherf9039c92007-10-22 03:54:16 +00004442 }
4443
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004444 /*
4445 * Either:
4446 * - no matching names found, return empty new search set, or
4447 * - one or more matches with sub-directories found (no leaf matches),
4448 * in which case return new search set.
4449 *
4450 * In either case return FALSE as we don't want to exclude this entry
4451 */
plougher8f8e1a12007-10-18 02:50:21 +00004452 return FALSE;
4453}
4454
4455
Phillip Lougher386128f2012-12-16 05:23:45 +00004456void process_exclude_file(char *argv)
4457{
4458 FILE *fd;
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004459 char buffer[MAX_LINE + 1]; /* overflow safe */
Phillip Lougherb22336d2012-12-20 18:44:22 +00004460 char *filename;
Phillip Lougher386128f2012-12-16 05:23:45 +00004461
Phillip Lougherb22336d2012-12-20 18:44:22 +00004462 fd = fopen(argv, "r");
4463 if(fd == NULL)
4464 BAD_ERROR("Failed to open exclude file \"%s\" because %s\n",
4465 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004466
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004467 while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
Phillip Lougherb22336d2012-12-20 18:44:22 +00004468 int len = strlen(filename);
4469
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004470 if(len == MAX_LINE && filename[len - 1] != '\n')
Phillip Lougherb22336d2012-12-20 18:44:22 +00004471 /* line too large */
4472 BAD_ERROR("Line too long when reading "
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004473 "exclude file \"%s\", larger than %d "
Phillip Lougher83847c12012-12-23 07:22:36 +00004474 "bytes\n", argv, MAX_LINE);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004475
4476 /*
4477 * Remove '\n' terminator if it exists (the last line
4478 * in the file may not be '\n' terminated)
4479 */
4480 if(len && filename[len - 1] == '\n')
4481 filename[len - 1] = '\0';
4482
4483 /* Skip any leading whitespace */
4484 while(isspace(*filename))
4485 filename ++;
4486
4487 /* if comment line, skip */
4488 if(*filename == '#')
4489 continue;
4490
4491 /*
4492 * check for initial backslash, to accommodate
4493 * filenames with leading space or leading # character
4494 */
4495 if(*filename == '\\')
4496 filename ++;
4497
4498 /* if line is now empty after skipping characters, skip it */
4499 if(*filename == '\0')
4500 continue;
4501
Phillip Lougher386128f2012-12-16 05:23:45 +00004502 if(old_exclude)
4503 old_add_exclude(filename);
4504 else
4505 add_exclude(filename);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004506 }
4507
4508 if(ferror(fd))
4509 BAD_ERROR("Reading exclude file \"%s\" failed because %s\n",
4510 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004511
4512 fclose(fd);
4513}
4514
4515
plougher99ac0cc2007-10-29 03:17:10 +00004516#define RECOVER_ID "Squashfs recovery file v1.0\n"
4517#define RECOVER_ID_SIZE 28
4518
plougher64e83fd2010-12-31 21:21:26 +00004519void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004520{
plougher1d065e92010-06-18 03:58:27 +00004521 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004522 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004523 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004524 char header[] = RECOVER_ID;
4525
4526 if(recover == FALSE) {
4527 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004528 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004529 return;
4530 }
4531
plougher1b879bc2010-12-18 02:49:42 +00004532 metadata = malloc(bytes);
4533 if(metadata == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004534 MEM_ERROR();
plougher44d54ef2010-02-08 22:13:49 +00004535
plougher1d065e92010-06-18 03:58:27 +00004536 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
Phillip Lougher477f4332013-03-06 03:55:08 +00004537 if(res == 0) {
4538 ERROR("Failed to read append filesystem metadata\n");
4539 BAD_ERROR("Filesystem corrupted?\n");
4540 }
plougher99ac0cc2007-10-29 03:17:10 +00004541
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004542 res = asprintf(&recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004543 getbase(destination_file), pid);
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004544 if(res == -1)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004545 MEM_ERROR();
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004546
plougherb3604122009-03-30 02:07:20 +00004547 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4548 if(recoverfd == -1)
4549 BAD_ERROR("Failed to create recovery file, because %s. "
4550 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004551
plougher628e7682009-03-29 22:12:24 +00004552 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004553 BAD_ERROR("Failed to write recovery file, because %s\n",
4554 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004555
plougher64e83fd2010-12-31 21:21:26 +00004556 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004557 BAD_ERROR("Failed to write recovery file, because %s\n",
4558 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004559
plougher628e7682009-03-29 22:12:24 +00004560 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004561 BAD_ERROR("Failed to write recovery file, because %s\n",
4562 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004563
4564 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004565 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004566
4567 printf("Recovery file \"%s\" written\n", recovery_file);
4568 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004569 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4570 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004571 printf("to restore filesystem\n\n");
4572}
4573
4574
4575void read_recovery_data(char *recovery_file, char *destination_file)
4576{
4577 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004578 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004579 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004580 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004581 struct stat buf;
4582 char header[] = RECOVER_ID;
4583 char header2[RECOVER_ID_SIZE];
4584
plougher9e9d9dc2010-12-18 02:53:57 +00004585 recoverfd = open(recovery_file, O_RDONLY);
4586 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004587 BAD_ERROR("Failed to open recovery file because %s\n",
4588 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004589
4590 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004591 BAD_ERROR("Failed to stat destination file, because %s\n",
4592 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004593
plougher9e9d9dc2010-12-18 02:53:57 +00004594 fd = open(destination_file, O_RDWR);
4595 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004596 BAD_ERROR("Failed to open destination file because %s\n",
4597 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004598
plougher8a8c4102009-03-29 22:28:49 +00004599 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4600 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004601 BAD_ERROR("Failed to read recovery file, because %s\n",
4602 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004603 if(res < RECOVER_ID_SIZE)
4604 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004605 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4606 BAD_ERROR("Not a recovery file\n");
4607
plougher64e83fd2010-12-31 21:21:26 +00004608 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004609 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004610 BAD_ERROR("Failed to read recovery file, because %s\n",
4611 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004612 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004613 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004614
plougher64e83fd2010-12-31 21:21:26 +00004615 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
Phillip Lougher477f4332013-03-06 03:55:08 +00004616 if(res == 0) {
4617 ERROR("Failed to read superblock from output filesystem\n");
4618 BAD_ERROR("Output filesystem is empty!\n");
4619 }
plougher99ac0cc2007-10-29 03:17:10 +00004620
plougherb3604122009-03-30 02:07:20 +00004621 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004622 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004623 BAD_ERROR("Recovery file and destination file do not seem to "
4624 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004625
4626 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4627
plougher9e9d9dc2010-12-18 02:53:57 +00004628 metadata = malloc(bytes);
4629 if(metadata == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004630 MEM_ERROR();
plougher99ac0cc2007-10-29 03:17:10 +00004631
plougher8a8c4102009-03-29 22:28:49 +00004632 res = read_bytes(recoverfd, metadata, bytes);
4633 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004634 BAD_ERROR("Failed to read recovery file, because %s\n",
4635 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004636 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004637 BAD_ERROR("Recovery file appears to be truncated\n");
4638
plougher64e83fd2010-12-31 21:21:26 +00004639 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004640
plougher0dd6f122009-03-29 21:43:57 +00004641 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004642
4643 close(recoverfd);
4644 close(fd);
4645
plougherb3604122009-03-30 02:07:20 +00004646 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4647 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004648
4649 exit(0);
4650}
4651
4652
Phillip Lougherd6b1f0d2013-03-26 03:09:27 +00004653void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad)
4654{
4655 int i;
4656
4657 sBlk->fragments = fragments;
Phillip Lougherd6b1f0d2013-03-26 03:09:27 +00004658 sBlk->no_ids = id_count;
4659 sBlk->inode_table_start = write_inodes();
4660 sBlk->directory_table_start = write_directories();
4661 sBlk->fragment_table_start = write_fragment_table();
4662 sBlk->lookup_table_start = exportable ? write_inode_lookup_table() :
4663 SQUASHFS_INVALID_BLK;
4664 sBlk->id_table_start = write_id_table();
4665 sBlk->xattr_id_table_start = write_xattrs();
4666
4667 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start);
4668 TRACE("sBlk->directory_table_start 0x%llx\n",
4669 sBlk->directory_table_start);
4670 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start);
4671 if(exportable)
4672 TRACE("sBlk->lookup_table_start 0x%llx\n",
4673 sBlk->lookup_table_start);
4674
4675 sBlk->bytes_used = bytes;
4676
4677 sBlk->compression = comp->id;
4678
4679 SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
4680 write_destination(fd, SQUASHFS_START, sizeof(*sBlk), sBlk);
4681
4682 if(!nopad && (i = bytes & (4096 - 1))) {
4683 char temp[4096] = {0};
4684 write_destination(fd, bytes, 4096 - i, temp);
4685 }
4686
4687 close(fd);
4688
Phillip Lougherd6b1f0d2013-03-26 03:09:27 +00004689 if(recovery_file)
4690 unlink(recovery_file);
4691
4692 total_bytes += total_inode_bytes + total_directory_bytes +
4693 sizeof(struct squashfs_super_block) + total_xattr_bytes;
4694
4695 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
4696 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
4697 SQUASHFS_MINOR, comp->name, block_size);
4698 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
4699 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
4700 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
4701 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
4702 "compressed");
4703 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
4704 "not ");
4705 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
4706 bytes / (1024.0 * 1024.0));
4707 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
4708 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
4709 printf("Inode table size %d bytes (%.2f Kbytes)\n",
4710 inode_bytes, inode_bytes / 1024.0);
4711 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
4712 ((float) inode_bytes / total_inode_bytes) * 100.0,
4713 total_inode_bytes);
4714 printf("Directory table size %d bytes (%.2f Kbytes)\n",
4715 directory_bytes, directory_bytes / 1024.0);
4716 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
4717 ((float) directory_bytes / total_directory_bytes) * 100.0,
4718 total_directory_bytes);
4719 if(total_xattr_bytes) {
4720 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
4721 xattr_bytes, xattr_bytes / 1024.0);
4722 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
4723 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
4724 total_xattr_bytes);
4725 }
4726 if(duplicate_checking)
4727 printf("Number of duplicate files found %d\n", file_count -
4728 dup_files);
4729 else
4730 printf("No duplicate files removed\n");
4731 printf("Number of inodes %d\n", inode_count);
4732 printf("Number of files %d\n", file_count);
4733 if(!no_fragments)
4734 printf("Number of fragments %d\n", fragments);
4735 printf("Number of symbolic links %d\n", sym_count);
4736 printf("Number of device nodes %d\n", dev_count);
4737 printf("Number of fifo nodes %d\n", fifo_count);
4738 printf("Number of socket nodes %d\n", sock_count);
4739 printf("Number of directories %d\n", dir_count);
4740 printf("Number of ids (unique uids + gids) %d\n", id_count);
4741 printf("Number of uids %d\n", uid_count);
4742
4743 for(i = 0; i < id_count; i++) {
4744 if(id_table[i]->flags & ISA_UID) {
4745 struct passwd *user = getpwuid(id_table[i]->id);
4746 printf("\t%s (%d)\n", user == NULL ? "unknown" :
4747 user->pw_name, id_table[i]->id);
4748 }
4749 }
4750
4751 printf("Number of gids %d\n", guid_count);
4752
4753 for(i = 0; i < id_count; i++) {
4754 if(id_table[i]->flags & ISA_GID) {
4755 struct group *group = getgrgid(id_table[i]->id);
4756 printf("\t%s (%d)\n", group == NULL ? "unknown" :
4757 group->gr_name, id_table[i]->id);
4758 }
4759 }
4760}
4761
4762
Phillip Lougher57e2f692014-05-05 23:50:24 +01004763int parse_numberll(char *start, long long *res, int size)
4764{
4765 char *end;
4766 long long number;
4767
4768 errno = 0; /* To distinguish success/failure after call */
4769
4770 number = strtoll(start, &end, 10);
4771
4772 /*
4773 * check for strtoll underflow or overflow in conversion, and other
4774 * errors.
4775 */
4776 if((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) ||
4777 (errno != 0 && number == 0))
4778 return 0;
4779
4780 /* reject negative numbers as invalid */
4781 if(number < 0)
4782 return 0;
4783
4784 if(size) {
4785 /*
4786 * Check for multiplier and trailing junk.
4787 * But first check that a number exists before the
4788 * multiplier
4789 */
4790 if(end == start)
4791 return 0;
4792
4793 switch(end[0]) {
4794 case 'g':
4795 case 'G':
4796 if(multiply_overflowll(number, 1073741824))
4797 return 0;
4798 number *= 1073741824;
4799
4800 if(end[1] != '\0')
4801 /* trailing junk after multiplier, but
4802 * allow it to be "bytes" */
4803 if(strcmp(end + 1, "bytes"))
4804 return 0;
4805
4806 break;
4807 case 'm':
4808 case 'M':
4809 if(multiply_overflowll(number, 1048576))
4810 return 0;
4811 number *= 1048576;
4812
4813 if(end[1] != '\0')
4814 /* trailing junk after multiplier, but
4815 * allow it to be "bytes" */
4816 if(strcmp(end + 1, "bytes"))
4817 return 0;
4818
4819 break;
4820 case 'k':
4821 case 'K':
4822 if(multiply_overflowll(number, 1024))
4823 return 0;
4824 number *= 1024;
4825
4826 if(end[1] != '\0')
4827 /* trailing junk after multiplier, but
4828 * allow it to be "bytes" */
4829 if(strcmp(end + 1, "bytes"))
4830 return 0;
4831
4832 break;
4833 case '\0':
4834 break;
4835 default:
4836 /* trailing junk after number */
4837 return 0;
4838 }
4839 } else if(end[0] != '\0')
4840 /* trailing junk after number */
4841 return 0;
4842
4843 *res = number;
4844 return 1;
4845}
4846
4847
4848int parse_number(char *start, int *res, int size)
4849{
4850 long long number;
4851
4852 if(!parse_numberll(start, &number, size))
4853 return 0;
4854
4855 /* check if long result will overflow signed int */
4856 if(number > INT_MAX)
4857 return 0;
4858
4859 *res = (int) number;
4860 return 1;
4861}
4862
4863
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004864int parse_num(char *arg, int *res)
4865{
4866 return parse_number(arg, res, 0);
4867}
4868
4869
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004870int get_physical_memory()
4871{
Phillip Lougher97ad5e82014-06-16 02:21:33 +01004872 /*
4873 * Long longs are used here because with PAE, a 32-bit
4874 * machine can have more than 4GB of physical memory
4875 *
4876 * sysconf(_SC_PHYS_PAGES) relies on /proc being mounted.
4877 * If it isn't fail.
4878 */
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004879 long long num_pages = sysconf(_SC_PHYS_PAGES);
4880 long long page_size = sysconf(_SC_PAGESIZE);
Phillip Lougher48d42fc2014-04-24 03:04:44 +01004881 int phys_mem = num_pages * page_size >> 20;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004882
Phillip Lougher97ad5e82014-06-16 02:21:33 +01004883 if(num_pages == -1 || page_size == -1)
4884 return 0;
4885
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004886 if(phys_mem < SQUASHFS_LOWMEM)
4887 BAD_ERROR("Mksquashfs requires more physical memory than is "
4888 "available!\n");
4889
Phillip Lougher78784bb2014-04-28 04:08:40 +01004890 return phys_mem;
Phillip Lougher48d42fc2014-04-24 03:04:44 +01004891}
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004892
Phillip Lougher48d42fc2014-04-24 03:04:44 +01004893
Phillip Lougher285a2fd2014-06-10 21:51:52 +01004894void check_usable_phys_mem(int total_mem)
4895{
4896 /*
4897 * We want to allow users to use as much of their physical
4898 * memory as they wish. However, for practical reasons there are
4899 * limits which need to be imposed, to protect users from themselves
4900 * and to prevent people from using Mksquashfs as a DOS attack by using
4901 * all physical memory. Mksquashfs uses memory to cache data from disk
4902 * to optimise performance. It is pointless to ask it to use more
4903 * than 75% of physical memory, as this causes thrashing and it is thus
4904 * self-defeating.
4905 */
4906 int mem = get_physical_memory();
4907
4908 mem = (mem >> 1) + (mem >> 2); /* 75% */
4909
Phillip Lougher97ad5e82014-06-16 02:21:33 +01004910 if(total_mem > mem && mem) {
Phillip Lougher285a2fd2014-06-10 21:51:52 +01004911 ERROR("Total memory requested is more than 75%% of physical "
4912 "memory.\n");
4913 ERROR("Mksquashfs uses memory to cache data from disk to "
4914 "optimise performance.\n");
4915 ERROR("It is pointless to ask it to use more than this amount "
4916 "of memory, as this\n");
4917 ERROR("causes thrashing and it is thus self-defeating.\n");
4918 BAD_ERROR("Requested memory size too large\n");
4919 }
4920
4921 if(sizeof(void *) == 4 && total_mem > 2048) {
4922 /*
4923 * If we're running on a kernel with PAE or on a 64-bit kernel,
4924 * then the 75% physical memory limit can still easily exceed
4925 * the addressable memory by this process.
4926 *
4927 * Due to the typical kernel/user-space split (1GB/3GB, or
4928 * 2GB/2GB), we have to conservatively assume the 32-bit
4929 * processes can only address 2-3GB. So refuse if the user
4930 * tries to allocate more than 2GB.
4931 */
4932 ERROR("Total memory requested may exceed maximum "
4933 "addressable memory by this process\n");
4934 BAD_ERROR("Requested memory size too large\n");
4935 }
4936}
4937
4938
4939int get_default_phys_mem()
4940{
Phillip Lougher97ad5e82014-06-16 02:21:33 +01004941 /*
4942 * get_physical_memory() relies on /proc being mounted.
4943 * If it fails, issue a warning, and use
4944 * SQUASHFS_LOWMEM / SQUASHFS_TAKE as default,
4945 * and allow a larger value to be set with -mem.
4946 */
4947 int mem = get_physical_memory();
4948
4949 if(mem == 0) {
4950 mem = SQUASHFS_LOWMEM / SQUASHFS_TAKE;
4951
4952 ERROR("Warning: Cannot get size of physical memory, probably "
4953 "because /proc is missing.\n");
4954 ERROR("Warning: Defaulting to minimal use of %d Mbytes, use "
4955 "-mem to set a better value,\n", mem);
4956 ERROR("Warning: or fix /proc.\n");
4957 } else
4958 mem /= SQUASHFS_TAKE;
Phillip Lougher285a2fd2014-06-10 21:51:52 +01004959
4960 if(sizeof(void *) == 4 && mem > 640) {
4961 /*
4962 * If we're running on a kernel with PAE or on a 64-bit kernel,
4963 * the default memory usage can exceed the addressable
4964 * memory by this process.
4965 * Due to the typical kernel/user-space split (1GB/3GB, or
4966 * 2GB/2GB), we have to conservatively assume the 32-bit
4967 * processes can only address 2-3GB. So limit the default
4968 * usage to 640M, which gives room for other data.
4969 */
4970 mem = 640;
4971 }
4972
4973 return mem;
4974}
4975
4976
Phillip Lougher48d42fc2014-04-24 03:04:44 +01004977void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
4978 int *fwriteq)
4979{
4980 *readq = mem / SQUASHFS_READQ_MEM;
4981 *bwriteq = mem / SQUASHFS_BWRITEQ_MEM;
4982 *fwriteq = mem / SQUASHFS_FWRITEQ_MEM;
4983 *fragq = mem - *readq - *bwriteq - *fwriteq;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01004984}
4985
4986
plougher1f413c82005-11-18 00:02:14 +00004987#define VERSION() \
Phillip Lougherb29dd5e2014-06-23 04:46:50 +01004988 printf("mksquashfs version 4.3-git (2014/06/22)\n");\
Phillip Loughercc064952014-01-03 04:26:34 +00004989 printf("copyright (C) 2014 Phillip Lougher "\
Phillip Lougher83d42a32012-10-31 23:42:22 +00004990 "<phillip@squashfs.org.uk>\n\n"); \
plougher16111452010-07-22 05:12:18 +00004991 printf("This program is free software; you can redistribute it and/or"\
4992 "\n");\
4993 printf("modify it under the terms of the GNU General Public License"\
4994 "\n");\
4995 printf("as published by the Free Software Foundation; either version "\
4996 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004997 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004998 printf("This program is distributed in the hope that it will be "\
4999 "useful,\n");\
5000 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
5001 "of\n");\
5002 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
5003 "\n");\
plougher1f413c82005-11-18 00:02:14 +00005004 printf("GNU General Public License for more details.\n");
5005int main(int argc, char *argv[])
5006{
plougher324978d2006-02-27 04:53:29 +00005007 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00005008 int res, i;
plougher1f413c82005-11-18 00:02:14 +00005009 char *b, *root_name = NULL;
Phillip Loughera709bff2013-03-28 17:48:31 +00005010 int keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005011 squashfs_inode inode;
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005012 int readq;
5013 int fragq;
5014 int bwriteq;
5015 int fwriteq;
Phillip Lougher285a2fd2014-06-10 21:51:52 +01005016 int total_mem = get_default_phys_mem();
Phillip Lougher569a9632013-04-22 03:30:30 +01005017 int progress = TRUE;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005018 int force_progress = FALSE;
Phillip Loughera709bff2013-03-28 17:48:31 +00005019 struct file_buffer **fragment = NULL;
plougher1f413c82005-11-18 00:02:14 +00005020
plougher1f413c82005-11-18 00:02:14 +00005021 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
5022 VERSION();
5023 exit(0);
5024 }
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005025
5026 block_log = slog(block_size);
Phillip Lougher48d42fc2014-04-24 03:04:44 +01005027 calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq);
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005028
plougher1f413c82005-11-18 00:02:14 +00005029 for(i = 1; i < argc && argv[i][0] != '-'; i++);
5030 if(i < 3)
5031 goto printOptions;
5032 source_path = argv + 1;
5033 source = i - 2;
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005034
plougher4da4bd42010-11-21 05:01:54 +00005035 /*
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005036 * Scan the command line for -comp xxx option, this is to ensure
5037 * any -X compressor specific options are passed to the
5038 * correct compressor
plougher4da4bd42010-11-21 05:01:54 +00005039 */
plougher1f413c82005-11-18 00:02:14 +00005040 for(; i < argc; i++) {
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005041 struct compressor *prev_comp = comp;
5042
5043 if(strcmp(argv[i], "-comp") == 0) {
5044 if(++i == argc) {
5045 ERROR("%s: -comp missing compression type\n",
5046 argv[0]);
5047 exit(1);
5048 }
5049 comp = lookup_compressor(argv[i]);
5050 if(!comp->supported) {
5051 ERROR("%s: Compressor \"%s\" is not supported!"
5052 "\n", argv[0], argv[i]);
5053 ERROR("%s: Compressors available:\n", argv[0]);
5054 display_compressors("", COMP_DEFAULT);
5055 exit(1);
5056 }
5057 if(prev_comp != NULL && prev_comp != comp) {
5058 ERROR("%s: -comp multiple conflicting -comp"
5059 " options specified on command line"
5060 ", previously %s, now %s\n", argv[0],
5061 prev_comp->name, comp->name);
5062 exit(1);
5063 }
5064 compressor_opt_parsed = 1;
5065
5066 } else if(strcmp(argv[i], "-e") == 0)
5067 break;
5068 else if(strcmp(argv[i], "-root-becomes") == 0 ||
5069 strcmp(argv[i], "-ef") == 0 ||
5070 strcmp(argv[i], "-pf") == 0 ||
5071 strcmp(argv[i], "-af") == 0 ||
5072 strcmp(argv[i], "-comp") == 0)
5073 i++;
5074 }
5075
5076 /*
5077 * if no -comp option specified lookup default compressor. Note the
5078 * Makefile ensures the default compressor has been built, and so we
5079 * don't need to to check for failure here
5080 */
5081 if(comp == NULL)
5082 comp = lookup_compressor(COMP_DEFAULT);
5083
5084 for(i = source + 2; i < argc; i++) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005085 if(strcmp(argv[i], "-action") == 0 ||
5086 strcmp(argv[i], "-a") ==0) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005087 if(++i == argc) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005088 ERROR("%s: %s missing action\n",
5089 argv[0], argv[i - 1]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005090 exit(1);
5091 }
5092 res = parse_action(argv[i]);
5093 if(res == 0)
5094 exit(1);
5095
Phillip Lougherb73caba2012-12-24 21:58:41 +00005096 } else if(strcmp(argv[i], "-af") == 0) {
5097 if(++i == argc) {
5098 ERROR("%s: -af missing filename\n", argv[0]);
5099 exit(1);
5100 }
5101 if(read_action_file(argv[i]) == FALSE)
5102 exit(1);
5103
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005104 } else if(strcmp(argv[i], "-comp") == 0)
5105 /* parsed previously */
5106 i++;
plougherb5576ea2010-11-22 01:06:53 +00005107
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005108 else if(strncmp(argv[i], "-X", 2) == 0) {
Phillip Lougher774b7b32014-01-07 04:47:13 +00005109 int args;
5110
5111 if(strcmp(argv[i] + 2, "help") == 0)
5112 goto print_compressor_options;
5113
5114 args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00005115 if(args < 0) {
5116 if(args == -1) {
5117 ERROR("%s: Unrecognised compressor"
5118 " option %s\n", argv[0],
5119 argv[i]);
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005120 if(!compressor_opt_parsed)
5121 ERROR("%s: Did you forget to"
5122 " specify -comp?\n",
5123 argv[0]);
Phillip Lougher774b7b32014-01-07 04:47:13 +00005124print_compressor_options:
Phillip Lougherb1c3b6a2014-01-06 05:30:00 +00005125 ERROR("%s: selected compressor \"%s\""
5126 ". Options supported: %s\n",
5127 argv[0], comp->name,
5128 comp->usage ? "" : "none");
5129 if(comp->usage)
5130 comp->usage();
Phillip Lougher1f6c7402014-01-06 04:16:48 +00005131 }
plougherb5576ea2010-11-22 01:06:53 +00005132 exit(1);
5133 }
5134 i += args;
5135
plougherae9dcd82009-08-01 02:59:38 +00005136 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00005137 if(++i == argc) {
5138 ERROR("%s: -pf missing filename\n", argv[0]);
5139 exit(1);
5140 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005141 if(read_pseudo_file(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005142 exit(1);
plougher43244f22009-04-05 02:04:51 +00005143 } else if(strcmp(argv[i], "-p") == 0) {
5144 if(++i == argc) {
5145 ERROR("%s: -p missing pseudo file definition\n",
5146 argv[0]);
5147 exit(1);
5148 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005149 if(read_pseudo_def(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005150 exit(1);
plougher43244f22009-04-05 02:04:51 +00005151 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00005152 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00005153 ERROR("%s: -recover missing recovery file\n",
5154 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00005155 exit(1);
5156 }
5157 read_recovery_data(argv[i], argv[source + 1]);
5158 } else if(strcmp(argv[i], "-no-recovery") == 0)
5159 recover = FALSE;
5160 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00005161 old_exclude = FALSE;
5162 use_regex = FALSE;
5163 } else if(strcmp(argv[i], "-regex") == 0) {
5164 old_exclude = FALSE;
5165 use_regex = TRUE;
5166 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00005167 sparse_files = FALSE;
5168 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00005169 progress = FALSE;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005170 else if(strcmp(argv[i], "-progress") == 0)
5171 force_progress = TRUE;
plougher02bc3bc2007-02-25 12:12:01 +00005172 else if(strcmp(argv[i], "-no-exports") == 0)
5173 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00005174 else if(strcmp(argv[i], "-processors") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005175 if((++i == argc) || !parse_num(argv[i], &processors)) {
plougher360514a2009-03-30 03:01:38 +00005176 ERROR("%s: -processors missing or invalid "
5177 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005178 exit(1);
5179 }
5180 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00005181 ERROR("%s: -processors should be 1 or larger\n",
5182 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005183 exit(1);
5184 }
plougher0e453652006-11-06 01:49:35 +00005185 } else if(strcmp(argv[i], "-read-queue") == 0) {
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005186 if((++i == argc) || !parse_num(argv[i], &readq)) {
plougher50b31762009-03-31 04:14:46 +00005187 ERROR("%s: -read-queue missing or invalid "
5188 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005189 exit(1);
5190 }
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005191 if(readq < 1) {
plougher360514a2009-03-30 03:01:38 +00005192 ERROR("%s: -read-queue should be 1 megabyte or "
5193 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005194 exit(1);
5195 }
plougher0e453652006-11-06 01:49:35 +00005196 } else if(strcmp(argv[i], "-write-queue") == 0) {
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005197 if((++i == argc) || !parse_num(argv[i], &bwriteq)) {
plougher50b31762009-03-31 04:14:46 +00005198 ERROR("%s: -write-queue missing or invalid "
5199 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005200 exit(1);
5201 }
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005202 if(bwriteq < 2) {
5203 ERROR("%s: -write-queue should be 2 megabytes "
plougher50b31762009-03-31 04:14:46 +00005204 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005205 exit(1);
5206 }
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005207 fwriteq = bwriteq >> 1;
5208 bwriteq -= fwriteq;
plougher217bad82008-04-05 11:36:41 +00005209 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005210 if((++i == argc) || !parse_num(argv[i], &fragq)) {
plougher360514a2009-03-30 03:01:38 +00005211 ERROR("%s: -fragment-queue missing or invalid "
5212 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005213 exit(1);
5214 }
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005215 if(fragq < 1) {
plougher50b31762009-03-31 04:14:46 +00005216 ERROR("%s: -fragment-queue should be 1 "
5217 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005218 exit(1);
5219 }
Phillip Lougher48d42fc2014-04-24 03:04:44 +01005220 } else if(strcmp(argv[i], "-mem") == 0) {
Phillip Lougher57e2f692014-05-05 23:50:24 +01005221 long long number;
5222
5223 if((++i == argc) ||
5224 !parse_numberll(argv[i], &number, 1)) {
Phillip Lougher48d42fc2014-04-24 03:04:44 +01005225 ERROR("%s: -mem missing or invalid mem size\n",
5226 argv[0]);
5227 exit(1);
5228 }
Phillip Lougher368becc2014-06-11 04:51:37 +01005229
5230 /*
5231 * convert from bytes to Mbytes, ensuring the value
5232 * does not overflow a signed int
5233 */
5234 if(number >= (1LL << 51)) {
5235 ERROR("%s: -mem invalid mem size\n", argv[0]);
5236 exit(1);
5237 }
5238
Phillip Lougher57e2f692014-05-05 23:50:24 +01005239 total_mem = number / 1048576;
Phillip Lougher07def8b2014-05-11 19:56:11 +01005240 if(total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) {
Phillip Lougher48d42fc2014-04-24 03:04:44 +01005241 ERROR("%s: -mem should be %d Mbytes or "
Phillip Lougher07def8b2014-05-11 19:56:11 +01005242 "larger\n", argv[0],
5243 SQUASHFS_LOWMEM / SQUASHFS_TAKE);
Phillip Lougher48d42fc2014-04-24 03:04:44 +01005244 exit(1);
5245 }
5246 calculate_queue_sizes(total_mem, &readq, &fragq,
5247 &bwriteq, &fwriteq);
plougher5507dd92006-11-06 00:43:10 +00005248 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00005249 if(++i == argc) {
5250 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005251 exit(1);
5252 }
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005253 if(!parse_number(argv[i], &block_size, 1)) {
plougher4c99cb72007-06-14 21:46:31 +00005254 ERROR("%s: -b invalid block size\n", argv[0]);
5255 exit(1);
5256 }
plougher1f413c82005-11-18 00:02:14 +00005257 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00005258 ERROR("%s: -b block size not power of two or "
5259 "not between 4096 and 1Mbyte\n",
5260 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005261 exit(1);
5262 }
5263 } else if(strcmp(argv[i], "-ef") == 0) {
5264 if(++i == argc) {
5265 ERROR("%s: -ef missing filename\n", argv[0]);
5266 exit(1);
5267 }
plougher9b5bf8c2006-03-20 18:43:33 +00005268 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00005269 duplicate_checking = FALSE;
5270
5271 else if(strcmp(argv[i], "-no-fragments") == 0)
5272 no_fragments = TRUE;
5273
5274 else if(strcmp(argv[i], "-always-use-fragments") == 0)
5275 always_use_fragments = TRUE;
5276
5277 else if(strcmp(argv[i], "-sort") == 0) {
5278 if(++i == argc) {
5279 ERROR("%s: -sort missing filename\n", argv[0]);
5280 exit(1);
5281 }
5282 } else if(strcmp(argv[i], "-all-root") == 0 ||
5283 strcmp(argv[i], "-root-owned") == 0)
5284 global_uid = global_gid = 0;
5285
5286 else if(strcmp(argv[i], "-force-uid") == 0) {
5287 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005288 ERROR("%s: -force-uid missing uid or user\n",
5289 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005290 exit(1);
5291 }
5292 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005293 if(global_uid < 0 || global_uid >
5294 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005295 ERROR("%s: -force-uid uid out of range"
5296 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005297 exit(1);
5298 }
5299 } else {
5300 struct passwd *uid = getpwnam(argv[i]);
5301 if(uid)
5302 global_uid = uid->pw_uid;
5303 else {
plougher360514a2009-03-30 03:01:38 +00005304 ERROR("%s: -force-uid invalid uid or "
5305 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005306 exit(1);
5307 }
5308 }
5309 } else if(strcmp(argv[i], "-force-gid") == 0) {
5310 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00005311 ERROR("%s: -force-gid missing gid or group\n",
5312 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005313 exit(1);
5314 }
5315 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005316 if(global_gid < 0 || global_gid >
5317 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005318 ERROR("%s: -force-gid gid out of range"
5319 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005320 exit(1);
5321 }
5322 } else {
5323 struct group *gid = getgrnam(argv[i]);
5324 if(gid)
5325 global_gid = gid->gr_gid;
5326 else {
plougher360514a2009-03-30 03:01:38 +00005327 ERROR("%s: -force-gid invalid gid or "
5328 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005329 exit(1);
5330 }
5331 }
5332 } else if(strcmp(argv[i], "-noI") == 0 ||
5333 strcmp(argv[i], "-noInodeCompression") == 0)
5334 noI = TRUE;
5335
5336 else if(strcmp(argv[i], "-noD") == 0 ||
5337 strcmp(argv[i], "-noDataCompression") == 0)
5338 noD = TRUE;
5339
5340 else if(strcmp(argv[i], "-noF") == 0 ||
5341 strcmp(argv[i], "-noFragmentCompression") == 0)
5342 noF = TRUE;
5343
plougherb99d7832010-05-19 01:57:34 +00005344 else if(strcmp(argv[i], "-noX") == 0 ||
5345 strcmp(argv[i], "-noXattrCompression") == 0)
5346 noX = TRUE;
5347
plougherce564c62010-05-19 03:01:49 +00005348 else if(strcmp(argv[i], "-no-xattrs") == 0)
5349 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00005350
plougher30281c82010-08-25 05:06:11 +00005351 else if(strcmp(argv[i], "-xattrs") == 0)
5352 no_xattrs = FALSE;
5353
plougher1f413c82005-11-18 00:02:14 +00005354 else if(strcmp(argv[i], "-nopad") == 0)
5355 nopad = TRUE;
5356
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005357 else if(strcmp(argv[i], "-info") == 0)
plougher91fbb302008-05-06 02:29:36 +00005358 silent = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005359
5360 else if(strcmp(argv[i], "-e") == 0)
5361 break;
5362
5363 else if(strcmp(argv[i], "-noappend") == 0)
5364 delete = TRUE;
5365
5366 else if(strcmp(argv[i], "-keep-as-directory") == 0)
5367 keep_as_directory = TRUE;
5368
Phillip Lougher85776df2014-01-31 03:10:46 +00005369 else if(strcmp(argv[i], "-exit-on-error") == 0)
5370 exit_on_error = TRUE;
5371
plougher1f413c82005-11-18 00:02:14 +00005372 else if(strcmp(argv[i], "-root-becomes") == 0) {
5373 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005374 ERROR("%s: -root-becomes: missing name\n",
5375 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005376 exit(1);
5377 }
5378 root_name = argv[i];
5379 } else if(strcmp(argv[i], "-version") == 0) {
5380 VERSION();
5381 } else {
5382 ERROR("%s: invalid option\n\n", argv[0]);
5383printOptions:
plougher360514a2009-03-30 03:01:38 +00005384 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
5385 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00005386 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00005387 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00005388 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00005389 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00005390 ERROR("-b <block_size>\t\tset data block to "
Phillip Lougherb74a59c2014-04-30 03:10:44 +01005391 "<block_size>. Default 128 Kbytes\n");
5392 ERROR("\t\t\tOptionally a suffix of K or M can be"
5393 " given to specify\n\t\t\tKbytes or Mbytes"
5394 " respectively\n");
plougher37632562009-08-07 19:09:01 +00005395 ERROR("-no-exports\t\tdon't make the filesystem "
5396 "exportable via NFS\n");
5397 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00005398 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00005399 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00005400 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00005401 "\n");
plougher1f413c82005-11-18 00:02:14 +00005402 ERROR("-noI\t\t\tdo not compress inode table\n");
5403 ERROR("-noD\t\t\tdo not compress data blocks\n");
5404 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00005405 ERROR("-noX\t\t\tdo not compress extended "
5406 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00005407 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00005408 ERROR("-always-use-fragments\tuse fragment blocks for "
5409 "files larger than block size\n");
5410 ERROR("-no-duplicates\t\tdo not perform duplicate "
5411 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00005412 ERROR("-all-root\t\tmake all files owned by root\n");
5413 ERROR("-force-uid uid\t\tset all file uids to uid\n");
5414 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00005415 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
5416 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00005417 ERROR("-keep-as-directory\tif one source directory is "
5418 "specified, create a root\n");
5419 ERROR("\t\t\tdirectory containing that directory, "
5420 "rather than the\n");
5421 ERROR("\t\t\tcontents of the directory\n");
5422 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00005423 ERROR("-p <pseudo-definition>\tAdd pseudo file "
5424 "definition\n");
5425 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
5426 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00005427 ERROR("-sort <sort_file>\tsort files according to "
5428 "priorities in <sort_file>. One\n");
5429 ERROR("\t\t\tfile or dir with priority per line. "
5430 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00005431 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00005432 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
5433 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00005434 ERROR("-wildcards\t\tAllow extended shell wildcards "
5435 "(globbing) to be used in\n\t\t\texclude "
5436 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00005437 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
5438 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00005439 ERROR("\nFilesystem append options:\n");
5440 ERROR("-noappend\t\tdo not append to existing "
5441 "filesystem\n");
5442 ERROR("-root-becomes <name>\twhen appending source "
5443 "files/directories, make the\n");
5444 ERROR("\t\t\toriginal root become a subdirectory in "
5445 "the new root\n");
5446 ERROR("\t\t\tcalled <name>, rather than adding the new "
5447 "source items\n");
5448 ERROR("\t\t\tto the original root\n");
5449 ERROR("\nMksquashfs runtime options:\n");
5450 ERROR("-version\t\tprint version, licence and "
5451 "copyright message\n");
Phillip Lougher85776df2014-01-31 03:10:46 +00005452 ERROR("-exit-on-error\t\ttreat normally ignored errors "
5453 "as fatal\n");
plougher37632562009-08-07 19:09:01 +00005454 ERROR("-recover <name>\t\trecover filesystem data "
5455 "using recovery file <name>\n");
5456 ERROR("-no-recovery\t\tdon't generate a recovery "
5457 "file\n");
5458 ERROR("-info\t\t\tprint files written to filesystem\n");
5459 ERROR("-no-progress\t\tdon't display the progress "
5460 "bar\n");
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005461 ERROR("-progress\t\tdisplay progress bar when using "
5462 "the -info option\n");
plougher37632562009-08-07 19:09:01 +00005463 ERROR("-processors <number>\tUse <number> processors."
5464 " By default will use number of\n");
5465 ERROR("\t\t\tprocessors available\n");
Phillip Lougher57e2f692014-05-05 23:50:24 +01005466 ERROR("-mem <size>\t\tUse <size> physical memory. "
5467 "Currently set to %dM\n", total_mem);
5468 ERROR("\t\t\tOptionally a suffix of K, M or G can be"
5469 " given to specify\n\t\t\tKbytes, Mbytes or"
5470 " Gbytes respectively\n");
plougher37632562009-08-07 19:09:01 +00005471 ERROR("\nMiscellaneous options:\n");
5472 ERROR("-root-owned\t\talternative name for -all-root"
5473 "\n");
5474 ERROR("-noInodeCompression\talternative name for -noI"
5475 "\n");
5476 ERROR("-noDataCompression\talternative name for -noD"
5477 "\n");
5478 ERROR("-noFragmentCompression\talternative name for "
5479 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005480 ERROR("-noXattrCompression\talternative name for "
5481 "-noX\n");
Phillip Lougher774b7b32014-01-07 04:47:13 +00005482 ERROR("\n-Xhelp\t\t\tprint compressor options for"
5483 " selected compressor\n");
plougher4fb66822010-12-08 02:49:28 +00005484 ERROR("\nCompressors available and compressor specific "
5485 "options:\n");
5486 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005487 exit(1);
5488 }
5489 }
5490
plougherb747f4f2010-12-25 04:05:47 +00005491 /*
5492 * Some compressors may need the options to be checked for validity
5493 * once all the options have been processed
5494 */
5495 res = compressor_options_post(comp, block_size);
5496 if(res)
5497 EXIT_MKSQUASHFS();
5498
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005499 /*
5500 * If the -info option has been selected then disable the
5501 * progress bar unless it has been explicitly enabled with
5502 * the -progress option
5503 */
5504 if(!silent)
5505 progress = force_progress;
5506
5507#ifdef SQUASHFS_TRACE
Phillip Lougher989f5fe2013-04-22 03:16:29 +01005508 /*
5509 * Disable progress bar if full debug tracing is enabled.
5510 * The progress bar in this case just gets in the way of the
5511 * debug trace output
5512 */
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005513 progress = FALSE;
5514#endif
5515
plougher91fbb302008-05-06 02:29:36 +00005516 for(i = 0; i < source; i++)
5517 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005518 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005519 "because %s\n", source_path[i],
5520 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005521 EXIT_MKSQUASHFS();
5522 }
plougher324978d2006-02-27 04:53:29 +00005523
5524 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005525 if(stat(argv[source + 1], &buf) == -1) {
5526 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005527 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005528 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005529 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005530 perror("Could not create destination file");
5531 exit(1);
5532 }
5533 delete = TRUE;
5534 } else {
5535 perror("Could not stat destination file");
5536 exit(1);
5537 }
5538
5539 } else {
5540 if(S_ISBLK(buf.st_mode)) {
5541 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005542 perror("Could not open block device as "
5543 "destination");
plougher1f413c82005-11-18 00:02:14 +00005544 exit(1);
5545 }
5546 block_device = 1;
5547
5548 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005549 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5550 O_RDWR);
5551 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005552 perror("Could not open regular file for "
5553 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005554 exit(1);
5555 }
plougher44d54ef2010-02-08 22:13:49 +00005556 }
plougher1f413c82005-11-18 00:02:14 +00005557 else {
5558 ERROR("Destination not block device or regular file\n");
5559 exit(1);
5560 }
5561
plougher324978d2006-02-27 04:53:29 +00005562 }
plougher1f413c82005-11-18 00:02:14 +00005563
plougher16111452010-07-22 05:12:18 +00005564 /*
5565 * process the exclude files - must be done afer destination file has
5566 * been possibly created
5567 */
plougher1f413c82005-11-18 00:02:14 +00005568 for(i = source + 2; i < argc; i++)
Phillip Lougher386128f2012-12-16 05:23:45 +00005569 if(strcmp(argv[i], "-ef") == 0)
5570 /*
5571 * Note presence of filename arg has already
5572 * been checked
5573 */
5574 process_exclude_file(argv[++i]);
5575 else if(strcmp(argv[i], "-e") == 0)
plougher1f413c82005-11-18 00:02:14 +00005576 break;
plougher8b9a7f62009-08-01 22:52:45 +00005577 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005578 strcmp(argv[i], "-sort") == 0 ||
5579 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005580 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005581 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005582 i++;
5583
5584 if(i != argc) {
5585 if(++i == argc) {
5586 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005587 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005588 }
plougher8f8e1a12007-10-18 02:50:21 +00005589 while(i < argc)
5590 if(old_exclude)
5591 old_add_exclude(argv[i++]);
5592 else
plougher05e50ef2007-10-23 12:34:20 +00005593 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005594 }
5595
5596 /* process the sort files - must be done afer the exclude files */
5597 for(i = source + 2; i < argc; i++)
5598 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005599 int res = read_sort_file(argv[++i], source,
5600 source_path);
5601 if(res == FALSE)
5602 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005603 sorted ++;
5604 } else if(strcmp(argv[i], "-e") == 0)
5605 break;
plougher8b9a7f62009-08-01 22:52:45 +00005606 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005607 strcmp(argv[i], "-ef") == 0 ||
5608 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005609 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005610 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005611 i++;
5612
plougher4c99cb72007-06-14 21:46:31 +00005613 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005614 comp = read_super(fd, &sBlk, argv[source + 1]);
5615 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005616 ERROR("Failed to read existing filesystem - will not "
5617 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005618 ERROR("To force Mksquashfs to write to this block "
5619 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005620 EXIT_MKSQUASHFS();
5621 }
plougher1f413c82005-11-18 00:02:14 +00005622
plougher1f413c82005-11-18 00:02:14 +00005623 block_log = slog(block_size = sBlk.block_size);
5624 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5625 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5626 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005627 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005628 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5629 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5630 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005631 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005632 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005633 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005634 }
5635
Phillip Lougherc3af83a2014-04-21 21:38:16 +01005636 initialise_threads(readq, fragq, bwriteq, fwriteq, delete,
5637 destination_file);
plougher4c99cb72007-06-14 21:46:31 +00005638
plougher13fdddf2010-11-24 01:23:41 +00005639 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5640 if(res)
5641 BAD_ERROR("compressor_init failed\n");
5642
plougher4c99cb72007-06-14 21:46:31 +00005643 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005644 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005645 void *comp_data = compressor_dump_options(comp, block_size,
5646 &size);
plougher3d7e5182010-12-25 01:49:42 +00005647
plougherdf6d8f02009-03-20 03:10:00 +00005648 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005649 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005650
plougher871c72a2010-12-25 04:17:27 +00005651 /*
5652 * store any compressor specific options after the superblock,
5653 * and set the COMP_OPT flag to show that the filesystem has
5654 * compressor specfic options
5655 */
plougher3d7e5182010-12-25 01:49:42 +00005656 if(comp_data) {
5657 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5658
5659 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005660 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005661 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005662 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005663 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005664 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005665 + size;
5666 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005667 } else
plougher64e83fd2010-12-31 21:21:26 +00005668 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005669 } else {
plougher360514a2009-03-30 03:01:38 +00005670 unsigned int last_directory_block, inode_dir_offset,
5671 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005672 inode_dir_start_block, uncompressed_data,
5673 compressed_data, inode_dir_inode_number,
5674 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005675 unsigned int root_inode_start =
5676 SQUASHFS_INODE_BLK(sBlk.root_inode),
5677 root_inode_offset =
5678 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005679
plougher360514a2009-03-30 03:01:38 +00005680 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5681 &data_cache, &directory_table,
5682 &directory_data_cache, &last_directory_block,
5683 &inode_dir_offset, &inode_dir_file_size,
5684 &root_inode_size, &inode_dir_start_block,
5685 &file_count, &sym_count, &dev_count, &dir_count,
5686 &fifo_count, &sock_count, &total_bytes,
5687 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005688 &inode_dir_inode_number,
5689 &inode_dir_parent_inode, add_old_root_entry,
5690 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005691 ERROR("Failed to read existing filesystem - will not "
5692 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005693 ERROR("To force Mksquashfs to write to this block "
5694 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005695 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005696 }
Phillip Lougherb4fc3bf2014-02-06 01:42:06 +00005697 if((append_fragments = fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005698 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005699 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005700 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005701 if(fragment_table == NULL)
5702 BAD_ERROR("Out of memory in save filesystem state\n");
5703 }
plougher1f413c82005-11-18 00:02:14 +00005704
plougher50b31762009-03-31 04:14:46 +00005705 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005706 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005707 block_size);
plougher89c7a512010-12-15 08:35:51 +00005708 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005709 "-always-use-fragments,\n-exportable and -comp options "
5710 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005711 printf("\nIf appending is not wanted, please re-run with "
5712 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005713
plougher360514a2009-03-30 03:01:38 +00005714 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5715 ~(SQUASHFS_METADATA_SIZE - 1);
5716 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5717 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005718
5719 /* save original filesystem state for restoring ... */
5720 sfragments = fragments;
5721 sbytes = bytes;
5722 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005723 scache_bytes = root_inode_offset + root_inode_size;
5724 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005725 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005726 if(sdata_cache == NULL)
5727 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005728 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005729 if(sdirectory_data_cache == NULL)
5730 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005731 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005732 memcpy(sdirectory_data_cache, directory_data_cache +
5733 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005734 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005735 stotal_bytes = total_bytes;
5736 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005737 stotal_directory_bytes = total_directory_bytes +
5738 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005739 sfile_count = file_count;
5740 ssym_count = sym_count;
5741 sdev_count = dev_count;
5742 sdir_count = dir_count + 1;
5743 sfifo_count = fifo_count;
5744 ssock_count = sock_count;
5745 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005746 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005747 write_recovery_data(&sBlk);
Phillip Lougher3bcf67d2013-02-24 10:56:38 +00005748 save_xattrs();
Phillip Lougher3794e342014-04-10 02:15:45 +01005749 appending = TRUE;
plougher1f413c82005-11-18 00:02:14 +00005750
plougher360514a2009-03-30 03:01:38 +00005751 /*
5752 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005753 * original filesystem. The filesystem state differs depending
5754 * on whether we're appending to the original root directory, or
5755 * if the original root directory becomes a sub-directory
5756 * (root-becomes specified on command line, here root_name !=
5757 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005758 */
5759 inode_bytes = inode_size = root_inode_start;
5760 directory_size = last_directory_block;
5761 cache_size = root_inode_offset + root_inode_size;
5762 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5763 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005764 sdirectory_bytes = last_directory_block;
5765 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005766 root_inode_number = inode_dir_parent_inode;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005767 inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005768 directory_bytes = last_directory_block;
5769 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005770 memmove(directory_data_cache, directory_data_cache +
5771 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005772 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005773 add_old_root_entry(root_name, sBlk.root_inode,
5774 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005775 total_directory_bytes += compressed_data;
5776 dir_count ++;
5777 } else {
plougher360514a2009-03-30 03:01:38 +00005778 sdirectory_compressed_bytes = last_directory_block -
5779 inode_dir_start_block;
5780 sdirectory_compressed =
5781 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005782 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005783 BAD_ERROR("Out of memory in save filesystem "
5784 "state\n");
plougher360514a2009-03-30 03:01:38 +00005785 memcpy(sdirectory_compressed, directory_table +
5786 inode_dir_start_block,
5787 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005788 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005789 root_inode_number = inode_dir_inode_number;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005790 inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005791 directory_bytes = inode_dir_start_block;
5792 directory_cache_bytes = inode_dir_offset;
5793 cache_bytes = root_inode_offset;
5794 }
5795
plougher360514a2009-03-30 03:01:38 +00005796 inode_count = file_count + dir_count + sym_count + dev_count +
5797 fifo_count + sock_count;
plougher1f413c82005-11-18 00:02:14 +00005798 }
5799
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00005800 if(path)
5801 paths = add_subdir(paths, path);
plougherf9039c92007-10-22 03:54:16 +00005802
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005803 dump_actions();
Phillip Lougher7a28f7a2014-04-20 23:47:08 +01005804 dump_pseudos();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005805
plougher360514a2009-03-30 03:01:38 +00005806 if(delete && !keep_as_directory && source == 1 &&
5807 S_ISDIR(source_buf.st_mode))
Phillip Lougherbae0e422014-01-19 23:42:11 +00005808 dir_scan(&inode, source_path[0], scan1_readdir, progress);
plougher50b31762009-03-31 04:14:46 +00005809 else if(!keep_as_directory && source == 1 &&
5810 S_ISDIR(source_buf.st_mode))
Phillip Lougherbae0e422014-01-19 23:42:11 +00005811 dir_scan(&inode, source_path[0], scan1_single_readdir, progress);
plougher1f413c82005-11-18 00:02:14 +00005812 else
Phillip Lougherbae0e422014-01-19 23:42:11 +00005813 dir_scan(&inode, "", scan1_encomp_readdir, progress);
plougher1f413c82005-11-18 00:02:14 +00005814 sBlk.root_inode = inode;
5815 sBlk.inodes = inode_count;
5816 sBlk.s_magic = SQUASHFS_MAGIC;
5817 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005818 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005819 sBlk.block_size = block_size;
5820 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005821 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005822 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005823 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005824 sBlk.mkfs_time = time(NULL);
5825
Phillip Lougher83b8f862013-04-09 03:28:55 +01005826 disable_info();
plougherc9b11db2008-05-06 23:59:15 +00005827
Phillip Loughera709bff2013-03-28 17:48:31 +00005828 while((fragment = get_frag_action(fragment)))
5829 write_fragment(*fragment);
5830 unlock_fragments();
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01005831 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
Phillip Loughera709bff2013-03-28 17:48:31 +00005832 pthread_mutex_lock(&fragment_mutex);
5833 while(fragments_outstanding) {
5834 pthread_mutex_unlock(&fragment_mutex);
5835 sched_yield();
5836 pthread_mutex_lock(&fragment_mutex);
5837 }
Phillip Lougherfd74d9a2013-03-31 22:49:50 +01005838 pthread_cleanup_pop(1);
Phillip Loughera709bff2013-03-28 17:48:31 +00005839
5840 queue_put(to_writer, NULL);
5841 if(queue_get(from_writer) != 0)
5842 EXIT_MKSQUASHFS();
5843
Phillip Loughercd1a5a62014-01-21 04:53:46 +00005844 set_progressbar_state(FALSE);
Phillip Lougherd6b1f0d2013-03-26 03:09:27 +00005845 write_filesystem_tables(&sBlk, nopad);
plougher99ac0cc2007-10-29 03:17:10 +00005846
plougher1f413c82005-11-18 00:02:14 +00005847 return 0;
5848}