blob: b429d963178cb671c60352c6a1b892a40ae8c1b8 [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
Phillip Lougherfe2c7352012-12-23 06:55:41 +000028#define MAX_LINE 16384
plougher8cb05cd2005-12-11 23:32:35 +000029
plougher1f413c82005-11-18 00:02:14 +000030#include <pwd.h>
31#include <grp.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000035#include <stddef.h>
plougher1f413c82005-11-18 00:02:14 +000036#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <dirent.h>
41#include <string.h>
plougher1f413c82005-11-18 00:02:14 +000042#include <stdlib.h>
43#include <signal.h>
44#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000045#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000046#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000047#include <pthread.h>
plougher8f8e1a12007-10-18 02:50:21 +000048#include <regex.h>
49#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000050#include <sys/wait.h>
Phillip Lougher94c1fe02012-11-28 03:32:36 +000051#include <limits.h>
Phillip Lougherb22336d2012-12-20 18:44:22 +000052#include <ctype.h>
plougher1f413c82005-11-18 00:02:14 +000053
plougher68853292005-12-27 02:47:04 +000054#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000055#define __BYTE_ORDER BYTE_ORDER
56#define __BIG_ENDIAN BIG_ENDIAN
57#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000058#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000059#else
60#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000061#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000062#endif
63
plougher860c1f32010-08-11 01:37:17 +000064#include "squashfs_fs.h"
plougher860c1f32010-08-11 01:37:17 +000065#include "squashfs_swap.h"
66#include "mksquashfs.h"
67#include "sort.h"
68#include "pseudo.h"
69#include "compressor.h"
70#include "xattr.h"
Phillip Lougher4bcb7f82011-08-28 03:18:26 +010071#include "action.h"
Phillip Lougher2477d0d2012-10-24 21:49:28 +010072#include "error.h"
plougher860c1f32010-08-11 01:37:17 +000073
plougher324978d2006-02-27 04:53:29 +000074int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +000075int fd;
76
77/* filesystem flags for building */
plougher3d7e5182010-12-25 01:49:42 +000078int comp_opts = FALSE;
plougher30281c82010-08-25 05:06:11 +000079int no_xattrs = XATTR_DEF, noX = 0;
plougher1f413c82005-11-18 00:02:14 +000080int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
plougher6d89ac22010-05-19 02:59:23 +000081int noI = 0, noD = 0;
plougher1f288f62009-02-21 03:05:52 +000082int silent = TRUE;
plougher1f413c82005-11-18 00:02:14 +000083long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +000084int exportable = TRUE;
85int progress = TRUE;
plougher8dcc6992007-08-17 19:32:52 +000086int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +000087int old_exclude = TRUE;
88int use_regex = FALSE;
plougher801ba6a2010-02-01 03:12:59 +000089int first_freelist = TRUE;
plougher1f413c82005-11-18 00:02:14 +000090
91/* superblock attributes */
92int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +000093unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +000094int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
95 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +000096
97/* write position within data section */
98long long bytes = 0, total_bytes = 0;
99
100/* in memory directory table - possibly compressed */
101char *directory_table = NULL;
102unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
103
104/* cached directory table */
105char *directory_data_cache = NULL;
106unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
107
108/* in memory inode table - possibly compressed */
109char *inode_table = NULL;
110unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
111
112/* cached inode table */
113char *data_cache = NULL;
114unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
115
plougher0e453652006-11-06 01:49:35 +0000116/* inode lookup table */
117squashfs_inode *inode_lookup_table = NULL;
118
plougher1f413c82005-11-18 00:02:14 +0000119/* in memory directory data */
120#define I_COUNT_SIZE 128
121#define DIR_ENTRIES 32
122#define INODE_HASH_SIZE 65536
123#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
124#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
125
126struct cached_dir_index {
plougher2bd2b722010-12-31 10:52:15 +0000127 struct squashfs_dir_index index;
128 char *name;
plougher1f413c82005-11-18 00:02:14 +0000129};
130
131struct directory {
132 unsigned int start_block;
133 unsigned int size;
134 unsigned char *buff;
135 unsigned char *p;
136 unsigned int entry_count;
137 unsigned char *entry_count_p;
138 unsigned int i_count;
139 unsigned int i_size;
140 struct cached_dir_index *index;
141 unsigned char *index_count_p;
142 unsigned int inode_number;
143};
144
plougher1f413c82005-11-18 00:02:14 +0000145struct inode_info *inode_info[INODE_HASH_SIZE];
146
147/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000148struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000149int dup_files = 0;
150
plougher8f8e1a12007-10-18 02:50:21 +0000151/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000152/* list of exclude dirs/files */
153struct exclude_info {
154 dev_t st_dev;
155 ino_t st_ino;
156};
157
158#define EXCLUDE_SIZE 8192
159int exclude = 0;
160struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000161int old_excluded(char *filename, struct stat *buf);
162
163struct path_entry {
164 char *name;
165 regex_t *preg;
166 struct pathname *paths;
167};
168
169struct pathname {
170 int names;
171 struct path_entry *name;
172};
173
plougherf9039c92007-10-22 03:54:16 +0000174struct pathnames {
175 int count;
176 struct pathname *path[0];
177};
178#define PATHS_ALLOC_SIZE 10
179
180struct pathnames *paths = NULL;
181struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000182struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000183int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000184
185/* fragment block data structures */
186int fragments = 0;
plougher76c64082008-03-08 01:32:23 +0000187
plougher1f413c82005-11-18 00:02:14 +0000188struct fragment {
189 unsigned int index;
190 int offset;
191 int size;
192};
plougher76c64082008-03-08 01:32:23 +0000193
plougher1f413c82005-11-18 00:02:14 +0000194#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000195#define FRAG_INDEX (1LL << 32)
196
plougher8ed84b92010-12-31 10:37:24 +0000197struct squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000198int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000199
plougher1f413c82005-11-18 00:02:14 +0000200/* current inode number for directories and non directories */
Phillip Lougher539c2b12012-07-30 20:14:52 +0100201unsigned int inode_no = 1;
plougherdf70c3e2006-01-27 09:34:13 +0000202unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000203
204/* list of source dirs/files */
205int source = 0;
206char **source_path;
207
208/* list of root directory entries read from original filesystem */
209int old_root_entries = 0;
210struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000211 char *name;
212 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000213};
214struct old_root_entry_info *old_root_entry;
215
216/* in memory file info */
217struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000218 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000219 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000220 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000221 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000222 long long start;
223 unsigned int *block_list;
224 struct file_info *next;
225 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000226 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000227};
228
229/* count of how many times SIGINT or SIGQUIT has been sent */
230int interrupted = 0;
231
plougher875bfef2010-08-12 23:48:41 +0000232/* flag if we're restoring existing filesystem */
233int restoring = 0;
234
plougherfd57dfe2009-03-30 01:17:52 +0000235/* restore orignal filesystem state if appending to existing filesystem is
236 * cancelled */
plougher1f413c82005-11-18 00:02:14 +0000237jmp_buf env;
plougherca2c93f2008-08-15 08:34:57 +0000238char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
plougher1f413c82005-11-18 00:02:14 +0000239
240long long sbytes, stotal_bytes;
241
242unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
plougherca2c93f2008-08-15 08:34:57 +0000243 sdirectory_cache_bytes, sdirectory_compressed_bytes,
plougher1f413c82005-11-18 00:02:14 +0000244 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000245 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000246 sdir_count, sfifo_count, ssock_count, sdup_files;
247int sfragments;
248int restore = 0;
plougher5507dd92006-11-06 00:43:10 +0000249int threads;
plougher1f413c82005-11-18 00:02:14 +0000250
251/* flag whether destination file is a block device */
252int block_device = 0;
253
254/* flag indicating whether files are sorted using sort list(s) */
255int sorted = 0;
256
plougher324978d2006-02-27 04:53:29 +0000257/* save destination file name for deleting on error */
258char *destination_file = NULL;
259
plougher99ac0cc2007-10-29 03:17:10 +0000260/* recovery file for abnormal exit on appending */
Phillip Lougheraf4c9232012-11-15 03:46:28 +0000261char *recovery_file = NULL;
plougher99ac0cc2007-10-29 03:17:10 +0000262int recover = TRUE;
263
ploughereb6eac92008-02-26 01:50:48 +0000264/* struct describing a cache entry passed between threads */
plougher5507dd92006-11-06 00:43:10 +0000265struct file_buffer {
ploughereb6eac92008-02-26 01:50:48 +0000266 struct cache *cache;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100267 struct file_buffer *hash_next;
268 struct file_buffer *hash_prev;
269 struct file_buffer *free_next;
270 struct file_buffer *free_prev;
271 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000272 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000273 long long index;
274 long long block;
plougher0f464442008-03-31 00:27:56 +0000275 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000276 int size;
277 int c_byte;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100278 char keep;
279 char used;
280 char fragment;
281 char error;
Phillip Lougher63f531f2011-09-10 04:03:32 +0100282 char noD;
plougher76c64082008-03-08 01:32:23 +0000283 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000284};
285
ploughereb6eac92008-02-26 01:50:48 +0000286
plougher5507dd92006-11-06 00:43:10 +0000287/* struct describing queues used to pass data between threads */
288struct queue {
289 int size;
290 int readp;
291 int writep;
292 pthread_mutex_t mutex;
293 pthread_cond_t empty;
294 pthread_cond_t full;
295 void **data;
296};
297
plougher1b899fc2008-08-07 01:24:06 +0000298
299/* in memory uid tables */
300#define ID_ENTRIES 256
301#define ID_HASH(id) (id & (ID_ENTRIES - 1))
302#define ISA_UID 1
303#define ISA_GID 2
304struct id {
305 unsigned int id;
306 int index;
307 char flags;
308 struct id *next;
plougher5507dd92006-11-06 00:43:10 +0000309};
plougher1b899fc2008-08-07 01:24:06 +0000310struct id *id_hash_table[ID_ENTRIES];
311struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
312unsigned int uid_count = 0, guid_count = 0;
313unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000314
ploughereb6eac92008-02-26 01:50:48 +0000315struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougherfd57dfe2009-03-30 01:17:52 +0000316struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
317 *to_frag;
Phillip Lougher3b89ee82012-10-18 23:55:37 +0100318pthread_t *thread, *deflator_thread, *frag_deflator_thread;
plougher5507dd92006-11-06 00:43:10 +0000319pthread_mutex_t fragment_mutex;
320pthread_cond_t fragment_waiting;
321pthread_mutex_t pos_mutex;
322
323/* user options that control parallelisation */
324int processors = -1;
325/* default size of output buffer in Mbytes */
326#define WRITER_BUFFER_DEFAULT 512
327/* default size of input buffer in Mbytes */
328#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000329/* default size of fragment buffer in Mbytes */
330#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000331int writer_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000332
plougherc5d59872010-11-22 01:36:01 +0000333/* compression operations */
ploughera175ce22009-07-30 04:43:27 +0000334static struct compressor *comp;
plougherc5d59872010-11-22 01:36:01 +0000335int compressor_opts_parsed = 0;
plougher13fdddf2010-11-24 01:23:41 +0000336void *stream = NULL;
plougher7b8ee502009-07-29 07:54:30 +0000337
plougher860c1f32010-08-11 01:37:17 +0000338/* xattr stats */
339unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
340
plougher49b57a92009-03-31 03:23:05 +0000341char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000342void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
343 int type);
plougher64e83fd2010-12-31 21:21:26 +0000344extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
ploughera175ce22009-07-30 04:43:27 +0000345 char *source);
plougherfd57dfe2009-03-30 01:17:52 +0000346extern long long read_filesystem(char *root_name, int fd,
plougher64e83fd2010-12-31 21:21:26 +0000347 struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
plougherfd57dfe2009-03-30 01:17:52 +0000348 char **cdirectory_table, char **directory_data_cache,
349 unsigned int *last_directory_block, unsigned int *inode_dir_offset,
350 unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
351 unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
352 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
353 long long *uncompressed_file, unsigned int *uncompressed_inode,
plougher50b31762009-03-31 04:14:46 +0000354 unsigned int *uncompressed_directory,
355 unsigned int *inode_dir_inode_number,
356 unsigned int *inode_dir_parent_inode,
plougherfd57dfe2009-03-30 01:17:52 +0000357 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher8ed84b92010-12-31 10:37:24 +0000358 struct squashfs_fragment_entry **fragment_table,
plougherfd57dfe2009-03-30 01:17:52 +0000359 squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000360extern int read_sort_file(char *filename, int source, char *source_path[]);
361extern void sort_files_and_write(struct dir_info *dir);
plougherfd57dfe2009-03-30 01:17:52 +0000362struct file_info *duplicate(long long file_size, long long bytes,
363 unsigned int **block_list, long long *start, struct fragment **fragment,
364 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
365 unsigned short fragment_checksum, int checksum_flag);
Phillip Lougherb38c1722012-02-09 23:26:19 +0000366struct dir_info *dir_scan1(char *, char *, struct pathnames *,
Phillip Lougher494479f2012-02-03 15:45:41 +0000367 struct dir_ent *(_readdir)(struct dir_info *), int);
Phillip Lougher24eeb772012-10-13 01:56:24 +0100368void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
Phillip Lougher23d83622012-10-14 02:35:22 +0100369void dir_scan3(struct dir_info *root, struct dir_info *dir);
370void dir_scan4(struct dir_info *dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +0000371void dir_scan5(struct dir_info *dir);
372void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000373struct file_info *add_non_dup(long long file_size, long long bytes,
374 unsigned int *block_list, long long start, struct fragment *fragment,
375 unsigned short checksum, unsigned short fragment_checksum,
376 int checksum_flag);
plougher1d1c6bb2010-07-21 03:03:13 +0000377extern int generate_file_priorities(struct dir_info *dir, int priority,
plougherfd57dfe2009-03-30 01:17:52 +0000378 struct stat *buf);
plougher5507dd92006-11-06 00:43:10 +0000379extern struct priority_entry *priority_list[65536];
ploughera0a49c32010-08-11 01:47:59 +0000380long long generic_write_table(int, void *, int, void *, int);
plougherca61d1c2010-07-20 18:32:32 +0000381void restorefs();
Phillip Lougher1eae83d2012-09-26 02:12:45 +0100382struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
plougher5507dd92006-11-06 00:43:10 +0000383
384
Phillip Lougher838d2962012-10-23 03:29:30 +0100385void prep_exit_mksquashfs()
386{
387 if(restore)
388 restorefs();
389 if(delete && destination_file && !block_device)
390 unlink(destination_file);
391 exit(1);
392}
393
394
plougher5507dd92006-11-06 00:43:10 +0000395struct queue *queue_init(int size)
396{
397 struct queue *queue = malloc(sizeof(struct queue));
398
399 if(queue == NULL)
plougherca61d1c2010-07-20 18:32:32 +0000400 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000401
plougher0d55d9e2010-12-16 04:50:21 +0000402 queue->data = malloc(sizeof(void *) * (size + 1));
403 if(queue->data == NULL) {
plougher5507dd92006-11-06 00:43:10 +0000404 free(queue);
plougherca61d1c2010-07-20 18:32:32 +0000405 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000406 }
407
408 queue->size = size + 1;
409 queue->readp = queue->writep = 0;
410 pthread_mutex_init(&queue->mutex, NULL);
411 pthread_cond_init(&queue->empty, NULL);
412 pthread_cond_init(&queue->full, NULL);
413
414 return queue;
plougherca61d1c2010-07-20 18:32:32 +0000415
416failed:
417 BAD_ERROR("Out of memory in queue_init\n");
plougher5507dd92006-11-06 00:43:10 +0000418}
419
420
421void queue_put(struct queue *queue, void *data)
422{
423 int nextp;
424
425 pthread_mutex_lock(&queue->mutex);
426
427 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
428 pthread_cond_wait(&queue->full, &queue->mutex);
429
430 queue->data[queue->writep] = data;
431 queue->writep = nextp;
432 pthread_cond_signal(&queue->empty);
433 pthread_mutex_unlock(&queue->mutex);
434}
435
436
437void *queue_get(struct queue *queue)
438{
439 void *data;
440 pthread_mutex_lock(&queue->mutex);
441
442 while(queue->readp == queue->writep)
443 pthread_cond_wait(&queue->empty, &queue->mutex);
444
445 data = queue->data[queue->readp];
446 queue->readp = (queue->readp + 1) % queue->size;
447 pthread_cond_signal(&queue->full);
448 pthread_mutex_unlock(&queue->mutex);
449
450 return data;
451}
452
plougher1f413c82005-11-18 00:02:14 +0000453
ploughereb6eac92008-02-26 01:50:48 +0000454/* Cache status struct. Caches are used to keep
455 track of memory buffers passed between different threads */
456struct cache {
457 int max_buffers;
458 int count;
459 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000460 pthread_mutex_t mutex;
461 pthread_cond_t wait_for_free;
462 struct file_buffer *free_list;
463 struct file_buffer *hash_table[65536];
464};
465
466
plougher2ea89142008-03-11 01:34:19 +0000467#define INSERT_LIST(NAME, TYPE) \
468void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
469 if(*list) { \
470 entry->NAME##_next = *list; \
471 entry->NAME##_prev = (*list)->NAME##_prev; \
472 (*list)->NAME##_prev->NAME##_next = entry; \
473 (*list)->NAME##_prev = entry; \
474 } else { \
475 *list = entry; \
476 entry->NAME##_prev = entry->NAME##_next = entry; \
477 } \
478}
479
480
481#define REMOVE_LIST(NAME, TYPE) \
482void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
483 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
484 /* only this entry in the list */ \
485 *list = NULL; \
486 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
487 /* more than one entry in the list */ \
488 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
489 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
490 if(*list == entry) \
491 *list = entry->NAME##_next; \
492 } \
493 entry->NAME##_prev = entry->NAME##_next = NULL; \
494}
495
496
497#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000498
499
500/* Called with the cache mutex held */
501void insert_hash_table(struct cache *cache, struct file_buffer *entry)
502{
503 int hash = CALCULATE_HASH(entry->index);
504
505 entry->hash_next = cache->hash_table[hash];
506 cache->hash_table[hash] = entry;
507 entry->hash_prev = NULL;
508 if(entry->hash_next)
509 entry->hash_next->hash_prev = entry;
510}
511
512
513/* Called with the cache mutex held */
514void remove_hash_table(struct cache *cache, struct file_buffer *entry)
515{
516 if(entry->hash_prev)
517 entry->hash_prev->hash_next = entry->hash_next;
518 else
plougher50b31762009-03-31 04:14:46 +0000519 cache->hash_table[CALCULATE_HASH(entry->index)] =
520 entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000521 if(entry->hash_next)
522 entry->hash_next->hash_prev = entry->hash_prev;
523
524 entry->hash_prev = entry->hash_next = NULL;
525}
526
527
528/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000529INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000530
531/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000532REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000533
534
535struct cache *cache_init(int buffer_size, int max_buffers)
536{
537 struct cache *cache = malloc(sizeof(struct cache));
538
539 if(cache == NULL)
plougher9ca649c2010-07-21 00:46:11 +0000540 BAD_ERROR("Out of memory in cache_init\n");
ploughereb6eac92008-02-26 01:50:48 +0000541
542 cache->max_buffers = max_buffers;
543 cache->buffer_size = buffer_size;
544 cache->count = 0;
545 cache->free_list = NULL;
546 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000547 pthread_mutex_init(&cache->mutex, NULL);
548 pthread_cond_init(&cache->wait_for_free, NULL);
549
550 return cache;
551}
552
553
554struct file_buffer *cache_lookup(struct cache *cache, long long index)
555{
556 /* Lookup block in the cache, if found return with usage count
557 * incremented, if not found return NULL */
558 int hash = CALCULATE_HASH(index);
559 struct file_buffer *entry;
560
561 pthread_mutex_lock(&cache->mutex);
562
563 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
564 if(entry->index == index)
565 break;
566
567 if(entry) {
568 /* found the block in the cache, increment used count and
569 * if necessary remove from free list so it won't disappear
570 */
571 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000572 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000573 }
574
575 pthread_mutex_unlock(&cache->mutex);
576
577 return entry;
578}
579
580
plougher76c64082008-03-08 01:32:23 +0000581struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000582{
583 /* Get a free block out of the cache indexed on index. */
584 struct file_buffer *entry;
585
586 pthread_mutex_lock(&cache->mutex);
587
plougher76c64082008-03-08 01:32:23 +0000588 while(1) {
589 /* first try to get a block from the free list */
plougher801ba6a2010-02-01 03:12:59 +0000590 if(first_freelist && cache->free_list) {
plougher76c64082008-03-08 01:32:23 +0000591 /* a block on the free_list is a "keep" block */
592 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000593 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000594 remove_hash_table(cache, entry);
595 break;
plougher801ba6a2010-02-01 03:12:59 +0000596 } else if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000597 /* next try to allocate new block */
plougherfd57dfe2009-03-30 01:17:52 +0000598 entry = malloc(sizeof(struct file_buffer) +
599 cache->buffer_size);
plougher76c64082008-03-08 01:32:23 +0000600 if(entry == NULL)
601 goto failed;
602 entry->cache = cache;
603 entry->free_prev = entry->free_next = NULL;
604 cache->count ++;
605 break;
plougher801ba6a2010-02-01 03:12:59 +0000606 } else if(!first_freelist && cache->free_list) {
plougher2ea89142008-03-11 01:34:19 +0000607 /* a block on the free_list is a "keep" block */
608 entry = cache->free_list;
609 remove_free_list(&cache->free_list, entry);
610 remove_hash_table(cache, entry);
611 break;
plougher801ba6a2010-02-01 03:12:59 +0000612 } else
plougher76c64082008-03-08 01:32:23 +0000613 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000614 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000615 }
616
plougher76c64082008-03-08 01:32:23 +0000617 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000618 entry->used = 1;
619 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000620 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000621 if(keep) {
622 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000623 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000624 }
ploughereb6eac92008-02-26 01:50:48 +0000625 pthread_mutex_unlock(&cache->mutex);
626
627 return entry;
628
629failed:
630 pthread_mutex_unlock(&cache->mutex);
ploughercc6896d2010-07-21 00:56:25 +0000631 BAD_ERROR("Out of memory in cache_get\n");
ploughereb6eac92008-02-26 01:50:48 +0000632}
633
ploughereb6eac92008-02-26 01:50:48 +0000634
plougher0f464442008-03-31 00:27:56 +0000635void cache_rehash(struct file_buffer *entry, long long index)
636{
637 struct cache *cache = entry->cache;
638
639 pthread_mutex_lock(&cache->mutex);
640 if(entry->keep)
641 remove_hash_table(cache, entry);
642 entry->keep = TRUE;
643 entry->index = index;
644 insert_hash_table(cache, entry);
645 pthread_mutex_unlock(&cache->mutex);
646}
647
648
ploughereb6eac92008-02-26 01:50:48 +0000649void cache_block_put(struct file_buffer *entry)
650{
plougher76c64082008-03-08 01:32:23 +0000651 struct cache *cache;
652
ploughereb6eac92008-02-26 01:50:48 +0000653 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000654 * can be reused and if a keep block put onto the free list. As keep
plougher50b31762009-03-31 04:14:46 +0000655 * blocks remain accessible via the hash table they can be found
656 * getting a new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000657
658 if(entry == NULL)
659 return;
660
plougher76c64082008-03-08 01:32:23 +0000661 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000662
plougher76c64082008-03-08 01:32:23 +0000663 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000664
665 entry->used --;
666 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000667 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000668 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000669 else {
670 free(entry);
671 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000672 }
plougher76c64082008-03-08 01:32:23 +0000673
674 /* One or more threads may be waiting on this block */
675 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000676 }
677
plougher76c64082008-03-08 01:32:23 +0000678 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000679}
680
681
plougher50b31762009-03-31 04:14:46 +0000682#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
683 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000684
685
plougher5507dd92006-11-06 00:43:10 +0000686inline void waitforthread(int i)
687{
688 TRACE("Waiting for thread %d\n", i);
689 while(thread[i] != 0)
690 sched_yield();
691}
692
693
plougher1f413c82005-11-18 00:02:14 +0000694void restorefs()
695{
plougher5507dd92006-11-06 00:43:10 +0000696 int i;
697
plougher02bc3bc2007-02-25 12:12:01 +0000698 if(thread == NULL || thread[0] == 0)
699 return;
700
plougher875bfef2010-08-12 23:48:41 +0000701 if(restoring++)
702 /*
plougher5b290d22010-08-12 23:52:21 +0000703 * Recursive failure when trying to restore filesystem!
704 * Nothing to do except to exit, otherwise we'll just appear
plougher875bfef2010-08-12 23:48:41 +0000705 * to hang. The user should be able to restore from the
plougher5b290d22010-08-12 23:52:21 +0000706 * recovery file (which is why it was added, in case of
707 * catastrophic failure in Mksquashfs)
plougher875bfef2010-08-12 23:48:41 +0000708 */
709 exit(1);
710
plougher1f413c82005-11-18 00:02:14 +0000711 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000712
plougher91fbb302008-05-06 02:29:36 +0000713 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000714 if(thread[i])
715 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000716 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000717 waitforthread(i);
718 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000719 bytes = sbytes;
720 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000721 memcpy(directory_data_cache, sdirectory_data_cache,
722 sdirectory_cache_bytes);
723 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000724 inode_bytes = sinode_bytes;
725 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000726 memcpy(directory_table + directory_bytes, sdirectory_compressed,
727 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000728 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000729 total_bytes = stotal_bytes;
730 total_inode_bytes = stotal_inode_bytes;
731 total_directory_bytes = stotal_directory_bytes;
732 inode_count = sinode_count;
733 file_count = sfile_count;
734 sym_count = ssym_count;
735 dev_count = sdev_count;
736 dir_count = sdir_count;
737 fifo_count = sfifo_count;
738 sock_count = ssock_count;
739 dup_files = sdup_files;
740 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000741 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000742 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000743 longjmp(env, 1);
744}
745
746
747void sighandler()
748{
plougher5507dd92006-11-06 00:43:10 +0000749 if(++interrupted > 2)
750 return;
751 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000752 restorefs();
753 else {
754 ERROR("Interrupting will restore original filesystem!\n");
755 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000756 }
757}
758
759
plougher324978d2006-02-27 04:53:29 +0000760void sighandler2()
761{
762 EXIT_MKSQUASHFS();
763}
764
765
plougher5507dd92006-11-06 00:43:10 +0000766void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000767{
plougher5507dd92006-11-06 00:43:10 +0000768 int i;
769 sigset_t sigmask;
770 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000771
plougher5507dd92006-11-06 00:43:10 +0000772 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
773 thread[i] = (pthread_t) 0;
774
plougher07966f72007-11-14 10:54:45 +0000775 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000776
777 sigemptyset(&sigmask);
778 sigaddset(&sigmask, SIGINT);
779 sigaddset(&sigmask, SIGQUIT);
780 sigaddset(&sigmask, SIGUSR1);
781 while(1) {
782 sigsuspend(&sigmask);
783 TRACE("After wait in sigusr1_handler :(\n");
784 }
785}
786
787
plougher13fdddf2010-11-24 01:23:41 +0000788int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000789 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000790{
plougher7b8ee502009-07-29 07:54:30 +0000791 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000792
plougher7b8ee502009-07-29 07:54:30 +0000793 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000794 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
795 &error);
plougher7b8ee502009-07-29 07:54:30 +0000796 if(c_byte == -1)
797 BAD_ERROR("mangle2:: %s compress failed with error "
798 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000799 }
800
plougher7b8ee502009-07-29 07:54:30 +0000801 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000802 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000803 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
804 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000805 }
806
plougher7b8ee502009-07-29 07:54:30 +0000807 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000808}
809
810
plougher7b8ee502009-07-29 07:54:30 +0000811int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000812 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000813{
plougher13fdddf2010-11-24 01:23:41 +0000814 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000815 data_block);
plougher5507dd92006-11-06 00:43:10 +0000816}
817
818
plougherac28cd12010-02-24 02:25:03 +0000819void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000820{
821 int data_space;
822 unsigned short c_byte;
823
824 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000825 if((inode_size - inode_bytes) <
826 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000827 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000828 (SQUASHFS_METADATA_SIZE << 1) + 2);
plougher1eb2a662010-07-26 17:30:50 +0000829 if(it == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000830 goto failed;
831 }
plougher1eb2a662010-07-26 17:30:50 +0000832 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000833 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
834 }
835
plougherfd57dfe2009-03-30 01:17:52 +0000836 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000837 data_cache, SQUASHFS_METADATA_SIZE,
838 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000839 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000840 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000841 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
842 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000843 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000844 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000845 cache_bytes -= SQUASHFS_METADATA_SIZE;
846 }
847
848 data_space = (cache_size - cache_bytes);
849 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000850 int realloc_size = cache_size == 0 ?
851 ((req_size + SQUASHFS_METADATA_SIZE) &
852 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
853 data_space;
plougher1f413c82005-11-18 00:02:14 +0000854
plougher17248ca2010-07-27 00:24:35 +0000855 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000856 realloc_size);
plougher17248ca2010-07-27 00:24:35 +0000857 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000858 goto failed;
859 }
860 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000861 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000862 }
863
864 cache_bytes += req_size;
865
plougherac28cd12010-02-24 02:25:03 +0000866 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000867
868failed:
869 BAD_ERROR("Out of memory in inode table reallocation!\n");
870}
871
872
plougher8a8c4102009-03-29 22:28:49 +0000873int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000874{
875 int res, count;
876
877 for(count = 0; count < bytes; count += res) {
878 res = read(fd, buff + count, bytes - count);
879 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000880 if(res == 0)
881 goto bytes_read;
882 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000883 ERROR("Read failed because %s\n",
884 strerror(errno));
885 return -1;
886 } else
887 res = 0;
888 }
889 }
890
891bytes_read:
892 return count;
893}
894
895
plougher3306cb22010-06-18 04:22:44 +0000896int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000897{
898 off_t off = byte;
899
plougher1d065e92010-06-18 03:58:27 +0000900 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000901 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000902
plougher5507dd92006-11-06 00:43:10 +0000903 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000904 if(lseek(fd, off, SEEK_SET) == -1) {
905 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000906 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000907 goto failed;
908 }
plougher1f413c82005-11-18 00:02:14 +0000909
plougher1d065e92010-06-18 03:58:27 +0000910 if(read_bytes(fd, buff, bytes) < bytes) {
911 ERROR("Read on destination failed\n");
912 goto failed;
913 }
914
plougher5507dd92006-11-06 00:43:10 +0000915 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000916 return 1;
917
918failed:
919 pthread_mutex_unlock(&pos_mutex);
920 return 0;
plougher1f413c82005-11-18 00:02:14 +0000921}
922
923
plougher628e7682009-03-29 22:12:24 +0000924int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000925{
926 int res, count;
927
928 for(count = 0; count < bytes; count += res) {
929 res = write(fd, buff + count, bytes - count);
930 if(res == -1) {
931 if(errno != EINTR) {
932 ERROR("Write failed because %s\n",
933 strerror(errno));
934 return -1;
935 }
936 res = 0;
937 }
938 }
939
940 return 0;
941}
942
943
plougher29e2ace2010-12-31 08:50:00 +0000944void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000945{
946 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000947
plougher875bfef2010-08-12 23:48:41 +0000948 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000949 pthread_mutex_lock(&pos_mutex);
950
plougher91fbb302008-05-06 02:29:36 +0000951 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +0000952 BAD_ERROR("Lseek on destination failed because %s\n",
953 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +0000954
plougher0dd6f122009-03-29 21:43:57 +0000955 if(write_bytes(fd, buff, bytes) == -1)
956 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +0000957
plougher875bfef2010-08-12 23:48:41 +0000958 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000959 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000960}
961
962
963long long write_inodes()
964{
965 unsigned short c_byte;
966 int avail_bytes;
967 char *datap = data_cache;
968 long long start_bytes = bytes;
969
970 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000971 if(inode_size - inode_bytes <
972 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +0000973 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000974 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +0000975 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +0000976 BAD_ERROR("Out of memory in inode table "
977 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +0000978 }
979 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +0000980 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000981 }
plougherfd57dfe2009-03-30 01:17:52 +0000982 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
983 SQUASHFS_METADATA_SIZE : cache_bytes;
984 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
985 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000986 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000987 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000988 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
989 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +0000990 datap += avail_bytes;
991 cache_bytes -= avail_bytes;
992 }
993
plougher29e2ace2010-12-31 08:50:00 +0000994 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +0000995 bytes += inode_bytes;
996
997 return start_bytes;
998}
999
1000
1001long long write_directories()
1002{
1003 unsigned short c_byte;
1004 int avail_bytes;
1005 char *directoryp = directory_data_cache;
1006 long long start_bytes = bytes;
1007
1008 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001009 if(directory_size - directory_bytes <
1010 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001011 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001012 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1013 + 2));
plougher79d665a2010-07-27 00:19:23 +00001014 if(dt == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001015 BAD_ERROR("Out of memory in directory table "
1016 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001017 }
1018 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001019 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001020 }
plougherfd57dfe2009-03-30 01:17:52 +00001021 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1022 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001023 c_byte = mangle(directory_table + directory_bytes +
1024 BLOCK_OFFSET, directoryp, avail_bytes,
1025 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001026 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1027 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001028 SQUASHFS_SWAP_SHORTS(&c_byte,
1029 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001030 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1031 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001032 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001033 directoryp += avail_bytes;
1034 directory_cache_bytes -= avail_bytes;
1035 }
plougher29e2ace2010-12-31 08:50:00 +00001036 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +00001037 bytes += directory_bytes;
1038
1039 return start_bytes;
1040}
1041
1042
plougher1b899fc2008-08-07 01:24:06 +00001043long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001044{
plougher1b899fc2008-08-07 01:24:06 +00001045 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001046 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001047 int i;
1048
plougher1b899fc2008-08-07 01:24:06 +00001049 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001050 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001051 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001052 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001053 }
1054
ploughera0a49c32010-08-11 01:47:59 +00001055 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001056}
1057
1058
plougher1b899fc2008-08-07 01:24:06 +00001059struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001060{
plougher1b899fc2008-08-07 01:24:06 +00001061 int hash = ID_HASH(id);
1062 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001063
plougher1b899fc2008-08-07 01:24:06 +00001064 for(; entry; entry = entry->next)
1065 if(entry->id == id)
1066 break;
plougher1f413c82005-11-18 00:02:14 +00001067
plougher1b899fc2008-08-07 01:24:06 +00001068 return entry;
plougher1f413c82005-11-18 00:02:14 +00001069}
1070
1071
plougher1b899fc2008-08-07 01:24:06 +00001072struct id *create_id(unsigned int id)
1073{
1074 int hash = ID_HASH(id);
1075 struct id *entry = malloc(sizeof(struct id));
1076 if(entry == NULL)
1077 BAD_ERROR("Out of memory in create_id\n");
1078 entry->id = id;
1079 entry->index = id_count ++;
1080 entry->flags = 0;
1081 entry->next = id_hash_table[hash];
1082 id_hash_table[hash] = entry;
1083 id_table[entry->index] = entry;
1084 return entry;
1085}
1086
1087
1088unsigned int get_uid(unsigned int uid)
1089{
1090 struct id *entry = get_id(uid);
1091
1092 if(entry == NULL) {
1093 if(id_count == SQUASHFS_IDS)
1094 BAD_ERROR("Out of uids!\n");
1095 entry = create_id(uid);
1096 }
1097
1098 if((entry->flags & ISA_UID) == 0) {
1099 entry->flags |= ISA_UID;
1100 uid_count ++;
1101 }
1102
1103 return entry->index;
1104}
1105
1106
1107unsigned int get_guid(unsigned int guid)
1108{
1109 struct id *entry = get_id(guid);
1110
1111 if(entry == NULL) {
1112 if(id_count == SQUASHFS_IDS)
1113 BAD_ERROR("Out of gids!\n");
1114 entry = create_id(guid);
1115 }
1116
1117 if((entry->flags & ISA_GID) == 0) {
1118 entry->flags |= ISA_GID;
1119 guid_count ++;
1120 }
1121
1122 return entry->index;
1123}
1124
1125
Phillip Lougher5ef51692012-11-19 03:35:39 +00001126#define ALLOC_SIZE 128
Phillip Lougher494479f2012-02-03 15:45:41 +00001127
Phillip Lougher5ef51692012-11-19 03:35:39 +00001128char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size)
1129{
1130 if(pathname == NULL) {
1131 pathname = malloc(ALLOC_SIZE);
1132 if(pathname == NULL)
1133 BAD_ERROR("Out of memory in pathname\n");
1134 }
1135
1136 for(;;) {
1137 int res = snprintf(pathname, *size, "%s/%s",
1138 dir_ent->our_dir->pathname,
1139 dir_ent->source_name ? : dir_ent->name);
1140
1141 if(res < 0)
1142 BAD_ERROR("snprintf failed in pathname\n");
1143 else if(res >= *size) {
1144 /*
1145 * pathname is too small to contain the result, so
1146 * increase it and try again
1147 */
1148 *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1149 pathname = realloc(pathname, *size);
1150 if(pathname == NULL)
1151 BAD_ERROR("Out of memory in pathname\n");
1152 } else
1153 break;
1154 }
Phillip Lougher494479f2012-02-03 15:45:41 +00001155
1156 return pathname;
1157}
1158
1159
1160char *pathname(struct dir_ent *dir_ent)
1161{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001162 static char *pathname = NULL;
1163 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001164
Phillip Lougher5ef51692012-11-19 03:35:39 +00001165 if (dir_ent->nonstandard_pathname)
1166 return dir_ent->nonstandard_pathname;
1167
1168 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001169}
1170
1171
1172char *pathname_reader(struct dir_ent *dir_ent)
1173{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001174 static char *pathname = NULL;
1175 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001176
Phillip Lougher5ef51692012-11-19 03:35:39 +00001177 if (dir_ent->nonstandard_pathname)
1178 return dir_ent->nonstandard_pathname;
1179
1180 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001181}
1182
1183
Phillip Lougherb38c1722012-02-09 23:26:19 +00001184char *subpathname(struct dir_ent *dir_ent)
1185{
Phillip Lougherd457ed32012-11-19 01:36:56 +00001186 static char *subpath = NULL;
1187 static int size = ALLOC_SIZE;
1188 int res;
Phillip Lougherb38c1722012-02-09 23:26:19 +00001189
Phillip Lougherd457ed32012-11-19 01:36:56 +00001190 if(subpath == NULL) {
1191 subpath = malloc(ALLOC_SIZE);
1192 if(subpath == NULL)
1193 BAD_ERROR("Out of memory in subpathname\n");
1194 }
1195
1196 for(;;) {
1197 if(dir_ent->our_dir->subpath[0] != '\0')
1198 res = snprintf(subpath, size, "%s/%s",
1199 dir_ent->our_dir->subpath, dir_ent->name);
1200 else
1201 res = snprintf(subpath, size, "/%s", dir_ent->name);
1202
1203 if(res < 0)
1204 BAD_ERROR("snprintf failed in subpathname\n");
1205 else if(res >= size) {
1206 /*
1207 * subpath is too small to contain the result, so
1208 * increase it and try again
1209 */
1210 size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1211 subpath = realloc(subpath, size);
1212 if(subpath == NULL)
1213 BAD_ERROR("Out of memory in subpathname\n");
1214 } else
1215 break;
Phillip Lougher90e08252012-10-05 04:33:35 +01001216 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00001217
1218 return subpath;
1219}
1220
1221
Phillip Lougher539c2b12012-07-30 20:14:52 +01001222inline unsigned int get_inode_no(struct inode_info *inode)
Phillip Lougher53cef742012-07-25 05:12:50 +01001223{
Phillip Lougher539c2b12012-07-30 20:14:52 +01001224 return inode->inode_number;
Phillip Lougher53cef742012-07-25 05:12:50 +01001225}
1226
1227
Phillip Lougher539c2b12012-07-30 20:14:52 +01001228inline unsigned int get_parent_no(struct dir_info *dir)
Phillip Lougher53cef742012-07-25 05:12:50 +01001229{
Phillip Lougher1eae83d2012-09-26 02:12:45 +01001230 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
Phillip Lougher53cef742012-07-25 05:12:50 +01001231}
1232
1233
plougher3c6bdb52010-05-01 02:30:59 +00001234int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1235 struct dir_ent *dir_ent, int type, long long byte_size,
1236 long long start_block, unsigned int offset, unsigned int *block_list,
1237 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001238{
1239 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +00001240 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +00001241 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +00001242 void *inode;
Phillip Lougher494479f2012-02-03 15:45:41 +00001243 char *filename = pathname(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001244 int nlink = dir_ent->inode->nlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001245 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001246
ploughere6e0e1b2010-05-12 17:17:06 +00001247 switch(type) {
1248 case SQUASHFS_FILE_TYPE:
1249 if(dir_ent->inode->nlink > 1 ||
1250 byte_size >= (1LL << 32) ||
1251 start_block >= (1LL << 32) ||
1252 sparse || IS_XATTR(xattr))
1253 type = SQUASHFS_LREG_TYPE;
1254 break;
1255 case SQUASHFS_DIR_TYPE:
1256 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1257 type = SQUASHFS_LDIR_TYPE;
1258 break;
1259 case SQUASHFS_SYMLINK_TYPE:
1260 if(IS_XATTR(xattr))
1261 type = SQUASHFS_LSYMLINK_TYPE;
1262 break;
1263 case SQUASHFS_BLKDEV_TYPE:
1264 if(IS_XATTR(xattr))
1265 type = SQUASHFS_LBLKDEV_TYPE;
1266 break;
1267 case SQUASHFS_CHRDEV_TYPE:
1268 if(IS_XATTR(xattr))
1269 type = SQUASHFS_LCHRDEV_TYPE;
1270 break;
plougherc5d69322010-05-12 19:28:38 +00001271 case SQUASHFS_FIFO_TYPE:
1272 if(IS_XATTR(xattr))
1273 type = SQUASHFS_LFIFO_TYPE;
1274 break;
1275 case SQUASHFS_SOCKET_TYPE:
1276 if(IS_XATTR(xattr))
1277 type = SQUASHFS_LSOCKET_TYPE;
1278 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001279 }
1280
plougher1f413c82005-11-18 00:02:14 +00001281 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001282 base->uid = get_uid((unsigned int) global_uid == -1 ?
1283 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001284 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001285 base->guid = get_guid((unsigned int) global_gid == -1 ?
1286 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001287 base->mtime = buf->st_mtime;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001288 base->inode_number = get_inode_no(dir_ent->inode);
plougher1f413c82005-11-18 00:02:14 +00001289
1290 if(type == SQUASHFS_FILE_TYPE) {
1291 int i;
plougher8701ed62010-12-31 20:38:38 +00001292 struct squashfs_reg_inode_header *reg = &inode_header.reg;
1293 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001294
1295 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001296 reg->file_size = byte_size;
1297 reg->start_block = start_block;
1298 reg->fragment = fragment->index;
1299 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001300 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1301 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001302 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1303 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001304 start_block, offset, fragment->index, fragment->offset,
1305 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001306 for(i = 0; i < offset; i++)
1307 TRACE("Block %d, size %d\n", i, block_list[i]);
1308 }
1309 else if(type == SQUASHFS_LREG_TYPE) {
1310 int i;
plougher1e6ac4a2010-12-31 20:42:02 +00001311 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1312 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001313
1314 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001315 reg->nlink = nlink;
1316 reg->file_size = byte_size;
1317 reg->start_block = start_block;
1318 reg->fragment = fragment->index;
1319 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001320 if(sparse && sparse >= byte_size)
1321 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001322 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001323 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001324 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1325 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001326 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001327 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1328 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001329 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001330 for(i = 0; i < offset; i++)
1331 TRACE("Block %d, size %d\n", i, block_list[i]);
1332 }
1333 else if(type == SQUASHFS_LDIR_TYPE) {
1334 int i;
1335 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +00001336 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001337 struct cached_dir_index *index = dir_in->index;
1338 unsigned int i_count = dir_in->i_count;
1339 unsigned int i_size = dir_in->i_size;
1340
1341 if(byte_size >= 1 << 27)
1342 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1343
1344 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001345 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001346 dir->nlink = dir_ent->dir->directory_count + 2;
1347 dir->file_size = byte_size;
1348 dir->offset = offset;
1349 dir->start_block = start_block;
1350 dir->i_count = i_count;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001351 dir->parent_inode = get_parent_no(dir_ent->our_dir);
ploughere6e0e1b2010-05-12 17:17:06 +00001352 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001353
plougherac28cd12010-02-24 02:25:03 +00001354 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +00001355 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001356 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001357 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +00001358 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +00001359 memcpy(p, index[i].name, index[i].index.size + 1);
1360 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001361 }
plougher50b31762009-03-31 04:14:46 +00001362 TRACE("Long directory inode, file_size %lld, start_block "
1363 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1364 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001365 }
1366 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +00001367 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +00001368
1369 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001370 dir->nlink = dir_ent->dir->directory_count + 2;
1371 dir->file_size = byte_size;
1372 dir->offset = offset;
1373 dir->start_block = start_block;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001374 dir->parent_inode = get_parent_no(dir_ent->our_dir);
plougherac28cd12010-02-24 02:25:03 +00001375 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001376 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001377 "offset 0x%x, nlink %d\n", byte_size, start_block,
1378 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001379 }
1380 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +00001381 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001382 unsigned int major = major(buf->st_rdev);
1383 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001384
plougher5b398502008-10-04 23:22:03 +00001385 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001386 ERROR("Major %d out of range in device node %s, "
1387 "truncating to %d\n", major, filename,
1388 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001389 major &= 0xfff;
1390 }
1391 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001392 ERROR("Minor %d out of range in device node %s, "
1393 "truncating to %d\n", minor, filename,
1394 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001395 minor &= 0xfffff;
1396 }
plougher1f413c82005-11-18 00:02:14 +00001397 inode = get_inode(sizeof(*dev));
1398 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001399 dev->rdev = (major << 8) | (minor & 0xff) |
1400 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001401 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001402 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001403 }
ploughere6e0e1b2010-05-12 17:17:06 +00001404 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001405 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001406 unsigned int major = major(buf->st_rdev);
1407 unsigned int minor = minor(buf->st_rdev);
1408
1409 if(major > 0xfff) {
1410 ERROR("Major %d out of range in device node %s, "
1411 "truncating to %d\n", major, filename,
1412 major & 0xfff);
1413 major &= 0xfff;
1414 }
1415 if(minor > 0xfffff) {
1416 ERROR("Minor %d out of range in device node %s, "
1417 "truncating to %d\n", minor, filename,
1418 minor & 0xfffff);
1419 minor &= 0xfffff;
1420 }
1421 inode = get_inode(sizeof(*dev));
1422 dev->nlink = nlink;
1423 dev->rdev = (major << 8) | (minor & 0xff) |
1424 ((minor & ~0xff) << 12);
1425 dev->xattr = xattr;
1426 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1427 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1428 }
plougher1f413c82005-11-18 00:02:14 +00001429 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001430 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001431 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001432 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001433 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001434
plougher5cf38b82010-12-16 04:55:32 +00001435 byte = readlink(filename, buff, 65536);
1436 if(byte == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001437 ERROR("Failed to read symlink %s, creating empty "
1438 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001439 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001440 }
1441
1442 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001443 ERROR("Symlink %s is greater than 65536 bytes! "
1444 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001445 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001446 }
1447
1448 inode = get_inode(sizeof(*symlink) + byte);
1449 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001450 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001451 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1452 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001453 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1454 nlink);
plougher1f413c82005-11-18 00:02:14 +00001455 }
ploughere6e0e1b2010-05-12 17:17:06 +00001456 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001457 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001458 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001459 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001460 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001461
plougherdf2b9aa2010-12-16 04:56:23 +00001462 byte = readlink(filename, buff, 65536);
1463 if(byte == -1) {
ploughere6e0e1b2010-05-12 17:17:06 +00001464 ERROR("Failed to read symlink %s, creating empty "
1465 "symlink\n", filename);
1466 byte = 0;
1467 }
1468
1469 if(byte == 65536) {
1470 ERROR("Symlink %s is greater than 65536 bytes! "
1471 "Creating empty symlink\n", filename);
1472 byte = 0;
1473 }
1474
1475 inode = get_inode(sizeof(*symlink) + byte +
1476 sizeof(unsigned int));
1477 symlink->nlink = nlink;
1478 symlink->symlink_size = byte;
1479 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1480 strncpy(inode + off, buff, byte);
1481 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1482 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1483 nlink);
1484 }
plougher1f413c82005-11-18 00:02:14 +00001485 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001486 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001487
1488 inode = get_inode(sizeof(*ipc));
1489 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001490 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001491 TRACE("ipc inode, type %s, nlink %d\n", type ==
1492 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001493 }
1494 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001495 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001496
1497 inode = get_inode(sizeof(*ipc));
1498 ipc->nlink = nlink;
1499 ipc->xattr = xattr;
1500 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1501 TRACE("ipc inode, type %s, nlink %d\n", type ==
1502 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001503 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001504 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001505
1506 *i_no = MKINODE(inode);
1507 inode_count ++;
1508
plougherfd57dfe2009-03-30 01:17:52 +00001509 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1510 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001511
1512 return TRUE;
1513}
1514
1515
plougher50b31762009-03-31 04:14:46 +00001516void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1517 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001518{
plougher8cb05cd2005-12-11 23:32:35 +00001519 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001520 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001521 unsigned int start_block = inode >> 16;
1522 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001523 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001524 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001525
plougher43d49082010-12-16 05:01:15 +00001526 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001527 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001528 ERROR("Filename is greater than %d characters, truncating! ..."
1529 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001530 }
1531
plougher9b393552010-12-31 20:55:43 +00001532 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001533 sizeof(struct squashfs_dir_header)
1534 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001535 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1536 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001537 BAD_ERROR("Out of memory reallocating directory buffer"
1538 "\n");
plougher1f413c82005-11-18 00:02:14 +00001539 }
1540
1541 dir->p = (dir->p - dir->buff) + buff;
1542 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001543 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1544 buff);
plougher1f413c82005-11-18 00:02:14 +00001545 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1546 dir->buff = buff;
1547 }
1548
plougherfd57dfe2009-03-30 01:17:52 +00001549 if(dir->entry_count == 256 || start_block != dir->start_block ||
1550 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001551 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001552 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001553 ((long long) inode_number - dir->inode_number) > 32767
1554 || ((long long) inode_number - dir->inode_number)
1555 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001556 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001557 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001558
plougher9b393552010-12-31 20:55:43 +00001559 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001560 dir->index_count_p) >
1561 SQUASHFS_METADATA_SIZE) {
1562 if(dir->i_count % I_COUNT_SIZE == 0) {
1563 dir->index = realloc(dir->index,
1564 (dir->i_count + I_COUNT_SIZE) *
1565 sizeof(struct cached_dir_index));
1566 if(dir->index == NULL)
1567 BAD_ERROR("Out of memory in "
1568 "directory index table "
1569 "reallocation!\n");
1570 }
1571 dir->index[dir->i_count].index.index =
1572 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001573 dir->index[dir->i_count].index.size = size - 1;
1574 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001575 dir->i_size += sizeof(struct squashfs_dir_index)
1576 + size;
plougher1f413c82005-11-18 00:02:14 +00001577 dir->index_count_p = dir->p;
1578 }
1579
1580 dir_header.count = dir->entry_count - 1;
1581 dir_header.start_block = dir->start_block;
1582 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001583 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001584 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001585
1586 }
1587
1588
1589 dir->entry_count_p = dir->p;
1590 dir->start_block = start_block;
1591 dir->entry_count = 0;
1592 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001593 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001594 }
1595
plougher1f413c82005-11-18 00:02:14 +00001596 idir.offset = offset;
1597 idir.type = type;
1598 idir.size = size - 1;
1599 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001600 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1601 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001602 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001603 dir->entry_count ++;
1604}
1605
1606
plougherfd57dfe2009-03-30 01:17:52 +00001607void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1608 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001609{
1610 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001611 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001612 unsigned int directory_block, directory_offset, i_count, index;
1613 unsigned short c_byte;
1614
1615 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001616 int realloc_size = directory_cache_size == 0 ?
1617 ((dir_size + SQUASHFS_METADATA_SIZE) &
1618 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001619
plougher17248ca2010-07-27 00:24:35 +00001620 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001621 directory_cache_size + realloc_size);
plougher17248ca2010-07-27 00:24:35 +00001622 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001623 goto failed;
1624 }
1625 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001626 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001627 }
1628
1629 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001630 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001631
1632 dir_header.count = dir->entry_count - 1;
1633 dir_header.start_block = dir->start_block;
1634 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001635 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001636 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1637 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001638 }
1639 directory_offset = directory_cache_bytes;
1640 directory_block = directory_bytes;
1641 directory_cache_bytes += dir_size;
1642 i_count = 0;
1643 index = SQUASHFS_METADATA_SIZE - directory_offset;
1644
1645 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001646 while(i_count < dir->i_count &&
1647 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001648 dir->index[i_count++].index.start_block =
1649 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001650 index += SQUASHFS_METADATA_SIZE;
1651
1652 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1653 break;
1654
plougherfd57dfe2009-03-30 01:17:52 +00001655 if((directory_size - directory_bytes) <
1656 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001657 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001658 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1659 + 2);
plougher79d665a2010-07-27 00:19:23 +00001660 if(dt == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001661 goto failed;
1662 }
1663 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001664 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001665 }
1666
plougher50b31762009-03-31 04:14:46 +00001667 c_byte = mangle(directory_table + directory_bytes +
1668 BLOCK_OFFSET, directory_data_cache,
1669 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1670 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001671 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1672 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001673 SQUASHFS_SWAP_SHORTS(&c_byte,
1674 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001675 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1676 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001677 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001678 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001679 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1680 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001681 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1682 }
1683
plougher3c6bdb52010-05-01 02:30:59 +00001684 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1685 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1686 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001687
1688#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001689 {
plougher1f413c82005-11-18 00:02:14 +00001690 unsigned char *dirp;
1691 int count;
1692
1693 TRACE("Directory contents of inode 0x%llx\n", *inode);
1694 dirp = dir->buff;
1695 while(dirp < dir->p) {
1696 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001697 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001698 struct squashfs_dir_header dirh;
1699 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001700 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001701 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001702 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001703
plougher50b31762009-03-31 04:14:46 +00001704 TRACE("\tStart block 0x%x, count %d\n",
1705 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001706
1707 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001708 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001709 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001710 strncpy(buffer, idirp->name, idir.size + 1);
1711 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001712 TRACE("\t\tname %s, inode offset 0x%x, type "
1713 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001714 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001715 1;
plougher1f413c82005-11-18 00:02:14 +00001716 }
1717 }
1718 }
1719#endif
1720 dir_count ++;
1721
plougher29e37092007-04-15 01:24:51 +00001722 return;
plougher1f413c82005-11-18 00:02:14 +00001723
1724failed:
1725 BAD_ERROR("Out of memory in directory table reallocation!\n");
1726}
1727
1728
plougher76c64082008-03-08 01:32:23 +00001729struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001730{
plougher8ed84b92010-12-31 10:37:24 +00001731 struct squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001732 int res, size;
plougher76c64082008-03-08 01:32:23 +00001733 long long start_block;
1734 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001735
plougher76c64082008-03-08 01:32:23 +00001736 if(fragment->index == SQUASHFS_INVALID_FRAG)
1737 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001738
plougher76c64082008-03-08 01:32:23 +00001739 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001740 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001741 return buffer;
plougher76c64082008-03-08 01:32:23 +00001742
plougherfd57dfe2009-03-30 01:17:52 +00001743 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1744 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001745
plougher76c64082008-03-08 01:32:23 +00001746 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001747
1748 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001749 disk_fragment = &fragment_table[fragment->index];
1750 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001751 start_block = disk_fragment->start_block;
1752 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001753
plougher0f464442008-03-31 00:27:56 +00001754 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001755 int error;
plougher76c64082008-03-08 01:32:23 +00001756 char *data;
plougher1f413c82005-11-18 00:02:14 +00001757
plougher76c64082008-03-08 01:32:23 +00001758 if(compressed_buffer)
1759 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001760 else
1761 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001762
plougherb48442b2010-12-31 07:57:54 +00001763 res = compressor_uncompress(comp, buffer->data, data, size,
1764 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001765 if(res == -1)
1766 BAD_ERROR("%s uncompress failed with error code %d\n",
1767 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001768 } else if(compressed_buffer)
1769 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001770 else {
1771 res = read_fs_bytes(fd, start_block, size, buffer->data);
1772 if(res == 0)
1773 EXIT_MKSQUASHFS();
1774 }
plougher1f413c82005-11-18 00:02:14 +00001775
plougher03859fa2009-03-31 03:18:18 +00001776 cache_block_put(compressed_buffer);
1777
plougher76c64082008-03-08 01:32:23 +00001778 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001779}
1780
plougher2ea89142008-03-11 01:34:19 +00001781
1782struct frag_locked {
1783 struct file_buffer *buffer;
1784 int c_byte;
1785 int fragment;
1786 struct frag_locked *fragment_prev;
1787 struct frag_locked *fragment_next;
1788};
1789
1790int fragments_locked = FALSE;
1791struct frag_locked *frag_locked_list = NULL;
1792
1793INSERT_LIST(fragment, struct frag_locked)
1794REMOVE_LIST(fragment, struct frag_locked)
1795
plougher4e8484a2008-03-15 23:30:16 +00001796int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001797{
plougher4e8484a2008-03-15 23:30:16 +00001798 int count;
plougher5507dd92006-11-06 00:43:10 +00001799 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001800 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001801 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001802 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001803 return count;
plougher2ea89142008-03-11 01:34:19 +00001804}
1805
1806
1807void unlock_fragments()
1808{
1809 struct frag_locked *entry;
1810 int compressed_size;
1811
1812 pthread_mutex_lock(&fragment_mutex);
1813 while(frag_locked_list) {
1814 entry = frag_locked_list;
1815 remove_fragment_list(&frag_locked_list, entry);
1816 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1817 fragment_table[entry->fragment].size = entry->c_byte;
1818 fragment_table[entry->fragment].start_block = bytes;
1819 entry->buffer->block = bytes;
1820 bytes += compressed_size;
1821 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001822 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001823 TRACE("fragment_locked writing fragment %d, compressed size %d"
1824 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001825 free(entry);
1826 }
1827 fragments_locked = FALSE;
1828 pthread_mutex_unlock(&fragment_mutex);
1829}
1830
1831
plougherb7a66812010-07-21 01:06:59 +00001832void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001833 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001834{
1835 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1836 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001837 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001838 entry->buffer = write_buffer;
1839 entry->c_byte = c_byte;
1840 entry->fragment = fragment;
1841 entry->fragment_prev = entry->fragment_next = NULL;
1842 pthread_mutex_lock(&fragment_mutex);
1843 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001844 pthread_mutex_unlock(&fragment_mutex);
1845}
1846
1847
Phillip Lougher04b7b532011-06-11 02:14:15 +01001848void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001849{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001850 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001851 return;
1852
plougher5507dd92006-11-06 00:43:10 +00001853 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001854 fragment_table[fragment->block].unused = 0;
1855 fragments_outstanding ++;
1856 queue_put(to_frag, fragment);
1857 pthread_mutex_unlock(&fragment_mutex);
1858}
1859
1860
1861struct file_buffer *allocate_fragment()
1862{
1863 struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
1864
1865 pthread_mutex_lock(&fragment_mutex);
1866
plougher5507dd92006-11-06 00:43:10 +00001867 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001868 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001869 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001870 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001871 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001872 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001873 }
plougherfa89c332010-07-27 00:27:15 +00001874 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001875 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001876
1877 fragment->size = 0;
1878 fragment->block = fragments ++;
1879
plougher5507dd92006-11-06 00:43:10 +00001880 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001881
1882 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001883}
1884
ploughereb6eac92008-02-26 01:50:48 +00001885
plougher1f413c82005-11-18 00:02:14 +00001886static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001887struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1888 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001889{
1890 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001891 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001892
plougher5507dd92006-11-06 00:43:10 +00001893 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001894 return &empty_fragment;
1895
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001896 fragment = eval_frag_actions(dir_ent);
1897
1898 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1899 write_fragment(*fragment);
1900 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001901 }
plougher1f413c82005-11-18 00:02:14 +00001902
ploughere7e6e832010-12-16 05:08:06 +00001903 ffrg = malloc(sizeof(struct fragment));
1904 if(ffrg == NULL)
plougher1f413c82005-11-18 00:02:14 +00001905 BAD_ERROR("Out of memory in fragment block allocation!\n");
1906
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001907 if(*fragment == NULL)
1908 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001909
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001910 ffrg->index = (*fragment)->block;
1911 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001912 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001913 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001914 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001915 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001916
1917 return ffrg;
1918}
1919
1920
ploughera0a49c32010-08-11 01:47:59 +00001921long long generic_write_table(int length, void *buffer, int length2,
1922 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001923{
plougher17b269c2009-03-30 01:33:07 +00001924 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1925 SQUASHFS_METADATA_SIZE;
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001926 long long *list, start_bytes;
Phillip Lougherc1305322012-11-02 22:28:02 +00001927 int compressed_size, i, list_size = meta_blocks * sizeof(long long);
plougher1f413c82005-11-18 00:02:14 +00001928 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001929 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1930
plougher82ab2332009-04-21 00:21:21 +00001931#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001932 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001933 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001934#endif
plougher1f413c82005-11-18 00:02:14 +00001935
Phillip Lougherc1305322012-11-02 22:28:02 +00001936 list = malloc(list_size);
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001937 if(list == NULL)
1938 BAD_ERROR("Out of memory in generic_write_table\n");
1939
plougher1f413c82005-11-18 00:02:14 +00001940 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001941 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1942 SQUASHFS_METADATA_SIZE : length;
1943 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1944 SQUASHFS_METADATA_SIZE , avail_bytes,
1945 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001946 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001947 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001948 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1949 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001950 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1951 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001952 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001953 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001954 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001955 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001956 }
1957
ploughere6e0e1b2010-05-12 17:17:06 +00001958 start_bytes = bytes;
1959 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001960 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001961 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001962 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001963 }
1964
plougher1f288f62009-02-21 03:05:52 +00001965 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
Phillip Lougherc1305322012-11-02 22:28:02 +00001966 write_destination(fd, bytes, list_size, list);
1967 bytes += list_size;
1968 total_bytes += list_size;
plougher1f413c82005-11-18 00:02:14 +00001969
plougher40d8b952010-02-12 16:26:32 +00001970 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1971 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001972
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001973 free(list);
1974
plougher1f413c82005-11-18 00:02:14 +00001975 return start_bytes;
1976}
1977
1978
plougher0e453652006-11-06 01:49:35 +00001979long long write_fragment_table()
1980{
1981 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher0e453652006-11-06 01:49:35 +00001982 int i;
1983
plougher17b269c2009-03-30 01:33:07 +00001984 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1985 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001986 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001987 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1988 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001989 fragment_table[i].size);
Phillip Lougher162c24c2012-10-30 02:54:16 +00001990 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
plougher0e453652006-11-06 01:49:35 +00001991 }
1992
Phillip Lougher162c24c2012-10-30 02:54:16 +00001993 return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001994}
1995
1996
plougher1f413c82005-11-18 00:02:14 +00001997char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001998char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001999{
plougher1d065e92010-06-18 03:58:27 +00002000 int res;
2001
2002 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
2003 if(res == 0)
2004 EXIT_MKSQUASHFS();
2005
plougher1f413c82005-11-18 00:02:14 +00002006 return read_from_file_buffer;
2007}
2008
2009
plougher1b899fc2008-08-07 01:24:06 +00002010char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
2011char *read_from_disk2(long long start, unsigned int avail_bytes)
2012{
plougher1d065e92010-06-18 03:58:27 +00002013 int res;
2014
2015 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
2016 if(res == 0)
2017 EXIT_MKSQUASHFS();
2018
plougher1b899fc2008-08-07 01:24:06 +00002019 return read_from_file_buffer2;
2020}
2021
2022
plougher1f413c82005-11-18 00:02:14 +00002023/*
2024 * Compute 16 bit BSD checksum over the data
2025 */
plougher5507dd92006-11-06 00:43:10 +00002026unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00002027{
plougher5507dd92006-11-06 00:43:10 +00002028 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00002029
plougher5507dd92006-11-06 00:43:10 +00002030 while(bytes --) {
2031 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
2032 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00002033 }
2034
2035 return chksum;
2036}
2037
2038
plougher17b269c2009-03-30 01:33:07 +00002039unsigned short get_checksum_disk(long long start, long long l,
2040 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00002041{
2042 unsigned short chksum = 0;
2043 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00002044 struct file_buffer *write_buffer;
2045 int i;
plougher5507dd92006-11-06 00:43:10 +00002046
plougher57e6d182008-05-06 23:51:29 +00002047 for(i = 0; l; i++) {
2048 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2049 if(bytes == 0) /* sparse block */
2050 continue;
2051 write_buffer = cache_lookup(writer_buffer, start);
2052 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002053 chksum = get_checksum(write_buffer->data, bytes,
2054 chksum);
plougher57e6d182008-05-06 23:51:29 +00002055 cache_block_put(write_buffer);
2056 } else
plougher50b31762009-03-31 04:14:46 +00002057 chksum = get_checksum(read_from_disk(start, bytes),
2058 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002059 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002060 start += bytes;
2061 }
2062
2063 return chksum;
2064}
2065
2066
plougher5507dd92006-11-06 00:43:10 +00002067unsigned short get_checksum_mem(char *buff, int bytes)
2068{
2069 return get_checksum(buff, bytes, 0);
2070}
2071
2072
2073unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2074{
2075 if(file_buffer == NULL)
2076 return 0;
2077 else
2078 return get_checksum(file_buffer->data, file_buffer->size, 0);
2079}
2080
2081
plougher5507dd92006-11-06 00:43:10 +00002082#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002083void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002084 unsigned int *block_listp, int blocks, unsigned int fragment,
2085 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002086{
2087 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002088 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002089 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002090
plougher5507dd92006-11-06 00:43:10 +00002091 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002092 return;
2093
plougher5507dd92006-11-06 00:43:10 +00002094 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2095 if(file_size != dupl_ptr->file_size)
2096 continue;
2097 if(blocks != 0 && start != dupl_ptr->start)
2098 continue;
2099 if(fragment != dupl_ptr->fragment->index)
2100 continue;
plougher17b269c2009-03-30 01:33:07 +00002101 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2102 dupl_ptr->fragment->offset || bytes !=
2103 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002104 continue;
2105 return;
2106 }
2107
plougher3bb279c2010-12-16 05:10:03 +00002108 frg = malloc(sizeof(struct fragment));
2109 if(frg == NULL)
plougher1f413c82005-11-18 00:02:14 +00002110 BAD_ERROR("Out of memory in fragment block allocation!\n");
2111
2112 frg->index = fragment;
2113 frg->offset = offset;
2114 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002115
plougher5507dd92006-11-06 00:43:10 +00002116 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2117}
plougher1f413c82005-11-18 00:02:14 +00002118
plougher1f413c82005-11-18 00:02:14 +00002119
plougher5507dd92006-11-06 00:43:10 +00002120int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002121{
plougher5507dd92006-11-06 00:43:10 +00002122 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002123
2124 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002125 if(dupl_ptr->file_size == file_size)
2126 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002127
plougher5507dd92006-11-06 00:43:10 +00002128 return FALSE;
2129}
2130
2131
2132int pre_duplicate_frag(long long file_size, unsigned short checksum)
2133{
2134 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2135
2136 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002137 if(file_size == dupl_ptr->file_size && file_size ==
2138 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002139 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002140 struct file_buffer *frag_buffer =
2141 get_fragment(dupl_ptr->fragment);
2142 dupl_ptr->checksum =
2143 get_checksum_disk(dupl_ptr->start,
2144 dupl_ptr->bytes, dupl_ptr->block_list);
2145 dupl_ptr->fragment_checksum =
2146 get_checksum_mem(frag_buffer->data +
2147 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002148 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002149 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002150 }
plougher5507dd92006-11-06 00:43:10 +00002151 if(dupl_ptr->fragment_checksum == checksum)
2152 return TRUE;
2153 }
plougher1f413c82005-11-18 00:02:14 +00002154
plougher5507dd92006-11-06 00:43:10 +00002155 return FALSE;
2156}
2157
2158
plougher17b269c2009-03-30 01:33:07 +00002159struct file_info *add_non_dup(long long file_size, long long bytes,
2160 unsigned int *block_list, long long start, struct fragment *fragment,
2161 unsigned short checksum, unsigned short fragment_checksum,
2162 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002163{
plougher51ef9ae2010-12-16 05:14:28 +00002164 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00002165
plougher51ef9ae2010-12-16 05:14:28 +00002166 if(dupl_ptr == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002167 BAD_ERROR("Out of memory in dup_files allocation!\n");
2168 }
2169
2170 dupl_ptr->file_size = file_size;
2171 dupl_ptr->bytes = bytes;
2172 dupl_ptr->block_list = block_list;
2173 dupl_ptr->start = start;
2174 dupl_ptr->fragment = fragment;
2175 dupl_ptr->checksum = checksum;
2176 dupl_ptr->fragment_checksum = fragment_checksum;
2177 dupl_ptr->checksum_flag = checksum_flag;
2178 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2179 dupl[DUP_HASH(file_size)] = dupl_ptr;
2180 dup_files ++;
2181
2182 return dupl_ptr;
2183}
2184
2185
plougher17b269c2009-03-30 01:33:07 +00002186struct file_info *duplicate(long long file_size, long long bytes,
2187 unsigned int **block_list, long long *start, struct fragment **fragment,
2188 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2189 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002190{
2191 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2192 int frag_bytes = file_buffer ? file_buffer->size : 0;
2193
2194 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002195 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2196 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002197 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002198 int block;
2199
plougher17b269c2009-03-30 01:33:07 +00002200 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2201 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002202 continue;
2203
plougher5507dd92006-11-06 00:43:10 +00002204 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002205 checksum = get_checksum_disk(*start, bytes,
2206 *block_list);
2207 fragment_checksum =
2208 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002209 checksum_flag = TRUE;
2210 }
2211
2212 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002213 struct file_buffer *frag_buffer =
2214 get_fragment(dupl_ptr->fragment);
2215 dupl_ptr->checksum =
2216 get_checksum_disk(dupl_ptr->start,
2217 dupl_ptr->bytes, dupl_ptr->block_list);
2218 dupl_ptr->fragment_checksum =
2219 get_checksum_mem(frag_buffer->data +
2220 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002221 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002222 dupl_ptr->checksum_flag = TRUE;
2223 }
2224
plougher17b269c2009-03-30 01:33:07 +00002225 if(checksum != dupl_ptr->checksum ||
2226 fragment_checksum !=
2227 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002228 continue;
2229
plougher1b899fc2008-08-07 01:24:06 +00002230 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002231 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002232 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2233 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002234 struct file_buffer *target_buffer = NULL;
2235 struct file_buffer *dup_buffer = NULL;
2236 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002237 int res;
plougher5507dd92006-11-06 00:43:10 +00002238
plougher1b899fc2008-08-07 01:24:06 +00002239 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002240 continue;
plougher17b269c2009-03-30 01:33:07 +00002241 target_buffer = cache_lookup(writer_buffer,
2242 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002243 if(target_buffer)
2244 target_data = target_buffer->data;
2245 else
plougher50b31762009-03-31 04:14:46 +00002246 target_data =
2247 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002248 size);
plougher5507dd92006-11-06 00:43:10 +00002249
plougher360514a2009-03-30 03:01:38 +00002250 dup_buffer = cache_lookup(writer_buffer,
2251 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002252 if(dup_buffer)
2253 dup_data = dup_buffer->data;
2254 else
plougher360514a2009-03-30 03:01:38 +00002255 dup_data = read_from_disk2(dup_start,
2256 size);
plougher1b899fc2008-08-07 01:24:06 +00002257
2258 res = memcmp(target_data, dup_data, size);
2259 cache_block_put(target_buffer);
2260 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002261 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002262 break;
plougher1b899fc2008-08-07 01:24:06 +00002263 target_start += size;
2264 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002265 }
2266 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002267 struct file_buffer *frag_buffer =
2268 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002269
plougher17b269c2009-03-30 01:33:07 +00002270 if(frag_bytes == 0 ||
2271 memcmp(file_buffer->data,
2272 frag_buffer->data +
2273 dupl_ptr->fragment->offset,
2274 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002275 TRACE("Found duplicate file, start "
2276 "0x%llx, size %lld, checksum "
2277 "0x%x, fragment %d, size %d, "
2278 "offset %d, checksum 0x%x\n",
2279 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002280 dupl_ptr->bytes,
2281 dupl_ptr->checksum,
2282 dupl_ptr->fragment->index,
2283 frag_bytes,
2284 dupl_ptr->fragment->offset,
2285 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002286 *block_list = dupl_ptr->block_list;
2287 *start = dupl_ptr->start;
2288 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002289 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002290 return 0;
2291 }
plougher76c64082008-03-08 01:32:23 +00002292 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002293 }
2294 }
2295
2296
plougher17b269c2009-03-30 01:33:07 +00002297 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2298 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002299}
2300
2301
Phillip Lougher2504b082011-09-07 02:28:45 +01002302inline int is_fragment(struct inode_info *inode)
2303{
2304 int file_size = inode->buf.st_size;
2305
Phillip Lougher63f531f2011-09-10 04:03:32 +01002306 /*
2307 * If this block is to be compressed differently to the
2308 * fragment compression then it cannot be a fragment
2309 */
2310 if(inode->noF != noF)
2311 return FALSE;
2312
Phillip Lougher2504b082011-09-07 02:28:45 +01002313 return !inode->no_fragments && (file_size < block_size ||
2314 (inode->always_use_fragments && file_size & (block_size - 1)));
2315}
2316
2317
plougher00d08172009-09-03 10:17:44 +00002318static int seq = 0;
2319void reader_read_process(struct dir_ent *dir_ent)
2320{
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002321 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002322 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002323 int status, res, byte, count = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002324 int file = get_pseudo_file(inode->pseudo_id)->fd;
2325 int child = get_pseudo_file(inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002326 long long bytes = 0;
2327
2328 while(1) {
2329 file_buffer = cache_get(reader_buffer, 0, 0);
2330 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002331 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002332
2333 byte = read_bytes(file, file_buffer->data, block_size);
2334 if(byte == -1)
2335 goto read_err;
2336
2337 file_buffer->size = byte;
2338 file_buffer->file_size = -1;
2339 file_buffer->block = count ++;
2340 file_buffer->error = FALSE;
2341 file_buffer->fragment = FALSE;
2342 bytes += byte;
2343
2344 if(byte == 0)
2345 break;
2346
plougher286b6b32009-09-19 03:29:27 +00002347 /*
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002348 * Update progress bar size. This is done
plougher286b6b32009-09-19 03:29:27 +00002349 * on every block rather than waiting for all blocks to be
2350 * read incase write_file_process() is running in parallel
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002351 * with this. Otherwise the current progress bar position
2352 * may get ahead of the progress bar size.
plougher286b6b32009-09-19 03:29:27 +00002353 */
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002354 progress_bar_size(1);
plougher286b6b32009-09-19 03:29:27 +00002355
plougher00d08172009-09-03 10:17:44 +00002356 if(prev_buffer)
2357 queue_put(from_reader, prev_buffer);
2358 prev_buffer = file_buffer;
2359 }
2360
plougher54d67292009-09-19 03:26:27 +00002361 /*
2362 * Update inode file size now that the size of the dynamic pseudo file
2363 * is known. This is needed for the -info option.
2364 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002365 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002366
plougherba674e82009-09-10 03:50:00 +00002367 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002368 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002369 goto read_err;
2370
plougher00d08172009-09-03 10:17:44 +00002371 if(prev_buffer == NULL)
2372 prev_buffer = file_buffer;
2373 else {
2374 cache_block_put(file_buffer);
2375 seq --;
2376 }
2377 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002378 prev_buffer->fragment = is_fragment(inode);
plougher00d08172009-09-03 10:17:44 +00002379 queue_put(from_reader, prev_buffer);
2380
2381 return;
2382
2383read_err:
2384 if(prev_buffer) {
2385 cache_block_put(file_buffer);
2386 seq --;
2387 file_buffer = prev_buffer;
2388 }
2389 file_buffer->error = TRUE;
2390 queue_put(from_deflate, file_buffer);
2391}
2392
2393
plougher5507dd92006-11-06 00:43:10 +00002394void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002395{
plougher018d2b32007-04-23 03:01:48 +00002396 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002397 struct file_buffer *file_buffer;
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002398 int blocks, byte, count, expected, file, res;
plougher018d2b32007-04-23 03:01:48 +00002399 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002400 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002401
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002402 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002403 return;
2404
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002405 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002406again:
2407 bytes = 0;
2408 count = 0;
2409 file_buffer = NULL;
2410 read_size = buf->st_size;
2411 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002412
Phillip Lougher494479f2012-02-03 15:45:41 +00002413 file = open(pathname_reader(dir_ent), O_RDONLY);
plougherc1d258e2010-12-16 05:16:45 +00002414 if(file == -1) {
plougher1e380702010-08-11 01:52:49 +00002415 file_buffer = cache_get(reader_buffer, 0, 0);
2416 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002417 goto read_err;
plougher1e380702010-08-11 01:52:49 +00002418 }
plougher5507dd92006-11-06 00:43:10 +00002419
plougher018d2b32007-04-23 03:01:48 +00002420 do {
plougher110799c2009-03-30 01:50:40 +00002421 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002422 block_size ? block_size :
2423 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002424
2425 if(file_buffer)
2426 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002427 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002428 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002429 file_buffer->noD = inode->noD;
plougher5507dd92006-11-06 00:43:10 +00002430
ploughera4c24ed2010-08-11 02:08:38 +00002431 /*
2432 * Always try to read block_size bytes from the file rather
2433 * than expected bytes (which will be less than the block_size
2434 * at the file tail) to check that the file hasn't grown
2435 * since being stated. If it is longer (or shorter) than
2436 * expected, then restat, and try again. Note the special
2437 * case where the file is an exact multiple of the block_size
2438 * is dealt with later.
2439 */
plougher110799c2009-03-30 01:50:40 +00002440 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2441 block_size);
plougher018d2b32007-04-23 03:01:48 +00002442
plougher018d2b32007-04-23 03:01:48 +00002443 file_buffer->file_size = read_size;
2444
ploughera4c24ed2010-08-11 02:08:38 +00002445 if(byte == -1)
2446 goto read_err;
2447
plougher018d2b32007-04-23 03:01:48 +00002448 if(byte != expected)
2449 goto restat;
2450
2451 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002452 file_buffer->error = FALSE;
Phillip Lougher2504b082011-09-07 02:28:45 +01002453 file_buffer->fragment = FALSE;
plougher018d2b32007-04-23 03:01:48 +00002454
2455 bytes += byte;
2456 count ++;
2457 } while(count < blocks);
2458
2459 if(read_size != bytes)
2460 goto restat;
2461
2462 if(expected == block_size) {
ploughera4c24ed2010-08-11 02:08:38 +00002463 /*
2464 * Special case where we've not tried to read past the end of
2465 * the file. We expect to get EOF, i.e. the file isn't larger
2466 * than we expect.
2467 */
plougher018d2b32007-04-23 03:01:48 +00002468 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002469 int res;
plougher018d2b32007-04-23 03:01:48 +00002470
ploughera4c24ed2010-08-11 02:08:38 +00002471 res = read_bytes(file, &buffer, 1);
2472 if(res == -1)
2473 goto read_err;
2474
2475 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002476 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002477 }
2478
Phillip Lougher2504b082011-09-07 02:28:45 +01002479 file_buffer->fragment = is_fragment(inode);
plougher1b899fc2008-08-07 01:24:06 +00002480 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002481
plougher5507dd92006-11-06 00:43:10 +00002482 close(file);
plougher5507dd92006-11-06 00:43:10 +00002483
2484 return;
2485
plougher018d2b32007-04-23 03:01:48 +00002486restat:
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002487 res = fstat(file, &buf2);
plougher018d2b32007-04-23 03:01:48 +00002488 close(file);
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002489 if(res == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00002490 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002491 pathname_reader(dir_ent), strerror(errno));
2492 goto read_err;
2493 }
2494
plougher018d2b32007-04-23 03:01:48 +00002495 if(read_size != buf2.st_size) {
2496 memcpy(buf, &buf2, sizeof(struct stat));
2497 file_buffer->error = 2;
2498 queue_put(from_deflate, file_buffer);
2499 goto again;
2500 }
plougher1e380702010-08-11 01:52:49 +00002501read_err:
2502 file_buffer->error = TRUE;
2503 queue_put(from_deflate, file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002504}
2505
2506
2507void reader_scan(struct dir_info *dir) {
Phillip Lougherbf338362012-08-22 05:24:36 +01002508 struct dir_ent *dir_ent = dir->list;
plougher5507dd92006-11-06 00:43:10 +00002509
Phillip Lougherbf338362012-08-22 05:24:36 +01002510 for(; dir_ent; dir_ent = dir_ent->next) {
plougher5507dd92006-11-06 00:43:10 +00002511 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002512 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002513 continue;
2514
plougherb3977eb2010-05-02 02:08:48 +00002515 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002516 reader_read_process(dir_ent);
2517 continue;
2518 }
2519
plougher5507dd92006-11-06 00:43:10 +00002520 switch(buf->st_mode & S_IFMT) {
2521 case S_IFREG:
2522 reader_read_file(dir_ent);
2523 break;
2524 case S_IFDIR:
2525 reader_scan(dir_ent->dir);
2526 break;
2527 }
2528 }
2529}
2530
2531
2532void *reader(void *arg)
2533{
2534 int oldstate;
2535
2536 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2537 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2538
2539 if(!sorted)
2540 reader_scan(queue_get(to_reader));
2541 else {
2542 int i;
2543 struct priority_entry *entry;
2544
2545 queue_get(to_reader);
2546 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002547 for(entry = priority_list[i]; entry;
2548 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002549 reader_read_file(entry->dir);
2550 }
rloughere4873e02007-11-08 17:50:42 +00002551
plougher5aa18162007-12-13 12:15:21 +00002552 thread[0] = 0;
2553
rloughere4873e02007-11-08 17:50:42 +00002554 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002555}
2556
2557
2558void *writer(void *arg)
2559{
2560 int write_error = FALSE;
2561 int oldstate;
2562
2563 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2564 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2565
2566 while(1) {
2567 struct file_buffer *file_buffer = queue_get(to_writer);
2568 off_t off;
2569
2570 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002571 queue_put(from_writer,
plougherc2a5ae12010-12-31 08:35:28 +00002572 write_error ? &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002573 continue;
2574 }
2575
2576 off = file_buffer->block;
2577
2578 pthread_mutex_lock(&pos_mutex);
2579
2580 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002581 ERROR("Lseek on destination failed because %s\n",
2582 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002583 write_error = TRUE;
2584 }
2585
plougher110799c2009-03-30 01:50:40 +00002586 if(!write_error && write_bytes(fd, file_buffer->data,
2587 file_buffer->size) == -1) {
2588 ERROR("Write on destination failed because %s\n",
2589 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002590 write_error = TRUE;
2591 }
2592 pthread_mutex_unlock(&pos_mutex);
2593
ploughereb6eac92008-02-26 01:50:48 +00002594 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002595 }
2596}
2597
2598
plougher5b09fd42007-08-06 10:28:41 +00002599int all_zero(struct file_buffer *file_buffer)
2600{
2601 int i;
2602 long entries = file_buffer->size / sizeof(long);
2603 long *p = (long *) file_buffer->data;
2604
2605 for(i = 0; i < entries && p[i] == 0; i++);
2606
2607 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002608 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002609 i < file_buffer->size && file_buffer->data[i] == 0;
2610 i++);
plougher5b09fd42007-08-06 10:28:41 +00002611
2612 return i == file_buffer->size;
2613 }
2614
2615 return 0;
2616}
2617
2618
plougher5507dd92006-11-06 00:43:10 +00002619void *deflator(void *arg)
2620{
plougher7b8ee502009-07-29 07:54:30 +00002621 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002622 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002623
2624 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2625 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2626
plougher13fdddf2010-11-24 01:23:41 +00002627 res = compressor_init(comp, &stream, block_size, 1);
2628 if(res)
2629 BAD_ERROR("deflator:: compressor_init failed\n");
2630
plougher5507dd92006-11-06 00:43:10 +00002631 while(1) {
2632 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002633 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002634
Phillip Lougher48854382011-09-09 03:36:55 +01002635 if(file_buffer->file_size == 0) {
2636 file_buffer->c_byte = 0;
2637 queue_put(from_deflate, file_buffer);
2638 } else if(sparse_files && all_zero(file_buffer)) {
plougher1b899fc2008-08-07 01:24:06 +00002639 file_buffer->c_byte = 0;
2640 queue_put(from_deflate, file_buffer);
2641 } else if(file_buffer->fragment) {
2642 file_buffer->c_byte = file_buffer->size;
2643 queue_put(from_deflate, file_buffer);
2644 } else {
2645 write_buffer = cache_get(writer_buffer, 0, 0);
plougher13fdddf2010-11-24 01:23:41 +00002646 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002647 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002648 file_buffer->size, block_size,
2649 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002650 write_buffer->sequence = file_buffer->sequence;
2651 write_buffer->file_size = file_buffer->file_size;
2652 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002653 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2654 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002655 write_buffer->fragment = FALSE;
2656 write_buffer->error = FALSE;
2657 cache_block_put(file_buffer);
2658 queue_put(from_deflate, write_buffer);
2659 }
plougher5507dd92006-11-06 00:43:10 +00002660 }
2661}
2662
2663
2664void *frag_deflator(void *arg)
2665{
plougher7b8ee502009-07-29 07:54:30 +00002666 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002667 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002668
2669 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2670 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2671
plougher13fdddf2010-11-24 01:23:41 +00002672 res = compressor_init(comp, &stream, block_size, 1);
2673 if(res)
2674 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2675
plougher5507dd92006-11-06 00:43:10 +00002676 while(1) {
2677 int c_byte, compressed_size;
2678 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002679 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002680 cache_get(writer_buffer, file_buffer->block +
2681 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002682
plougher13fdddf2010-11-24 01:23:41 +00002683 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002684 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002685 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002686 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002687 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002688 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002689 fragment_table[file_buffer->block].size = c_byte;
2690 fragment_table[file_buffer->block].start_block = bytes;
2691 write_buffer->block = bytes;
2692 bytes += compressed_size;
2693 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002694 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002695 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002696 TRACE("Writing fragment %lld, uncompressed size %d, "
2697 "compressed size %d\n", file_buffer->block,
2698 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002699 } else {
2700 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002701 add_pending_fragment(write_buffer, c_byte,
2702 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002703 }
ploughereb6eac92008-02-26 01:50:48 +00002704 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002705 }
2706}
2707
2708
2709#define HASH_ENTRIES 256
2710#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2711struct file_buffer *block_hash[HASH_ENTRIES];
2712
2713void push_buffer(struct file_buffer *file_buffer)
2714{
plougher0f464442008-03-31 00:27:56 +00002715 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002716
2717 file_buffer->next = block_hash[hash];
2718 block_hash[hash] = file_buffer;
2719}
2720
2721
2722struct file_buffer *get_file_buffer(struct queue *queue)
2723{
plougher0f464442008-03-31 00:27:56 +00002724 static unsigned int sequence = 0;
2725 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002726 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2727
2728 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002729 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002730 break;
2731
2732 if(file_buffer) {
2733 if(prev)
2734 prev->next = file_buffer->next;
2735 else
2736 block_hash[hash] = file_buffer->next;
2737 } else {
2738 while(1) {
2739 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002740 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002741 break;
2742 push_buffer(file_buffer);
2743 }
2744 }
2745
plougher0f464442008-03-31 00:27:56 +00002746 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002747
2748 return file_buffer;
2749}
2750
2751
plougher110799c2009-03-30 01:50:40 +00002752void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2753 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002754{
2755 file_count ++;
2756 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002757 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2758 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002759}
2760
2761
plougher50b31762009-03-31 04:14:46 +00002762void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2763 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002764 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002765{
plougher5507dd92006-11-06 00:43:10 +00002766 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002767 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002768 unsigned int *block_listp = NULL;
2769 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002770
plougher50b31762009-03-31 04:14:46 +00002771 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2772 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002773
plougher5507dd92006-11-06 00:43:10 +00002774 if(dupl_ptr) {
2775 *duplicate_file = FALSE;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002776 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002777 dupl_ptr->fragment = fragment;
2778 } else
2779 *duplicate_file = TRUE;
2780
ploughereb6eac92008-02-26 01:50:48 +00002781 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002782
2783 total_bytes += size;
2784 file_count ++;
2785
plougher35a10602008-04-21 02:58:16 +00002786 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002787
plougherc1ace522010-05-01 03:00:45 +00002788 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002789 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002790}
2791
2792
plougher110799c2009-03-30 01:50:40 +00002793void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2794 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002795{
2796 struct fragment *fragment;
2797 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002798
2799 checksum = get_checksum_mem_buffer(file_buffer);
2800
plougher29e37092007-04-15 01:24:51 +00002801 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002802 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2803 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002804 return;
2805 }
plougher5507dd92006-11-06 00:43:10 +00002806
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002807 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002808
ploughereb6eac92008-02-26 01:50:48 +00002809 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002810
2811 if(duplicate_checking)
2812 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2813
2814 total_bytes += size;
2815 file_count ++;
2816
2817 *duplicate_file = FALSE;
2818
plougher35a10602008-04-21 02:58:16 +00002819 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002820
plougherc1ace522010-05-01 03:00:45 +00002821 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002822 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002823
plougher018d2b32007-04-23 03:01:48 +00002824 return;
plougher5507dd92006-11-06 00:43:10 +00002825}
2826
2827
plougher00d08172009-09-03 10:17:44 +00002828int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2829 struct file_buffer *read_buffer, int *duplicate_file)
2830{
2831 long long read_size, file_bytes, start;
2832 struct fragment *fragment;
2833 unsigned int *block_list = NULL;
2834 int block = 0, status;
2835 long long sparse = 0;
2836 struct file_buffer *fragment_buffer = NULL;
2837
2838 *duplicate_file = FALSE;
2839
2840 lock_fragments();
2841
2842 file_bytes = 0;
2843 start = bytes;
2844 while (1) {
2845 read_size = read_buffer->file_size;
2846 if(read_buffer->fragment && read_buffer->c_byte)
2847 fragment_buffer = read_buffer;
2848 else {
2849 block_list = realloc(block_list, (block + 1) *
2850 sizeof(unsigned int));
2851 if(block_list == NULL)
2852 BAD_ERROR("Out of memory allocating block_list"
2853 "\n");
2854 block_list[block ++] = read_buffer->c_byte;
2855 if(read_buffer->c_byte) {
2856 read_buffer->block = bytes;
2857 bytes += read_buffer->size;
2858 cache_rehash(read_buffer, read_buffer->block);
2859 file_bytes += read_buffer->size;
2860 queue_put(to_writer, read_buffer);
2861 } else {
2862 sparse += read_buffer->size;
2863 cache_block_put(read_buffer);
2864 }
2865 }
plougher286b6b32009-09-19 03:29:27 +00002866 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002867
2868 if(read_size != -1)
2869 break;
2870
2871 read_buffer = get_file_buffer(from_deflate);
2872 if(read_buffer->error)
2873 goto read_err;
2874 }
2875
2876 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002877 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002878 cache_block_put(fragment_buffer);
2879
2880 if(duplicate_checking)
2881 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2882 0, 0, FALSE);
2883 file_count ++;
2884 total_bytes += read_size;
2885
plougherc1ace522010-05-01 03:00:45 +00002886 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2887 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002888
2889 if(duplicate_checking == FALSE)
2890 free(block_list);
2891
2892 return 0;
2893
2894read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002895 dec_progress_bar(block);
plougher00d08172009-09-03 10:17:44 +00002896 status = read_buffer->error;
2897 bytes = start;
2898 if(!block_device) {
2899 int res;
2900
2901 queue_put(to_writer, NULL);
2902 if(queue_get(from_writer) != 0)
2903 EXIT_MKSQUASHFS();
2904 res = ftruncate(fd, bytes);
2905 if(res != 0)
2906 BAD_ERROR("Failed to truncate dest file because %s\n",
2907 strerror(errno));
2908 }
2909 unlock_fragments();
2910 free(block_list);
2911 cache_block_put(read_buffer);
2912 return status;
2913}
2914
2915
plougher110799c2009-03-30 01:50:40 +00002916int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002917 long long read_size, struct file_buffer *read_buffer,
2918 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002919{
plougher23377982007-11-12 04:04:48 +00002920 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002921 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002922 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002923 int block, status;
2924 int blocks = (read_size + block_size - 1) >> block_log;
2925 long long sparse = 0;
2926 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002927
plougher29e37092007-04-15 01:24:51 +00002928 *duplicate_file = FALSE;
2929
plougher87139622010-12-16 05:19:30 +00002930 block_list = malloc(blocks * sizeof(unsigned int));
2931 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00002932 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002933
plougher2ea89142008-03-11 01:34:19 +00002934 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002935
plougher5507dd92006-11-06 00:43:10 +00002936 file_bytes = 0;
2937 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002938 for(block = 0; block < blocks;) {
2939 if(read_buffer->fragment && read_buffer->c_byte) {
2940 fragment_buffer = read_buffer;
2941 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002942 } else {
plougher1b899fc2008-08-07 01:24:06 +00002943 block_list[block] = read_buffer->c_byte;
2944 if(read_buffer->c_byte) {
2945 read_buffer->block = bytes;
2946 bytes += read_buffer->size;
2947 cache_rehash(read_buffer, read_buffer->block);
2948 file_bytes += read_buffer->size;
2949 queue_put(to_writer, read_buffer);
2950 } else {
2951 sparse += read_buffer->size;
2952 cache_block_put(read_buffer);
2953 }
2954 }
2955 inc_progress_bar();
2956
2957 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002958 read_buffer = get_file_buffer(from_deflate);
2959 if(read_buffer->error)
2960 goto read_err;
2961 }
plougher1f413c82005-11-18 00:02:14 +00002962 }
2963
plougher2ea89142008-03-11 01:34:19 +00002964 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002965 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher1b899fc2008-08-07 01:24:06 +00002966 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002967
plougher1f413c82005-11-18 00:02:14 +00002968 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00002969 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2970 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002971 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002972 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002973
plougher360514a2009-03-30 03:01:38 +00002974 /*
2975 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002976 * a smaller block count on stat calls to sparse files. This is
2977 * to ensure intelligent applications like cp correctly handle the
2978 * file as a sparse file. If the file in the original filesystem isn't
2979 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002980 * report it as non-sparse on stat calls to preserve semantics
2981 */
plougher1b899fc2008-08-07 01:24:06 +00002982 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2983 sparse = 0;
2984
plougherc1ace522010-05-01 03:00:45 +00002985 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2986 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002987
plougher5507dd92006-11-06 00:43:10 +00002988 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002989 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002990
plougher018d2b32007-04-23 03:01:48 +00002991 return 0;
plougher1f413c82005-11-18 00:02:14 +00002992
2993read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002994 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00002995 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002996 bytes = start;
2997 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00002998 int res;
2999
plougher5507dd92006-11-06 00:43:10 +00003000 queue_put(to_writer, NULL);
3001 if(queue_get(from_writer) != 0)
3002 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003003 res = ftruncate(fd, bytes);
3004 if(res != 0)
3005 BAD_ERROR("Failed to truncate dest file because %s\n",
3006 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003007 }
plougher2ea89142008-03-11 01:34:19 +00003008 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003009 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003010 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003011 return status;
plougher1f413c82005-11-18 00:02:14 +00003012}
3013
3014
plougher110799c2009-03-30 01:50:40 +00003015int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003016 long long read_size, struct file_buffer *read_buffer,
3017 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003018{
plougher29e37092007-04-15 01:24:51 +00003019 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003020 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003021 struct fragment *fragment;
3022 struct file_info *dupl_ptr;
3023 int blocks = (read_size + block_size - 1) >> block_log;
3024 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003025 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003026 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003027 long long sparse = 0;
3028 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003029
plougher50b31762009-03-31 04:14:46 +00003030 block_list = malloc(blocks * sizeof(unsigned int));
3031 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003032 BAD_ERROR("Out of memory allocating block_list\n");
3033 block_listp = block_list;
3034
plougher50b31762009-03-31 04:14:46 +00003035 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3036 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00003037 BAD_ERROR("Out of memory allocating file block list\n");
3038
plougher4e8484a2008-03-15 23:30:16 +00003039 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003040
3041 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003042 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003043 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3044 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003045
3046 for(block = 0; block < blocks;) {
3047 if(read_buffer->fragment && read_buffer->c_byte) {
3048 fragment_buffer = read_buffer;
3049 blocks = read_size >> block_log;
3050 } else {
3051 block_list[block] = read_buffer->c_byte;
3052
3053 if(read_buffer->c_byte) {
3054 read_buffer->block = bytes;
3055 bytes += read_buffer->size;
3056 file_bytes += read_buffer->size;
3057 cache_rehash(read_buffer, read_buffer->block);
3058 if(block < thresh) {
3059 buffer_list[block] = NULL;
3060 queue_put(to_writer, read_buffer);
3061 } else
3062 buffer_list[block] = read_buffer;
3063 } else {
3064 buffer_list[block] = NULL;
3065 sparse += read_buffer->size;
3066 cache_block_put(read_buffer);
3067 }
3068 }
3069 inc_progress_bar();
3070
3071 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003072 read_buffer = get_file_buffer(from_deflate);
3073 if(read_buffer->error)
3074 goto read_err;
3075 }
plougher5507dd92006-11-06 00:43:10 +00003076 }
3077
plougher110799c2009-03-30 01:50:40 +00003078 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3079 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003080
3081 if(dupl_ptr) {
3082 *duplicate_file = FALSE;
3083 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003084 if(buffer_list[block])
3085 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003086 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00003087 dupl_ptr->fragment = fragment;
3088 } else {
3089 *duplicate_file = TRUE;
3090 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003091 cache_block_put(buffer_list[block]);
3092 bytes = start;
3093 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003094 int res;
3095
plougher1b899fc2008-08-07 01:24:06 +00003096 queue_put(to_writer, NULL);
3097 if(queue_get(from_writer) != 0)
3098 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003099 res = ftruncate(fd, bytes);
3100 if(res != 0)
3101 BAD_ERROR("Failed to truncate dest file because"
3102 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003103 }
plougher5507dd92006-11-06 00:43:10 +00003104 }
3105
plougher2ea89142008-03-11 01:34:19 +00003106 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003107 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003108 free(buffer_list);
3109 file_count ++;
3110 total_bytes += read_size;
3111
plougher360514a2009-03-30 03:01:38 +00003112 /*
3113 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003114 * a smaller block count on stat calls to sparse files. This is
3115 * to ensure intelligent applications like cp correctly handle the
3116 * file as a sparse file. If the file in the original filesystem isn't
3117 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003118 * report it as non-sparse on stat calls to preserve semantics
3119 */
plougher1b899fc2008-08-07 01:24:06 +00003120 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3121 sparse = 0;
3122
plougherc1ace522010-05-01 03:00:45 +00003123 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3124 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003125
plougher5507dd92006-11-06 00:43:10 +00003126 if(*duplicate_file == TRUE)
3127 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003128
plougher018d2b32007-04-23 03:01:48 +00003129 return 0;
plougher5507dd92006-11-06 00:43:10 +00003130
3131read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003132 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00003133 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003134 bytes = start;
3135 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003136 int res;
3137
plougher5507dd92006-11-06 00:43:10 +00003138 queue_put(to_writer, NULL);
3139 if(queue_get(from_writer) != 0)
3140 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003141 res = ftruncate(fd, bytes);
3142 if(res != 0)
3143 BAD_ERROR("Failed to truncate dest file because %s\n",
3144 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003145 }
plougher2ea89142008-03-11 01:34:19 +00003146 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003147 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003148 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003149 free(buffer_list);
3150 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003151 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003152 return status;
plougher5507dd92006-11-06 00:43:10 +00003153}
3154
3155
plougher110799c2009-03-30 01:50:40 +00003156void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3157 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003158{
plougher018d2b32007-04-23 03:01:48 +00003159 int status;
3160 struct file_buffer *read_buffer;
3161 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003162
plougher018d2b32007-04-23 03:01:48 +00003163again:
3164 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003165
plougher23377982007-11-12 04:04:48 +00003166 status = read_buffer->error;
3167 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003168 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003169 goto file_err;
3170 }
3171
3172 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003173
plougher00d08172009-09-03 10:17:44 +00003174 if(read_size == -1)
3175 status = write_file_process(inode, dir_ent, read_buffer,
3176 duplicate_file);
3177 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003178 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003179 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003180 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003181 write_file_frag(inode, dir_ent, read_size, read_buffer,
3182 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003183 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003184 status = write_file_blocks_dup(inode, dir_ent, read_size,
3185 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003186 else
plougher50b31762009-03-31 04:14:46 +00003187 status = write_file_blocks(inode, dir_ent, read_size,
3188 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003189
plougher018d2b32007-04-23 03:01:48 +00003190file_err:
3191 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003192 ERROR("File %s changed size while reading filesystem, "
Phillip Lougher494479f2012-02-03 15:45:41 +00003193 "attempting to re-read\n", pathname(dir_ent));
plougher018d2b32007-04-23 03:01:48 +00003194 goto again;
3195 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003196 ERROR("Failed to read file %s, creating empty file\n",
Phillip Lougher494479f2012-02-03 15:45:41 +00003197 pathname(dir_ent));
plougher29e37092007-04-15 01:24:51 +00003198 write_file_empty(inode, dir_ent, duplicate_file);
3199 }
plougher5507dd92006-11-06 00:43:10 +00003200}
3201
3202
Phillip Lougher3f81a772012-12-04 05:07:24 +00003203#define BUFF_SIZE 512
plougher1f413c82005-11-18 00:02:14 +00003204char *name;
3205char *basename_r();
3206
3207char *getbase(char *pathname)
3208{
Phillip Lougher3f81a772012-12-04 05:07:24 +00003209 static char *b_buffer = NULL;
3210 static int b_size = BUFF_SIZE;
plougher1f413c82005-11-18 00:02:14 +00003211 char *result;
3212
Phillip Lougher3f81a772012-12-04 05:07:24 +00003213 if(b_buffer == NULL) {
3214 b_buffer = malloc(b_size);
3215 if(b_buffer == NULL)
3216 BAD_ERROR("Malloc failed in getbase\n");
3217 }
3218
3219 while(1) {
3220 if(*pathname != '/') {
3221 result = getcwd(b_buffer, b_size);
3222 if(result == NULL && errno != ERANGE)
3223 BAD_ERROR("Getcwd failed in getbase\n");
3224
3225 /* enough room for pathname + "/" + '\0' terminator? */
3226 if(result && strlen(pathname) + 2 <=
3227 b_size - strlen(b_buffer)) {
3228 strcat(strcat(b_buffer, "/"), pathname);
3229 break;
3230 }
3231 } else if(strlen(pathname) < b_size) {
3232 strcpy(b_buffer, pathname);
3233 break;
3234 }
3235
3236 /* Buffer not large enough, realloc and try again */
3237 b_buffer = realloc(b_buffer, b_size += BUFF_SIZE);
3238 if(b_buffer == NULL)
3239 BAD_ERROR("Realloc failed in getbase\n");
3240 }
3241
plougher1f413c82005-11-18 00:02:14 +00003242 name = b_buffer;
3243 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3244 return NULL;
3245 else
3246 return result;
3247}
3248
3249
3250char *basename_r()
3251{
3252 char *s;
3253 char *p;
3254 int n = 1;
3255
3256 for(;;) {
3257 s = name;
3258 if(*name == '\0')
3259 return NULL;
3260 if(*name != '/') {
3261 while(*name != '\0' && *name != '/') name++;
3262 n = name - s;
3263 }
3264 while(*name == '/') name++;
3265 if(strncmp(s, ".", n) == 0)
3266 continue;
plougher110799c2009-03-30 01:50:40 +00003267 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3268 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003269 s[n] = '\0';
3270 return s;
3271 }
3272 if(strcmp(p, "..") == 0)
3273 continue;
3274 return p;
3275 }
3276}
3277
3278
Phillip Lougher81204c22012-07-25 03:30:30 +01003279struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
plougher1f413c82005-11-18 00:02:14 +00003280{
Phillip Lougherd6577802012-10-04 19:14:33 +01003281 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3282 struct inode_info *inode;
plougher1f413c82005-11-18 00:02:14 +00003283
Phillip Lougherd6577802012-10-04 19:14:33 +01003284 /*
3285 * Look-up inode in hash table, if it already exists we have a
3286 * hard-link, so increment the nlink count and return it.
3287 * Don't do the look-up for directories because we don't hard-link
3288 * directories.
3289 */
3290 if ((buf->st_mode & S_IFMT) != S_IFDIR) {
3291 for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
3292 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3293 inode->nlink ++;
3294 return inode;
3295 }
plougher1f413c82005-11-18 00:02:14 +00003296 }
plougher1f413c82005-11-18 00:02:14 +00003297 }
3298
plougher288f6852010-12-16 05:22:55 +00003299 inode = malloc(sizeof(struct inode_info));
3300 if(inode == NULL)
plougher50b31762009-03-31 04:14:46 +00003301 BAD_ERROR("Out of memory in inode hash table entry allocation"
3302 "\n");
plougher1f413c82005-11-18 00:02:14 +00003303
3304 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003305 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003306 inode->root_entry = FALSE;
Phillip Lougher81204c22012-07-25 03:30:30 +01003307 inode->pseudo_file = pseudo;
3308 inode->pseudo_id = id;
plougher1f413c82005-11-18 00:02:14 +00003309 inode->inode = SQUASHFS_INVALID_BLK;
3310 inode->nlink = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003311 inode->inode_number = 0;
plougherdc86c3c2007-12-05 02:15:10 +00003312
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003313 /*
3314 * Copy filesystem wide defaults into inode, these filesystem
3315 * wide defaults may be altered on an individual inode basis by
3316 * user specified actions
3317 *
3318 */
3319 inode->no_fragments = no_fragments;
3320 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003321 inode->noD = noD;
3322 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003323
plougherdc86c3c2007-12-05 02:15:10 +00003324 if((buf->st_mode & S_IFMT) == S_IFREG)
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003325 progress_bar_size((buf->st_size + block_size - 1) >> block_log);
plougherdc86c3c2007-12-05 02:15:10 +00003326
Phillip Lougherd6577802012-10-04 19:14:33 +01003327 inode->next = inode_info[ino_hash];
3328 inode_info[ino_hash] = inode;
plougher1f413c82005-11-18 00:02:14 +00003329
3330 return inode;
3331}
3332
3333
Phillip Lougher81204c22012-07-25 03:30:30 +01003334inline struct inode_info *lookup_inode(struct stat *buf)
3335{
3336 return lookup_inode2(buf, 0, 0);
3337}
3338
3339
Phillip Lougher539c2b12012-07-30 20:14:52 +01003340inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3341{
3342 if (inode->inode_number == 0)
3343 inode->inode_number = use_this ? : inode_no ++;
3344}
3345
3346
Phillip Lougher494479f2012-02-03 15:45:41 +00003347inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3348 char *nonstandard_pathname, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003349{
Phillip Lougher494479f2012-02-03 15:45:41 +00003350 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3351 if(dir_ent == NULL)
3352 BAD_ERROR("Out of memory in linux_opendir\n");
3353
3354 dir_ent->name = name;
3355 dir_ent->source_name = source_name;
3356 dir_ent->nonstandard_pathname = nonstandard_pathname;
3357 dir_ent->our_dir = dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003358 dir_ent->next = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003359
3360 return dir_ent;
3361}
3362
3363
3364inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3365 struct inode_info *inode_info)
3366{
3367 struct dir_info *dir = dir_ent->our_dir;
3368
plougher1f413c82005-11-18 00:02:14 +00003369 if(sub_dir)
Phillip Lougher494479f2012-02-03 15:45:41 +00003370 sub_dir->dir_ent = dir_ent;
3371 dir_ent->inode = inode_info;
3372 dir_ent->dir = sub_dir;
3373
Phillip Lougherbf338362012-08-22 05:24:36 +01003374 dir_ent->next = dir->list;
3375 dir->list = dir_ent;
3376 dir->count++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003377}
3378
3379
3380inline void add_dir_entry2(char *name, char *source_name,
3381 char *nonstandard_pathname, struct dir_info *sub_dir,
3382 struct inode_info *inode_info, struct dir_info *dir)
3383{
3384 struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3385 nonstandard_pathname, dir);
3386
3387
3388 add_dir_entry(dir_ent, sub_dir, inode_info);
plougher1f413c82005-11-18 00:02:14 +00003389}
3390
3391
Phillip Lougher10a4b572012-02-18 23:26:10 +00003392inline void free_dir_entry(struct dir_ent *dir_ent)
3393{
Phillip Loughereb92b192012-10-01 03:39:00 +01003394 if(dir_ent->name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003395 free(dir_ent->name);
3396
Phillip Loughereb92b192012-10-01 03:39:00 +01003397 if(dir_ent->source_name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003398 free(dir_ent->source_name);
3399
3400 free(dir_ent);
3401}
3402
3403
Phillip Lougherad0f9212011-12-31 00:55:51 +00003404inline void add_excluded(struct dir_info *dir)
3405{
3406 dir->excluded ++;
3407}
3408
3409
plougher1f413c82005-11-18 00:02:14 +00003410
Phillip Lougherabc3b492012-07-29 02:53:35 +01003411void dir_scan(squashfs_inode *inode, char *pathname,
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00003412 struct dir_ent *(_readdir)(struct dir_info *))
Phillip Lougherabc3b492012-07-29 02:53:35 +01003413{
3414 struct stat buf;
3415 struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
3416 struct dir_ent *dir_ent;
3417
3418 if(dir_info == NULL)
3419 return;
3420
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003421 /*
3422 * Process most actions and any pseudo files
3423 */
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00003424 if(actions() || get_pseudo())
3425 dir_scan2(dir_info, get_pseudo());
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003426
Phillip Loughere92cb512012-11-15 02:22:28 +00003427 /*
3428 * Process move actions
3429 */
3430 if(move_actions()) {
3431 dir_scan3(dir_info, dir_info);
3432 do_move_actions();
3433 }
3434
Phillip Lougher71ae14e2012-11-15 02:27:50 +00003435 /*
3436 * Process empty actions
3437 */
3438 if(empty_actions())
3439 dir_scan4(dir_info);
3440
Phillip Loughereb69dad2012-11-15 03:34:02 +00003441 /*
3442 * Sort directories and compute the inode numbers
3443 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003444 dir_scan5(dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003445
Phillip Lougherd0fe1d52012-10-09 03:34:34 +01003446 dir_ent = create_dir_entry("", NULL, pathname,
Phillip Lougher1eae83d2012-09-26 02:12:45 +01003447 scan1_opendir("", "", 0));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003448
3449 if(pathname[0] == '\0') {
3450 /*
3451 * dummy top level directory, if multiple sources specified on
3452 * command line
3453 */
3454 memset(&buf, 0, sizeof(buf));
3455 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3456 buf.st_uid = getuid();
3457 buf.st_gid = getgid();
3458 buf.st_mtime = time(NULL);
3459 buf.st_dev = 0;
3460 buf.st_ino = 0;
3461 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3462 } else {
Phillip Lougher38a35ec2012-11-30 04:31:35 +00003463 if(lstat(pathname, &buf) == -1)
3464 /* source directory has disappeared? */
Phillip Lougherfe58b492012-12-15 01:27:07 +00003465 BAD_ERROR("Cannot stat source directory %s because %s\n",
Phillip Lougherabc3b492012-07-29 02:53:35 +01003466 pathname, strerror(errno));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003467 dir_ent->inode = lookup_inode(&buf);
3468 }
3469
Phillip Lougher539c2b12012-07-30 20:14:52 +01003470 alloc_inode_no(dir_ent->inode, root_inode_number);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003471 dir_ent->dir = dir_info;
3472 dir_info->dir_ent = dir_ent;
3473
Andy Lutomirski3f31dcf2012-09-21 18:08:08 -07003474 eval_actions(dir_ent);
3475
Phillip Lougherabc3b492012-07-29 02:53:35 +01003476 if(sorted) {
3477 int res = generate_file_priorities(dir_info, 0,
3478 &dir_info->dir_ent->inode->buf);
3479
3480 if(res == FALSE)
3481 BAD_ERROR("generate_file_priorities failed\n");
3482 }
3483 queue_put(to_reader, dir_info);
3484 if(sorted)
3485 sort_files_and_write(dir_info);
3486 if(progress)
3487 enable_progress_bar();
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003488 dir_scan6(inode, dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003489 dir_ent->inode->inode = *inode;
3490 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003491}
3492
3493
Phillip Lougherabc3b492012-07-29 02:53:35 +01003494/*
3495 * dir_scan1 routines...
Phillip Loughere8630be2012-11-11 02:24:24 +00003496 * These scan the source directories into memory for processing.
3497 * Exclude actions are processed here (in contrast to the other actions)
3498 * because they affect what is scanned.
Phillip Lougherabc3b492012-07-29 02:53:35 +01003499 */
Phillip Lougherb38c1722012-02-09 23:26:19 +00003500struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
plougher1f413c82005-11-18 00:02:14 +00003501{
plougher1f413c82005-11-18 00:02:14 +00003502 struct dir_info *dir;
3503
plougher6da792b2010-12-16 05:25:39 +00003504 dir = malloc(sizeof(struct dir_info));
3505 if(dir == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003506 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003507
3508 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3509 free(dir);
3510 return NULL;
3511 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003512 dir->pathname = pathname;
Phillip Lougherb38c1722012-02-09 23:26:19 +00003513 dir->subpath = subpath;
Phillip Lougherded70fa2011-12-25 02:14:58 +00003514 dir->count = 0;
3515 dir->directory_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003516 dir->dir_is_ldir = TRUE;
3517 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003518 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003519 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003520
3521 return dir;
3522}
3523
3524
Phillip Lougher494479f2012-02-03 15:45:41 +00003525struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003526{
plougher1f413c82005-11-18 00:02:14 +00003527 static int index = 0;
3528
plougher11266ba2010-12-16 05:34:30 +00003529 if(dir->count < old_root_entries) {
3530 int i;
3531
plougher1f413c82005-11-18 00:02:14 +00003532 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003533 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003534 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003535 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003536 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003537 }
plougher11266ba2010-12-16 05:34:30 +00003538 }
plougher1f413c82005-11-18 00:02:14 +00003539
3540 while(index < source) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003541 char *basename = NULL;
3542 char *dir_name = getbase(source_path[index]);
Phillip Lougherbf338362012-08-22 05:24:36 +01003543 int pass = 1, res;
plougher89fe2c72010-12-16 05:31:34 +00003544
Phillip Lougherc73ed322012-10-01 03:25:41 +01003545 if(dir_name == NULL) {
plougher110799c2009-03-30 01:50:40 +00003546 ERROR("Bad source directory %s - skipping ...\n",
3547 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003548 index ++;
3549 continue;
3550 }
Phillip Lougherc73ed322012-10-01 03:25:41 +01003551 dir_name = strdup(dir_name);
plougher1f413c82005-11-18 00:02:14 +00003552 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003553 struct dir_ent *dir_ent = dir->list;
3554
3555 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3556 dir_ent = dir_ent->next);
3557 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003558 break;
plougher50b31762009-03-31 04:14:46 +00003559 ERROR("Source directory entry %s already used! - trying"
3560 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003561 if(pass == 1)
3562 basename = dir_name;
3563 else
Phillip Lougherb38c1722012-02-09 23:26:19 +00003564 free(dir_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003565 res = asprintf(&dir_name, "%s_%d", basename, pass++);
3566 if(res == -1)
3567 BAD_ERROR("asprintf failed in "
3568 "scan1_encomp_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003569 ERROR("%s\n", dir_name);
3570 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00003571 return create_dir_entry(dir_name, basename,
3572 source_path[index ++], dir);
plougher1f413c82005-11-18 00:02:14 +00003573 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003574 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003575}
3576
3577
Phillip Lougher494479f2012-02-03 15:45:41 +00003578struct dir_ent *scan1_single_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003579{
3580 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003581 int i;
plougher1f413c82005-11-18 00:02:14 +00003582
plougher4925e172010-12-16 05:45:54 +00003583 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003584 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003585 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003586 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003587 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003588 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003589 }
plougher4925e172010-12-16 05:45:54 +00003590 }
plougher1f413c82005-11-18 00:02:14 +00003591
3592 if((d_name = readdir(dir->linuxdir)) != NULL) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003593 char *basename = NULL;
3594 char *dir_name = strdup(d_name->d_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003595 int pass = 1, res;
plougher4925e172010-12-16 05:45:54 +00003596
plougher1f413c82005-11-18 00:02:14 +00003597 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003598 struct dir_ent *dir_ent = dir->list;
3599
3600 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3601 dir_ent = dir_ent->next);
3602 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003603 break;
plougher50b31762009-03-31 04:14:46 +00003604 ERROR("Source directory entry %s already used! - trying"
3605 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003606 if (pass == 1)
3607 basename = dir_name;
3608 else
Phillip Lougher494479f2012-02-03 15:45:41 +00003609 free(dir_name);
3610 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3611 if(res == -1)
3612 BAD_ERROR("asprintf failed in "
3613 "scan1_single_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003614 ERROR("%s\n", dir_name);
3615 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003616 return create_dir_entry(dir_name, basename, NULL, dir);
plougher1f413c82005-11-18 00:02:14 +00003617 }
3618
Phillip Lougher494479f2012-02-03 15:45:41 +00003619 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003620}
3621
3622
Phillip Lougher494479f2012-02-03 15:45:41 +00003623struct dir_ent *scan1_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003624{
plougher480d9bf2010-12-18 02:28:39 +00003625 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003626
Phillip Lougher494479f2012-02-03 15:45:41 +00003627 return d_name ?
3628 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3629 NULL;
plougher1f413c82005-11-18 00:02:14 +00003630}
3631
3632
plougher1f413c82005-11-18 00:02:14 +00003633void scan1_freedir(struct dir_info *dir)
3634{
plougherfbed12b2006-02-07 12:45:53 +00003635 if(dir->pathname[0] != '\0')
3636 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003637}
3638
3639
Phillip Lougherb38c1722012-02-09 23:26:19 +00003640struct dir_info *dir_scan1(char *filename, char *subpath,
3641 struct pathnames *paths,
Phillip Lougher494479f2012-02-03 15:45:41 +00003642 struct dir_ent *(_readdir)(struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003643{
Phillip Lougherb38c1722012-02-09 23:26:19 +00003644 struct dir_info *dir = scan1_opendir(filename, subpath, depth);
Phillip Lougher494479f2012-02-03 15:45:41 +00003645 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003646
plougher360b6e42010-12-18 02:40:28 +00003647 if(dir == NULL) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003648 ERROR("Could not open %s, skipping...\n", filename);
plougher1f413c82005-11-18 00:02:14 +00003649 goto error;
3650 }
3651
Phillip Lougher494479f2012-02-03 15:45:41 +00003652 while((dir_ent = _readdir(dir))) {
plougher360b6e42010-12-18 02:40:28 +00003653 struct dir_info *sub_dir;
3654 struct stat buf;
3655 struct pathnames *new;
Phillip Lougher494479f2012-02-03 15:45:41 +00003656 char *filename = pathname(dir_ent);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003657 char *subpath = subpathname(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003658 char *dir_name = dir_ent->name;
plougher1f413c82005-11-18 00:02:14 +00003659
Phillip Lougher494479f2012-02-03 15:45:41 +00003660 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003661 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003662 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003663 }
plougher1f413c82005-11-18 00:02:14 +00003664
3665 if(lstat(filename, &buf) == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00003666 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
plougher110799c2009-03-30 01:50:40 +00003667 filename, strerror(errno));
Phillip Lougher10a4b572012-02-18 23:26:10 +00003668 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003669 continue;
3670 }
plougher29e37092007-04-15 01:24:51 +00003671
3672 if((buf.st_mode & S_IFMT) != S_IFREG &&
Phillip Loughere4ff36a2012-11-19 01:34:47 +00003673 (buf.st_mode & S_IFMT) != S_IFDIR &&
3674 (buf.st_mode & S_IFMT) != S_IFLNK &&
3675 (buf.st_mode & S_IFMT) != S_IFCHR &&
3676 (buf.st_mode & S_IFMT) != S_IFBLK &&
3677 (buf.st_mode & S_IFMT) != S_IFIFO &&
3678 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003679 ERROR("File %s has unrecognised filetype %d, ignoring"
3680 "\n", filename, buf.st_mode & S_IFMT);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003681 free_dir_entry(dir_ent);
plougher29e37092007-04-15 01:24:51 +00003682 continue;
3683 }
3684
Phillip Lougherad0f9212011-12-31 00:55:51 +00003685 if((old_exclude && old_excluded(filename, &buf)) ||
3686 excluded(paths, dir_name, &new) ||
Phillip Lougherb4f4b0d2012-02-20 02:30:26 +00003687 eval_exclude_actions(dir_name, filename, subpath,
3688 &buf, depth)) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003689 add_excluded(dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003690 free_dir_entry(dir_ent);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003691 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003692 }
plougher1f413c82005-11-18 00:02:14 +00003693
3694 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003695 filename = strdup(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003696 subpath = strdup(subpath);
3697 sub_dir = dir_scan1(filename, subpath, new,
3698 scan1_readdir, depth + 1);
Phillip Lougher494479f2012-02-03 15:45:41 +00003699 if(sub_dir == NULL) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003700 free_dir_entry(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003701 free(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003702 free(subpath);
plougher1f413c82005-11-18 00:02:14 +00003703 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003704 }
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003705
plougher1f413c82005-11-18 00:02:14 +00003706 dir->directory_count ++;
3707 } else
3708 sub_dir = NULL;
3709
Phillip Lougher494479f2012-02-03 15:45:41 +00003710 add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
plougher1f413c82005-11-18 00:02:14 +00003711 }
3712
3713 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003714
3715error:
3716 return dir;
3717}
3718
plougher2ea89142008-03-11 01:34:19 +00003719
Phillip Lougherabc3b492012-07-29 02:53:35 +01003720/*
3721 * dir_scan2 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003722 * This processes most actions and any pseudo files
Phillip Lougherabc3b492012-07-29 02:53:35 +01003723 */
Phillip Lougherbf338362012-08-22 05:24:36 +01003724struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003725{
Phillip Lougherbf338362012-08-22 05:24:36 +01003726 if (dir_ent == NULL)
3727 dir_ent = dir->list;
3728 else
3729 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003730
Phillip Lougherbf338362012-08-22 05:24:36 +01003731 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3732
3733 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003734}
3735
3736
3737struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3738{
Phillip Lougherbf338362012-08-22 05:24:36 +01003739 struct dir_ent *dir_ent = dir->list;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003740
Phillip Lougherbf338362012-08-22 05:24:36 +01003741 for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3742 dir_ent = dir_ent->next);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003743
Phillip Lougherbf338362012-08-22 05:24:36 +01003744 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003745}
3746
3747
Phillip Lougher24eeb772012-10-13 01:56:24 +01003748void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
plougher43244f22009-04-05 02:04:51 +00003749{
Phillip Lougherbf338362012-08-22 05:24:36 +01003750 struct dir_ent *dir_ent = NULL;
plougher43244f22009-04-05 02:04:51 +00003751 struct pseudo_entry *pseudo_ent;
3752 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003753 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003754
Phillip Lougherbf338362012-08-22 05:24:36 +01003755 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
plougher43244f22009-04-05 02:04:51 +00003756 struct inode_info *inode_info = dir_ent->inode;
3757 struct stat *buf = &inode_info->buf;
3758 char *name = dir_ent->name;
3759
Phillip Lougher89d757c2011-09-20 00:33:19 +01003760 eval_actions(dir_ent);
3761
plougher43244f22009-04-05 02:04:51 +00003762 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher24eeb772012-10-13 01:56:24 +01003763 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
plougher43244f22009-04-05 02:04:51 +00003764 }
3765
3766 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3767 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003768 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003769 struct stat *buf;
3770 if(dir_ent == NULL) {
plougherdcd66c52010-09-17 03:44:17 +00003771 ERROR("Pseudo modify file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003772 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003773 pseudo_ent->pathname);
3774 continue;
3775 }
ploughera326c182009-08-29 05:41:45 +00003776 if(dir_ent->inode->root_entry) {
plougherdcd66c52010-09-17 03:44:17 +00003777 ERROR("Pseudo modify file \"%s\" is a pre-existing"
plougherb34f9f62009-04-26 02:08:42 +00003778 " file in the filesystem being appended"
3779 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003780 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003781 continue;
3782 }
3783 buf = &dir_ent->inode->buf;
3784 buf->st_mode = (buf->st_mode & S_IFMT) |
3785 pseudo_ent->dev->mode;
3786 buf->st_uid = pseudo_ent->dev->uid;
3787 buf->st_gid = pseudo_ent->dev->gid;
3788 continue;
3789 }
3790
plougher43244f22009-04-05 02:04:51 +00003791 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003792 if(dir_ent->inode->root_entry)
3793 ERROR("Pseudo file \"%s\" is a pre-existing"
3794 " file in the filesystem being appended"
3795 " to. Ignoring.\n",
3796 pseudo_ent->pathname);
3797 else
3798 ERROR("Pseudo file \"%s\" exists in source "
plougherdcd66c52010-09-17 03:44:17 +00003799 "filesystem \"%s\".\nIgnoring, "
plougherf0dc2382010-05-01 23:55:06 +00003800 "exclude it (-e/-ef) to override.\n",
3801 pseudo_ent->pathname,
Phillip Lougher494479f2012-02-03 15:45:41 +00003802 pathname(dir_ent));
plougher43244f22009-04-05 02:04:51 +00003803 continue;
3804 }
3805
plougher43244f22009-04-05 02:04:51 +00003806 memset(&buf, 0, sizeof(buf));
3807 buf.st_mode = pseudo_ent->dev->mode;
3808 buf.st_uid = pseudo_ent->dev->uid;
3809 buf.st_gid = pseudo_ent->dev->gid;
3810 buf.st_rdev = makedev(pseudo_ent->dev->major,
3811 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003812 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003813 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003814
Phillip Lougher5d579292012-10-13 01:37:16 +01003815 if(pseudo_ent->dev->type == 'd') {
3816 struct dir_ent *dir_ent =
3817 create_dir_entry(pseudo_ent->name, NULL,
3818 pseudo_ent->pathname, dir);
3819 char *subpath = strdup(subpathname(dir_ent));
3820 struct dir_info *sub_dir = scan1_opendir("", subpath,
Phillip Lougher24eeb772012-10-13 01:56:24 +01003821 dir->depth + 1);
Phillip Lougher5d579292012-10-13 01:37:16 +01003822 if(sub_dir == NULL) {
3823 ERROR("Could not create pseudo directory \"%s\""
3824 ", skipping...\n",
3825 pseudo_ent->pathname);
3826 free(subpath);
3827 pseudo_ino --;
3828 continue;
3829 }
Phillip Lougher24eeb772012-10-13 01:56:24 +01003830 dir_scan2(sub_dir, pseudo_ent->pseudo);
Phillip Lougher5d579292012-10-13 01:37:16 +01003831 dir->directory_count ++;
3832 add_dir_entry(dir_ent, sub_dir,
3833 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3834 } else if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003835#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003836 struct stat buf2;
3837 int res = stat(pseudo_ent->dev->filename, &buf2);
3838 if(res == -1) {
3839 ERROR("Stat on pseudo file \"%s\" failed, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00003840 "skipping...\n", pseudo_ent->pathname);
Phillip Lougher5d579292012-10-13 01:37:16 +01003841 pseudo_ino --;
plougher4ab7e512009-05-05 02:35:58 +00003842 continue;
3843 }
3844 buf.st_size = buf2.st_size;
Phillip Lougher494479f2012-02-03 15:45:41 +00003845 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003846 pseudo_ent->dev->filename, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003847 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougher00d08172009-09-03 10:17:44 +00003848#else
Phillip Lougher494479f2012-02-03 15:45:41 +00003849 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003850 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003851 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3852 pseudo_ent->dev->pseudo_id), dir);
plougher00d08172009-09-03 10:17:44 +00003853#endif
plougherb85e9ad2010-05-02 01:46:12 +00003854 } else {
Phillip Lougher494479f2012-02-03 15:45:41 +00003855 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003856 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003857 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003858 }
plougher43244f22009-04-05 02:04:51 +00003859 }
plougher43244f22009-04-05 02:04:51 +00003860}
3861
3862
Phillip Lougherabc3b492012-07-29 02:53:35 +01003863/*
3864 * dir_scan3 routines...
Phillip Lougher23d83622012-10-14 02:35:22 +01003865 * This processes the move action
3866 */
3867void dir_scan3(struct dir_info *root, struct dir_info *dir)
3868{
3869 struct dir_ent *dir_ent = NULL;
3870
3871 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3872
3873 eval_move_actions(root, dir_ent);
3874
3875 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3876 dir_scan3(root, dir_ent->dir);
3877 }
3878}
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003879
3880
Phillip Lougher23d83622012-10-14 02:35:22 +01003881/*
3882 * dir_scan4 routines...
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003883 * This processes the empty action. This action has to be processed after
3884 * all other actions because the previous exclude and move actions and the
3885 * pseudo actions affect whether a directory is empty
3886 */
3887void dir_scan4(struct dir_info *dir)
3888{
3889 struct dir_ent *dir_ent = dir->list, *prev = NULL;
3890
3891 while(dir_ent) {
Phillip Lougher15e8f042012-11-16 00:57:39 +00003892 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3893 dir_scan4(dir_ent->dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003894
Phillip Lougher15e8f042012-11-16 00:57:39 +00003895 if(eval_empty_actions(dir_ent)) {
3896 struct dir_ent *tmp = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003897
Phillip Lougher15e8f042012-11-16 00:57:39 +00003898 /*
3899 * delete sub-directory, this is by definition
3900 * empty
3901 */
3902 free(dir_ent->dir->pathname);
3903 free(dir_ent->dir->subpath);
3904 free(dir_ent->dir);
3905
3906 /* remove dir_ent from list */
3907 dir_ent = dir_ent->next;
3908 if(prev)
3909 prev->next = dir_ent;
3910 else
3911 dir->list = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003912
Phillip Lougher15e8f042012-11-16 00:57:39 +00003913 /* free it */
3914 free_dir_entry(tmp);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003915
Phillip Lougher15e8f042012-11-16 00:57:39 +00003916 /* update counts */
3917 dir->directory_count --;
3918 dir->count --;
3919 add_excluded(dir);
3920 continue;
3921 }
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003922 }
Phillip Lougher15e8f042012-11-16 00:57:39 +00003923
3924 prev = dir_ent;
3925 dir_ent = dir_ent->next;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003926 }
3927}
3928
3929
3930/*
3931 * dir_scan5 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003932 * This sorts every directory and computes the inode numbers
3933 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003934
Phillip Lougher242242e2012-08-24 04:15:36 +01003935/*
3936 * Bottom up linked list merge sort.
3937 *
3938 * Qsort and other O(n log n) algorithms work well with arrays but not
3939 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand
3940 * is not ideal for arrays (as it needs an additonal n storage locations
3941 * as sorting is not done in place), but it is ideal for linked lists because
3942 * it doesn't require any extra storage,
3943 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003944void sort_directory(struct dir_info *dir)
3945{
Phillip Lougher242242e2012-08-24 04:15:36 +01003946 struct dir_ent *cur, *l1, *l2, *next;
3947 int len1, len2, stride = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003948
Phillip Lougher242242e2012-08-24 04:15:36 +01003949 if(dir->count < 2)
Phillip Lougherbf338362012-08-22 05:24:36 +01003950 return;
3951
Phillip Lougher242242e2012-08-24 04:15:36 +01003952 /*
3953 * We can consider our linked-list to be made up of stride length
3954 * sublists. Eacn iteration around this loop merges adjacent
3955 * stride length sublists into larger 2*stride sublists. We stop
3956 * when stride becomes equal to the entire list.
3957 *
3958 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
3959 * these 1 element sublists are merged into 2 element sublists, which
3960 * are then merged into 4 element sublists and so on.
3961 */
3962 do {
3963 l2 = dir->list; /* head of current linked list */
3964 cur = NULL; /* empty output list */
Phillip Lougherbf338362012-08-22 05:24:36 +01003965
Phillip Lougher242242e2012-08-24 04:15:36 +01003966 /*
3967 * Iterate through the linked list, merging adjacent sublists.
3968 * On each interation l2 points to the next sublist pair to be
3969 * merged (if there's only one sublist left this is simply added
3970 * to the output list)
3971 */
3972 while(l2) {
3973 l1 = l2;
3974 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
3975 len2 = stride;
Phillip Lougherbf338362012-08-22 05:24:36 +01003976
Phillip Lougher242242e2012-08-24 04:15:36 +01003977 /*
3978 * l1 points to first sublist.
3979 * l2 points to second sublist.
3980 * Merge them onto the output list
3981 */
3982 while(len1 && l2 && len2) {
3983 if(strcmp(l1->name, l2->name) <= 0) {
3984 next = l1;
3985 l1 = l1->next;
3986 len1 --;
3987 } else {
3988 next = l2;
3989 l2 = l2->next;
3990 len2 --;
3991 }
3992
3993 if(cur) {
3994 cur->next = next;
3995 cur = next;
3996 } else
3997 dir->list = cur = next;
3998 }
3999 /*
4000 * One sublist is now empty, copy the other one onto the
4001 * output list
4002 */
4003 for(; len1; len1 --, l1 = l1->next) {
4004 if(cur) {
4005 cur->next = l1;
4006 cur = l1;
4007 } else
4008 dir->list = cur = l1;
4009 }
4010 for(; l2 && len2; len2 --, l2 = l2->next) {
4011 if(cur) {
4012 cur->next = l2;
4013 cur = l2;
4014 } else
4015 dir->list = cur = l2;
4016 }
4017 }
4018 cur->next = NULL;
4019 stride = stride << 1;
4020 } while(stride < dir->count);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004021}
4022
4023
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004024void dir_scan5(struct dir_info *dir)
Phillip Lougher539c2b12012-07-30 20:14:52 +01004025{
Phillip Lougher23d83622012-10-14 02:35:22 +01004026 struct dir_ent *dir_ent;
4027 unsigned int byte_count = 0;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004028
4029 sort_directory(dir);
4030
Phillip Lougher23d83622012-10-14 02:35:22 +01004031 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
4032 byte_count += strlen(dir_ent->name) +
4033 sizeof(struct squashfs_dir_entry);
4034
4035 if(dir_ent->inode->root_entry)
4036 continue;
4037
Phillip Lougher539c2b12012-07-30 20:14:52 +01004038 alloc_inode_no(dir_ent->inode, 0);
Phillip Lougher23d83622012-10-14 02:35:22 +01004039
Phillip Lougher539c2b12012-07-30 20:14:52 +01004040 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
Phillip Loughere69b5882012-11-19 01:31:09 +00004041 dir_scan5(dir_ent->dir);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004042 }
Phillip Lougher23d83622012-10-14 02:35:22 +01004043
4044 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
4045 dir->dir_is_ldir = FALSE;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004046}
4047
4048
4049/*
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004050 * dir_scan6 routines...
Phillip Lougherabc3b492012-07-29 02:53:35 +01004051 * This generates the filesystem metadata and writes it out to the destination
4052 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004053void scan6_init_dir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004054{
4055 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
4056 if(dir->buff == NULL) {
4057 BAD_ERROR("Out of memory allocating directory buffer\n");
4058 }
4059
4060 dir->size = SQUASHFS_METADATA_SIZE;
4061 dir->p = dir->index_count_p = dir->buff;
4062 dir->entry_count = 256;
4063 dir->entry_count_p = NULL;
4064 dir->index = NULL;
4065 dir->i_count = dir->i_size = 0;
4066}
4067
4068
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004069struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
Phillip Lougherbf338362012-08-22 05:24:36 +01004070 struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004071{
Phillip Lougherbf338362012-08-22 05:24:36 +01004072 if (dir_ent == NULL)
4073 dir_ent = dir_info->list;
4074 else
4075 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004076
Phillip Lougherbf338362012-08-22 05:24:36 +01004077 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
4078 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
4079 dir_ent->name, dir_ent->inode->type, dir);
4080
4081 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004082}
4083
4084
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004085void scan6_freedir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004086{
4087 if(dir->index)
4088 free(dir->index);
4089 free(dir->buff);
4090}
4091
4092
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004093void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00004094{
4095 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00004096 int duplicate_file;
plougher1f413c82005-11-18 00:02:14 +00004097 struct directory dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01004098 struct dir_ent *dir_ent = NULL;
plougher1f413c82005-11-18 00:02:14 +00004099
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004100 scan6_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004101
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004102 while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
Phillip Lougher0a670882012-10-05 04:09:13 +01004103 struct stat *buf = &dir_ent->inode->buf;
plougher1f413c82005-11-18 00:02:14 +00004104
4105 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
4106 switch(buf->st_mode & S_IFMT) {
4107 case S_IFREG:
4108 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00004109 write_file(inode, dir_ent,
4110 &duplicate_file);
4111 INFO("file %s, uncompressed size %lld "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004112 "bytes %s\n",
4113 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004114 (long long) buf->st_size,
4115 duplicate_file ? "DUPLICATE" :
4116 "");
plougher1f413c82005-11-18 00:02:14 +00004117 break;
4118
4119 case S_IFDIR:
4120 squashfs_type = SQUASHFS_DIR_TYPE;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004121 dir_scan6(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00004122 break;
4123
4124 case S_IFLNK:
4125 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004126 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004127 squashfs_type, 0, 0, 0, NULL,
4128 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004129 INFO("symbolic link %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004130 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004131 sym_count ++;
4132 break;
4133
4134 case S_IFCHR:
4135 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004136 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004137 squashfs_type, 0, 0, 0, NULL,
4138 NULL, NULL, 0);
4139 INFO("character device %s inode 0x%llx"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004140 "\n", subpathname(dir_ent),
4141 *inode);
plougher1f413c82005-11-18 00:02:14 +00004142 dev_count ++;
4143 break;
4144
4145 case S_IFBLK:
4146 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004147 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004148 squashfs_type, 0, 0, 0, NULL,
4149 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004150 INFO("block device %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004151 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004152 dev_count ++;
4153 break;
4154
4155 case S_IFIFO:
4156 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004157 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004158 squashfs_type, 0, 0, 0, NULL,
4159 NULL, NULL, 0);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004160 INFO("fifo %s inode 0x%llx\n",
4161 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004162 fifo_count ++;
4163 break;
4164
4165 case S_IFSOCK:
4166 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004167 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004168 squashfs_type, 0, 0, 0, NULL,
4169 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004170 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004171 "0x%llx\n",
4172 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004173 sock_count ++;
4174 break;
4175
plougher23377982007-11-12 04:04:48 +00004176 default:
plougherb3604122009-03-30 02:07:20 +00004177 BAD_ERROR("%s unrecognised file type, "
Phillip Lougher494479f2012-02-03 15:45:41 +00004178 "mode is %x\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004179 subpathname(dir_ent),
plougherb3604122009-03-30 02:07:20 +00004180 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00004181 }
4182 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00004183 dir_ent->inode->type = squashfs_type;
4184 } else {
4185 *inode = dir_ent->inode->inode;
4186 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00004187 switch(squashfs_type) {
4188 case SQUASHFS_FILE_TYPE:
4189 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00004190 INFO("file %s, uncompressed "
4191 "size %lld bytes LINK"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004192 "\n",
4193 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004194 (long long)
plougher50b31762009-03-31 04:14:46 +00004195 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00004196 break;
4197 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00004198 INFO("symbolic link %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004199 "LINK\n", subpathname(dir_ent),
4200 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004201 break;
4202 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004203 INFO("character device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004204 "LINK\n", subpathname(dir_ent),
4205 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004206 break;
plougher5507dd92006-11-06 00:43:10 +00004207 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004208 INFO("block device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004209 "LINK\n", subpathname(dir_ent),
4210 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004211 break;
4212 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00004213 INFO("fifo %s inode 0x%llx LINK\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004214 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004215 break;
4216 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00004217 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004218 "0x%llx LINK\n",
4219 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004220 break;
4221 }
plougher1f413c82005-11-18 00:02:14 +00004222 }
4223
Phillip Lougher0366aec2012-10-05 04:06:04 +01004224 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
4225 squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00004226 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004227 }
4228
plougher29e37092007-04-15 01:24:51 +00004229 write_dir(inode, dir_info, &dir);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004230 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
4231 *inode);
plougher1f413c82005-11-18 00:02:14 +00004232
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004233 scan6_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004234}
4235
4236
4237unsigned int slog(unsigned int block)
4238{
4239 int i;
4240
plougher4c99cb72007-06-14 21:46:31 +00004241 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00004242 if(block == (1 << i))
4243 return i;
4244 return 0;
4245}
4246
4247
plougher8f8e1a12007-10-18 02:50:21 +00004248int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00004249{
4250 int i;
4251
4252 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00004253 if((exclude_paths[i].st_dev == buf->st_dev) &&
4254 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00004255 return TRUE;
4256 return FALSE;
4257}
4258
4259
4260#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00004261 if(exclude % EXCLUDE_SIZE == 0) { \
4262 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4263 * sizeof(struct exclude_info)); \
4264 if(exclude_paths == NULL) \
4265 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
4266 } \
4267 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00004268 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00004269int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00004270{
4271 int i;
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004272 char *filename;
plougher1f413c82005-11-18 00:02:14 +00004273 struct stat buf;
4274
plougherb3604122009-03-30 02:07:20 +00004275 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4276 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00004277 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00004278 ERROR("Cannot stat exclude dir/file %s because %s, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004279 "ignoring\n", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004280 return TRUE;
4281 }
4282 ADD_ENTRY(buf);
4283 return TRUE;
4284 }
4285
4286 for(i = 0; i < source; i++) {
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004287 int res = asprintf(&filename, "%s/%s", source_path[i], path);
4288 if(res == -1)
4289 BAD_ERROR("asprintf failed in old_add_exclude\n");
plougher1f413c82005-11-18 00:02:14 +00004290 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00004291 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00004292 ERROR("Cannot stat exclude dir/file %s because "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004293 "%s, ignoring\n", filename,
plougher50b31762009-03-31 04:14:46 +00004294 strerror(errno));
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004295 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004296 continue;
4297 }
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004298 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004299 ADD_ENTRY(buf);
4300 }
4301 return TRUE;
4302}
4303
4304
plougherb3604122009-03-30 02:07:20 +00004305void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4306 int type)
plougher1f413c82005-11-18 00:02:14 +00004307{
plougherb3604122009-03-30 02:07:20 +00004308 old_root_entry = realloc(old_root_entry,
4309 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4310 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00004311 BAD_ERROR("Out of memory in old root directory entries "
4312 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00004313
ploughera326c182009-08-29 05:41:45 +00004314 old_root_entry[old_root_entries].name = strdup(name);
4315 old_root_entry[old_root_entries].inode.inode = inode;
4316 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4317 old_root_entry[old_root_entries].inode.type = type;
4318 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004319}
4320
4321
plougher5741d792010-09-04 03:20:50 +00004322void initialise_threads(int readb_mbytes, int writeb_mbytes,
4323 int fragmentb_mbytes)
plougher5507dd92006-11-06 00:43:10 +00004324{
4325 int i;
4326 sigset_t sigmask, old_mask;
plougher5741d792010-09-04 03:20:50 +00004327 int reader_buffer_size = readb_mbytes << (20 - block_log);
4328 int fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
4329
4330 /*
4331 * writer_buffer_size is global because it is needed in
4332 * write_file_blocks_dup()
4333 */
4334 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004335
4336 sigemptyset(&sigmask);
4337 sigaddset(&sigmask, SIGINT);
4338 sigaddset(&sigmask, SIGQUIT);
4339 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4340 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4341
4342 signal(SIGUSR1, sigusr1_handler);
4343
4344 if(processors == -1) {
4345#ifndef linux
4346 int mib[2];
4347 size_t len = sizeof(processors);
4348
4349 mib[0] = CTL_HW;
4350#ifdef HW_AVAILCPU
4351 mib[1] = HW_AVAILCPU;
4352#else
4353 mib[1] = HW_NCPU;
4354#endif
4355
4356 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004357 ERROR("Failed to get number of available processors. "
4358 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004359 processors = 1;
4360 }
4361#else
plougher9cc26b72010-08-17 01:05:55 +00004362 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004363#endif
4364 }
4365
plougherf2d2a842010-12-18 02:43:48 +00004366 thread = malloc((2 + processors * 2) * sizeof(pthread_t));
4367 if(thread == NULL)
plougher5507dd92006-11-06 00:43:10 +00004368 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004369 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004370 frag_deflator_thread = &deflator_thread[processors];
4371
4372 to_reader = queue_init(1);
4373 from_reader = queue_init(reader_buffer_size);
4374 to_writer = queue_init(writer_buffer_size);
4375 from_writer = queue_init(1);
4376 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004377 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004378 reader_buffer = cache_init(block_size, reader_buffer_size);
4379 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004380 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004381 pthread_create(&thread[0], NULL, reader, NULL);
4382 pthread_create(&thread[1], NULL, writer, NULL);
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004383 init_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00004384 pthread_mutex_init(&fragment_mutex, NULL);
4385 pthread_cond_init(&fragment_waiting, NULL);
4386
4387 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004388 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4389 0)
plougher5507dd92006-11-06 00:43:10 +00004390 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004391 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4392 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004393 BAD_ERROR("Failed to create thread\n");
4394 }
4395
4396 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4397 processors == 1 ? "" : "s");
4398
4399 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4400 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4401}
4402
4403
plougher0e453652006-11-06 01:49:35 +00004404long long write_inode_lookup_table()
4405{
4406 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004407 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004408
4409 if(inode_count == sinode_count)
4410 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004411
plougher44f03282010-07-27 00:31:36 +00004412 it = realloc(inode_lookup_table, lookup_bytes);
4413 if(it == NULL)
plougher0e453652006-11-06 01:49:35 +00004414 BAD_ERROR("Out of memory in write_inode_table\n");
plougher44f03282010-07-27 00:31:36 +00004415 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004416
plougher0e453652006-11-06 01:49:35 +00004417 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4418 struct inode_info *inode = inode_info[i];
4419
4420 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004421
Phillip Lougher539c2b12012-07-30 20:14:52 +01004422 inode_number = get_inode_no(inode);
plougher0e453652006-11-06 01:49:35 +00004423
plougher360514a2009-03-30 03:01:38 +00004424 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4425 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004426
plougher0e453652006-11-06 01:49:35 +00004427 }
4428 }
4429
plougher02bc3bc2007-02-25 12:12:01 +00004430skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004431 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4432 noI);
plougher0e453652006-11-06 01:49:35 +00004433}
4434
plougher2ea89142008-03-11 01:34:19 +00004435
Phillip Lougher8e44e052012-11-26 02:58:35 +00004436char *get_component(char *target, char **targname)
plougher8f8e1a12007-10-18 02:50:21 +00004437{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004438 char *start;
4439
plougher8f8e1a12007-10-18 02:50:21 +00004440 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004441 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004442
Phillip Lougher8e44e052012-11-26 02:58:35 +00004443 start = target;
plougher8f8e1a12007-10-18 02:50:21 +00004444 while(*target != '/' && *target!= '\0')
Phillip Lougher8e44e052012-11-26 02:58:35 +00004445 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004446
Phillip Lougher8e44e052012-11-26 02:58:35 +00004447 *targname = strndup(start, target - start);
plougher8f8e1a12007-10-18 02:50:21 +00004448
4449 return target;
4450}
4451
4452
4453void free_path(struct pathname *paths)
4454{
4455 int i;
4456
4457 for(i = 0; i < paths->names; i++) {
4458 if(paths->name[i].paths)
4459 free_path(paths->name[i].paths);
4460 free(paths->name[i].name);
4461 if(paths->name[i].preg) {
4462 regfree(paths->name[i].preg);
4463 free(paths->name[i].preg);
4464 }
4465 }
4466
4467 free(paths);
4468}
4469
4470
4471struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4472{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004473 char *targname;
plougher8f8e1a12007-10-18 02:50:21 +00004474 int i, error;
4475
Phillip Lougher8e44e052012-11-26 02:58:35 +00004476 target = get_component(target, &targname);
plougher8f8e1a12007-10-18 02:50:21 +00004477
4478 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004479 paths = malloc(sizeof(struct pathname));
4480 if(paths == NULL)
plougher8f8e1a12007-10-18 02:50:21 +00004481 BAD_ERROR("failed to allocate paths\n");
4482
4483 paths->names = 0;
4484 paths->name = NULL;
4485 }
4486
4487 for(i = 0; i < paths->names; i++)
4488 if(strcmp(paths->name[i].name, targname) == 0)
4489 break;
4490
4491 if(i == paths->names) {
4492 /* allocate new name entry */
4493 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004494 paths->name = realloc(paths->name, (i + 1) *
4495 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004496 if(paths->name == NULL)
4497 BAD_ERROR("Out of memory in add path\n");
Phillip Lougher8e44e052012-11-26 02:58:35 +00004498 paths->name[i].name = targname;
plougher8f8e1a12007-10-18 02:50:21 +00004499 paths->name[i].paths = NULL;
4500 if(use_regex) {
4501 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004502 if(paths->name[i].preg == NULL)
4503 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004504 error = regcomp(paths->name[i].preg, targname,
4505 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004506 if(error) {
Phillip Lougher62859d22012-11-30 05:53:56 +00004507 char str[1024]; /* overflow safe */
plougher8f8e1a12007-10-18 02:50:21 +00004508
4509 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004510 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004511 "because %s\n", targname, alltarget,
4512 str);
plougher8f8e1a12007-10-18 02:50:21 +00004513 }
4514 } else
4515 paths->name[i].preg = NULL;
4516
4517 if(target[0] == '\0')
4518 /* at leaf pathname component */
4519 paths->name[i].paths = NULL;
4520 else
4521 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004522 paths->name[i].paths = add_path(NULL, target,
4523 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004524 } else {
4525 /* existing matching entry */
Phillip Lougher8e44e052012-11-26 02:58:35 +00004526 free(targname);
4527
plougher8f8e1a12007-10-18 02:50:21 +00004528 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004529 /* No sub-directory which means this is the leaf
4530 * component of a pre-existing exclude which subsumes
4531 * the exclude currently being added, in which case stop
4532 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004533 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004534 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004535 * from more specific excludes, delete as they're
4536 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004537 free_path(paths->name[i].paths);
4538 paths->name[i].paths = NULL;
4539 } else
4540 /* recurse adding child components */
4541 add_path(paths->name[i].paths, target, alltarget);
4542 }
4543
4544 return paths;
4545}
plougher2ea89142008-03-11 01:34:19 +00004546
4547
plougher05e50ef2007-10-23 12:34:20 +00004548void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004549{
plougher05e50ef2007-10-23 12:34:20 +00004550
plougherb3604122009-03-30 02:07:20 +00004551 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4552 strncmp(target, "../", 3) == 0)
4553 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4554 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004555 else if(strncmp(target, "... ", 4) == 0)
4556 stickypath = add_path(stickypath, target + 4, target + 4);
4557 else
4558 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004559}
4560
4561
4562void display_path(int depth, struct pathname *paths)
4563{
4564 int i, n;
4565
4566 if(paths == NULL)
4567 return;
4568
4569 for(i = 0; i < paths->names; i++) {
4570 for(n = 0; n < depth; n++)
4571 printf("\t");
4572 printf("%d: %s\n", depth, paths->name[i].name);
4573 display_path(depth + 1, paths->name[i].paths);
4574 }
4575}
4576
4577
4578void display_path2(struct pathname *paths, char *string)
4579{
4580 int i;
Phillip Lougher91459c12012-11-30 05:24:44 +00004581 char *path;
plougher8f8e1a12007-10-18 02:50:21 +00004582
4583 if(paths == NULL) {
4584 printf("%s\n", string);
4585 return;
4586 }
4587
4588 for(i = 0; i < paths->names; i++) {
Phillip Lougher91459c12012-11-30 05:24:44 +00004589 int res = asprintf(&path, "%s/%s", string, paths->name[i].name);
4590 if(res == -1)
4591 BAD_ERROR("asprintf failed in display_path2\n");
plougher8f8e1a12007-10-18 02:50:21 +00004592 display_path2(paths->name[i].paths, path);
Phillip Lougher91459c12012-11-30 05:24:44 +00004593 free(path);
plougher8f8e1a12007-10-18 02:50:21 +00004594 }
4595}
4596
4597
plougherf9039c92007-10-22 03:54:16 +00004598struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004599{
ploughera2968ef2009-03-03 10:46:00 +00004600 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004601 if(new == NULL)
4602 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004603 new->count = 0;
4604 return new;
4605}
4606
4607
4608struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4609{
plougher6f2a8262010-07-27 00:37:19 +00004610 if(paths->count % PATHS_ALLOC_SIZE == 0) {
plougherb3604122009-03-30 02:07:20 +00004611 paths = realloc(paths, sizeof(struct pathnames *) +
4612 (paths->count + PATHS_ALLOC_SIZE) *
4613 sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004614 if(paths == NULL)
4615 BAD_ERROR("Out of memory in add_subdir\n");
4616 }
plougherf9039c92007-10-22 03:54:16 +00004617
4618 paths->path[paths->count++] = path;
4619 return paths;
4620}
4621
4622
4623void free_subdir(struct pathnames *paths)
4624{
4625 free(paths);
4626}
4627
4628
4629int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4630{
4631 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004632
plougherf9039c92007-10-22 03:54:16 +00004633 if(paths == NULL) {
4634 *new = NULL;
4635 return FALSE;
4636 }
plougher8f8e1a12007-10-18 02:50:21 +00004637
plougherf9039c92007-10-22 03:54:16 +00004638
4639 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004640 if(stickypath)
4641 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004642
4643 for(n = 0; n < paths->count; n++) {
4644 struct pathname *path = paths->path[n];
4645
4646 for(i = 0; i < path->names; i++) {
4647 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004648 regexec(path->name[i].preg, name, (size_t) 0,
4649 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004650 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004651 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4652 0;
plougherf9039c92007-10-22 03:54:16 +00004653
4654 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004655 /* match on a leaf component, any subdirectories
4656 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004657 res = TRUE;
4658 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004659 }
4660
plougherf9039c92007-10-22 03:54:16 +00004661 if(match)
plougherb3604122009-03-30 02:07:20 +00004662 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004663 * subdirectories to the new set of
4664 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004665 *new = add_subdir(*new, path->name[i].paths);
4666 }
4667 }
4668
4669 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004670 /* no matching names found, return empty new search set
4671 */
plougherf9039c92007-10-22 03:54:16 +00004672 res = FALSE;
4673 goto empty_set;
4674 }
4675
4676 /* one or more matches with sub-directories found (no leaf matches).
4677 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004678 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004679
4680empty_set:
4681 free_subdir(*new);
4682 *new = NULL;
4683 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004684}
4685
4686
Phillip Lougher386128f2012-12-16 05:23:45 +00004687void process_exclude_file(char *argv)
4688{
4689 FILE *fd;
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004690 char buffer[MAX_LINE + 1]; /* overflow safe */
Phillip Lougherb22336d2012-12-20 18:44:22 +00004691 char *filename;
Phillip Lougher386128f2012-12-16 05:23:45 +00004692
Phillip Lougherb22336d2012-12-20 18:44:22 +00004693 fd = fopen(argv, "r");
4694 if(fd == NULL)
4695 BAD_ERROR("Failed to open exclude file \"%s\" because %s\n",
4696 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004697
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004698 while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
Phillip Lougherb22336d2012-12-20 18:44:22 +00004699 int len = strlen(filename);
4700
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004701 if(len == MAX_LINE && filename[len - 1] != '\n')
Phillip Lougherb22336d2012-12-20 18:44:22 +00004702 /* line too large */
4703 BAD_ERROR("Line too long when reading "
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004704 "exclude file \"%s\", larger than %d "
Phillip Lougher83847c12012-12-23 07:22:36 +00004705 "bytes\n", argv, MAX_LINE);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004706
4707 /*
4708 * Remove '\n' terminator if it exists (the last line
4709 * in the file may not be '\n' terminated)
4710 */
4711 if(len && filename[len - 1] == '\n')
4712 filename[len - 1] = '\0';
4713
4714 /* Skip any leading whitespace */
4715 while(isspace(*filename))
4716 filename ++;
4717
4718 /* if comment line, skip */
4719 if(*filename == '#')
4720 continue;
4721
4722 /*
4723 * check for initial backslash, to accommodate
4724 * filenames with leading space or leading # character
4725 */
4726 if(*filename == '\\')
4727 filename ++;
4728
4729 /* if line is now empty after skipping characters, skip it */
4730 if(*filename == '\0')
4731 continue;
4732
Phillip Lougher386128f2012-12-16 05:23:45 +00004733 if(old_exclude)
4734 old_add_exclude(filename);
4735 else
4736 add_exclude(filename);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004737 }
4738
4739 if(ferror(fd))
4740 BAD_ERROR("Reading exclude file \"%s\" failed because %s\n",
4741 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004742
4743 fclose(fd);
4744}
4745
4746
plougher99ac0cc2007-10-29 03:17:10 +00004747#define RECOVER_ID "Squashfs recovery file v1.0\n"
4748#define RECOVER_ID_SIZE 28
4749
plougher64e83fd2010-12-31 21:21:26 +00004750void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004751{
plougher1d065e92010-06-18 03:58:27 +00004752 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004753 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004754 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004755 char header[] = RECOVER_ID;
4756
4757 if(recover == FALSE) {
4758 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004759 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004760 return;
4761 }
4762
plougher1b879bc2010-12-18 02:49:42 +00004763 metadata = malloc(bytes);
4764 if(metadata == NULL)
plougher50b31762009-03-31 04:14:46 +00004765 BAD_ERROR("Failed to alloc metadata buffer in "
4766 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004767
plougher1d065e92010-06-18 03:58:27 +00004768 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4769 if(res == 0)
4770 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004771
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004772 res = asprintf(&recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004773 getbase(destination_file), pid);
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004774 if(res == -1)
4775 BAD_ERROR("Out of memory allocating recovery_file\n");
4776
plougherb3604122009-03-30 02:07:20 +00004777 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4778 if(recoverfd == -1)
4779 BAD_ERROR("Failed to create recovery file, because %s. "
4780 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004781
plougher628e7682009-03-29 22:12:24 +00004782 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004783 BAD_ERROR("Failed to write recovery file, because %s\n",
4784 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004785
plougher64e83fd2010-12-31 21:21:26 +00004786 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004787 BAD_ERROR("Failed to write recovery file, because %s\n",
4788 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004789
plougher628e7682009-03-29 22:12:24 +00004790 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004791 BAD_ERROR("Failed to write recovery file, because %s\n",
4792 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004793
4794 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004795 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004796
4797 printf("Recovery file \"%s\" written\n", recovery_file);
4798 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004799 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4800 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004801 printf("to restore filesystem\n\n");
4802}
4803
4804
4805void read_recovery_data(char *recovery_file, char *destination_file)
4806{
4807 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004808 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004809 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004810 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004811 struct stat buf;
4812 char header[] = RECOVER_ID;
4813 char header2[RECOVER_ID_SIZE];
4814
plougher9e9d9dc2010-12-18 02:53:57 +00004815 recoverfd = open(recovery_file, O_RDONLY);
4816 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004817 BAD_ERROR("Failed to open recovery file because %s\n",
4818 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004819
4820 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004821 BAD_ERROR("Failed to stat destination file, because %s\n",
4822 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004823
plougher9e9d9dc2010-12-18 02:53:57 +00004824 fd = open(destination_file, O_RDWR);
4825 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004826 BAD_ERROR("Failed to open destination file because %s\n",
4827 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004828
plougher8a8c4102009-03-29 22:28:49 +00004829 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4830 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004831 BAD_ERROR("Failed to read recovery file, because %s\n",
4832 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004833 if(res < RECOVER_ID_SIZE)
4834 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004835 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4836 BAD_ERROR("Not a recovery file\n");
4837
plougher64e83fd2010-12-31 21:21:26 +00004838 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004839 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004840 BAD_ERROR("Failed to read recovery file, because %s\n",
4841 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004842 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004843 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004844
plougher64e83fd2010-12-31 21:21:26 +00004845 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004846 if(res == 0)
4847 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004848
plougherb3604122009-03-30 02:07:20 +00004849 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004850 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004851 BAD_ERROR("Recovery file and destination file do not seem to "
4852 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004853
4854 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4855
plougher9e9d9dc2010-12-18 02:53:57 +00004856 metadata = malloc(bytes);
4857 if(metadata == NULL)
plougherb3604122009-03-30 02:07:20 +00004858 BAD_ERROR("Failed to alloc metadata buffer in "
4859 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004860
plougher8a8c4102009-03-29 22:28:49 +00004861 res = read_bytes(recoverfd, metadata, bytes);
4862 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004863 BAD_ERROR("Failed to read recovery file, because %s\n",
4864 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004865 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004866 BAD_ERROR("Recovery file appears to be truncated\n");
4867
plougher64e83fd2010-12-31 21:21:26 +00004868 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004869
plougher0dd6f122009-03-29 21:43:57 +00004870 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004871
4872 close(recoverfd);
4873 close(fd);
4874
plougherb3604122009-03-30 02:07:20 +00004875 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4876 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004877
4878 exit(0);
4879}
4880
4881
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004882int multiply_overflow(int a, int multiplier)
4883{
4884 return (INT_MAX / multiplier) < a;
4885}
4886
4887
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004888int parse_number(char *start, int *res, int size)
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004889{
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004890 char *end;
4891 long number = strtol(start, &end, 10);
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004892
Phillip Lougherf4f48382012-11-29 03:52:44 +00004893 /*
4894 * check for strtol underflow or overflow in conversion.
4895 * Note: strtol can validly return LONG_MIN and LONG_MAX
4896 * if the user entered these values, but, additional code
4897 * to distinguish this scenario is unnecessary, because for
4898 * our purposes LONG_MIN and LONG_MAX are too large anyway
4899 */
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004900 if(number == LONG_MIN || number == LONG_MAX)
4901 return 0;
4902
4903 /* reject negative numbers as invalid */
4904 if(number < 0)
4905 return 0;
4906
4907 /* check if long result will overflow signed int */
4908 if(number > INT_MAX)
4909 return 0;
4910
4911 if(size) {
Phillip Loughered345692012-11-28 03:56:16 +00004912 /*
4913 * Check for multiplier and trailing junk.
4914 * But first check that a number exists before the
4915 * multiplier
4916 */
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004917 if(end == start)
Phillip Loughered345692012-11-28 03:56:16 +00004918 return 0;
4919
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004920 switch(end[0]) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004921 case 'm':
4922 case 'M':
4923 if(multiply_overflow((int) number, 1048576))
4924 return 0;
4925 number *= 1048576;
Phillip Loughera9e65632012-11-28 04:17:27 +00004926
Phillip Lougherf968be82012-12-04 05:12:32 +00004927 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004928 /* trailing junk after number */
4929 return 0;
4930
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004931 break;
4932 case 'k':
4933 case 'K':
4934 if(multiply_overflow((int) number, 1024))
4935 return 0;
4936 number *= 1024;
Phillip Loughera9e65632012-11-28 04:17:27 +00004937
Phillip Lougherf968be82012-12-04 05:12:32 +00004938 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004939 /* trailing junk after number */
4940 return 0;
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004941 case '\0':
4942 break;
4943 default:
4944 /* trailing junk after number */
4945 return 0;
4946 }
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004947 } else if(end[0] != '\0')
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004948 /* trailing junk after number */
4949 return 0;
4950
4951 *res = number;
4952 return 1;
4953}
4954
4955
4956int parse_num(char *arg, int *res)
4957{
4958 return parse_number(arg, res, 0);
4959}
4960
4961
plougher1f413c82005-11-18 00:02:14 +00004962#define VERSION() \
Phillip Lougherb73caba2012-12-24 21:58:41 +00004963 printf("mksquashfs version 4.2-git (2012/12/24)\n");\
Phillip Lougherb38c1722012-02-09 23:26:19 +00004964 printf("copyright (C) 2012 Phillip Lougher "\
Phillip Lougher83d42a32012-10-31 23:42:22 +00004965 "<phillip@squashfs.org.uk>\n\n"); \
plougher16111452010-07-22 05:12:18 +00004966 printf("This program is free software; you can redistribute it and/or"\
4967 "\n");\
4968 printf("modify it under the terms of the GNU General Public License"\
4969 "\n");\
4970 printf("as published by the Free Software Foundation; either version "\
4971 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004972 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004973 printf("This program is distributed in the hope that it will be "\
4974 "useful,\n");\
4975 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4976 "of\n");\
4977 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4978 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004979 printf("GNU General Public License for more details.\n");
4980int main(int argc, char *argv[])
4981{
plougher324978d2006-02-27 04:53:29 +00004982 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00004983 int res, i;
plougher64e83fd2010-12-31 21:21:26 +00004984 struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +00004985 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004986 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004987 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004988 int readb_mbytes = READER_BUFFER_DEFAULT,
4989 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4990 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01004991 int force_progress = FALSE;
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
Phillip Lougherb73caba2012-12-24 21:58:41 +00005021 } else if(strcmp(argv[i], "-af") == 0) {
5022 if(++i == argc) {
5023 ERROR("%s: -af missing filename\n", argv[0]);
5024 exit(1);
5025 }
5026 if(read_action_file(argv[i]) == FALSE)
5027 exit(1);
5028
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005029 } else if(strcmp(argv[i], "-comp") == 0) {
plougherc5d59872010-11-22 01:36:01 +00005030 if(compressor_opts_parsed) {
5031 ERROR("%s: -comp must appear before -X options"
5032 "\n", argv[0]);
5033 exit(1);
5034 }
plougherae9dcd82009-08-01 02:59:38 +00005035 if(++i == argc) {
5036 ERROR("%s: -comp missing compression type\n",
5037 argv[0]);
5038 exit(1);
5039 }
plougher5c2adaf2010-11-22 01:00:15 +00005040 comp = lookup_compressor(argv[i]);
plougher4da4bd42010-11-21 05:01:54 +00005041 if(!comp->supported) {
plougherc5d59872010-11-22 01:36:01 +00005042 ERROR("%s: Compressor \"%s\" is not supported!"
5043 "\n", argv[0], argv[i]);
5044 ERROR("%s: Compressors available:\n", argv[0]);
plougher4da4bd42010-11-21 05:01:54 +00005045 display_compressors("", COMP_DEFAULT);
5046 exit(1);
5047 }
plougherb5576ea2010-11-22 01:06:53 +00005048
5049 } else if(strncmp(argv[i], "-X", 2) == 0) {
5050 int args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00005051 if(args < 0) {
5052 if(args == -1) {
5053 ERROR("%s: Unrecognised compressor"
5054 " option %s\n", argv[0],
5055 argv[i]);
5056 ERROR("%s: Did you forget to specify"
5057 " -comp, or specify it after"
5058 " the compressor specific"
5059 " option?\n", argv[0]);
5060 }
plougherb5576ea2010-11-22 01:06:53 +00005061 exit(1);
5062 }
5063 i += args;
plougherc5d59872010-11-22 01:36:01 +00005064 compressor_opts_parsed = 1;
plougherb5576ea2010-11-22 01:06:53 +00005065
plougherae9dcd82009-08-01 02:59:38 +00005066 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00005067 if(++i == argc) {
5068 ERROR("%s: -pf missing filename\n", argv[0]);
5069 exit(1);
5070 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005071 if(read_pseudo_file(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005072 exit(1);
plougher43244f22009-04-05 02:04:51 +00005073 } else if(strcmp(argv[i], "-p") == 0) {
5074 if(++i == argc) {
5075 ERROR("%s: -p missing pseudo file definition\n",
5076 argv[0]);
5077 exit(1);
5078 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005079 if(read_pseudo_def(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005080 exit(1);
plougher43244f22009-04-05 02:04:51 +00005081 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00005082 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00005083 ERROR("%s: -recover missing recovery file\n",
5084 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00005085 exit(1);
5086 }
5087 read_recovery_data(argv[i], argv[source + 1]);
5088 } else if(strcmp(argv[i], "-no-recovery") == 0)
5089 recover = FALSE;
5090 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00005091 old_exclude = FALSE;
5092 use_regex = FALSE;
5093 } else if(strcmp(argv[i], "-regex") == 0) {
5094 old_exclude = FALSE;
5095 use_regex = TRUE;
5096 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00005097 sparse_files = FALSE;
5098 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00005099 progress = FALSE;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005100 else if(strcmp(argv[i], "-progress") == 0)
5101 force_progress = TRUE;
plougher02bc3bc2007-02-25 12:12:01 +00005102 else if(strcmp(argv[i], "-no-exports") == 0)
5103 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00005104 else if(strcmp(argv[i], "-processors") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005105 if((++i == argc) || !parse_num(argv[i], &processors)) {
plougher360514a2009-03-30 03:01:38 +00005106 ERROR("%s: -processors missing or invalid "
5107 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005108 exit(1);
5109 }
5110 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00005111 ERROR("%s: -processors should be 1 or larger\n",
5112 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005113 exit(1);
5114 }
plougher0e453652006-11-06 01:49:35 +00005115 } else if(strcmp(argv[i], "-read-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005116 if((++i == argc) ||
5117 !parse_num(argv[i], &readb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005118 ERROR("%s: -read-queue missing or invalid "
5119 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005120 exit(1);
5121 }
5122 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00005123 ERROR("%s: -read-queue should be 1 megabyte or "
5124 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005125 exit(1);
5126 }
plougher0e453652006-11-06 01:49:35 +00005127 } else if(strcmp(argv[i], "-write-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005128 if((++i == argc) ||
5129 !parse_num(argv[i], &writeb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005130 ERROR("%s: -write-queue missing or invalid "
5131 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005132 exit(1);
5133 }
5134 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005135 ERROR("%s: -write-queue should be 1 megabyte "
5136 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005137 exit(1);
5138 }
plougher217bad82008-04-05 11:36:41 +00005139 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00005140 if((++i == argc) ||
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005141 !parse_num(argv[i],
5142 &fragmentb_mbytes)) {
plougher360514a2009-03-30 03:01:38 +00005143 ERROR("%s: -fragment-queue missing or invalid "
5144 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005145 exit(1);
5146 }
5147 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005148 ERROR("%s: -fragment-queue should be 1 "
5149 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005150 exit(1);
5151 }
plougher5507dd92006-11-06 00:43:10 +00005152 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00005153 if(++i == argc) {
5154 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005155 exit(1);
5156 }
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005157 if(!parse_number(argv[i], &block_size, 1)) {
plougher4c99cb72007-06-14 21:46:31 +00005158 ERROR("%s: -b invalid block size\n", argv[0]);
5159 exit(1);
5160 }
plougher1f413c82005-11-18 00:02:14 +00005161 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00005162 ERROR("%s: -b block size not power of two or "
5163 "not between 4096 and 1Mbyte\n",
5164 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005165 exit(1);
5166 }
5167 } else if(strcmp(argv[i], "-ef") == 0) {
5168 if(++i == argc) {
5169 ERROR("%s: -ef missing filename\n", argv[0]);
5170 exit(1);
5171 }
plougher9b5bf8c2006-03-20 18:43:33 +00005172 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00005173 duplicate_checking = FALSE;
5174
5175 else if(strcmp(argv[i], "-no-fragments") == 0)
5176 no_fragments = TRUE;
5177
5178 else if(strcmp(argv[i], "-always-use-fragments") == 0)
5179 always_use_fragments = TRUE;
5180
5181 else if(strcmp(argv[i], "-sort") == 0) {
5182 if(++i == argc) {
5183 ERROR("%s: -sort missing filename\n", argv[0]);
5184 exit(1);
5185 }
5186 } else if(strcmp(argv[i], "-all-root") == 0 ||
5187 strcmp(argv[i], "-root-owned") == 0)
5188 global_uid = global_gid = 0;
5189
5190 else if(strcmp(argv[i], "-force-uid") == 0) {
5191 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005192 ERROR("%s: -force-uid missing uid or user\n",
5193 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005194 exit(1);
5195 }
5196 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005197 if(global_uid < 0 || global_uid >
5198 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005199 ERROR("%s: -force-uid uid out of range"
5200 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005201 exit(1);
5202 }
5203 } else {
5204 struct passwd *uid = getpwnam(argv[i]);
5205 if(uid)
5206 global_uid = uid->pw_uid;
5207 else {
plougher360514a2009-03-30 03:01:38 +00005208 ERROR("%s: -force-uid invalid uid or "
5209 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005210 exit(1);
5211 }
5212 }
5213 } else if(strcmp(argv[i], "-force-gid") == 0) {
5214 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00005215 ERROR("%s: -force-gid missing gid or group\n",
5216 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005217 exit(1);
5218 }
5219 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005220 if(global_gid < 0 || global_gid >
5221 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005222 ERROR("%s: -force-gid gid out of range"
5223 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005224 exit(1);
5225 }
5226 } else {
5227 struct group *gid = getgrnam(argv[i]);
5228 if(gid)
5229 global_gid = gid->gr_gid;
5230 else {
plougher360514a2009-03-30 03:01:38 +00005231 ERROR("%s: -force-gid invalid gid or "
5232 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005233 exit(1);
5234 }
5235 }
5236 } else if(strcmp(argv[i], "-noI") == 0 ||
5237 strcmp(argv[i], "-noInodeCompression") == 0)
5238 noI = TRUE;
5239
5240 else if(strcmp(argv[i], "-noD") == 0 ||
5241 strcmp(argv[i], "-noDataCompression") == 0)
5242 noD = TRUE;
5243
5244 else if(strcmp(argv[i], "-noF") == 0 ||
5245 strcmp(argv[i], "-noFragmentCompression") == 0)
5246 noF = TRUE;
5247
plougherb99d7832010-05-19 01:57:34 +00005248 else if(strcmp(argv[i], "-noX") == 0 ||
5249 strcmp(argv[i], "-noXattrCompression") == 0)
5250 noX = TRUE;
5251
plougherce564c62010-05-19 03:01:49 +00005252 else if(strcmp(argv[i], "-no-xattrs") == 0)
5253 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00005254
plougher30281c82010-08-25 05:06:11 +00005255 else if(strcmp(argv[i], "-xattrs") == 0)
5256 no_xattrs = FALSE;
5257
plougher1f413c82005-11-18 00:02:14 +00005258 else if(strcmp(argv[i], "-nopad") == 0)
5259 nopad = TRUE;
5260
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005261 else if(strcmp(argv[i], "-info") == 0)
plougher91fbb302008-05-06 02:29:36 +00005262 silent = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005263
5264 else if(strcmp(argv[i], "-e") == 0)
5265 break;
5266
5267 else if(strcmp(argv[i], "-noappend") == 0)
5268 delete = TRUE;
5269
5270 else if(strcmp(argv[i], "-keep-as-directory") == 0)
5271 keep_as_directory = TRUE;
5272
5273 else if(strcmp(argv[i], "-root-becomes") == 0) {
5274 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005275 ERROR("%s: -root-becomes: missing name\n",
5276 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005277 exit(1);
5278 }
5279 root_name = argv[i];
5280 } else if(strcmp(argv[i], "-version") == 0) {
5281 VERSION();
5282 } else {
5283 ERROR("%s: invalid option\n\n", argv[0]);
5284printOptions:
plougher360514a2009-03-30 03:01:38 +00005285 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
5286 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00005287 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00005288 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00005289 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00005290 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00005291 ERROR("-b <block_size>\t\tset data block to "
5292 "<block_size>. Default %d bytes\n",
5293 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00005294 ERROR("-no-exports\t\tdon't make the filesystem "
5295 "exportable via NFS\n");
5296 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00005297 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00005298 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00005299 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00005300 "\n");
plougher1f413c82005-11-18 00:02:14 +00005301 ERROR("-noI\t\t\tdo not compress inode table\n");
5302 ERROR("-noD\t\t\tdo not compress data blocks\n");
5303 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00005304 ERROR("-noX\t\t\tdo not compress extended "
5305 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00005306 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00005307 ERROR("-always-use-fragments\tuse fragment blocks for "
5308 "files larger than block size\n");
5309 ERROR("-no-duplicates\t\tdo not perform duplicate "
5310 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00005311 ERROR("-all-root\t\tmake all files owned by root\n");
5312 ERROR("-force-uid uid\t\tset all file uids to uid\n");
5313 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00005314 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
5315 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00005316 ERROR("-keep-as-directory\tif one source directory is "
5317 "specified, create a root\n");
5318 ERROR("\t\t\tdirectory containing that directory, "
5319 "rather than the\n");
5320 ERROR("\t\t\tcontents of the directory\n");
5321 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00005322 ERROR("-p <pseudo-definition>\tAdd pseudo file "
5323 "definition\n");
5324 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
5325 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00005326 ERROR("-sort <sort_file>\tsort files according to "
5327 "priorities in <sort_file>. One\n");
5328 ERROR("\t\t\tfile or dir with priority per line. "
5329 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00005330 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00005331 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
5332 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00005333 ERROR("-wildcards\t\tAllow extended shell wildcards "
5334 "(globbing) to be used in\n\t\t\texclude "
5335 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00005336 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
5337 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00005338 ERROR("\nFilesystem append options:\n");
5339 ERROR("-noappend\t\tdo not append to existing "
5340 "filesystem\n");
5341 ERROR("-root-becomes <name>\twhen appending source "
5342 "files/directories, make the\n");
5343 ERROR("\t\t\toriginal root become a subdirectory in "
5344 "the new root\n");
5345 ERROR("\t\t\tcalled <name>, rather than adding the new "
5346 "source items\n");
5347 ERROR("\t\t\tto the original root\n");
5348 ERROR("\nMksquashfs runtime options:\n");
5349 ERROR("-version\t\tprint version, licence and "
5350 "copyright message\n");
5351 ERROR("-recover <name>\t\trecover filesystem data "
5352 "using recovery file <name>\n");
5353 ERROR("-no-recovery\t\tdon't generate a recovery "
5354 "file\n");
5355 ERROR("-info\t\t\tprint files written to filesystem\n");
5356 ERROR("-no-progress\t\tdon't display the progress "
5357 "bar\n");
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005358 ERROR("-progress\t\tdisplay progress bar when using "
5359 "the -info option\n");
plougher37632562009-08-07 19:09:01 +00005360 ERROR("-processors <number>\tUse <number> processors."
5361 " By default will use number of\n");
5362 ERROR("\t\t\tprocessors available\n");
5363 ERROR("-read-queue <size>\tSet input queue to <size> "
5364 "Mbytes. Default %d Mbytes\n",
5365 READER_BUFFER_DEFAULT);
5366 ERROR("-write-queue <size>\tSet output queue to <size> "
5367 "Mbytes. Default %d Mbytes\n",
5368 WRITER_BUFFER_DEFAULT);
plougher8bc376b2010-11-12 04:55:20 +00005369 ERROR("-fragment-queue <size>\tSet fragment queue to "
plougher37632562009-08-07 19:09:01 +00005370 "<size> Mbytes. Default %d Mbytes\n",
5371 FRAGMENT_BUFFER_DEFAULT);
5372 ERROR("\nMiscellaneous options:\n");
5373 ERROR("-root-owned\t\talternative name for -all-root"
5374 "\n");
5375 ERROR("-noInodeCompression\talternative name for -noI"
5376 "\n");
5377 ERROR("-noDataCompression\talternative name for -noD"
5378 "\n");
5379 ERROR("-noFragmentCompression\talternative name for "
5380 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005381 ERROR("-noXattrCompression\talternative name for "
5382 "-noX\n");
plougher4fb66822010-12-08 02:49:28 +00005383 ERROR("\nCompressors available and compressor specific "
5384 "options:\n");
5385 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005386 exit(1);
5387 }
5388 }
5389
plougherb747f4f2010-12-25 04:05:47 +00005390 /*
5391 * Some compressors may need the options to be checked for validity
5392 * once all the options have been processed
5393 */
5394 res = compressor_options_post(comp, block_size);
5395 if(res)
5396 EXIT_MKSQUASHFS();
5397
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005398 /*
5399 * If the -info option has been selected then disable the
5400 * progress bar unless it has been explicitly enabled with
5401 * the -progress option
5402 */
5403 if(!silent)
5404 progress = force_progress;
5405
5406#ifdef SQUASHFS_TRACE
5407 progress = FALSE;
5408#endif
5409
plougher91fbb302008-05-06 02:29:36 +00005410 for(i = 0; i < source; i++)
5411 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005412 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005413 "because %s\n", source_path[i],
5414 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005415 EXIT_MKSQUASHFS();
5416 }
plougher324978d2006-02-27 04:53:29 +00005417
5418 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005419 if(stat(argv[source + 1], &buf) == -1) {
5420 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005421 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005422 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005423 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005424 perror("Could not create destination file");
5425 exit(1);
5426 }
5427 delete = TRUE;
5428 } else {
5429 perror("Could not stat destination file");
5430 exit(1);
5431 }
5432
5433 } else {
5434 if(S_ISBLK(buf.st_mode)) {
5435 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005436 perror("Could not open block device as "
5437 "destination");
plougher1f413c82005-11-18 00:02:14 +00005438 exit(1);
5439 }
5440 block_device = 1;
5441
5442 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005443 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5444 O_RDWR);
5445 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005446 perror("Could not open regular file for "
5447 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005448 exit(1);
5449 }
plougher44d54ef2010-02-08 22:13:49 +00005450 }
plougher1f413c82005-11-18 00:02:14 +00005451 else {
5452 ERROR("Destination not block device or regular file\n");
5453 exit(1);
5454 }
5455
plougher324978d2006-02-27 04:53:29 +00005456 }
plougher1f413c82005-11-18 00:02:14 +00005457
plougher4c99cb72007-06-14 21:46:31 +00005458 signal(SIGTERM, sighandler2);
5459 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00005460
plougher16111452010-07-22 05:12:18 +00005461 /*
5462 * process the exclude files - must be done afer destination file has
5463 * been possibly created
5464 */
plougher1f413c82005-11-18 00:02:14 +00005465 for(i = source + 2; i < argc; i++)
Phillip Lougher386128f2012-12-16 05:23:45 +00005466 if(strcmp(argv[i], "-ef") == 0)
5467 /*
5468 * Note presence of filename arg has already
5469 * been checked
5470 */
5471 process_exclude_file(argv[++i]);
5472 else if(strcmp(argv[i], "-e") == 0)
plougher1f413c82005-11-18 00:02:14 +00005473 break;
plougher8b9a7f62009-08-01 22:52:45 +00005474 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005475 strcmp(argv[i], "-sort") == 0 ||
5476 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005477 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005478 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005479 i++;
5480
5481 if(i != argc) {
5482 if(++i == argc) {
5483 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005484 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005485 }
plougher8f8e1a12007-10-18 02:50:21 +00005486 while(i < argc)
5487 if(old_exclude)
5488 old_add_exclude(argv[i++]);
5489 else
plougher05e50ef2007-10-23 12:34:20 +00005490 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005491 }
5492
5493 /* process the sort files - must be done afer the exclude files */
5494 for(i = source + 2; i < argc; i++)
5495 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005496 int res = read_sort_file(argv[++i], source,
5497 source_path);
5498 if(res == FALSE)
5499 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005500 sorted ++;
5501 } else if(strcmp(argv[i], "-e") == 0)
5502 break;
plougher8b9a7f62009-08-01 22:52:45 +00005503 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005504 strcmp(argv[i], "-ef") == 0 ||
5505 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005506 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005507 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005508 i++;
5509
plougher4c99cb72007-06-14 21:46:31 +00005510 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005511 comp = read_super(fd, &sBlk, argv[source + 1]);
5512 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005513 ERROR("Failed to read existing filesystem - will not "
5514 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005515 ERROR("To force Mksquashfs to write to this block "
5516 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005517 EXIT_MKSQUASHFS();
5518 }
plougher1f413c82005-11-18 00:02:14 +00005519
plougher1f413c82005-11-18 00:02:14 +00005520 block_log = slog(block_size = sBlk.block_size);
5521 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5522 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5523 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005524 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005525 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5526 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5527 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005528 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005529 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005530 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005531 }
5532
plougher5741d792010-09-04 03:20:50 +00005533 initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
plougher4c99cb72007-06-14 21:46:31 +00005534
plougher13fdddf2010-11-24 01:23:41 +00005535 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5536 if(res)
5537 BAD_ERROR("compressor_init failed\n");
5538
plougher4c99cb72007-06-14 21:46:31 +00005539 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005540 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005541 void *comp_data = compressor_dump_options(comp, block_size,
5542 &size);
plougher3d7e5182010-12-25 01:49:42 +00005543
plougherdf6d8f02009-03-20 03:10:00 +00005544 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005545 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005546
plougher871c72a2010-12-25 04:17:27 +00005547 /*
5548 * store any compressor specific options after the superblock,
5549 * and set the COMP_OPT flag to show that the filesystem has
5550 * compressor specfic options
5551 */
plougher3d7e5182010-12-25 01:49:42 +00005552 if(comp_data) {
5553 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5554
5555 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005556 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005557 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005558 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005559 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005560 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005561 + size;
5562 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005563 } else
plougher64e83fd2010-12-31 21:21:26 +00005564 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005565 } else {
plougher360514a2009-03-30 03:01:38 +00005566 unsigned int last_directory_block, inode_dir_offset,
5567 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005568 inode_dir_start_block, uncompressed_data,
5569 compressed_data, inode_dir_inode_number,
5570 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005571 unsigned int root_inode_start =
5572 SQUASHFS_INODE_BLK(sBlk.root_inode),
5573 root_inode_offset =
5574 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005575
plougher360514a2009-03-30 03:01:38 +00005576 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5577 &data_cache, &directory_table,
5578 &directory_data_cache, &last_directory_block,
5579 &inode_dir_offset, &inode_dir_file_size,
5580 &root_inode_size, &inode_dir_start_block,
5581 &file_count, &sym_count, &dev_count, &dir_count,
5582 &fifo_count, &sock_count, &total_bytes,
5583 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005584 &inode_dir_inode_number,
5585 &inode_dir_parent_inode, add_old_root_entry,
5586 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005587 ERROR("Failed to read existing filesystem - will not "
5588 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005589 ERROR("To force Mksquashfs to write to this block "
5590 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005591 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005592 }
plougher6f2a8262010-07-27 00:37:19 +00005593 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005594 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005595 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005596 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005597 if(fragment_table == NULL)
5598 BAD_ERROR("Out of memory in save filesystem state\n");
5599 }
plougher1f413c82005-11-18 00:02:14 +00005600
plougher50b31762009-03-31 04:14:46 +00005601 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005602 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005603 block_size);
plougher89c7a512010-12-15 08:35:51 +00005604 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005605 "-always-use-fragments,\n-exportable and -comp options "
5606 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005607 printf("\nIf appending is not wanted, please re-run with "
5608 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005609
plougher360514a2009-03-30 03:01:38 +00005610 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5611 ~(SQUASHFS_METADATA_SIZE - 1);
5612 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5613 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005614
5615 /* save original filesystem state for restoring ... */
5616 sfragments = fragments;
5617 sbytes = bytes;
5618 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005619 scache_bytes = root_inode_offset + root_inode_size;
5620 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005621 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005622 if(sdata_cache == NULL)
5623 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005624 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005625 if(sdirectory_data_cache == NULL)
5626 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005627 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005628 memcpy(sdirectory_data_cache, directory_data_cache +
5629 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005630 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005631 stotal_bytes = total_bytes;
5632 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005633 stotal_directory_bytes = total_directory_bytes +
5634 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005635 sfile_count = file_count;
5636 ssym_count = sym_count;
5637 sdev_count = dev_count;
5638 sdir_count = dir_count + 1;
5639 sfifo_count = fifo_count;
5640 ssock_count = sock_count;
5641 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005642 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005643 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005644 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005645 BAD_ERROR("Failed to save xattrs from existing "
5646 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005647 restore = TRUE;
5648 if(setjmp(env))
5649 goto restore_filesystem;
5650 signal(SIGTERM, sighandler);
5651 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005652 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005653
plougher360514a2009-03-30 03:01:38 +00005654 /*
5655 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005656 * original filesystem. The filesystem state differs depending
5657 * on whether we're appending to the original root directory, or
5658 * if the original root directory becomes a sub-directory
5659 * (root-becomes specified on command line, here root_name !=
5660 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005661 */
5662 inode_bytes = inode_size = root_inode_start;
5663 directory_size = last_directory_block;
5664 cache_size = root_inode_offset + root_inode_size;
5665 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5666 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005667 sdirectory_bytes = last_directory_block;
5668 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005669 root_inode_number = inode_dir_parent_inode;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005670 inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005671 directory_bytes = last_directory_block;
5672 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005673 memmove(directory_data_cache, directory_data_cache +
5674 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005675 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005676 add_old_root_entry(root_name, sBlk.root_inode,
5677 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005678 total_directory_bytes += compressed_data;
5679 dir_count ++;
5680 } else {
plougher360514a2009-03-30 03:01:38 +00005681 sdirectory_compressed_bytes = last_directory_block -
5682 inode_dir_start_block;
5683 sdirectory_compressed =
5684 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005685 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005686 BAD_ERROR("Out of memory in save filesystem "
5687 "state\n");
plougher360514a2009-03-30 03:01:38 +00005688 memcpy(sdirectory_compressed, directory_table +
5689 inode_dir_start_block,
5690 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005691 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005692 root_inode_number = inode_dir_inode_number;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005693 inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005694 directory_bytes = inode_dir_start_block;
5695 directory_cache_bytes = inode_dir_offset;
5696 cache_bytes = root_inode_offset;
5697 }
5698
plougher360514a2009-03-30 03:01:38 +00005699 inode_count = file_count + dir_count + sym_count + dev_count +
5700 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005701
5702 /*
5703 * The default use freelist before growing cache policy behaves
5704 * poorly with appending - with many deplicates the caches
5705 * do not grow due to the fact that large queues of outstanding
5706 * fragments/writer blocks do not occur, leading to small caches
5707 * and un-uncessary performance loss to frequent cache
5708 * replacement in the small caches. Therefore with appending
5709 * change the policy to grow the caches before reusing blocks
5710 * from the freelist
5711 */
5712 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005713 }
5714
plougher05e50ef2007-10-23 12:34:20 +00005715 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005716 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005717 if(path)
5718 paths = add_subdir(paths, path);
5719 if(stickypath)
5720 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005721 }
5722
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005723 dump_actions();
5724
plougher360514a2009-03-30 03:01:38 +00005725 if(delete && !keep_as_directory && source == 1 &&
5726 S_ISDIR(source_buf.st_mode))
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005727 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005728 else if(!keep_as_directory && source == 1 &&
5729 S_ISDIR(source_buf.st_mode))
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005730 dir_scan(&inode, source_path[0], scan1_single_readdir);
plougher1f413c82005-11-18 00:02:14 +00005731 else
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005732 dir_scan(&inode, "", scan1_encomp_readdir);
plougher1f413c82005-11-18 00:02:14 +00005733 sBlk.root_inode = inode;
5734 sBlk.inodes = inode_count;
5735 sBlk.s_magic = SQUASHFS_MAGIC;
5736 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005737 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005738 sBlk.block_size = block_size;
5739 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005740 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005741 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005742 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005743 sBlk.mkfs_time = time(NULL);
5744
5745restore_filesystem:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01005746 if(progress)
plougherc9b11db2008-05-06 23:59:15 +00005747 disable_progress_bar();
plougherc9b11db2008-05-06 23:59:15 +00005748
plougher1f413c82005-11-18 00:02:14 +00005749 sBlk.fragments = fragments;
plougher875bfef2010-08-12 23:48:41 +00005750 if(!restoring) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005751 struct file_buffer **fragment = NULL;
5752 while((fragment = get_frag_action(fragment)))
5753 write_fragment(*fragment);
plougher2ea89142008-03-11 01:34:19 +00005754 unlock_fragments();
5755 pthread_mutex_lock(&fragment_mutex);
5756 while(fragments_outstanding) {
5757 pthread_mutex_unlock(&fragment_mutex);
5758 sched_yield();
5759 pthread_mutex_lock(&fragment_mutex);
5760 }
plougher5507dd92006-11-06 00:43:10 +00005761 queue_put(to_writer, NULL);
5762 if(queue_get(from_writer) != 0)
5763 EXIT_MKSQUASHFS();
5764 }
5765
ploughere6e0e1b2010-05-12 17:17:06 +00005766 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005767 sBlk.inode_table_start = write_inodes();
5768 sBlk.directory_table_start = write_directories();
5769 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005770 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5771 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005772 sBlk.id_table_start = write_id_table();
5773 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005774
plougher0e453652006-11-06 01:49:35 +00005775 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005776 TRACE("sBlk->directory_table_start 0x%llx\n",
5777 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005778 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5779 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005780 TRACE("sBlk->lookup_table_start 0x%llx\n",
5781 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005782
plougher1f413c82005-11-18 00:02:14 +00005783 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005784
plougher8c4b7b92009-07-30 04:47:52 +00005785 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005786
plougher1f288f62009-02-21 03:05:52 +00005787 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher29e2ace2010-12-31 08:50:00 +00005788 write_destination(fd, SQUASHFS_START, sizeof(sBlk), &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005789
5790 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005791 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005792 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005793 }
5794
plougher99ac0cc2007-10-29 03:17:10 +00005795 close(fd);
5796
plougher11e7b1b2009-09-11 12:10:58 +00005797 delete_pseudo_files();
5798
Phillip Lougheraf4c9232012-11-15 03:46:28 +00005799 if(recovery_file)
plougher99ac0cc2007-10-29 03:17:10 +00005800 unlink(recovery_file);
5801
plougher10f7d572010-07-20 02:14:04 +00005802 total_bytes += total_inode_bytes + total_directory_bytes +
plougher64e83fd2010-12-31 21:21:26 +00005803 sizeof(struct squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005804
plougher62542fb2009-08-06 08:43:08 +00005805 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5806 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5807 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005808 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005809 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5810 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005811 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5812 "compressed");
plougher50b31762009-03-31 04:14:46 +00005813 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5814 "not ");
plougher360514a2009-03-30 03:01:38 +00005815 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5816 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005817 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5818 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5819 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5820 inode_bytes, inode_bytes / 1024.0);
5821 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005822 ((float) inode_bytes / total_inode_bytes) * 100.0,
5823 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005824 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5825 directory_bytes, directory_bytes / 1024.0);
5826 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005827 ((float) directory_bytes / total_directory_bytes) * 100.0,
5828 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005829 if(total_xattr_bytes) {
5830 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5831 xattr_bytes, xattr_bytes / 1024.0);
5832 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5833 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5834 total_xattr_bytes);
5835 }
plougher1f413c82005-11-18 00:02:14 +00005836 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005837 printf("Number of duplicate files found %d\n", file_count -
5838 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005839 else
5840 printf("No duplicate files removed\n");
5841 printf("Number of inodes %d\n", inode_count);
5842 printf("Number of files %d\n", file_count);
5843 if(!no_fragments)
5844 printf("Number of fragments %d\n", fragments);
5845 printf("Number of symbolic links %d\n", sym_count);
5846 printf("Number of device nodes %d\n", dev_count);
5847 printf("Number of fifo nodes %d\n", fifo_count);
5848 printf("Number of socket nodes %d\n", sock_count);
5849 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005850 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005851 printf("Number of uids %d\n", uid_count);
5852
plougher1b899fc2008-08-07 01:24:06 +00005853 for(i = 0; i < id_count; i++) {
5854 if(id_table[i]->flags & ISA_UID) {
5855 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005856 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5857 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005858 }
plougher1f413c82005-11-18 00:02:14 +00005859 }
5860
5861 printf("Number of gids %d\n", guid_count);
5862
plougher1b899fc2008-08-07 01:24:06 +00005863 for(i = 0; i < id_count; i++) {
5864 if(id_table[i]->flags & ISA_GID) {
5865 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005866 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5867 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005868 }
plougher1f413c82005-11-18 00:02:14 +00005869 }
plougher99ac0cc2007-10-29 03:17:10 +00005870
plougher1f413c82005-11-18 00:02:14 +00005871 return 0;
5872}