blob: f8a3ab6268d8915ffb0fd37f916f0165ba97e0d6 [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
plougher16111452010-07-22 05:12:18 +00002 * Create a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
plougher1f413c82005-11-18 00:02:14 +00004 *
Phillip Lougher43cc4282012-01-25 00:25:56 +00005 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
6 * 2012
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
plougher8cb05cd2005-12-11 23:32:35 +000028
plougher1f413c82005-11-18 00:02:14 +000029#include <pwd.h>
30#include <grp.h>
31#include <time.h>
32#include <unistd.h>
33#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000034#include <stddef.h>
plougher1f413c82005-11-18 00:02:14 +000035#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <dirent.h>
40#include <string.h>
plougher1f413c82005-11-18 00:02:14 +000041#include <stdlib.h>
42#include <signal.h>
43#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000044#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000045#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000046#include <pthread.h>
plougher8f8e1a12007-10-18 02:50:21 +000047#include <regex.h>
48#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000049#include <sys/wait.h>
Phillip Lougher94c1fe02012-11-28 03:32:36 +000050#include <limits.h>
Phillip Lougherb22336d2012-12-20 18:44:22 +000051#include <ctype.h>
plougher1f413c82005-11-18 00:02:14 +000052
plougher68853292005-12-27 02:47:04 +000053#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000054#define __BYTE_ORDER BYTE_ORDER
55#define __BIG_ENDIAN BIG_ENDIAN
56#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000057#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000058#else
59#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000060#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000061#endif
62
plougher860c1f32010-08-11 01:37:17 +000063#include "squashfs_fs.h"
plougher860c1f32010-08-11 01:37:17 +000064#include "squashfs_swap.h"
65#include "mksquashfs.h"
66#include "sort.h"
67#include "pseudo.h"
68#include "compressor.h"
69#include "xattr.h"
Phillip Lougher4bcb7f82011-08-28 03:18:26 +010070#include "action.h"
Phillip Lougher2477d0d2012-10-24 21:49:28 +010071#include "error.h"
plougher860c1f32010-08-11 01:37:17 +000072
plougher324978d2006-02-27 04:53:29 +000073int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +000074int fd;
75
76/* filesystem flags for building */
plougher3d7e5182010-12-25 01:49:42 +000077int comp_opts = FALSE;
plougher30281c82010-08-25 05:06:11 +000078int no_xattrs = XATTR_DEF, noX = 0;
plougher1f413c82005-11-18 00:02:14 +000079int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
plougher6d89ac22010-05-19 02:59:23 +000080int noI = 0, noD = 0;
plougher1f288f62009-02-21 03:05:52 +000081int silent = TRUE;
plougher1f413c82005-11-18 00:02:14 +000082long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +000083int exportable = TRUE;
84int progress = TRUE;
plougher8dcc6992007-08-17 19:32:52 +000085int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +000086int old_exclude = TRUE;
87int use_regex = FALSE;
plougher801ba6a2010-02-01 03:12:59 +000088int first_freelist = TRUE;
plougher1f413c82005-11-18 00:02:14 +000089
90/* superblock attributes */
91int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +000092unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +000093int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
94 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +000095
96/* write position within data section */
97long long bytes = 0, total_bytes = 0;
98
99/* in memory directory table - possibly compressed */
100char *directory_table = NULL;
101unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
102
103/* cached directory table */
104char *directory_data_cache = NULL;
105unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
106
107/* in memory inode table - possibly compressed */
108char *inode_table = NULL;
109unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
110
111/* cached inode table */
112char *data_cache = NULL;
113unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
114
plougher0e453652006-11-06 01:49:35 +0000115/* inode lookup table */
116squashfs_inode *inode_lookup_table = NULL;
117
plougher1f413c82005-11-18 00:02:14 +0000118/* in memory directory data */
119#define I_COUNT_SIZE 128
120#define DIR_ENTRIES 32
121#define INODE_HASH_SIZE 65536
122#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
123#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
124
125struct cached_dir_index {
plougher2bd2b722010-12-31 10:52:15 +0000126 struct squashfs_dir_index index;
127 char *name;
plougher1f413c82005-11-18 00:02:14 +0000128};
129
130struct directory {
131 unsigned int start_block;
132 unsigned int size;
133 unsigned char *buff;
134 unsigned char *p;
135 unsigned int entry_count;
136 unsigned char *entry_count_p;
137 unsigned int i_count;
138 unsigned int i_size;
139 struct cached_dir_index *index;
140 unsigned char *index_count_p;
141 unsigned int inode_number;
142};
143
plougher1f413c82005-11-18 00:02:14 +0000144struct inode_info *inode_info[INODE_HASH_SIZE];
145
146/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000147struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000148int dup_files = 0;
149
plougher8f8e1a12007-10-18 02:50:21 +0000150/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000151/* list of exclude dirs/files */
152struct exclude_info {
153 dev_t st_dev;
154 ino_t st_ino;
155};
156
157#define EXCLUDE_SIZE 8192
158int exclude = 0;
159struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000160int old_excluded(char *filename, struct stat *buf);
161
162struct path_entry {
163 char *name;
164 regex_t *preg;
165 struct pathname *paths;
166};
167
168struct pathname {
169 int names;
170 struct path_entry *name;
171};
172
plougherf9039c92007-10-22 03:54:16 +0000173struct pathnames {
174 int count;
175 struct pathname *path[0];
176};
177#define PATHS_ALLOC_SIZE 10
178
179struct pathnames *paths = NULL;
180struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000181struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000182int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000183
184/* fragment block data structures */
185int fragments = 0;
plougher76c64082008-03-08 01:32:23 +0000186
plougher1f413c82005-11-18 00:02:14 +0000187struct fragment {
188 unsigned int index;
189 int offset;
190 int size;
191};
plougher76c64082008-03-08 01:32:23 +0000192
plougher1f413c82005-11-18 00:02:14 +0000193#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000194#define FRAG_INDEX (1LL << 32)
195
plougher8ed84b92010-12-31 10:37:24 +0000196struct squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000197int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000198
plougher1f413c82005-11-18 00:02:14 +0000199/* current inode number for directories and non directories */
Phillip Lougher539c2b12012-07-30 20:14:52 +0100200unsigned int inode_no = 1;
plougherdf70c3e2006-01-27 09:34:13 +0000201unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000202
203/* list of source dirs/files */
204int source = 0;
205char **source_path;
206
207/* list of root directory entries read from original filesystem */
208int old_root_entries = 0;
209struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000210 char *name;
211 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000212};
213struct old_root_entry_info *old_root_entry;
214
215/* in memory file info */
216struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000217 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000218 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000219 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000220 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000221 long long start;
222 unsigned int *block_list;
223 struct file_info *next;
224 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000225 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000226};
227
228/* count of how many times SIGINT or SIGQUIT has been sent */
229int interrupted = 0;
230
plougher875bfef2010-08-12 23:48:41 +0000231/* flag if we're restoring existing filesystem */
232int restoring = 0;
233
plougherfd57dfe2009-03-30 01:17:52 +0000234/* restore orignal filesystem state if appending to existing filesystem is
235 * cancelled */
plougher1f413c82005-11-18 00:02:14 +0000236jmp_buf env;
plougherca2c93f2008-08-15 08:34:57 +0000237char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
plougher1f413c82005-11-18 00:02:14 +0000238
239long long sbytes, stotal_bytes;
240
241unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
plougherca2c93f2008-08-15 08:34:57 +0000242 sdirectory_cache_bytes, sdirectory_compressed_bytes,
plougher1f413c82005-11-18 00:02:14 +0000243 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000244 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000245 sdir_count, sfifo_count, ssock_count, sdup_files;
246int sfragments;
247int restore = 0;
plougher5507dd92006-11-06 00:43:10 +0000248int threads;
plougher1f413c82005-11-18 00:02:14 +0000249
250/* flag whether destination file is a block device */
251int block_device = 0;
252
253/* flag indicating whether files are sorted using sort list(s) */
254int sorted = 0;
255
plougher324978d2006-02-27 04:53:29 +0000256/* save destination file name for deleting on error */
257char *destination_file = NULL;
258
plougher99ac0cc2007-10-29 03:17:10 +0000259/* recovery file for abnormal exit on appending */
Phillip Lougheraf4c9232012-11-15 03:46:28 +0000260char *recovery_file = NULL;
plougher99ac0cc2007-10-29 03:17:10 +0000261int recover = TRUE;
262
ploughereb6eac92008-02-26 01:50:48 +0000263/* struct describing a cache entry passed between threads */
plougher5507dd92006-11-06 00:43:10 +0000264struct file_buffer {
ploughereb6eac92008-02-26 01:50:48 +0000265 struct cache *cache;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100266 struct file_buffer *hash_next;
267 struct file_buffer *hash_prev;
268 struct file_buffer *free_next;
269 struct file_buffer *free_prev;
270 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000271 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000272 long long index;
273 long long block;
plougher0f464442008-03-31 00:27:56 +0000274 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000275 int size;
276 int c_byte;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100277 char keep;
278 char used;
279 char fragment;
280 char error;
Phillip Lougher63f531f2011-09-10 04:03:32 +0100281 char noD;
plougher76c64082008-03-08 01:32:23 +0000282 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000283};
284
ploughereb6eac92008-02-26 01:50:48 +0000285
plougher5507dd92006-11-06 00:43:10 +0000286/* struct describing queues used to pass data between threads */
287struct queue {
288 int size;
289 int readp;
290 int writep;
291 pthread_mutex_t mutex;
292 pthread_cond_t empty;
293 pthread_cond_t full;
294 void **data;
295};
296
plougher1b899fc2008-08-07 01:24:06 +0000297
298/* in memory uid tables */
299#define ID_ENTRIES 256
300#define ID_HASH(id) (id & (ID_ENTRIES - 1))
301#define ISA_UID 1
302#define ISA_GID 2
303struct id {
304 unsigned int id;
305 int index;
306 char flags;
307 struct id *next;
plougher5507dd92006-11-06 00:43:10 +0000308};
plougher1b899fc2008-08-07 01:24:06 +0000309struct id *id_hash_table[ID_ENTRIES];
310struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
311unsigned int uid_count = 0, guid_count = 0;
312unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000313
ploughereb6eac92008-02-26 01:50:48 +0000314struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougherfd57dfe2009-03-30 01:17:52 +0000315struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
316 *to_frag;
Phillip Lougher3b89ee82012-10-18 23:55:37 +0100317pthread_t *thread, *deflator_thread, *frag_deflator_thread;
plougher5507dd92006-11-06 00:43:10 +0000318pthread_mutex_t fragment_mutex;
319pthread_cond_t fragment_waiting;
320pthread_mutex_t pos_mutex;
321
322/* user options that control parallelisation */
323int processors = -1;
324/* default size of output buffer in Mbytes */
325#define WRITER_BUFFER_DEFAULT 512
326/* default size of input buffer in Mbytes */
327#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000328/* default size of fragment buffer in Mbytes */
329#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000330int writer_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000331
plougherc5d59872010-11-22 01:36:01 +0000332/* compression operations */
ploughera175ce22009-07-30 04:43:27 +0000333static struct compressor *comp;
plougherc5d59872010-11-22 01:36:01 +0000334int compressor_opts_parsed = 0;
plougher13fdddf2010-11-24 01:23:41 +0000335void *stream = NULL;
plougher7b8ee502009-07-29 07:54:30 +0000336
plougher860c1f32010-08-11 01:37:17 +0000337/* xattr stats */
338unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
339
plougher49b57a92009-03-31 03:23:05 +0000340char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000341void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
342 int type);
plougher64e83fd2010-12-31 21:21:26 +0000343extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
ploughera175ce22009-07-30 04:43:27 +0000344 char *source);
plougherfd57dfe2009-03-30 01:17:52 +0000345extern long long read_filesystem(char *root_name, int fd,
plougher64e83fd2010-12-31 21:21:26 +0000346 struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
plougherfd57dfe2009-03-30 01:17:52 +0000347 char **cdirectory_table, char **directory_data_cache,
348 unsigned int *last_directory_block, unsigned int *inode_dir_offset,
349 unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
350 unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
351 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
352 long long *uncompressed_file, unsigned int *uncompressed_inode,
plougher50b31762009-03-31 04:14:46 +0000353 unsigned int *uncompressed_directory,
354 unsigned int *inode_dir_inode_number,
355 unsigned int *inode_dir_parent_inode,
plougherfd57dfe2009-03-30 01:17:52 +0000356 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher8ed84b92010-12-31 10:37:24 +0000357 struct squashfs_fragment_entry **fragment_table,
plougherfd57dfe2009-03-30 01:17:52 +0000358 squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000359extern int read_sort_file(char *filename, int source, char *source_path[]);
360extern void sort_files_and_write(struct dir_info *dir);
plougherfd57dfe2009-03-30 01:17:52 +0000361struct file_info *duplicate(long long file_size, long long bytes,
362 unsigned int **block_list, long long *start, struct fragment **fragment,
363 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
364 unsigned short fragment_checksum, int checksum_flag);
Phillip Lougherb38c1722012-02-09 23:26:19 +0000365struct dir_info *dir_scan1(char *, char *, struct pathnames *,
Phillip Lougher494479f2012-02-03 15:45:41 +0000366 struct dir_ent *(_readdir)(struct dir_info *), int);
Phillip Lougher24eeb772012-10-13 01:56:24 +0100367void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
Phillip Lougher23d83622012-10-14 02:35:22 +0100368void dir_scan3(struct dir_info *root, struct dir_info *dir);
369void dir_scan4(struct dir_info *dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +0000370void dir_scan5(struct dir_info *dir);
371void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000372struct file_info *add_non_dup(long long file_size, long long bytes,
373 unsigned int *block_list, long long start, struct fragment *fragment,
374 unsigned short checksum, unsigned short fragment_checksum,
375 int checksum_flag);
plougher1d1c6bb2010-07-21 03:03:13 +0000376extern int generate_file_priorities(struct dir_info *dir, int priority,
plougherfd57dfe2009-03-30 01:17:52 +0000377 struct stat *buf);
plougher5507dd92006-11-06 00:43:10 +0000378extern struct priority_entry *priority_list[65536];
ploughera0a49c32010-08-11 01:47:59 +0000379long long generic_write_table(int, void *, int, void *, int);
plougherca61d1c2010-07-20 18:32:32 +0000380void restorefs();
Phillip Lougher1eae83d2012-09-26 02:12:45 +0100381struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
plougher5507dd92006-11-06 00:43:10 +0000382
383
Phillip Lougher838d2962012-10-23 03:29:30 +0100384void prep_exit_mksquashfs()
385{
386 if(restore)
387 restorefs();
388 if(delete && destination_file && !block_device)
389 unlink(destination_file);
390 exit(1);
391}
392
393
plougher5507dd92006-11-06 00:43:10 +0000394struct queue *queue_init(int size)
395{
396 struct queue *queue = malloc(sizeof(struct queue));
397
398 if(queue == NULL)
plougherca61d1c2010-07-20 18:32:32 +0000399 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000400
plougher0d55d9e2010-12-16 04:50:21 +0000401 queue->data = malloc(sizeof(void *) * (size + 1));
402 if(queue->data == NULL) {
plougher5507dd92006-11-06 00:43:10 +0000403 free(queue);
plougherca61d1c2010-07-20 18:32:32 +0000404 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000405 }
406
407 queue->size = size + 1;
408 queue->readp = queue->writep = 0;
409 pthread_mutex_init(&queue->mutex, NULL);
410 pthread_cond_init(&queue->empty, NULL);
411 pthread_cond_init(&queue->full, NULL);
412
413 return queue;
plougherca61d1c2010-07-20 18:32:32 +0000414
415failed:
416 BAD_ERROR("Out of memory in queue_init\n");
plougher5507dd92006-11-06 00:43:10 +0000417}
418
419
420void queue_put(struct queue *queue, void *data)
421{
422 int nextp;
423
424 pthread_mutex_lock(&queue->mutex);
425
426 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
427 pthread_cond_wait(&queue->full, &queue->mutex);
428
429 queue->data[queue->writep] = data;
430 queue->writep = nextp;
431 pthread_cond_signal(&queue->empty);
432 pthread_mutex_unlock(&queue->mutex);
433}
434
435
436void *queue_get(struct queue *queue)
437{
438 void *data;
439 pthread_mutex_lock(&queue->mutex);
440
441 while(queue->readp == queue->writep)
442 pthread_cond_wait(&queue->empty, &queue->mutex);
443
444 data = queue->data[queue->readp];
445 queue->readp = (queue->readp + 1) % queue->size;
446 pthread_cond_signal(&queue->full);
447 pthread_mutex_unlock(&queue->mutex);
448
449 return data;
450}
451
plougher1f413c82005-11-18 00:02:14 +0000452
ploughereb6eac92008-02-26 01:50:48 +0000453/* Cache status struct. Caches are used to keep
454 track of memory buffers passed between different threads */
455struct cache {
456 int max_buffers;
457 int count;
458 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000459 pthread_mutex_t mutex;
460 pthread_cond_t wait_for_free;
461 struct file_buffer *free_list;
462 struct file_buffer *hash_table[65536];
463};
464
465
plougher2ea89142008-03-11 01:34:19 +0000466#define INSERT_LIST(NAME, TYPE) \
467void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
468 if(*list) { \
469 entry->NAME##_next = *list; \
470 entry->NAME##_prev = (*list)->NAME##_prev; \
471 (*list)->NAME##_prev->NAME##_next = entry; \
472 (*list)->NAME##_prev = entry; \
473 } else { \
474 *list = entry; \
475 entry->NAME##_prev = entry->NAME##_next = entry; \
476 } \
477}
478
479
480#define REMOVE_LIST(NAME, TYPE) \
481void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
482 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
483 /* only this entry in the list */ \
484 *list = NULL; \
485 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
486 /* more than one entry in the list */ \
487 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
488 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
489 if(*list == entry) \
490 *list = entry->NAME##_next; \
491 } \
492 entry->NAME##_prev = entry->NAME##_next = NULL; \
493}
494
495
496#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000497
498
499/* Called with the cache mutex held */
500void insert_hash_table(struct cache *cache, struct file_buffer *entry)
501{
502 int hash = CALCULATE_HASH(entry->index);
503
504 entry->hash_next = cache->hash_table[hash];
505 cache->hash_table[hash] = entry;
506 entry->hash_prev = NULL;
507 if(entry->hash_next)
508 entry->hash_next->hash_prev = entry;
509}
510
511
512/* Called with the cache mutex held */
513void remove_hash_table(struct cache *cache, struct file_buffer *entry)
514{
515 if(entry->hash_prev)
516 entry->hash_prev->hash_next = entry->hash_next;
517 else
plougher50b31762009-03-31 04:14:46 +0000518 cache->hash_table[CALCULATE_HASH(entry->index)] =
519 entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000520 if(entry->hash_next)
521 entry->hash_next->hash_prev = entry->hash_prev;
522
523 entry->hash_prev = entry->hash_next = NULL;
524}
525
526
527/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000528INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000529
530/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000531REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000532
533
534struct cache *cache_init(int buffer_size, int max_buffers)
535{
536 struct cache *cache = malloc(sizeof(struct cache));
537
538 if(cache == NULL)
plougher9ca649c2010-07-21 00:46:11 +0000539 BAD_ERROR("Out of memory in cache_init\n");
ploughereb6eac92008-02-26 01:50:48 +0000540
541 cache->max_buffers = max_buffers;
542 cache->buffer_size = buffer_size;
543 cache->count = 0;
544 cache->free_list = NULL;
545 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000546 pthread_mutex_init(&cache->mutex, NULL);
547 pthread_cond_init(&cache->wait_for_free, NULL);
548
549 return cache;
550}
551
552
553struct file_buffer *cache_lookup(struct cache *cache, long long index)
554{
555 /* Lookup block in the cache, if found return with usage count
556 * incremented, if not found return NULL */
557 int hash = CALCULATE_HASH(index);
558 struct file_buffer *entry;
559
560 pthread_mutex_lock(&cache->mutex);
561
562 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
563 if(entry->index == index)
564 break;
565
566 if(entry) {
567 /* found the block in the cache, increment used count and
568 * if necessary remove from free list so it won't disappear
569 */
570 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000571 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000572 }
573
574 pthread_mutex_unlock(&cache->mutex);
575
576 return entry;
577}
578
579
plougher76c64082008-03-08 01:32:23 +0000580struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000581{
582 /* Get a free block out of the cache indexed on index. */
583 struct file_buffer *entry;
584
585 pthread_mutex_lock(&cache->mutex);
586
plougher76c64082008-03-08 01:32:23 +0000587 while(1) {
588 /* first try to get a block from the free list */
plougher801ba6a2010-02-01 03:12:59 +0000589 if(first_freelist && cache->free_list) {
plougher76c64082008-03-08 01:32:23 +0000590 /* a block on the free_list is a "keep" block */
591 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000592 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000593 remove_hash_table(cache, entry);
594 break;
plougher801ba6a2010-02-01 03:12:59 +0000595 } else if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000596 /* next try to allocate new block */
plougherfd57dfe2009-03-30 01:17:52 +0000597 entry = malloc(sizeof(struct file_buffer) +
598 cache->buffer_size);
plougher76c64082008-03-08 01:32:23 +0000599 if(entry == NULL)
600 goto failed;
601 entry->cache = cache;
602 entry->free_prev = entry->free_next = NULL;
603 cache->count ++;
604 break;
plougher801ba6a2010-02-01 03:12:59 +0000605 } else if(!first_freelist && cache->free_list) {
plougher2ea89142008-03-11 01:34:19 +0000606 /* a block on the free_list is a "keep" block */
607 entry = cache->free_list;
608 remove_free_list(&cache->free_list, entry);
609 remove_hash_table(cache, entry);
610 break;
plougher801ba6a2010-02-01 03:12:59 +0000611 } else
plougher76c64082008-03-08 01:32:23 +0000612 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000613 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000614 }
615
plougher76c64082008-03-08 01:32:23 +0000616 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000617 entry->used = 1;
618 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000619 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000620 if(keep) {
621 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000622 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000623 }
ploughereb6eac92008-02-26 01:50:48 +0000624 pthread_mutex_unlock(&cache->mutex);
625
626 return entry;
627
628failed:
629 pthread_mutex_unlock(&cache->mutex);
ploughercc6896d2010-07-21 00:56:25 +0000630 BAD_ERROR("Out of memory in cache_get\n");
ploughereb6eac92008-02-26 01:50:48 +0000631}
632
ploughereb6eac92008-02-26 01:50:48 +0000633
plougher0f464442008-03-31 00:27:56 +0000634void cache_rehash(struct file_buffer *entry, long long index)
635{
636 struct cache *cache = entry->cache;
637
638 pthread_mutex_lock(&cache->mutex);
639 if(entry->keep)
640 remove_hash_table(cache, entry);
641 entry->keep = TRUE;
642 entry->index = index;
643 insert_hash_table(cache, entry);
644 pthread_mutex_unlock(&cache->mutex);
645}
646
647
ploughereb6eac92008-02-26 01:50:48 +0000648void cache_block_put(struct file_buffer *entry)
649{
plougher76c64082008-03-08 01:32:23 +0000650 struct cache *cache;
651
ploughereb6eac92008-02-26 01:50:48 +0000652 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000653 * can be reused and if a keep block put onto the free list. As keep
plougher50b31762009-03-31 04:14:46 +0000654 * blocks remain accessible via the hash table they can be found
655 * getting a new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000656
657 if(entry == NULL)
658 return;
659
plougher76c64082008-03-08 01:32:23 +0000660 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000661
plougher76c64082008-03-08 01:32:23 +0000662 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000663
664 entry->used --;
665 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000666 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000667 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000668 else {
669 free(entry);
670 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000671 }
plougher76c64082008-03-08 01:32:23 +0000672
673 /* One or more threads may be waiting on this block */
674 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000675 }
676
plougher76c64082008-03-08 01:32:23 +0000677 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000678}
679
680
plougher50b31762009-03-31 04:14:46 +0000681#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
682 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000683
684
plougher5507dd92006-11-06 00:43:10 +0000685inline void waitforthread(int i)
686{
687 TRACE("Waiting for thread %d\n", i);
688 while(thread[i] != 0)
689 sched_yield();
690}
691
692
plougher1f413c82005-11-18 00:02:14 +0000693void restorefs()
694{
plougher5507dd92006-11-06 00:43:10 +0000695 int i;
696
plougher02bc3bc2007-02-25 12:12:01 +0000697 if(thread == NULL || thread[0] == 0)
698 return;
699
plougher875bfef2010-08-12 23:48:41 +0000700 if(restoring++)
701 /*
plougher5b290d22010-08-12 23:52:21 +0000702 * Recursive failure when trying to restore filesystem!
703 * Nothing to do except to exit, otherwise we'll just appear
plougher875bfef2010-08-12 23:48:41 +0000704 * to hang. The user should be able to restore from the
plougher5b290d22010-08-12 23:52:21 +0000705 * recovery file (which is why it was added, in case of
706 * catastrophic failure in Mksquashfs)
plougher875bfef2010-08-12 23:48:41 +0000707 */
708 exit(1);
709
plougher1f413c82005-11-18 00:02:14 +0000710 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000711
plougher91fbb302008-05-06 02:29:36 +0000712 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000713 if(thread[i])
714 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000715 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000716 waitforthread(i);
717 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000718 bytes = sbytes;
719 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000720 memcpy(directory_data_cache, sdirectory_data_cache,
721 sdirectory_cache_bytes);
722 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000723 inode_bytes = sinode_bytes;
724 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000725 memcpy(directory_table + directory_bytes, sdirectory_compressed,
726 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000727 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000728 total_bytes = stotal_bytes;
729 total_inode_bytes = stotal_inode_bytes;
730 total_directory_bytes = stotal_directory_bytes;
731 inode_count = sinode_count;
732 file_count = sfile_count;
733 sym_count = ssym_count;
734 dev_count = sdev_count;
735 dir_count = sdir_count;
736 fifo_count = sfifo_count;
737 sock_count = ssock_count;
738 dup_files = sdup_files;
739 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000740 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000741 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000742 longjmp(env, 1);
743}
744
745
746void sighandler()
747{
plougher5507dd92006-11-06 00:43:10 +0000748 if(++interrupted > 2)
749 return;
750 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000751 restorefs();
752 else {
753 ERROR("Interrupting will restore original filesystem!\n");
754 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000755 }
756}
757
758
plougher324978d2006-02-27 04:53:29 +0000759void sighandler2()
760{
761 EXIT_MKSQUASHFS();
762}
763
764
plougher5507dd92006-11-06 00:43:10 +0000765void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000766{
plougher5507dd92006-11-06 00:43:10 +0000767 int i;
768 sigset_t sigmask;
769 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000770
plougher5507dd92006-11-06 00:43:10 +0000771 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
772 thread[i] = (pthread_t) 0;
773
plougher07966f72007-11-14 10:54:45 +0000774 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000775
776 sigemptyset(&sigmask);
777 sigaddset(&sigmask, SIGINT);
778 sigaddset(&sigmask, SIGQUIT);
779 sigaddset(&sigmask, SIGUSR1);
780 while(1) {
781 sigsuspend(&sigmask);
782 TRACE("After wait in sigusr1_handler :(\n");
783 }
784}
785
786
plougher13fdddf2010-11-24 01:23:41 +0000787int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000788 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000789{
plougher7b8ee502009-07-29 07:54:30 +0000790 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000791
plougher7b8ee502009-07-29 07:54:30 +0000792 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000793 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
794 &error);
plougher7b8ee502009-07-29 07:54:30 +0000795 if(c_byte == -1)
796 BAD_ERROR("mangle2:: %s compress failed with error "
797 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000798 }
799
plougher7b8ee502009-07-29 07:54:30 +0000800 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000801 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000802 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
803 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000804 }
805
plougher7b8ee502009-07-29 07:54:30 +0000806 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000807}
808
809
plougher7b8ee502009-07-29 07:54:30 +0000810int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000811 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000812{
plougher13fdddf2010-11-24 01:23:41 +0000813 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000814 data_block);
plougher5507dd92006-11-06 00:43:10 +0000815}
816
817
plougherac28cd12010-02-24 02:25:03 +0000818void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000819{
820 int data_space;
821 unsigned short c_byte;
822
823 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000824 if((inode_size - inode_bytes) <
825 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000826 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000827 (SQUASHFS_METADATA_SIZE << 1) + 2);
plougher1eb2a662010-07-26 17:30:50 +0000828 if(it == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000829 goto failed;
830 }
plougher1eb2a662010-07-26 17:30:50 +0000831 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000832 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
833 }
834
plougherfd57dfe2009-03-30 01:17:52 +0000835 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000836 data_cache, SQUASHFS_METADATA_SIZE,
837 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000838 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000839 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000840 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
841 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000842 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000843 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000844 cache_bytes -= SQUASHFS_METADATA_SIZE;
845 }
846
847 data_space = (cache_size - cache_bytes);
848 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000849 int realloc_size = cache_size == 0 ?
850 ((req_size + SQUASHFS_METADATA_SIZE) &
851 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
852 data_space;
plougher1f413c82005-11-18 00:02:14 +0000853
plougher17248ca2010-07-27 00:24:35 +0000854 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000855 realloc_size);
plougher17248ca2010-07-27 00:24:35 +0000856 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000857 goto failed;
858 }
859 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000860 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000861 }
862
863 cache_bytes += req_size;
864
plougherac28cd12010-02-24 02:25:03 +0000865 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000866
867failed:
868 BAD_ERROR("Out of memory in inode table reallocation!\n");
869}
870
871
plougher8a8c4102009-03-29 22:28:49 +0000872int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000873{
874 int res, count;
875
876 for(count = 0; count < bytes; count += res) {
877 res = read(fd, buff + count, bytes - count);
878 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000879 if(res == 0)
880 goto bytes_read;
881 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000882 ERROR("Read failed because %s\n",
883 strerror(errno));
884 return -1;
885 } else
886 res = 0;
887 }
888 }
889
890bytes_read:
891 return count;
892}
893
894
plougher3306cb22010-06-18 04:22:44 +0000895int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000896{
897 off_t off = byte;
898
plougher1d065e92010-06-18 03:58:27 +0000899 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000900 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000901
plougher5507dd92006-11-06 00:43:10 +0000902 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000903 if(lseek(fd, off, SEEK_SET) == -1) {
904 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000905 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000906 goto failed;
907 }
plougher1f413c82005-11-18 00:02:14 +0000908
plougher1d065e92010-06-18 03:58:27 +0000909 if(read_bytes(fd, buff, bytes) < bytes) {
910 ERROR("Read on destination failed\n");
911 goto failed;
912 }
913
plougher5507dd92006-11-06 00:43:10 +0000914 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000915 return 1;
916
917failed:
918 pthread_mutex_unlock(&pos_mutex);
919 return 0;
plougher1f413c82005-11-18 00:02:14 +0000920}
921
922
plougher628e7682009-03-29 22:12:24 +0000923int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000924{
925 int res, count;
926
927 for(count = 0; count < bytes; count += res) {
928 res = write(fd, buff + count, bytes - count);
929 if(res == -1) {
930 if(errno != EINTR) {
931 ERROR("Write failed because %s\n",
932 strerror(errno));
933 return -1;
934 }
935 res = 0;
936 }
937 }
938
939 return 0;
940}
941
942
plougher29e2ace2010-12-31 08:50:00 +0000943void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000944{
945 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000946
plougher875bfef2010-08-12 23:48:41 +0000947 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000948 pthread_mutex_lock(&pos_mutex);
949
plougher91fbb302008-05-06 02:29:36 +0000950 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +0000951 BAD_ERROR("Lseek on destination failed because %s\n",
952 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +0000953
plougher0dd6f122009-03-29 21:43:57 +0000954 if(write_bytes(fd, buff, bytes) == -1)
955 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +0000956
plougher875bfef2010-08-12 23:48:41 +0000957 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000958 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000959}
960
961
962long long write_inodes()
963{
964 unsigned short c_byte;
965 int avail_bytes;
966 char *datap = data_cache;
967 long long start_bytes = bytes;
968
969 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000970 if(inode_size - inode_bytes <
971 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +0000972 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000973 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +0000974 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +0000975 BAD_ERROR("Out of memory in inode table "
976 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +0000977 }
978 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +0000979 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000980 }
plougherfd57dfe2009-03-30 01:17:52 +0000981 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
982 SQUASHFS_METADATA_SIZE : cache_bytes;
983 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
984 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000985 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000986 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000987 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
988 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +0000989 datap += avail_bytes;
990 cache_bytes -= avail_bytes;
991 }
992
plougher29e2ace2010-12-31 08:50:00 +0000993 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +0000994 bytes += inode_bytes;
995
996 return start_bytes;
997}
998
999
1000long long write_directories()
1001{
1002 unsigned short c_byte;
1003 int avail_bytes;
1004 char *directoryp = directory_data_cache;
1005 long long start_bytes = bytes;
1006
1007 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001008 if(directory_size - directory_bytes <
1009 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001010 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001011 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1012 + 2));
plougher79d665a2010-07-27 00:19:23 +00001013 if(dt == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001014 BAD_ERROR("Out of memory in directory table "
1015 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001016 }
1017 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001018 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001019 }
plougherfd57dfe2009-03-30 01:17:52 +00001020 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1021 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001022 c_byte = mangle(directory_table + directory_bytes +
1023 BLOCK_OFFSET, directoryp, avail_bytes,
1024 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001025 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1026 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001027 SQUASHFS_SWAP_SHORTS(&c_byte,
1028 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001029 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1030 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001031 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001032 directoryp += avail_bytes;
1033 directory_cache_bytes -= avail_bytes;
1034 }
plougher29e2ace2010-12-31 08:50:00 +00001035 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +00001036 bytes += directory_bytes;
1037
1038 return start_bytes;
1039}
1040
1041
plougher1b899fc2008-08-07 01:24:06 +00001042long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001043{
plougher1b899fc2008-08-07 01:24:06 +00001044 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001045 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001046 int i;
1047
plougher1b899fc2008-08-07 01:24:06 +00001048 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001049 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001050 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001051 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001052 }
1053
ploughera0a49c32010-08-11 01:47:59 +00001054 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001055}
1056
1057
plougher1b899fc2008-08-07 01:24:06 +00001058struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001059{
plougher1b899fc2008-08-07 01:24:06 +00001060 int hash = ID_HASH(id);
1061 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001062
plougher1b899fc2008-08-07 01:24:06 +00001063 for(; entry; entry = entry->next)
1064 if(entry->id == id)
1065 break;
plougher1f413c82005-11-18 00:02:14 +00001066
plougher1b899fc2008-08-07 01:24:06 +00001067 return entry;
plougher1f413c82005-11-18 00:02:14 +00001068}
1069
1070
plougher1b899fc2008-08-07 01:24:06 +00001071struct id *create_id(unsigned int id)
1072{
1073 int hash = ID_HASH(id);
1074 struct id *entry = malloc(sizeof(struct id));
1075 if(entry == NULL)
1076 BAD_ERROR("Out of memory in create_id\n");
1077 entry->id = id;
1078 entry->index = id_count ++;
1079 entry->flags = 0;
1080 entry->next = id_hash_table[hash];
1081 id_hash_table[hash] = entry;
1082 id_table[entry->index] = entry;
1083 return entry;
1084}
1085
1086
1087unsigned int get_uid(unsigned int uid)
1088{
1089 struct id *entry = get_id(uid);
1090
1091 if(entry == NULL) {
1092 if(id_count == SQUASHFS_IDS)
1093 BAD_ERROR("Out of uids!\n");
1094 entry = create_id(uid);
1095 }
1096
1097 if((entry->flags & ISA_UID) == 0) {
1098 entry->flags |= ISA_UID;
1099 uid_count ++;
1100 }
1101
1102 return entry->index;
1103}
1104
1105
1106unsigned int get_guid(unsigned int guid)
1107{
1108 struct id *entry = get_id(guid);
1109
1110 if(entry == NULL) {
1111 if(id_count == SQUASHFS_IDS)
1112 BAD_ERROR("Out of gids!\n");
1113 entry = create_id(guid);
1114 }
1115
1116 if((entry->flags & ISA_GID) == 0) {
1117 entry->flags |= ISA_GID;
1118 guid_count ++;
1119 }
1120
1121 return entry->index;
1122}
1123
1124
Phillip Lougher5ef51692012-11-19 03:35:39 +00001125#define ALLOC_SIZE 128
Phillip Lougher494479f2012-02-03 15:45:41 +00001126
Phillip Lougher5ef51692012-11-19 03:35:39 +00001127char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size)
1128{
1129 if(pathname == NULL) {
1130 pathname = malloc(ALLOC_SIZE);
1131 if(pathname == NULL)
1132 BAD_ERROR("Out of memory in pathname\n");
1133 }
1134
1135 for(;;) {
1136 int res = snprintf(pathname, *size, "%s/%s",
1137 dir_ent->our_dir->pathname,
1138 dir_ent->source_name ? : dir_ent->name);
1139
1140 if(res < 0)
1141 BAD_ERROR("snprintf failed in pathname\n");
1142 else if(res >= *size) {
1143 /*
1144 * pathname is too small to contain the result, so
1145 * increase it and try again
1146 */
1147 *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1148 pathname = realloc(pathname, *size);
1149 if(pathname == NULL)
1150 BAD_ERROR("Out of memory in pathname\n");
1151 } else
1152 break;
1153 }
Phillip Lougher494479f2012-02-03 15:45:41 +00001154
1155 return pathname;
1156}
1157
1158
1159char *pathname(struct dir_ent *dir_ent)
1160{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001161 static char *pathname = NULL;
1162 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001163
Phillip Lougher5ef51692012-11-19 03:35:39 +00001164 if (dir_ent->nonstandard_pathname)
1165 return dir_ent->nonstandard_pathname;
1166
1167 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001168}
1169
1170
1171char *pathname_reader(struct dir_ent *dir_ent)
1172{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001173 static char *pathname = NULL;
1174 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001175
Phillip Lougher5ef51692012-11-19 03:35:39 +00001176 if (dir_ent->nonstandard_pathname)
1177 return dir_ent->nonstandard_pathname;
1178
1179 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001180}
1181
1182
Phillip Lougherb38c1722012-02-09 23:26:19 +00001183char *subpathname(struct dir_ent *dir_ent)
1184{
Phillip Lougherd457ed32012-11-19 01:36:56 +00001185 static char *subpath = NULL;
1186 static int size = ALLOC_SIZE;
1187 int res;
Phillip Lougherb38c1722012-02-09 23:26:19 +00001188
Phillip Lougherd457ed32012-11-19 01:36:56 +00001189 if(subpath == NULL) {
1190 subpath = malloc(ALLOC_SIZE);
1191 if(subpath == NULL)
1192 BAD_ERROR("Out of memory in subpathname\n");
1193 }
1194
1195 for(;;) {
1196 if(dir_ent->our_dir->subpath[0] != '\0')
1197 res = snprintf(subpath, size, "%s/%s",
1198 dir_ent->our_dir->subpath, dir_ent->name);
1199 else
1200 res = snprintf(subpath, size, "/%s", dir_ent->name);
1201
1202 if(res < 0)
1203 BAD_ERROR("snprintf failed in subpathname\n");
1204 else if(res >= size) {
1205 /*
1206 * subpath is too small to contain the result, so
1207 * increase it and try again
1208 */
1209 size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1210 subpath = realloc(subpath, size);
1211 if(subpath == NULL)
1212 BAD_ERROR("Out of memory in subpathname\n");
1213 } else
1214 break;
Phillip Lougher90e08252012-10-05 04:33:35 +01001215 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00001216
1217 return subpath;
1218}
1219
1220
Phillip Lougher539c2b12012-07-30 20:14:52 +01001221inline unsigned int get_inode_no(struct inode_info *inode)
Phillip Lougher53cef742012-07-25 05:12:50 +01001222{
Phillip Lougher539c2b12012-07-30 20:14:52 +01001223 return inode->inode_number;
Phillip Lougher53cef742012-07-25 05:12:50 +01001224}
1225
1226
Phillip Lougher539c2b12012-07-30 20:14:52 +01001227inline unsigned int get_parent_no(struct dir_info *dir)
Phillip Lougher53cef742012-07-25 05:12:50 +01001228{
Phillip Lougher1eae83d2012-09-26 02:12:45 +01001229 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
Phillip Lougher53cef742012-07-25 05:12:50 +01001230}
1231
1232
plougher3c6bdb52010-05-01 02:30:59 +00001233int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1234 struct dir_ent *dir_ent, int type, long long byte_size,
1235 long long start_block, unsigned int offset, unsigned int *block_list,
1236 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001237{
1238 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +00001239 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +00001240 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +00001241 void *inode;
Phillip Lougher494479f2012-02-03 15:45:41 +00001242 char *filename = pathname(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001243 int nlink = dir_ent->inode->nlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001244 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001245
ploughere6e0e1b2010-05-12 17:17:06 +00001246 switch(type) {
1247 case SQUASHFS_FILE_TYPE:
1248 if(dir_ent->inode->nlink > 1 ||
1249 byte_size >= (1LL << 32) ||
1250 start_block >= (1LL << 32) ||
1251 sparse || IS_XATTR(xattr))
1252 type = SQUASHFS_LREG_TYPE;
1253 break;
1254 case SQUASHFS_DIR_TYPE:
1255 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1256 type = SQUASHFS_LDIR_TYPE;
1257 break;
1258 case SQUASHFS_SYMLINK_TYPE:
1259 if(IS_XATTR(xattr))
1260 type = SQUASHFS_LSYMLINK_TYPE;
1261 break;
1262 case SQUASHFS_BLKDEV_TYPE:
1263 if(IS_XATTR(xattr))
1264 type = SQUASHFS_LBLKDEV_TYPE;
1265 break;
1266 case SQUASHFS_CHRDEV_TYPE:
1267 if(IS_XATTR(xattr))
1268 type = SQUASHFS_LCHRDEV_TYPE;
1269 break;
plougherc5d69322010-05-12 19:28:38 +00001270 case SQUASHFS_FIFO_TYPE:
1271 if(IS_XATTR(xattr))
1272 type = SQUASHFS_LFIFO_TYPE;
1273 break;
1274 case SQUASHFS_SOCKET_TYPE:
1275 if(IS_XATTR(xattr))
1276 type = SQUASHFS_LSOCKET_TYPE;
1277 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001278 }
1279
plougher1f413c82005-11-18 00:02:14 +00001280 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001281 base->uid = get_uid((unsigned int) global_uid == -1 ?
1282 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001283 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001284 base->guid = get_guid((unsigned int) global_gid == -1 ?
1285 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001286 base->mtime = buf->st_mtime;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001287 base->inode_number = get_inode_no(dir_ent->inode);
plougher1f413c82005-11-18 00:02:14 +00001288
1289 if(type == SQUASHFS_FILE_TYPE) {
1290 int i;
plougher8701ed62010-12-31 20:38:38 +00001291 struct squashfs_reg_inode_header *reg = &inode_header.reg;
1292 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001293
1294 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001295 reg->file_size = byte_size;
1296 reg->start_block = start_block;
1297 reg->fragment = fragment->index;
1298 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001299 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1300 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001301 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1302 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001303 start_block, offset, fragment->index, fragment->offset,
1304 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001305 for(i = 0; i < offset; i++)
1306 TRACE("Block %d, size %d\n", i, block_list[i]);
1307 }
1308 else if(type == SQUASHFS_LREG_TYPE) {
1309 int i;
plougher1e6ac4a2010-12-31 20:42:02 +00001310 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1311 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001312
1313 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001314 reg->nlink = nlink;
1315 reg->file_size = byte_size;
1316 reg->start_block = start_block;
1317 reg->fragment = fragment->index;
1318 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001319 if(sparse && sparse >= byte_size)
1320 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001321 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001322 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001323 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1324 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001325 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001326 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1327 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001328 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001329 for(i = 0; i < offset; i++)
1330 TRACE("Block %d, size %d\n", i, block_list[i]);
1331 }
1332 else if(type == SQUASHFS_LDIR_TYPE) {
1333 int i;
1334 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +00001335 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001336 struct cached_dir_index *index = dir_in->index;
1337 unsigned int i_count = dir_in->i_count;
1338 unsigned int i_size = dir_in->i_size;
1339
1340 if(byte_size >= 1 << 27)
1341 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1342
1343 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001344 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001345 dir->nlink = dir_ent->dir->directory_count + 2;
1346 dir->file_size = byte_size;
1347 dir->offset = offset;
1348 dir->start_block = start_block;
1349 dir->i_count = i_count;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001350 dir->parent_inode = get_parent_no(dir_ent->our_dir);
ploughere6e0e1b2010-05-12 17:17:06 +00001351 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001352
plougherac28cd12010-02-24 02:25:03 +00001353 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +00001354 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001355 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001356 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +00001357 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +00001358 memcpy(p, index[i].name, index[i].index.size + 1);
1359 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001360 }
plougher50b31762009-03-31 04:14:46 +00001361 TRACE("Long directory inode, file_size %lld, start_block "
1362 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1363 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001364 }
1365 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +00001366 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +00001367
1368 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001369 dir->nlink = dir_ent->dir->directory_count + 2;
1370 dir->file_size = byte_size;
1371 dir->offset = offset;
1372 dir->start_block = start_block;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001373 dir->parent_inode = get_parent_no(dir_ent->our_dir);
plougherac28cd12010-02-24 02:25:03 +00001374 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001375 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001376 "offset 0x%x, nlink %d\n", byte_size, start_block,
1377 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001378 }
1379 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +00001380 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001381 unsigned int major = major(buf->st_rdev);
1382 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001383
plougher5b398502008-10-04 23:22:03 +00001384 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001385 ERROR("Major %d out of range in device node %s, "
1386 "truncating to %d\n", major, filename,
1387 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001388 major &= 0xfff;
1389 }
1390 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001391 ERROR("Minor %d out of range in device node %s, "
1392 "truncating to %d\n", minor, filename,
1393 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001394 minor &= 0xfffff;
1395 }
plougher1f413c82005-11-18 00:02:14 +00001396 inode = get_inode(sizeof(*dev));
1397 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001398 dev->rdev = (major << 8) | (minor & 0xff) |
1399 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001400 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001401 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001402 }
ploughere6e0e1b2010-05-12 17:17:06 +00001403 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001404 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001405 unsigned int major = major(buf->st_rdev);
1406 unsigned int minor = minor(buf->st_rdev);
1407
1408 if(major > 0xfff) {
1409 ERROR("Major %d out of range in device node %s, "
1410 "truncating to %d\n", major, filename,
1411 major & 0xfff);
1412 major &= 0xfff;
1413 }
1414 if(minor > 0xfffff) {
1415 ERROR("Minor %d out of range in device node %s, "
1416 "truncating to %d\n", minor, filename,
1417 minor & 0xfffff);
1418 minor &= 0xfffff;
1419 }
1420 inode = get_inode(sizeof(*dev));
1421 dev->nlink = nlink;
1422 dev->rdev = (major << 8) | (minor & 0xff) |
1423 ((minor & ~0xff) << 12);
1424 dev->xattr = xattr;
1425 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1426 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1427 }
plougher1f413c82005-11-18 00:02:14 +00001428 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001429 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001430 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001431 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001432 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001433
plougher5cf38b82010-12-16 04:55:32 +00001434 byte = readlink(filename, buff, 65536);
1435 if(byte == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001436 ERROR("Failed to read symlink %s, creating empty "
1437 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001438 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001439 }
1440
1441 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001442 ERROR("Symlink %s is greater than 65536 bytes! "
1443 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001444 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001445 }
1446
1447 inode = get_inode(sizeof(*symlink) + byte);
1448 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001449 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001450 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1451 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001452 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1453 nlink);
plougher1f413c82005-11-18 00:02:14 +00001454 }
ploughere6e0e1b2010-05-12 17:17:06 +00001455 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001456 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001457 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001458 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001459 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001460
plougherdf2b9aa2010-12-16 04:56:23 +00001461 byte = readlink(filename, buff, 65536);
1462 if(byte == -1) {
ploughere6e0e1b2010-05-12 17:17:06 +00001463 ERROR("Failed to read symlink %s, creating empty "
1464 "symlink\n", filename);
1465 byte = 0;
1466 }
1467
1468 if(byte == 65536) {
1469 ERROR("Symlink %s is greater than 65536 bytes! "
1470 "Creating empty symlink\n", filename);
1471 byte = 0;
1472 }
1473
1474 inode = get_inode(sizeof(*symlink) + byte +
1475 sizeof(unsigned int));
1476 symlink->nlink = nlink;
1477 symlink->symlink_size = byte;
1478 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1479 strncpy(inode + off, buff, byte);
1480 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1481 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1482 nlink);
1483 }
plougher1f413c82005-11-18 00:02:14 +00001484 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001485 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001486
1487 inode = get_inode(sizeof(*ipc));
1488 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001489 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001490 TRACE("ipc inode, type %s, nlink %d\n", type ==
1491 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001492 }
1493 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001494 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001495
1496 inode = get_inode(sizeof(*ipc));
1497 ipc->nlink = nlink;
1498 ipc->xattr = xattr;
1499 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1500 TRACE("ipc inode, type %s, nlink %d\n", type ==
1501 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001502 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001503 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001504
1505 *i_no = MKINODE(inode);
1506 inode_count ++;
1507
plougherfd57dfe2009-03-30 01:17:52 +00001508 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1509 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001510
1511 return TRUE;
1512}
1513
1514
plougher50b31762009-03-31 04:14:46 +00001515void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1516 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001517{
plougher8cb05cd2005-12-11 23:32:35 +00001518 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001519 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001520 unsigned int start_block = inode >> 16;
1521 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001522 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001523 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001524
plougher43d49082010-12-16 05:01:15 +00001525 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001526 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001527 ERROR("Filename is greater than %d characters, truncating! ..."
1528 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001529 }
1530
plougher9b393552010-12-31 20:55:43 +00001531 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001532 sizeof(struct squashfs_dir_header)
1533 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001534 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1535 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001536 BAD_ERROR("Out of memory reallocating directory buffer"
1537 "\n");
plougher1f413c82005-11-18 00:02:14 +00001538 }
1539
1540 dir->p = (dir->p - dir->buff) + buff;
1541 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001542 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1543 buff);
plougher1f413c82005-11-18 00:02:14 +00001544 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1545 dir->buff = buff;
1546 }
1547
plougherfd57dfe2009-03-30 01:17:52 +00001548 if(dir->entry_count == 256 || start_block != dir->start_block ||
1549 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001550 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001551 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001552 ((long long) inode_number - dir->inode_number) > 32767
1553 || ((long long) inode_number - dir->inode_number)
1554 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001555 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001556 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001557
plougher9b393552010-12-31 20:55:43 +00001558 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001559 dir->index_count_p) >
1560 SQUASHFS_METADATA_SIZE) {
1561 if(dir->i_count % I_COUNT_SIZE == 0) {
1562 dir->index = realloc(dir->index,
1563 (dir->i_count + I_COUNT_SIZE) *
1564 sizeof(struct cached_dir_index));
1565 if(dir->index == NULL)
1566 BAD_ERROR("Out of memory in "
1567 "directory index table "
1568 "reallocation!\n");
1569 }
1570 dir->index[dir->i_count].index.index =
1571 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001572 dir->index[dir->i_count].index.size = size - 1;
1573 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001574 dir->i_size += sizeof(struct squashfs_dir_index)
1575 + size;
plougher1f413c82005-11-18 00:02:14 +00001576 dir->index_count_p = dir->p;
1577 }
1578
1579 dir_header.count = dir->entry_count - 1;
1580 dir_header.start_block = dir->start_block;
1581 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001582 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001583 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001584
1585 }
1586
1587
1588 dir->entry_count_p = dir->p;
1589 dir->start_block = start_block;
1590 dir->entry_count = 0;
1591 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001592 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001593 }
1594
plougher1f413c82005-11-18 00:02:14 +00001595 idir.offset = offset;
1596 idir.type = type;
1597 idir.size = size - 1;
1598 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001599 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1600 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001601 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001602 dir->entry_count ++;
1603}
1604
1605
plougherfd57dfe2009-03-30 01:17:52 +00001606void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1607 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001608{
1609 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001610 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001611 unsigned int directory_block, directory_offset, i_count, index;
1612 unsigned short c_byte;
1613
1614 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001615 int realloc_size = directory_cache_size == 0 ?
1616 ((dir_size + SQUASHFS_METADATA_SIZE) &
1617 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001618
plougher17248ca2010-07-27 00:24:35 +00001619 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001620 directory_cache_size + realloc_size);
plougher17248ca2010-07-27 00:24:35 +00001621 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001622 goto failed;
1623 }
1624 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001625 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001626 }
1627
1628 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001629 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001630
1631 dir_header.count = dir->entry_count - 1;
1632 dir_header.start_block = dir->start_block;
1633 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001634 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001635 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1636 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001637 }
1638 directory_offset = directory_cache_bytes;
1639 directory_block = directory_bytes;
1640 directory_cache_bytes += dir_size;
1641 i_count = 0;
1642 index = SQUASHFS_METADATA_SIZE - directory_offset;
1643
1644 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001645 while(i_count < dir->i_count &&
1646 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001647 dir->index[i_count++].index.start_block =
1648 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001649 index += SQUASHFS_METADATA_SIZE;
1650
1651 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1652 break;
1653
plougherfd57dfe2009-03-30 01:17:52 +00001654 if((directory_size - directory_bytes) <
1655 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001656 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001657 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1658 + 2);
plougher79d665a2010-07-27 00:19:23 +00001659 if(dt == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001660 goto failed;
1661 }
1662 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001663 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001664 }
1665
plougher50b31762009-03-31 04:14:46 +00001666 c_byte = mangle(directory_table + directory_bytes +
1667 BLOCK_OFFSET, directory_data_cache,
1668 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1669 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001670 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1671 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001672 SQUASHFS_SWAP_SHORTS(&c_byte,
1673 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001674 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1675 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001676 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001677 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001678 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1679 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001680 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1681 }
1682
plougher3c6bdb52010-05-01 02:30:59 +00001683 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1684 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1685 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001686
1687#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001688 {
plougher1f413c82005-11-18 00:02:14 +00001689 unsigned char *dirp;
1690 int count;
1691
1692 TRACE("Directory contents of inode 0x%llx\n", *inode);
1693 dirp = dir->buff;
1694 while(dirp < dir->p) {
1695 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001696 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001697 struct squashfs_dir_header dirh;
1698 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001699 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001700 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001701 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001702
plougher50b31762009-03-31 04:14:46 +00001703 TRACE("\tStart block 0x%x, count %d\n",
1704 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001705
1706 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001707 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001708 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001709 strncpy(buffer, idirp->name, idir.size + 1);
1710 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001711 TRACE("\t\tname %s, inode offset 0x%x, type "
1712 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001713 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001714 1;
plougher1f413c82005-11-18 00:02:14 +00001715 }
1716 }
1717 }
1718#endif
1719 dir_count ++;
1720
plougher29e37092007-04-15 01:24:51 +00001721 return;
plougher1f413c82005-11-18 00:02:14 +00001722
1723failed:
1724 BAD_ERROR("Out of memory in directory table reallocation!\n");
1725}
1726
1727
plougher76c64082008-03-08 01:32:23 +00001728struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001729{
plougher8ed84b92010-12-31 10:37:24 +00001730 struct squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001731 int res, size;
plougher76c64082008-03-08 01:32:23 +00001732 long long start_block;
1733 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001734
plougher76c64082008-03-08 01:32:23 +00001735 if(fragment->index == SQUASHFS_INVALID_FRAG)
1736 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001737
plougher76c64082008-03-08 01:32:23 +00001738 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001739 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001740 return buffer;
plougher76c64082008-03-08 01:32:23 +00001741
plougherfd57dfe2009-03-30 01:17:52 +00001742 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1743 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001744
plougher76c64082008-03-08 01:32:23 +00001745 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001746
1747 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001748 disk_fragment = &fragment_table[fragment->index];
1749 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001750 start_block = disk_fragment->start_block;
1751 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001752
plougher0f464442008-03-31 00:27:56 +00001753 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001754 int error;
plougher76c64082008-03-08 01:32:23 +00001755 char *data;
plougher1f413c82005-11-18 00:02:14 +00001756
plougher76c64082008-03-08 01:32:23 +00001757 if(compressed_buffer)
1758 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001759 else
1760 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001761
plougherb48442b2010-12-31 07:57:54 +00001762 res = compressor_uncompress(comp, buffer->data, data, size,
1763 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001764 if(res == -1)
1765 BAD_ERROR("%s uncompress failed with error code %d\n",
1766 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001767 } else if(compressed_buffer)
1768 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001769 else {
1770 res = read_fs_bytes(fd, start_block, size, buffer->data);
1771 if(res == 0)
1772 EXIT_MKSQUASHFS();
1773 }
plougher1f413c82005-11-18 00:02:14 +00001774
plougher03859fa2009-03-31 03:18:18 +00001775 cache_block_put(compressed_buffer);
1776
plougher76c64082008-03-08 01:32:23 +00001777 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001778}
1779
plougher2ea89142008-03-11 01:34:19 +00001780
1781struct frag_locked {
1782 struct file_buffer *buffer;
1783 int c_byte;
1784 int fragment;
1785 struct frag_locked *fragment_prev;
1786 struct frag_locked *fragment_next;
1787};
1788
1789int fragments_locked = FALSE;
1790struct frag_locked *frag_locked_list = NULL;
1791
1792INSERT_LIST(fragment, struct frag_locked)
1793REMOVE_LIST(fragment, struct frag_locked)
1794
plougher4e8484a2008-03-15 23:30:16 +00001795int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001796{
plougher4e8484a2008-03-15 23:30:16 +00001797 int count;
plougher5507dd92006-11-06 00:43:10 +00001798 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001799 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001800 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001801 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001802 return count;
plougher2ea89142008-03-11 01:34:19 +00001803}
1804
1805
1806void unlock_fragments()
1807{
1808 struct frag_locked *entry;
1809 int compressed_size;
1810
1811 pthread_mutex_lock(&fragment_mutex);
1812 while(frag_locked_list) {
1813 entry = frag_locked_list;
1814 remove_fragment_list(&frag_locked_list, entry);
1815 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1816 fragment_table[entry->fragment].size = entry->c_byte;
1817 fragment_table[entry->fragment].start_block = bytes;
1818 entry->buffer->block = bytes;
1819 bytes += compressed_size;
1820 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001821 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001822 TRACE("fragment_locked writing fragment %d, compressed size %d"
1823 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001824 free(entry);
1825 }
1826 fragments_locked = FALSE;
1827 pthread_mutex_unlock(&fragment_mutex);
1828}
1829
1830
plougherb7a66812010-07-21 01:06:59 +00001831void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001832 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001833{
1834 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1835 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001836 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001837 entry->buffer = write_buffer;
1838 entry->c_byte = c_byte;
1839 entry->fragment = fragment;
1840 entry->fragment_prev = entry->fragment_next = NULL;
1841 pthread_mutex_lock(&fragment_mutex);
1842 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001843 pthread_mutex_unlock(&fragment_mutex);
1844}
1845
1846
Phillip Lougher04b7b532011-06-11 02:14:15 +01001847void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001848{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001849 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001850 return;
1851
plougher5507dd92006-11-06 00:43:10 +00001852 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001853 fragment_table[fragment->block].unused = 0;
1854 fragments_outstanding ++;
1855 queue_put(to_frag, fragment);
1856 pthread_mutex_unlock(&fragment_mutex);
1857}
1858
1859
1860struct file_buffer *allocate_fragment()
1861{
1862 struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
1863
1864 pthread_mutex_lock(&fragment_mutex);
1865
plougher5507dd92006-11-06 00:43:10 +00001866 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001867 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001868 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001869 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001870 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001871 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001872 }
plougherfa89c332010-07-27 00:27:15 +00001873 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001874 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001875
1876 fragment->size = 0;
1877 fragment->block = fragments ++;
1878
plougher5507dd92006-11-06 00:43:10 +00001879 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001880
1881 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001882}
1883
ploughereb6eac92008-02-26 01:50:48 +00001884
plougher1f413c82005-11-18 00:02:14 +00001885static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001886struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1887 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001888{
1889 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001890 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001891
plougher5507dd92006-11-06 00:43:10 +00001892 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001893 return &empty_fragment;
1894
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001895 fragment = eval_frag_actions(dir_ent);
1896
1897 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1898 write_fragment(*fragment);
1899 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001900 }
plougher1f413c82005-11-18 00:02:14 +00001901
ploughere7e6e832010-12-16 05:08:06 +00001902 ffrg = malloc(sizeof(struct fragment));
1903 if(ffrg == NULL)
plougher1f413c82005-11-18 00:02:14 +00001904 BAD_ERROR("Out of memory in fragment block allocation!\n");
1905
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001906 if(*fragment == NULL)
1907 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001908
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001909 ffrg->index = (*fragment)->block;
1910 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001911 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001912 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001913 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001914 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001915
1916 return ffrg;
1917}
1918
1919
ploughera0a49c32010-08-11 01:47:59 +00001920long long generic_write_table(int length, void *buffer, int length2,
1921 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001922{
plougher17b269c2009-03-30 01:33:07 +00001923 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1924 SQUASHFS_METADATA_SIZE;
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001925 long long *list, start_bytes;
Phillip Lougherc1305322012-11-02 22:28:02 +00001926 int compressed_size, i, list_size = meta_blocks * sizeof(long long);
plougher1f413c82005-11-18 00:02:14 +00001927 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001928 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1929
plougher82ab2332009-04-21 00:21:21 +00001930#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001931 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001932 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001933#endif
plougher1f413c82005-11-18 00:02:14 +00001934
Phillip Lougherc1305322012-11-02 22:28:02 +00001935 list = malloc(list_size);
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001936 if(list == NULL)
1937 BAD_ERROR("Out of memory in generic_write_table\n");
1938
plougher1f413c82005-11-18 00:02:14 +00001939 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001940 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1941 SQUASHFS_METADATA_SIZE : length;
1942 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1943 SQUASHFS_METADATA_SIZE , avail_bytes,
1944 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001945 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001946 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001947 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1948 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001949 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1950 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001951 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001952 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001953 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001954 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001955 }
1956
ploughere6e0e1b2010-05-12 17:17:06 +00001957 start_bytes = bytes;
1958 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001959 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001960 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001961 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001962 }
1963
plougher1f288f62009-02-21 03:05:52 +00001964 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
Phillip Lougherc1305322012-11-02 22:28:02 +00001965 write_destination(fd, bytes, list_size, list);
1966 bytes += list_size;
1967 total_bytes += list_size;
plougher1f413c82005-11-18 00:02:14 +00001968
plougher40d8b952010-02-12 16:26:32 +00001969 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1970 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001971
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001972 free(list);
1973
plougher1f413c82005-11-18 00:02:14 +00001974 return start_bytes;
1975}
1976
1977
plougher0e453652006-11-06 01:49:35 +00001978long long write_fragment_table()
1979{
1980 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher0e453652006-11-06 01:49:35 +00001981 int i;
1982
plougher17b269c2009-03-30 01:33:07 +00001983 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1984 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001985 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001986 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1987 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001988 fragment_table[i].size);
Phillip Lougher162c24c2012-10-30 02:54:16 +00001989 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
plougher0e453652006-11-06 01:49:35 +00001990 }
1991
Phillip Lougher162c24c2012-10-30 02:54:16 +00001992 return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001993}
1994
1995
plougher1f413c82005-11-18 00:02:14 +00001996char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001997char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001998{
plougher1d065e92010-06-18 03:58:27 +00001999 int res;
2000
2001 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
2002 if(res == 0)
2003 EXIT_MKSQUASHFS();
2004
plougher1f413c82005-11-18 00:02:14 +00002005 return read_from_file_buffer;
2006}
2007
2008
plougher1b899fc2008-08-07 01:24:06 +00002009char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
2010char *read_from_disk2(long long start, unsigned int avail_bytes)
2011{
plougher1d065e92010-06-18 03:58:27 +00002012 int res;
2013
2014 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
2015 if(res == 0)
2016 EXIT_MKSQUASHFS();
2017
plougher1b899fc2008-08-07 01:24:06 +00002018 return read_from_file_buffer2;
2019}
2020
2021
plougher1f413c82005-11-18 00:02:14 +00002022/*
2023 * Compute 16 bit BSD checksum over the data
2024 */
plougher5507dd92006-11-06 00:43:10 +00002025unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00002026{
plougher5507dd92006-11-06 00:43:10 +00002027 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00002028
plougher5507dd92006-11-06 00:43:10 +00002029 while(bytes --) {
2030 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
2031 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00002032 }
2033
2034 return chksum;
2035}
2036
2037
plougher17b269c2009-03-30 01:33:07 +00002038unsigned short get_checksum_disk(long long start, long long l,
2039 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00002040{
2041 unsigned short chksum = 0;
2042 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00002043 struct file_buffer *write_buffer;
2044 int i;
plougher5507dd92006-11-06 00:43:10 +00002045
plougher57e6d182008-05-06 23:51:29 +00002046 for(i = 0; l; i++) {
2047 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2048 if(bytes == 0) /* sparse block */
2049 continue;
2050 write_buffer = cache_lookup(writer_buffer, start);
2051 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002052 chksum = get_checksum(write_buffer->data, bytes,
2053 chksum);
plougher57e6d182008-05-06 23:51:29 +00002054 cache_block_put(write_buffer);
2055 } else
plougher50b31762009-03-31 04:14:46 +00002056 chksum = get_checksum(read_from_disk(start, bytes),
2057 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002058 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002059 start += bytes;
2060 }
2061
2062 return chksum;
2063}
2064
2065
plougher5507dd92006-11-06 00:43:10 +00002066unsigned short get_checksum_mem(char *buff, int bytes)
2067{
2068 return get_checksum(buff, bytes, 0);
2069}
2070
2071
2072unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2073{
2074 if(file_buffer == NULL)
2075 return 0;
2076 else
2077 return get_checksum(file_buffer->data, file_buffer->size, 0);
2078}
2079
2080
plougher5507dd92006-11-06 00:43:10 +00002081#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002082void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002083 unsigned int *block_listp, int blocks, unsigned int fragment,
2084 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002085{
2086 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002087 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002088 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002089
plougher5507dd92006-11-06 00:43:10 +00002090 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002091 return;
2092
plougher5507dd92006-11-06 00:43:10 +00002093 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2094 if(file_size != dupl_ptr->file_size)
2095 continue;
2096 if(blocks != 0 && start != dupl_ptr->start)
2097 continue;
2098 if(fragment != dupl_ptr->fragment->index)
2099 continue;
plougher17b269c2009-03-30 01:33:07 +00002100 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2101 dupl_ptr->fragment->offset || bytes !=
2102 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002103 continue;
2104 return;
2105 }
2106
plougher3bb279c2010-12-16 05:10:03 +00002107 frg = malloc(sizeof(struct fragment));
2108 if(frg == NULL)
plougher1f413c82005-11-18 00:02:14 +00002109 BAD_ERROR("Out of memory in fragment block allocation!\n");
2110
2111 frg->index = fragment;
2112 frg->offset = offset;
2113 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002114
plougher5507dd92006-11-06 00:43:10 +00002115 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2116}
plougher1f413c82005-11-18 00:02:14 +00002117
plougher1f413c82005-11-18 00:02:14 +00002118
plougher5507dd92006-11-06 00:43:10 +00002119int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002120{
plougher5507dd92006-11-06 00:43:10 +00002121 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002122
2123 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002124 if(dupl_ptr->file_size == file_size)
2125 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002126
plougher5507dd92006-11-06 00:43:10 +00002127 return FALSE;
2128}
2129
2130
2131int pre_duplicate_frag(long long file_size, unsigned short checksum)
2132{
2133 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2134
2135 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002136 if(file_size == dupl_ptr->file_size && file_size ==
2137 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002138 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002139 struct file_buffer *frag_buffer =
2140 get_fragment(dupl_ptr->fragment);
2141 dupl_ptr->checksum =
2142 get_checksum_disk(dupl_ptr->start,
2143 dupl_ptr->bytes, dupl_ptr->block_list);
2144 dupl_ptr->fragment_checksum =
2145 get_checksum_mem(frag_buffer->data +
2146 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002147 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002148 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002149 }
plougher5507dd92006-11-06 00:43:10 +00002150 if(dupl_ptr->fragment_checksum == checksum)
2151 return TRUE;
2152 }
plougher1f413c82005-11-18 00:02:14 +00002153
plougher5507dd92006-11-06 00:43:10 +00002154 return FALSE;
2155}
2156
2157
plougher17b269c2009-03-30 01:33:07 +00002158struct file_info *add_non_dup(long long file_size, long long bytes,
2159 unsigned int *block_list, long long start, struct fragment *fragment,
2160 unsigned short checksum, unsigned short fragment_checksum,
2161 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002162{
plougher51ef9ae2010-12-16 05:14:28 +00002163 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00002164
plougher51ef9ae2010-12-16 05:14:28 +00002165 if(dupl_ptr == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002166 BAD_ERROR("Out of memory in dup_files allocation!\n");
2167 }
2168
2169 dupl_ptr->file_size = file_size;
2170 dupl_ptr->bytes = bytes;
2171 dupl_ptr->block_list = block_list;
2172 dupl_ptr->start = start;
2173 dupl_ptr->fragment = fragment;
2174 dupl_ptr->checksum = checksum;
2175 dupl_ptr->fragment_checksum = fragment_checksum;
2176 dupl_ptr->checksum_flag = checksum_flag;
2177 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2178 dupl[DUP_HASH(file_size)] = dupl_ptr;
2179 dup_files ++;
2180
2181 return dupl_ptr;
2182}
2183
2184
plougher17b269c2009-03-30 01:33:07 +00002185struct file_info *duplicate(long long file_size, long long bytes,
2186 unsigned int **block_list, long long *start, struct fragment **fragment,
2187 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2188 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002189{
2190 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2191 int frag_bytes = file_buffer ? file_buffer->size : 0;
2192
2193 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002194 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2195 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002196 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002197 int block;
2198
plougher17b269c2009-03-30 01:33:07 +00002199 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2200 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002201 continue;
2202
plougher5507dd92006-11-06 00:43:10 +00002203 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002204 checksum = get_checksum_disk(*start, bytes,
2205 *block_list);
2206 fragment_checksum =
2207 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002208 checksum_flag = TRUE;
2209 }
2210
2211 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002212 struct file_buffer *frag_buffer =
2213 get_fragment(dupl_ptr->fragment);
2214 dupl_ptr->checksum =
2215 get_checksum_disk(dupl_ptr->start,
2216 dupl_ptr->bytes, dupl_ptr->block_list);
2217 dupl_ptr->fragment_checksum =
2218 get_checksum_mem(frag_buffer->data +
2219 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002220 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002221 dupl_ptr->checksum_flag = TRUE;
2222 }
2223
plougher17b269c2009-03-30 01:33:07 +00002224 if(checksum != dupl_ptr->checksum ||
2225 fragment_checksum !=
2226 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002227 continue;
2228
plougher1b899fc2008-08-07 01:24:06 +00002229 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002230 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002231 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2232 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002233 struct file_buffer *target_buffer = NULL;
2234 struct file_buffer *dup_buffer = NULL;
2235 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002236 int res;
plougher5507dd92006-11-06 00:43:10 +00002237
plougher1b899fc2008-08-07 01:24:06 +00002238 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002239 continue;
plougher17b269c2009-03-30 01:33:07 +00002240 target_buffer = cache_lookup(writer_buffer,
2241 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002242 if(target_buffer)
2243 target_data = target_buffer->data;
2244 else
plougher50b31762009-03-31 04:14:46 +00002245 target_data =
2246 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002247 size);
plougher5507dd92006-11-06 00:43:10 +00002248
plougher360514a2009-03-30 03:01:38 +00002249 dup_buffer = cache_lookup(writer_buffer,
2250 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002251 if(dup_buffer)
2252 dup_data = dup_buffer->data;
2253 else
plougher360514a2009-03-30 03:01:38 +00002254 dup_data = read_from_disk2(dup_start,
2255 size);
plougher1b899fc2008-08-07 01:24:06 +00002256
2257 res = memcmp(target_data, dup_data, size);
2258 cache_block_put(target_buffer);
2259 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002260 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002261 break;
plougher1b899fc2008-08-07 01:24:06 +00002262 target_start += size;
2263 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002264 }
2265 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002266 struct file_buffer *frag_buffer =
2267 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002268
plougher17b269c2009-03-30 01:33:07 +00002269 if(frag_bytes == 0 ||
2270 memcmp(file_buffer->data,
2271 frag_buffer->data +
2272 dupl_ptr->fragment->offset,
2273 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002274 TRACE("Found duplicate file, start "
2275 "0x%llx, size %lld, checksum "
2276 "0x%x, fragment %d, size %d, "
2277 "offset %d, checksum 0x%x\n",
2278 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002279 dupl_ptr->bytes,
2280 dupl_ptr->checksum,
2281 dupl_ptr->fragment->index,
2282 frag_bytes,
2283 dupl_ptr->fragment->offset,
2284 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002285 *block_list = dupl_ptr->block_list;
2286 *start = dupl_ptr->start;
2287 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002288 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002289 return 0;
2290 }
plougher76c64082008-03-08 01:32:23 +00002291 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002292 }
2293 }
2294
2295
plougher17b269c2009-03-30 01:33:07 +00002296 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2297 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002298}
2299
2300
Phillip Lougher2504b082011-09-07 02:28:45 +01002301inline int is_fragment(struct inode_info *inode)
2302{
2303 int file_size = inode->buf.st_size;
2304
Phillip Lougher63f531f2011-09-10 04:03:32 +01002305 /*
2306 * If this block is to be compressed differently to the
2307 * fragment compression then it cannot be a fragment
2308 */
2309 if(inode->noF != noF)
2310 return FALSE;
2311
Phillip Lougher2504b082011-09-07 02:28:45 +01002312 return !inode->no_fragments && (file_size < block_size ||
2313 (inode->always_use_fragments && file_size & (block_size - 1)));
2314}
2315
2316
plougher00d08172009-09-03 10:17:44 +00002317static int seq = 0;
2318void reader_read_process(struct dir_ent *dir_ent)
2319{
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002320 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002321 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002322 int status, res, byte, count = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002323 int file = get_pseudo_file(inode->pseudo_id)->fd;
2324 int child = get_pseudo_file(inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002325 long long bytes = 0;
2326
2327 while(1) {
2328 file_buffer = cache_get(reader_buffer, 0, 0);
2329 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002330 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002331
2332 byte = read_bytes(file, file_buffer->data, block_size);
2333 if(byte == -1)
2334 goto read_err;
2335
2336 file_buffer->size = byte;
2337 file_buffer->file_size = -1;
2338 file_buffer->block = count ++;
2339 file_buffer->error = FALSE;
2340 file_buffer->fragment = FALSE;
2341 bytes += byte;
2342
2343 if(byte == 0)
2344 break;
2345
plougher286b6b32009-09-19 03:29:27 +00002346 /*
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002347 * Update progress bar size. This is done
plougher286b6b32009-09-19 03:29:27 +00002348 * on every block rather than waiting for all blocks to be
2349 * read incase write_file_process() is running in parallel
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002350 * with this. Otherwise the current progress bar position
2351 * may get ahead of the progress bar size.
plougher286b6b32009-09-19 03:29:27 +00002352 */
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002353 progress_bar_size(1);
plougher286b6b32009-09-19 03:29:27 +00002354
plougher00d08172009-09-03 10:17:44 +00002355 if(prev_buffer)
2356 queue_put(from_reader, prev_buffer);
2357 prev_buffer = file_buffer;
2358 }
2359
plougher54d67292009-09-19 03:26:27 +00002360 /*
2361 * Update inode file size now that the size of the dynamic pseudo file
2362 * is known. This is needed for the -info option.
2363 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002364 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002365
plougherba674e82009-09-10 03:50:00 +00002366 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002367 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002368 goto read_err;
2369
plougher00d08172009-09-03 10:17:44 +00002370 if(prev_buffer == NULL)
2371 prev_buffer = file_buffer;
2372 else {
2373 cache_block_put(file_buffer);
2374 seq --;
2375 }
2376 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002377 prev_buffer->fragment = is_fragment(inode);
plougher00d08172009-09-03 10:17:44 +00002378 queue_put(from_reader, prev_buffer);
2379
2380 return;
2381
2382read_err:
2383 if(prev_buffer) {
2384 cache_block_put(file_buffer);
2385 seq --;
2386 file_buffer = prev_buffer;
2387 }
2388 file_buffer->error = TRUE;
2389 queue_put(from_deflate, file_buffer);
2390}
2391
2392
plougher5507dd92006-11-06 00:43:10 +00002393void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002394{
plougher018d2b32007-04-23 03:01:48 +00002395 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002396 struct file_buffer *file_buffer;
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002397 int blocks, byte, count, expected, file, res;
plougher018d2b32007-04-23 03:01:48 +00002398 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002399 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002400
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002401 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002402 return;
2403
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002404 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002405again:
2406 bytes = 0;
2407 count = 0;
2408 file_buffer = NULL;
2409 read_size = buf->st_size;
2410 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002411
Phillip Lougher494479f2012-02-03 15:45:41 +00002412 file = open(pathname_reader(dir_ent), O_RDONLY);
plougherc1d258e2010-12-16 05:16:45 +00002413 if(file == -1) {
plougher1e380702010-08-11 01:52:49 +00002414 file_buffer = cache_get(reader_buffer, 0, 0);
2415 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002416 goto read_err;
plougher1e380702010-08-11 01:52:49 +00002417 }
plougher5507dd92006-11-06 00:43:10 +00002418
plougher018d2b32007-04-23 03:01:48 +00002419 do {
plougher110799c2009-03-30 01:50:40 +00002420 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002421 block_size ? block_size :
2422 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002423
2424 if(file_buffer)
2425 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002426 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002427 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002428 file_buffer->noD = inode->noD;
plougher5507dd92006-11-06 00:43:10 +00002429
ploughera4c24ed2010-08-11 02:08:38 +00002430 /*
2431 * Always try to read block_size bytes from the file rather
2432 * than expected bytes (which will be less than the block_size
2433 * at the file tail) to check that the file hasn't grown
2434 * since being stated. If it is longer (or shorter) than
2435 * expected, then restat, and try again. Note the special
2436 * case where the file is an exact multiple of the block_size
2437 * is dealt with later.
2438 */
plougher110799c2009-03-30 01:50:40 +00002439 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2440 block_size);
plougher018d2b32007-04-23 03:01:48 +00002441
plougher018d2b32007-04-23 03:01:48 +00002442 file_buffer->file_size = read_size;
2443
ploughera4c24ed2010-08-11 02:08:38 +00002444 if(byte == -1)
2445 goto read_err;
2446
plougher018d2b32007-04-23 03:01:48 +00002447 if(byte != expected)
2448 goto restat;
2449
2450 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002451 file_buffer->error = FALSE;
Phillip Lougher2504b082011-09-07 02:28:45 +01002452 file_buffer->fragment = FALSE;
plougher018d2b32007-04-23 03:01:48 +00002453
2454 bytes += byte;
2455 count ++;
2456 } while(count < blocks);
2457
2458 if(read_size != bytes)
2459 goto restat;
2460
2461 if(expected == block_size) {
ploughera4c24ed2010-08-11 02:08:38 +00002462 /*
2463 * Special case where we've not tried to read past the end of
2464 * the file. We expect to get EOF, i.e. the file isn't larger
2465 * than we expect.
2466 */
plougher018d2b32007-04-23 03:01:48 +00002467 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002468 int res;
plougher018d2b32007-04-23 03:01:48 +00002469
ploughera4c24ed2010-08-11 02:08:38 +00002470 res = read_bytes(file, &buffer, 1);
2471 if(res == -1)
2472 goto read_err;
2473
2474 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002475 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002476 }
2477
Phillip Lougher2504b082011-09-07 02:28:45 +01002478 file_buffer->fragment = is_fragment(inode);
plougher1b899fc2008-08-07 01:24:06 +00002479 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002480
plougher5507dd92006-11-06 00:43:10 +00002481 close(file);
plougher5507dd92006-11-06 00:43:10 +00002482
2483 return;
2484
plougher018d2b32007-04-23 03:01:48 +00002485restat:
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002486 res = fstat(file, &buf2);
plougher018d2b32007-04-23 03:01:48 +00002487 close(file);
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002488 if(res == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00002489 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002490 pathname_reader(dir_ent), strerror(errno));
2491 goto read_err;
2492 }
2493
plougher018d2b32007-04-23 03:01:48 +00002494 if(read_size != buf2.st_size) {
2495 memcpy(buf, &buf2, sizeof(struct stat));
2496 file_buffer->error = 2;
2497 queue_put(from_deflate, file_buffer);
2498 goto again;
2499 }
plougher1e380702010-08-11 01:52:49 +00002500read_err:
2501 file_buffer->error = TRUE;
2502 queue_put(from_deflate, file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002503}
2504
2505
2506void reader_scan(struct dir_info *dir) {
Phillip Lougherbf338362012-08-22 05:24:36 +01002507 struct dir_ent *dir_ent = dir->list;
plougher5507dd92006-11-06 00:43:10 +00002508
Phillip Lougherbf338362012-08-22 05:24:36 +01002509 for(; dir_ent; dir_ent = dir_ent->next) {
plougher5507dd92006-11-06 00:43:10 +00002510 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002511 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002512 continue;
2513
plougherb3977eb2010-05-02 02:08:48 +00002514 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002515 reader_read_process(dir_ent);
2516 continue;
2517 }
2518
plougher5507dd92006-11-06 00:43:10 +00002519 switch(buf->st_mode & S_IFMT) {
2520 case S_IFREG:
2521 reader_read_file(dir_ent);
2522 break;
2523 case S_IFDIR:
2524 reader_scan(dir_ent->dir);
2525 break;
2526 }
2527 }
2528}
2529
2530
2531void *reader(void *arg)
2532{
2533 int oldstate;
2534
2535 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2536 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2537
2538 if(!sorted)
2539 reader_scan(queue_get(to_reader));
2540 else {
2541 int i;
2542 struct priority_entry *entry;
2543
2544 queue_get(to_reader);
2545 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002546 for(entry = priority_list[i]; entry;
2547 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002548 reader_read_file(entry->dir);
2549 }
rloughere4873e02007-11-08 17:50:42 +00002550
plougher5aa18162007-12-13 12:15:21 +00002551 thread[0] = 0;
2552
rloughere4873e02007-11-08 17:50:42 +00002553 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002554}
2555
2556
2557void *writer(void *arg)
2558{
2559 int write_error = FALSE;
2560 int oldstate;
2561
2562 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2563 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2564
2565 while(1) {
2566 struct file_buffer *file_buffer = queue_get(to_writer);
2567 off_t off;
2568
2569 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002570 queue_put(from_writer,
plougherc2a5ae12010-12-31 08:35:28 +00002571 write_error ? &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002572 continue;
2573 }
2574
2575 off = file_buffer->block;
2576
2577 pthread_mutex_lock(&pos_mutex);
2578
2579 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002580 ERROR("Lseek on destination failed because %s\n",
2581 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002582 write_error = TRUE;
2583 }
2584
plougher110799c2009-03-30 01:50:40 +00002585 if(!write_error && write_bytes(fd, file_buffer->data,
2586 file_buffer->size) == -1) {
2587 ERROR("Write on destination failed because %s\n",
2588 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002589 write_error = TRUE;
2590 }
2591 pthread_mutex_unlock(&pos_mutex);
2592
ploughereb6eac92008-02-26 01:50:48 +00002593 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002594 }
2595}
2596
2597
plougher5b09fd42007-08-06 10:28:41 +00002598int all_zero(struct file_buffer *file_buffer)
2599{
2600 int i;
2601 long entries = file_buffer->size / sizeof(long);
2602 long *p = (long *) file_buffer->data;
2603
2604 for(i = 0; i < entries && p[i] == 0; i++);
2605
2606 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002607 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002608 i < file_buffer->size && file_buffer->data[i] == 0;
2609 i++);
plougher5b09fd42007-08-06 10:28:41 +00002610
2611 return i == file_buffer->size;
2612 }
2613
2614 return 0;
2615}
2616
2617
plougher5507dd92006-11-06 00:43:10 +00002618void *deflator(void *arg)
2619{
plougher7b8ee502009-07-29 07:54:30 +00002620 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002621 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002622
2623 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2624 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2625
plougher13fdddf2010-11-24 01:23:41 +00002626 res = compressor_init(comp, &stream, block_size, 1);
2627 if(res)
2628 BAD_ERROR("deflator:: compressor_init failed\n");
2629
plougher5507dd92006-11-06 00:43:10 +00002630 while(1) {
2631 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002632 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002633
Phillip Lougher48854382011-09-09 03:36:55 +01002634 if(file_buffer->file_size == 0) {
2635 file_buffer->c_byte = 0;
2636 queue_put(from_deflate, file_buffer);
2637 } else if(sparse_files && all_zero(file_buffer)) {
plougher1b899fc2008-08-07 01:24:06 +00002638 file_buffer->c_byte = 0;
2639 queue_put(from_deflate, file_buffer);
2640 } else if(file_buffer->fragment) {
2641 file_buffer->c_byte = file_buffer->size;
2642 queue_put(from_deflate, file_buffer);
2643 } else {
2644 write_buffer = cache_get(writer_buffer, 0, 0);
plougher13fdddf2010-11-24 01:23:41 +00002645 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002646 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002647 file_buffer->size, block_size,
2648 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002649 write_buffer->sequence = file_buffer->sequence;
2650 write_buffer->file_size = file_buffer->file_size;
2651 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002652 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2653 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002654 write_buffer->fragment = FALSE;
2655 write_buffer->error = FALSE;
2656 cache_block_put(file_buffer);
2657 queue_put(from_deflate, write_buffer);
2658 }
plougher5507dd92006-11-06 00:43:10 +00002659 }
2660}
2661
2662
2663void *frag_deflator(void *arg)
2664{
plougher7b8ee502009-07-29 07:54:30 +00002665 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002666 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002667
2668 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2669 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2670
plougher13fdddf2010-11-24 01:23:41 +00002671 res = compressor_init(comp, &stream, block_size, 1);
2672 if(res)
2673 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2674
plougher5507dd92006-11-06 00:43:10 +00002675 while(1) {
2676 int c_byte, compressed_size;
2677 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002678 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002679 cache_get(writer_buffer, file_buffer->block +
2680 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002681
plougher13fdddf2010-11-24 01:23:41 +00002682 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002683 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002684 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002685 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002686 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002687 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002688 fragment_table[file_buffer->block].size = c_byte;
2689 fragment_table[file_buffer->block].start_block = bytes;
2690 write_buffer->block = bytes;
2691 bytes += compressed_size;
2692 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002693 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002694 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002695 TRACE("Writing fragment %lld, uncompressed size %d, "
2696 "compressed size %d\n", file_buffer->block,
2697 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002698 } else {
2699 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002700 add_pending_fragment(write_buffer, c_byte,
2701 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002702 }
ploughereb6eac92008-02-26 01:50:48 +00002703 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002704 }
2705}
2706
2707
2708#define HASH_ENTRIES 256
2709#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2710struct file_buffer *block_hash[HASH_ENTRIES];
2711
2712void push_buffer(struct file_buffer *file_buffer)
2713{
plougher0f464442008-03-31 00:27:56 +00002714 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002715
2716 file_buffer->next = block_hash[hash];
2717 block_hash[hash] = file_buffer;
2718}
2719
2720
2721struct file_buffer *get_file_buffer(struct queue *queue)
2722{
plougher0f464442008-03-31 00:27:56 +00002723 static unsigned int sequence = 0;
2724 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002725 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2726
2727 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002728 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002729 break;
2730
2731 if(file_buffer) {
2732 if(prev)
2733 prev->next = file_buffer->next;
2734 else
2735 block_hash[hash] = file_buffer->next;
2736 } else {
2737 while(1) {
2738 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002739 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002740 break;
2741 push_buffer(file_buffer);
2742 }
2743 }
2744
plougher0f464442008-03-31 00:27:56 +00002745 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002746
2747 return file_buffer;
2748}
2749
2750
plougher110799c2009-03-30 01:50:40 +00002751void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2752 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002753{
2754 file_count ++;
2755 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002756 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2757 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002758}
2759
2760
plougher50b31762009-03-31 04:14:46 +00002761void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2762 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002763 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002764{
plougher5507dd92006-11-06 00:43:10 +00002765 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002766 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002767 unsigned int *block_listp = NULL;
2768 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002769
plougher50b31762009-03-31 04:14:46 +00002770 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2771 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002772
plougher5507dd92006-11-06 00:43:10 +00002773 if(dupl_ptr) {
2774 *duplicate_file = FALSE;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002775 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002776 dupl_ptr->fragment = fragment;
2777 } else
2778 *duplicate_file = TRUE;
2779
ploughereb6eac92008-02-26 01:50:48 +00002780 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002781
2782 total_bytes += size;
2783 file_count ++;
2784
plougher35a10602008-04-21 02:58:16 +00002785 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002786
plougherc1ace522010-05-01 03:00:45 +00002787 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002788 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002789}
2790
2791
plougher110799c2009-03-30 01:50:40 +00002792void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2793 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002794{
2795 struct fragment *fragment;
2796 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002797
2798 checksum = get_checksum_mem_buffer(file_buffer);
2799
plougher29e37092007-04-15 01:24:51 +00002800 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002801 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2802 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002803 return;
2804 }
plougher5507dd92006-11-06 00:43:10 +00002805
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002806 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002807
ploughereb6eac92008-02-26 01:50:48 +00002808 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002809
2810 if(duplicate_checking)
2811 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2812
2813 total_bytes += size;
2814 file_count ++;
2815
2816 *duplicate_file = FALSE;
2817
plougher35a10602008-04-21 02:58:16 +00002818 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002819
plougherc1ace522010-05-01 03:00:45 +00002820 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002821 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002822
plougher018d2b32007-04-23 03:01:48 +00002823 return;
plougher5507dd92006-11-06 00:43:10 +00002824}
2825
2826
plougher00d08172009-09-03 10:17:44 +00002827int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2828 struct file_buffer *read_buffer, int *duplicate_file)
2829{
2830 long long read_size, file_bytes, start;
2831 struct fragment *fragment;
2832 unsigned int *block_list = NULL;
2833 int block = 0, status;
2834 long long sparse = 0;
2835 struct file_buffer *fragment_buffer = NULL;
2836
2837 *duplicate_file = FALSE;
2838
2839 lock_fragments();
2840
2841 file_bytes = 0;
2842 start = bytes;
2843 while (1) {
2844 read_size = read_buffer->file_size;
2845 if(read_buffer->fragment && read_buffer->c_byte)
2846 fragment_buffer = read_buffer;
2847 else {
2848 block_list = realloc(block_list, (block + 1) *
2849 sizeof(unsigned int));
2850 if(block_list == NULL)
2851 BAD_ERROR("Out of memory allocating block_list"
2852 "\n");
2853 block_list[block ++] = read_buffer->c_byte;
2854 if(read_buffer->c_byte) {
2855 read_buffer->block = bytes;
2856 bytes += read_buffer->size;
2857 cache_rehash(read_buffer, read_buffer->block);
2858 file_bytes += read_buffer->size;
2859 queue_put(to_writer, read_buffer);
2860 } else {
2861 sparse += read_buffer->size;
2862 cache_block_put(read_buffer);
2863 }
2864 }
plougher286b6b32009-09-19 03:29:27 +00002865 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002866
2867 if(read_size != -1)
2868 break;
2869
2870 read_buffer = get_file_buffer(from_deflate);
2871 if(read_buffer->error)
2872 goto read_err;
2873 }
2874
2875 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002876 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002877 cache_block_put(fragment_buffer);
2878
2879 if(duplicate_checking)
2880 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2881 0, 0, FALSE);
2882 file_count ++;
2883 total_bytes += read_size;
2884
plougherc1ace522010-05-01 03:00:45 +00002885 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2886 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002887
2888 if(duplicate_checking == FALSE)
2889 free(block_list);
2890
2891 return 0;
2892
2893read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002894 dec_progress_bar(block);
plougher00d08172009-09-03 10:17:44 +00002895 status = read_buffer->error;
2896 bytes = start;
2897 if(!block_device) {
2898 int res;
2899
2900 queue_put(to_writer, NULL);
2901 if(queue_get(from_writer) != 0)
2902 EXIT_MKSQUASHFS();
2903 res = ftruncate(fd, bytes);
2904 if(res != 0)
2905 BAD_ERROR("Failed to truncate dest file because %s\n",
2906 strerror(errno));
2907 }
2908 unlock_fragments();
2909 free(block_list);
2910 cache_block_put(read_buffer);
2911 return status;
2912}
2913
2914
plougher110799c2009-03-30 01:50:40 +00002915int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002916 long long read_size, struct file_buffer *read_buffer,
2917 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002918{
plougher23377982007-11-12 04:04:48 +00002919 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002920 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002921 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002922 int block, status;
2923 int blocks = (read_size + block_size - 1) >> block_log;
2924 long long sparse = 0;
2925 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002926
plougher29e37092007-04-15 01:24:51 +00002927 *duplicate_file = FALSE;
2928
plougher87139622010-12-16 05:19:30 +00002929 block_list = malloc(blocks * sizeof(unsigned int));
2930 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00002931 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002932
plougher2ea89142008-03-11 01:34:19 +00002933 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002934
plougher5507dd92006-11-06 00:43:10 +00002935 file_bytes = 0;
2936 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002937 for(block = 0; block < blocks;) {
2938 if(read_buffer->fragment && read_buffer->c_byte) {
2939 fragment_buffer = read_buffer;
2940 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002941 } else {
plougher1b899fc2008-08-07 01:24:06 +00002942 block_list[block] = read_buffer->c_byte;
2943 if(read_buffer->c_byte) {
2944 read_buffer->block = bytes;
2945 bytes += read_buffer->size;
2946 cache_rehash(read_buffer, read_buffer->block);
2947 file_bytes += read_buffer->size;
2948 queue_put(to_writer, read_buffer);
2949 } else {
2950 sparse += read_buffer->size;
2951 cache_block_put(read_buffer);
2952 }
2953 }
2954 inc_progress_bar();
2955
2956 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002957 read_buffer = get_file_buffer(from_deflate);
2958 if(read_buffer->error)
2959 goto read_err;
2960 }
plougher1f413c82005-11-18 00:02:14 +00002961 }
2962
plougher2ea89142008-03-11 01:34:19 +00002963 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002964 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher1b899fc2008-08-07 01:24:06 +00002965 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002966
plougher1f413c82005-11-18 00:02:14 +00002967 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00002968 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2969 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002970 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002971 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002972
plougher360514a2009-03-30 03:01:38 +00002973 /*
2974 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002975 * a smaller block count on stat calls to sparse files. This is
2976 * to ensure intelligent applications like cp correctly handle the
2977 * file as a sparse file. If the file in the original filesystem isn't
2978 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002979 * report it as non-sparse on stat calls to preserve semantics
2980 */
plougher1b899fc2008-08-07 01:24:06 +00002981 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2982 sparse = 0;
2983
plougherc1ace522010-05-01 03:00:45 +00002984 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2985 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002986
plougher5507dd92006-11-06 00:43:10 +00002987 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002988 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002989
plougher018d2b32007-04-23 03:01:48 +00002990 return 0;
plougher1f413c82005-11-18 00:02:14 +00002991
2992read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002993 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00002994 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002995 bytes = start;
2996 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00002997 int res;
2998
plougher5507dd92006-11-06 00:43:10 +00002999 queue_put(to_writer, NULL);
3000 if(queue_get(from_writer) != 0)
3001 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003002 res = ftruncate(fd, bytes);
3003 if(res != 0)
3004 BAD_ERROR("Failed to truncate dest file because %s\n",
3005 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003006 }
plougher2ea89142008-03-11 01:34:19 +00003007 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003008 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003009 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003010 return status;
plougher1f413c82005-11-18 00:02:14 +00003011}
3012
3013
plougher110799c2009-03-30 01:50:40 +00003014int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003015 long long read_size, struct file_buffer *read_buffer,
3016 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003017{
plougher29e37092007-04-15 01:24:51 +00003018 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003019 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003020 struct fragment *fragment;
3021 struct file_info *dupl_ptr;
3022 int blocks = (read_size + block_size - 1) >> block_log;
3023 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003024 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003025 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003026 long long sparse = 0;
3027 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003028
plougher50b31762009-03-31 04:14:46 +00003029 block_list = malloc(blocks * sizeof(unsigned int));
3030 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003031 BAD_ERROR("Out of memory allocating block_list\n");
3032 block_listp = block_list;
3033
plougher50b31762009-03-31 04:14:46 +00003034 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3035 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003036 BAD_ERROR("Out of memory allocating file block list\n");
3037
plougher4e8484a2008-03-15 23:30:16 +00003038 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003039
3040 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003041 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003042 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3043 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003044
3045 for(block = 0; block < blocks;) {
3046 if(read_buffer->fragment && read_buffer->c_byte) {
3047 fragment_buffer = read_buffer;
3048 blocks = read_size >> block_log;
3049 } else {
3050 block_list[block] = read_buffer->c_byte;
3051
3052 if(read_buffer->c_byte) {
3053 read_buffer->block = bytes;
3054 bytes += read_buffer->size;
3055 file_bytes += read_buffer->size;
3056 cache_rehash(read_buffer, read_buffer->block);
3057 if(block < thresh) {
3058 buffer_list[block] = NULL;
3059 queue_put(to_writer, read_buffer);
3060 } else
3061 buffer_list[block] = read_buffer;
3062 } else {
3063 buffer_list[block] = NULL;
3064 sparse += read_buffer->size;
3065 cache_block_put(read_buffer);
3066 }
3067 }
3068 inc_progress_bar();
3069
3070 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003071 read_buffer = get_file_buffer(from_deflate);
3072 if(read_buffer->error)
3073 goto read_err;
3074 }
plougher5507dd92006-11-06 00:43:10 +00003075 }
3076
plougher110799c2009-03-30 01:50:40 +00003077 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3078 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003079
3080 if(dupl_ptr) {
3081 *duplicate_file = FALSE;
3082 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003083 if(buffer_list[block])
3084 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003085 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00003086 dupl_ptr->fragment = fragment;
3087 } else {
3088 *duplicate_file = TRUE;
3089 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003090 cache_block_put(buffer_list[block]);
3091 bytes = start;
3092 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003093 int res;
3094
plougher1b899fc2008-08-07 01:24:06 +00003095 queue_put(to_writer, NULL);
3096 if(queue_get(from_writer) != 0)
3097 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003098 res = ftruncate(fd, bytes);
3099 if(res != 0)
3100 BAD_ERROR("Failed to truncate dest file because"
3101 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003102 }
plougher5507dd92006-11-06 00:43:10 +00003103 }
3104
plougher2ea89142008-03-11 01:34:19 +00003105 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003106 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003107 free(buffer_list);
3108 file_count ++;
3109 total_bytes += read_size;
3110
plougher360514a2009-03-30 03:01:38 +00003111 /*
3112 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003113 * a smaller block count on stat calls to sparse files. This is
3114 * to ensure intelligent applications like cp correctly handle the
3115 * file as a sparse file. If the file in the original filesystem isn't
3116 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003117 * report it as non-sparse on stat calls to preserve semantics
3118 */
plougher1b899fc2008-08-07 01:24:06 +00003119 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3120 sparse = 0;
3121
plougherc1ace522010-05-01 03:00:45 +00003122 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3123 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003124
plougher5507dd92006-11-06 00:43:10 +00003125 if(*duplicate_file == TRUE)
3126 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003127
plougher018d2b32007-04-23 03:01:48 +00003128 return 0;
plougher5507dd92006-11-06 00:43:10 +00003129
3130read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003131 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00003132 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003133 bytes = start;
3134 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003135 int res;
3136
plougher5507dd92006-11-06 00:43:10 +00003137 queue_put(to_writer, NULL);
3138 if(queue_get(from_writer) != 0)
3139 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003140 res = ftruncate(fd, bytes);
3141 if(res != 0)
3142 BAD_ERROR("Failed to truncate dest file because %s\n",
3143 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003144 }
plougher2ea89142008-03-11 01:34:19 +00003145 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003146 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003147 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003148 free(buffer_list);
3149 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003150 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003151 return status;
plougher5507dd92006-11-06 00:43:10 +00003152}
3153
3154
plougher110799c2009-03-30 01:50:40 +00003155void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3156 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003157{
plougher018d2b32007-04-23 03:01:48 +00003158 int status;
3159 struct file_buffer *read_buffer;
3160 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003161
plougher018d2b32007-04-23 03:01:48 +00003162again:
3163 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003164
plougher23377982007-11-12 04:04:48 +00003165 status = read_buffer->error;
3166 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003167 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003168 goto file_err;
3169 }
3170
3171 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003172
plougher00d08172009-09-03 10:17:44 +00003173 if(read_size == -1)
3174 status = write_file_process(inode, dir_ent, read_buffer,
3175 duplicate_file);
3176 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003177 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003178 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003179 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003180 write_file_frag(inode, dir_ent, read_size, read_buffer,
3181 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003182 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003183 status = write_file_blocks_dup(inode, dir_ent, read_size,
3184 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003185 else
plougher50b31762009-03-31 04:14:46 +00003186 status = write_file_blocks(inode, dir_ent, read_size,
3187 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003188
plougher018d2b32007-04-23 03:01:48 +00003189file_err:
3190 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003191 ERROR("File %s changed size while reading filesystem, "
Phillip Lougher494479f2012-02-03 15:45:41 +00003192 "attempting to re-read\n", pathname(dir_ent));
plougher018d2b32007-04-23 03:01:48 +00003193 goto again;
3194 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003195 ERROR("Failed to read file %s, creating empty file\n",
Phillip Lougher494479f2012-02-03 15:45:41 +00003196 pathname(dir_ent));
plougher29e37092007-04-15 01:24:51 +00003197 write_file_empty(inode, dir_ent, duplicate_file);
3198 }
plougher5507dd92006-11-06 00:43:10 +00003199}
3200
3201
Phillip Lougher3f81a772012-12-04 05:07:24 +00003202#define BUFF_SIZE 512
plougher1f413c82005-11-18 00:02:14 +00003203char *name;
3204char *basename_r();
3205
3206char *getbase(char *pathname)
3207{
Phillip Lougher3f81a772012-12-04 05:07:24 +00003208 static char *b_buffer = NULL;
3209 static int b_size = BUFF_SIZE;
plougher1f413c82005-11-18 00:02:14 +00003210 char *result;
3211
Phillip Lougher3f81a772012-12-04 05:07:24 +00003212 if(b_buffer == NULL) {
3213 b_buffer = malloc(b_size);
3214 if(b_buffer == NULL)
3215 BAD_ERROR("Malloc failed in getbase\n");
3216 }
3217
3218 while(1) {
3219 if(*pathname != '/') {
3220 result = getcwd(b_buffer, b_size);
3221 if(result == NULL && errno != ERANGE)
3222 BAD_ERROR("Getcwd failed in getbase\n");
3223
3224 /* enough room for pathname + "/" + '\0' terminator? */
3225 if(result && strlen(pathname) + 2 <=
3226 b_size - strlen(b_buffer)) {
3227 strcat(strcat(b_buffer, "/"), pathname);
3228 break;
3229 }
3230 } else if(strlen(pathname) < b_size) {
3231 strcpy(b_buffer, pathname);
3232 break;
3233 }
3234
3235 /* Buffer not large enough, realloc and try again */
3236 b_buffer = realloc(b_buffer, b_size += BUFF_SIZE);
3237 if(b_buffer == NULL)
3238 BAD_ERROR("Realloc failed in getbase\n");
3239 }
3240
plougher1f413c82005-11-18 00:02:14 +00003241 name = b_buffer;
3242 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3243 return NULL;
3244 else
3245 return result;
3246}
3247
3248
3249char *basename_r()
3250{
3251 char *s;
3252 char *p;
3253 int n = 1;
3254
3255 for(;;) {
3256 s = name;
3257 if(*name == '\0')
3258 return NULL;
3259 if(*name != '/') {
3260 while(*name != '\0' && *name != '/') name++;
3261 n = name - s;
3262 }
3263 while(*name == '/') name++;
3264 if(strncmp(s, ".", n) == 0)
3265 continue;
plougher110799c2009-03-30 01:50:40 +00003266 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3267 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003268 s[n] = '\0';
3269 return s;
3270 }
3271 if(strcmp(p, "..") == 0)
3272 continue;
3273 return p;
3274 }
3275}
3276
3277
Phillip Lougher81204c22012-07-25 03:30:30 +01003278struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
plougher1f413c82005-11-18 00:02:14 +00003279{
Phillip Lougherd6577802012-10-04 19:14:33 +01003280 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3281 struct inode_info *inode;
plougher1f413c82005-11-18 00:02:14 +00003282
Phillip Lougherd6577802012-10-04 19:14:33 +01003283 /*
3284 * Look-up inode in hash table, if it already exists we have a
3285 * hard-link, so increment the nlink count and return it.
3286 * Don't do the look-up for directories because we don't hard-link
3287 * directories.
3288 */
3289 if ((buf->st_mode & S_IFMT) != S_IFDIR) {
3290 for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
3291 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3292 inode->nlink ++;
3293 return inode;
3294 }
plougher1f413c82005-11-18 00:02:14 +00003295 }
plougher1f413c82005-11-18 00:02:14 +00003296 }
3297
plougher288f6852010-12-16 05:22:55 +00003298 inode = malloc(sizeof(struct inode_info));
3299 if(inode == NULL)
plougher50b31762009-03-31 04:14:46 +00003300 BAD_ERROR("Out of memory in inode hash table entry allocation"
3301 "\n");
plougher1f413c82005-11-18 00:02:14 +00003302
3303 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003304 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003305 inode->root_entry = FALSE;
Phillip Lougher81204c22012-07-25 03:30:30 +01003306 inode->pseudo_file = pseudo;
3307 inode->pseudo_id = id;
plougher1f413c82005-11-18 00:02:14 +00003308 inode->inode = SQUASHFS_INVALID_BLK;
3309 inode->nlink = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003310 inode->inode_number = 0;
plougherdc86c3c2007-12-05 02:15:10 +00003311
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003312 /*
3313 * Copy filesystem wide defaults into inode, these filesystem
3314 * wide defaults may be altered on an individual inode basis by
3315 * user specified actions
3316 *
3317 */
3318 inode->no_fragments = no_fragments;
3319 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003320 inode->noD = noD;
3321 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003322
plougherdc86c3c2007-12-05 02:15:10 +00003323 if((buf->st_mode & S_IFMT) == S_IFREG)
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003324 progress_bar_size((buf->st_size + block_size - 1) >> block_log);
plougherdc86c3c2007-12-05 02:15:10 +00003325
Phillip Lougherd6577802012-10-04 19:14:33 +01003326 inode->next = inode_info[ino_hash];
3327 inode_info[ino_hash] = inode;
plougher1f413c82005-11-18 00:02:14 +00003328
3329 return inode;
3330}
3331
3332
Phillip Lougher81204c22012-07-25 03:30:30 +01003333inline struct inode_info *lookup_inode(struct stat *buf)
3334{
3335 return lookup_inode2(buf, 0, 0);
3336}
3337
3338
Phillip Lougher539c2b12012-07-30 20:14:52 +01003339inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3340{
3341 if (inode->inode_number == 0)
3342 inode->inode_number = use_this ? : inode_no ++;
3343}
3344
3345
Phillip Lougher494479f2012-02-03 15:45:41 +00003346inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3347 char *nonstandard_pathname, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003348{
Phillip Lougher494479f2012-02-03 15:45:41 +00003349 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3350 if(dir_ent == NULL)
3351 BAD_ERROR("Out of memory in linux_opendir\n");
3352
3353 dir_ent->name = name;
3354 dir_ent->source_name = source_name;
3355 dir_ent->nonstandard_pathname = nonstandard_pathname;
3356 dir_ent->our_dir = dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003357 dir_ent->next = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003358
3359 return dir_ent;
3360}
3361
3362
3363inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3364 struct inode_info *inode_info)
3365{
3366 struct dir_info *dir = dir_ent->our_dir;
3367
plougher1f413c82005-11-18 00:02:14 +00003368 if(sub_dir)
Phillip Lougher494479f2012-02-03 15:45:41 +00003369 sub_dir->dir_ent = dir_ent;
3370 dir_ent->inode = inode_info;
3371 dir_ent->dir = sub_dir;
3372
Phillip Lougherbf338362012-08-22 05:24:36 +01003373 dir_ent->next = dir->list;
3374 dir->list = dir_ent;
3375 dir->count++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003376}
3377
3378
3379inline void add_dir_entry2(char *name, char *source_name,
3380 char *nonstandard_pathname, struct dir_info *sub_dir,
3381 struct inode_info *inode_info, struct dir_info *dir)
3382{
3383 struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3384 nonstandard_pathname, dir);
3385
3386
3387 add_dir_entry(dir_ent, sub_dir, inode_info);
plougher1f413c82005-11-18 00:02:14 +00003388}
3389
3390
Phillip Lougher10a4b572012-02-18 23:26:10 +00003391inline void free_dir_entry(struct dir_ent *dir_ent)
3392{
Phillip Loughereb92b192012-10-01 03:39:00 +01003393 if(dir_ent->name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003394 free(dir_ent->name);
3395
Phillip Loughereb92b192012-10-01 03:39:00 +01003396 if(dir_ent->source_name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003397 free(dir_ent->source_name);
3398
3399 free(dir_ent);
3400}
3401
3402
Phillip Lougherad0f9212011-12-31 00:55:51 +00003403inline void add_excluded(struct dir_info *dir)
3404{
3405 dir->excluded ++;
3406}
3407
3408
plougher1f413c82005-11-18 00:02:14 +00003409
Phillip Lougherabc3b492012-07-29 02:53:35 +01003410void dir_scan(squashfs_inode *inode, char *pathname,
Phillip Lougherdc587a02012-11-14 05:30:27 +00003411 struct dir_ent *(_readdir)(struct dir_info *), struct pseudo *pseudo)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003412{
3413 struct stat buf;
3414 struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
3415 struct dir_ent *dir_ent;
3416
3417 if(dir_info == NULL)
3418 return;
3419
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003420 /*
3421 * Process most actions and any pseudo files
3422 */
3423 if(actions() || pseudo)
3424 dir_scan2(dir_info, pseudo);
3425
Phillip Loughere92cb512012-11-15 02:22:28 +00003426 /*
3427 * Process move actions
3428 */
3429 if(move_actions()) {
3430 dir_scan3(dir_info, dir_info);
3431 do_move_actions();
3432 }
3433
Phillip Lougher71ae14e2012-11-15 02:27:50 +00003434 /*
3435 * Process empty actions
3436 */
3437 if(empty_actions())
3438 dir_scan4(dir_info);
3439
Phillip Loughereb69dad2012-11-15 03:34:02 +00003440 /*
3441 * Sort directories and compute the inode numbers
3442 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003443 dir_scan5(dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003444
Phillip Lougherd0fe1d52012-10-09 03:34:34 +01003445 dir_ent = create_dir_entry("", NULL, pathname,
Phillip Lougher1eae83d2012-09-26 02:12:45 +01003446 scan1_opendir("", "", 0));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003447
3448 if(pathname[0] == '\0') {
3449 /*
3450 * dummy top level directory, if multiple sources specified on
3451 * command line
3452 */
3453 memset(&buf, 0, sizeof(buf));
3454 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3455 buf.st_uid = getuid();
3456 buf.st_gid = getgid();
3457 buf.st_mtime = time(NULL);
3458 buf.st_dev = 0;
3459 buf.st_ino = 0;
3460 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3461 } else {
Phillip Lougher38a35ec2012-11-30 04:31:35 +00003462 if(lstat(pathname, &buf) == -1)
3463 /* source directory has disappeared? */
Phillip Lougherfe58b492012-12-15 01:27:07 +00003464 BAD_ERROR("Cannot stat source directory %s because %s\n",
Phillip Lougherabc3b492012-07-29 02:53:35 +01003465 pathname, strerror(errno));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003466 dir_ent->inode = lookup_inode(&buf);
3467 }
3468
Phillip Lougher539c2b12012-07-30 20:14:52 +01003469 alloc_inode_no(dir_ent->inode, root_inode_number);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003470 dir_ent->dir = dir_info;
3471 dir_info->dir_ent = dir_ent;
3472
Andy Lutomirski3f31dcf2012-09-21 18:08:08 -07003473 eval_actions(dir_ent);
3474
Phillip Lougherabc3b492012-07-29 02:53:35 +01003475 if(sorted) {
3476 int res = generate_file_priorities(dir_info, 0,
3477 &dir_info->dir_ent->inode->buf);
3478
3479 if(res == FALSE)
3480 BAD_ERROR("generate_file_priorities failed\n");
3481 }
3482 queue_put(to_reader, dir_info);
3483 if(sorted)
3484 sort_files_and_write(dir_info);
3485 if(progress)
3486 enable_progress_bar();
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003487 dir_scan6(inode, dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003488 dir_ent->inode->inode = *inode;
3489 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003490}
3491
3492
Phillip Lougherabc3b492012-07-29 02:53:35 +01003493/*
3494 * dir_scan1 routines...
Phillip Loughere8630be2012-11-11 02:24:24 +00003495 * These scan the source directories into memory for processing.
3496 * Exclude actions are processed here (in contrast to the other actions)
3497 * because they affect what is scanned.
Phillip Lougherabc3b492012-07-29 02:53:35 +01003498 */
Phillip Lougherb38c1722012-02-09 23:26:19 +00003499struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
plougher1f413c82005-11-18 00:02:14 +00003500{
plougher1f413c82005-11-18 00:02:14 +00003501 struct dir_info *dir;
3502
plougher6da792b2010-12-16 05:25:39 +00003503 dir = malloc(sizeof(struct dir_info));
3504 if(dir == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003505 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003506
3507 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3508 free(dir);
3509 return NULL;
3510 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003511 dir->pathname = pathname;
Phillip Lougherb38c1722012-02-09 23:26:19 +00003512 dir->subpath = subpath;
Phillip Lougherded70fa2011-12-25 02:14:58 +00003513 dir->count = 0;
3514 dir->directory_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003515 dir->dir_is_ldir = TRUE;
3516 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003517 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003518 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003519
3520 return dir;
3521}
3522
3523
Phillip Lougher494479f2012-02-03 15:45:41 +00003524struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003525{
plougher1f413c82005-11-18 00:02:14 +00003526 static int index = 0;
3527
plougher11266ba2010-12-16 05:34:30 +00003528 if(dir->count < old_root_entries) {
3529 int i;
3530
plougher1f413c82005-11-18 00:02:14 +00003531 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003532 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003533 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003534 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003535 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003536 }
plougher11266ba2010-12-16 05:34:30 +00003537 }
plougher1f413c82005-11-18 00:02:14 +00003538
3539 while(index < source) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003540 char *basename = NULL;
3541 char *dir_name = getbase(source_path[index]);
Phillip Lougherbf338362012-08-22 05:24:36 +01003542 int pass = 1, res;
plougher89fe2c72010-12-16 05:31:34 +00003543
Phillip Lougherc73ed322012-10-01 03:25:41 +01003544 if(dir_name == NULL) {
plougher110799c2009-03-30 01:50:40 +00003545 ERROR("Bad source directory %s - skipping ...\n",
3546 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003547 index ++;
3548 continue;
3549 }
Phillip Lougherc73ed322012-10-01 03:25:41 +01003550 dir_name = strdup(dir_name);
plougher1f413c82005-11-18 00:02:14 +00003551 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003552 struct dir_ent *dir_ent = dir->list;
3553
3554 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3555 dir_ent = dir_ent->next);
3556 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003557 break;
plougher50b31762009-03-31 04:14:46 +00003558 ERROR("Source directory entry %s already used! - trying"
3559 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003560 if(pass == 1)
3561 basename = dir_name;
3562 else
Phillip Lougherb38c1722012-02-09 23:26:19 +00003563 free(dir_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003564 res = asprintf(&dir_name, "%s_%d", basename, pass++);
3565 if(res == -1)
3566 BAD_ERROR("asprintf failed in "
3567 "scan1_encomp_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003568 ERROR("%s\n", dir_name);
3569 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00003570 return create_dir_entry(dir_name, basename,
3571 source_path[index ++], dir);
plougher1f413c82005-11-18 00:02:14 +00003572 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003573 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003574}
3575
3576
Phillip Lougher494479f2012-02-03 15:45:41 +00003577struct dir_ent *scan1_single_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003578{
3579 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003580 int i;
plougher1f413c82005-11-18 00:02:14 +00003581
plougher4925e172010-12-16 05:45:54 +00003582 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003583 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003584 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003585 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003586 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003587 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003588 }
plougher4925e172010-12-16 05:45:54 +00003589 }
plougher1f413c82005-11-18 00:02:14 +00003590
3591 if((d_name = readdir(dir->linuxdir)) != NULL) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003592 char *basename = NULL;
3593 char *dir_name = strdup(d_name->d_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003594 int pass = 1, res;
plougher4925e172010-12-16 05:45:54 +00003595
plougher1f413c82005-11-18 00:02:14 +00003596 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003597 struct dir_ent *dir_ent = dir->list;
3598
3599 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3600 dir_ent = dir_ent->next);
3601 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003602 break;
plougher50b31762009-03-31 04:14:46 +00003603 ERROR("Source directory entry %s already used! - trying"
3604 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003605 if (pass == 1)
3606 basename = dir_name;
3607 else
Phillip Lougher494479f2012-02-03 15:45:41 +00003608 free(dir_name);
3609 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3610 if(res == -1)
3611 BAD_ERROR("asprintf failed in "
3612 "scan1_single_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003613 ERROR("%s\n", dir_name);
3614 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003615 return create_dir_entry(dir_name, basename, NULL, dir);
plougher1f413c82005-11-18 00:02:14 +00003616 }
3617
Phillip Lougher494479f2012-02-03 15:45:41 +00003618 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003619}
3620
3621
Phillip Lougher494479f2012-02-03 15:45:41 +00003622struct dir_ent *scan1_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003623{
plougher480d9bf2010-12-18 02:28:39 +00003624 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003625
Phillip Lougher494479f2012-02-03 15:45:41 +00003626 return d_name ?
3627 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3628 NULL;
plougher1f413c82005-11-18 00:02:14 +00003629}
3630
3631
plougher1f413c82005-11-18 00:02:14 +00003632void scan1_freedir(struct dir_info *dir)
3633{
plougherfbed12b2006-02-07 12:45:53 +00003634 if(dir->pathname[0] != '\0')
3635 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003636}
3637
3638
Phillip Lougherb38c1722012-02-09 23:26:19 +00003639struct dir_info *dir_scan1(char *filename, char *subpath,
3640 struct pathnames *paths,
Phillip Lougher494479f2012-02-03 15:45:41 +00003641 struct dir_ent *(_readdir)(struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003642{
Phillip Lougherb38c1722012-02-09 23:26:19 +00003643 struct dir_info *dir = scan1_opendir(filename, subpath, depth);
Phillip Lougher494479f2012-02-03 15:45:41 +00003644 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003645
plougher360b6e42010-12-18 02:40:28 +00003646 if(dir == NULL) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003647 ERROR("Could not open %s, skipping...\n", filename);
plougher1f413c82005-11-18 00:02:14 +00003648 goto error;
3649 }
3650
Phillip Lougher494479f2012-02-03 15:45:41 +00003651 while((dir_ent = _readdir(dir))) {
plougher360b6e42010-12-18 02:40:28 +00003652 struct dir_info *sub_dir;
3653 struct stat buf;
3654 struct pathnames *new;
Phillip Lougher494479f2012-02-03 15:45:41 +00003655 char *filename = pathname(dir_ent);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003656 char *subpath = subpathname(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003657 char *dir_name = dir_ent->name;
plougher1f413c82005-11-18 00:02:14 +00003658
Phillip Lougher494479f2012-02-03 15:45:41 +00003659 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003660 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003661 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003662 }
plougher1f413c82005-11-18 00:02:14 +00003663
3664 if(lstat(filename, &buf) == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00003665 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
plougher110799c2009-03-30 01:50:40 +00003666 filename, strerror(errno));
Phillip Lougher10a4b572012-02-18 23:26:10 +00003667 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003668 continue;
3669 }
plougher29e37092007-04-15 01:24:51 +00003670
3671 if((buf.st_mode & S_IFMT) != S_IFREG &&
Phillip Loughere4ff36a2012-11-19 01:34:47 +00003672 (buf.st_mode & S_IFMT) != S_IFDIR &&
3673 (buf.st_mode & S_IFMT) != S_IFLNK &&
3674 (buf.st_mode & S_IFMT) != S_IFCHR &&
3675 (buf.st_mode & S_IFMT) != S_IFBLK &&
3676 (buf.st_mode & S_IFMT) != S_IFIFO &&
3677 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003678 ERROR("File %s has unrecognised filetype %d, ignoring"
3679 "\n", filename, buf.st_mode & S_IFMT);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003680 free_dir_entry(dir_ent);
plougher29e37092007-04-15 01:24:51 +00003681 continue;
3682 }
3683
Phillip Lougherad0f9212011-12-31 00:55:51 +00003684 if((old_exclude && old_excluded(filename, &buf)) ||
3685 excluded(paths, dir_name, &new) ||
Phillip Lougherb4f4b0d2012-02-20 02:30:26 +00003686 eval_exclude_actions(dir_name, filename, subpath,
3687 &buf, depth)) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003688 add_excluded(dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003689 free_dir_entry(dir_ent);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003690 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003691 }
plougher1f413c82005-11-18 00:02:14 +00003692
3693 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003694 filename = strdup(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003695 subpath = strdup(subpath);
3696 sub_dir = dir_scan1(filename, subpath, new,
3697 scan1_readdir, depth + 1);
Phillip Lougher494479f2012-02-03 15:45:41 +00003698 if(sub_dir == NULL) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003699 free_dir_entry(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003700 free(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003701 free(subpath);
plougher1f413c82005-11-18 00:02:14 +00003702 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003703 }
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003704
plougher1f413c82005-11-18 00:02:14 +00003705 dir->directory_count ++;
3706 } else
3707 sub_dir = NULL;
3708
Phillip Lougher494479f2012-02-03 15:45:41 +00003709 add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
plougher1f413c82005-11-18 00:02:14 +00003710 }
3711
3712 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003713
3714error:
3715 return dir;
3716}
3717
plougher2ea89142008-03-11 01:34:19 +00003718
Phillip Lougherabc3b492012-07-29 02:53:35 +01003719/*
3720 * dir_scan2 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003721 * This processes most actions and any pseudo files
Phillip Lougherabc3b492012-07-29 02:53:35 +01003722 */
Phillip Lougherbf338362012-08-22 05:24:36 +01003723struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003724{
Phillip Lougherbf338362012-08-22 05:24:36 +01003725 if (dir_ent == NULL)
3726 dir_ent = dir->list;
3727 else
3728 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003729
Phillip Lougherbf338362012-08-22 05:24:36 +01003730 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3731
3732 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003733}
3734
3735
3736struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3737{
Phillip Lougherbf338362012-08-22 05:24:36 +01003738 struct dir_ent *dir_ent = dir->list;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003739
Phillip Lougherbf338362012-08-22 05:24:36 +01003740 for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3741 dir_ent = dir_ent->next);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003742
Phillip Lougherbf338362012-08-22 05:24:36 +01003743 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003744}
3745
3746
Phillip Lougher24eeb772012-10-13 01:56:24 +01003747void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
plougher43244f22009-04-05 02:04:51 +00003748{
Phillip Lougherbf338362012-08-22 05:24:36 +01003749 struct dir_ent *dir_ent = NULL;
plougher43244f22009-04-05 02:04:51 +00003750 struct pseudo_entry *pseudo_ent;
3751 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003752 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003753
Phillip Lougherbf338362012-08-22 05:24:36 +01003754 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
plougher43244f22009-04-05 02:04:51 +00003755 struct inode_info *inode_info = dir_ent->inode;
3756 struct stat *buf = &inode_info->buf;
3757 char *name = dir_ent->name;
3758
Phillip Lougher89d757c2011-09-20 00:33:19 +01003759 eval_actions(dir_ent);
3760
plougher43244f22009-04-05 02:04:51 +00003761 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher24eeb772012-10-13 01:56:24 +01003762 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
plougher43244f22009-04-05 02:04:51 +00003763 }
3764
3765 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3766 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003767 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003768 struct stat *buf;
3769 if(dir_ent == NULL) {
plougherdcd66c52010-09-17 03:44:17 +00003770 ERROR("Pseudo modify file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003771 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003772 pseudo_ent->pathname);
3773 continue;
3774 }
ploughera326c182009-08-29 05:41:45 +00003775 if(dir_ent->inode->root_entry) {
plougherdcd66c52010-09-17 03:44:17 +00003776 ERROR("Pseudo modify file \"%s\" is a pre-existing"
plougherb34f9f62009-04-26 02:08:42 +00003777 " file in the filesystem being appended"
3778 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003779 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003780 continue;
3781 }
3782 buf = &dir_ent->inode->buf;
3783 buf->st_mode = (buf->st_mode & S_IFMT) |
3784 pseudo_ent->dev->mode;
3785 buf->st_uid = pseudo_ent->dev->uid;
3786 buf->st_gid = pseudo_ent->dev->gid;
3787 continue;
3788 }
3789
plougher43244f22009-04-05 02:04:51 +00003790 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003791 if(dir_ent->inode->root_entry)
3792 ERROR("Pseudo file \"%s\" is a pre-existing"
3793 " file in the filesystem being appended"
3794 " to. Ignoring.\n",
3795 pseudo_ent->pathname);
3796 else
3797 ERROR("Pseudo file \"%s\" exists in source "
plougherdcd66c52010-09-17 03:44:17 +00003798 "filesystem \"%s\".\nIgnoring, "
plougherf0dc2382010-05-01 23:55:06 +00003799 "exclude it (-e/-ef) to override.\n",
3800 pseudo_ent->pathname,
Phillip Lougher494479f2012-02-03 15:45:41 +00003801 pathname(dir_ent));
plougher43244f22009-04-05 02:04:51 +00003802 continue;
3803 }
3804
plougher43244f22009-04-05 02:04:51 +00003805 memset(&buf, 0, sizeof(buf));
3806 buf.st_mode = pseudo_ent->dev->mode;
3807 buf.st_uid = pseudo_ent->dev->uid;
3808 buf.st_gid = pseudo_ent->dev->gid;
3809 buf.st_rdev = makedev(pseudo_ent->dev->major,
3810 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003811 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003812 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003813
Phillip Lougher5d579292012-10-13 01:37:16 +01003814 if(pseudo_ent->dev->type == 'd') {
3815 struct dir_ent *dir_ent =
3816 create_dir_entry(pseudo_ent->name, NULL,
3817 pseudo_ent->pathname, dir);
3818 char *subpath = strdup(subpathname(dir_ent));
3819 struct dir_info *sub_dir = scan1_opendir("", subpath,
Phillip Lougher24eeb772012-10-13 01:56:24 +01003820 dir->depth + 1);
Phillip Lougher5d579292012-10-13 01:37:16 +01003821 if(sub_dir == NULL) {
3822 ERROR("Could not create pseudo directory \"%s\""
3823 ", skipping...\n",
3824 pseudo_ent->pathname);
3825 free(subpath);
3826 pseudo_ino --;
3827 continue;
3828 }
Phillip Lougher24eeb772012-10-13 01:56:24 +01003829 dir_scan2(sub_dir, pseudo_ent->pseudo);
Phillip Lougher5d579292012-10-13 01:37:16 +01003830 dir->directory_count ++;
3831 add_dir_entry(dir_ent, sub_dir,
3832 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3833 } else if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003834#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003835 struct stat buf2;
3836 int res = stat(pseudo_ent->dev->filename, &buf2);
3837 if(res == -1) {
3838 ERROR("Stat on pseudo file \"%s\" failed, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00003839 "skipping...\n", pseudo_ent->pathname);
Phillip Lougher5d579292012-10-13 01:37:16 +01003840 pseudo_ino --;
plougher4ab7e512009-05-05 02:35:58 +00003841 continue;
3842 }
3843 buf.st_size = buf2.st_size;
Phillip Lougher494479f2012-02-03 15:45:41 +00003844 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003845 pseudo_ent->dev->filename, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003846 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougher00d08172009-09-03 10:17:44 +00003847#else
Phillip Lougher494479f2012-02-03 15:45:41 +00003848 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003849 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003850 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3851 pseudo_ent->dev->pseudo_id), dir);
plougher00d08172009-09-03 10:17:44 +00003852#endif
plougherb85e9ad2010-05-02 01:46:12 +00003853 } else {
Phillip Lougher494479f2012-02-03 15:45:41 +00003854 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003855 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003856 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003857 }
plougher43244f22009-04-05 02:04:51 +00003858 }
plougher43244f22009-04-05 02:04:51 +00003859}
3860
3861
Phillip Lougherabc3b492012-07-29 02:53:35 +01003862/*
3863 * dir_scan3 routines...
Phillip Lougher23d83622012-10-14 02:35:22 +01003864 * This processes the move action
3865 */
3866void dir_scan3(struct dir_info *root, struct dir_info *dir)
3867{
3868 struct dir_ent *dir_ent = NULL;
3869
3870 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3871
3872 eval_move_actions(root, dir_ent);
3873
3874 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3875 dir_scan3(root, dir_ent->dir);
3876 }
3877}
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003878
3879
Phillip Lougher23d83622012-10-14 02:35:22 +01003880/*
3881 * dir_scan4 routines...
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003882 * This processes the empty action. This action has to be processed after
3883 * all other actions because the previous exclude and move actions and the
3884 * pseudo actions affect whether a directory is empty
3885 */
3886void dir_scan4(struct dir_info *dir)
3887{
3888 struct dir_ent *dir_ent = dir->list, *prev = NULL;
3889
3890 while(dir_ent) {
Phillip Lougher15e8f042012-11-16 00:57:39 +00003891 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3892 dir_scan4(dir_ent->dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003893
Phillip Lougher15e8f042012-11-16 00:57:39 +00003894 if(eval_empty_actions(dir_ent)) {
3895 struct dir_ent *tmp = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003896
Phillip Lougher15e8f042012-11-16 00:57:39 +00003897 /*
3898 * delete sub-directory, this is by definition
3899 * empty
3900 */
3901 free(dir_ent->dir->pathname);
3902 free(dir_ent->dir->subpath);
3903 free(dir_ent->dir);
3904
3905 /* remove dir_ent from list */
3906 dir_ent = dir_ent->next;
3907 if(prev)
3908 prev->next = dir_ent;
3909 else
3910 dir->list = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003911
Phillip Lougher15e8f042012-11-16 00:57:39 +00003912 /* free it */
3913 free_dir_entry(tmp);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003914
Phillip Lougher15e8f042012-11-16 00:57:39 +00003915 /* update counts */
3916 dir->directory_count --;
3917 dir->count --;
3918 add_excluded(dir);
3919 continue;
3920 }
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003921 }
Phillip Lougher15e8f042012-11-16 00:57:39 +00003922
3923 prev = dir_ent;
3924 dir_ent = dir_ent->next;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003925 }
3926}
3927
3928
3929/*
3930 * dir_scan5 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003931 * This sorts every directory and computes the inode numbers
3932 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003933
Phillip Lougher242242e2012-08-24 04:15:36 +01003934/*
3935 * Bottom up linked list merge sort.
3936 *
3937 * Qsort and other O(n log n) algorithms work well with arrays but not
3938 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand
3939 * is not ideal for arrays (as it needs an additonal n storage locations
3940 * as sorting is not done in place), but it is ideal for linked lists because
3941 * it doesn't require any extra storage,
3942 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003943void sort_directory(struct dir_info *dir)
3944{
Phillip Lougher242242e2012-08-24 04:15:36 +01003945 struct dir_ent *cur, *l1, *l2, *next;
3946 int len1, len2, stride = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003947
Phillip Lougher242242e2012-08-24 04:15:36 +01003948 if(dir->count < 2)
Phillip Lougherbf338362012-08-22 05:24:36 +01003949 return;
3950
Phillip Lougher242242e2012-08-24 04:15:36 +01003951 /*
3952 * We can consider our linked-list to be made up of stride length
3953 * sublists. Eacn iteration around this loop merges adjacent
3954 * stride length sublists into larger 2*stride sublists. We stop
3955 * when stride becomes equal to the entire list.
3956 *
3957 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
3958 * these 1 element sublists are merged into 2 element sublists, which
3959 * are then merged into 4 element sublists and so on.
3960 */
3961 do {
3962 l2 = dir->list; /* head of current linked list */
3963 cur = NULL; /* empty output list */
Phillip Lougherbf338362012-08-22 05:24:36 +01003964
Phillip Lougher242242e2012-08-24 04:15:36 +01003965 /*
3966 * Iterate through the linked list, merging adjacent sublists.
3967 * On each interation l2 points to the next sublist pair to be
3968 * merged (if there's only one sublist left this is simply added
3969 * to the output list)
3970 */
3971 while(l2) {
3972 l1 = l2;
3973 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
3974 len2 = stride;
Phillip Lougherbf338362012-08-22 05:24:36 +01003975
Phillip Lougher242242e2012-08-24 04:15:36 +01003976 /*
3977 * l1 points to first sublist.
3978 * l2 points to second sublist.
3979 * Merge them onto the output list
3980 */
3981 while(len1 && l2 && len2) {
3982 if(strcmp(l1->name, l2->name) <= 0) {
3983 next = l1;
3984 l1 = l1->next;
3985 len1 --;
3986 } else {
3987 next = l2;
3988 l2 = l2->next;
3989 len2 --;
3990 }
3991
3992 if(cur) {
3993 cur->next = next;
3994 cur = next;
3995 } else
3996 dir->list = cur = next;
3997 }
3998 /*
3999 * One sublist is now empty, copy the other one onto the
4000 * output list
4001 */
4002 for(; len1; len1 --, l1 = l1->next) {
4003 if(cur) {
4004 cur->next = l1;
4005 cur = l1;
4006 } else
4007 dir->list = cur = l1;
4008 }
4009 for(; l2 && len2; len2 --, l2 = l2->next) {
4010 if(cur) {
4011 cur->next = l2;
4012 cur = l2;
4013 } else
4014 dir->list = cur = l2;
4015 }
4016 }
4017 cur->next = NULL;
4018 stride = stride << 1;
4019 } while(stride < dir->count);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004020}
4021
4022
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004023void dir_scan5(struct dir_info *dir)
Phillip Lougher539c2b12012-07-30 20:14:52 +01004024{
Phillip Lougher23d83622012-10-14 02:35:22 +01004025 struct dir_ent *dir_ent;
4026 unsigned int byte_count = 0;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004027
4028 sort_directory(dir);
4029
Phillip Lougher23d83622012-10-14 02:35:22 +01004030 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
4031 byte_count += strlen(dir_ent->name) +
4032 sizeof(struct squashfs_dir_entry);
4033
4034 if(dir_ent->inode->root_entry)
4035 continue;
4036
Phillip Lougher539c2b12012-07-30 20:14:52 +01004037 alloc_inode_no(dir_ent->inode, 0);
Phillip Lougher23d83622012-10-14 02:35:22 +01004038
Phillip Lougher539c2b12012-07-30 20:14:52 +01004039 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
Phillip Loughere69b5882012-11-19 01:31:09 +00004040 dir_scan5(dir_ent->dir);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004041 }
Phillip Lougher23d83622012-10-14 02:35:22 +01004042
4043 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
4044 dir->dir_is_ldir = FALSE;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004045}
4046
4047
4048/*
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004049 * dir_scan6 routines...
Phillip Lougherabc3b492012-07-29 02:53:35 +01004050 * This generates the filesystem metadata and writes it out to the destination
4051 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004052void scan6_init_dir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004053{
4054 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
4055 if(dir->buff == NULL) {
4056 BAD_ERROR("Out of memory allocating directory buffer\n");
4057 }
4058
4059 dir->size = SQUASHFS_METADATA_SIZE;
4060 dir->p = dir->index_count_p = dir->buff;
4061 dir->entry_count = 256;
4062 dir->entry_count_p = NULL;
4063 dir->index = NULL;
4064 dir->i_count = dir->i_size = 0;
4065}
4066
4067
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004068struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
Phillip Lougherbf338362012-08-22 05:24:36 +01004069 struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004070{
Phillip Lougherbf338362012-08-22 05:24:36 +01004071 if (dir_ent == NULL)
4072 dir_ent = dir_info->list;
4073 else
4074 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004075
Phillip Lougherbf338362012-08-22 05:24:36 +01004076 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
4077 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
4078 dir_ent->name, dir_ent->inode->type, dir);
4079
4080 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004081}
4082
4083
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004084void scan6_freedir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004085{
4086 if(dir->index)
4087 free(dir->index);
4088 free(dir->buff);
4089}
4090
4091
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004092void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00004093{
4094 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00004095 int duplicate_file;
plougher1f413c82005-11-18 00:02:14 +00004096 struct directory dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01004097 struct dir_ent *dir_ent = NULL;
plougher1f413c82005-11-18 00:02:14 +00004098
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004099 scan6_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004100
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004101 while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
Phillip Lougher0a670882012-10-05 04:09:13 +01004102 struct stat *buf = &dir_ent->inode->buf;
plougher1f413c82005-11-18 00:02:14 +00004103
4104 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
4105 switch(buf->st_mode & S_IFMT) {
4106 case S_IFREG:
4107 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00004108 write_file(inode, dir_ent,
4109 &duplicate_file);
4110 INFO("file %s, uncompressed size %lld "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004111 "bytes %s\n",
4112 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004113 (long long) buf->st_size,
4114 duplicate_file ? "DUPLICATE" :
4115 "");
plougher1f413c82005-11-18 00:02:14 +00004116 break;
4117
4118 case S_IFDIR:
4119 squashfs_type = SQUASHFS_DIR_TYPE;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004120 dir_scan6(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00004121 break;
4122
4123 case S_IFLNK:
4124 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004125 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004126 squashfs_type, 0, 0, 0, NULL,
4127 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004128 INFO("symbolic link %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004129 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004130 sym_count ++;
4131 break;
4132
4133 case S_IFCHR:
4134 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004135 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004136 squashfs_type, 0, 0, 0, NULL,
4137 NULL, NULL, 0);
4138 INFO("character device %s inode 0x%llx"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004139 "\n", subpathname(dir_ent),
4140 *inode);
plougher1f413c82005-11-18 00:02:14 +00004141 dev_count ++;
4142 break;
4143
4144 case S_IFBLK:
4145 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004146 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004147 squashfs_type, 0, 0, 0, NULL,
4148 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004149 INFO("block device %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004150 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004151 dev_count ++;
4152 break;
4153
4154 case S_IFIFO:
4155 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004156 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004157 squashfs_type, 0, 0, 0, NULL,
4158 NULL, NULL, 0);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004159 INFO("fifo %s inode 0x%llx\n",
4160 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004161 fifo_count ++;
4162 break;
4163
4164 case S_IFSOCK:
4165 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004166 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004167 squashfs_type, 0, 0, 0, NULL,
4168 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004169 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004170 "0x%llx\n",
4171 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004172 sock_count ++;
4173 break;
4174
plougher23377982007-11-12 04:04:48 +00004175 default:
plougherb3604122009-03-30 02:07:20 +00004176 BAD_ERROR("%s unrecognised file type, "
Phillip Lougher494479f2012-02-03 15:45:41 +00004177 "mode is %x\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004178 subpathname(dir_ent),
plougherb3604122009-03-30 02:07:20 +00004179 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00004180 }
4181 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00004182 dir_ent->inode->type = squashfs_type;
4183 } else {
4184 *inode = dir_ent->inode->inode;
4185 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00004186 switch(squashfs_type) {
4187 case SQUASHFS_FILE_TYPE:
4188 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00004189 INFO("file %s, uncompressed "
4190 "size %lld bytes LINK"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004191 "\n",
4192 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004193 (long long)
plougher50b31762009-03-31 04:14:46 +00004194 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00004195 break;
4196 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00004197 INFO("symbolic link %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004198 "LINK\n", subpathname(dir_ent),
4199 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004200 break;
4201 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004202 INFO("character device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004203 "LINK\n", subpathname(dir_ent),
4204 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004205 break;
plougher5507dd92006-11-06 00:43:10 +00004206 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004207 INFO("block device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004208 "LINK\n", subpathname(dir_ent),
4209 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004210 break;
4211 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00004212 INFO("fifo %s inode 0x%llx LINK\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004213 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004214 break;
4215 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00004216 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004217 "0x%llx LINK\n",
4218 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004219 break;
4220 }
plougher1f413c82005-11-18 00:02:14 +00004221 }
4222
Phillip Lougher0366aec2012-10-05 04:06:04 +01004223 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
4224 squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00004225 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004226 }
4227
plougher29e37092007-04-15 01:24:51 +00004228 write_dir(inode, dir_info, &dir);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004229 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
4230 *inode);
plougher1f413c82005-11-18 00:02:14 +00004231
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004232 scan6_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004233}
4234
4235
4236unsigned int slog(unsigned int block)
4237{
4238 int i;
4239
plougher4c99cb72007-06-14 21:46:31 +00004240 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00004241 if(block == (1 << i))
4242 return i;
4243 return 0;
4244}
4245
4246
plougher8f8e1a12007-10-18 02:50:21 +00004247int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00004248{
4249 int i;
4250
4251 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00004252 if((exclude_paths[i].st_dev == buf->st_dev) &&
4253 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00004254 return TRUE;
4255 return FALSE;
4256}
4257
4258
4259#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00004260 if(exclude % EXCLUDE_SIZE == 0) { \
4261 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4262 * sizeof(struct exclude_info)); \
4263 if(exclude_paths == NULL) \
4264 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
4265 } \
4266 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00004267 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00004268int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00004269{
4270 int i;
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004271 char *filename;
plougher1f413c82005-11-18 00:02:14 +00004272 struct stat buf;
4273
plougherb3604122009-03-30 02:07:20 +00004274 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4275 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00004276 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00004277 ERROR("Cannot stat exclude dir/file %s because %s, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004278 "ignoring\n", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004279 return TRUE;
4280 }
4281 ADD_ENTRY(buf);
4282 return TRUE;
4283 }
4284
4285 for(i = 0; i < source; i++) {
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004286 int res = asprintf(&filename, "%s/%s", source_path[i], path);
4287 if(res == -1)
4288 BAD_ERROR("asprintf failed in old_add_exclude\n");
plougher1f413c82005-11-18 00:02:14 +00004289 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00004290 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00004291 ERROR("Cannot stat exclude dir/file %s because "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004292 "%s, ignoring\n", filename,
plougher50b31762009-03-31 04:14:46 +00004293 strerror(errno));
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004294 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004295 continue;
4296 }
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004297 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004298 ADD_ENTRY(buf);
4299 }
4300 return TRUE;
4301}
4302
4303
plougherb3604122009-03-30 02:07:20 +00004304void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4305 int type)
plougher1f413c82005-11-18 00:02:14 +00004306{
plougherb3604122009-03-30 02:07:20 +00004307 old_root_entry = realloc(old_root_entry,
4308 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4309 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00004310 BAD_ERROR("Out of memory in old root directory entries "
4311 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00004312
ploughera326c182009-08-29 05:41:45 +00004313 old_root_entry[old_root_entries].name = strdup(name);
4314 old_root_entry[old_root_entries].inode.inode = inode;
4315 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4316 old_root_entry[old_root_entries].inode.type = type;
4317 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004318}
4319
4320
plougher5741d792010-09-04 03:20:50 +00004321void initialise_threads(int readb_mbytes, int writeb_mbytes,
4322 int fragmentb_mbytes)
plougher5507dd92006-11-06 00:43:10 +00004323{
4324 int i;
4325 sigset_t sigmask, old_mask;
plougher5741d792010-09-04 03:20:50 +00004326 int reader_buffer_size = readb_mbytes << (20 - block_log);
4327 int fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
4328
4329 /*
4330 * writer_buffer_size is global because it is needed in
4331 * write_file_blocks_dup()
4332 */
4333 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004334
4335 sigemptyset(&sigmask);
4336 sigaddset(&sigmask, SIGINT);
4337 sigaddset(&sigmask, SIGQUIT);
4338 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4339 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4340
4341 signal(SIGUSR1, sigusr1_handler);
4342
4343 if(processors == -1) {
4344#ifndef linux
4345 int mib[2];
4346 size_t len = sizeof(processors);
4347
4348 mib[0] = CTL_HW;
4349#ifdef HW_AVAILCPU
4350 mib[1] = HW_AVAILCPU;
4351#else
4352 mib[1] = HW_NCPU;
4353#endif
4354
4355 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004356 ERROR("Failed to get number of available processors. "
4357 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004358 processors = 1;
4359 }
4360#else
plougher9cc26b72010-08-17 01:05:55 +00004361 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004362#endif
4363 }
4364
plougherf2d2a842010-12-18 02:43:48 +00004365 thread = malloc((2 + processors * 2) * sizeof(pthread_t));
4366 if(thread == NULL)
plougher5507dd92006-11-06 00:43:10 +00004367 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004368 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004369 frag_deflator_thread = &deflator_thread[processors];
4370
4371 to_reader = queue_init(1);
4372 from_reader = queue_init(reader_buffer_size);
4373 to_writer = queue_init(writer_buffer_size);
4374 from_writer = queue_init(1);
4375 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004376 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004377 reader_buffer = cache_init(block_size, reader_buffer_size);
4378 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004379 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004380 pthread_create(&thread[0], NULL, reader, NULL);
4381 pthread_create(&thread[1], NULL, writer, NULL);
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004382 init_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00004383 pthread_mutex_init(&fragment_mutex, NULL);
4384 pthread_cond_init(&fragment_waiting, NULL);
4385
4386 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004387 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4388 0)
plougher5507dd92006-11-06 00:43:10 +00004389 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004390 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4391 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004392 BAD_ERROR("Failed to create thread\n");
4393 }
4394
4395 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4396 processors == 1 ? "" : "s");
4397
4398 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4399 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4400}
4401
4402
plougher0e453652006-11-06 01:49:35 +00004403long long write_inode_lookup_table()
4404{
4405 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004406 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004407
4408 if(inode_count == sinode_count)
4409 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004410
plougher44f03282010-07-27 00:31:36 +00004411 it = realloc(inode_lookup_table, lookup_bytes);
4412 if(it == NULL)
plougher0e453652006-11-06 01:49:35 +00004413 BAD_ERROR("Out of memory in write_inode_table\n");
plougher44f03282010-07-27 00:31:36 +00004414 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004415
plougher0e453652006-11-06 01:49:35 +00004416 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4417 struct inode_info *inode = inode_info[i];
4418
4419 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004420
Phillip Lougher539c2b12012-07-30 20:14:52 +01004421 inode_number = get_inode_no(inode);
plougher0e453652006-11-06 01:49:35 +00004422
plougher360514a2009-03-30 03:01:38 +00004423 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4424 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004425
plougher0e453652006-11-06 01:49:35 +00004426 }
4427 }
4428
plougher02bc3bc2007-02-25 12:12:01 +00004429skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004430 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4431 noI);
plougher0e453652006-11-06 01:49:35 +00004432}
4433
plougher2ea89142008-03-11 01:34:19 +00004434
Phillip Lougher8e44e052012-11-26 02:58:35 +00004435char *get_component(char *target, char **targname)
plougher8f8e1a12007-10-18 02:50:21 +00004436{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004437 char *start;
4438
plougher8f8e1a12007-10-18 02:50:21 +00004439 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004440 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004441
Phillip Lougher8e44e052012-11-26 02:58:35 +00004442 start = target;
plougher8f8e1a12007-10-18 02:50:21 +00004443 while(*target != '/' && *target!= '\0')
Phillip Lougher8e44e052012-11-26 02:58:35 +00004444 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004445
Phillip Lougher8e44e052012-11-26 02:58:35 +00004446 *targname = strndup(start, target - start);
plougher8f8e1a12007-10-18 02:50:21 +00004447
4448 return target;
4449}
4450
4451
4452void free_path(struct pathname *paths)
4453{
4454 int i;
4455
4456 for(i = 0; i < paths->names; i++) {
4457 if(paths->name[i].paths)
4458 free_path(paths->name[i].paths);
4459 free(paths->name[i].name);
4460 if(paths->name[i].preg) {
4461 regfree(paths->name[i].preg);
4462 free(paths->name[i].preg);
4463 }
4464 }
4465
4466 free(paths);
4467}
4468
4469
4470struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4471{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004472 char *targname;
plougher8f8e1a12007-10-18 02:50:21 +00004473 int i, error;
4474
Phillip Lougher8e44e052012-11-26 02:58:35 +00004475 target = get_component(target, &targname);
plougher8f8e1a12007-10-18 02:50:21 +00004476
4477 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004478 paths = malloc(sizeof(struct pathname));
4479 if(paths == NULL)
plougher8f8e1a12007-10-18 02:50:21 +00004480 BAD_ERROR("failed to allocate paths\n");
4481
4482 paths->names = 0;
4483 paths->name = NULL;
4484 }
4485
4486 for(i = 0; i < paths->names; i++)
4487 if(strcmp(paths->name[i].name, targname) == 0)
4488 break;
4489
4490 if(i == paths->names) {
4491 /* allocate new name entry */
4492 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004493 paths->name = realloc(paths->name, (i + 1) *
4494 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004495 if(paths->name == NULL)
4496 BAD_ERROR("Out of memory in add path\n");
Phillip Lougher8e44e052012-11-26 02:58:35 +00004497 paths->name[i].name = targname;
plougher8f8e1a12007-10-18 02:50:21 +00004498 paths->name[i].paths = NULL;
4499 if(use_regex) {
4500 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004501 if(paths->name[i].preg == NULL)
4502 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004503 error = regcomp(paths->name[i].preg, targname,
4504 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004505 if(error) {
Phillip Lougher62859d22012-11-30 05:53:56 +00004506 char str[1024]; /* overflow safe */
plougher8f8e1a12007-10-18 02:50:21 +00004507
4508 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004509 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004510 "because %s\n", targname, alltarget,
4511 str);
plougher8f8e1a12007-10-18 02:50:21 +00004512 }
4513 } else
4514 paths->name[i].preg = NULL;
4515
4516 if(target[0] == '\0')
4517 /* at leaf pathname component */
4518 paths->name[i].paths = NULL;
4519 else
4520 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004521 paths->name[i].paths = add_path(NULL, target,
4522 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004523 } else {
4524 /* existing matching entry */
Phillip Lougher8e44e052012-11-26 02:58:35 +00004525 free(targname);
4526
plougher8f8e1a12007-10-18 02:50:21 +00004527 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004528 /* No sub-directory which means this is the leaf
4529 * component of a pre-existing exclude which subsumes
4530 * the exclude currently being added, in which case stop
4531 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004532 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004533 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004534 * from more specific excludes, delete as they're
4535 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004536 free_path(paths->name[i].paths);
4537 paths->name[i].paths = NULL;
4538 } else
4539 /* recurse adding child components */
4540 add_path(paths->name[i].paths, target, alltarget);
4541 }
4542
4543 return paths;
4544}
plougher2ea89142008-03-11 01:34:19 +00004545
4546
plougher05e50ef2007-10-23 12:34:20 +00004547void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004548{
plougher05e50ef2007-10-23 12:34:20 +00004549
plougherb3604122009-03-30 02:07:20 +00004550 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4551 strncmp(target, "../", 3) == 0)
4552 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4553 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004554 else if(strncmp(target, "... ", 4) == 0)
4555 stickypath = add_path(stickypath, target + 4, target + 4);
4556 else
4557 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004558}
4559
4560
4561void display_path(int depth, struct pathname *paths)
4562{
4563 int i, n;
4564
4565 if(paths == NULL)
4566 return;
4567
4568 for(i = 0; i < paths->names; i++) {
4569 for(n = 0; n < depth; n++)
4570 printf("\t");
4571 printf("%d: %s\n", depth, paths->name[i].name);
4572 display_path(depth + 1, paths->name[i].paths);
4573 }
4574}
4575
4576
4577void display_path2(struct pathname *paths, char *string)
4578{
4579 int i;
Phillip Lougher91459c12012-11-30 05:24:44 +00004580 char *path;
plougher8f8e1a12007-10-18 02:50:21 +00004581
4582 if(paths == NULL) {
4583 printf("%s\n", string);
4584 return;
4585 }
4586
4587 for(i = 0; i < paths->names; i++) {
Phillip Lougher91459c12012-11-30 05:24:44 +00004588 int res = asprintf(&path, "%s/%s", string, paths->name[i].name);
4589 if(res == -1)
4590 BAD_ERROR("asprintf failed in display_path2\n");
plougher8f8e1a12007-10-18 02:50:21 +00004591 display_path2(paths->name[i].paths, path);
Phillip Lougher91459c12012-11-30 05:24:44 +00004592 free(path);
plougher8f8e1a12007-10-18 02:50:21 +00004593 }
4594}
4595
4596
plougherf9039c92007-10-22 03:54:16 +00004597struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004598{
ploughera2968ef2009-03-03 10:46:00 +00004599 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004600 if(new == NULL)
4601 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004602 new->count = 0;
4603 return new;
4604}
4605
4606
4607struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4608{
plougher6f2a8262010-07-27 00:37:19 +00004609 if(paths->count % PATHS_ALLOC_SIZE == 0) {
plougherb3604122009-03-30 02:07:20 +00004610 paths = realloc(paths, sizeof(struct pathnames *) +
4611 (paths->count + PATHS_ALLOC_SIZE) *
4612 sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004613 if(paths == NULL)
4614 BAD_ERROR("Out of memory in add_subdir\n");
4615 }
plougherf9039c92007-10-22 03:54:16 +00004616
4617 paths->path[paths->count++] = path;
4618 return paths;
4619}
4620
4621
4622void free_subdir(struct pathnames *paths)
4623{
4624 free(paths);
4625}
4626
4627
4628int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4629{
4630 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004631
plougherf9039c92007-10-22 03:54:16 +00004632 if(paths == NULL) {
4633 *new = NULL;
4634 return FALSE;
4635 }
plougher8f8e1a12007-10-18 02:50:21 +00004636
plougherf9039c92007-10-22 03:54:16 +00004637
4638 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004639 if(stickypath)
4640 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004641
4642 for(n = 0; n < paths->count; n++) {
4643 struct pathname *path = paths->path[n];
4644
4645 for(i = 0; i < path->names; i++) {
4646 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004647 regexec(path->name[i].preg, name, (size_t) 0,
4648 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004649 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004650 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4651 0;
plougherf9039c92007-10-22 03:54:16 +00004652
4653 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004654 /* match on a leaf component, any subdirectories
4655 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004656 res = TRUE;
4657 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004658 }
4659
plougherf9039c92007-10-22 03:54:16 +00004660 if(match)
plougherb3604122009-03-30 02:07:20 +00004661 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004662 * subdirectories to the new set of
4663 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004664 *new = add_subdir(*new, path->name[i].paths);
4665 }
4666 }
4667
4668 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004669 /* no matching names found, return empty new search set
4670 */
plougherf9039c92007-10-22 03:54:16 +00004671 res = FALSE;
4672 goto empty_set;
4673 }
4674
4675 /* one or more matches with sub-directories found (no leaf matches).
4676 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004677 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004678
4679empty_set:
4680 free_subdir(*new);
4681 *new = NULL;
4682 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004683}
4684
4685
Phillip Lougher386128f2012-12-16 05:23:45 +00004686void process_exclude_file(char *argv)
4687{
4688 FILE *fd;
Phillip Lougherb22336d2012-12-20 18:44:22 +00004689 char buffer[16385]; /* overflow safe */
4690 char *filename;
Phillip Lougher386128f2012-12-16 05:23:45 +00004691
Phillip Lougherb22336d2012-12-20 18:44:22 +00004692 fd = fopen(argv, "r");
4693 if(fd == NULL)
4694 BAD_ERROR("Failed to open exclude file \"%s\" because %s\n",
4695 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004696
Phillip Lougherb22336d2012-12-20 18:44:22 +00004697 while(fgets(filename = buffer, 16384, fd) != NULL) {
4698 int len = strlen(filename);
4699
4700 if(len == 16384 && filename[len] != '\n')
4701 /* line too large */
4702 BAD_ERROR("Line too long when reading "
4703 "exclude file \"%s\", larger than 16384 "
4704 "bytes\n", argv);
4705
4706 /*
4707 * Remove '\n' terminator if it exists (the last line
4708 * in the file may not be '\n' terminated)
4709 */
4710 if(len && filename[len - 1] == '\n')
4711 filename[len - 1] = '\0';
4712
4713 /* Skip any leading whitespace */
4714 while(isspace(*filename))
4715 filename ++;
4716
4717 /* if comment line, skip */
4718 if(*filename == '#')
4719 continue;
4720
4721 /*
4722 * check for initial backslash, to accommodate
4723 * filenames with leading space or leading # character
4724 */
4725 if(*filename == '\\')
4726 filename ++;
4727
4728 /* if line is now empty after skipping characters, skip it */
4729 if(*filename == '\0')
4730 continue;
4731
Phillip Lougher386128f2012-12-16 05:23:45 +00004732 if(old_exclude)
4733 old_add_exclude(filename);
4734 else
4735 add_exclude(filename);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004736 }
4737
4738 if(ferror(fd))
4739 BAD_ERROR("Reading exclude file \"%s\" failed because %s\n",
4740 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004741
4742 fclose(fd);
4743}
4744
4745
plougher99ac0cc2007-10-29 03:17:10 +00004746#define RECOVER_ID "Squashfs recovery file v1.0\n"
4747#define RECOVER_ID_SIZE 28
4748
plougher64e83fd2010-12-31 21:21:26 +00004749void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004750{
plougher1d065e92010-06-18 03:58:27 +00004751 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004752 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004753 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004754 char header[] = RECOVER_ID;
4755
4756 if(recover == FALSE) {
4757 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004758 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004759 return;
4760 }
4761
plougher1b879bc2010-12-18 02:49:42 +00004762 metadata = malloc(bytes);
4763 if(metadata == NULL)
plougher50b31762009-03-31 04:14:46 +00004764 BAD_ERROR("Failed to alloc metadata buffer in "
4765 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004766
plougher1d065e92010-06-18 03:58:27 +00004767 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4768 if(res == 0)
4769 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004770
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004771 res = asprintf(&recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004772 getbase(destination_file), pid);
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004773 if(res == -1)
4774 BAD_ERROR("Out of memory allocating recovery_file\n");
4775
plougherb3604122009-03-30 02:07:20 +00004776 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4777 if(recoverfd == -1)
4778 BAD_ERROR("Failed to create recovery file, because %s. "
4779 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004780
plougher628e7682009-03-29 22:12:24 +00004781 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004782 BAD_ERROR("Failed to write recovery file, because %s\n",
4783 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004784
plougher64e83fd2010-12-31 21:21:26 +00004785 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004786 BAD_ERROR("Failed to write recovery file, because %s\n",
4787 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004788
plougher628e7682009-03-29 22:12:24 +00004789 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004790 BAD_ERROR("Failed to write recovery file, because %s\n",
4791 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004792
4793 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004794 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004795
4796 printf("Recovery file \"%s\" written\n", recovery_file);
4797 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004798 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4799 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004800 printf("to restore filesystem\n\n");
4801}
4802
4803
4804void read_recovery_data(char *recovery_file, char *destination_file)
4805{
4806 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004807 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004808 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004809 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004810 struct stat buf;
4811 char header[] = RECOVER_ID;
4812 char header2[RECOVER_ID_SIZE];
4813
plougher9e9d9dc2010-12-18 02:53:57 +00004814 recoverfd = open(recovery_file, O_RDONLY);
4815 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004816 BAD_ERROR("Failed to open recovery file because %s\n",
4817 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004818
4819 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004820 BAD_ERROR("Failed to stat destination file, because %s\n",
4821 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004822
plougher9e9d9dc2010-12-18 02:53:57 +00004823 fd = open(destination_file, O_RDWR);
4824 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004825 BAD_ERROR("Failed to open destination file because %s\n",
4826 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004827
plougher8a8c4102009-03-29 22:28:49 +00004828 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4829 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004830 BAD_ERROR("Failed to read recovery file, because %s\n",
4831 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004832 if(res < RECOVER_ID_SIZE)
4833 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004834 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4835 BAD_ERROR("Not a recovery file\n");
4836
plougher64e83fd2010-12-31 21:21:26 +00004837 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004838 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004839 BAD_ERROR("Failed to read recovery file, because %s\n",
4840 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004841 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004842 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004843
plougher64e83fd2010-12-31 21:21:26 +00004844 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004845 if(res == 0)
4846 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004847
plougherb3604122009-03-30 02:07:20 +00004848 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004849 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004850 BAD_ERROR("Recovery file and destination file do not seem to "
4851 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004852
4853 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4854
plougher9e9d9dc2010-12-18 02:53:57 +00004855 metadata = malloc(bytes);
4856 if(metadata == NULL)
plougherb3604122009-03-30 02:07:20 +00004857 BAD_ERROR("Failed to alloc metadata buffer in "
4858 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004859
plougher8a8c4102009-03-29 22:28:49 +00004860 res = read_bytes(recoverfd, metadata, bytes);
4861 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004862 BAD_ERROR("Failed to read recovery file, because %s\n",
4863 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004864 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004865 BAD_ERROR("Recovery file appears to be truncated\n");
4866
plougher64e83fd2010-12-31 21:21:26 +00004867 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004868
plougher0dd6f122009-03-29 21:43:57 +00004869 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004870
4871 close(recoverfd);
4872 close(fd);
4873
plougherb3604122009-03-30 02:07:20 +00004874 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4875 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004876
4877 exit(0);
4878}
4879
4880
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004881int multiply_overflow(int a, int multiplier)
4882{
4883 return (INT_MAX / multiplier) < a;
4884}
4885
4886
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004887int parse_number(char *start, int *res, int size)
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004888{
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004889 char *end;
4890 long number = strtol(start, &end, 10);
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004891
Phillip Lougherf4f48382012-11-29 03:52:44 +00004892 /*
4893 * check for strtol underflow or overflow in conversion.
4894 * Note: strtol can validly return LONG_MIN and LONG_MAX
4895 * if the user entered these values, but, additional code
4896 * to distinguish this scenario is unnecessary, because for
4897 * our purposes LONG_MIN and LONG_MAX are too large anyway
4898 */
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004899 if(number == LONG_MIN || number == LONG_MAX)
4900 return 0;
4901
4902 /* reject negative numbers as invalid */
4903 if(number < 0)
4904 return 0;
4905
4906 /* check if long result will overflow signed int */
4907 if(number > INT_MAX)
4908 return 0;
4909
4910 if(size) {
Phillip Loughered345692012-11-28 03:56:16 +00004911 /*
4912 * Check for multiplier and trailing junk.
4913 * But first check that a number exists before the
4914 * multiplier
4915 */
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004916 if(end == start)
Phillip Loughered345692012-11-28 03:56:16 +00004917 return 0;
4918
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004919 switch(end[0]) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004920 case 'm':
4921 case 'M':
4922 if(multiply_overflow((int) number, 1048576))
4923 return 0;
4924 number *= 1048576;
Phillip Loughera9e65632012-11-28 04:17:27 +00004925
Phillip Lougherf968be82012-12-04 05:12:32 +00004926 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004927 /* trailing junk after number */
4928 return 0;
4929
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004930 break;
4931 case 'k':
4932 case 'K':
4933 if(multiply_overflow((int) number, 1024))
4934 return 0;
4935 number *= 1024;
Phillip Loughera9e65632012-11-28 04:17:27 +00004936
Phillip Lougherf968be82012-12-04 05:12:32 +00004937 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004938 /* trailing junk after number */
4939 return 0;
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004940 case '\0':
4941 break;
4942 default:
4943 /* trailing junk after number */
4944 return 0;
4945 }
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004946 } else if(end[0] != '\0')
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004947 /* trailing junk after number */
4948 return 0;
4949
4950 *res = number;
4951 return 1;
4952}
4953
4954
4955int parse_num(char *arg, int *res)
4956{
4957 return parse_number(arg, res, 0);
4958}
4959
4960
plougher1f413c82005-11-18 00:02:14 +00004961#define VERSION() \
Phillip Lougherb22336d2012-12-20 18:44:22 +00004962 printf("mksquashfs version 4.2-git (2012/12/20)\n");\
Phillip Lougherb38c1722012-02-09 23:26:19 +00004963 printf("copyright (C) 2012 Phillip Lougher "\
Phillip Lougher83d42a32012-10-31 23:42:22 +00004964 "<phillip@squashfs.org.uk>\n\n"); \
plougher16111452010-07-22 05:12:18 +00004965 printf("This program is free software; you can redistribute it and/or"\
4966 "\n");\
4967 printf("modify it under the terms of the GNU General Public License"\
4968 "\n");\
4969 printf("as published by the Free Software Foundation; either version "\
4970 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004971 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004972 printf("This program is distributed in the hope that it will be "\
4973 "useful,\n");\
4974 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4975 "of\n");\
4976 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4977 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004978 printf("GNU General Public License for more details.\n");
4979int main(int argc, char *argv[])
4980{
plougher324978d2006-02-27 04:53:29 +00004981 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00004982 int res, i;
plougher64e83fd2010-12-31 21:21:26 +00004983 struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +00004984 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004985 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004986 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004987 int readb_mbytes = READER_BUFFER_DEFAULT,
4988 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4989 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01004990 int force_progress = FALSE;
Phillip Lougherdc587a02012-11-14 05:30:27 +00004991 struct pseudo *pseudo = NULL;
plougher1f413c82005-11-18 00:02:14 +00004992
plougher1f413c82005-11-18 00:02:14 +00004993 block_log = slog(block_size);
4994 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
4995 VERSION();
4996 exit(0);
4997 }
4998 for(i = 1; i < argc && argv[i][0] != '-'; i++);
4999 if(i < 3)
5000 goto printOptions;
5001 source_path = argv + 1;
5002 source = i - 2;
plougher4da4bd42010-11-21 05:01:54 +00005003 /*
5004 * lookup default compressor. Note the Makefile ensures the default
5005 * compressor has been built, and so we don't need to to check
5006 * for failure here
5007 */
plougher5c2adaf2010-11-22 01:00:15 +00005008 comp = lookup_compressor(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005009 for(; i < argc; i++) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005010 if(strcmp(argv[i], "-action") == 0 ||
5011 strcmp(argv[i], "-a") ==0) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005012 if(++i == argc) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005013 ERROR("%s: %s missing action\n",
5014 argv[0], argv[i - 1]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005015 exit(1);
5016 }
5017 res = parse_action(argv[i]);
5018 if(res == 0)
5019 exit(1);
5020
5021 } else if(strcmp(argv[i], "-comp") == 0) {
plougherc5d59872010-11-22 01:36:01 +00005022 if(compressor_opts_parsed) {
5023 ERROR("%s: -comp must appear before -X options"
5024 "\n", argv[0]);
5025 exit(1);
5026 }
plougherae9dcd82009-08-01 02:59:38 +00005027 if(++i == argc) {
5028 ERROR("%s: -comp missing compression type\n",
5029 argv[0]);
5030 exit(1);
5031 }
plougher5c2adaf2010-11-22 01:00:15 +00005032 comp = lookup_compressor(argv[i]);
plougher4da4bd42010-11-21 05:01:54 +00005033 if(!comp->supported) {
plougherc5d59872010-11-22 01:36:01 +00005034 ERROR("%s: Compressor \"%s\" is not supported!"
5035 "\n", argv[0], argv[i]);
5036 ERROR("%s: Compressors available:\n", argv[0]);
plougher4da4bd42010-11-21 05:01:54 +00005037 display_compressors("", COMP_DEFAULT);
5038 exit(1);
5039 }
plougherb5576ea2010-11-22 01:06:53 +00005040
5041 } else if(strncmp(argv[i], "-X", 2) == 0) {
5042 int args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00005043 if(args < 0) {
5044 if(args == -1) {
5045 ERROR("%s: Unrecognised compressor"
5046 " option %s\n", argv[0],
5047 argv[i]);
5048 ERROR("%s: Did you forget to specify"
5049 " -comp, or specify it after"
5050 " the compressor specific"
5051 " option?\n", argv[0]);
5052 }
plougherb5576ea2010-11-22 01:06:53 +00005053 exit(1);
5054 }
5055 i += args;
plougherc5d59872010-11-22 01:36:01 +00005056 compressor_opts_parsed = 1;
plougherb5576ea2010-11-22 01:06:53 +00005057
plougherae9dcd82009-08-01 02:59:38 +00005058 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00005059 if(++i == argc) {
5060 ERROR("%s: -pf missing filename\n", argv[0]);
5061 exit(1);
5062 }
plougher620b7172009-09-10 04:17:48 +00005063 if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005064 exit(1);
plougher43244f22009-04-05 02:04:51 +00005065 } else if(strcmp(argv[i], "-p") == 0) {
5066 if(++i == argc) {
5067 ERROR("%s: -p missing pseudo file definition\n",
5068 argv[0]);
5069 exit(1);
5070 }
plougher620b7172009-09-10 04:17:48 +00005071 if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005072 exit(1);
plougher43244f22009-04-05 02:04:51 +00005073 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00005074 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00005075 ERROR("%s: -recover missing recovery file\n",
5076 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00005077 exit(1);
5078 }
5079 read_recovery_data(argv[i], argv[source + 1]);
5080 } else if(strcmp(argv[i], "-no-recovery") == 0)
5081 recover = FALSE;
5082 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00005083 old_exclude = FALSE;
5084 use_regex = FALSE;
5085 } else if(strcmp(argv[i], "-regex") == 0) {
5086 old_exclude = FALSE;
5087 use_regex = TRUE;
5088 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00005089 sparse_files = FALSE;
5090 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00005091 progress = FALSE;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005092 else if(strcmp(argv[i], "-progress") == 0)
5093 force_progress = TRUE;
plougher02bc3bc2007-02-25 12:12:01 +00005094 else if(strcmp(argv[i], "-no-exports") == 0)
5095 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00005096 else if(strcmp(argv[i], "-processors") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005097 if((++i == argc) || !parse_num(argv[i], &processors)) {
plougher360514a2009-03-30 03:01:38 +00005098 ERROR("%s: -processors missing or invalid "
5099 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005100 exit(1);
5101 }
5102 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00005103 ERROR("%s: -processors should be 1 or larger\n",
5104 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005105 exit(1);
5106 }
plougher0e453652006-11-06 01:49:35 +00005107 } else if(strcmp(argv[i], "-read-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005108 if((++i == argc) ||
5109 !parse_num(argv[i], &readb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005110 ERROR("%s: -read-queue missing or invalid "
5111 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005112 exit(1);
5113 }
5114 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00005115 ERROR("%s: -read-queue should be 1 megabyte or "
5116 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005117 exit(1);
5118 }
plougher0e453652006-11-06 01:49:35 +00005119 } else if(strcmp(argv[i], "-write-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005120 if((++i == argc) ||
5121 !parse_num(argv[i], &writeb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005122 ERROR("%s: -write-queue missing or invalid "
5123 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005124 exit(1);
5125 }
5126 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005127 ERROR("%s: -write-queue should be 1 megabyte "
5128 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005129 exit(1);
5130 }
plougher217bad82008-04-05 11:36:41 +00005131 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00005132 if((++i == argc) ||
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005133 !parse_num(argv[i],
5134 &fragmentb_mbytes)) {
plougher360514a2009-03-30 03:01:38 +00005135 ERROR("%s: -fragment-queue missing or invalid "
5136 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005137 exit(1);
5138 }
5139 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005140 ERROR("%s: -fragment-queue should be 1 "
5141 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005142 exit(1);
5143 }
plougher5507dd92006-11-06 00:43:10 +00005144 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00005145 if(++i == argc) {
5146 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005147 exit(1);
5148 }
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005149 if(!parse_number(argv[i], &block_size, 1)) {
plougher4c99cb72007-06-14 21:46:31 +00005150 ERROR("%s: -b invalid block size\n", argv[0]);
5151 exit(1);
5152 }
plougher1f413c82005-11-18 00:02:14 +00005153 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00005154 ERROR("%s: -b block size not power of two or "
5155 "not between 4096 and 1Mbyte\n",
5156 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005157 exit(1);
5158 }
5159 } else if(strcmp(argv[i], "-ef") == 0) {
5160 if(++i == argc) {
5161 ERROR("%s: -ef missing filename\n", argv[0]);
5162 exit(1);
5163 }
plougher9b5bf8c2006-03-20 18:43:33 +00005164 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00005165 duplicate_checking = FALSE;
5166
5167 else if(strcmp(argv[i], "-no-fragments") == 0)
5168 no_fragments = TRUE;
5169
5170 else if(strcmp(argv[i], "-always-use-fragments") == 0)
5171 always_use_fragments = TRUE;
5172
5173 else if(strcmp(argv[i], "-sort") == 0) {
5174 if(++i == argc) {
5175 ERROR("%s: -sort missing filename\n", argv[0]);
5176 exit(1);
5177 }
5178 } else if(strcmp(argv[i], "-all-root") == 0 ||
5179 strcmp(argv[i], "-root-owned") == 0)
5180 global_uid = global_gid = 0;
5181
5182 else if(strcmp(argv[i], "-force-uid") == 0) {
5183 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005184 ERROR("%s: -force-uid missing uid or user\n",
5185 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005186 exit(1);
5187 }
5188 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005189 if(global_uid < 0 || global_uid >
5190 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005191 ERROR("%s: -force-uid uid out of range"
5192 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005193 exit(1);
5194 }
5195 } else {
5196 struct passwd *uid = getpwnam(argv[i]);
5197 if(uid)
5198 global_uid = uid->pw_uid;
5199 else {
plougher360514a2009-03-30 03:01:38 +00005200 ERROR("%s: -force-uid invalid uid or "
5201 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005202 exit(1);
5203 }
5204 }
5205 } else if(strcmp(argv[i], "-force-gid") == 0) {
5206 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00005207 ERROR("%s: -force-gid missing gid or group\n",
5208 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005209 exit(1);
5210 }
5211 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005212 if(global_gid < 0 || global_gid >
5213 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005214 ERROR("%s: -force-gid gid out of range"
5215 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005216 exit(1);
5217 }
5218 } else {
5219 struct group *gid = getgrnam(argv[i]);
5220 if(gid)
5221 global_gid = gid->gr_gid;
5222 else {
plougher360514a2009-03-30 03:01:38 +00005223 ERROR("%s: -force-gid invalid gid or "
5224 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005225 exit(1);
5226 }
5227 }
5228 } else if(strcmp(argv[i], "-noI") == 0 ||
5229 strcmp(argv[i], "-noInodeCompression") == 0)
5230 noI = TRUE;
5231
5232 else if(strcmp(argv[i], "-noD") == 0 ||
5233 strcmp(argv[i], "-noDataCompression") == 0)
5234 noD = TRUE;
5235
5236 else if(strcmp(argv[i], "-noF") == 0 ||
5237 strcmp(argv[i], "-noFragmentCompression") == 0)
5238 noF = TRUE;
5239
plougherb99d7832010-05-19 01:57:34 +00005240 else if(strcmp(argv[i], "-noX") == 0 ||
5241 strcmp(argv[i], "-noXattrCompression") == 0)
5242 noX = TRUE;
5243
plougherce564c62010-05-19 03:01:49 +00005244 else if(strcmp(argv[i], "-no-xattrs") == 0)
5245 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00005246
plougher30281c82010-08-25 05:06:11 +00005247 else if(strcmp(argv[i], "-xattrs") == 0)
5248 no_xattrs = FALSE;
5249
plougher1f413c82005-11-18 00:02:14 +00005250 else if(strcmp(argv[i], "-nopad") == 0)
5251 nopad = TRUE;
5252
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005253 else if(strcmp(argv[i], "-info") == 0)
plougher91fbb302008-05-06 02:29:36 +00005254 silent = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005255
5256 else if(strcmp(argv[i], "-e") == 0)
5257 break;
5258
5259 else if(strcmp(argv[i], "-noappend") == 0)
5260 delete = TRUE;
5261
5262 else if(strcmp(argv[i], "-keep-as-directory") == 0)
5263 keep_as_directory = TRUE;
5264
5265 else if(strcmp(argv[i], "-root-becomes") == 0) {
5266 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005267 ERROR("%s: -root-becomes: missing name\n",
5268 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005269 exit(1);
5270 }
5271 root_name = argv[i];
5272 } else if(strcmp(argv[i], "-version") == 0) {
5273 VERSION();
5274 } else {
5275 ERROR("%s: invalid option\n\n", argv[0]);
5276printOptions:
plougher360514a2009-03-30 03:01:38 +00005277 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
5278 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00005279 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00005280 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00005281 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00005282 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00005283 ERROR("-b <block_size>\t\tset data block to "
5284 "<block_size>. Default %d bytes\n",
5285 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00005286 ERROR("-no-exports\t\tdon't make the filesystem "
5287 "exportable via NFS\n");
5288 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00005289 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00005290 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00005291 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00005292 "\n");
plougher1f413c82005-11-18 00:02:14 +00005293 ERROR("-noI\t\t\tdo not compress inode table\n");
5294 ERROR("-noD\t\t\tdo not compress data blocks\n");
5295 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00005296 ERROR("-noX\t\t\tdo not compress extended "
5297 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00005298 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00005299 ERROR("-always-use-fragments\tuse fragment blocks for "
5300 "files larger than block size\n");
5301 ERROR("-no-duplicates\t\tdo not perform duplicate "
5302 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00005303 ERROR("-all-root\t\tmake all files owned by root\n");
5304 ERROR("-force-uid uid\t\tset all file uids to uid\n");
5305 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00005306 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
5307 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00005308 ERROR("-keep-as-directory\tif one source directory is "
5309 "specified, create a root\n");
5310 ERROR("\t\t\tdirectory containing that directory, "
5311 "rather than the\n");
5312 ERROR("\t\t\tcontents of the directory\n");
5313 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00005314 ERROR("-p <pseudo-definition>\tAdd pseudo file "
5315 "definition\n");
5316 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
5317 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00005318 ERROR("-sort <sort_file>\tsort files according to "
5319 "priorities in <sort_file>. One\n");
5320 ERROR("\t\t\tfile or dir with priority per line. "
5321 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00005322 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00005323 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
5324 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00005325 ERROR("-wildcards\t\tAllow extended shell wildcards "
5326 "(globbing) to be used in\n\t\t\texclude "
5327 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00005328 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
5329 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00005330 ERROR("\nFilesystem append options:\n");
5331 ERROR("-noappend\t\tdo not append to existing "
5332 "filesystem\n");
5333 ERROR("-root-becomes <name>\twhen appending source "
5334 "files/directories, make the\n");
5335 ERROR("\t\t\toriginal root become a subdirectory in "
5336 "the new root\n");
5337 ERROR("\t\t\tcalled <name>, rather than adding the new "
5338 "source items\n");
5339 ERROR("\t\t\tto the original root\n");
5340 ERROR("\nMksquashfs runtime options:\n");
5341 ERROR("-version\t\tprint version, licence and "
5342 "copyright message\n");
5343 ERROR("-recover <name>\t\trecover filesystem data "
5344 "using recovery file <name>\n");
5345 ERROR("-no-recovery\t\tdon't generate a recovery "
5346 "file\n");
5347 ERROR("-info\t\t\tprint files written to filesystem\n");
5348 ERROR("-no-progress\t\tdon't display the progress "
5349 "bar\n");
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005350 ERROR("-progress\t\tdisplay progress bar when using "
5351 "the -info option\n");
plougher37632562009-08-07 19:09:01 +00005352 ERROR("-processors <number>\tUse <number> processors."
5353 " By default will use number of\n");
5354 ERROR("\t\t\tprocessors available\n");
5355 ERROR("-read-queue <size>\tSet input queue to <size> "
5356 "Mbytes. Default %d Mbytes\n",
5357 READER_BUFFER_DEFAULT);
5358 ERROR("-write-queue <size>\tSet output queue to <size> "
5359 "Mbytes. Default %d Mbytes\n",
5360 WRITER_BUFFER_DEFAULT);
plougher8bc376b2010-11-12 04:55:20 +00005361 ERROR("-fragment-queue <size>\tSet fragment queue to "
plougher37632562009-08-07 19:09:01 +00005362 "<size> Mbytes. Default %d Mbytes\n",
5363 FRAGMENT_BUFFER_DEFAULT);
5364 ERROR("\nMiscellaneous options:\n");
5365 ERROR("-root-owned\t\talternative name for -all-root"
5366 "\n");
5367 ERROR("-noInodeCompression\talternative name for -noI"
5368 "\n");
5369 ERROR("-noDataCompression\talternative name for -noD"
5370 "\n");
5371 ERROR("-noFragmentCompression\talternative name for "
5372 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005373 ERROR("-noXattrCompression\talternative name for "
5374 "-noX\n");
plougher4fb66822010-12-08 02:49:28 +00005375 ERROR("\nCompressors available and compressor specific "
5376 "options:\n");
5377 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005378 exit(1);
5379 }
5380 }
5381
plougherb747f4f2010-12-25 04:05:47 +00005382 /*
5383 * Some compressors may need the options to be checked for validity
5384 * once all the options have been processed
5385 */
5386 res = compressor_options_post(comp, block_size);
5387 if(res)
5388 EXIT_MKSQUASHFS();
5389
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005390 /*
5391 * If the -info option has been selected then disable the
5392 * progress bar unless it has been explicitly enabled with
5393 * the -progress option
5394 */
5395 if(!silent)
5396 progress = force_progress;
5397
5398#ifdef SQUASHFS_TRACE
5399 progress = FALSE;
5400#endif
5401
plougher91fbb302008-05-06 02:29:36 +00005402 for(i = 0; i < source; i++)
5403 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005404 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005405 "because %s\n", source_path[i],
5406 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005407 EXIT_MKSQUASHFS();
5408 }
plougher324978d2006-02-27 04:53:29 +00005409
5410 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005411 if(stat(argv[source + 1], &buf) == -1) {
5412 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005413 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005414 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005415 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005416 perror("Could not create destination file");
5417 exit(1);
5418 }
5419 delete = TRUE;
5420 } else {
5421 perror("Could not stat destination file");
5422 exit(1);
5423 }
5424
5425 } else {
5426 if(S_ISBLK(buf.st_mode)) {
5427 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005428 perror("Could not open block device as "
5429 "destination");
plougher1f413c82005-11-18 00:02:14 +00005430 exit(1);
5431 }
5432 block_device = 1;
5433
5434 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005435 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5436 O_RDWR);
5437 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005438 perror("Could not open regular file for "
5439 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005440 exit(1);
5441 }
plougher44d54ef2010-02-08 22:13:49 +00005442 }
plougher1f413c82005-11-18 00:02:14 +00005443 else {
5444 ERROR("Destination not block device or regular file\n");
5445 exit(1);
5446 }
5447
plougher324978d2006-02-27 04:53:29 +00005448 }
plougher1f413c82005-11-18 00:02:14 +00005449
plougher4c99cb72007-06-14 21:46:31 +00005450 signal(SIGTERM, sighandler2);
5451 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00005452
plougher16111452010-07-22 05:12:18 +00005453 /*
5454 * process the exclude files - must be done afer destination file has
5455 * been possibly created
5456 */
plougher1f413c82005-11-18 00:02:14 +00005457 for(i = source + 2; i < argc; i++)
Phillip Lougher386128f2012-12-16 05:23:45 +00005458 if(strcmp(argv[i], "-ef") == 0)
5459 /*
5460 * Note presence of filename arg has already
5461 * been checked
5462 */
5463 process_exclude_file(argv[++i]);
5464 else if(strcmp(argv[i], "-e") == 0)
plougher1f413c82005-11-18 00:02:14 +00005465 break;
plougher8b9a7f62009-08-01 22:52:45 +00005466 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005467 strcmp(argv[i], "-sort") == 0 ||
5468 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005469 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005470 i++;
5471
5472 if(i != argc) {
5473 if(++i == argc) {
5474 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005475 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005476 }
plougher8f8e1a12007-10-18 02:50:21 +00005477 while(i < argc)
5478 if(old_exclude)
5479 old_add_exclude(argv[i++]);
5480 else
plougher05e50ef2007-10-23 12:34:20 +00005481 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005482 }
5483
5484 /* process the sort files - must be done afer the exclude files */
5485 for(i = source + 2; i < argc; i++)
5486 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005487 int res = read_sort_file(argv[++i], source,
5488 source_path);
5489 if(res == FALSE)
5490 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005491 sorted ++;
5492 } else if(strcmp(argv[i], "-e") == 0)
5493 break;
plougher8b9a7f62009-08-01 22:52:45 +00005494 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005495 strcmp(argv[i], "-ef") == 0 ||
5496 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005497 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005498 i++;
5499
plougher4c99cb72007-06-14 21:46:31 +00005500 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005501 comp = read_super(fd, &sBlk, argv[source + 1]);
5502 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005503 ERROR("Failed to read existing filesystem - will not "
5504 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005505 ERROR("To force Mksquashfs to write to this block "
5506 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005507 EXIT_MKSQUASHFS();
5508 }
plougher1f413c82005-11-18 00:02:14 +00005509
plougher1f413c82005-11-18 00:02:14 +00005510 block_log = slog(block_size = sBlk.block_size);
5511 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5512 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5513 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005514 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005515 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5516 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5517 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005518 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005519 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005520 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005521 }
5522
plougher5741d792010-09-04 03:20:50 +00005523 initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
plougher4c99cb72007-06-14 21:46:31 +00005524
plougher13fdddf2010-11-24 01:23:41 +00005525 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5526 if(res)
5527 BAD_ERROR("compressor_init failed\n");
5528
plougher4c99cb72007-06-14 21:46:31 +00005529 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005530 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005531 void *comp_data = compressor_dump_options(comp, block_size,
5532 &size);
plougher3d7e5182010-12-25 01:49:42 +00005533
plougherdf6d8f02009-03-20 03:10:00 +00005534 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005535 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005536
plougher871c72a2010-12-25 04:17:27 +00005537 /*
5538 * store any compressor specific options after the superblock,
5539 * and set the COMP_OPT flag to show that the filesystem has
5540 * compressor specfic options
5541 */
plougher3d7e5182010-12-25 01:49:42 +00005542 if(comp_data) {
5543 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5544
5545 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005546 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005547 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005548 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005549 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005550 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005551 + size;
5552 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005553 } else
plougher64e83fd2010-12-31 21:21:26 +00005554 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005555 } else {
plougher360514a2009-03-30 03:01:38 +00005556 unsigned int last_directory_block, inode_dir_offset,
5557 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005558 inode_dir_start_block, uncompressed_data,
5559 compressed_data, inode_dir_inode_number,
5560 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005561 unsigned int root_inode_start =
5562 SQUASHFS_INODE_BLK(sBlk.root_inode),
5563 root_inode_offset =
5564 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005565
plougher360514a2009-03-30 03:01:38 +00005566 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5567 &data_cache, &directory_table,
5568 &directory_data_cache, &last_directory_block,
5569 &inode_dir_offset, &inode_dir_file_size,
5570 &root_inode_size, &inode_dir_start_block,
5571 &file_count, &sym_count, &dev_count, &dir_count,
5572 &fifo_count, &sock_count, &total_bytes,
5573 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005574 &inode_dir_inode_number,
5575 &inode_dir_parent_inode, add_old_root_entry,
5576 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005577 ERROR("Failed to read existing filesystem - will not "
5578 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005579 ERROR("To force Mksquashfs to write to this block "
5580 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005581 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005582 }
plougher6f2a8262010-07-27 00:37:19 +00005583 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005584 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005585 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005586 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005587 if(fragment_table == NULL)
5588 BAD_ERROR("Out of memory in save filesystem state\n");
5589 }
plougher1f413c82005-11-18 00:02:14 +00005590
plougher50b31762009-03-31 04:14:46 +00005591 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005592 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005593 block_size);
plougher89c7a512010-12-15 08:35:51 +00005594 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005595 "-always-use-fragments,\n-exportable and -comp options "
5596 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005597 printf("\nIf appending is not wanted, please re-run with "
5598 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005599
plougher360514a2009-03-30 03:01:38 +00005600 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5601 ~(SQUASHFS_METADATA_SIZE - 1);
5602 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5603 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005604
5605 /* save original filesystem state for restoring ... */
5606 sfragments = fragments;
5607 sbytes = bytes;
5608 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005609 scache_bytes = root_inode_offset + root_inode_size;
5610 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005611 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005612 if(sdata_cache == NULL)
5613 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005614 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005615 if(sdirectory_data_cache == NULL)
5616 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005617 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005618 memcpy(sdirectory_data_cache, directory_data_cache +
5619 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005620 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005621 stotal_bytes = total_bytes;
5622 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005623 stotal_directory_bytes = total_directory_bytes +
5624 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005625 sfile_count = file_count;
5626 ssym_count = sym_count;
5627 sdev_count = dev_count;
5628 sdir_count = dir_count + 1;
5629 sfifo_count = fifo_count;
5630 ssock_count = sock_count;
5631 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005632 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005633 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005634 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005635 BAD_ERROR("Failed to save xattrs from existing "
5636 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005637 restore = TRUE;
5638 if(setjmp(env))
5639 goto restore_filesystem;
5640 signal(SIGTERM, sighandler);
5641 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005642 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005643
plougher360514a2009-03-30 03:01:38 +00005644 /*
5645 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005646 * original filesystem. The filesystem state differs depending
5647 * on whether we're appending to the original root directory, or
5648 * if the original root directory becomes a sub-directory
5649 * (root-becomes specified on command line, here root_name !=
5650 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005651 */
5652 inode_bytes = inode_size = root_inode_start;
5653 directory_size = last_directory_block;
5654 cache_size = root_inode_offset + root_inode_size;
5655 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5656 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005657 sdirectory_bytes = last_directory_block;
5658 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005659 root_inode_number = inode_dir_parent_inode;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005660 inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005661 directory_bytes = last_directory_block;
5662 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005663 memmove(directory_data_cache, directory_data_cache +
5664 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005665 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005666 add_old_root_entry(root_name, sBlk.root_inode,
5667 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005668 total_directory_bytes += compressed_data;
5669 dir_count ++;
5670 } else {
plougher360514a2009-03-30 03:01:38 +00005671 sdirectory_compressed_bytes = last_directory_block -
5672 inode_dir_start_block;
5673 sdirectory_compressed =
5674 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005675 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005676 BAD_ERROR("Out of memory in save filesystem "
5677 "state\n");
plougher360514a2009-03-30 03:01:38 +00005678 memcpy(sdirectory_compressed, directory_table +
5679 inode_dir_start_block,
5680 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005681 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005682 root_inode_number = inode_dir_inode_number;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005683 inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005684 directory_bytes = inode_dir_start_block;
5685 directory_cache_bytes = inode_dir_offset;
5686 cache_bytes = root_inode_offset;
5687 }
5688
plougher360514a2009-03-30 03:01:38 +00005689 inode_count = file_count + dir_count + sym_count + dev_count +
5690 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005691
5692 /*
5693 * The default use freelist before growing cache policy behaves
5694 * poorly with appending - with many deplicates the caches
5695 * do not grow due to the fact that large queues of outstanding
5696 * fragments/writer blocks do not occur, leading to small caches
5697 * and un-uncessary performance loss to frequent cache
5698 * replacement in the small caches. Therefore with appending
5699 * change the policy to grow the caches before reusing blocks
5700 * from the freelist
5701 */
5702 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005703 }
5704
plougher05e50ef2007-10-23 12:34:20 +00005705 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005706 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005707 if(path)
5708 paths = add_subdir(paths, path);
5709 if(stickypath)
5710 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005711 }
5712
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005713 dump_actions();
5714
plougher360514a2009-03-30 03:01:38 +00005715 if(delete && !keep_as_directory && source == 1 &&
5716 S_ISDIR(source_buf.st_mode))
Phillip Lougherdc587a02012-11-14 05:30:27 +00005717 dir_scan(&inode, source_path[0], scan1_readdir, pseudo);
plougher50b31762009-03-31 04:14:46 +00005718 else if(!keep_as_directory && source == 1 &&
5719 S_ISDIR(source_buf.st_mode))
Phillip Lougherdc587a02012-11-14 05:30:27 +00005720 dir_scan(&inode, source_path[0], scan1_single_readdir, pseudo);
plougher1f413c82005-11-18 00:02:14 +00005721 else
Phillip Lougherdc587a02012-11-14 05:30:27 +00005722 dir_scan(&inode, "", scan1_encomp_readdir, pseudo);
plougher1f413c82005-11-18 00:02:14 +00005723 sBlk.root_inode = inode;
5724 sBlk.inodes = inode_count;
5725 sBlk.s_magic = SQUASHFS_MAGIC;
5726 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005727 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005728 sBlk.block_size = block_size;
5729 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005730 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005731 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005732 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005733 sBlk.mkfs_time = time(NULL);
5734
5735restore_filesystem:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01005736 if(progress)
plougherc9b11db2008-05-06 23:59:15 +00005737 disable_progress_bar();
plougherc9b11db2008-05-06 23:59:15 +00005738
plougher1f413c82005-11-18 00:02:14 +00005739 sBlk.fragments = fragments;
plougher875bfef2010-08-12 23:48:41 +00005740 if(!restoring) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005741 struct file_buffer **fragment = NULL;
5742 while((fragment = get_frag_action(fragment)))
5743 write_fragment(*fragment);
plougher2ea89142008-03-11 01:34:19 +00005744 unlock_fragments();
5745 pthread_mutex_lock(&fragment_mutex);
5746 while(fragments_outstanding) {
5747 pthread_mutex_unlock(&fragment_mutex);
5748 sched_yield();
5749 pthread_mutex_lock(&fragment_mutex);
5750 }
plougher5507dd92006-11-06 00:43:10 +00005751 queue_put(to_writer, NULL);
5752 if(queue_get(from_writer) != 0)
5753 EXIT_MKSQUASHFS();
5754 }
5755
ploughere6e0e1b2010-05-12 17:17:06 +00005756 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005757 sBlk.inode_table_start = write_inodes();
5758 sBlk.directory_table_start = write_directories();
5759 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005760 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5761 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005762 sBlk.id_table_start = write_id_table();
5763 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005764
plougher0e453652006-11-06 01:49:35 +00005765 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005766 TRACE("sBlk->directory_table_start 0x%llx\n",
5767 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005768 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5769 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005770 TRACE("sBlk->lookup_table_start 0x%llx\n",
5771 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005772
plougher1f413c82005-11-18 00:02:14 +00005773 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005774
plougher8c4b7b92009-07-30 04:47:52 +00005775 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005776
plougher1f288f62009-02-21 03:05:52 +00005777 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher29e2ace2010-12-31 08:50:00 +00005778 write_destination(fd, SQUASHFS_START, sizeof(sBlk), &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005779
5780 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005781 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005782 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005783 }
5784
plougher99ac0cc2007-10-29 03:17:10 +00005785 close(fd);
5786
plougher11e7b1b2009-09-11 12:10:58 +00005787 delete_pseudo_files();
5788
Phillip Lougheraf4c9232012-11-15 03:46:28 +00005789 if(recovery_file)
plougher99ac0cc2007-10-29 03:17:10 +00005790 unlink(recovery_file);
5791
plougher10f7d572010-07-20 02:14:04 +00005792 total_bytes += total_inode_bytes + total_directory_bytes +
plougher64e83fd2010-12-31 21:21:26 +00005793 sizeof(struct squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005794
plougher62542fb2009-08-06 08:43:08 +00005795 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5796 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5797 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005798 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005799 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5800 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005801 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5802 "compressed");
plougher50b31762009-03-31 04:14:46 +00005803 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5804 "not ");
plougher360514a2009-03-30 03:01:38 +00005805 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5806 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005807 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5808 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5809 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5810 inode_bytes, inode_bytes / 1024.0);
5811 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005812 ((float) inode_bytes / total_inode_bytes) * 100.0,
5813 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005814 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5815 directory_bytes, directory_bytes / 1024.0);
5816 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005817 ((float) directory_bytes / total_directory_bytes) * 100.0,
5818 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005819 if(total_xattr_bytes) {
5820 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5821 xattr_bytes, xattr_bytes / 1024.0);
5822 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5823 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5824 total_xattr_bytes);
5825 }
plougher1f413c82005-11-18 00:02:14 +00005826 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005827 printf("Number of duplicate files found %d\n", file_count -
5828 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005829 else
5830 printf("No duplicate files removed\n");
5831 printf("Number of inodes %d\n", inode_count);
5832 printf("Number of files %d\n", file_count);
5833 if(!no_fragments)
5834 printf("Number of fragments %d\n", fragments);
5835 printf("Number of symbolic links %d\n", sym_count);
5836 printf("Number of device nodes %d\n", dev_count);
5837 printf("Number of fifo nodes %d\n", fifo_count);
5838 printf("Number of socket nodes %d\n", sock_count);
5839 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005840 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005841 printf("Number of uids %d\n", uid_count);
5842
plougher1b899fc2008-08-07 01:24:06 +00005843 for(i = 0; i < id_count; i++) {
5844 if(id_table[i]->flags & ISA_UID) {
5845 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005846 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5847 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005848 }
plougher1f413c82005-11-18 00:02:14 +00005849 }
5850
5851 printf("Number of gids %d\n", guid_count);
5852
plougher1b899fc2008-08-07 01:24:06 +00005853 for(i = 0; i < id_count; i++) {
5854 if(id_table[i]->flags & ISA_GID) {
5855 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005856 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5857 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005858 }
plougher1f413c82005-11-18 00:02:14 +00005859 }
plougher99ac0cc2007-10-29 03:17:10 +00005860
plougher1f413c82005-11-18 00:02:14 +00005861 return 0;
5862}