blob: da92903101f27807b3121be1c62357d83180559b [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
plougher16111452010-07-22 05:12:18 +00002 * Create a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
plougher1f413c82005-11-18 00:02:14 +00004 *
Phillip Lougher43cc4282012-01-25 00:25:56 +00005 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00006 * 2012, 2013
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;
Phillip Lougherb2abb1c2013-01-09 04:51:21 +0000183int excluded(char *name, struct pathnames *paths, 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);
Phillip Lougher19b877d2013-02-23 11:15:38 +0000377extern void 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
Phillip Loughere1668fe2012-12-30 05:48:12 +0000395int add_overflow(int a, int b)
396{
397 return (INT_MAX - a) < b;
398}
399
400
401int shift_overflow(int a, int shift)
402{
403 return (INT_MAX >> shift) < a;
404}
405
406
407int multiply_overflow(int a, int multiplier)
408{
409 return (INT_MAX / multiplier) < a;
410}
411
412
plougher5507dd92006-11-06 00:43:10 +0000413struct queue *queue_init(int size)
414{
415 struct queue *queue = malloc(sizeof(struct queue));
416
417 if(queue == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000418 MEM_ERROR();
Phillip Loughere1668fe2012-12-30 05:48:12 +0000419
420 if(add_overflow(size, 1) ||
421 multiply_overflow(size + 1, sizeof(void *)))
422 BAD_ERROR("Size too large in queue_init\n");
plougher5507dd92006-11-06 00:43:10 +0000423
plougher0d55d9e2010-12-16 04:50:21 +0000424 queue->data = malloc(sizeof(void *) * (size + 1));
Phillip Loughere1668fe2012-12-30 05:48:12 +0000425 if(queue->data == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000426 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +0000427
428 queue->size = size + 1;
429 queue->readp = queue->writep = 0;
430 pthread_mutex_init(&queue->mutex, NULL);
431 pthread_cond_init(&queue->empty, NULL);
432 pthread_cond_init(&queue->full, NULL);
433
434 return queue;
435}
436
437
438void queue_put(struct queue *queue, void *data)
439{
440 int nextp;
441
442 pthread_mutex_lock(&queue->mutex);
443
444 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
445 pthread_cond_wait(&queue->full, &queue->mutex);
446
447 queue->data[queue->writep] = data;
448 queue->writep = nextp;
449 pthread_cond_signal(&queue->empty);
450 pthread_mutex_unlock(&queue->mutex);
451}
452
453
454void *queue_get(struct queue *queue)
455{
456 void *data;
457 pthread_mutex_lock(&queue->mutex);
458
459 while(queue->readp == queue->writep)
460 pthread_cond_wait(&queue->empty, &queue->mutex);
461
462 data = queue->data[queue->readp];
463 queue->readp = (queue->readp + 1) % queue->size;
464 pthread_cond_signal(&queue->full);
465 pthread_mutex_unlock(&queue->mutex);
466
467 return data;
468}
469
plougher1f413c82005-11-18 00:02:14 +0000470
ploughereb6eac92008-02-26 01:50:48 +0000471/* Cache status struct. Caches are used to keep
472 track of memory buffers passed between different threads */
473struct cache {
474 int max_buffers;
475 int count;
476 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000477 pthread_mutex_t mutex;
478 pthread_cond_t wait_for_free;
479 struct file_buffer *free_list;
480 struct file_buffer *hash_table[65536];
481};
482
483
plougher2ea89142008-03-11 01:34:19 +0000484#define INSERT_LIST(NAME, TYPE) \
485void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
486 if(*list) { \
487 entry->NAME##_next = *list; \
488 entry->NAME##_prev = (*list)->NAME##_prev; \
489 (*list)->NAME##_prev->NAME##_next = entry; \
490 (*list)->NAME##_prev = entry; \
491 } else { \
492 *list = entry; \
493 entry->NAME##_prev = entry->NAME##_next = entry; \
494 } \
495}
496
497
498#define REMOVE_LIST(NAME, TYPE) \
499void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
500 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
501 /* only this entry in the list */ \
502 *list = NULL; \
503 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
504 /* more than one entry in the list */ \
505 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
506 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
507 if(*list == entry) \
508 *list = entry->NAME##_next; \
509 } \
510 entry->NAME##_prev = entry->NAME##_next = NULL; \
511}
512
513
514#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000515
516
517/* Called with the cache mutex held */
518void insert_hash_table(struct cache *cache, struct file_buffer *entry)
519{
520 int hash = CALCULATE_HASH(entry->index);
521
522 entry->hash_next = cache->hash_table[hash];
523 cache->hash_table[hash] = entry;
524 entry->hash_prev = NULL;
525 if(entry->hash_next)
526 entry->hash_next->hash_prev = entry;
527}
528
529
530/* Called with the cache mutex held */
531void remove_hash_table(struct cache *cache, struct file_buffer *entry)
532{
533 if(entry->hash_prev)
534 entry->hash_prev->hash_next = entry->hash_next;
535 else
plougher50b31762009-03-31 04:14:46 +0000536 cache->hash_table[CALCULATE_HASH(entry->index)] =
537 entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000538 if(entry->hash_next)
539 entry->hash_next->hash_prev = entry->hash_prev;
540
541 entry->hash_prev = entry->hash_next = NULL;
542}
543
544
545/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000546INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000547
548/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000549REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000550
551
552struct cache *cache_init(int buffer_size, int max_buffers)
553{
554 struct cache *cache = malloc(sizeof(struct cache));
555
556 if(cache == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000557 MEM_ERROR();
ploughereb6eac92008-02-26 01:50:48 +0000558
559 cache->max_buffers = max_buffers;
560 cache->buffer_size = buffer_size;
561 cache->count = 0;
562 cache->free_list = NULL;
563 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000564 pthread_mutex_init(&cache->mutex, NULL);
565 pthread_cond_init(&cache->wait_for_free, NULL);
566
567 return cache;
568}
569
570
571struct file_buffer *cache_lookup(struct cache *cache, long long index)
572{
573 /* Lookup block in the cache, if found return with usage count
574 * incremented, if not found return NULL */
575 int hash = CALCULATE_HASH(index);
576 struct file_buffer *entry;
577
578 pthread_mutex_lock(&cache->mutex);
579
580 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
581 if(entry->index == index)
582 break;
583
584 if(entry) {
585 /* found the block in the cache, increment used count and
586 * if necessary remove from free list so it won't disappear
587 */
588 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000589 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000590 }
591
592 pthread_mutex_unlock(&cache->mutex);
593
594 return entry;
595}
596
597
plougher76c64082008-03-08 01:32:23 +0000598struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000599{
600 /* Get a free block out of the cache indexed on index. */
601 struct file_buffer *entry;
602
603 pthread_mutex_lock(&cache->mutex);
604
plougher76c64082008-03-08 01:32:23 +0000605 while(1) {
606 /* first try to get a block from the free list */
plougher801ba6a2010-02-01 03:12:59 +0000607 if(first_freelist && cache->free_list) {
plougher76c64082008-03-08 01:32:23 +0000608 /* a block on the free_list is a "keep" block */
609 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000610 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000611 remove_hash_table(cache, entry);
612 break;
plougher801ba6a2010-02-01 03:12:59 +0000613 } else if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000614 /* next try to allocate new block */
plougherfd57dfe2009-03-30 01:17:52 +0000615 entry = malloc(sizeof(struct file_buffer) +
616 cache->buffer_size);
plougher76c64082008-03-08 01:32:23 +0000617 if(entry == NULL)
618 goto failed;
619 entry->cache = cache;
620 entry->free_prev = entry->free_next = NULL;
621 cache->count ++;
622 break;
plougher801ba6a2010-02-01 03:12:59 +0000623 } else if(!first_freelist && cache->free_list) {
plougher2ea89142008-03-11 01:34:19 +0000624 /* a block on the free_list is a "keep" block */
625 entry = cache->free_list;
626 remove_free_list(&cache->free_list, entry);
627 remove_hash_table(cache, entry);
628 break;
plougher801ba6a2010-02-01 03:12:59 +0000629 } else
plougher76c64082008-03-08 01:32:23 +0000630 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000631 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000632 }
633
plougher76c64082008-03-08 01:32:23 +0000634 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000635 entry->used = 1;
636 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000637 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000638 if(keep) {
639 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000640 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000641 }
ploughereb6eac92008-02-26 01:50:48 +0000642 pthread_mutex_unlock(&cache->mutex);
643
644 return entry;
645
646failed:
647 pthread_mutex_unlock(&cache->mutex);
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000648 MEM_ERROR();
ploughereb6eac92008-02-26 01:50:48 +0000649}
650
ploughereb6eac92008-02-26 01:50:48 +0000651
plougher0f464442008-03-31 00:27:56 +0000652void cache_rehash(struct file_buffer *entry, long long index)
653{
654 struct cache *cache = entry->cache;
655
656 pthread_mutex_lock(&cache->mutex);
657 if(entry->keep)
658 remove_hash_table(cache, entry);
659 entry->keep = TRUE;
660 entry->index = index;
661 insert_hash_table(cache, entry);
662 pthread_mutex_unlock(&cache->mutex);
663}
664
665
ploughereb6eac92008-02-26 01:50:48 +0000666void cache_block_put(struct file_buffer *entry)
667{
plougher76c64082008-03-08 01:32:23 +0000668 struct cache *cache;
669
ploughereb6eac92008-02-26 01:50:48 +0000670 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000671 * can be reused and if a keep block put onto the free list. As keep
plougher50b31762009-03-31 04:14:46 +0000672 * blocks remain accessible via the hash table they can be found
673 * getting a new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000674
675 if(entry == NULL)
676 return;
677
plougher76c64082008-03-08 01:32:23 +0000678 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000679
plougher76c64082008-03-08 01:32:23 +0000680 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000681
682 entry->used --;
683 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000684 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000685 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000686 else {
687 free(entry);
688 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000689 }
plougher76c64082008-03-08 01:32:23 +0000690
691 /* One or more threads may be waiting on this block */
692 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000693 }
694
plougher76c64082008-03-08 01:32:23 +0000695 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000696}
697
698
plougher50b31762009-03-31 04:14:46 +0000699#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
700 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000701
702
plougher5507dd92006-11-06 00:43:10 +0000703inline void waitforthread(int i)
704{
705 TRACE("Waiting for thread %d\n", i);
706 while(thread[i] != 0)
707 sched_yield();
708}
709
710
plougher1f413c82005-11-18 00:02:14 +0000711void restorefs()
712{
plougher5507dd92006-11-06 00:43:10 +0000713 int i;
714
plougher02bc3bc2007-02-25 12:12:01 +0000715 if(thread == NULL || thread[0] == 0)
716 return;
717
plougher875bfef2010-08-12 23:48:41 +0000718 if(restoring++)
719 /*
plougher5b290d22010-08-12 23:52:21 +0000720 * Recursive failure when trying to restore filesystem!
721 * Nothing to do except to exit, otherwise we'll just appear
plougher875bfef2010-08-12 23:48:41 +0000722 * to hang. The user should be able to restore from the
plougher5b290d22010-08-12 23:52:21 +0000723 * recovery file (which is why it was added, in case of
724 * catastrophic failure in Mksquashfs)
plougher875bfef2010-08-12 23:48:41 +0000725 */
726 exit(1);
727
plougher1f413c82005-11-18 00:02:14 +0000728 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000729
plougher91fbb302008-05-06 02:29:36 +0000730 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000731 if(thread[i])
732 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000733 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000734 waitforthread(i);
735 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000736 bytes = sbytes;
737 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000738 memcpy(directory_data_cache, sdirectory_data_cache,
739 sdirectory_cache_bytes);
740 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000741 inode_bytes = sinode_bytes;
742 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000743 memcpy(directory_table + directory_bytes, sdirectory_compressed,
744 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000745 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000746 total_bytes = stotal_bytes;
747 total_inode_bytes = stotal_inode_bytes;
748 total_directory_bytes = stotal_directory_bytes;
749 inode_count = sinode_count;
750 file_count = sfile_count;
751 sym_count = ssym_count;
752 dev_count = sdev_count;
753 dir_count = sdir_count;
754 fifo_count = sfifo_count;
755 sock_count = ssock_count;
756 dup_files = sdup_files;
757 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000758 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000759 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000760 longjmp(env, 1);
761}
762
763
764void sighandler()
765{
plougher5507dd92006-11-06 00:43:10 +0000766 if(++interrupted > 2)
767 return;
768 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000769 restorefs();
770 else {
771 ERROR("Interrupting will restore original filesystem!\n");
772 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000773 }
774}
775
776
plougher324978d2006-02-27 04:53:29 +0000777void sighandler2()
778{
779 EXIT_MKSQUASHFS();
780}
781
782
plougher5507dd92006-11-06 00:43:10 +0000783void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000784{
plougher5507dd92006-11-06 00:43:10 +0000785 int i;
786 sigset_t sigmask;
787 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000788
plougher5507dd92006-11-06 00:43:10 +0000789 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
790 thread[i] = (pthread_t) 0;
791
plougher07966f72007-11-14 10:54:45 +0000792 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000793
794 sigemptyset(&sigmask);
795 sigaddset(&sigmask, SIGINT);
796 sigaddset(&sigmask, SIGQUIT);
797 sigaddset(&sigmask, SIGUSR1);
798 while(1) {
799 sigsuspend(&sigmask);
800 TRACE("After wait in sigusr1_handler :(\n");
801 }
802}
803
804
plougher13fdddf2010-11-24 01:23:41 +0000805int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000806 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000807{
plougher7b8ee502009-07-29 07:54:30 +0000808 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000809
plougher7b8ee502009-07-29 07:54:30 +0000810 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000811 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
812 &error);
plougher7b8ee502009-07-29 07:54:30 +0000813 if(c_byte == -1)
814 BAD_ERROR("mangle2:: %s compress failed with error "
815 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000816 }
817
plougher7b8ee502009-07-29 07:54:30 +0000818 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000819 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000820 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
821 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000822 }
823
plougher7b8ee502009-07-29 07:54:30 +0000824 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000825}
826
827
plougher7b8ee502009-07-29 07:54:30 +0000828int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000829 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000830{
plougher13fdddf2010-11-24 01:23:41 +0000831 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000832 data_block);
plougher5507dd92006-11-06 00:43:10 +0000833}
834
835
plougherac28cd12010-02-24 02:25:03 +0000836void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000837{
838 int data_space;
839 unsigned short c_byte;
840
841 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000842 if((inode_size - inode_bytes) <
843 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000844 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000845 (SQUASHFS_METADATA_SIZE << 1) + 2);
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000846 if(it == NULL)
847 MEM_ERROR();
plougher1eb2a662010-07-26 17:30:50 +0000848 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000849 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
850 }
851
plougherfd57dfe2009-03-30 01:17:52 +0000852 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000853 data_cache, SQUASHFS_METADATA_SIZE,
854 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000855 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000856 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000857 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
858 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000859 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000860 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000861 cache_bytes -= SQUASHFS_METADATA_SIZE;
862 }
863
864 data_space = (cache_size - cache_bytes);
865 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000866 int realloc_size = cache_size == 0 ?
867 ((req_size + SQUASHFS_METADATA_SIZE) &
868 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
869 data_space;
plougher1f413c82005-11-18 00:02:14 +0000870
plougher17248ca2010-07-27 00:24:35 +0000871 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000872 realloc_size);
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000873 if(dc == NULL)
874 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +0000875 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000876 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000877 }
878
879 cache_bytes += req_size;
880
plougherac28cd12010-02-24 02:25:03 +0000881 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000882}
883
884
plougher8a8c4102009-03-29 22:28:49 +0000885int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000886{
887 int res, count;
888
889 for(count = 0; count < bytes; count += res) {
890 res = read(fd, buff + count, bytes - count);
891 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000892 if(res == 0)
893 goto bytes_read;
894 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000895 ERROR("Read failed because %s\n",
896 strerror(errno));
897 return -1;
898 } else
899 res = 0;
900 }
901 }
902
903bytes_read:
904 return count;
905}
906
907
plougher3306cb22010-06-18 04:22:44 +0000908int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000909{
910 off_t off = byte;
911
plougher1d065e92010-06-18 03:58:27 +0000912 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000913 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000914
plougher5507dd92006-11-06 00:43:10 +0000915 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000916 if(lseek(fd, off, SEEK_SET) == -1) {
Phillip Lougher1d3177a2013-02-06 21:48:58 +0000917 ERROR("read_fs_bytes: Lseek on destination failed because %s, "
918 "offset=0x%llx\n", strerror(errno), off);
plougher1d065e92010-06-18 03:58:27 +0000919 goto failed;
920 }
plougher1f413c82005-11-18 00:02:14 +0000921
plougher1d065e92010-06-18 03:58:27 +0000922 if(read_bytes(fd, buff, bytes) < bytes) {
923 ERROR("Read on destination failed\n");
924 goto failed;
925 }
926
plougher5507dd92006-11-06 00:43:10 +0000927 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000928 return 1;
929
930failed:
931 pthread_mutex_unlock(&pos_mutex);
932 return 0;
plougher1f413c82005-11-18 00:02:14 +0000933}
934
935
plougher628e7682009-03-29 22:12:24 +0000936int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000937{
938 int res, count;
939
940 for(count = 0; count < bytes; count += res) {
941 res = write(fd, buff + count, bytes - count);
942 if(res == -1) {
943 if(errno != EINTR) {
944 ERROR("Write failed because %s\n",
945 strerror(errno));
946 return -1;
947 }
948 res = 0;
949 }
950 }
951
952 return 0;
953}
954
955
plougher29e2ace2010-12-31 08:50:00 +0000956void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000957{
958 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000959
plougher875bfef2010-08-12 23:48:41 +0000960 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000961 pthread_mutex_lock(&pos_mutex);
962
Phillip Loughera0c23462013-02-12 03:30:12 +0000963 if(lseek(fd, off, SEEK_SET) == -1) {
964 ERROR("write_destination: Lseek on destination "
Phillip Lougher1d3177a2013-02-06 21:48:58 +0000965 "failed because %s, offset=0x%llx\n", strerror(errno),
966 off);
Phillip Loughera0c23462013-02-12 03:30:12 +0000967 BAD_ERROR("Probably out of space on output %s\n",
968 block_device ? "block device" : "filesystem");
969 }
plougher1f413c82005-11-18 00:02:14 +0000970
plougher0dd6f122009-03-29 21:43:57 +0000971 if(write_bytes(fd, buff, bytes) == -1)
Phillip Loughere8b536f2013-02-12 22:01:21 +0000972 BAD_ERROR("Failed to write to output %s\n",
973 block_device ? "block device" : "filesystem");
plougher5507dd92006-11-06 00:43:10 +0000974
plougher875bfef2010-08-12 23:48:41 +0000975 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000976 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000977}
978
979
980long long write_inodes()
981{
982 unsigned short c_byte;
983 int avail_bytes;
984 char *datap = data_cache;
985 long long start_bytes = bytes;
986
987 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000988 if(inode_size - inode_bytes <
989 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +0000990 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000991 ((SQUASHFS_METADATA_SIZE << 1) + 2));
Phillip Lougherec71c3c2013-02-21 22:25:53 +0000992 if(it == NULL)
993 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +0000994 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +0000995 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000996 }
plougherfd57dfe2009-03-30 01:17:52 +0000997 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
998 SQUASHFS_METADATA_SIZE : cache_bytes;
999 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
1000 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001001 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +00001002 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +00001003 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
1004 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001005 datap += avail_bytes;
1006 cache_bytes -= avail_bytes;
1007 }
1008
plougher29e2ace2010-12-31 08:50:00 +00001009 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +00001010 bytes += inode_bytes;
1011
1012 return start_bytes;
1013}
1014
1015
1016long long write_directories()
1017{
1018 unsigned short c_byte;
1019 int avail_bytes;
1020 char *directoryp = directory_data_cache;
1021 long long start_bytes = bytes;
1022
1023 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001024 if(directory_size - directory_bytes <
1025 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001026 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001027 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1028 + 2));
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001029 if(dt == NULL)
1030 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001031 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001032 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001033 }
plougherfd57dfe2009-03-30 01:17:52 +00001034 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1035 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001036 c_byte = mangle(directory_table + directory_bytes +
1037 BLOCK_OFFSET, directoryp, avail_bytes,
1038 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001039 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1040 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001041 SQUASHFS_SWAP_SHORTS(&c_byte,
1042 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001043 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1044 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001045 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001046 directoryp += avail_bytes;
1047 directory_cache_bytes -= avail_bytes;
1048 }
plougher29e2ace2010-12-31 08:50:00 +00001049 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +00001050 bytes += directory_bytes;
1051
1052 return start_bytes;
1053}
1054
1055
plougher1b899fc2008-08-07 01:24:06 +00001056long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001057{
plougher1b899fc2008-08-07 01:24:06 +00001058 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001059 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001060 int i;
1061
plougher1b899fc2008-08-07 01:24:06 +00001062 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001063 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001064 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001065 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001066 }
1067
ploughera0a49c32010-08-11 01:47:59 +00001068 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001069}
1070
1071
plougher1b899fc2008-08-07 01:24:06 +00001072struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001073{
plougher1b899fc2008-08-07 01:24:06 +00001074 int hash = ID_HASH(id);
1075 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001076
plougher1b899fc2008-08-07 01:24:06 +00001077 for(; entry; entry = entry->next)
1078 if(entry->id == id)
1079 break;
plougher1f413c82005-11-18 00:02:14 +00001080
plougher1b899fc2008-08-07 01:24:06 +00001081 return entry;
plougher1f413c82005-11-18 00:02:14 +00001082}
1083
1084
plougher1b899fc2008-08-07 01:24:06 +00001085struct id *create_id(unsigned int id)
1086{
1087 int hash = ID_HASH(id);
1088 struct id *entry = malloc(sizeof(struct id));
1089 if(entry == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001090 MEM_ERROR();
plougher1b899fc2008-08-07 01:24:06 +00001091 entry->id = id;
1092 entry->index = id_count ++;
1093 entry->flags = 0;
1094 entry->next = id_hash_table[hash];
1095 id_hash_table[hash] = entry;
1096 id_table[entry->index] = entry;
1097 return entry;
1098}
1099
1100
1101unsigned int get_uid(unsigned int uid)
1102{
1103 struct id *entry = get_id(uid);
1104
1105 if(entry == NULL) {
1106 if(id_count == SQUASHFS_IDS)
1107 BAD_ERROR("Out of uids!\n");
1108 entry = create_id(uid);
1109 }
1110
1111 if((entry->flags & ISA_UID) == 0) {
1112 entry->flags |= ISA_UID;
1113 uid_count ++;
1114 }
1115
1116 return entry->index;
1117}
1118
1119
1120unsigned int get_guid(unsigned int guid)
1121{
1122 struct id *entry = get_id(guid);
1123
1124 if(entry == NULL) {
1125 if(id_count == SQUASHFS_IDS)
1126 BAD_ERROR("Out of gids!\n");
1127 entry = create_id(guid);
1128 }
1129
1130 if((entry->flags & ISA_GID) == 0) {
1131 entry->flags |= ISA_GID;
1132 guid_count ++;
1133 }
1134
1135 return entry->index;
1136}
1137
1138
Phillip Lougher5ef51692012-11-19 03:35:39 +00001139#define ALLOC_SIZE 128
Phillip Lougher494479f2012-02-03 15:45:41 +00001140
Phillip Lougher5ef51692012-11-19 03:35:39 +00001141char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size)
1142{
1143 if(pathname == NULL) {
1144 pathname = malloc(ALLOC_SIZE);
1145 if(pathname == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001146 MEM_ERROR();
Phillip Lougher5ef51692012-11-19 03:35:39 +00001147 }
1148
1149 for(;;) {
1150 int res = snprintf(pathname, *size, "%s/%s",
1151 dir_ent->our_dir->pathname,
1152 dir_ent->source_name ? : dir_ent->name);
1153
1154 if(res < 0)
1155 BAD_ERROR("snprintf failed in pathname\n");
1156 else if(res >= *size) {
1157 /*
1158 * pathname is too small to contain the result, so
1159 * increase it and try again
1160 */
1161 *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1162 pathname = realloc(pathname, *size);
1163 if(pathname == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001164 MEM_ERROR();
Phillip Lougher5ef51692012-11-19 03:35:39 +00001165 } else
1166 break;
1167 }
Phillip Lougher494479f2012-02-03 15:45:41 +00001168
1169 return pathname;
1170}
1171
1172
1173char *pathname(struct dir_ent *dir_ent)
1174{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001175 static char *pathname = NULL;
1176 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001177
Phillip Lougher5ef51692012-11-19 03:35:39 +00001178 if (dir_ent->nonstandard_pathname)
1179 return dir_ent->nonstandard_pathname;
1180
1181 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001182}
1183
1184
1185char *pathname_reader(struct dir_ent *dir_ent)
1186{
Phillip Lougher5ef51692012-11-19 03:35:39 +00001187 static char *pathname = NULL;
1188 static int size = ALLOC_SIZE;
Phillip Lougher494479f2012-02-03 15:45:41 +00001189
Phillip Lougher5ef51692012-11-19 03:35:39 +00001190 if (dir_ent->nonstandard_pathname)
1191 return dir_ent->nonstandard_pathname;
1192
1193 return pathname = _pathname(dir_ent, pathname, &size);
Phillip Lougher494479f2012-02-03 15:45:41 +00001194}
1195
1196
Phillip Lougherb38c1722012-02-09 23:26:19 +00001197char *subpathname(struct dir_ent *dir_ent)
1198{
Phillip Lougherd457ed32012-11-19 01:36:56 +00001199 static char *subpath = NULL;
1200 static int size = ALLOC_SIZE;
1201 int res;
Phillip Lougherb38c1722012-02-09 23:26:19 +00001202
Phillip Lougherd457ed32012-11-19 01:36:56 +00001203 if(subpath == NULL) {
1204 subpath = malloc(ALLOC_SIZE);
1205 if(subpath == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001206 MEM_ERROR();
Phillip Lougherd457ed32012-11-19 01:36:56 +00001207 }
1208
1209 for(;;) {
1210 if(dir_ent->our_dir->subpath[0] != '\0')
1211 res = snprintf(subpath, size, "%s/%s",
1212 dir_ent->our_dir->subpath, dir_ent->name);
1213 else
1214 res = snprintf(subpath, size, "/%s", dir_ent->name);
1215
1216 if(res < 0)
1217 BAD_ERROR("snprintf failed in subpathname\n");
1218 else if(res >= size) {
1219 /*
1220 * subpath is too small to contain the result, so
1221 * increase it and try again
1222 */
1223 size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
1224 subpath = realloc(subpath, size);
1225 if(subpath == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001226 MEM_ERROR();
Phillip Lougherd457ed32012-11-19 01:36:56 +00001227 } else
1228 break;
Phillip Lougher90e08252012-10-05 04:33:35 +01001229 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00001230
1231 return subpath;
1232}
1233
1234
Phillip Lougher539c2b12012-07-30 20:14:52 +01001235inline unsigned int get_inode_no(struct inode_info *inode)
Phillip Lougher53cef742012-07-25 05:12:50 +01001236{
Phillip Lougher539c2b12012-07-30 20:14:52 +01001237 return inode->inode_number;
Phillip Lougher53cef742012-07-25 05:12:50 +01001238}
1239
1240
Phillip Lougher539c2b12012-07-30 20:14:52 +01001241inline unsigned int get_parent_no(struct dir_info *dir)
Phillip Lougher53cef742012-07-25 05:12:50 +01001242{
Phillip Lougher1eae83d2012-09-26 02:12:45 +01001243 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
Phillip Lougher53cef742012-07-25 05:12:50 +01001244}
1245
1246
plougher3c6bdb52010-05-01 02:30:59 +00001247int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1248 struct dir_ent *dir_ent, int type, long long byte_size,
1249 long long start_block, unsigned int offset, unsigned int *block_list,
1250 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001251{
1252 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +00001253 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +00001254 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +00001255 void *inode;
Phillip Lougher494479f2012-02-03 15:45:41 +00001256 char *filename = pathname(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001257 int nlink = dir_ent->inode->nlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001258 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001259
ploughere6e0e1b2010-05-12 17:17:06 +00001260 switch(type) {
1261 case SQUASHFS_FILE_TYPE:
1262 if(dir_ent->inode->nlink > 1 ||
1263 byte_size >= (1LL << 32) ||
1264 start_block >= (1LL << 32) ||
1265 sparse || IS_XATTR(xattr))
1266 type = SQUASHFS_LREG_TYPE;
1267 break;
1268 case SQUASHFS_DIR_TYPE:
1269 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1270 type = SQUASHFS_LDIR_TYPE;
1271 break;
1272 case SQUASHFS_SYMLINK_TYPE:
1273 if(IS_XATTR(xattr))
1274 type = SQUASHFS_LSYMLINK_TYPE;
1275 break;
1276 case SQUASHFS_BLKDEV_TYPE:
1277 if(IS_XATTR(xattr))
1278 type = SQUASHFS_LBLKDEV_TYPE;
1279 break;
1280 case SQUASHFS_CHRDEV_TYPE:
1281 if(IS_XATTR(xattr))
1282 type = SQUASHFS_LCHRDEV_TYPE;
1283 break;
plougherc5d69322010-05-12 19:28:38 +00001284 case SQUASHFS_FIFO_TYPE:
1285 if(IS_XATTR(xattr))
1286 type = SQUASHFS_LFIFO_TYPE;
1287 break;
1288 case SQUASHFS_SOCKET_TYPE:
1289 if(IS_XATTR(xattr))
1290 type = SQUASHFS_LSOCKET_TYPE;
1291 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001292 }
1293
plougher1f413c82005-11-18 00:02:14 +00001294 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001295 base->uid = get_uid((unsigned int) global_uid == -1 ?
1296 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001297 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001298 base->guid = get_guid((unsigned int) global_gid == -1 ?
1299 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001300 base->mtime = buf->st_mtime;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001301 base->inode_number = get_inode_no(dir_ent->inode);
plougher1f413c82005-11-18 00:02:14 +00001302
1303 if(type == SQUASHFS_FILE_TYPE) {
1304 int i;
plougher8701ed62010-12-31 20:38:38 +00001305 struct squashfs_reg_inode_header *reg = &inode_header.reg;
1306 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001307
1308 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001309 reg->file_size = byte_size;
1310 reg->start_block = start_block;
1311 reg->fragment = fragment->index;
1312 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001313 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1314 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001315 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1316 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001317 start_block, offset, fragment->index, fragment->offset,
1318 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001319 for(i = 0; i < offset; i++)
1320 TRACE("Block %d, size %d\n", i, block_list[i]);
1321 }
1322 else if(type == SQUASHFS_LREG_TYPE) {
1323 int i;
plougher1e6ac4a2010-12-31 20:42:02 +00001324 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1325 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001326
1327 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001328 reg->nlink = nlink;
1329 reg->file_size = byte_size;
1330 reg->start_block = start_block;
1331 reg->fragment = fragment->index;
1332 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001333 if(sparse && sparse >= byte_size)
1334 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001335 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001336 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001337 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1338 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001339 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001340 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1341 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001342 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001343 for(i = 0; i < offset; i++)
1344 TRACE("Block %d, size %d\n", i, block_list[i]);
1345 }
1346 else if(type == SQUASHFS_LDIR_TYPE) {
1347 int i;
1348 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +00001349 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001350 struct cached_dir_index *index = dir_in->index;
1351 unsigned int i_count = dir_in->i_count;
1352 unsigned int i_size = dir_in->i_size;
1353
1354 if(byte_size >= 1 << 27)
1355 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1356
1357 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001358 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001359 dir->nlink = dir_ent->dir->directory_count + 2;
1360 dir->file_size = byte_size;
1361 dir->offset = offset;
1362 dir->start_block = start_block;
1363 dir->i_count = i_count;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001364 dir->parent_inode = get_parent_no(dir_ent->our_dir);
ploughere6e0e1b2010-05-12 17:17:06 +00001365 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001366
plougherac28cd12010-02-24 02:25:03 +00001367 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +00001368 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001369 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001370 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +00001371 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +00001372 memcpy(p, index[i].name, index[i].index.size + 1);
1373 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001374 }
plougher50b31762009-03-31 04:14:46 +00001375 TRACE("Long directory inode, file_size %lld, start_block "
1376 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1377 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001378 }
1379 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +00001380 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +00001381
1382 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001383 dir->nlink = dir_ent->dir->directory_count + 2;
1384 dir->file_size = byte_size;
1385 dir->offset = offset;
1386 dir->start_block = start_block;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001387 dir->parent_inode = get_parent_no(dir_ent->our_dir);
plougherac28cd12010-02-24 02:25:03 +00001388 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001389 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001390 "offset 0x%x, nlink %d\n", byte_size, start_block,
1391 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001392 }
1393 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +00001394 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001395 unsigned int major = major(buf->st_rdev);
1396 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001397
plougher5b398502008-10-04 23:22:03 +00001398 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001399 ERROR("Major %d out of range in device node %s, "
1400 "truncating to %d\n", major, filename,
1401 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001402 major &= 0xfff;
1403 }
1404 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001405 ERROR("Minor %d out of range in device node %s, "
1406 "truncating to %d\n", minor, filename,
1407 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001408 minor &= 0xfffff;
1409 }
plougher1f413c82005-11-18 00:02:14 +00001410 inode = get_inode(sizeof(*dev));
1411 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001412 dev->rdev = (major << 8) | (minor & 0xff) |
1413 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001414 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001415 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001416 }
ploughere6e0e1b2010-05-12 17:17:06 +00001417 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001418 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001419 unsigned int major = major(buf->st_rdev);
1420 unsigned int minor = minor(buf->st_rdev);
1421
1422 if(major > 0xfff) {
1423 ERROR("Major %d out of range in device node %s, "
1424 "truncating to %d\n", major, filename,
1425 major & 0xfff);
1426 major &= 0xfff;
1427 }
1428 if(minor > 0xfffff) {
1429 ERROR("Minor %d out of range in device node %s, "
1430 "truncating to %d\n", minor, filename,
1431 minor & 0xfffff);
1432 minor &= 0xfffff;
1433 }
1434 inode = get_inode(sizeof(*dev));
1435 dev->nlink = nlink;
1436 dev->rdev = (major << 8) | (minor & 0xff) |
1437 ((minor & ~0xff) << 12);
1438 dev->xattr = xattr;
1439 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1440 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1441 }
plougher1f413c82005-11-18 00:02:14 +00001442 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001443 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001444 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001445 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001446 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001447
plougher5cf38b82010-12-16 04:55:32 +00001448 byte = readlink(filename, buff, 65536);
1449 if(byte == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001450 ERROR("Failed to read symlink %s, creating empty "
1451 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001452 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001453 }
1454
1455 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001456 ERROR("Symlink %s is greater than 65536 bytes! "
1457 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001458 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001459 }
1460
1461 inode = get_inode(sizeof(*symlink) + byte);
1462 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001463 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001464 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1465 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001466 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1467 nlink);
plougher1f413c82005-11-18 00:02:14 +00001468 }
ploughere6e0e1b2010-05-12 17:17:06 +00001469 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001470 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001471 int byte;
Phillip Lougher1df6c112012-12-12 05:21:42 +00001472 char buff[65536]; /* overflow safe */
plougher5ae6e952010-12-31 20:44:34 +00001473 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001474
plougherdf2b9aa2010-12-16 04:56:23 +00001475 byte = readlink(filename, buff, 65536);
1476 if(byte == -1) {
ploughere6e0e1b2010-05-12 17:17:06 +00001477 ERROR("Failed to read symlink %s, creating empty "
1478 "symlink\n", filename);
1479 byte = 0;
1480 }
1481
1482 if(byte == 65536) {
1483 ERROR("Symlink %s is greater than 65536 bytes! "
1484 "Creating empty symlink\n", filename);
1485 byte = 0;
1486 }
1487
1488 inode = get_inode(sizeof(*symlink) + byte +
1489 sizeof(unsigned int));
1490 symlink->nlink = nlink;
1491 symlink->symlink_size = byte;
1492 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1493 strncpy(inode + off, buff, byte);
1494 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1495 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1496 nlink);
1497 }
plougher1f413c82005-11-18 00:02:14 +00001498 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001499 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001500
1501 inode = get_inode(sizeof(*ipc));
1502 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001503 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001504 TRACE("ipc inode, type %s, nlink %d\n", type ==
1505 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001506 }
1507 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001508 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001509
1510 inode = get_inode(sizeof(*ipc));
1511 ipc->nlink = nlink;
1512 ipc->xattr = xattr;
1513 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1514 TRACE("ipc inode, type %s, nlink %d\n", type ==
1515 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001516 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001517 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001518
1519 *i_no = MKINODE(inode);
1520 inode_count ++;
1521
plougherfd57dfe2009-03-30 01:17:52 +00001522 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1523 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001524
1525 return TRUE;
1526}
1527
1528
plougher50b31762009-03-31 04:14:46 +00001529void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1530 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001531{
plougher8cb05cd2005-12-11 23:32:35 +00001532 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001533 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001534 unsigned int start_block = inode >> 16;
1535 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001536 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001537 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001538
plougher43d49082010-12-16 05:01:15 +00001539 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001540 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001541 ERROR("Filename is greater than %d characters, truncating! ..."
1542 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001543 }
1544
plougher9b393552010-12-31 20:55:43 +00001545 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001546 sizeof(struct squashfs_dir_header)
1547 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001548 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001549 if(buff == NULL)
1550 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001551
1552 dir->p = (dir->p - dir->buff) + buff;
1553 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001554 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1555 buff);
plougher1f413c82005-11-18 00:02:14 +00001556 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1557 dir->buff = buff;
1558 }
1559
plougherfd57dfe2009-03-30 01:17:52 +00001560 if(dir->entry_count == 256 || start_block != dir->start_block ||
1561 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001562 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001563 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001564 ((long long) inode_number - dir->inode_number) > 32767
1565 || ((long long) inode_number - dir->inode_number)
1566 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001567 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001568 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001569
plougher9b393552010-12-31 20:55:43 +00001570 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001571 dir->index_count_p) >
1572 SQUASHFS_METADATA_SIZE) {
1573 if(dir->i_count % I_COUNT_SIZE == 0) {
1574 dir->index = realloc(dir->index,
1575 (dir->i_count + I_COUNT_SIZE) *
1576 sizeof(struct cached_dir_index));
1577 if(dir->index == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001578 MEM_ERROR();
plougherfd57dfe2009-03-30 01:17:52 +00001579 }
1580 dir->index[dir->i_count].index.index =
1581 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001582 dir->index[dir->i_count].index.size = size - 1;
1583 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001584 dir->i_size += sizeof(struct squashfs_dir_index)
1585 + size;
plougher1f413c82005-11-18 00:02:14 +00001586 dir->index_count_p = dir->p;
1587 }
1588
1589 dir_header.count = dir->entry_count - 1;
1590 dir_header.start_block = dir->start_block;
1591 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001592 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001593 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001594
1595 }
1596
1597
1598 dir->entry_count_p = dir->p;
1599 dir->start_block = start_block;
1600 dir->entry_count = 0;
1601 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001602 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001603 }
1604
plougher1f413c82005-11-18 00:02:14 +00001605 idir.offset = offset;
1606 idir.type = type;
1607 idir.size = size - 1;
1608 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001609 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1610 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001611 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001612 dir->entry_count ++;
1613}
1614
1615
plougherfd57dfe2009-03-30 01:17:52 +00001616void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1617 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001618{
1619 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001620 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001621 unsigned int directory_block, directory_offset, i_count, index;
1622 unsigned short c_byte;
1623
1624 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001625 int realloc_size = directory_cache_size == 0 ?
1626 ((dir_size + SQUASHFS_METADATA_SIZE) &
1627 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001628
plougher17248ca2010-07-27 00:24:35 +00001629 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001630 directory_cache_size + realloc_size);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001631 if(dc == NULL)
1632 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001633 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001634 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001635 }
1636
1637 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001638 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001639
1640 dir_header.count = dir->entry_count - 1;
1641 dir_header.start_block = dir->start_block;
1642 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001643 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001644 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1645 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001646 }
1647 directory_offset = directory_cache_bytes;
1648 directory_block = directory_bytes;
1649 directory_cache_bytes += dir_size;
1650 i_count = 0;
1651 index = SQUASHFS_METADATA_SIZE - directory_offset;
1652
1653 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001654 while(i_count < dir->i_count &&
1655 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001656 dir->index[i_count++].index.start_block =
1657 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001658 index += SQUASHFS_METADATA_SIZE;
1659
1660 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1661 break;
1662
plougherfd57dfe2009-03-30 01:17:52 +00001663 if((directory_size - directory_bytes) <
1664 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001665 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001666 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1667 + 2);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001668 if(dt == NULL)
1669 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001670 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001671 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001672 }
1673
plougher50b31762009-03-31 04:14:46 +00001674 c_byte = mangle(directory_table + directory_bytes +
1675 BLOCK_OFFSET, directory_data_cache,
1676 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1677 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001678 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1679 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001680 SQUASHFS_SWAP_SHORTS(&c_byte,
1681 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001682 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1683 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001684 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001685 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001686 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1687 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001688 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1689 }
1690
plougher3c6bdb52010-05-01 02:30:59 +00001691 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1692 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1693 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001694
1695#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001696 {
plougher1f413c82005-11-18 00:02:14 +00001697 unsigned char *dirp;
1698 int count;
1699
1700 TRACE("Directory contents of inode 0x%llx\n", *inode);
1701 dirp = dir->buff;
1702 while(dirp < dir->p) {
1703 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001704 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001705 struct squashfs_dir_header dirh;
1706 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001707 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001708 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001709 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001710
plougher50b31762009-03-31 04:14:46 +00001711 TRACE("\tStart block 0x%x, count %d\n",
1712 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001713
1714 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001715 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001716 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001717 strncpy(buffer, idirp->name, idir.size + 1);
1718 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001719 TRACE("\t\tname %s, inode offset 0x%x, type "
1720 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001721 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001722 1;
plougher1f413c82005-11-18 00:02:14 +00001723 }
1724 }
1725 }
1726#endif
1727 dir_count ++;
plougher1f413c82005-11-18 00:02:14 +00001728}
1729
1730
plougher76c64082008-03-08 01:32:23 +00001731struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001732{
plougher8ed84b92010-12-31 10:37:24 +00001733 struct squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001734 int res, size;
plougher76c64082008-03-08 01:32:23 +00001735 long long start_block;
1736 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001737
plougher76c64082008-03-08 01:32:23 +00001738 if(fragment->index == SQUASHFS_INVALID_FRAG)
1739 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001740
plougher76c64082008-03-08 01:32:23 +00001741 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001742 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001743 return buffer;
plougher76c64082008-03-08 01:32:23 +00001744
plougherfd57dfe2009-03-30 01:17:52 +00001745 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1746 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001747
plougher76c64082008-03-08 01:32:23 +00001748 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001749
1750 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001751 disk_fragment = &fragment_table[fragment->index];
1752 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001753 start_block = disk_fragment->start_block;
1754 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001755
plougher0f464442008-03-31 00:27:56 +00001756 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001757 int error;
plougher76c64082008-03-08 01:32:23 +00001758 char *data;
plougher1f413c82005-11-18 00:02:14 +00001759
plougher76c64082008-03-08 01:32:23 +00001760 if(compressed_buffer)
1761 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001762 else
1763 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001764
plougherb48442b2010-12-31 07:57:54 +00001765 res = compressor_uncompress(comp, buffer->data, data, size,
1766 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001767 if(res == -1)
1768 BAD_ERROR("%s uncompress failed with error code %d\n",
1769 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001770 } else if(compressed_buffer)
1771 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001772 else {
1773 res = read_fs_bytes(fd, start_block, size, buffer->data);
Phillip Lougher94519382013-03-06 02:43:42 +00001774 if(res == 0) {
1775 ERROR("Failed to read fragment from output "
1776 "filesystem\n");
1777 BAD_ERROR("Output filesystem corrupted?\n");
1778 }
plougher1d065e92010-06-18 03:58:27 +00001779 }
plougher1f413c82005-11-18 00:02:14 +00001780
plougher03859fa2009-03-31 03:18:18 +00001781 cache_block_put(compressed_buffer);
1782
plougher76c64082008-03-08 01:32:23 +00001783 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001784}
1785
plougher2ea89142008-03-11 01:34:19 +00001786
1787struct frag_locked {
1788 struct file_buffer *buffer;
1789 int c_byte;
1790 int fragment;
1791 struct frag_locked *fragment_prev;
1792 struct frag_locked *fragment_next;
1793};
1794
1795int fragments_locked = FALSE;
1796struct frag_locked *frag_locked_list = NULL;
1797
1798INSERT_LIST(fragment, struct frag_locked)
1799REMOVE_LIST(fragment, struct frag_locked)
1800
plougher4e8484a2008-03-15 23:30:16 +00001801int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001802{
plougher4e8484a2008-03-15 23:30:16 +00001803 int count;
plougher5507dd92006-11-06 00:43:10 +00001804 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001805 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001806 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001807 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001808 return count;
plougher2ea89142008-03-11 01:34:19 +00001809}
1810
1811
1812void unlock_fragments()
1813{
1814 struct frag_locked *entry;
1815 int compressed_size;
1816
1817 pthread_mutex_lock(&fragment_mutex);
1818 while(frag_locked_list) {
1819 entry = frag_locked_list;
1820 remove_fragment_list(&frag_locked_list, entry);
1821 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1822 fragment_table[entry->fragment].size = entry->c_byte;
1823 fragment_table[entry->fragment].start_block = bytes;
1824 entry->buffer->block = bytes;
1825 bytes += compressed_size;
1826 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001827 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001828 TRACE("fragment_locked writing fragment %d, compressed size %d"
1829 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001830 free(entry);
1831 }
1832 fragments_locked = FALSE;
1833 pthread_mutex_unlock(&fragment_mutex);
1834}
1835
1836
plougherb7a66812010-07-21 01:06:59 +00001837void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001838 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001839{
1840 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1841 if(entry == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001842 MEM_ERROR();
plougher2ea89142008-03-11 01:34:19 +00001843 entry->buffer = write_buffer;
1844 entry->c_byte = c_byte;
1845 entry->fragment = fragment;
1846 entry->fragment_prev = entry->fragment_next = NULL;
1847 pthread_mutex_lock(&fragment_mutex);
1848 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001849 pthread_mutex_unlock(&fragment_mutex);
1850}
1851
1852
Phillip Lougher04b7b532011-06-11 02:14:15 +01001853void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001854{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001855 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001856 return;
1857
plougher5507dd92006-11-06 00:43:10 +00001858 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001859 fragment_table[fragment->block].unused = 0;
1860 fragments_outstanding ++;
1861 queue_put(to_frag, fragment);
1862 pthread_mutex_unlock(&fragment_mutex);
1863}
1864
1865
1866struct file_buffer *allocate_fragment()
1867{
1868 struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
1869
1870 pthread_mutex_lock(&fragment_mutex);
1871
plougher5507dd92006-11-06 00:43:10 +00001872 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001873 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001874 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001875 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001876 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001877 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00001878 }
plougherfa89c332010-07-27 00:27:15 +00001879 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001880 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001881
1882 fragment->size = 0;
1883 fragment->block = fragments ++;
1884
plougher5507dd92006-11-06 00:43:10 +00001885 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001886
1887 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001888}
1889
ploughereb6eac92008-02-26 01:50:48 +00001890
plougher1f413c82005-11-18 00:02:14 +00001891static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougherd2f045f2012-12-28 03:15:45 +00001892
1893
1894void free_fragment(struct fragment *fragment)
1895{
1896 if(fragment != &empty_fragment)
1897 free(fragment);
1898}
1899
1900
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001901struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1902 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001903{
1904 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001905 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001906
plougher5507dd92006-11-06 00:43:10 +00001907 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001908 return &empty_fragment;
1909
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001910 fragment = eval_frag_actions(dir_ent);
1911
1912 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1913 write_fragment(*fragment);
1914 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001915 }
plougher1f413c82005-11-18 00:02:14 +00001916
ploughere7e6e832010-12-16 05:08:06 +00001917 ffrg = malloc(sizeof(struct fragment));
1918 if(ffrg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001919 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00001920
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001921 if(*fragment == NULL)
1922 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001923
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001924 ffrg->index = (*fragment)->block;
1925 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001926 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001927 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001928 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001929 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001930
1931 return ffrg;
1932}
1933
1934
ploughera0a49c32010-08-11 01:47:59 +00001935long long generic_write_table(int length, void *buffer, int length2,
1936 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001937{
plougher17b269c2009-03-30 01:33:07 +00001938 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1939 SQUASHFS_METADATA_SIZE;
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001940 long long *list, start_bytes;
Phillip Lougherc1305322012-11-02 22:28:02 +00001941 int compressed_size, i, list_size = meta_blocks * sizeof(long long);
plougher1f413c82005-11-18 00:02:14 +00001942 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001943 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1944
plougher82ab2332009-04-21 00:21:21 +00001945#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001946 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001947 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001948#endif
plougher1f413c82005-11-18 00:02:14 +00001949
Phillip Lougherc1305322012-11-02 22:28:02 +00001950 list = malloc(list_size);
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001951 if(list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00001952 MEM_ERROR();
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001953
plougher1f413c82005-11-18 00:02:14 +00001954 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001955 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1956 SQUASHFS_METADATA_SIZE : length;
1957 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1958 SQUASHFS_METADATA_SIZE , avail_bytes,
1959 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001960 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001961 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001962 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1963 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001964 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1965 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001966 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001967 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001968 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001969 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001970 }
1971
ploughere6e0e1b2010-05-12 17:17:06 +00001972 start_bytes = bytes;
1973 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001974 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001975 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001976 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001977 }
1978
plougher1f288f62009-02-21 03:05:52 +00001979 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
Phillip Lougherc1305322012-11-02 22:28:02 +00001980 write_destination(fd, bytes, list_size, list);
1981 bytes += list_size;
1982 total_bytes += list_size;
plougher1f413c82005-11-18 00:02:14 +00001983
plougher40d8b952010-02-12 16:26:32 +00001984 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1985 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001986
Phillip Lougherd4e78ee2012-10-31 21:32:40 +00001987 free(list);
1988
plougher1f413c82005-11-18 00:02:14 +00001989 return start_bytes;
1990}
1991
1992
plougher0e453652006-11-06 01:49:35 +00001993long long write_fragment_table()
1994{
1995 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher0e453652006-11-06 01:49:35 +00001996 int i;
1997
plougher17b269c2009-03-30 01:33:07 +00001998 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1999 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00002000 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00002001 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
2002 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00002003 fragment_table[i].size);
Phillip Lougher162c24c2012-10-30 02:54:16 +00002004 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
plougher0e453652006-11-06 01:49:35 +00002005 }
2006
Phillip Lougher162c24c2012-10-30 02:54:16 +00002007 return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00002008}
2009
2010
plougher1f413c82005-11-18 00:02:14 +00002011char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00002012char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00002013{
plougher1d065e92010-06-18 03:58:27 +00002014 int res;
2015
2016 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
Phillip Lougher94519382013-03-06 02:43:42 +00002017 if(res == 0) {
2018 ERROR("Failed to read data from output filesystem\n");
2019 BAD_ERROR("Output filesystem corrupted?\n");
2020 }
plougher1d065e92010-06-18 03:58:27 +00002021
plougher1f413c82005-11-18 00:02:14 +00002022 return read_from_file_buffer;
2023}
2024
2025
plougher1b899fc2008-08-07 01:24:06 +00002026char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
2027char *read_from_disk2(long long start, unsigned int avail_bytes)
2028{
plougher1d065e92010-06-18 03:58:27 +00002029 int res;
2030
2031 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
Phillip Lougher94519382013-03-06 02:43:42 +00002032 if(res == 0) {
2033 ERROR("Failed to read data from output filesystem\n");
2034 BAD_ERROR("Output filesystem corrupted?\n");
2035 }
plougher1d065e92010-06-18 03:58:27 +00002036
plougher1b899fc2008-08-07 01:24:06 +00002037 return read_from_file_buffer2;
2038}
2039
2040
plougher1f413c82005-11-18 00:02:14 +00002041/*
2042 * Compute 16 bit BSD checksum over the data
2043 */
plougher5507dd92006-11-06 00:43:10 +00002044unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00002045{
plougher5507dd92006-11-06 00:43:10 +00002046 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00002047
plougher5507dd92006-11-06 00:43:10 +00002048 while(bytes --) {
2049 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
2050 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00002051 }
2052
2053 return chksum;
2054}
2055
2056
plougher17b269c2009-03-30 01:33:07 +00002057unsigned short get_checksum_disk(long long start, long long l,
2058 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00002059{
2060 unsigned short chksum = 0;
2061 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00002062 struct file_buffer *write_buffer;
2063 int i;
plougher5507dd92006-11-06 00:43:10 +00002064
plougher57e6d182008-05-06 23:51:29 +00002065 for(i = 0; l; i++) {
2066 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2067 if(bytes == 0) /* sparse block */
2068 continue;
2069 write_buffer = cache_lookup(writer_buffer, start);
2070 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002071 chksum = get_checksum(write_buffer->data, bytes,
2072 chksum);
plougher57e6d182008-05-06 23:51:29 +00002073 cache_block_put(write_buffer);
2074 } else
plougher50b31762009-03-31 04:14:46 +00002075 chksum = get_checksum(read_from_disk(start, bytes),
2076 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002077 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002078 start += bytes;
2079 }
2080
2081 return chksum;
2082}
2083
2084
plougher5507dd92006-11-06 00:43:10 +00002085unsigned short get_checksum_mem(char *buff, int bytes)
2086{
2087 return get_checksum(buff, bytes, 0);
2088}
2089
2090
2091unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2092{
2093 if(file_buffer == NULL)
2094 return 0;
2095 else
2096 return get_checksum(file_buffer->data, file_buffer->size, 0);
2097}
2098
2099
plougher5507dd92006-11-06 00:43:10 +00002100#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002101void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002102 unsigned int *block_listp, int blocks, unsigned int fragment,
2103 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002104{
2105 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002106 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002107 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002108
plougher5507dd92006-11-06 00:43:10 +00002109 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002110 return;
2111
plougher5507dd92006-11-06 00:43:10 +00002112 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2113 if(file_size != dupl_ptr->file_size)
2114 continue;
2115 if(blocks != 0 && start != dupl_ptr->start)
2116 continue;
2117 if(fragment != dupl_ptr->fragment->index)
2118 continue;
plougher17b269c2009-03-30 01:33:07 +00002119 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2120 dupl_ptr->fragment->offset || bytes !=
2121 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002122 continue;
2123 return;
2124 }
2125
plougher3bb279c2010-12-16 05:10:03 +00002126 frg = malloc(sizeof(struct fragment));
2127 if(frg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002128 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00002129
2130 frg->index = fragment;
2131 frg->offset = offset;
2132 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002133
plougher5507dd92006-11-06 00:43:10 +00002134 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2135}
plougher1f413c82005-11-18 00:02:14 +00002136
plougher1f413c82005-11-18 00:02:14 +00002137
plougher5507dd92006-11-06 00:43:10 +00002138int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002139{
plougher5507dd92006-11-06 00:43:10 +00002140 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002141
2142 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002143 if(dupl_ptr->file_size == file_size)
2144 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002145
plougher5507dd92006-11-06 00:43:10 +00002146 return FALSE;
2147}
2148
2149
2150int pre_duplicate_frag(long long file_size, unsigned short checksum)
2151{
2152 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2153
2154 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002155 if(file_size == dupl_ptr->file_size && file_size ==
2156 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002157 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002158 struct file_buffer *frag_buffer =
2159 get_fragment(dupl_ptr->fragment);
2160 dupl_ptr->checksum =
2161 get_checksum_disk(dupl_ptr->start,
2162 dupl_ptr->bytes, dupl_ptr->block_list);
2163 dupl_ptr->fragment_checksum =
2164 get_checksum_mem(frag_buffer->data +
2165 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002166 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002167 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002168 }
plougher5507dd92006-11-06 00:43:10 +00002169 if(dupl_ptr->fragment_checksum == checksum)
2170 return TRUE;
2171 }
plougher1f413c82005-11-18 00:02:14 +00002172
plougher5507dd92006-11-06 00:43:10 +00002173 return FALSE;
2174}
2175
2176
plougher17b269c2009-03-30 01:33:07 +00002177struct file_info *add_non_dup(long long file_size, long long bytes,
2178 unsigned int *block_list, long long start, struct fragment *fragment,
2179 unsigned short checksum, unsigned short fragment_checksum,
2180 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002181{
plougher51ef9ae2010-12-16 05:14:28 +00002182 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00002183
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002184 if(dupl_ptr == NULL)
2185 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00002186
2187 dupl_ptr->file_size = file_size;
2188 dupl_ptr->bytes = bytes;
2189 dupl_ptr->block_list = block_list;
2190 dupl_ptr->start = start;
2191 dupl_ptr->fragment = fragment;
2192 dupl_ptr->checksum = checksum;
2193 dupl_ptr->fragment_checksum = fragment_checksum;
2194 dupl_ptr->checksum_flag = checksum_flag;
2195 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2196 dupl[DUP_HASH(file_size)] = dupl_ptr;
2197 dup_files ++;
2198
2199 return dupl_ptr;
2200}
2201
2202
plougher17b269c2009-03-30 01:33:07 +00002203struct file_info *duplicate(long long file_size, long long bytes,
2204 unsigned int **block_list, long long *start, struct fragment **fragment,
2205 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2206 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002207{
2208 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2209 int frag_bytes = file_buffer ? file_buffer->size : 0;
2210
2211 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002212 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2213 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002214 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002215 int block;
2216
plougher17b269c2009-03-30 01:33:07 +00002217 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2218 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002219 continue;
2220
plougher5507dd92006-11-06 00:43:10 +00002221 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002222 checksum = get_checksum_disk(*start, bytes,
2223 *block_list);
2224 fragment_checksum =
2225 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002226 checksum_flag = TRUE;
2227 }
2228
2229 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002230 struct file_buffer *frag_buffer =
2231 get_fragment(dupl_ptr->fragment);
2232 dupl_ptr->checksum =
2233 get_checksum_disk(dupl_ptr->start,
2234 dupl_ptr->bytes, dupl_ptr->block_list);
2235 dupl_ptr->fragment_checksum =
2236 get_checksum_mem(frag_buffer->data +
2237 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002238 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002239 dupl_ptr->checksum_flag = TRUE;
2240 }
2241
plougher17b269c2009-03-30 01:33:07 +00002242 if(checksum != dupl_ptr->checksum ||
2243 fragment_checksum !=
2244 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002245 continue;
2246
plougher1b899fc2008-08-07 01:24:06 +00002247 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002248 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002249 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2250 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002251 struct file_buffer *target_buffer = NULL;
2252 struct file_buffer *dup_buffer = NULL;
2253 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002254 int res;
plougher5507dd92006-11-06 00:43:10 +00002255
plougher1b899fc2008-08-07 01:24:06 +00002256 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002257 continue;
plougher17b269c2009-03-30 01:33:07 +00002258 target_buffer = cache_lookup(writer_buffer,
2259 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002260 if(target_buffer)
2261 target_data = target_buffer->data;
2262 else
plougher50b31762009-03-31 04:14:46 +00002263 target_data =
2264 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002265 size);
plougher5507dd92006-11-06 00:43:10 +00002266
plougher360514a2009-03-30 03:01:38 +00002267 dup_buffer = cache_lookup(writer_buffer,
2268 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002269 if(dup_buffer)
2270 dup_data = dup_buffer->data;
2271 else
plougher360514a2009-03-30 03:01:38 +00002272 dup_data = read_from_disk2(dup_start,
2273 size);
plougher1b899fc2008-08-07 01:24:06 +00002274
2275 res = memcmp(target_data, dup_data, size);
2276 cache_block_put(target_buffer);
2277 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002278 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002279 break;
plougher1b899fc2008-08-07 01:24:06 +00002280 target_start += size;
2281 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002282 }
2283 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002284 struct file_buffer *frag_buffer =
2285 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002286
plougher17b269c2009-03-30 01:33:07 +00002287 if(frag_bytes == 0 ||
2288 memcmp(file_buffer->data,
2289 frag_buffer->data +
2290 dupl_ptr->fragment->offset,
2291 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002292 TRACE("Found duplicate file, start "
2293 "0x%llx, size %lld, checksum "
2294 "0x%x, fragment %d, size %d, "
2295 "offset %d, checksum 0x%x\n",
2296 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002297 dupl_ptr->bytes,
2298 dupl_ptr->checksum,
2299 dupl_ptr->fragment->index,
2300 frag_bytes,
2301 dupl_ptr->fragment->offset,
2302 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002303 *block_list = dupl_ptr->block_list;
2304 *start = dupl_ptr->start;
2305 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002306 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002307 return 0;
2308 }
plougher76c64082008-03-08 01:32:23 +00002309 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002310 }
2311 }
2312
2313
plougher17b269c2009-03-30 01:33:07 +00002314 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2315 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002316}
2317
2318
Phillip Lougher2504b082011-09-07 02:28:45 +01002319inline int is_fragment(struct inode_info *inode)
2320{
2321 int file_size = inode->buf.st_size;
2322
Phillip Lougher63f531f2011-09-10 04:03:32 +01002323 /*
2324 * If this block is to be compressed differently to the
2325 * fragment compression then it cannot be a fragment
2326 */
2327 if(inode->noF != noF)
2328 return FALSE;
2329
Phillip Lougher2504b082011-09-07 02:28:45 +01002330 return !inode->no_fragments && (file_size < block_size ||
2331 (inode->always_use_fragments && file_size & (block_size - 1)));
2332}
2333
2334
plougher00d08172009-09-03 10:17:44 +00002335static int seq = 0;
2336void reader_read_process(struct dir_ent *dir_ent)
2337{
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002338 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002339 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002340 int status, res, byte, count = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002341 int file = get_pseudo_file(inode->pseudo_id)->fd;
2342 int child = get_pseudo_file(inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002343 long long bytes = 0;
2344
2345 while(1) {
2346 file_buffer = cache_get(reader_buffer, 0, 0);
2347 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002348 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002349
2350 byte = read_bytes(file, file_buffer->data, block_size);
2351 if(byte == -1)
2352 goto read_err;
2353
2354 file_buffer->size = byte;
2355 file_buffer->file_size = -1;
2356 file_buffer->block = count ++;
2357 file_buffer->error = FALSE;
2358 file_buffer->fragment = FALSE;
2359 bytes += byte;
2360
2361 if(byte == 0)
2362 break;
2363
plougher286b6b32009-09-19 03:29:27 +00002364 /*
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002365 * Update progress bar size. This is done
plougher286b6b32009-09-19 03:29:27 +00002366 * on every block rather than waiting for all blocks to be
2367 * read incase write_file_process() is running in parallel
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002368 * with this. Otherwise the current progress bar position
2369 * may get ahead of the progress bar size.
plougher286b6b32009-09-19 03:29:27 +00002370 */
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002371 progress_bar_size(1);
plougher286b6b32009-09-19 03:29:27 +00002372
plougher00d08172009-09-03 10:17:44 +00002373 if(prev_buffer)
2374 queue_put(from_reader, prev_buffer);
2375 prev_buffer = file_buffer;
2376 }
2377
plougher54d67292009-09-19 03:26:27 +00002378 /*
2379 * Update inode file size now that the size of the dynamic pseudo file
2380 * is known. This is needed for the -info option.
2381 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002382 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002383
plougherba674e82009-09-10 03:50:00 +00002384 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002385 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002386 goto read_err;
2387
plougher00d08172009-09-03 10:17:44 +00002388 if(prev_buffer == NULL)
2389 prev_buffer = file_buffer;
2390 else {
2391 cache_block_put(file_buffer);
2392 seq --;
2393 }
2394 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002395 prev_buffer->fragment = is_fragment(inode);
plougher00d08172009-09-03 10:17:44 +00002396 queue_put(from_reader, prev_buffer);
2397
2398 return;
2399
2400read_err:
2401 if(prev_buffer) {
2402 cache_block_put(file_buffer);
2403 seq --;
2404 file_buffer = prev_buffer;
2405 }
2406 file_buffer->error = TRUE;
2407 queue_put(from_deflate, file_buffer);
2408}
2409
2410
plougher5507dd92006-11-06 00:43:10 +00002411void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002412{
plougher018d2b32007-04-23 03:01:48 +00002413 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002414 struct file_buffer *file_buffer;
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002415 int blocks, byte, count, expected, file, res;
plougher018d2b32007-04-23 03:01:48 +00002416 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002417 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002418
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002419 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002420 return;
2421
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002422 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002423again:
2424 bytes = 0;
2425 count = 0;
2426 file_buffer = NULL;
2427 read_size = buf->st_size;
2428 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002429
Phillip Lougher494479f2012-02-03 15:45:41 +00002430 file = open(pathname_reader(dir_ent), O_RDONLY);
plougherc1d258e2010-12-16 05:16:45 +00002431 if(file == -1) {
plougher1e380702010-08-11 01:52:49 +00002432 file_buffer = cache_get(reader_buffer, 0, 0);
2433 file_buffer->sequence = seq ++;
Phillip Lougher2302f692012-12-27 04:05:02 +00002434 goto read_err2;
plougher1e380702010-08-11 01:52:49 +00002435 }
plougher5507dd92006-11-06 00:43:10 +00002436
plougher018d2b32007-04-23 03:01:48 +00002437 do {
plougher110799c2009-03-30 01:50:40 +00002438 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002439 block_size ? block_size :
2440 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002441
2442 if(file_buffer)
2443 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002444 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002445 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002446 file_buffer->noD = inode->noD;
plougher5507dd92006-11-06 00:43:10 +00002447
ploughera4c24ed2010-08-11 02:08:38 +00002448 /*
2449 * Always try to read block_size bytes from the file rather
2450 * than expected bytes (which will be less than the block_size
2451 * at the file tail) to check that the file hasn't grown
2452 * since being stated. If it is longer (or shorter) than
2453 * expected, then restat, and try again. Note the special
2454 * case where the file is an exact multiple of the block_size
2455 * is dealt with later.
2456 */
plougher110799c2009-03-30 01:50:40 +00002457 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2458 block_size);
plougher018d2b32007-04-23 03:01:48 +00002459
plougher018d2b32007-04-23 03:01:48 +00002460 file_buffer->file_size = read_size;
2461
ploughera4c24ed2010-08-11 02:08:38 +00002462 if(byte == -1)
2463 goto read_err;
2464
plougher018d2b32007-04-23 03:01:48 +00002465 if(byte != expected)
2466 goto restat;
2467
2468 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002469 file_buffer->error = FALSE;
Phillip Lougher2504b082011-09-07 02:28:45 +01002470 file_buffer->fragment = FALSE;
plougher018d2b32007-04-23 03:01:48 +00002471
2472 bytes += byte;
2473 count ++;
2474 } while(count < blocks);
2475
2476 if(read_size != bytes)
2477 goto restat;
2478
2479 if(expected == block_size) {
ploughera4c24ed2010-08-11 02:08:38 +00002480 /*
2481 * Special case where we've not tried to read past the end of
2482 * the file. We expect to get EOF, i.e. the file isn't larger
2483 * than we expect.
2484 */
plougher018d2b32007-04-23 03:01:48 +00002485 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002486 int res;
plougher018d2b32007-04-23 03:01:48 +00002487
ploughera4c24ed2010-08-11 02:08:38 +00002488 res = read_bytes(file, &buffer, 1);
2489 if(res == -1)
2490 goto read_err;
2491
2492 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002493 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002494 }
2495
Phillip Lougher2504b082011-09-07 02:28:45 +01002496 file_buffer->fragment = is_fragment(inode);
plougher1b899fc2008-08-07 01:24:06 +00002497 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002498
plougher5507dd92006-11-06 00:43:10 +00002499 close(file);
plougher5507dd92006-11-06 00:43:10 +00002500
2501 return;
2502
plougher018d2b32007-04-23 03:01:48 +00002503restat:
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002504 res = fstat(file, &buf2);
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002505 if(res == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00002506 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
Phillip Lougher66f7bfd2012-11-29 23:54:18 +00002507 pathname_reader(dir_ent), strerror(errno));
2508 goto read_err;
2509 }
2510
plougher018d2b32007-04-23 03:01:48 +00002511 if(read_size != buf2.st_size) {
Phillip Lougher2302f692012-12-27 04:05:02 +00002512 close(file);
plougher018d2b32007-04-23 03:01:48 +00002513 memcpy(buf, &buf2, sizeof(struct stat));
2514 file_buffer->error = 2;
2515 queue_put(from_deflate, file_buffer);
2516 goto again;
2517 }
plougher1e380702010-08-11 01:52:49 +00002518read_err:
Phillip Lougher2302f692012-12-27 04:05:02 +00002519 close(file);
2520read_err2:
plougher1e380702010-08-11 01:52:49 +00002521 file_buffer->error = TRUE;
2522 queue_put(from_deflate, file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002523}
2524
2525
2526void reader_scan(struct dir_info *dir) {
Phillip Lougherbf338362012-08-22 05:24:36 +01002527 struct dir_ent *dir_ent = dir->list;
plougher5507dd92006-11-06 00:43:10 +00002528
Phillip Lougherbf338362012-08-22 05:24:36 +01002529 for(; dir_ent; dir_ent = dir_ent->next) {
plougher5507dd92006-11-06 00:43:10 +00002530 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002531 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002532 continue;
2533
plougherb3977eb2010-05-02 02:08:48 +00002534 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002535 reader_read_process(dir_ent);
2536 continue;
2537 }
2538
plougher5507dd92006-11-06 00:43:10 +00002539 switch(buf->st_mode & S_IFMT) {
2540 case S_IFREG:
2541 reader_read_file(dir_ent);
2542 break;
2543 case S_IFDIR:
2544 reader_scan(dir_ent->dir);
2545 break;
2546 }
2547 }
2548}
2549
2550
2551void *reader(void *arg)
2552{
2553 int oldstate;
2554
2555 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2556 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2557
2558 if(!sorted)
2559 reader_scan(queue_get(to_reader));
2560 else {
2561 int i;
2562 struct priority_entry *entry;
2563
2564 queue_get(to_reader);
2565 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002566 for(entry = priority_list[i]; entry;
2567 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002568 reader_read_file(entry->dir);
2569 }
rloughere4873e02007-11-08 17:50:42 +00002570
plougher5aa18162007-12-13 12:15:21 +00002571 thread[0] = 0;
2572
rloughere4873e02007-11-08 17:50:42 +00002573 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002574}
2575
2576
2577void *writer(void *arg)
2578{
plougher5507dd92006-11-06 00:43:10 +00002579 int oldstate;
2580
2581 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2582 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2583
2584 while(1) {
2585 struct file_buffer *file_buffer = queue_get(to_writer);
2586 off_t off;
2587
2588 if(file_buffer == NULL) {
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002589 queue_put(from_writer, NULL);
plougher5507dd92006-11-06 00:43:10 +00002590 continue;
2591 }
2592
2593 off = file_buffer->block;
2594
2595 pthread_mutex_lock(&pos_mutex);
2596
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002597 if(lseek(fd, off, SEEK_SET) == -1) {
Phillip Lougherd23000c2013-02-06 22:05:45 +00002598 ERROR("writer: Lseek on destination failed because "
2599 "%s, offset=0x%llx\n", strerror(errno), off);
Phillip Lougher3f4ccd22013-02-11 04:40:09 +00002600 ERROR("FATAL ERROR: Probably out of space on output "
2601 "%s\n", block_device ? "block device" :
2602 "filesystem");
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002603 goto outofspace;
plougher5507dd92006-11-06 00:43:10 +00002604 }
2605
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002606 if(write_bytes(fd, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002607 file_buffer->size) == -1) {
Phillip Loughere9df4552013-02-14 23:06:29 +00002608 ERROR("Failed to write to output %s\n",
2609 block_device ? "block device" : "filesystem");
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002610 goto outofspace;
plougher5507dd92006-11-06 00:43:10 +00002611 }
2612 pthread_mutex_unlock(&pos_mutex);
2613
ploughereb6eac92008-02-26 01:50:48 +00002614 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002615 }
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00002616
2617outofspace:
2618 /*
2619 * Probably out of space on the filesystem or block device,
2620 * tell the main process to exit, and restore the previous filsystem
2621 * if appending
2622 */
2623 pthread_mutex_unlock(&pos_mutex);
2624 thread[1] = 0;
2625 kill(getpid(), SIGUSR2);
2626 return NULL;
plougher5507dd92006-11-06 00:43:10 +00002627}
2628
2629
plougher5b09fd42007-08-06 10:28:41 +00002630int all_zero(struct file_buffer *file_buffer)
2631{
2632 int i;
2633 long entries = file_buffer->size / sizeof(long);
2634 long *p = (long *) file_buffer->data;
2635
2636 for(i = 0; i < entries && p[i] == 0; i++);
2637
2638 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002639 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002640 i < file_buffer->size && file_buffer->data[i] == 0;
2641 i++);
plougher5b09fd42007-08-06 10:28:41 +00002642
2643 return i == file_buffer->size;
2644 }
2645
2646 return 0;
2647}
2648
2649
plougher5507dd92006-11-06 00:43:10 +00002650void *deflator(void *arg)
2651{
plougher7b8ee502009-07-29 07:54:30 +00002652 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002653 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002654
2655 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2656 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2657
plougher13fdddf2010-11-24 01:23:41 +00002658 res = compressor_init(comp, &stream, block_size, 1);
2659 if(res)
2660 BAD_ERROR("deflator:: compressor_init failed\n");
2661
plougher5507dd92006-11-06 00:43:10 +00002662 while(1) {
2663 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002664 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002665
Phillip Lougher48854382011-09-09 03:36:55 +01002666 if(file_buffer->file_size == 0) {
2667 file_buffer->c_byte = 0;
2668 queue_put(from_deflate, file_buffer);
2669 } else if(sparse_files && all_zero(file_buffer)) {
plougher1b899fc2008-08-07 01:24:06 +00002670 file_buffer->c_byte = 0;
2671 queue_put(from_deflate, file_buffer);
2672 } else if(file_buffer->fragment) {
2673 file_buffer->c_byte = file_buffer->size;
2674 queue_put(from_deflate, file_buffer);
2675 } else {
2676 write_buffer = cache_get(writer_buffer, 0, 0);
plougher13fdddf2010-11-24 01:23:41 +00002677 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002678 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002679 file_buffer->size, block_size,
2680 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002681 write_buffer->sequence = file_buffer->sequence;
2682 write_buffer->file_size = file_buffer->file_size;
2683 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002684 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2685 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002686 write_buffer->fragment = FALSE;
2687 write_buffer->error = FALSE;
2688 cache_block_put(file_buffer);
2689 queue_put(from_deflate, write_buffer);
2690 }
plougher5507dd92006-11-06 00:43:10 +00002691 }
2692}
2693
2694
2695void *frag_deflator(void *arg)
2696{
plougher7b8ee502009-07-29 07:54:30 +00002697 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002698 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002699
2700 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2701 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2702
plougher13fdddf2010-11-24 01:23:41 +00002703 res = compressor_init(comp, &stream, block_size, 1);
2704 if(res)
2705 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2706
plougher5507dd92006-11-06 00:43:10 +00002707 while(1) {
2708 int c_byte, compressed_size;
2709 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002710 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002711 cache_get(writer_buffer, file_buffer->block +
2712 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002713
plougher13fdddf2010-11-24 01:23:41 +00002714 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002715 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002716 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002717 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002718 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002719 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002720 fragment_table[file_buffer->block].size = c_byte;
2721 fragment_table[file_buffer->block].start_block = bytes;
2722 write_buffer->block = bytes;
2723 bytes += compressed_size;
2724 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002725 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002726 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002727 TRACE("Writing fragment %lld, uncompressed size %d, "
2728 "compressed size %d\n", file_buffer->block,
2729 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002730 } else {
2731 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002732 add_pending_fragment(write_buffer, c_byte,
2733 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002734 }
ploughereb6eac92008-02-26 01:50:48 +00002735 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002736 }
2737}
2738
2739
2740#define HASH_ENTRIES 256
2741#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2742struct file_buffer *block_hash[HASH_ENTRIES];
2743
2744void push_buffer(struct file_buffer *file_buffer)
2745{
plougher0f464442008-03-31 00:27:56 +00002746 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002747
2748 file_buffer->next = block_hash[hash];
2749 block_hash[hash] = file_buffer;
2750}
2751
2752
2753struct file_buffer *get_file_buffer(struct queue *queue)
2754{
plougher0f464442008-03-31 00:27:56 +00002755 static unsigned int sequence = 0;
2756 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002757 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2758
2759 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002760 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002761 break;
2762
2763 if(file_buffer) {
2764 if(prev)
2765 prev->next = file_buffer->next;
2766 else
2767 block_hash[hash] = file_buffer->next;
2768 } else {
2769 while(1) {
2770 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002771 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002772 break;
2773 push_buffer(file_buffer);
2774 }
2775 }
2776
plougher0f464442008-03-31 00:27:56 +00002777 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002778
2779 return file_buffer;
2780}
2781
2782
plougher110799c2009-03-30 01:50:40 +00002783void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2784 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002785{
2786 file_count ++;
2787 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002788 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2789 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002790}
2791
2792
plougher50b31762009-03-31 04:14:46 +00002793void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2794 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002795 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002796{
plougher5507dd92006-11-06 00:43:10 +00002797 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002798 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002799 unsigned int *block_listp = NULL;
2800 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002801
plougher50b31762009-03-31 04:14:46 +00002802 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2803 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002804
plougher5507dd92006-11-06 00:43:10 +00002805 if(dupl_ptr) {
2806 *duplicate_file = FALSE;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002807 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002808 dupl_ptr->fragment = fragment;
2809 } else
2810 *duplicate_file = TRUE;
2811
ploughereb6eac92008-02-26 01:50:48 +00002812 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002813
2814 total_bytes += size;
2815 file_count ++;
2816
plougher35a10602008-04-21 02:58:16 +00002817 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002818
plougherc1ace522010-05-01 03:00:45 +00002819 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002820 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002821}
2822
2823
plougher110799c2009-03-30 01:50:40 +00002824void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2825 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002826{
2827 struct fragment *fragment;
2828 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002829
2830 checksum = get_checksum_mem_buffer(file_buffer);
2831
plougher29e37092007-04-15 01:24:51 +00002832 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002833 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2834 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002835 return;
2836 }
plougher5507dd92006-11-06 00:43:10 +00002837
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002838 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002839
ploughereb6eac92008-02-26 01:50:48 +00002840 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002841
2842 if(duplicate_checking)
2843 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2844
2845 total_bytes += size;
2846 file_count ++;
2847
2848 *duplicate_file = FALSE;
2849
plougher35a10602008-04-21 02:58:16 +00002850 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002851
plougherc1ace522010-05-01 03:00:45 +00002852 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002853 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002854
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002855 if(duplicate_checking == FALSE)
2856 free_fragment(fragment);
2857
plougher018d2b32007-04-23 03:01:48 +00002858 return;
plougher5507dd92006-11-06 00:43:10 +00002859}
2860
2861
plougher00d08172009-09-03 10:17:44 +00002862int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2863 struct file_buffer *read_buffer, int *duplicate_file)
2864{
2865 long long read_size, file_bytes, start;
2866 struct fragment *fragment;
2867 unsigned int *block_list = NULL;
2868 int block = 0, status;
2869 long long sparse = 0;
2870 struct file_buffer *fragment_buffer = NULL;
2871
2872 *duplicate_file = FALSE;
2873
2874 lock_fragments();
2875
2876 file_bytes = 0;
2877 start = bytes;
2878 while (1) {
2879 read_size = read_buffer->file_size;
2880 if(read_buffer->fragment && read_buffer->c_byte)
2881 fragment_buffer = read_buffer;
2882 else {
2883 block_list = realloc(block_list, (block + 1) *
2884 sizeof(unsigned int));
2885 if(block_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002886 MEM_ERROR();
plougher00d08172009-09-03 10:17:44 +00002887 block_list[block ++] = read_buffer->c_byte;
2888 if(read_buffer->c_byte) {
2889 read_buffer->block = bytes;
2890 bytes += read_buffer->size;
2891 cache_rehash(read_buffer, read_buffer->block);
2892 file_bytes += read_buffer->size;
2893 queue_put(to_writer, read_buffer);
2894 } else {
2895 sparse += read_buffer->size;
2896 cache_block_put(read_buffer);
2897 }
2898 }
plougher286b6b32009-09-19 03:29:27 +00002899 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002900
2901 if(read_size != -1)
2902 break;
2903
2904 read_buffer = get_file_buffer(from_deflate);
2905 if(read_buffer->error)
2906 goto read_err;
2907 }
2908
2909 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002910 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002911 cache_block_put(fragment_buffer);
2912
2913 if(duplicate_checking)
2914 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2915 0, 0, FALSE);
2916 file_count ++;
2917 total_bytes += read_size;
2918
plougherc1ace522010-05-01 03:00:45 +00002919 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2920 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002921
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002922 if(duplicate_checking == FALSE) {
plougher00d08172009-09-03 10:17:44 +00002923 free(block_list);
Phillip Lougherd2f045f2012-12-28 03:15:45 +00002924 free_fragment(fragment);
2925 }
plougher00d08172009-09-03 10:17:44 +00002926
2927 return 0;
2928
2929read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002930 dec_progress_bar(block);
plougher00d08172009-09-03 10:17:44 +00002931 status = read_buffer->error;
2932 bytes = start;
2933 if(!block_device) {
2934 int res;
2935
2936 queue_put(to_writer, NULL);
2937 if(queue_get(from_writer) != 0)
2938 EXIT_MKSQUASHFS();
2939 res = ftruncate(fd, bytes);
2940 if(res != 0)
2941 BAD_ERROR("Failed to truncate dest file because %s\n",
2942 strerror(errno));
2943 }
2944 unlock_fragments();
2945 free(block_list);
2946 cache_block_put(read_buffer);
2947 return status;
2948}
2949
2950
plougher110799c2009-03-30 01:50:40 +00002951int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002952 long long read_size, struct file_buffer *read_buffer,
2953 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002954{
plougher23377982007-11-12 04:04:48 +00002955 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002956 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002957 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002958 int block, status;
2959 int blocks = (read_size + block_size - 1) >> block_log;
2960 long long sparse = 0;
2961 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002962
plougher29e37092007-04-15 01:24:51 +00002963 *duplicate_file = FALSE;
2964
plougher87139622010-12-16 05:19:30 +00002965 block_list = malloc(blocks * sizeof(unsigned int));
2966 if(block_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00002967 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00002968
plougher2ea89142008-03-11 01:34:19 +00002969 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002970
plougher5507dd92006-11-06 00:43:10 +00002971 file_bytes = 0;
2972 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002973 for(block = 0; block < blocks;) {
2974 if(read_buffer->fragment && read_buffer->c_byte) {
Phillip Lougher2760d822013-01-13 21:14:06 +00002975 block_list[block] = 0;
plougher1b899fc2008-08-07 01:24:06 +00002976 fragment_buffer = read_buffer;
2977 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002978 } else {
plougher1b899fc2008-08-07 01:24:06 +00002979 block_list[block] = read_buffer->c_byte;
2980 if(read_buffer->c_byte) {
2981 read_buffer->block = bytes;
2982 bytes += read_buffer->size;
2983 cache_rehash(read_buffer, read_buffer->block);
2984 file_bytes += read_buffer->size;
2985 queue_put(to_writer, read_buffer);
2986 } else {
2987 sparse += read_buffer->size;
2988 cache_block_put(read_buffer);
2989 }
2990 }
2991 inc_progress_bar();
2992
2993 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002994 read_buffer = get_file_buffer(from_deflate);
2995 if(read_buffer->error)
2996 goto read_err;
2997 }
plougher1f413c82005-11-18 00:02:14 +00002998 }
2999
plougher2ea89142008-03-11 01:34:19 +00003000 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003001 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher1b899fc2008-08-07 01:24:06 +00003002 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003003
plougher1f413c82005-11-18 00:02:14 +00003004 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00003005 add_non_dup(read_size, file_bytes, block_list, start, fragment,
3006 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00003007 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00003008 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00003009
plougher360514a2009-03-30 03:01:38 +00003010 /*
3011 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003012 * a smaller block count on stat calls to sparse files. This is
3013 * to ensure intelligent applications like cp correctly handle the
3014 * file as a sparse file. If the file in the original filesystem isn't
3015 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003016 * report it as non-sparse on stat calls to preserve semantics
3017 */
plougher1b899fc2008-08-07 01:24:06 +00003018 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3019 sparse = 0;
3020
plougherc1ace522010-05-01 03:00:45 +00003021 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
3022 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003023
Phillip Lougherd2f045f2012-12-28 03:15:45 +00003024 if(duplicate_checking == FALSE) {
plougherf9c72b12006-01-23 13:52:40 +00003025 free(block_list);
Phillip Lougherd2f045f2012-12-28 03:15:45 +00003026 free_fragment(fragment);
3027 }
plougher29e37092007-04-15 01:24:51 +00003028
plougher018d2b32007-04-23 03:01:48 +00003029 return 0;
plougher1f413c82005-11-18 00:02:14 +00003030
3031read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003032 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00003033 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003034 bytes = start;
3035 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00003036 int res;
3037
plougher5507dd92006-11-06 00:43:10 +00003038 queue_put(to_writer, NULL);
3039 if(queue_get(from_writer) != 0)
3040 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003041 res = ftruncate(fd, bytes);
3042 if(res != 0)
3043 BAD_ERROR("Failed to truncate dest file because %s\n",
3044 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003045 }
plougher2ea89142008-03-11 01:34:19 +00003046 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00003047 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003048 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003049 return status;
plougher1f413c82005-11-18 00:02:14 +00003050}
3051
3052
plougher110799c2009-03-30 01:50:40 +00003053int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00003054 long long read_size, struct file_buffer *read_buffer,
3055 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003056{
plougher29e37092007-04-15 01:24:51 +00003057 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00003058 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00003059 struct fragment *fragment;
3060 struct file_info *dupl_ptr;
3061 int blocks = (read_size + block_size - 1) >> block_log;
3062 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00003063 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00003064 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00003065 long long sparse = 0;
3066 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00003067
plougher50b31762009-03-31 04:14:46 +00003068 block_list = malloc(blocks * sizeof(unsigned int));
3069 if(block_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003070 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00003071 block_listp = block_list;
3072
plougher50b31762009-03-31 04:14:46 +00003073 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
3074 if(buffer_list == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003075 MEM_ERROR();
plougher5507dd92006-11-06 00:43:10 +00003076
plougher4e8484a2008-03-15 23:30:16 +00003077 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003078
3079 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003080 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003081 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3082 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003083
3084 for(block = 0; block < blocks;) {
3085 if(read_buffer->fragment && read_buffer->c_byte) {
Phillip Lougher38cb1ab2013-01-13 21:20:09 +00003086 block_list[block] = 0;
Phillip Lougher19de5b62013-01-13 21:31:51 +00003087 buffer_list[block] = NULL;
plougher1b899fc2008-08-07 01:24:06 +00003088 fragment_buffer = read_buffer;
3089 blocks = read_size >> block_log;
3090 } else {
3091 block_list[block] = read_buffer->c_byte;
3092
3093 if(read_buffer->c_byte) {
3094 read_buffer->block = bytes;
3095 bytes += read_buffer->size;
3096 file_bytes += read_buffer->size;
3097 cache_rehash(read_buffer, read_buffer->block);
3098 if(block < thresh) {
3099 buffer_list[block] = NULL;
3100 queue_put(to_writer, read_buffer);
3101 } else
3102 buffer_list[block] = read_buffer;
3103 } else {
3104 buffer_list[block] = NULL;
3105 sparse += read_buffer->size;
3106 cache_block_put(read_buffer);
3107 }
3108 }
3109 inc_progress_bar();
3110
3111 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003112 read_buffer = get_file_buffer(from_deflate);
3113 if(read_buffer->error)
3114 goto read_err;
3115 }
plougher5507dd92006-11-06 00:43:10 +00003116 }
3117
plougher110799c2009-03-30 01:50:40 +00003118 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3119 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003120
3121 if(dupl_ptr) {
3122 *duplicate_file = FALSE;
3123 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003124 if(buffer_list[block])
3125 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003126 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00003127 dupl_ptr->fragment = fragment;
3128 } else {
3129 *duplicate_file = TRUE;
3130 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003131 cache_block_put(buffer_list[block]);
3132 bytes = start;
3133 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003134 int res;
3135
plougher1b899fc2008-08-07 01:24:06 +00003136 queue_put(to_writer, NULL);
3137 if(queue_get(from_writer) != 0)
3138 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003139 res = ftruncate(fd, bytes);
3140 if(res != 0)
3141 BAD_ERROR("Failed to truncate dest file because"
3142 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003143 }
plougher5507dd92006-11-06 00:43:10 +00003144 }
3145
plougher2ea89142008-03-11 01:34:19 +00003146 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003147 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003148 free(buffer_list);
3149 file_count ++;
3150 total_bytes += read_size;
3151
plougher360514a2009-03-30 03:01:38 +00003152 /*
3153 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003154 * a smaller block count on stat calls to sparse files. This is
3155 * to ensure intelligent applications like cp correctly handle the
3156 * file as a sparse file. If the file in the original filesystem isn't
3157 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003158 * report it as non-sparse on stat calls to preserve semantics
3159 */
plougher1b899fc2008-08-07 01:24:06 +00003160 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3161 sparse = 0;
3162
plougherc1ace522010-05-01 03:00:45 +00003163 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3164 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003165
plougher5507dd92006-11-06 00:43:10 +00003166 if(*duplicate_file == TRUE)
3167 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003168
plougher018d2b32007-04-23 03:01:48 +00003169 return 0;
plougher5507dd92006-11-06 00:43:10 +00003170
3171read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003172 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00003173 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003174 bytes = start;
3175 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003176 int res;
3177
plougher5507dd92006-11-06 00:43:10 +00003178 queue_put(to_writer, NULL);
3179 if(queue_get(from_writer) != 0)
3180 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003181 res = ftruncate(fd, bytes);
3182 if(res != 0)
3183 BAD_ERROR("Failed to truncate dest file because %s\n",
3184 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003185 }
plougher2ea89142008-03-11 01:34:19 +00003186 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003187 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003188 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003189 free(buffer_list);
3190 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003191 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003192 return status;
plougher5507dd92006-11-06 00:43:10 +00003193}
3194
3195
plougher110799c2009-03-30 01:50:40 +00003196void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3197 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003198{
plougher018d2b32007-04-23 03:01:48 +00003199 int status;
3200 struct file_buffer *read_buffer;
3201 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003202
plougher018d2b32007-04-23 03:01:48 +00003203again:
3204 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003205
plougher23377982007-11-12 04:04:48 +00003206 status = read_buffer->error;
3207 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003208 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003209 goto file_err;
3210 }
3211
3212 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003213
plougher00d08172009-09-03 10:17:44 +00003214 if(read_size == -1)
3215 status = write_file_process(inode, dir_ent, read_buffer,
3216 duplicate_file);
3217 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003218 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003219 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003220 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003221 write_file_frag(inode, dir_ent, read_size, read_buffer,
3222 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003223 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003224 status = write_file_blocks_dup(inode, dir_ent, read_size,
3225 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003226 else
plougher50b31762009-03-31 04:14:46 +00003227 status = write_file_blocks(inode, dir_ent, read_size,
3228 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003229
plougher018d2b32007-04-23 03:01:48 +00003230file_err:
3231 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003232 ERROR("File %s changed size while reading filesystem, "
Phillip Lougher494479f2012-02-03 15:45:41 +00003233 "attempting to re-read\n", pathname(dir_ent));
plougher018d2b32007-04-23 03:01:48 +00003234 goto again;
3235 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003236 ERROR("Failed to read file %s, creating empty file\n",
Phillip Lougher494479f2012-02-03 15:45:41 +00003237 pathname(dir_ent));
plougher29e37092007-04-15 01:24:51 +00003238 write_file_empty(inode, dir_ent, duplicate_file);
3239 }
plougher5507dd92006-11-06 00:43:10 +00003240}
3241
3242
Phillip Lougher3f81a772012-12-04 05:07:24 +00003243#define BUFF_SIZE 512
plougher1f413c82005-11-18 00:02:14 +00003244char *name;
3245char *basename_r();
3246
3247char *getbase(char *pathname)
3248{
Phillip Lougher3f81a772012-12-04 05:07:24 +00003249 static char *b_buffer = NULL;
3250 static int b_size = BUFF_SIZE;
plougher1f413c82005-11-18 00:02:14 +00003251 char *result;
3252
Phillip Lougher3f81a772012-12-04 05:07:24 +00003253 if(b_buffer == NULL) {
3254 b_buffer = malloc(b_size);
3255 if(b_buffer == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003256 MEM_ERROR();
Phillip Lougher3f81a772012-12-04 05:07:24 +00003257 }
3258
3259 while(1) {
3260 if(*pathname != '/') {
3261 result = getcwd(b_buffer, b_size);
3262 if(result == NULL && errno != ERANGE)
3263 BAD_ERROR("Getcwd failed in getbase\n");
3264
3265 /* enough room for pathname + "/" + '\0' terminator? */
3266 if(result && strlen(pathname) + 2 <=
3267 b_size - strlen(b_buffer)) {
3268 strcat(strcat(b_buffer, "/"), pathname);
3269 break;
3270 }
3271 } else if(strlen(pathname) < b_size) {
3272 strcpy(b_buffer, pathname);
3273 break;
3274 }
3275
3276 /* Buffer not large enough, realloc and try again */
3277 b_buffer = realloc(b_buffer, b_size += BUFF_SIZE);
3278 if(b_buffer == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003279 MEM_ERROR();
Phillip Lougher3f81a772012-12-04 05:07:24 +00003280 }
3281
plougher1f413c82005-11-18 00:02:14 +00003282 name = b_buffer;
3283 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3284 return NULL;
3285 else
3286 return result;
3287}
3288
3289
3290char *basename_r()
3291{
3292 char *s;
3293 char *p;
3294 int n = 1;
3295
3296 for(;;) {
3297 s = name;
3298 if(*name == '\0')
3299 return NULL;
3300 if(*name != '/') {
3301 while(*name != '\0' && *name != '/') name++;
3302 n = name - s;
3303 }
3304 while(*name == '/') name++;
3305 if(strncmp(s, ".", n) == 0)
3306 continue;
plougher110799c2009-03-30 01:50:40 +00003307 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3308 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003309 s[n] = '\0';
3310 return s;
3311 }
3312 if(strcmp(p, "..") == 0)
3313 continue;
3314 return p;
3315 }
3316}
3317
3318
Phillip Lougher81204c22012-07-25 03:30:30 +01003319struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
plougher1f413c82005-11-18 00:02:14 +00003320{
Phillip Lougherd6577802012-10-04 19:14:33 +01003321 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3322 struct inode_info *inode;
plougher1f413c82005-11-18 00:02:14 +00003323
Phillip Lougherd6577802012-10-04 19:14:33 +01003324 /*
3325 * Look-up inode in hash table, if it already exists we have a
3326 * hard-link, so increment the nlink count and return it.
3327 * Don't do the look-up for directories because we don't hard-link
3328 * directories.
3329 */
3330 if ((buf->st_mode & S_IFMT) != S_IFDIR) {
3331 for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
3332 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3333 inode->nlink ++;
3334 return inode;
3335 }
plougher1f413c82005-11-18 00:02:14 +00003336 }
plougher1f413c82005-11-18 00:02:14 +00003337 }
3338
plougher288f6852010-12-16 05:22:55 +00003339 inode = malloc(sizeof(struct inode_info));
3340 if(inode == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003341 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00003342
3343 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003344 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003345 inode->root_entry = FALSE;
Phillip Lougher81204c22012-07-25 03:30:30 +01003346 inode->pseudo_file = pseudo;
3347 inode->pseudo_id = id;
plougher1f413c82005-11-18 00:02:14 +00003348 inode->inode = SQUASHFS_INVALID_BLK;
3349 inode->nlink = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003350 inode->inode_number = 0;
plougherdc86c3c2007-12-05 02:15:10 +00003351
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003352 /*
3353 * Copy filesystem wide defaults into inode, these filesystem
3354 * wide defaults may be altered on an individual inode basis by
3355 * user specified actions
3356 *
3357 */
3358 inode->no_fragments = no_fragments;
3359 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003360 inode->noD = noD;
3361 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003362
plougherdc86c3c2007-12-05 02:15:10 +00003363 if((buf->st_mode & S_IFMT) == S_IFREG)
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003364 progress_bar_size((buf->st_size + block_size - 1) >> block_log);
plougherdc86c3c2007-12-05 02:15:10 +00003365
Phillip Lougherd6577802012-10-04 19:14:33 +01003366 inode->next = inode_info[ino_hash];
3367 inode_info[ino_hash] = inode;
plougher1f413c82005-11-18 00:02:14 +00003368
3369 return inode;
3370}
3371
3372
Phillip Lougher81204c22012-07-25 03:30:30 +01003373inline struct inode_info *lookup_inode(struct stat *buf)
3374{
3375 return lookup_inode2(buf, 0, 0);
3376}
3377
3378
Phillip Lougher539c2b12012-07-30 20:14:52 +01003379inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3380{
3381 if (inode->inode_number == 0)
3382 inode->inode_number = use_this ? : inode_no ++;
3383}
3384
3385
Phillip Lougher494479f2012-02-03 15:45:41 +00003386inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3387 char *nonstandard_pathname, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003388{
Phillip Lougher494479f2012-02-03 15:45:41 +00003389 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3390 if(dir_ent == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003391 MEM_ERROR();
Phillip Lougher494479f2012-02-03 15:45:41 +00003392
3393 dir_ent->name = name;
3394 dir_ent->source_name = source_name;
3395 dir_ent->nonstandard_pathname = nonstandard_pathname;
3396 dir_ent->our_dir = dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003397 dir_ent->next = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003398
3399 return dir_ent;
3400}
3401
3402
3403inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3404 struct inode_info *inode_info)
3405{
3406 struct dir_info *dir = dir_ent->our_dir;
3407
plougher1f413c82005-11-18 00:02:14 +00003408 if(sub_dir)
Phillip Lougher494479f2012-02-03 15:45:41 +00003409 sub_dir->dir_ent = dir_ent;
3410 dir_ent->inode = inode_info;
3411 dir_ent->dir = sub_dir;
3412
Phillip Lougherbf338362012-08-22 05:24:36 +01003413 dir_ent->next = dir->list;
3414 dir->list = dir_ent;
3415 dir->count++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003416}
3417
3418
3419inline void add_dir_entry2(char *name, char *source_name,
3420 char *nonstandard_pathname, struct dir_info *sub_dir,
3421 struct inode_info *inode_info, struct dir_info *dir)
3422{
3423 struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3424 nonstandard_pathname, dir);
3425
3426
3427 add_dir_entry(dir_ent, sub_dir, inode_info);
plougher1f413c82005-11-18 00:02:14 +00003428}
3429
3430
Phillip Lougher10a4b572012-02-18 23:26:10 +00003431inline void free_dir_entry(struct dir_ent *dir_ent)
3432{
Phillip Loughereb92b192012-10-01 03:39:00 +01003433 if(dir_ent->name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003434 free(dir_ent->name);
3435
Phillip Loughereb92b192012-10-01 03:39:00 +01003436 if(dir_ent->source_name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003437 free(dir_ent->source_name);
3438
3439 free(dir_ent);
3440}
3441
3442
Phillip Lougherad0f9212011-12-31 00:55:51 +00003443inline void add_excluded(struct dir_info *dir)
3444{
3445 dir->excluded ++;
3446}
3447
3448
plougher1f413c82005-11-18 00:02:14 +00003449
Phillip Lougherabc3b492012-07-29 02:53:35 +01003450void dir_scan(squashfs_inode *inode, char *pathname,
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00003451 struct dir_ent *(_readdir)(struct dir_info *))
Phillip Lougherabc3b492012-07-29 02:53:35 +01003452{
3453 struct stat buf;
3454 struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
3455 struct dir_ent *dir_ent;
3456
3457 if(dir_info == NULL)
3458 return;
3459
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003460 /*
3461 * Process most actions and any pseudo files
3462 */
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00003463 if(actions() || get_pseudo())
3464 dir_scan2(dir_info, get_pseudo());
Phillip Lougherf3d0f9c2012-11-14 05:36:58 +00003465
Phillip Loughere92cb512012-11-15 02:22:28 +00003466 /*
3467 * Process move actions
3468 */
3469 if(move_actions()) {
3470 dir_scan3(dir_info, dir_info);
3471 do_move_actions();
3472 }
3473
Phillip Lougher71ae14e2012-11-15 02:27:50 +00003474 /*
3475 * Process empty actions
3476 */
3477 if(empty_actions())
3478 dir_scan4(dir_info);
3479
Phillip Loughereb69dad2012-11-15 03:34:02 +00003480 /*
3481 * Sort directories and compute the inode numbers
3482 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003483 dir_scan5(dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003484
Phillip Lougherd0fe1d52012-10-09 03:34:34 +01003485 dir_ent = create_dir_entry("", NULL, pathname,
Phillip Lougher1eae83d2012-09-26 02:12:45 +01003486 scan1_opendir("", "", 0));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003487
3488 if(pathname[0] == '\0') {
3489 /*
3490 * dummy top level directory, if multiple sources specified on
3491 * command line
3492 */
3493 memset(&buf, 0, sizeof(buf));
3494 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3495 buf.st_uid = getuid();
3496 buf.st_gid = getgid();
3497 buf.st_mtime = time(NULL);
3498 buf.st_dev = 0;
3499 buf.st_ino = 0;
3500 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3501 } else {
Phillip Lougher38a35ec2012-11-30 04:31:35 +00003502 if(lstat(pathname, &buf) == -1)
3503 /* source directory has disappeared? */
Phillip Lougherfe58b492012-12-15 01:27:07 +00003504 BAD_ERROR("Cannot stat source directory %s because %s\n",
Phillip Lougherabc3b492012-07-29 02:53:35 +01003505 pathname, strerror(errno));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003506 dir_ent->inode = lookup_inode(&buf);
3507 }
3508
Phillip Lougher539c2b12012-07-30 20:14:52 +01003509 alloc_inode_no(dir_ent->inode, root_inode_number);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003510 dir_ent->dir = dir_info;
3511 dir_info->dir_ent = dir_ent;
3512
Andy Lutomirski3f31dcf2012-09-21 18:08:08 -07003513 eval_actions(dir_ent);
3514
Phillip Lougher19b877d2013-02-23 11:15:38 +00003515 if(sorted)
3516 generate_file_priorities(dir_info, 0,
Phillip Lougherabc3b492012-07-29 02:53:35 +01003517 &dir_info->dir_ent->inode->buf);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003518 queue_put(to_reader, dir_info);
3519 if(sorted)
3520 sort_files_and_write(dir_info);
3521 if(progress)
3522 enable_progress_bar();
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003523 dir_scan6(inode, dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003524 dir_ent->inode->inode = *inode;
3525 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003526}
3527
3528
Phillip Lougherabc3b492012-07-29 02:53:35 +01003529/*
3530 * dir_scan1 routines...
Phillip Loughere8630be2012-11-11 02:24:24 +00003531 * These scan the source directories into memory for processing.
3532 * Exclude actions are processed here (in contrast to the other actions)
3533 * because they affect what is scanned.
Phillip Lougherabc3b492012-07-29 02:53:35 +01003534 */
Phillip Lougherb38c1722012-02-09 23:26:19 +00003535struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
plougher1f413c82005-11-18 00:02:14 +00003536{
plougher1f413c82005-11-18 00:02:14 +00003537 struct dir_info *dir;
3538
plougher6da792b2010-12-16 05:25:39 +00003539 dir = malloc(sizeof(struct dir_info));
3540 if(dir == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00003541 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00003542
Phillip Lougher04ef2442013-01-09 06:03:50 +00003543 if(pathname[0] != '\0') {
3544 dir->linuxdir = opendir(pathname);
3545 if(dir->linuxdir == NULL) {
3546 free(dir);
3547 return NULL;
3548 }
plougher1f413c82005-11-18 00:02:14 +00003549 }
Phillip Lougher04ef2442013-01-09 06:03:50 +00003550
Phillip Lougher3cb5d6c2013-01-09 05:50:29 +00003551 dir->pathname = strdup(pathname);
3552 dir->subpath = strdup(subpath);
Phillip Lougherded70fa2011-12-25 02:14:58 +00003553 dir->count = 0;
3554 dir->directory_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003555 dir->dir_is_ldir = TRUE;
3556 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003557 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003558 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003559
3560 return dir;
3561}
3562
3563
Phillip Lougher494479f2012-02-03 15:45:41 +00003564struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003565{
plougher1f413c82005-11-18 00:02:14 +00003566 static int index = 0;
3567
plougher11266ba2010-12-16 05:34:30 +00003568 if(dir->count < old_root_entries) {
3569 int i;
3570
plougher1f413c82005-11-18 00:02:14 +00003571 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003572 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003573 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003574 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003575 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003576 }
plougher11266ba2010-12-16 05:34:30 +00003577 }
plougher1f413c82005-11-18 00:02:14 +00003578
3579 while(index < source) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003580 char *basename = NULL;
3581 char *dir_name = getbase(source_path[index]);
Phillip Lougherbf338362012-08-22 05:24:36 +01003582 int pass = 1, res;
plougher89fe2c72010-12-16 05:31:34 +00003583
Phillip Lougherc73ed322012-10-01 03:25:41 +01003584 if(dir_name == NULL) {
plougher110799c2009-03-30 01:50:40 +00003585 ERROR("Bad source directory %s - skipping ...\n",
3586 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003587 index ++;
3588 continue;
3589 }
Phillip Lougherc73ed322012-10-01 03:25:41 +01003590 dir_name = strdup(dir_name);
plougher1f413c82005-11-18 00:02:14 +00003591 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003592 struct dir_ent *dir_ent = dir->list;
3593
3594 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3595 dir_ent = dir_ent->next);
3596 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003597 break;
plougher50b31762009-03-31 04:14:46 +00003598 ERROR("Source directory entry %s already used! - trying"
3599 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003600 if(pass == 1)
3601 basename = dir_name;
3602 else
Phillip Lougherb38c1722012-02-09 23:26:19 +00003603 free(dir_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003604 res = asprintf(&dir_name, "%s_%d", basename, pass++);
3605 if(res == -1)
3606 BAD_ERROR("asprintf failed in "
3607 "scan1_encomp_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003608 ERROR("%s\n", dir_name);
3609 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00003610 return create_dir_entry(dir_name, basename,
3611 source_path[index ++], dir);
plougher1f413c82005-11-18 00:02:14 +00003612 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003613 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003614}
3615
3616
Phillip Lougher494479f2012-02-03 15:45:41 +00003617struct dir_ent *scan1_single_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003618{
3619 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003620 int i;
plougher1f413c82005-11-18 00:02:14 +00003621
plougher4925e172010-12-16 05:45:54 +00003622 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003623 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003624 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003625 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003626 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003627 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003628 }
plougher4925e172010-12-16 05:45:54 +00003629 }
plougher1f413c82005-11-18 00:02:14 +00003630
3631 if((d_name = readdir(dir->linuxdir)) != NULL) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003632 char *basename = NULL;
3633 char *dir_name = strdup(d_name->d_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003634 int pass = 1, res;
plougher4925e172010-12-16 05:45:54 +00003635
plougher1f413c82005-11-18 00:02:14 +00003636 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003637 struct dir_ent *dir_ent = dir->list;
3638
3639 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3640 dir_ent = dir_ent->next);
3641 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003642 break;
plougher50b31762009-03-31 04:14:46 +00003643 ERROR("Source directory entry %s already used! - trying"
3644 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003645 if (pass == 1)
3646 basename = dir_name;
3647 else
Phillip Lougher494479f2012-02-03 15:45:41 +00003648 free(dir_name);
3649 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3650 if(res == -1)
3651 BAD_ERROR("asprintf failed in "
3652 "scan1_single_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003653 ERROR("%s\n", dir_name);
3654 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003655 return create_dir_entry(dir_name, basename, NULL, dir);
plougher1f413c82005-11-18 00:02:14 +00003656 }
3657
Phillip Lougher494479f2012-02-03 15:45:41 +00003658 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003659}
3660
3661
Phillip Lougher494479f2012-02-03 15:45:41 +00003662struct dir_ent *scan1_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003663{
plougher480d9bf2010-12-18 02:28:39 +00003664 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003665
Phillip Lougher494479f2012-02-03 15:45:41 +00003666 return d_name ?
3667 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3668 NULL;
plougher1f413c82005-11-18 00:02:14 +00003669}
3670
3671
plougher1f413c82005-11-18 00:02:14 +00003672void scan1_freedir(struct dir_info *dir)
3673{
plougherfbed12b2006-02-07 12:45:53 +00003674 if(dir->pathname[0] != '\0')
3675 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003676}
3677
3678
Phillip Lougherb38c1722012-02-09 23:26:19 +00003679struct dir_info *dir_scan1(char *filename, char *subpath,
3680 struct pathnames *paths,
Phillip Lougher494479f2012-02-03 15:45:41 +00003681 struct dir_ent *(_readdir)(struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003682{
Phillip Lougherb38c1722012-02-09 23:26:19 +00003683 struct dir_info *dir = scan1_opendir(filename, subpath, depth);
Phillip Lougher494479f2012-02-03 15:45:41 +00003684 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003685
plougher360b6e42010-12-18 02:40:28 +00003686 if(dir == NULL) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003687 ERROR("Could not open %s, skipping...\n", filename);
Phillip Lougher87db5672013-01-09 05:40:46 +00003688 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003689 }
3690
Phillip Lougher494479f2012-02-03 15:45:41 +00003691 while((dir_ent = _readdir(dir))) {
plougher360b6e42010-12-18 02:40:28 +00003692 struct dir_info *sub_dir;
3693 struct stat buf;
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00003694 struct pathnames *new = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003695 char *filename = pathname(dir_ent);
Phillip Lougher651d68d2013-01-13 05:38:13 +00003696 char *subpath = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003697 char *dir_name = dir_ent->name;
plougher1f413c82005-11-18 00:02:14 +00003698
Phillip Lougher494479f2012-02-03 15:45:41 +00003699 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003700 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003701 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003702 }
plougher1f413c82005-11-18 00:02:14 +00003703
3704 if(lstat(filename, &buf) == -1) {
Phillip Lougherfe58b492012-12-15 01:27:07 +00003705 ERROR("Cannot stat dir/file %s because %s, ignoring\n",
plougher110799c2009-03-30 01:50:40 +00003706 filename, strerror(errno));
Phillip Lougher10a4b572012-02-18 23:26:10 +00003707 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003708 continue;
3709 }
plougher29e37092007-04-15 01:24:51 +00003710
3711 if((buf.st_mode & S_IFMT) != S_IFREG &&
Phillip Loughere4ff36a2012-11-19 01:34:47 +00003712 (buf.st_mode & S_IFMT) != S_IFDIR &&
3713 (buf.st_mode & S_IFMT) != S_IFLNK &&
3714 (buf.st_mode & S_IFMT) != S_IFCHR &&
3715 (buf.st_mode & S_IFMT) != S_IFBLK &&
3716 (buf.st_mode & S_IFMT) != S_IFIFO &&
3717 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003718 ERROR("File %s has unrecognised filetype %d, ignoring"
3719 "\n", filename, buf.st_mode & S_IFMT);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003720 free_dir_entry(dir_ent);
plougher29e37092007-04-15 01:24:51 +00003721 continue;
3722 }
3723
Phillip Lougherad0f9212011-12-31 00:55:51 +00003724 if((old_exclude && old_excluded(filename, &buf)) ||
Phillip Lougher651d68d2013-01-13 05:38:13 +00003725 (!old_exclude && excluded(dir_name, paths, &new))) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003726 add_excluded(dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003727 free_dir_entry(dir_ent);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003728 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003729 }
plougher1f413c82005-11-18 00:02:14 +00003730
Phillip Lougher651d68d2013-01-13 05:38:13 +00003731 if(exclude_actions()) {
3732 subpath = subpathname(dir_ent);
3733
3734 if(eval_exclude_actions(dir_name, filename, subpath,
3735 &buf, depth)) {
3736 add_excluded(dir);
3737 free_dir_entry(dir_ent);
3738 continue;
3739 }
3740 }
3741
plougher1f413c82005-11-18 00:02:14 +00003742 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher651d68d2013-01-13 05:38:13 +00003743 if(subpath == NULL)
3744 subpath = subpathname(dir_ent);
3745
Phillip Lougherb38c1722012-02-09 23:26:19 +00003746 sub_dir = dir_scan1(filename, subpath, new,
3747 scan1_readdir, depth + 1);
Phillip Lougher494479f2012-02-03 15:45:41 +00003748 if(sub_dir == NULL) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003749 free_dir_entry(dir_ent);
Phillip Lougher205c1e02013-01-07 01:37:56 +00003750 free(new);
plougher1f413c82005-11-18 00:02:14 +00003751 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003752 }
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003753
plougher1f413c82005-11-18 00:02:14 +00003754 dir->directory_count ++;
3755 } else
3756 sub_dir = NULL;
3757
Phillip Lougher494479f2012-02-03 15:45:41 +00003758 add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
Phillip Lougher205c1e02013-01-07 01:37:56 +00003759 free(new);
plougher1f413c82005-11-18 00:02:14 +00003760 }
3761
3762 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003763
plougher1f413c82005-11-18 00:02:14 +00003764 return dir;
3765}
3766
plougher2ea89142008-03-11 01:34:19 +00003767
Phillip Lougherabc3b492012-07-29 02:53:35 +01003768/*
3769 * dir_scan2 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003770 * This processes most actions and any pseudo files
Phillip Lougherabc3b492012-07-29 02:53:35 +01003771 */
Phillip Lougherbf338362012-08-22 05:24:36 +01003772struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003773{
Phillip Lougherbf338362012-08-22 05:24:36 +01003774 if (dir_ent == NULL)
3775 dir_ent = dir->list;
3776 else
3777 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003778
Phillip Lougherbf338362012-08-22 05:24:36 +01003779 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3780
3781 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003782}
3783
3784
3785struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3786{
Phillip Lougherbf338362012-08-22 05:24:36 +01003787 struct dir_ent *dir_ent = dir->list;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003788
Phillip Lougherbf338362012-08-22 05:24:36 +01003789 for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3790 dir_ent = dir_ent->next);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003791
Phillip Lougherbf338362012-08-22 05:24:36 +01003792 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003793}
3794
3795
Phillip Lougher24eeb772012-10-13 01:56:24 +01003796void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
plougher43244f22009-04-05 02:04:51 +00003797{
Phillip Lougherbf338362012-08-22 05:24:36 +01003798 struct dir_ent *dir_ent = NULL;
plougher43244f22009-04-05 02:04:51 +00003799 struct pseudo_entry *pseudo_ent;
3800 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003801 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003802
Phillip Lougherbf338362012-08-22 05:24:36 +01003803 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
plougher43244f22009-04-05 02:04:51 +00003804 struct inode_info *inode_info = dir_ent->inode;
3805 struct stat *buf = &inode_info->buf;
3806 char *name = dir_ent->name;
3807
Phillip Lougher89d757c2011-09-20 00:33:19 +01003808 eval_actions(dir_ent);
3809
plougher43244f22009-04-05 02:04:51 +00003810 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher24eeb772012-10-13 01:56:24 +01003811 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
plougher43244f22009-04-05 02:04:51 +00003812 }
3813
3814 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3815 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003816 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003817 struct stat *buf;
3818 if(dir_ent == NULL) {
plougherdcd66c52010-09-17 03:44:17 +00003819 ERROR("Pseudo modify file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003820 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003821 pseudo_ent->pathname);
3822 continue;
3823 }
ploughera326c182009-08-29 05:41:45 +00003824 if(dir_ent->inode->root_entry) {
plougherdcd66c52010-09-17 03:44:17 +00003825 ERROR("Pseudo modify file \"%s\" is a pre-existing"
plougherb34f9f62009-04-26 02:08:42 +00003826 " file in the filesystem being appended"
3827 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003828 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003829 continue;
3830 }
3831 buf = &dir_ent->inode->buf;
3832 buf->st_mode = (buf->st_mode & S_IFMT) |
3833 pseudo_ent->dev->mode;
3834 buf->st_uid = pseudo_ent->dev->uid;
3835 buf->st_gid = pseudo_ent->dev->gid;
3836 continue;
3837 }
3838
plougher43244f22009-04-05 02:04:51 +00003839 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003840 if(dir_ent->inode->root_entry)
3841 ERROR("Pseudo file \"%s\" is a pre-existing"
3842 " file in the filesystem being appended"
3843 " to. Ignoring.\n",
3844 pseudo_ent->pathname);
3845 else
3846 ERROR("Pseudo file \"%s\" exists in source "
plougherdcd66c52010-09-17 03:44:17 +00003847 "filesystem \"%s\".\nIgnoring, "
plougherf0dc2382010-05-01 23:55:06 +00003848 "exclude it (-e/-ef) to override.\n",
3849 pseudo_ent->pathname,
Phillip Lougher494479f2012-02-03 15:45:41 +00003850 pathname(dir_ent));
plougher43244f22009-04-05 02:04:51 +00003851 continue;
3852 }
3853
plougher43244f22009-04-05 02:04:51 +00003854 memset(&buf, 0, sizeof(buf));
3855 buf.st_mode = pseudo_ent->dev->mode;
3856 buf.st_uid = pseudo_ent->dev->uid;
3857 buf.st_gid = pseudo_ent->dev->gid;
3858 buf.st_rdev = makedev(pseudo_ent->dev->major,
3859 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003860 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003861 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003862
Phillip Lougher5d579292012-10-13 01:37:16 +01003863 if(pseudo_ent->dev->type == 'd') {
3864 struct dir_ent *dir_ent =
3865 create_dir_entry(pseudo_ent->name, NULL,
3866 pseudo_ent->pathname, dir);
3867 char *subpath = strdup(subpathname(dir_ent));
3868 struct dir_info *sub_dir = scan1_opendir("", subpath,
Phillip Lougher24eeb772012-10-13 01:56:24 +01003869 dir->depth + 1);
Phillip Lougher5d579292012-10-13 01:37:16 +01003870 if(sub_dir == NULL) {
3871 ERROR("Could not create pseudo directory \"%s\""
3872 ", skipping...\n",
3873 pseudo_ent->pathname);
3874 free(subpath);
3875 pseudo_ino --;
3876 continue;
3877 }
Phillip Lougher24eeb772012-10-13 01:56:24 +01003878 dir_scan2(sub_dir, pseudo_ent->pseudo);
Phillip Lougher5d579292012-10-13 01:37:16 +01003879 dir->directory_count ++;
3880 add_dir_entry(dir_ent, sub_dir,
3881 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3882 } else if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003883#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003884 struct stat buf2;
3885 int res = stat(pseudo_ent->dev->filename, &buf2);
3886 if(res == -1) {
3887 ERROR("Stat on pseudo file \"%s\" failed, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00003888 "skipping...\n", pseudo_ent->pathname);
Phillip Lougher5d579292012-10-13 01:37:16 +01003889 pseudo_ino --;
plougher4ab7e512009-05-05 02:35:58 +00003890 continue;
3891 }
3892 buf.st_size = buf2.st_size;
Phillip Lougher494479f2012-02-03 15:45:41 +00003893 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003894 pseudo_ent->dev->filename, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003895 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougher00d08172009-09-03 10:17:44 +00003896#else
Phillip Lougher494479f2012-02-03 15:45:41 +00003897 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003898 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003899 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3900 pseudo_ent->dev->pseudo_id), dir);
plougher00d08172009-09-03 10:17:44 +00003901#endif
plougherb85e9ad2010-05-02 01:46:12 +00003902 } else {
Phillip Lougher494479f2012-02-03 15:45:41 +00003903 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003904 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003905 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003906 }
plougher43244f22009-04-05 02:04:51 +00003907 }
plougher43244f22009-04-05 02:04:51 +00003908}
3909
3910
Phillip Lougherabc3b492012-07-29 02:53:35 +01003911/*
3912 * dir_scan3 routines...
Phillip Lougher23d83622012-10-14 02:35:22 +01003913 * This processes the move action
3914 */
3915void dir_scan3(struct dir_info *root, struct dir_info *dir)
3916{
3917 struct dir_ent *dir_ent = NULL;
3918
3919 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3920
3921 eval_move_actions(root, dir_ent);
3922
3923 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3924 dir_scan3(root, dir_ent->dir);
3925 }
3926}
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003927
3928
Phillip Lougher23d83622012-10-14 02:35:22 +01003929/*
3930 * dir_scan4 routines...
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003931 * This processes the empty action. This action has to be processed after
3932 * all other actions because the previous exclude and move actions and the
3933 * pseudo actions affect whether a directory is empty
3934 */
3935void dir_scan4(struct dir_info *dir)
3936{
3937 struct dir_ent *dir_ent = dir->list, *prev = NULL;
3938
3939 while(dir_ent) {
Phillip Lougher15e8f042012-11-16 00:57:39 +00003940 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3941 dir_scan4(dir_ent->dir);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003942
Phillip Lougher15e8f042012-11-16 00:57:39 +00003943 if(eval_empty_actions(dir_ent)) {
3944 struct dir_ent *tmp = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003945
Phillip Lougher15e8f042012-11-16 00:57:39 +00003946 /*
3947 * delete sub-directory, this is by definition
3948 * empty
3949 */
3950 free(dir_ent->dir->pathname);
3951 free(dir_ent->dir->subpath);
3952 free(dir_ent->dir);
3953
3954 /* remove dir_ent from list */
3955 dir_ent = dir_ent->next;
3956 if(prev)
3957 prev->next = dir_ent;
3958 else
3959 dir->list = dir_ent;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003960
Phillip Lougher15e8f042012-11-16 00:57:39 +00003961 /* free it */
3962 free_dir_entry(tmp);
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003963
Phillip Lougher15e8f042012-11-16 00:57:39 +00003964 /* update counts */
3965 dir->directory_count --;
3966 dir->count --;
3967 add_excluded(dir);
3968 continue;
3969 }
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003970 }
Phillip Lougher15e8f042012-11-16 00:57:39 +00003971
3972 prev = dir_ent;
3973 dir_ent = dir_ent->next;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00003974 }
3975}
3976
3977
3978/*
3979 * dir_scan5 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003980 * This sorts every directory and computes the inode numbers
3981 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003982
Phillip Lougher242242e2012-08-24 04:15:36 +01003983/*
3984 * Bottom up linked list merge sort.
3985 *
3986 * Qsort and other O(n log n) algorithms work well with arrays but not
3987 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand
3988 * is not ideal for arrays (as it needs an additonal n storage locations
3989 * as sorting is not done in place), but it is ideal for linked lists because
3990 * it doesn't require any extra storage,
3991 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003992void sort_directory(struct dir_info *dir)
3993{
Phillip Lougher242242e2012-08-24 04:15:36 +01003994 struct dir_ent *cur, *l1, *l2, *next;
3995 int len1, len2, stride = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003996
Phillip Lougher242242e2012-08-24 04:15:36 +01003997 if(dir->count < 2)
Phillip Lougherbf338362012-08-22 05:24:36 +01003998 return;
3999
Phillip Lougher242242e2012-08-24 04:15:36 +01004000 /*
4001 * We can consider our linked-list to be made up of stride length
4002 * sublists. Eacn iteration around this loop merges adjacent
4003 * stride length sublists into larger 2*stride sublists. We stop
4004 * when stride becomes equal to the entire list.
4005 *
4006 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
4007 * these 1 element sublists are merged into 2 element sublists, which
4008 * are then merged into 4 element sublists and so on.
4009 */
4010 do {
4011 l2 = dir->list; /* head of current linked list */
4012 cur = NULL; /* empty output list */
Phillip Lougherbf338362012-08-22 05:24:36 +01004013
Phillip Lougher242242e2012-08-24 04:15:36 +01004014 /*
4015 * Iterate through the linked list, merging adjacent sublists.
4016 * On each interation l2 points to the next sublist pair to be
4017 * merged (if there's only one sublist left this is simply added
4018 * to the output list)
4019 */
4020 while(l2) {
4021 l1 = l2;
4022 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
4023 len2 = stride;
Phillip Lougherbf338362012-08-22 05:24:36 +01004024
Phillip Lougher242242e2012-08-24 04:15:36 +01004025 /*
4026 * l1 points to first sublist.
4027 * l2 points to second sublist.
4028 * Merge them onto the output list
4029 */
4030 while(len1 && l2 && len2) {
4031 if(strcmp(l1->name, l2->name) <= 0) {
4032 next = l1;
4033 l1 = l1->next;
4034 len1 --;
4035 } else {
4036 next = l2;
4037 l2 = l2->next;
4038 len2 --;
4039 }
4040
4041 if(cur) {
4042 cur->next = next;
4043 cur = next;
4044 } else
4045 dir->list = cur = next;
4046 }
4047 /*
4048 * One sublist is now empty, copy the other one onto the
4049 * output list
4050 */
4051 for(; len1; len1 --, l1 = l1->next) {
4052 if(cur) {
4053 cur->next = l1;
4054 cur = l1;
4055 } else
4056 dir->list = cur = l1;
4057 }
4058 for(; l2 && len2; len2 --, l2 = l2->next) {
4059 if(cur) {
4060 cur->next = l2;
4061 cur = l2;
4062 } else
4063 dir->list = cur = l2;
4064 }
4065 }
4066 cur->next = NULL;
4067 stride = stride << 1;
4068 } while(stride < dir->count);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004069}
4070
4071
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004072void dir_scan5(struct dir_info *dir)
Phillip Lougher539c2b12012-07-30 20:14:52 +01004073{
Phillip Lougher23d83622012-10-14 02:35:22 +01004074 struct dir_ent *dir_ent;
4075 unsigned int byte_count = 0;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004076
4077 sort_directory(dir);
4078
Phillip Lougher23d83622012-10-14 02:35:22 +01004079 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
4080 byte_count += strlen(dir_ent->name) +
4081 sizeof(struct squashfs_dir_entry);
4082
4083 if(dir_ent->inode->root_entry)
4084 continue;
4085
Phillip Lougher539c2b12012-07-30 20:14:52 +01004086 alloc_inode_no(dir_ent->inode, 0);
Phillip Lougher23d83622012-10-14 02:35:22 +01004087
Phillip Lougher539c2b12012-07-30 20:14:52 +01004088 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
Phillip Loughere69b5882012-11-19 01:31:09 +00004089 dir_scan5(dir_ent->dir);
Phillip Lougher539c2b12012-07-30 20:14:52 +01004090 }
Phillip Lougher23d83622012-10-14 02:35:22 +01004091
4092 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
4093 dir->dir_is_ldir = FALSE;
Phillip Lougher539c2b12012-07-30 20:14:52 +01004094}
4095
4096
4097/*
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004098 * dir_scan6 routines...
Phillip Lougherabc3b492012-07-29 02:53:35 +01004099 * This generates the filesystem metadata and writes it out to the destination
4100 */
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004101void scan6_init_dir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004102{
4103 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004104 if(dir->buff == NULL)
4105 MEM_ERROR();
Phillip Lougherabc3b492012-07-29 02:53:35 +01004106
4107 dir->size = SQUASHFS_METADATA_SIZE;
4108 dir->p = dir->index_count_p = dir->buff;
4109 dir->entry_count = 256;
4110 dir->entry_count_p = NULL;
4111 dir->index = NULL;
4112 dir->i_count = dir->i_size = 0;
4113}
4114
4115
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004116struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
Phillip Lougherbf338362012-08-22 05:24:36 +01004117 struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004118{
Phillip Lougherbf338362012-08-22 05:24:36 +01004119 if (dir_ent == NULL)
4120 dir_ent = dir_info->list;
4121 else
4122 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004123
Phillip Lougherbf338362012-08-22 05:24:36 +01004124 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
4125 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
4126 dir_ent->name, dir_ent->inode->type, dir);
4127
4128 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01004129}
4130
4131
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004132void scan6_freedir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01004133{
4134 if(dir->index)
4135 free(dir->index);
4136 free(dir->buff);
4137}
4138
4139
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004140void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00004141{
4142 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00004143 int duplicate_file;
plougher1f413c82005-11-18 00:02:14 +00004144 struct directory dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01004145 struct dir_ent *dir_ent = NULL;
plougher1f413c82005-11-18 00:02:14 +00004146
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004147 scan6_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004148
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004149 while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
Phillip Lougher0a670882012-10-05 04:09:13 +01004150 struct stat *buf = &dir_ent->inode->buf;
plougher1f413c82005-11-18 00:02:14 +00004151
4152 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
4153 switch(buf->st_mode & S_IFMT) {
4154 case S_IFREG:
4155 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00004156 write_file(inode, dir_ent,
4157 &duplicate_file);
4158 INFO("file %s, uncompressed size %lld "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004159 "bytes %s\n",
4160 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004161 (long long) buf->st_size,
4162 duplicate_file ? "DUPLICATE" :
4163 "");
plougher1f413c82005-11-18 00:02:14 +00004164 break;
4165
4166 case S_IFDIR:
4167 squashfs_type = SQUASHFS_DIR_TYPE;
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004168 dir_scan6(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00004169 break;
4170
4171 case S_IFLNK:
4172 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004173 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004174 squashfs_type, 0, 0, 0, NULL,
4175 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004176 INFO("symbolic link %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004177 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004178 sym_count ++;
4179 break;
4180
4181 case S_IFCHR:
4182 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004183 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004184 squashfs_type, 0, 0, 0, NULL,
4185 NULL, NULL, 0);
4186 INFO("character device %s inode 0x%llx"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004187 "\n", subpathname(dir_ent),
4188 *inode);
plougher1f413c82005-11-18 00:02:14 +00004189 dev_count ++;
4190 break;
4191
4192 case S_IFBLK:
4193 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004194 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004195 squashfs_type, 0, 0, 0, NULL,
4196 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004197 INFO("block device %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004198 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004199 dev_count ++;
4200 break;
4201
4202 case S_IFIFO:
4203 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004204 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004205 squashfs_type, 0, 0, 0, NULL,
4206 NULL, NULL, 0);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004207 INFO("fifo %s inode 0x%llx\n",
4208 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004209 fifo_count ++;
4210 break;
4211
4212 case S_IFSOCK:
4213 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004214 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004215 squashfs_type, 0, 0, 0, NULL,
4216 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004217 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004218 "0x%llx\n",
4219 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004220 sock_count ++;
4221 break;
4222
plougher23377982007-11-12 04:04:48 +00004223 default:
plougherb3604122009-03-30 02:07:20 +00004224 BAD_ERROR("%s unrecognised file type, "
Phillip Lougher494479f2012-02-03 15:45:41 +00004225 "mode is %x\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004226 subpathname(dir_ent),
plougherb3604122009-03-30 02:07:20 +00004227 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00004228 }
4229 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00004230 dir_ent->inode->type = squashfs_type;
4231 } else {
4232 *inode = dir_ent->inode->inode;
4233 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00004234 switch(squashfs_type) {
4235 case SQUASHFS_FILE_TYPE:
4236 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00004237 INFO("file %s, uncompressed "
4238 "size %lld bytes LINK"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004239 "\n",
4240 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004241 (long long)
plougher50b31762009-03-31 04:14:46 +00004242 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00004243 break;
4244 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00004245 INFO("symbolic link %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004246 "LINK\n", subpathname(dir_ent),
4247 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004248 break;
4249 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004250 INFO("character device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004251 "LINK\n", subpathname(dir_ent),
4252 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004253 break;
plougher5507dd92006-11-06 00:43:10 +00004254 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004255 INFO("block device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004256 "LINK\n", subpathname(dir_ent),
4257 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004258 break;
4259 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00004260 INFO("fifo %s inode 0x%llx LINK\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004261 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004262 break;
4263 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00004264 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004265 "0x%llx LINK\n",
4266 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004267 break;
4268 }
plougher1f413c82005-11-18 00:02:14 +00004269 }
4270
Phillip Lougher0366aec2012-10-05 04:06:04 +01004271 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
4272 squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00004273 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004274 }
4275
plougher29e37092007-04-15 01:24:51 +00004276 write_dir(inode, dir_info, &dir);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004277 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
4278 *inode);
plougher1f413c82005-11-18 00:02:14 +00004279
Phillip Lougher2abfcf72012-11-11 03:59:56 +00004280 scan6_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004281}
4282
4283
4284unsigned int slog(unsigned int block)
4285{
4286 int i;
4287
plougher4c99cb72007-06-14 21:46:31 +00004288 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00004289 if(block == (1 << i))
4290 return i;
4291 return 0;
4292}
4293
4294
plougher8f8e1a12007-10-18 02:50:21 +00004295int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00004296{
4297 int i;
4298
4299 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00004300 if((exclude_paths[i].st_dev == buf->st_dev) &&
4301 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00004302 return TRUE;
4303 return FALSE;
4304}
4305
4306
4307#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00004308 if(exclude % EXCLUDE_SIZE == 0) { \
4309 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4310 * sizeof(struct exclude_info)); \
4311 if(exclude_paths == NULL) \
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004312 MEM_ERROR(); \
plougher360514a2009-03-30 03:01:38 +00004313 } \
4314 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00004315 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00004316int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00004317{
4318 int i;
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004319 char *filename;
plougher1f413c82005-11-18 00:02:14 +00004320 struct stat buf;
4321
plougherb3604122009-03-30 02:07:20 +00004322 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4323 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00004324 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00004325 ERROR("Cannot stat exclude dir/file %s because %s, "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004326 "ignoring\n", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004327 return TRUE;
4328 }
4329 ADD_ENTRY(buf);
4330 return TRUE;
4331 }
4332
4333 for(i = 0; i < source; i++) {
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004334 int res = asprintf(&filename, "%s/%s", source_path[i], path);
4335 if(res == -1)
4336 BAD_ERROR("asprintf failed in old_add_exclude\n");
plougher1f413c82005-11-18 00:02:14 +00004337 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00004338 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00004339 ERROR("Cannot stat exclude dir/file %s because "
Phillip Lougherfe58b492012-12-15 01:27:07 +00004340 "%s, ignoring\n", filename,
plougher50b31762009-03-31 04:14:46 +00004341 strerror(errno));
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004342 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004343 continue;
4344 }
Phillip Lougherdcb5af92012-11-30 03:05:31 +00004345 free(filename);
plougher1f413c82005-11-18 00:02:14 +00004346 ADD_ENTRY(buf);
4347 }
4348 return TRUE;
4349}
4350
4351
plougherb3604122009-03-30 02:07:20 +00004352void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4353 int type)
plougher1f413c82005-11-18 00:02:14 +00004354{
plougherb3604122009-03-30 02:07:20 +00004355 old_root_entry = realloc(old_root_entry,
4356 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4357 if(old_root_entry == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004358 MEM_ERROR();
plougher1f413c82005-11-18 00:02:14 +00004359
ploughera326c182009-08-29 05:41:45 +00004360 old_root_entry[old_root_entries].name = strdup(name);
4361 old_root_entry[old_root_entries].inode.inode = inode;
4362 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4363 old_root_entry[old_root_entries].inode.type = type;
4364 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004365}
4366
4367
plougher5741d792010-09-04 03:20:50 +00004368void initialise_threads(int readb_mbytes, int writeb_mbytes,
4369 int fragmentb_mbytes)
plougher5507dd92006-11-06 00:43:10 +00004370{
4371 int i;
4372 sigset_t sigmask, old_mask;
Phillip Loughere1668fe2012-12-30 05:48:12 +00004373 int reader_buffer_size;
4374 int fragment_buffer_size;
plougher5741d792010-09-04 03:20:50 +00004375 /*
4376 * writer_buffer_size is global because it is needed in
4377 * write_file_blocks_dup()
4378 */
Phillip Loughere1668fe2012-12-30 05:48:12 +00004379
4380 /*
4381 * convert from queue size in Mbytes to queue size in
4382 * blocks.
4383 *
4384 * In doing so, check that the user supplied values do not
4385 * overflow a signed int
4386 */
4387 if(shift_overflow(readb_mbytes, 20 - block_log))
4388 BAD_ERROR("Read queue is too large\n");
4389 else
4390 reader_buffer_size = readb_mbytes << (20 - block_log);
4391
4392 if(shift_overflow(fragmentb_mbytes, 20 - block_log))
4393 BAD_ERROR("Fragment queue is too large\n");
4394 else
4395 fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
4396
4397 if(shift_overflow(writeb_mbytes, 20 - block_log))
4398 BAD_ERROR("Write queue is too large\n");
4399 else
4400 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004401
4402 sigemptyset(&sigmask);
4403 sigaddset(&sigmask, SIGINT);
4404 sigaddset(&sigmask, SIGQUIT);
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00004405 sigaddset(&sigmask, SIGUSR2);
plougher5507dd92006-11-06 00:43:10 +00004406 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4407 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4408
4409 signal(SIGUSR1, sigusr1_handler);
4410
4411 if(processors == -1) {
4412#ifndef linux
4413 int mib[2];
4414 size_t len = sizeof(processors);
4415
4416 mib[0] = CTL_HW;
4417#ifdef HW_AVAILCPU
4418 mib[1] = HW_AVAILCPU;
4419#else
4420 mib[1] = HW_NCPU;
4421#endif
4422
4423 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004424 ERROR("Failed to get number of available processors. "
4425 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004426 processors = 1;
4427 }
4428#else
plougher9cc26b72010-08-17 01:05:55 +00004429 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004430#endif
4431 }
4432
Phillip Loughere1668fe2012-12-30 05:48:12 +00004433 if(multiply_overflow(processors, 2) ||
4434 add_overflow(processors * 2, 2) ||
4435 multiply_overflow(processors * 2 + 2,
4436 sizeof(pthread_t)))
4437 BAD_ERROR("Processors too large\n");
4438
plougherf2d2a842010-12-18 02:43:48 +00004439 thread = malloc((2 + processors * 2) * sizeof(pthread_t));
4440 if(thread == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004441 MEM_ERROR();
Phillip Loughere1668fe2012-12-30 05:48:12 +00004442
plougher91fbb302008-05-06 02:29:36 +00004443 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004444 frag_deflator_thread = &deflator_thread[processors];
4445
4446 to_reader = queue_init(1);
4447 from_reader = queue_init(reader_buffer_size);
4448 to_writer = queue_init(writer_buffer_size);
4449 from_writer = queue_init(1);
4450 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004451 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004452 reader_buffer = cache_init(block_size, reader_buffer_size);
4453 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004454 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004455 pthread_create(&thread[0], NULL, reader, NULL);
4456 pthread_create(&thread[1], NULL, writer, NULL);
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004457 init_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00004458 pthread_mutex_init(&fragment_mutex, NULL);
4459 pthread_cond_init(&fragment_waiting, NULL);
4460
4461 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004462 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4463 0)
plougher5507dd92006-11-06 00:43:10 +00004464 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004465 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4466 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004467 BAD_ERROR("Failed to create thread\n");
4468 }
4469
4470 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4471 processors == 1 ? "" : "s");
4472
4473 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4474 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4475}
4476
4477
plougher0e453652006-11-06 01:49:35 +00004478long long write_inode_lookup_table()
4479{
4480 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004481 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004482
4483 if(inode_count == sinode_count)
4484 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004485
plougher44f03282010-07-27 00:31:36 +00004486 it = realloc(inode_lookup_table, lookup_bytes);
4487 if(it == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004488 MEM_ERROR();
plougher44f03282010-07-27 00:31:36 +00004489 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004490
plougher0e453652006-11-06 01:49:35 +00004491 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4492 struct inode_info *inode = inode_info[i];
4493
4494 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004495
Phillip Lougher539c2b12012-07-30 20:14:52 +01004496 inode_number = get_inode_no(inode);
plougher0e453652006-11-06 01:49:35 +00004497
plougher360514a2009-03-30 03:01:38 +00004498 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4499 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004500
plougher0e453652006-11-06 01:49:35 +00004501 }
4502 }
4503
plougher02bc3bc2007-02-25 12:12:01 +00004504skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004505 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4506 noI);
plougher0e453652006-11-06 01:49:35 +00004507}
4508
plougher2ea89142008-03-11 01:34:19 +00004509
Phillip Lougher8e44e052012-11-26 02:58:35 +00004510char *get_component(char *target, char **targname)
plougher8f8e1a12007-10-18 02:50:21 +00004511{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004512 char *start;
4513
plougher8f8e1a12007-10-18 02:50:21 +00004514 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004515 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004516
Phillip Lougher8e44e052012-11-26 02:58:35 +00004517 start = target;
plougher8f8e1a12007-10-18 02:50:21 +00004518 while(*target != '/' && *target!= '\0')
Phillip Lougher8e44e052012-11-26 02:58:35 +00004519 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004520
Phillip Lougher8e44e052012-11-26 02:58:35 +00004521 *targname = strndup(start, target - start);
plougher8f8e1a12007-10-18 02:50:21 +00004522
4523 return target;
4524}
4525
4526
4527void free_path(struct pathname *paths)
4528{
4529 int i;
4530
4531 for(i = 0; i < paths->names; i++) {
4532 if(paths->name[i].paths)
4533 free_path(paths->name[i].paths);
4534 free(paths->name[i].name);
4535 if(paths->name[i].preg) {
4536 regfree(paths->name[i].preg);
4537 free(paths->name[i].preg);
4538 }
4539 }
4540
4541 free(paths);
4542}
4543
4544
4545struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4546{
Phillip Lougher8e44e052012-11-26 02:58:35 +00004547 char *targname;
plougher8f8e1a12007-10-18 02:50:21 +00004548 int i, error;
4549
Phillip Lougher8e44e052012-11-26 02:58:35 +00004550 target = get_component(target, &targname);
plougher8f8e1a12007-10-18 02:50:21 +00004551
4552 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004553 paths = malloc(sizeof(struct pathname));
4554 if(paths == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004555 MEM_ERROR();
plougher8f8e1a12007-10-18 02:50:21 +00004556
4557 paths->names = 0;
4558 paths->name = NULL;
4559 }
4560
4561 for(i = 0; i < paths->names; i++)
4562 if(strcmp(paths->name[i].name, targname) == 0)
4563 break;
4564
4565 if(i == paths->names) {
4566 /* allocate new name entry */
4567 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004568 paths->name = realloc(paths->name, (i + 1) *
4569 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004570 if(paths->name == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004571 MEM_ERROR();
Phillip Lougher8e44e052012-11-26 02:58:35 +00004572 paths->name[i].name = targname;
plougher8f8e1a12007-10-18 02:50:21 +00004573 paths->name[i].paths = NULL;
4574 if(use_regex) {
4575 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004576 if(paths->name[i].preg == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004577 MEM_ERROR();
plougherb3604122009-03-30 02:07:20 +00004578 error = regcomp(paths->name[i].preg, targname,
4579 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004580 if(error) {
Phillip Lougher62859d22012-11-30 05:53:56 +00004581 char str[1024]; /* overflow safe */
plougher8f8e1a12007-10-18 02:50:21 +00004582
4583 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004584 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004585 "because %s\n", targname, alltarget,
4586 str);
plougher8f8e1a12007-10-18 02:50:21 +00004587 }
4588 } else
4589 paths->name[i].preg = NULL;
4590
4591 if(target[0] == '\0')
4592 /* at leaf pathname component */
4593 paths->name[i].paths = NULL;
4594 else
4595 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004596 paths->name[i].paths = add_path(NULL, target,
4597 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004598 } else {
4599 /* existing matching entry */
Phillip Lougher8e44e052012-11-26 02:58:35 +00004600 free(targname);
4601
plougher8f8e1a12007-10-18 02:50:21 +00004602 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004603 /* No sub-directory which means this is the leaf
4604 * component of a pre-existing exclude which subsumes
4605 * the exclude currently being added, in which case stop
4606 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004607 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004608 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004609 * from more specific excludes, delete as they're
4610 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004611 free_path(paths->name[i].paths);
4612 paths->name[i].paths = NULL;
4613 } else
4614 /* recurse adding child components */
4615 add_path(paths->name[i].paths, target, alltarget);
4616 }
4617
4618 return paths;
4619}
plougher2ea89142008-03-11 01:34:19 +00004620
4621
plougher05e50ef2007-10-23 12:34:20 +00004622void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004623{
plougher05e50ef2007-10-23 12:34:20 +00004624
plougherb3604122009-03-30 02:07:20 +00004625 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4626 strncmp(target, "../", 3) == 0)
4627 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4628 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004629 else if(strncmp(target, "... ", 4) == 0)
4630 stickypath = add_path(stickypath, target + 4, target + 4);
4631 else
4632 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004633}
4634
4635
4636void display_path(int depth, struct pathname *paths)
4637{
4638 int i, n;
4639
4640 if(paths == NULL)
4641 return;
4642
4643 for(i = 0; i < paths->names; i++) {
4644 for(n = 0; n < depth; n++)
4645 printf("\t");
4646 printf("%d: %s\n", depth, paths->name[i].name);
4647 display_path(depth + 1, paths->name[i].paths);
4648 }
4649}
4650
4651
4652void display_path2(struct pathname *paths, char *string)
4653{
4654 int i;
Phillip Lougher91459c12012-11-30 05:24:44 +00004655 char *path;
plougher8f8e1a12007-10-18 02:50:21 +00004656
4657 if(paths == NULL) {
4658 printf("%s\n", string);
4659 return;
4660 }
4661
4662 for(i = 0; i < paths->names; i++) {
Phillip Lougher91459c12012-11-30 05:24:44 +00004663 int res = asprintf(&path, "%s/%s", string, paths->name[i].name);
4664 if(res == -1)
4665 BAD_ERROR("asprintf failed in display_path2\n");
plougher8f8e1a12007-10-18 02:50:21 +00004666 display_path2(paths->name[i].paths, path);
Phillip Lougher91459c12012-11-30 05:24:44 +00004667 free(path);
plougher8f8e1a12007-10-18 02:50:21 +00004668 }
4669}
4670
4671
plougherf9039c92007-10-22 03:54:16 +00004672struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4673{
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004674 int count = paths == NULL ? 0 : paths->count;
4675
4676 if(count % PATHS_ALLOC_SIZE == 0) {
4677 paths = realloc(paths, sizeof(struct pathnames) +
4678 (count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004679 if(paths == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004680 MEM_ERROR();
plougher6f2a8262010-07-27 00:37:19 +00004681 }
plougherf9039c92007-10-22 03:54:16 +00004682
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004683 paths->path[count] = path;
4684 paths->count = count + 1;
plougherf9039c92007-10-22 03:54:16 +00004685 return paths;
4686}
4687
4688
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004689int excluded_match(char *name, struct pathname *path, struct pathnames **new)
plougherf9039c92007-10-22 03:54:16 +00004690{
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004691 int i;
plougher8f8e1a12007-10-18 02:50:21 +00004692
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004693 for(i = 0; i < path->names; i++) {
4694 int match = use_regex ?
4695 regexec(path->name[i].preg, name, (size_t) 0,
plougher50b31762009-03-31 04:14:46 +00004696 NULL, 0) == 0 :
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004697 fnmatch(path->name[i].name, name,
4698 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
plougherf9039c92007-10-22 03:54:16 +00004699
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004700 if(match) {
4701 if(path->name[i].paths == NULL || new == NULL)
plougherb3604122009-03-30 02:07:20 +00004702 /* match on a leaf component, any subdirectories
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004703 * in the filesystem should be excluded */
4704 return TRUE;
4705 else
plougherb3604122009-03-30 02:07:20 +00004706 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004707 * subdirectories to the new set of
4708 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004709 *new = add_subdir(*new, path->name[i].paths);
4710 }
4711 }
4712
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004713 return FALSE;
4714}
4715
4716
4717int excluded(char *name, struct pathnames *paths, struct pathnames **new)
4718{
4719 int n;
4720
4721 if(stickypath && excluded_match(name, stickypath, NULL))
4722 return TRUE;
4723
4724 for(n = 0; paths && n < paths->count; n++) {
4725 int res = excluded_match(name, paths->path[n], new);
4726 if(res) {
4727 free(*new);
4728 *new = NULL;
4729 return TRUE;
4730 }
plougherf9039c92007-10-22 03:54:16 +00004731 }
4732
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00004733 /*
4734 * Either:
4735 * - no matching names found, return empty new search set, or
4736 * - one or more matches with sub-directories found (no leaf matches),
4737 * in which case return new search set.
4738 *
4739 * In either case return FALSE as we don't want to exclude this entry
4740 */
plougher8f8e1a12007-10-18 02:50:21 +00004741 return FALSE;
4742}
4743
4744
Phillip Lougher386128f2012-12-16 05:23:45 +00004745void process_exclude_file(char *argv)
4746{
4747 FILE *fd;
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004748 char buffer[MAX_LINE + 1]; /* overflow safe */
Phillip Lougherb22336d2012-12-20 18:44:22 +00004749 char *filename;
Phillip Lougher386128f2012-12-16 05:23:45 +00004750
Phillip Lougherb22336d2012-12-20 18:44:22 +00004751 fd = fopen(argv, "r");
4752 if(fd == NULL)
4753 BAD_ERROR("Failed to open exclude file \"%s\" because %s\n",
4754 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004755
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004756 while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
Phillip Lougherb22336d2012-12-20 18:44:22 +00004757 int len = strlen(filename);
4758
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004759 if(len == MAX_LINE && filename[len - 1] != '\n')
Phillip Lougherb22336d2012-12-20 18:44:22 +00004760 /* line too large */
4761 BAD_ERROR("Line too long when reading "
Phillip Lougherfe2c7352012-12-23 06:55:41 +00004762 "exclude file \"%s\", larger than %d "
Phillip Lougher83847c12012-12-23 07:22:36 +00004763 "bytes\n", argv, MAX_LINE);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004764
4765 /*
4766 * Remove '\n' terminator if it exists (the last line
4767 * in the file may not be '\n' terminated)
4768 */
4769 if(len && filename[len - 1] == '\n')
4770 filename[len - 1] = '\0';
4771
4772 /* Skip any leading whitespace */
4773 while(isspace(*filename))
4774 filename ++;
4775
4776 /* if comment line, skip */
4777 if(*filename == '#')
4778 continue;
4779
4780 /*
4781 * check for initial backslash, to accommodate
4782 * filenames with leading space or leading # character
4783 */
4784 if(*filename == '\\')
4785 filename ++;
4786
4787 /* if line is now empty after skipping characters, skip it */
4788 if(*filename == '\0')
4789 continue;
4790
Phillip Lougher386128f2012-12-16 05:23:45 +00004791 if(old_exclude)
4792 old_add_exclude(filename);
4793 else
4794 add_exclude(filename);
Phillip Lougherb22336d2012-12-20 18:44:22 +00004795 }
4796
4797 if(ferror(fd))
4798 BAD_ERROR("Reading exclude file \"%s\" failed because %s\n",
4799 argv, strerror(errno));
Phillip Lougher386128f2012-12-16 05:23:45 +00004800
4801 fclose(fd);
4802}
4803
4804
plougher99ac0cc2007-10-29 03:17:10 +00004805#define RECOVER_ID "Squashfs recovery file v1.0\n"
4806#define RECOVER_ID_SIZE 28
4807
plougher64e83fd2010-12-31 21:21:26 +00004808void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004809{
plougher1d065e92010-06-18 03:58:27 +00004810 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004811 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004812 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004813 char header[] = RECOVER_ID;
4814
4815 if(recover == FALSE) {
4816 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004817 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004818 return;
4819 }
4820
plougher1b879bc2010-12-18 02:49:42 +00004821 metadata = malloc(bytes);
4822 if(metadata == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004823 MEM_ERROR();
plougher44d54ef2010-02-08 22:13:49 +00004824
plougher1d065e92010-06-18 03:58:27 +00004825 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4826 if(res == 0)
4827 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004828
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004829 res = asprintf(&recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004830 getbase(destination_file), pid);
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004831 if(res == -1)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004832 MEM_ERROR();
Phillip Lougheraf4c9232012-11-15 03:46:28 +00004833
plougherb3604122009-03-30 02:07:20 +00004834 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4835 if(recoverfd == -1)
4836 BAD_ERROR("Failed to create recovery file, because %s. "
4837 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004838
plougher628e7682009-03-29 22:12:24 +00004839 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004840 BAD_ERROR("Failed to write recovery file, because %s\n",
4841 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004842
plougher64e83fd2010-12-31 21:21:26 +00004843 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004844 BAD_ERROR("Failed to write recovery file, because %s\n",
4845 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004846
plougher628e7682009-03-29 22:12:24 +00004847 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004848 BAD_ERROR("Failed to write recovery file, because %s\n",
4849 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004850
4851 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004852 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004853
4854 printf("Recovery file \"%s\" written\n", recovery_file);
4855 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004856 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4857 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004858 printf("to restore filesystem\n\n");
4859}
4860
4861
4862void read_recovery_data(char *recovery_file, char *destination_file)
4863{
4864 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004865 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004866 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004867 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004868 struct stat buf;
4869 char header[] = RECOVER_ID;
4870 char header2[RECOVER_ID_SIZE];
4871
plougher9e9d9dc2010-12-18 02:53:57 +00004872 recoverfd = open(recovery_file, O_RDONLY);
4873 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004874 BAD_ERROR("Failed to open recovery file because %s\n",
4875 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004876
4877 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004878 BAD_ERROR("Failed to stat destination file, because %s\n",
4879 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004880
plougher9e9d9dc2010-12-18 02:53:57 +00004881 fd = open(destination_file, O_RDWR);
4882 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004883 BAD_ERROR("Failed to open destination file because %s\n",
4884 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004885
plougher8a8c4102009-03-29 22:28:49 +00004886 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4887 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004888 BAD_ERROR("Failed to read recovery file, because %s\n",
4889 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004890 if(res < RECOVER_ID_SIZE)
4891 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004892 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4893 BAD_ERROR("Not a recovery file\n");
4894
plougher64e83fd2010-12-31 21:21:26 +00004895 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004896 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004897 BAD_ERROR("Failed to read recovery file, because %s\n",
4898 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004899 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004900 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004901
plougher64e83fd2010-12-31 21:21:26 +00004902 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004903 if(res == 0)
4904 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004905
plougherb3604122009-03-30 02:07:20 +00004906 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004907 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004908 BAD_ERROR("Recovery file and destination file do not seem to "
4909 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004910
4911 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4912
plougher9e9d9dc2010-12-18 02:53:57 +00004913 metadata = malloc(bytes);
4914 if(metadata == NULL)
Phillip Lougherec71c3c2013-02-21 22:25:53 +00004915 MEM_ERROR();
plougher99ac0cc2007-10-29 03:17:10 +00004916
plougher8a8c4102009-03-29 22:28:49 +00004917 res = read_bytes(recoverfd, metadata, bytes);
4918 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004919 BAD_ERROR("Failed to read recovery file, because %s\n",
4920 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004921 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004922 BAD_ERROR("Recovery file appears to be truncated\n");
4923
plougher64e83fd2010-12-31 21:21:26 +00004924 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004925
plougher0dd6f122009-03-29 21:43:57 +00004926 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004927
4928 close(recoverfd);
4929 close(fd);
4930
plougherb3604122009-03-30 02:07:20 +00004931 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4932 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004933
4934 exit(0);
4935}
4936
4937
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004938int parse_number(char *start, int *res, int size)
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004939{
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004940 char *end;
4941 long number = strtol(start, &end, 10);
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004942
Phillip Lougherf4f48382012-11-29 03:52:44 +00004943 /*
4944 * check for strtol underflow or overflow in conversion.
4945 * Note: strtol can validly return LONG_MIN and LONG_MAX
4946 * if the user entered these values, but, additional code
4947 * to distinguish this scenario is unnecessary, because for
4948 * our purposes LONG_MIN and LONG_MAX are too large anyway
4949 */
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004950 if(number == LONG_MIN || number == LONG_MAX)
4951 return 0;
4952
4953 /* reject negative numbers as invalid */
4954 if(number < 0)
4955 return 0;
4956
4957 /* check if long result will overflow signed int */
4958 if(number > INT_MAX)
4959 return 0;
4960
4961 if(size) {
Phillip Loughered345692012-11-28 03:56:16 +00004962 /*
4963 * Check for multiplier and trailing junk.
4964 * But first check that a number exists before the
4965 * multiplier
4966 */
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004967 if(end == start)
Phillip Loughered345692012-11-28 03:56:16 +00004968 return 0;
4969
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004970 switch(end[0]) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004971 case 'm':
4972 case 'M':
4973 if(multiply_overflow((int) number, 1048576))
4974 return 0;
4975 number *= 1048576;
Phillip Loughera9e65632012-11-28 04:17:27 +00004976
Phillip Lougherf968be82012-12-04 05:12:32 +00004977 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004978 /* trailing junk after number */
4979 return 0;
4980
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004981 break;
4982 case 'k':
4983 case 'K':
4984 if(multiply_overflow((int) number, 1024))
4985 return 0;
4986 number *= 1024;
Phillip Loughera9e65632012-11-28 04:17:27 +00004987
Phillip Lougherf968be82012-12-04 05:12:32 +00004988 if(end[1] != '\0')
Phillip Loughera9e65632012-11-28 04:17:27 +00004989 /* trailing junk after number */
4990 return 0;
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004991 case '\0':
4992 break;
4993 default:
4994 /* trailing junk after number */
4995 return 0;
4996 }
Phillip Lougherda96f5b2012-11-28 04:32:13 +00004997 } else if(end[0] != '\0')
Phillip Lougher94c1fe02012-11-28 03:32:36 +00004998 /* trailing junk after number */
4999 return 0;
5000
5001 *res = number;
5002 return 1;
5003}
5004
5005
5006int parse_num(char *arg, int *res)
5007{
5008 return parse_number(arg, res, 0);
5009}
5010
5011
plougher1f413c82005-11-18 00:02:14 +00005012#define VERSION() \
Phillip Lougher21d5dc42013-02-28 23:56:54 +00005013 printf("mksquashfs version 4.2-git (2013/02/28)\n");\
Phillip Lougher11532792013-01-04 01:46:25 +00005014 printf("copyright (C) 2013 Phillip Lougher "\
Phillip Lougher83d42a32012-10-31 23:42:22 +00005015 "<phillip@squashfs.org.uk>\n\n"); \
plougher16111452010-07-22 05:12:18 +00005016 printf("This program is free software; you can redistribute it and/or"\
5017 "\n");\
5018 printf("modify it under the terms of the GNU General Public License"\
5019 "\n");\
5020 printf("as published by the Free Software Foundation; either version "\
5021 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00005022 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00005023 printf("This program is distributed in the hope that it will be "\
5024 "useful,\n");\
5025 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
5026 "of\n");\
5027 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
5028 "\n");\
plougher1f413c82005-11-18 00:02:14 +00005029 printf("GNU General Public License for more details.\n");
5030int main(int argc, char *argv[])
5031{
plougher324978d2006-02-27 04:53:29 +00005032 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00005033 int res, i;
plougher64e83fd2010-12-31 21:21:26 +00005034 struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +00005035 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00005036 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005037 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00005038 int readb_mbytes = READER_BUFFER_DEFAULT,
5039 writeb_mbytes = WRITER_BUFFER_DEFAULT,
5040 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005041 int force_progress = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005042
plougher1f413c82005-11-18 00:02:14 +00005043 block_log = slog(block_size);
5044 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
5045 VERSION();
5046 exit(0);
5047 }
5048 for(i = 1; i < argc && argv[i][0] != '-'; i++);
5049 if(i < 3)
5050 goto printOptions;
5051 source_path = argv + 1;
5052 source = i - 2;
plougher4da4bd42010-11-21 05:01:54 +00005053 /*
5054 * lookup default compressor. Note the Makefile ensures the default
5055 * compressor has been built, and so we don't need to to check
5056 * for failure here
5057 */
plougher5c2adaf2010-11-22 01:00:15 +00005058 comp = lookup_compressor(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005059 for(; i < argc; i++) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005060 if(strcmp(argv[i], "-action") == 0 ||
5061 strcmp(argv[i], "-a") ==0) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005062 if(++i == argc) {
Phillip Lougher9523b042012-10-27 01:48:48 +01005063 ERROR("%s: %s missing action\n",
5064 argv[0], argv[i - 1]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005065 exit(1);
5066 }
5067 res = parse_action(argv[i]);
5068 if(res == 0)
5069 exit(1);
5070
Phillip Lougherb73caba2012-12-24 21:58:41 +00005071 } else if(strcmp(argv[i], "-af") == 0) {
5072 if(++i == argc) {
5073 ERROR("%s: -af missing filename\n", argv[0]);
5074 exit(1);
5075 }
5076 if(read_action_file(argv[i]) == FALSE)
5077 exit(1);
5078
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005079 } else if(strcmp(argv[i], "-comp") == 0) {
plougherc5d59872010-11-22 01:36:01 +00005080 if(compressor_opts_parsed) {
5081 ERROR("%s: -comp must appear before -X options"
5082 "\n", argv[0]);
5083 exit(1);
5084 }
plougherae9dcd82009-08-01 02:59:38 +00005085 if(++i == argc) {
5086 ERROR("%s: -comp missing compression type\n",
5087 argv[0]);
5088 exit(1);
5089 }
plougher5c2adaf2010-11-22 01:00:15 +00005090 comp = lookup_compressor(argv[i]);
plougher4da4bd42010-11-21 05:01:54 +00005091 if(!comp->supported) {
plougherc5d59872010-11-22 01:36:01 +00005092 ERROR("%s: Compressor \"%s\" is not supported!"
5093 "\n", argv[0], argv[i]);
5094 ERROR("%s: Compressors available:\n", argv[0]);
plougher4da4bd42010-11-21 05:01:54 +00005095 display_compressors("", COMP_DEFAULT);
5096 exit(1);
5097 }
plougherb5576ea2010-11-22 01:06:53 +00005098
5099 } else if(strncmp(argv[i], "-X", 2) == 0) {
5100 int args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00005101 if(args < 0) {
5102 if(args == -1) {
5103 ERROR("%s: Unrecognised compressor"
5104 " option %s\n", argv[0],
5105 argv[i]);
5106 ERROR("%s: Did you forget to specify"
5107 " -comp, or specify it after"
5108 " the compressor specific"
5109 " option?\n", argv[0]);
5110 }
plougherb5576ea2010-11-22 01:06:53 +00005111 exit(1);
5112 }
5113 i += args;
plougherc5d59872010-11-22 01:36:01 +00005114 compressor_opts_parsed = 1;
plougherb5576ea2010-11-22 01:06:53 +00005115
plougherae9dcd82009-08-01 02:59:38 +00005116 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00005117 if(++i == argc) {
5118 ERROR("%s: -pf missing filename\n", argv[0]);
5119 exit(1);
5120 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005121 if(read_pseudo_file(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005122 exit(1);
plougher43244f22009-04-05 02:04:51 +00005123 } else if(strcmp(argv[i], "-p") == 0) {
5124 if(++i == argc) {
5125 ERROR("%s: -p missing pseudo file definition\n",
5126 argv[0]);
5127 exit(1);
5128 }
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005129 if(read_pseudo_def(argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00005130 exit(1);
plougher43244f22009-04-05 02:04:51 +00005131 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00005132 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00005133 ERROR("%s: -recover missing recovery file\n",
5134 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00005135 exit(1);
5136 }
5137 read_recovery_data(argv[i], argv[source + 1]);
5138 } else if(strcmp(argv[i], "-no-recovery") == 0)
5139 recover = FALSE;
5140 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00005141 old_exclude = FALSE;
5142 use_regex = FALSE;
5143 } else if(strcmp(argv[i], "-regex") == 0) {
5144 old_exclude = FALSE;
5145 use_regex = TRUE;
5146 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00005147 sparse_files = FALSE;
5148 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00005149 progress = FALSE;
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005150 else if(strcmp(argv[i], "-progress") == 0)
5151 force_progress = TRUE;
plougher02bc3bc2007-02-25 12:12:01 +00005152 else if(strcmp(argv[i], "-no-exports") == 0)
5153 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00005154 else if(strcmp(argv[i], "-processors") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005155 if((++i == argc) || !parse_num(argv[i], &processors)) {
plougher360514a2009-03-30 03:01:38 +00005156 ERROR("%s: -processors missing or invalid "
5157 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005158 exit(1);
5159 }
5160 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00005161 ERROR("%s: -processors should be 1 or larger\n",
5162 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005163 exit(1);
5164 }
plougher0e453652006-11-06 01:49:35 +00005165 } else if(strcmp(argv[i], "-read-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005166 if((++i == argc) ||
5167 !parse_num(argv[i], &readb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005168 ERROR("%s: -read-queue missing or invalid "
5169 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005170 exit(1);
5171 }
5172 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00005173 ERROR("%s: -read-queue should be 1 megabyte or "
5174 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005175 exit(1);
5176 }
plougher0e453652006-11-06 01:49:35 +00005177 } else if(strcmp(argv[i], "-write-queue") == 0) {
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005178 if((++i == argc) ||
5179 !parse_num(argv[i], &writeb_mbytes)) {
plougher50b31762009-03-31 04:14:46 +00005180 ERROR("%s: -write-queue missing or invalid "
5181 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005182 exit(1);
5183 }
5184 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005185 ERROR("%s: -write-queue should be 1 megabyte "
5186 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00005187 exit(1);
5188 }
plougher217bad82008-04-05 11:36:41 +00005189 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00005190 if((++i == argc) ||
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005191 !parse_num(argv[i],
5192 &fragmentb_mbytes)) {
plougher360514a2009-03-30 03:01:38 +00005193 ERROR("%s: -fragment-queue missing or invalid "
5194 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005195 exit(1);
5196 }
5197 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00005198 ERROR("%s: -fragment-queue should be 1 "
5199 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00005200 exit(1);
5201 }
plougher5507dd92006-11-06 00:43:10 +00005202 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00005203 if(++i == argc) {
5204 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005205 exit(1);
5206 }
Phillip Lougher94c1fe02012-11-28 03:32:36 +00005207 if(!parse_number(argv[i], &block_size, 1)) {
plougher4c99cb72007-06-14 21:46:31 +00005208 ERROR("%s: -b invalid block size\n", argv[0]);
5209 exit(1);
5210 }
plougher1f413c82005-11-18 00:02:14 +00005211 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00005212 ERROR("%s: -b block size not power of two or "
5213 "not between 4096 and 1Mbyte\n",
5214 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005215 exit(1);
5216 }
5217 } else if(strcmp(argv[i], "-ef") == 0) {
5218 if(++i == argc) {
5219 ERROR("%s: -ef missing filename\n", argv[0]);
5220 exit(1);
5221 }
plougher9b5bf8c2006-03-20 18:43:33 +00005222 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00005223 duplicate_checking = FALSE;
5224
5225 else if(strcmp(argv[i], "-no-fragments") == 0)
5226 no_fragments = TRUE;
5227
5228 else if(strcmp(argv[i], "-always-use-fragments") == 0)
5229 always_use_fragments = TRUE;
5230
5231 else if(strcmp(argv[i], "-sort") == 0) {
5232 if(++i == argc) {
5233 ERROR("%s: -sort missing filename\n", argv[0]);
5234 exit(1);
5235 }
5236 } else if(strcmp(argv[i], "-all-root") == 0 ||
5237 strcmp(argv[i], "-root-owned") == 0)
5238 global_uid = global_gid = 0;
5239
5240 else if(strcmp(argv[i], "-force-uid") == 0) {
5241 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005242 ERROR("%s: -force-uid missing uid or user\n",
5243 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005244 exit(1);
5245 }
5246 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005247 if(global_uid < 0 || global_uid >
5248 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005249 ERROR("%s: -force-uid uid out of range"
5250 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005251 exit(1);
5252 }
5253 } else {
5254 struct passwd *uid = getpwnam(argv[i]);
5255 if(uid)
5256 global_uid = uid->pw_uid;
5257 else {
plougher360514a2009-03-30 03:01:38 +00005258 ERROR("%s: -force-uid invalid uid or "
5259 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005260 exit(1);
5261 }
5262 }
5263 } else if(strcmp(argv[i], "-force-gid") == 0) {
5264 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00005265 ERROR("%s: -force-gid missing gid or group\n",
5266 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005267 exit(1);
5268 }
5269 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00005270 if(global_gid < 0 || global_gid >
5271 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00005272 ERROR("%s: -force-gid gid out of range"
5273 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005274 exit(1);
5275 }
5276 } else {
5277 struct group *gid = getgrnam(argv[i]);
5278 if(gid)
5279 global_gid = gid->gr_gid;
5280 else {
plougher360514a2009-03-30 03:01:38 +00005281 ERROR("%s: -force-gid invalid gid or "
5282 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005283 exit(1);
5284 }
5285 }
5286 } else if(strcmp(argv[i], "-noI") == 0 ||
5287 strcmp(argv[i], "-noInodeCompression") == 0)
5288 noI = TRUE;
5289
5290 else if(strcmp(argv[i], "-noD") == 0 ||
5291 strcmp(argv[i], "-noDataCompression") == 0)
5292 noD = TRUE;
5293
5294 else if(strcmp(argv[i], "-noF") == 0 ||
5295 strcmp(argv[i], "-noFragmentCompression") == 0)
5296 noF = TRUE;
5297
plougherb99d7832010-05-19 01:57:34 +00005298 else if(strcmp(argv[i], "-noX") == 0 ||
5299 strcmp(argv[i], "-noXattrCompression") == 0)
5300 noX = TRUE;
5301
plougherce564c62010-05-19 03:01:49 +00005302 else if(strcmp(argv[i], "-no-xattrs") == 0)
5303 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00005304
plougher30281c82010-08-25 05:06:11 +00005305 else if(strcmp(argv[i], "-xattrs") == 0)
5306 no_xattrs = FALSE;
5307
plougher1f413c82005-11-18 00:02:14 +00005308 else if(strcmp(argv[i], "-nopad") == 0)
5309 nopad = TRUE;
5310
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005311 else if(strcmp(argv[i], "-info") == 0)
plougher91fbb302008-05-06 02:29:36 +00005312 silent = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005313
5314 else if(strcmp(argv[i], "-e") == 0)
5315 break;
5316
5317 else if(strcmp(argv[i], "-noappend") == 0)
5318 delete = TRUE;
5319
5320 else if(strcmp(argv[i], "-keep-as-directory") == 0)
5321 keep_as_directory = TRUE;
5322
5323 else if(strcmp(argv[i], "-root-becomes") == 0) {
5324 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00005325 ERROR("%s: -root-becomes: missing name\n",
5326 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00005327 exit(1);
5328 }
5329 root_name = argv[i];
5330 } else if(strcmp(argv[i], "-version") == 0) {
5331 VERSION();
5332 } else {
5333 ERROR("%s: invalid option\n\n", argv[0]);
5334printOptions:
plougher360514a2009-03-30 03:01:38 +00005335 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
5336 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00005337 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00005338 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00005339 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00005340 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00005341 ERROR("-b <block_size>\t\tset data block to "
5342 "<block_size>. Default %d bytes\n",
5343 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00005344 ERROR("-no-exports\t\tdon't make the filesystem "
5345 "exportable via NFS\n");
5346 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00005347 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00005348 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00005349 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00005350 "\n");
plougher1f413c82005-11-18 00:02:14 +00005351 ERROR("-noI\t\t\tdo not compress inode table\n");
5352 ERROR("-noD\t\t\tdo not compress data blocks\n");
5353 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00005354 ERROR("-noX\t\t\tdo not compress extended "
5355 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00005356 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00005357 ERROR("-always-use-fragments\tuse fragment blocks for "
5358 "files larger than block size\n");
5359 ERROR("-no-duplicates\t\tdo not perform duplicate "
5360 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00005361 ERROR("-all-root\t\tmake all files owned by root\n");
5362 ERROR("-force-uid uid\t\tset all file uids to uid\n");
5363 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00005364 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
5365 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00005366 ERROR("-keep-as-directory\tif one source directory is "
5367 "specified, create a root\n");
5368 ERROR("\t\t\tdirectory containing that directory, "
5369 "rather than the\n");
5370 ERROR("\t\t\tcontents of the directory\n");
5371 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00005372 ERROR("-p <pseudo-definition>\tAdd pseudo file "
5373 "definition\n");
5374 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
5375 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00005376 ERROR("-sort <sort_file>\tsort files according to "
5377 "priorities in <sort_file>. One\n");
5378 ERROR("\t\t\tfile or dir with priority per line. "
5379 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00005380 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00005381 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
5382 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00005383 ERROR("-wildcards\t\tAllow extended shell wildcards "
5384 "(globbing) to be used in\n\t\t\texclude "
5385 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00005386 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
5387 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00005388 ERROR("\nFilesystem append options:\n");
5389 ERROR("-noappend\t\tdo not append to existing "
5390 "filesystem\n");
5391 ERROR("-root-becomes <name>\twhen appending source "
5392 "files/directories, make the\n");
5393 ERROR("\t\t\toriginal root become a subdirectory in "
5394 "the new root\n");
5395 ERROR("\t\t\tcalled <name>, rather than adding the new "
5396 "source items\n");
5397 ERROR("\t\t\tto the original root\n");
5398 ERROR("\nMksquashfs runtime options:\n");
5399 ERROR("-version\t\tprint version, licence and "
5400 "copyright message\n");
5401 ERROR("-recover <name>\t\trecover filesystem data "
5402 "using recovery file <name>\n");
5403 ERROR("-no-recovery\t\tdon't generate a recovery "
5404 "file\n");
5405 ERROR("-info\t\t\tprint files written to filesystem\n");
5406 ERROR("-no-progress\t\tdon't display the progress "
5407 "bar\n");
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005408 ERROR("-progress\t\tdisplay progress bar when using "
5409 "the -info option\n");
plougher37632562009-08-07 19:09:01 +00005410 ERROR("-processors <number>\tUse <number> processors."
5411 " By default will use number of\n");
5412 ERROR("\t\t\tprocessors available\n");
5413 ERROR("-read-queue <size>\tSet input queue to <size> "
5414 "Mbytes. Default %d Mbytes\n",
5415 READER_BUFFER_DEFAULT);
5416 ERROR("-write-queue <size>\tSet output queue to <size> "
5417 "Mbytes. Default %d Mbytes\n",
5418 WRITER_BUFFER_DEFAULT);
plougher8bc376b2010-11-12 04:55:20 +00005419 ERROR("-fragment-queue <size>\tSet fragment queue to "
plougher37632562009-08-07 19:09:01 +00005420 "<size> Mbytes. Default %d Mbytes\n",
5421 FRAGMENT_BUFFER_DEFAULT);
5422 ERROR("\nMiscellaneous options:\n");
5423 ERROR("-root-owned\t\talternative name for -all-root"
5424 "\n");
5425 ERROR("-noInodeCompression\talternative name for -noI"
5426 "\n");
5427 ERROR("-noDataCompression\talternative name for -noD"
5428 "\n");
5429 ERROR("-noFragmentCompression\talternative name for "
5430 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005431 ERROR("-noXattrCompression\talternative name for "
5432 "-noX\n");
plougher4fb66822010-12-08 02:49:28 +00005433 ERROR("\nCompressors available and compressor specific "
5434 "options:\n");
5435 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005436 exit(1);
5437 }
5438 }
5439
plougherb747f4f2010-12-25 04:05:47 +00005440 /*
5441 * Some compressors may need the options to be checked for validity
5442 * once all the options have been processed
5443 */
5444 res = compressor_options_post(comp, block_size);
5445 if(res)
5446 EXIT_MKSQUASHFS();
5447
Phillip Lougherc6c73b22012-10-19 03:12:08 +01005448 /*
5449 * If the -info option has been selected then disable the
5450 * progress bar unless it has been explicitly enabled with
5451 * the -progress option
5452 */
5453 if(!silent)
5454 progress = force_progress;
5455
5456#ifdef SQUASHFS_TRACE
5457 progress = FALSE;
5458#endif
5459
plougher91fbb302008-05-06 02:29:36 +00005460 for(i = 0; i < source; i++)
5461 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005462 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005463 "because %s\n", source_path[i],
5464 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005465 EXIT_MKSQUASHFS();
5466 }
plougher324978d2006-02-27 04:53:29 +00005467
5468 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005469 if(stat(argv[source + 1], &buf) == -1) {
5470 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005471 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005472 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005473 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005474 perror("Could not create destination file");
5475 exit(1);
5476 }
5477 delete = TRUE;
5478 } else {
5479 perror("Could not stat destination file");
5480 exit(1);
5481 }
5482
5483 } else {
5484 if(S_ISBLK(buf.st_mode)) {
5485 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005486 perror("Could not open block device as "
5487 "destination");
plougher1f413c82005-11-18 00:02:14 +00005488 exit(1);
5489 }
5490 block_device = 1;
5491
5492 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005493 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5494 O_RDWR);
5495 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005496 perror("Could not open regular file for "
5497 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005498 exit(1);
5499 }
plougher44d54ef2010-02-08 22:13:49 +00005500 }
plougher1f413c82005-11-18 00:02:14 +00005501 else {
5502 ERROR("Destination not block device or regular file\n");
5503 exit(1);
5504 }
5505
plougher324978d2006-02-27 04:53:29 +00005506 }
plougher1f413c82005-11-18 00:02:14 +00005507
plougher4c99cb72007-06-14 21:46:31 +00005508 signal(SIGTERM, sighandler2);
5509 signal(SIGINT, sighandler2);
Phillip Lougherd2ffa3c2013-02-11 02:53:54 +00005510 signal(SIGUSR2, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00005511
plougher16111452010-07-22 05:12:18 +00005512 /*
5513 * process the exclude files - must be done afer destination file has
5514 * been possibly created
5515 */
plougher1f413c82005-11-18 00:02:14 +00005516 for(i = source + 2; i < argc; i++)
Phillip Lougher386128f2012-12-16 05:23:45 +00005517 if(strcmp(argv[i], "-ef") == 0)
5518 /*
5519 * Note presence of filename arg has already
5520 * been checked
5521 */
5522 process_exclude_file(argv[++i]);
5523 else if(strcmp(argv[i], "-e") == 0)
plougher1f413c82005-11-18 00:02:14 +00005524 break;
plougher8b9a7f62009-08-01 22:52:45 +00005525 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005526 strcmp(argv[i], "-sort") == 0 ||
5527 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005528 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005529 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005530 i++;
5531
5532 if(i != argc) {
5533 if(++i == argc) {
5534 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005535 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005536 }
plougher8f8e1a12007-10-18 02:50:21 +00005537 while(i < argc)
5538 if(old_exclude)
5539 old_add_exclude(argv[i++]);
5540 else
plougher05e50ef2007-10-23 12:34:20 +00005541 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005542 }
5543
5544 /* process the sort files - must be done afer the exclude files */
5545 for(i = source + 2; i < argc; i++)
5546 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005547 int res = read_sort_file(argv[++i], source,
5548 source_path);
5549 if(res == FALSE)
5550 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005551 sorted ++;
5552 } else if(strcmp(argv[i], "-e") == 0)
5553 break;
plougher8b9a7f62009-08-01 22:52:45 +00005554 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005555 strcmp(argv[i], "-ef") == 0 ||
5556 strcmp(argv[i], "-pf") == 0 ||
Phillip Lougherb73caba2012-12-24 21:58:41 +00005557 strcmp(argv[i], "-af") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005558 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005559 i++;
5560
plougher4c99cb72007-06-14 21:46:31 +00005561 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005562 comp = read_super(fd, &sBlk, argv[source + 1]);
5563 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005564 ERROR("Failed to read existing filesystem - will not "
5565 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005566 ERROR("To force Mksquashfs to write to this block "
5567 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005568 EXIT_MKSQUASHFS();
5569 }
plougher1f413c82005-11-18 00:02:14 +00005570
plougher1f413c82005-11-18 00:02:14 +00005571 block_log = slog(block_size = sBlk.block_size);
5572 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5573 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5574 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005575 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005576 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5577 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5578 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005579 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005580 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005581 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005582 }
5583
plougher5741d792010-09-04 03:20:50 +00005584 initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
plougher4c99cb72007-06-14 21:46:31 +00005585
plougher13fdddf2010-11-24 01:23:41 +00005586 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5587 if(res)
5588 BAD_ERROR("compressor_init failed\n");
5589
plougher4c99cb72007-06-14 21:46:31 +00005590 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005591 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005592 void *comp_data = compressor_dump_options(comp, block_size,
5593 &size);
plougher3d7e5182010-12-25 01:49:42 +00005594
plougherdf6d8f02009-03-20 03:10:00 +00005595 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005596 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005597
plougher871c72a2010-12-25 04:17:27 +00005598 /*
5599 * store any compressor specific options after the superblock,
5600 * and set the COMP_OPT flag to show that the filesystem has
5601 * compressor specfic options
5602 */
plougher3d7e5182010-12-25 01:49:42 +00005603 if(comp_data) {
5604 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5605
5606 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005607 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005608 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005609 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005610 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005611 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005612 + size;
5613 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005614 } else
plougher64e83fd2010-12-31 21:21:26 +00005615 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005616 } else {
plougher360514a2009-03-30 03:01:38 +00005617 unsigned int last_directory_block, inode_dir_offset,
5618 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005619 inode_dir_start_block, uncompressed_data,
5620 compressed_data, inode_dir_inode_number,
5621 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005622 unsigned int root_inode_start =
5623 SQUASHFS_INODE_BLK(sBlk.root_inode),
5624 root_inode_offset =
5625 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005626
plougher360514a2009-03-30 03:01:38 +00005627 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5628 &data_cache, &directory_table,
5629 &directory_data_cache, &last_directory_block,
5630 &inode_dir_offset, &inode_dir_file_size,
5631 &root_inode_size, &inode_dir_start_block,
5632 &file_count, &sym_count, &dev_count, &dir_count,
5633 &fifo_count, &sock_count, &total_bytes,
5634 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005635 &inode_dir_inode_number,
5636 &inode_dir_parent_inode, add_old_root_entry,
5637 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005638 ERROR("Failed to read existing filesystem - will not "
5639 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005640 ERROR("To force Mksquashfs to write to this block "
5641 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005642 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005643 }
plougher6f2a8262010-07-27 00:37:19 +00005644 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005645 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005646 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005647 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005648 if(fragment_table == NULL)
5649 BAD_ERROR("Out of memory in save filesystem state\n");
5650 }
plougher1f413c82005-11-18 00:02:14 +00005651
plougher50b31762009-03-31 04:14:46 +00005652 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005653 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005654 block_size);
plougher89c7a512010-12-15 08:35:51 +00005655 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005656 "-always-use-fragments,\n-exportable and -comp options "
5657 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005658 printf("\nIf appending is not wanted, please re-run with "
5659 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005660
plougher360514a2009-03-30 03:01:38 +00005661 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5662 ~(SQUASHFS_METADATA_SIZE - 1);
5663 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5664 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005665
5666 /* save original filesystem state for restoring ... */
5667 sfragments = fragments;
5668 sbytes = bytes;
5669 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005670 scache_bytes = root_inode_offset + root_inode_size;
5671 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005672 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005673 if(sdata_cache == NULL)
5674 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005675 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005676 if(sdirectory_data_cache == NULL)
5677 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005678 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005679 memcpy(sdirectory_data_cache, directory_data_cache +
5680 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005681 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005682 stotal_bytes = total_bytes;
5683 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005684 stotal_directory_bytes = total_directory_bytes +
5685 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005686 sfile_count = file_count;
5687 ssym_count = sym_count;
5688 sdev_count = dev_count;
5689 sdir_count = dir_count + 1;
5690 sfifo_count = fifo_count;
5691 ssock_count = sock_count;
5692 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005693 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005694 write_recovery_data(&sBlk);
Phillip Lougher3bcf67d2013-02-24 10:56:38 +00005695 save_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005696 restore = TRUE;
5697 if(setjmp(env))
5698 goto restore_filesystem;
5699 signal(SIGTERM, sighandler);
5700 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005701 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005702
plougher360514a2009-03-30 03:01:38 +00005703 /*
5704 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005705 * original filesystem. The filesystem state differs depending
5706 * on whether we're appending to the original root directory, or
5707 * if the original root directory becomes a sub-directory
5708 * (root-becomes specified on command line, here root_name !=
5709 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005710 */
5711 inode_bytes = inode_size = root_inode_start;
5712 directory_size = last_directory_block;
5713 cache_size = root_inode_offset + root_inode_size;
5714 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5715 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005716 sdirectory_bytes = last_directory_block;
5717 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005718 root_inode_number = inode_dir_parent_inode;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005719 inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005720 directory_bytes = last_directory_block;
5721 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005722 memmove(directory_data_cache, directory_data_cache +
5723 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005724 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005725 add_old_root_entry(root_name, sBlk.root_inode,
5726 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005727 total_directory_bytes += compressed_data;
5728 dir_count ++;
5729 } else {
plougher360514a2009-03-30 03:01:38 +00005730 sdirectory_compressed_bytes = last_directory_block -
5731 inode_dir_start_block;
5732 sdirectory_compressed =
5733 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005734 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005735 BAD_ERROR("Out of memory in save filesystem "
5736 "state\n");
plougher360514a2009-03-30 03:01:38 +00005737 memcpy(sdirectory_compressed, directory_table +
5738 inode_dir_start_block,
5739 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005740 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005741 root_inode_number = inode_dir_inode_number;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005742 inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005743 directory_bytes = inode_dir_start_block;
5744 directory_cache_bytes = inode_dir_offset;
5745 cache_bytes = root_inode_offset;
5746 }
5747
plougher360514a2009-03-30 03:01:38 +00005748 inode_count = file_count + dir_count + sym_count + dev_count +
5749 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005750
5751 /*
5752 * The default use freelist before growing cache policy behaves
5753 * poorly with appending - with many deplicates the caches
5754 * do not grow due to the fact that large queues of outstanding
5755 * fragments/writer blocks do not occur, leading to small caches
5756 * and un-uncessary performance loss to frequent cache
5757 * replacement in the small caches. Therefore with appending
5758 * change the policy to grow the caches before reusing blocks
5759 * from the freelist
5760 */
5761 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005762 }
5763
Phillip Lougherb2abb1c2013-01-09 04:51:21 +00005764 if(path)
5765 paths = add_subdir(paths, path);
plougherf9039c92007-10-22 03:54:16 +00005766
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005767 dump_actions();
5768
plougher360514a2009-03-30 03:01:38 +00005769 if(delete && !keep_as_directory && source == 1 &&
5770 S_ISDIR(source_buf.st_mode))
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005771 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005772 else if(!keep_as_directory && source == 1 &&
5773 S_ISDIR(source_buf.st_mode))
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005774 dir_scan(&inode, source_path[0], scan1_single_readdir);
plougher1f413c82005-11-18 00:02:14 +00005775 else
Phillip Lougher5ef2eba2012-12-24 20:33:13 +00005776 dir_scan(&inode, "", scan1_encomp_readdir);
plougher1f413c82005-11-18 00:02:14 +00005777 sBlk.root_inode = inode;
5778 sBlk.inodes = inode_count;
5779 sBlk.s_magic = SQUASHFS_MAGIC;
5780 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005781 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005782 sBlk.block_size = block_size;
5783 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005784 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005785 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005786 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005787 sBlk.mkfs_time = time(NULL);
5788
5789restore_filesystem:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01005790 if(progress)
plougherc9b11db2008-05-06 23:59:15 +00005791 disable_progress_bar();
plougherc9b11db2008-05-06 23:59:15 +00005792
plougher1f413c82005-11-18 00:02:14 +00005793 sBlk.fragments = fragments;
plougher875bfef2010-08-12 23:48:41 +00005794 if(!restoring) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005795 struct file_buffer **fragment = NULL;
5796 while((fragment = get_frag_action(fragment)))
5797 write_fragment(*fragment);
plougher2ea89142008-03-11 01:34:19 +00005798 unlock_fragments();
5799 pthread_mutex_lock(&fragment_mutex);
5800 while(fragments_outstanding) {
5801 pthread_mutex_unlock(&fragment_mutex);
5802 sched_yield();
5803 pthread_mutex_lock(&fragment_mutex);
5804 }
plougher5507dd92006-11-06 00:43:10 +00005805 queue_put(to_writer, NULL);
5806 if(queue_get(from_writer) != 0)
5807 EXIT_MKSQUASHFS();
5808 }
5809
ploughere6e0e1b2010-05-12 17:17:06 +00005810 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005811 sBlk.inode_table_start = write_inodes();
5812 sBlk.directory_table_start = write_directories();
5813 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005814 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5815 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005816 sBlk.id_table_start = write_id_table();
5817 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005818
plougher0e453652006-11-06 01:49:35 +00005819 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005820 TRACE("sBlk->directory_table_start 0x%llx\n",
5821 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005822 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5823 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005824 TRACE("sBlk->lookup_table_start 0x%llx\n",
5825 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005826
plougher1f413c82005-11-18 00:02:14 +00005827 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005828
plougher8c4b7b92009-07-30 04:47:52 +00005829 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005830
plougher1f288f62009-02-21 03:05:52 +00005831 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher29e2ace2010-12-31 08:50:00 +00005832 write_destination(fd, SQUASHFS_START, sizeof(sBlk), &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005833
5834 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005835 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005836 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005837 }
5838
plougher99ac0cc2007-10-29 03:17:10 +00005839 close(fd);
5840
plougher11e7b1b2009-09-11 12:10:58 +00005841 delete_pseudo_files();
5842
Phillip Lougheraf4c9232012-11-15 03:46:28 +00005843 if(recovery_file)
plougher99ac0cc2007-10-29 03:17:10 +00005844 unlink(recovery_file);
5845
plougher10f7d572010-07-20 02:14:04 +00005846 total_bytes += total_inode_bytes + total_directory_bytes +
plougher64e83fd2010-12-31 21:21:26 +00005847 sizeof(struct squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005848
plougher62542fb2009-08-06 08:43:08 +00005849 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5850 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5851 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005852 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005853 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5854 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005855 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5856 "compressed");
plougher50b31762009-03-31 04:14:46 +00005857 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5858 "not ");
plougher360514a2009-03-30 03:01:38 +00005859 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5860 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005861 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5862 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5863 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5864 inode_bytes, inode_bytes / 1024.0);
5865 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005866 ((float) inode_bytes / total_inode_bytes) * 100.0,
5867 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005868 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5869 directory_bytes, directory_bytes / 1024.0);
5870 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005871 ((float) directory_bytes / total_directory_bytes) * 100.0,
5872 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005873 if(total_xattr_bytes) {
5874 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5875 xattr_bytes, xattr_bytes / 1024.0);
5876 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5877 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5878 total_xattr_bytes);
5879 }
plougher1f413c82005-11-18 00:02:14 +00005880 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005881 printf("Number of duplicate files found %d\n", file_count -
5882 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005883 else
5884 printf("No duplicate files removed\n");
5885 printf("Number of inodes %d\n", inode_count);
5886 printf("Number of files %d\n", file_count);
5887 if(!no_fragments)
5888 printf("Number of fragments %d\n", fragments);
5889 printf("Number of symbolic links %d\n", sym_count);
5890 printf("Number of device nodes %d\n", dev_count);
5891 printf("Number of fifo nodes %d\n", fifo_count);
5892 printf("Number of socket nodes %d\n", sock_count);
5893 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005894 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005895 printf("Number of uids %d\n", uid_count);
5896
plougher1b899fc2008-08-07 01:24:06 +00005897 for(i = 0; i < id_count; i++) {
5898 if(id_table[i]->flags & ISA_UID) {
5899 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005900 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5901 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005902 }
plougher1f413c82005-11-18 00:02:14 +00005903 }
5904
5905 printf("Number of gids %d\n", guid_count);
5906
plougher1b899fc2008-08-07 01:24:06 +00005907 for(i = 0; i < id_count; i++) {
5908 if(id_table[i]->flags & ISA_GID) {
5909 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005910 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5911 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005912 }
plougher1f413c82005-11-18 00:02:14 +00005913 }
plougher99ac0cc2007-10-29 03:17:10 +00005914
plougher1f413c82005-11-18 00:02:14 +00005915 return 0;
5916}