blob: a5aebec014ede537da2b3e6d6facdc5e2dd60b37 [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
plougher16111452010-07-22 05:12:18 +00002 * Create a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
plougher1f413c82005-11-18 00:02:14 +00004 *
Phillip Lougher43cc4282012-01-25 00:25:56 +00005 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
6 * 2012
plougherf6cd3372007-08-19 03:33:23 +00007 * Phillip Lougher <phillip@lougher.demon.co.uk>
plougher1f413c82005-11-18 00:02:14 +00008 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2,
12 * or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * mksquashfs.c
24 */
25
plougher324978d2006-02-27 04:53:29 +000026#define FALSE 0
plougher1f413c82005-11-18 00:02:14 +000027#define TRUE 1
plougher8cb05cd2005-12-11 23:32:35 +000028
plougher1f413c82005-11-18 00:02:14 +000029#include <pwd.h>
30#include <grp.h>
31#include <time.h>
32#include <unistd.h>
33#include <stdio.h>
plougherac28cd12010-02-24 02:25:03 +000034#include <stddef.h>
plougher1f413c82005-11-18 00:02:14 +000035#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <dirent.h>
40#include <string.h>
plougher1f413c82005-11-18 00:02:14 +000041#include <stdlib.h>
42#include <signal.h>
43#include <setjmp.h>
plougher02bc3bc2007-02-25 12:12:01 +000044#include <sys/types.h>
plougher1f413c82005-11-18 00:02:14 +000045#include <sys/mman.h>
plougher5507dd92006-11-06 00:43:10 +000046#include <pthread.h>
plougher8f8e1a12007-10-18 02:50:21 +000047#include <regex.h>
48#include <fnmatch.h>
plougherba674e82009-09-10 03:50:00 +000049#include <sys/wait.h>
plougher1f413c82005-11-18 00:02:14 +000050
plougher68853292005-12-27 02:47:04 +000051#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000052#define __BYTE_ORDER BYTE_ORDER
53#define __BIG_ENDIAN BIG_ENDIAN
54#define __LITTLE_ENDIAN LITTLE_ENDIAN
plougher5507dd92006-11-06 00:43:10 +000055#include <sys/sysctl.h>
plougher8cb05cd2005-12-11 23:32:35 +000056#else
57#include <endian.h>
plougher5507dd92006-11-06 00:43:10 +000058#include <sys/sysinfo.h>
plougher8cb05cd2005-12-11 23:32:35 +000059#endif
60
plougher1f413c82005-11-18 00:02:14 +000061#ifdef SQUASHFS_TRACE
plougher16111452010-07-22 05:12:18 +000062#define TRACE(s, args...) \
63 do { \
plougher16111452010-07-22 05:12:18 +000064 printf("mksquashfs: "s, ## args); \
65 } while(0)
plougher1f413c82005-11-18 00:02:14 +000066#else
67#define TRACE(s, args...)
68#endif
69
plougher16111452010-07-22 05:12:18 +000070#define INFO(s, args...) \
71 do {\
72 if(!silent)\
73 printf("mksquashfs: "s, ## args);\
74 } while(0)
75
76#define ERROR(s, args...) \
77 do {\
Phillip Lougher3b89ee82012-10-18 23:55:37 +010078 progressbar_error(s, ## args); \
plougher16111452010-07-22 05:12:18 +000079 } while(0)
80
81#define EXIT_MKSQUASHFS() \
82 do {\
83 if(restore)\
84 restorefs();\
85 if(delete && destination_file && !block_device)\
86 unlink(destination_file);\
87 exit(1);\
88 } while(0)
89
90#define BAD_ERROR(s, args...) \
91 do {\
Phillip Lougher3b89ee82012-10-18 23:55:37 +010092 progressbar_error("FATAL ERROR:" s, ##args); \
plougher16111452010-07-22 05:12:18 +000093 EXIT_MKSQUASHFS();\
94 } while(0)
plougher1f413c82005-11-18 00:02:14 +000095
plougher860c1f32010-08-11 01:37:17 +000096#include "squashfs_fs.h"
plougher860c1f32010-08-11 01:37:17 +000097#include "squashfs_swap.h"
98#include "mksquashfs.h"
99#include "sort.h"
100#include "pseudo.h"
101#include "compressor.h"
102#include "xattr.h"
Phillip Lougher4bcb7f82011-08-28 03:18:26 +0100103#include "action.h"
Phillip Lougher3b89ee82012-10-18 23:55:37 +0100104#include "progressbar.h"
plougher860c1f32010-08-11 01:37:17 +0000105
plougher324978d2006-02-27 04:53:29 +0000106int delete = FALSE;
plougher1f413c82005-11-18 00:02:14 +0000107int fd;
108
109/* filesystem flags for building */
plougher3d7e5182010-12-25 01:49:42 +0000110int comp_opts = FALSE;
plougher30281c82010-08-25 05:06:11 +0000111int no_xattrs = XATTR_DEF, noX = 0;
plougher1f413c82005-11-18 00:02:14 +0000112int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
plougher6d89ac22010-05-19 02:59:23 +0000113int noI = 0, noD = 0;
plougher1f288f62009-02-21 03:05:52 +0000114int silent = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000115long long global_uid = -1, global_gid = -1;
plougher02bc3bc2007-02-25 12:12:01 +0000116int exportable = TRUE;
117int progress = TRUE;
plougher8dcc6992007-08-17 19:32:52 +0000118int sparse_files = TRUE;
plougher8f8e1a12007-10-18 02:50:21 +0000119int old_exclude = TRUE;
120int use_regex = FALSE;
plougher801ba6a2010-02-01 03:12:59 +0000121int first_freelist = TRUE;
plougher1f413c82005-11-18 00:02:14 +0000122
123/* superblock attributes */
124int block_size = SQUASHFS_FILE_SIZE, block_log;
plougher1b899fc2008-08-07 01:24:06 +0000125unsigned int id_count = 0;
plougherfd57dfe2009-03-30 01:17:52 +0000126int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
127 sock_count = 0;
plougher1f413c82005-11-18 00:02:14 +0000128
129/* write position within data section */
130long long bytes = 0, total_bytes = 0;
131
132/* in memory directory table - possibly compressed */
133char *directory_table = NULL;
134unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
135
136/* cached directory table */
137char *directory_data_cache = NULL;
138unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
139
140/* in memory inode table - possibly compressed */
141char *inode_table = NULL;
142unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
143
144/* cached inode table */
145char *data_cache = NULL;
146unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
147
plougher0e453652006-11-06 01:49:35 +0000148/* inode lookup table */
149squashfs_inode *inode_lookup_table = NULL;
150
plougher1f413c82005-11-18 00:02:14 +0000151/* in memory directory data */
152#define I_COUNT_SIZE 128
153#define DIR_ENTRIES 32
154#define INODE_HASH_SIZE 65536
155#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
156#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
157
158struct cached_dir_index {
plougher2bd2b722010-12-31 10:52:15 +0000159 struct squashfs_dir_index index;
160 char *name;
plougher1f413c82005-11-18 00:02:14 +0000161};
162
163struct directory {
164 unsigned int start_block;
165 unsigned int size;
166 unsigned char *buff;
167 unsigned char *p;
168 unsigned int entry_count;
169 unsigned char *entry_count_p;
170 unsigned int i_count;
171 unsigned int i_size;
172 struct cached_dir_index *index;
173 unsigned char *index_count_p;
174 unsigned int inode_number;
175};
176
plougher1f413c82005-11-18 00:02:14 +0000177struct inode_info *inode_info[INODE_HASH_SIZE];
178
179/* hash tables used to do fast duplicate searches in duplicate check */
plougher5507dd92006-11-06 00:43:10 +0000180struct file_info *dupl[65536];
plougher1f413c82005-11-18 00:02:14 +0000181int dup_files = 0;
182
plougher8f8e1a12007-10-18 02:50:21 +0000183/* exclude file handling */
plougher1f413c82005-11-18 00:02:14 +0000184/* list of exclude dirs/files */
185struct exclude_info {
186 dev_t st_dev;
187 ino_t st_ino;
188};
189
190#define EXCLUDE_SIZE 8192
191int exclude = 0;
192struct exclude_info *exclude_paths = NULL;
plougher8f8e1a12007-10-18 02:50:21 +0000193int old_excluded(char *filename, struct stat *buf);
194
195struct path_entry {
196 char *name;
197 regex_t *preg;
198 struct pathname *paths;
199};
200
201struct pathname {
202 int names;
203 struct path_entry *name;
204};
205
plougherf9039c92007-10-22 03:54:16 +0000206struct pathnames {
207 int count;
208 struct pathname *path[0];
209};
210#define PATHS_ALLOC_SIZE 10
211
212struct pathnames *paths = NULL;
213struct pathname *path = NULL;
plougher05e50ef2007-10-23 12:34:20 +0000214struct pathname *stickypath = NULL;
plougherf9039c92007-10-22 03:54:16 +0000215int excluded(struct pathnames *paths, char *name, struct pathnames **new);
plougher1f413c82005-11-18 00:02:14 +0000216
217/* fragment block data structures */
218int fragments = 0;
plougher76c64082008-03-08 01:32:23 +0000219
plougher1f413c82005-11-18 00:02:14 +0000220struct fragment {
221 unsigned int index;
222 int offset;
223 int size;
224};
plougher76c64082008-03-08 01:32:23 +0000225
plougher1f413c82005-11-18 00:02:14 +0000226#define FRAG_SIZE 32768
plougher76c64082008-03-08 01:32:23 +0000227#define FRAG_INDEX (1LL << 32)
228
plougher8ed84b92010-12-31 10:37:24 +0000229struct squashfs_fragment_entry *fragment_table = NULL;
plougher5507dd92006-11-06 00:43:10 +0000230int fragments_outstanding = 0;
plougher1f413c82005-11-18 00:02:14 +0000231
plougher1f413c82005-11-18 00:02:14 +0000232/* current inode number for directories and non directories */
Phillip Lougher539c2b12012-07-30 20:14:52 +0100233unsigned int inode_no = 1;
plougherdf70c3e2006-01-27 09:34:13 +0000234unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000235
236/* list of source dirs/files */
237int source = 0;
238char **source_path;
239
240/* list of root directory entries read from original filesystem */
241int old_root_entries = 0;
242struct old_root_entry_info {
ploughera326c182009-08-29 05:41:45 +0000243 char *name;
244 struct inode_info inode;
plougher1f413c82005-11-18 00:02:14 +0000245};
246struct old_root_entry_info *old_root_entry;
247
248/* in memory file info */
249struct file_info {
plougher5507dd92006-11-06 00:43:10 +0000250 long long file_size;
plougherf9c72b12006-01-23 13:52:40 +0000251 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000252 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +0000253 unsigned short fragment_checksum;
plougher1f413c82005-11-18 00:02:14 +0000254 long long start;
255 unsigned int *block_list;
256 struct file_info *next;
257 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +0000258 char checksum_flag;
plougher1f413c82005-11-18 00:02:14 +0000259};
260
261/* count of how many times SIGINT or SIGQUIT has been sent */
262int interrupted = 0;
263
plougher875bfef2010-08-12 23:48:41 +0000264/* flag if we're restoring existing filesystem */
265int restoring = 0;
266
plougherfd57dfe2009-03-30 01:17:52 +0000267/* restore orignal filesystem state if appending to existing filesystem is
268 * cancelled */
plougher1f413c82005-11-18 00:02:14 +0000269jmp_buf env;
plougherca2c93f2008-08-15 08:34:57 +0000270char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
plougher1f413c82005-11-18 00:02:14 +0000271
272long long sbytes, stotal_bytes;
273
274unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
plougherca2c93f2008-08-15 08:34:57 +0000275 sdirectory_cache_bytes, sdirectory_compressed_bytes,
plougher1f413c82005-11-18 00:02:14 +0000276 stotal_inode_bytes, stotal_directory_bytes,
plougher0e453652006-11-06 01:49:35 +0000277 sinode_count = 0, sfile_count, ssym_count, sdev_count,
plougher1f413c82005-11-18 00:02:14 +0000278 sdir_count, sfifo_count, ssock_count, sdup_files;
279int sfragments;
280int restore = 0;
plougher5507dd92006-11-06 00:43:10 +0000281int threads;
plougher1f413c82005-11-18 00:02:14 +0000282
283/* flag whether destination file is a block device */
284int block_device = 0;
285
286/* flag indicating whether files are sorted using sort list(s) */
287int sorted = 0;
288
plougher324978d2006-02-27 04:53:29 +0000289/* save destination file name for deleting on error */
290char *destination_file = NULL;
291
plougher99ac0cc2007-10-29 03:17:10 +0000292/* recovery file for abnormal exit on appending */
293char recovery_file[1024] = "";
294int recover = TRUE;
295
ploughereb6eac92008-02-26 01:50:48 +0000296/* struct describing a cache entry passed between threads */
plougher5507dd92006-11-06 00:43:10 +0000297struct file_buffer {
ploughereb6eac92008-02-26 01:50:48 +0000298 struct cache *cache;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100299 struct file_buffer *hash_next;
300 struct file_buffer *hash_prev;
301 struct file_buffer *free_next;
302 struct file_buffer *free_prev;
303 struct file_buffer *next;
plougher76c64082008-03-08 01:32:23 +0000304 long long file_size;
ploughereb6eac92008-02-26 01:50:48 +0000305 long long index;
306 long long block;
plougher0f464442008-03-31 00:27:56 +0000307 long long sequence;
ploughereb6eac92008-02-26 01:50:48 +0000308 int size;
309 int c_byte;
Phillip Lougherfe30cc62011-08-29 01:48:08 +0100310 char keep;
311 char used;
312 char fragment;
313 char error;
Phillip Lougher63f531f2011-09-10 04:03:32 +0100314 char noD;
plougher76c64082008-03-08 01:32:23 +0000315 char data[0];
plougher5507dd92006-11-06 00:43:10 +0000316};
317
ploughereb6eac92008-02-26 01:50:48 +0000318
plougher5507dd92006-11-06 00:43:10 +0000319/* struct describing queues used to pass data between threads */
320struct queue {
321 int size;
322 int readp;
323 int writep;
324 pthread_mutex_t mutex;
325 pthread_cond_t empty;
326 pthread_cond_t full;
327 void **data;
328};
329
plougher1b899fc2008-08-07 01:24:06 +0000330
331/* in memory uid tables */
332#define ID_ENTRIES 256
333#define ID_HASH(id) (id & (ID_ENTRIES - 1))
334#define ISA_UID 1
335#define ISA_GID 2
336struct id {
337 unsigned int id;
338 int index;
339 char flags;
340 struct id *next;
plougher5507dd92006-11-06 00:43:10 +0000341};
plougher1b899fc2008-08-07 01:24:06 +0000342struct id *id_hash_table[ID_ENTRIES];
343struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
344unsigned int uid_count = 0, guid_count = 0;
345unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
plougher5507dd92006-11-06 00:43:10 +0000346
ploughereb6eac92008-02-26 01:50:48 +0000347struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
plougherfd57dfe2009-03-30 01:17:52 +0000348struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
349 *to_frag;
Phillip Lougher3b89ee82012-10-18 23:55:37 +0100350pthread_t *thread, *deflator_thread, *frag_deflator_thread;
plougher5507dd92006-11-06 00:43:10 +0000351pthread_mutex_t fragment_mutex;
352pthread_cond_t fragment_waiting;
353pthread_mutex_t pos_mutex;
plougher43244f22009-04-05 02:04:51 +0000354struct pseudo *pseudo = NULL;
plougher5507dd92006-11-06 00:43:10 +0000355
356/* user options that control parallelisation */
357int processors = -1;
358/* default size of output buffer in Mbytes */
359#define WRITER_BUFFER_DEFAULT 512
360/* default size of input buffer in Mbytes */
361#define READER_BUFFER_DEFAULT 64
plougher76c64082008-03-08 01:32:23 +0000362/* default size of fragment buffer in Mbytes */
363#define FRAGMENT_BUFFER_DEFAULT 64
plougher5507dd92006-11-06 00:43:10 +0000364int writer_buffer_size;
plougher5507dd92006-11-06 00:43:10 +0000365
plougherc5d59872010-11-22 01:36:01 +0000366/* compression operations */
ploughera175ce22009-07-30 04:43:27 +0000367static struct compressor *comp;
plougherc5d59872010-11-22 01:36:01 +0000368int compressor_opts_parsed = 0;
plougher13fdddf2010-11-24 01:23:41 +0000369void *stream = NULL;
plougher7b8ee502009-07-29 07:54:30 +0000370
plougher860c1f32010-08-11 01:37:17 +0000371/* xattr stats */
372unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
373
plougher49b57a92009-03-31 03:23:05 +0000374char *read_from_disk(long long start, unsigned int avail_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000375void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
376 int type);
plougher64e83fd2010-12-31 21:21:26 +0000377extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
ploughera175ce22009-07-30 04:43:27 +0000378 char *source);
plougherfd57dfe2009-03-30 01:17:52 +0000379extern long long read_filesystem(char *root_name, int fd,
plougher64e83fd2010-12-31 21:21:26 +0000380 struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
plougherfd57dfe2009-03-30 01:17:52 +0000381 char **cdirectory_table, char **directory_data_cache,
382 unsigned int *last_directory_block, unsigned int *inode_dir_offset,
383 unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
384 unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
385 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
386 long long *uncompressed_file, unsigned int *uncompressed_inode,
plougher50b31762009-03-31 04:14:46 +0000387 unsigned int *uncompressed_directory,
388 unsigned int *inode_dir_inode_number,
389 unsigned int *inode_dir_parent_inode,
plougherfd57dfe2009-03-30 01:17:52 +0000390 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher8ed84b92010-12-31 10:37:24 +0000391 struct squashfs_fragment_entry **fragment_table,
plougherfd57dfe2009-03-30 01:17:52 +0000392 squashfs_inode **inode_lookup_table);
plougher5507dd92006-11-06 00:43:10 +0000393extern int read_sort_file(char *filename, int source, char *source_path[]);
394extern void sort_files_and_write(struct dir_info *dir);
plougherfd57dfe2009-03-30 01:17:52 +0000395struct file_info *duplicate(long long file_size, long long bytes,
396 unsigned int **block_list, long long *start, struct fragment **fragment,
397 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
398 unsigned short fragment_checksum, int checksum_flag);
Phillip Lougherb38c1722012-02-09 23:26:19 +0000399struct dir_info *dir_scan1(char *, char *, struct pathnames *,
Phillip Lougher494479f2012-02-03 15:45:41 +0000400 struct dir_ent *(_readdir)(struct dir_info *), int);
Phillip Lougher24eeb772012-10-13 01:56:24 +0100401void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
Phillip Lougher23d83622012-10-14 02:35:22 +0100402void dir_scan3(struct dir_info *root, struct dir_info *dir);
403void dir_scan4(struct dir_info *dir);
404void dir_scan5(squashfs_inode *inode, struct dir_info *dir_info);
plougherfd57dfe2009-03-30 01:17:52 +0000405struct file_info *add_non_dup(long long file_size, long long bytes,
406 unsigned int *block_list, long long start, struct fragment *fragment,
407 unsigned short checksum, unsigned short fragment_checksum,
408 int checksum_flag);
plougher1d1c6bb2010-07-21 03:03:13 +0000409extern int generate_file_priorities(struct dir_info *dir, int priority,
plougherfd57dfe2009-03-30 01:17:52 +0000410 struct stat *buf);
plougher5507dd92006-11-06 00:43:10 +0000411extern struct priority_entry *priority_list[65536];
ploughera0a49c32010-08-11 01:47:59 +0000412long long generic_write_table(int, void *, int, void *, int);
plougherca61d1c2010-07-20 18:32:32 +0000413void restorefs();
Phillip Lougher1eae83d2012-09-26 02:12:45 +0100414struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
plougher5507dd92006-11-06 00:43:10 +0000415
416
plougher5507dd92006-11-06 00:43:10 +0000417struct queue *queue_init(int size)
418{
419 struct queue *queue = malloc(sizeof(struct queue));
420
421 if(queue == NULL)
plougherca61d1c2010-07-20 18:32:32 +0000422 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000423
plougher0d55d9e2010-12-16 04:50:21 +0000424 queue->data = malloc(sizeof(void *) * (size + 1));
425 if(queue->data == NULL) {
plougher5507dd92006-11-06 00:43:10 +0000426 free(queue);
plougherca61d1c2010-07-20 18:32:32 +0000427 goto failed;
plougher5507dd92006-11-06 00:43:10 +0000428 }
429
430 queue->size = size + 1;
431 queue->readp = queue->writep = 0;
432 pthread_mutex_init(&queue->mutex, NULL);
433 pthread_cond_init(&queue->empty, NULL);
434 pthread_cond_init(&queue->full, NULL);
435
436 return queue;
plougherca61d1c2010-07-20 18:32:32 +0000437
438failed:
439 BAD_ERROR("Out of memory in queue_init\n");
plougher5507dd92006-11-06 00:43:10 +0000440}
441
442
443void queue_put(struct queue *queue, void *data)
444{
445 int nextp;
446
447 pthread_mutex_lock(&queue->mutex);
448
449 while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
450 pthread_cond_wait(&queue->full, &queue->mutex);
451
452 queue->data[queue->writep] = data;
453 queue->writep = nextp;
454 pthread_cond_signal(&queue->empty);
455 pthread_mutex_unlock(&queue->mutex);
456}
457
458
459void *queue_get(struct queue *queue)
460{
461 void *data;
462 pthread_mutex_lock(&queue->mutex);
463
464 while(queue->readp == queue->writep)
465 pthread_cond_wait(&queue->empty, &queue->mutex);
466
467 data = queue->data[queue->readp];
468 queue->readp = (queue->readp + 1) % queue->size;
469 pthread_cond_signal(&queue->full);
470 pthread_mutex_unlock(&queue->mutex);
471
472 return data;
473}
474
plougher1f413c82005-11-18 00:02:14 +0000475
ploughereb6eac92008-02-26 01:50:48 +0000476/* Cache status struct. Caches are used to keep
477 track of memory buffers passed between different threads */
478struct cache {
479 int max_buffers;
480 int count;
481 int buffer_size;
ploughereb6eac92008-02-26 01:50:48 +0000482 pthread_mutex_t mutex;
483 pthread_cond_t wait_for_free;
484 struct file_buffer *free_list;
485 struct file_buffer *hash_table[65536];
486};
487
488
plougher2ea89142008-03-11 01:34:19 +0000489#define INSERT_LIST(NAME, TYPE) \
490void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
491 if(*list) { \
492 entry->NAME##_next = *list; \
493 entry->NAME##_prev = (*list)->NAME##_prev; \
494 (*list)->NAME##_prev->NAME##_next = entry; \
495 (*list)->NAME##_prev = entry; \
496 } else { \
497 *list = entry; \
498 entry->NAME##_prev = entry->NAME##_next = entry; \
499 } \
500}
501
502
503#define REMOVE_LIST(NAME, TYPE) \
504void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
505 if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
506 /* only this entry in the list */ \
507 *list = NULL; \
508 } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
509 /* more than one entry in the list */ \
510 entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
511 entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
512 if(*list == entry) \
513 *list = entry->NAME##_next; \
514 } \
515 entry->NAME##_prev = entry->NAME##_next = NULL; \
516}
517
518
519#define CALCULATE_HASH(start) (start & 0xffff) \
ploughereb6eac92008-02-26 01:50:48 +0000520
521
522/* Called with the cache mutex held */
523void insert_hash_table(struct cache *cache, struct file_buffer *entry)
524{
525 int hash = CALCULATE_HASH(entry->index);
526
527 entry->hash_next = cache->hash_table[hash];
528 cache->hash_table[hash] = entry;
529 entry->hash_prev = NULL;
530 if(entry->hash_next)
531 entry->hash_next->hash_prev = entry;
532}
533
534
535/* Called with the cache mutex held */
536void remove_hash_table(struct cache *cache, struct file_buffer *entry)
537{
538 if(entry->hash_prev)
539 entry->hash_prev->hash_next = entry->hash_next;
540 else
plougher50b31762009-03-31 04:14:46 +0000541 cache->hash_table[CALCULATE_HASH(entry->index)] =
542 entry->hash_next;
ploughereb6eac92008-02-26 01:50:48 +0000543 if(entry->hash_next)
544 entry->hash_next->hash_prev = entry->hash_prev;
545
546 entry->hash_prev = entry->hash_next = NULL;
547}
548
549
550/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000551INSERT_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000552
553/* Called with the cache mutex held */
plougher2ea89142008-03-11 01:34:19 +0000554REMOVE_LIST(free, struct file_buffer)
ploughereb6eac92008-02-26 01:50:48 +0000555
556
557struct cache *cache_init(int buffer_size, int max_buffers)
558{
559 struct cache *cache = malloc(sizeof(struct cache));
560
561 if(cache == NULL)
plougher9ca649c2010-07-21 00:46:11 +0000562 BAD_ERROR("Out of memory in cache_init\n");
ploughereb6eac92008-02-26 01:50:48 +0000563
564 cache->max_buffers = max_buffers;
565 cache->buffer_size = buffer_size;
566 cache->count = 0;
567 cache->free_list = NULL;
568 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
ploughereb6eac92008-02-26 01:50:48 +0000569 pthread_mutex_init(&cache->mutex, NULL);
570 pthread_cond_init(&cache->wait_for_free, NULL);
571
572 return cache;
573}
574
575
576struct file_buffer *cache_lookup(struct cache *cache, long long index)
577{
578 /* Lookup block in the cache, if found return with usage count
579 * incremented, if not found return NULL */
580 int hash = CALCULATE_HASH(index);
581 struct file_buffer *entry;
582
583 pthread_mutex_lock(&cache->mutex);
584
585 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
586 if(entry->index == index)
587 break;
588
589 if(entry) {
590 /* found the block in the cache, increment used count and
591 * if necessary remove from free list so it won't disappear
592 */
593 entry->used ++;
plougher2ea89142008-03-11 01:34:19 +0000594 remove_free_list(&cache->free_list, entry);
ploughereb6eac92008-02-26 01:50:48 +0000595 }
596
597 pthread_mutex_unlock(&cache->mutex);
598
599 return entry;
600}
601
602
plougher76c64082008-03-08 01:32:23 +0000603struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
ploughereb6eac92008-02-26 01:50:48 +0000604{
605 /* Get a free block out of the cache indexed on index. */
606 struct file_buffer *entry;
607
608 pthread_mutex_lock(&cache->mutex);
609
plougher76c64082008-03-08 01:32:23 +0000610 while(1) {
611 /* first try to get a block from the free list */
plougher801ba6a2010-02-01 03:12:59 +0000612 if(first_freelist && cache->free_list) {
plougher76c64082008-03-08 01:32:23 +0000613 /* a block on the free_list is a "keep" block */
614 entry = cache->free_list;
plougher2ea89142008-03-11 01:34:19 +0000615 remove_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000616 remove_hash_table(cache, entry);
617 break;
plougher801ba6a2010-02-01 03:12:59 +0000618 } else if(cache->count < cache->max_buffers) {
plougher76c64082008-03-08 01:32:23 +0000619 /* next try to allocate new block */
plougherfd57dfe2009-03-30 01:17:52 +0000620 entry = malloc(sizeof(struct file_buffer) +
621 cache->buffer_size);
plougher76c64082008-03-08 01:32:23 +0000622 if(entry == NULL)
623 goto failed;
624 entry->cache = cache;
625 entry->free_prev = entry->free_next = NULL;
626 cache->count ++;
627 break;
plougher801ba6a2010-02-01 03:12:59 +0000628 } else if(!first_freelist && cache->free_list) {
plougher2ea89142008-03-11 01:34:19 +0000629 /* a block on the free_list is a "keep" block */
630 entry = cache->free_list;
631 remove_free_list(&cache->free_list, entry);
632 remove_hash_table(cache, entry);
633 break;
plougher801ba6a2010-02-01 03:12:59 +0000634 } else
plougher76c64082008-03-08 01:32:23 +0000635 /* wait for a block */
ploughereb6eac92008-02-26 01:50:48 +0000636 pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000637 }
638
plougher76c64082008-03-08 01:32:23 +0000639 /* initialise block and if a keep block insert into the hash table */
ploughereb6eac92008-02-26 01:50:48 +0000640 entry->used = 1;
641 entry->error = FALSE;
plougher76c64082008-03-08 01:32:23 +0000642 entry->keep = keep;
plougher0f464442008-03-31 00:27:56 +0000643 if(keep) {
644 entry->index = index;
plougher76c64082008-03-08 01:32:23 +0000645 insert_hash_table(cache, entry);
plougher0f464442008-03-31 00:27:56 +0000646 }
ploughereb6eac92008-02-26 01:50:48 +0000647 pthread_mutex_unlock(&cache->mutex);
648
649 return entry;
650
651failed:
652 pthread_mutex_unlock(&cache->mutex);
ploughercc6896d2010-07-21 00:56:25 +0000653 BAD_ERROR("Out of memory in cache_get\n");
ploughereb6eac92008-02-26 01:50:48 +0000654}
655
ploughereb6eac92008-02-26 01:50:48 +0000656
plougher0f464442008-03-31 00:27:56 +0000657void cache_rehash(struct file_buffer *entry, long long index)
658{
659 struct cache *cache = entry->cache;
660
661 pthread_mutex_lock(&cache->mutex);
662 if(entry->keep)
663 remove_hash_table(cache, entry);
664 entry->keep = TRUE;
665 entry->index = index;
666 insert_hash_table(cache, entry);
667 pthread_mutex_unlock(&cache->mutex);
668}
669
670
ploughereb6eac92008-02-26 01:50:48 +0000671void cache_block_put(struct file_buffer *entry)
672{
plougher76c64082008-03-08 01:32:23 +0000673 struct cache *cache;
674
ploughereb6eac92008-02-26 01:50:48 +0000675 /* finished with this cache entry, once the usage count reaches zero it
plougher76c64082008-03-08 01:32:23 +0000676 * can be reused and if a keep block put onto the free list. As keep
plougher50b31762009-03-31 04:14:46 +0000677 * blocks remain accessible via the hash table they can be found
678 * getting a new lease of life before they are reused. */
ploughereb6eac92008-02-26 01:50:48 +0000679
680 if(entry == NULL)
681 return;
682
plougher76c64082008-03-08 01:32:23 +0000683 cache = entry->cache;
ploughereb6eac92008-02-26 01:50:48 +0000684
plougher76c64082008-03-08 01:32:23 +0000685 pthread_mutex_lock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000686
687 entry->used --;
688 if(entry->used == 0) {
plougher76c64082008-03-08 01:32:23 +0000689 if(entry->keep)
plougher2ea89142008-03-11 01:34:19 +0000690 insert_free_list(&cache->free_list, entry);
plougher76c64082008-03-08 01:32:23 +0000691 else {
692 free(entry);
693 cache->count --;
ploughereb6eac92008-02-26 01:50:48 +0000694 }
plougher76c64082008-03-08 01:32:23 +0000695
696 /* One or more threads may be waiting on this block */
697 pthread_cond_signal(&cache->wait_for_free);
ploughereb6eac92008-02-26 01:50:48 +0000698 }
699
plougher76c64082008-03-08 01:32:23 +0000700 pthread_mutex_unlock(&cache->mutex);
ploughereb6eac92008-02-26 01:50:48 +0000701}
702
703
plougher50b31762009-03-31 04:14:46 +0000704#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
705 + (((char *)A) - data_cache)))
plougher1f413c82005-11-18 00:02:14 +0000706
707
plougher5507dd92006-11-06 00:43:10 +0000708inline void waitforthread(int i)
709{
710 TRACE("Waiting for thread %d\n", i);
711 while(thread[i] != 0)
712 sched_yield();
713}
714
715
plougher1f413c82005-11-18 00:02:14 +0000716void restorefs()
717{
plougher5507dd92006-11-06 00:43:10 +0000718 int i;
719
plougher02bc3bc2007-02-25 12:12:01 +0000720 if(thread == NULL || thread[0] == 0)
721 return;
722
plougher875bfef2010-08-12 23:48:41 +0000723 if(restoring++)
724 /*
plougher5b290d22010-08-12 23:52:21 +0000725 * Recursive failure when trying to restore filesystem!
726 * Nothing to do except to exit, otherwise we'll just appear
plougher875bfef2010-08-12 23:48:41 +0000727 * to hang. The user should be able to restore from the
plougher5b290d22010-08-12 23:52:21 +0000728 * recovery file (which is why it was added, in case of
729 * catastrophic failure in Mksquashfs)
plougher875bfef2010-08-12 23:48:41 +0000730 */
731 exit(1);
732
plougher1f413c82005-11-18 00:02:14 +0000733 ERROR("Exiting - restoring original filesystem!\n\n");
plougher5507dd92006-11-06 00:43:10 +0000734
plougher91fbb302008-05-06 02:29:36 +0000735 for(i = 0; i < 2 + processors * 2; i++)
plougher5aa18162007-12-13 12:15:21 +0000736 if(thread[i])
737 pthread_kill(thread[i], SIGUSR1);
plougher91fbb302008-05-06 02:29:36 +0000738 for(i = 0; i < 2 + processors * 2; i++)
plougher5507dd92006-11-06 00:43:10 +0000739 waitforthread(i);
740 TRACE("All threads in signal handler\n");
plougher1f413c82005-11-18 00:02:14 +0000741 bytes = sbytes;
742 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
plougherfd57dfe2009-03-30 01:17:52 +0000743 memcpy(directory_data_cache, sdirectory_data_cache,
744 sdirectory_cache_bytes);
745 directory_cache_bytes = sdirectory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +0000746 inode_bytes = sinode_bytes;
747 directory_bytes = sdirectory_bytes;
plougherfd57dfe2009-03-30 01:17:52 +0000748 memcpy(directory_table + directory_bytes, sdirectory_compressed,
749 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +0000750 directory_bytes += sdirectory_compressed_bytes;
plougher1f413c82005-11-18 00:02:14 +0000751 total_bytes = stotal_bytes;
752 total_inode_bytes = stotal_inode_bytes;
753 total_directory_bytes = stotal_directory_bytes;
754 inode_count = sinode_count;
755 file_count = sfile_count;
756 sym_count = ssym_count;
757 dev_count = sdev_count;
758 dir_count = sdir_count;
759 fifo_count = sfifo_count;
760 sock_count = ssock_count;
761 dup_files = sdup_files;
762 fragments = sfragments;
plougher1b899fc2008-08-07 01:24:06 +0000763 id_count = sid_count;
plougher21f63b32010-07-18 03:59:04 +0000764 restore_xattrs();
plougher1f413c82005-11-18 00:02:14 +0000765 longjmp(env, 1);
766}
767
768
769void sighandler()
770{
plougher5507dd92006-11-06 00:43:10 +0000771 if(++interrupted > 2)
772 return;
773 if(interrupted == 2)
plougher1f413c82005-11-18 00:02:14 +0000774 restorefs();
775 else {
776 ERROR("Interrupting will restore original filesystem!\n");
777 ERROR("Interrupt again to quit\n");
plougher1f413c82005-11-18 00:02:14 +0000778 }
779}
780
781
plougher324978d2006-02-27 04:53:29 +0000782void sighandler2()
783{
784 EXIT_MKSQUASHFS();
785}
786
787
plougher5507dd92006-11-06 00:43:10 +0000788void sigusr1_handler()
plougher1f413c82005-11-18 00:02:14 +0000789{
plougher5507dd92006-11-06 00:43:10 +0000790 int i;
791 sigset_t sigmask;
792 pthread_t thread_id = pthread_self();
plougher1f413c82005-11-18 00:02:14 +0000793
plougher5507dd92006-11-06 00:43:10 +0000794 for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
795 thread[i] = (pthread_t) 0;
796
plougher07966f72007-11-14 10:54:45 +0000797 TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
plougher5507dd92006-11-06 00:43:10 +0000798
799 sigemptyset(&sigmask);
800 sigaddset(&sigmask, SIGINT);
801 sigaddset(&sigmask, SIGQUIT);
802 sigaddset(&sigmask, SIGUSR1);
803 while(1) {
804 sigsuspend(&sigmask);
805 TRACE("After wait in sigusr1_handler :(\n");
806 }
807}
808
809
plougher13fdddf2010-11-24 01:23:41 +0000810int mangle2(void *strm, char *d, char *s, int size,
plougher50b31762009-03-31 04:14:46 +0000811 int block_size, int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000812{
plougher7b8ee502009-07-29 07:54:30 +0000813 int error, c_byte = 0;
plougher5507dd92006-11-06 00:43:10 +0000814
plougher7b8ee502009-07-29 07:54:30 +0000815 if(!uncompressed) {
plougherbfb876c2010-12-31 07:48:01 +0000816 c_byte = compressor_compress(comp, strm, d, s, size, block_size,
817 &error);
plougher7b8ee502009-07-29 07:54:30 +0000818 if(c_byte == -1)
819 BAD_ERROR("mangle2:: %s compress failed with error "
820 "code %d\n", comp->name, error);
plougher1f413c82005-11-18 00:02:14 +0000821 }
822
plougher7b8ee502009-07-29 07:54:30 +0000823 if(c_byte == 0 || c_byte >= size) {
plougher1f413c82005-11-18 00:02:14 +0000824 memcpy(d, s, size);
plougherfd57dfe2009-03-30 01:17:52 +0000825 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
826 SQUASHFS_COMPRESSED_BIT);
plougher1f413c82005-11-18 00:02:14 +0000827 }
828
plougher7b8ee502009-07-29 07:54:30 +0000829 return c_byte;
plougher1f413c82005-11-18 00:02:14 +0000830}
831
832
plougher7b8ee502009-07-29 07:54:30 +0000833int mangle(char *d, char *s, int size, int block_size,
plougher50b31762009-03-31 04:14:46 +0000834 int uncompressed, int data_block)
plougher5507dd92006-11-06 00:43:10 +0000835{
plougher13fdddf2010-11-24 01:23:41 +0000836 return mangle2(stream, d, s, size, block_size, uncompressed,
plougher50b31762009-03-31 04:14:46 +0000837 data_block);
plougher5507dd92006-11-06 00:43:10 +0000838}
839
840
plougherac28cd12010-02-24 02:25:03 +0000841void *get_inode(int req_size)
plougher1f413c82005-11-18 00:02:14 +0000842{
843 int data_space;
844 unsigned short c_byte;
845
846 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
plougherfd57dfe2009-03-30 01:17:52 +0000847 if((inode_size - inode_bytes) <
848 ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
plougher1eb2a662010-07-26 17:30:50 +0000849 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000850 (SQUASHFS_METADATA_SIZE << 1) + 2);
plougher1eb2a662010-07-26 17:30:50 +0000851 if(it == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000852 goto failed;
853 }
plougher1eb2a662010-07-26 17:30:50 +0000854 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +0000855 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
856 }
857
plougherfd57dfe2009-03-30 01:17:52 +0000858 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
plougher50b31762009-03-31 04:14:46 +0000859 data_cache, SQUASHFS_METADATA_SIZE,
860 SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +0000861 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +0000862 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +0000863 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
864 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +0000865 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
plougherfd57dfe2009-03-30 01:17:52 +0000866 cache_bytes - SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +0000867 cache_bytes -= SQUASHFS_METADATA_SIZE;
868 }
869
870 data_space = (cache_size - cache_bytes);
871 if(data_space < req_size) {
plougherfd57dfe2009-03-30 01:17:52 +0000872 int realloc_size = cache_size == 0 ?
873 ((req_size + SQUASHFS_METADATA_SIZE) &
874 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
875 data_space;
plougher1f413c82005-11-18 00:02:14 +0000876
plougher17248ca2010-07-27 00:24:35 +0000877 void *dc = realloc(data_cache, cache_size +
plougherfd57dfe2009-03-30 01:17:52 +0000878 realloc_size);
plougher17248ca2010-07-27 00:24:35 +0000879 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000880 goto failed;
881 }
882 cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +0000883 data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +0000884 }
885
886 cache_bytes += req_size;
887
plougherac28cd12010-02-24 02:25:03 +0000888 return data_cache + cache_bytes - req_size;
plougher1f413c82005-11-18 00:02:14 +0000889
890failed:
891 BAD_ERROR("Out of memory in inode table reallocation!\n");
892}
893
894
plougher8a8c4102009-03-29 22:28:49 +0000895int read_bytes(int fd, void *buff, int bytes)
plougher06a19d32009-03-29 22:00:03 +0000896{
897 int res, count;
898
899 for(count = 0; count < bytes; count += res) {
900 res = read(fd, buff + count, bytes - count);
901 if(res < 1) {
plougher96f85a12009-03-29 22:39:59 +0000902 if(res == 0)
903 goto bytes_read;
904 else if(errno != EINTR) {
plougher06a19d32009-03-29 22:00:03 +0000905 ERROR("Read failed because %s\n",
906 strerror(errno));
907 return -1;
908 } else
909 res = 0;
910 }
911 }
912
913bytes_read:
914 return count;
915}
916
917
plougher3306cb22010-06-18 04:22:44 +0000918int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000919{
920 off_t off = byte;
921
plougher1d065e92010-06-18 03:58:27 +0000922 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
plougherfd57dfe2009-03-30 01:17:52 +0000923 byte, bytes);
plougher06a19d32009-03-29 22:00:03 +0000924
plougher5507dd92006-11-06 00:43:10 +0000925 pthread_mutex_lock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000926 if(lseek(fd, off, SEEK_SET) == -1) {
927 ERROR("Lseek on destination failed because %s\n",
plougherfd57dfe2009-03-30 01:17:52 +0000928 strerror(errno));
plougher1d065e92010-06-18 03:58:27 +0000929 goto failed;
930 }
plougher1f413c82005-11-18 00:02:14 +0000931
plougher1d065e92010-06-18 03:58:27 +0000932 if(read_bytes(fd, buff, bytes) < bytes) {
933 ERROR("Read on destination failed\n");
934 goto failed;
935 }
936
plougher5507dd92006-11-06 00:43:10 +0000937 pthread_mutex_unlock(&pos_mutex);
plougher1d065e92010-06-18 03:58:27 +0000938 return 1;
939
940failed:
941 pthread_mutex_unlock(&pos_mutex);
942 return 0;
plougher1f413c82005-11-18 00:02:14 +0000943}
944
945
plougher628e7682009-03-29 22:12:24 +0000946int write_bytes(int fd, void *buff, int bytes)
plougher0dd6f122009-03-29 21:43:57 +0000947{
948 int res, count;
949
950 for(count = 0; count < bytes; count += res) {
951 res = write(fd, buff + count, bytes - count);
952 if(res == -1) {
953 if(errno != EINTR) {
954 ERROR("Write failed because %s\n",
955 strerror(errno));
956 return -1;
957 }
958 res = 0;
959 }
960 }
961
962 return 0;
963}
964
965
plougher29e2ace2010-12-31 08:50:00 +0000966void write_destination(int fd, long long byte, int bytes, void *buff)
plougher1f413c82005-11-18 00:02:14 +0000967{
968 off_t off = byte;
plougher1f413c82005-11-18 00:02:14 +0000969
plougher875bfef2010-08-12 23:48:41 +0000970 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000971 pthread_mutex_lock(&pos_mutex);
972
plougher91fbb302008-05-06 02:29:36 +0000973 if(lseek(fd, off, SEEK_SET) == -1)
plougherfd57dfe2009-03-30 01:17:52 +0000974 BAD_ERROR("Lseek on destination failed because %s\n",
975 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +0000976
plougher0dd6f122009-03-29 21:43:57 +0000977 if(write_bytes(fd, buff, bytes) == -1)
978 BAD_ERROR("Write on destination failed\n");
plougher5507dd92006-11-06 00:43:10 +0000979
plougher875bfef2010-08-12 23:48:41 +0000980 if(!restoring)
plougher5507dd92006-11-06 00:43:10 +0000981 pthread_mutex_unlock(&pos_mutex);
plougher1f413c82005-11-18 00:02:14 +0000982}
983
984
985long long write_inodes()
986{
987 unsigned short c_byte;
988 int avail_bytes;
989 char *datap = data_cache;
990 long long start_bytes = bytes;
991
992 while(cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +0000993 if(inode_size - inode_bytes <
994 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher1eb2a662010-07-26 17:30:50 +0000995 void *it = realloc(inode_table, inode_size +
plougherfd57dfe2009-03-30 01:17:52 +0000996 ((SQUASHFS_METADATA_SIZE << 1) + 2));
plougher1eb2a662010-07-26 17:30:50 +0000997 if(it == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +0000998 BAD_ERROR("Out of memory in inode table "
999 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001000 }
1001 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher1eb2a662010-07-26 17:30:50 +00001002 inode_table = it;
plougher1f413c82005-11-18 00:02:14 +00001003 }
plougherfd57dfe2009-03-30 01:17:52 +00001004 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
1005 SQUASHFS_METADATA_SIZE : cache_bytes;
1006 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
1007 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
rlougher8f7d0b82007-11-08 15:33:29 +00001008 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
plougherac28cd12010-02-24 02:25:03 +00001009 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
plougher1b899fc2008-08-07 01:24:06 +00001010 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
1011 total_inode_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001012 datap += avail_bytes;
1013 cache_bytes -= avail_bytes;
1014 }
1015
plougher29e2ace2010-12-31 08:50:00 +00001016 write_destination(fd, bytes, inode_bytes, inode_table);
plougher1f413c82005-11-18 00:02:14 +00001017 bytes += inode_bytes;
1018
1019 return start_bytes;
1020}
1021
1022
1023long long write_directories()
1024{
1025 unsigned short c_byte;
1026 int avail_bytes;
1027 char *directoryp = directory_data_cache;
1028 long long start_bytes = bytes;
1029
1030 while(directory_cache_bytes) {
plougherfd57dfe2009-03-30 01:17:52 +00001031 if(directory_size - directory_bytes <
1032 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001033 void *dt = realloc(directory_table,
plougherfd57dfe2009-03-30 01:17:52 +00001034 directory_size + ((SQUASHFS_METADATA_SIZE << 1)
1035 + 2));
plougher79d665a2010-07-27 00:19:23 +00001036 if(dt == NULL) {
plougherfd57dfe2009-03-30 01:17:52 +00001037 BAD_ERROR("Out of memory in directory table "
1038 "reallocation!\n");
plougher1f413c82005-11-18 00:02:14 +00001039 }
1040 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
plougher79d665a2010-07-27 00:19:23 +00001041 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001042 }
plougherfd57dfe2009-03-30 01:17:52 +00001043 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
1044 SQUASHFS_METADATA_SIZE : directory_cache_bytes;
plougher50b31762009-03-31 04:14:46 +00001045 c_byte = mangle(directory_table + directory_bytes +
1046 BLOCK_OFFSET, directoryp, avail_bytes,
1047 SQUASHFS_METADATA_SIZE, noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001048 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1049 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001050 SQUASHFS_SWAP_SHORTS(&c_byte,
1051 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001052 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1053 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001054 total_directory_bytes += avail_bytes + BLOCK_OFFSET;
plougher1f413c82005-11-18 00:02:14 +00001055 directoryp += avail_bytes;
1056 directory_cache_bytes -= avail_bytes;
1057 }
plougher29e2ace2010-12-31 08:50:00 +00001058 write_destination(fd, bytes, directory_bytes, directory_table);
plougher1f413c82005-11-18 00:02:14 +00001059 bytes += directory_bytes;
1060
1061 return start_bytes;
1062}
1063
1064
plougher1b899fc2008-08-07 01:24:06 +00001065long long write_id_table()
plougher1f413c82005-11-18 00:02:14 +00001066{
plougher1b899fc2008-08-07 01:24:06 +00001067 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
plougherac28cd12010-02-24 02:25:03 +00001068 unsigned int p[id_count];
plougher1f413c82005-11-18 00:02:14 +00001069 int i;
1070
plougher1b899fc2008-08-07 01:24:06 +00001071 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
plougherac28cd12010-02-24 02:25:03 +00001072 for(i = 0; i < id_count; i++) {
plougher1b899fc2008-08-07 01:24:06 +00001073 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
plougherac28cd12010-02-24 02:25:03 +00001074 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
plougher1f413c82005-11-18 00:02:14 +00001075 }
1076
ploughera0a49c32010-08-11 01:47:59 +00001077 return generic_write_table(id_bytes, p, 0, NULL, noI);
plougher1f413c82005-11-18 00:02:14 +00001078}
1079
1080
plougher1b899fc2008-08-07 01:24:06 +00001081struct id *get_id(unsigned int id)
plougher1f413c82005-11-18 00:02:14 +00001082{
plougher1b899fc2008-08-07 01:24:06 +00001083 int hash = ID_HASH(id);
1084 struct id *entry = id_hash_table[hash];
plougher1f413c82005-11-18 00:02:14 +00001085
plougher1b899fc2008-08-07 01:24:06 +00001086 for(; entry; entry = entry->next)
1087 if(entry->id == id)
1088 break;
plougher1f413c82005-11-18 00:02:14 +00001089
plougher1b899fc2008-08-07 01:24:06 +00001090 return entry;
plougher1f413c82005-11-18 00:02:14 +00001091}
1092
1093
plougher1b899fc2008-08-07 01:24:06 +00001094struct id *create_id(unsigned int id)
1095{
1096 int hash = ID_HASH(id);
1097 struct id *entry = malloc(sizeof(struct id));
1098 if(entry == NULL)
1099 BAD_ERROR("Out of memory in create_id\n");
1100 entry->id = id;
1101 entry->index = id_count ++;
1102 entry->flags = 0;
1103 entry->next = id_hash_table[hash];
1104 id_hash_table[hash] = entry;
1105 id_table[entry->index] = entry;
1106 return entry;
1107}
1108
1109
1110unsigned int get_uid(unsigned int uid)
1111{
1112 struct id *entry = get_id(uid);
1113
1114 if(entry == NULL) {
1115 if(id_count == SQUASHFS_IDS)
1116 BAD_ERROR("Out of uids!\n");
1117 entry = create_id(uid);
1118 }
1119
1120 if((entry->flags & ISA_UID) == 0) {
1121 entry->flags |= ISA_UID;
1122 uid_count ++;
1123 }
1124
1125 return entry->index;
1126}
1127
1128
1129unsigned int get_guid(unsigned int guid)
1130{
1131 struct id *entry = get_id(guid);
1132
1133 if(entry == NULL) {
1134 if(id_count == SQUASHFS_IDS)
1135 BAD_ERROR("Out of gids!\n");
1136 entry = create_id(guid);
1137 }
1138
1139 if((entry->flags & ISA_GID) == 0) {
1140 entry->flags |= ISA_GID;
1141 guid_count ++;
1142 }
1143
1144 return entry->index;
1145}
1146
1147
Phillip Lougher494479f2012-02-03 15:45:41 +00001148char *_pathname(struct dir_ent *dir_ent, char *pathname)
1149{
1150 if (dir_ent->nonstandard_pathname)
1151 return dir_ent->nonstandard_pathname;
1152
1153 strcpy(pathname, dir_ent->our_dir->pathname);
1154 strcat(pathname, "/");
1155 strcat(pathname, dir_ent->source_name ? : dir_ent->name);
1156
1157 return pathname;
1158}
1159
1160
1161char *pathname(struct dir_ent *dir_ent)
1162{
1163 static char pathname[1024];
1164
1165 return _pathname(dir_ent, pathname);
1166}
1167
1168
1169char *pathname_reader(struct dir_ent *dir_ent)
1170{
1171 static char pathname[1024];
1172
1173 return _pathname(dir_ent, pathname);
1174}
1175
1176
Phillip Lougherb38c1722012-02-09 23:26:19 +00001177char *subpathname(struct dir_ent *dir_ent)
1178{
1179 static char subpath[1024];
1180
1181 if(dir_ent->our_dir->subpath[0] != '\0') {
1182 strcpy(subpath, dir_ent->our_dir->subpath);
1183 strcat(subpath, "/");
Phillip Lougher9e2f1232012-10-01 02:26:09 +01001184 strcat(subpath, dir_ent->name);
Phillip Lougher90e08252012-10-05 04:33:35 +01001185 } else {
1186 strcpy(subpath, "/");
1187 strcat(subpath, dir_ent->name);
1188 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00001189
1190 return subpath;
1191}
1192
1193
Phillip Lougher539c2b12012-07-30 20:14:52 +01001194inline unsigned int get_inode_no(struct inode_info *inode)
Phillip Lougher53cef742012-07-25 05:12:50 +01001195{
Phillip Lougher539c2b12012-07-30 20:14:52 +01001196 return inode->inode_number;
Phillip Lougher53cef742012-07-25 05:12:50 +01001197}
1198
1199
Phillip Lougher539c2b12012-07-30 20:14:52 +01001200inline unsigned int get_parent_no(struct dir_info *dir)
Phillip Lougher53cef742012-07-25 05:12:50 +01001201{
Phillip Lougher1eae83d2012-09-26 02:12:45 +01001202 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
Phillip Lougher53cef742012-07-25 05:12:50 +01001203}
1204
1205
plougher3c6bdb52010-05-01 02:30:59 +00001206int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
1207 struct dir_ent *dir_ent, int type, long long byte_size,
1208 long long start_block, unsigned int offset, unsigned int *block_list,
1209 struct fragment *fragment, struct directory *dir_in, long long sparse)
plougher1f413c82005-11-18 00:02:14 +00001210{
1211 struct stat *buf = &dir_ent->inode->buf;
plougher8973a122010-12-31 09:52:45 +00001212 union squashfs_inode_header inode_header;
plougher857d0dd2010-12-31 21:03:13 +00001213 struct squashfs_base_inode_header *base = &inode_header.base;
plougherac28cd12010-02-24 02:25:03 +00001214 void *inode;
Phillip Lougher494479f2012-02-03 15:45:41 +00001215 char *filename = pathname(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001216 int nlink = dir_ent->inode->nlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001217 int xattr = read_xattrs(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00001218
ploughere6e0e1b2010-05-12 17:17:06 +00001219 switch(type) {
1220 case SQUASHFS_FILE_TYPE:
1221 if(dir_ent->inode->nlink > 1 ||
1222 byte_size >= (1LL << 32) ||
1223 start_block >= (1LL << 32) ||
1224 sparse || IS_XATTR(xattr))
1225 type = SQUASHFS_LREG_TYPE;
1226 break;
1227 case SQUASHFS_DIR_TYPE:
1228 if(dir_info->dir_is_ldir || IS_XATTR(xattr))
1229 type = SQUASHFS_LDIR_TYPE;
1230 break;
1231 case SQUASHFS_SYMLINK_TYPE:
1232 if(IS_XATTR(xattr))
1233 type = SQUASHFS_LSYMLINK_TYPE;
1234 break;
1235 case SQUASHFS_BLKDEV_TYPE:
1236 if(IS_XATTR(xattr))
1237 type = SQUASHFS_LBLKDEV_TYPE;
1238 break;
1239 case SQUASHFS_CHRDEV_TYPE:
1240 if(IS_XATTR(xattr))
1241 type = SQUASHFS_LCHRDEV_TYPE;
1242 break;
plougherc5d69322010-05-12 19:28:38 +00001243 case SQUASHFS_FIFO_TYPE:
1244 if(IS_XATTR(xattr))
1245 type = SQUASHFS_LFIFO_TYPE;
1246 break;
1247 case SQUASHFS_SOCKET_TYPE:
1248 if(IS_XATTR(xattr))
1249 type = SQUASHFS_LSOCKET_TYPE;
1250 break;
ploughere6e0e1b2010-05-12 17:17:06 +00001251 }
1252
plougher1f413c82005-11-18 00:02:14 +00001253 base->mode = SQUASHFS_MODE(buf->st_mode);
plougherfd57dfe2009-03-30 01:17:52 +00001254 base->uid = get_uid((unsigned int) global_uid == -1 ?
1255 buf->st_uid : global_uid);
plougher1f413c82005-11-18 00:02:14 +00001256 base->inode_type = type;
plougherfd57dfe2009-03-30 01:17:52 +00001257 base->guid = get_guid((unsigned int) global_gid == -1 ?
1258 buf->st_gid : global_gid);
plougher1f413c82005-11-18 00:02:14 +00001259 base->mtime = buf->st_mtime;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001260 base->inode_number = get_inode_no(dir_ent->inode);
plougher1f413c82005-11-18 00:02:14 +00001261
1262 if(type == SQUASHFS_FILE_TYPE) {
1263 int i;
plougher8701ed62010-12-31 20:38:38 +00001264 struct squashfs_reg_inode_header *reg = &inode_header.reg;
1265 size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001266
1267 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001268 reg->file_size = byte_size;
1269 reg->start_block = start_block;
1270 reg->fragment = fragment->index;
1271 reg->offset = fragment->offset;
plougherac28cd12010-02-24 02:25:03 +00001272 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1273 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougher50b31762009-03-31 04:14:46 +00001274 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1275 "%d, fragment %d, offset %d, size %d\n", byte_size,
plougherfd57dfe2009-03-30 01:17:52 +00001276 start_block, offset, fragment->index, fragment->offset,
1277 fragment->size);
plougher1f413c82005-11-18 00:02:14 +00001278 for(i = 0; i < offset; i++)
1279 TRACE("Block %d, size %d\n", i, block_list[i]);
1280 }
1281 else if(type == SQUASHFS_LREG_TYPE) {
1282 int i;
plougher1e6ac4a2010-12-31 20:42:02 +00001283 struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1284 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
plougher1f413c82005-11-18 00:02:14 +00001285
1286 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
plougher1f413c82005-11-18 00:02:14 +00001287 reg->nlink = nlink;
1288 reg->file_size = byte_size;
1289 reg->start_block = start_block;
1290 reg->fragment = fragment->index;
1291 reg->offset = fragment->offset;
plougherf5a674d2009-03-25 05:38:27 +00001292 if(sparse && sparse >= byte_size)
1293 sparse = byte_size - 1;
plougher1b899fc2008-08-07 01:24:06 +00001294 reg->sparse = sparse;
ploughere6e0e1b2010-05-12 17:17:06 +00001295 reg->xattr = xattr;
plougherac28cd12010-02-24 02:25:03 +00001296 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1297 SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
plougherfd57dfe2009-03-30 01:17:52 +00001298 TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001299 "blocks %d, fragment %d, offset %d, size %d, nlink %d"
1300 "\n", byte_size, start_block, offset, fragment->index,
plougherfd57dfe2009-03-30 01:17:52 +00001301 fragment->offset, fragment->size, nlink);
plougher1f413c82005-11-18 00:02:14 +00001302 for(i = 0; i < offset; i++)
1303 TRACE("Block %d, size %d\n", i, block_list[i]);
1304 }
1305 else if(type == SQUASHFS_LDIR_TYPE) {
1306 int i;
1307 unsigned char *p;
plougher2611d392010-12-31 20:50:36 +00001308 struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
plougher1f413c82005-11-18 00:02:14 +00001309 struct cached_dir_index *index = dir_in->index;
1310 unsigned int i_count = dir_in->i_count;
1311 unsigned int i_size = dir_in->i_size;
1312
1313 if(byte_size >= 1 << 27)
1314 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1315
1316 inode = get_inode(sizeof(*dir) + i_size);
plougher1f413c82005-11-18 00:02:14 +00001317 dir->inode_type = SQUASHFS_LDIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00001318 dir->nlink = dir_ent->dir->directory_count + 2;
1319 dir->file_size = byte_size;
1320 dir->offset = offset;
1321 dir->start_block = start_block;
1322 dir->i_count = i_count;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001323 dir->parent_inode = get_parent_no(dir_ent->our_dir);
ploughere6e0e1b2010-05-12 17:17:06 +00001324 dir->xattr = xattr;
plougher1f413c82005-11-18 00:02:14 +00001325
plougherac28cd12010-02-24 02:25:03 +00001326 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
plougher2611d392010-12-31 20:50:36 +00001327 p = inode + offsetof(struct squashfs_ldir_inode_header, index);
plougher1f413c82005-11-18 00:02:14 +00001328 for(i = 0; i < i_count; i++) {
plougherac28cd12010-02-24 02:25:03 +00001329 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
plougher2bd2b722010-12-31 10:52:15 +00001330 p += offsetof(struct squashfs_dir_index, name);
plougherac28cd12010-02-24 02:25:03 +00001331 memcpy(p, index[i].name, index[i].index.size + 1);
1332 p += index[i].index.size + 1;
plougher1f413c82005-11-18 00:02:14 +00001333 }
plougher50b31762009-03-31 04:14:46 +00001334 TRACE("Long directory inode, file_size %lld, start_block "
1335 "0x%llx, offset 0x%x, nlink %d\n", byte_size,
1336 start_block, offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001337 }
1338 else if(type == SQUASHFS_DIR_TYPE) {
plougher9d80a602010-12-31 20:47:24 +00001339 struct squashfs_dir_inode_header *dir = &inode_header.dir;
plougher1f413c82005-11-18 00:02:14 +00001340
1341 inode = get_inode(sizeof(*dir));
plougher1f413c82005-11-18 00:02:14 +00001342 dir->nlink = dir_ent->dir->directory_count + 2;
1343 dir->file_size = byte_size;
1344 dir->offset = offset;
1345 dir->start_block = start_block;
Phillip Lougher539c2b12012-07-30 20:14:52 +01001346 dir->parent_inode = get_parent_no(dir_ent->our_dir);
plougherac28cd12010-02-24 02:25:03 +00001347 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougherfd57dfe2009-03-30 01:17:52 +00001348 TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
plougher50b31762009-03-31 04:14:46 +00001349 "offset 0x%x, nlink %d\n", byte_size, start_block,
1350 offset, dir_ent->dir->directory_count + 2);
plougher1f413c82005-11-18 00:02:14 +00001351 }
1352 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
plougherc70c6332010-12-31 20:11:09 +00001353 struct squashfs_dev_inode_header *dev = &inode_header.dev;
plougher5b398502008-10-04 23:22:03 +00001354 unsigned int major = major(buf->st_rdev);
1355 unsigned int minor = minor(buf->st_rdev);
plougher1f413c82005-11-18 00:02:14 +00001356
plougher5b398502008-10-04 23:22:03 +00001357 if(major > 0xfff) {
plougherfd57dfe2009-03-30 01:17:52 +00001358 ERROR("Major %d out of range in device node %s, "
1359 "truncating to %d\n", major, filename,
1360 major & 0xfff);
plougher5b398502008-10-04 23:22:03 +00001361 major &= 0xfff;
1362 }
1363 if(minor > 0xfffff) {
plougherfd57dfe2009-03-30 01:17:52 +00001364 ERROR("Minor %d out of range in device node %s, "
1365 "truncating to %d\n", minor, filename,
1366 minor & 0xfffff);
plougher5b398502008-10-04 23:22:03 +00001367 minor &= 0xfffff;
1368 }
plougher1f413c82005-11-18 00:02:14 +00001369 inode = get_inode(sizeof(*dev));
1370 dev->nlink = nlink;
plougher5b398502008-10-04 23:22:03 +00001371 dev->rdev = (major << 8) | (minor & 0xff) |
1372 ((minor & ~0xff) << 12);
plougherac28cd12010-02-24 02:25:03 +00001373 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
rlougher8f7d0b82007-11-08 15:33:29 +00001374 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
plougher1f413c82005-11-18 00:02:14 +00001375 }
ploughere6e0e1b2010-05-12 17:17:06 +00001376 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
plougher0b4ee5b2010-12-31 20:14:00 +00001377 struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
ploughere6e0e1b2010-05-12 17:17:06 +00001378 unsigned int major = major(buf->st_rdev);
1379 unsigned int minor = minor(buf->st_rdev);
1380
1381 if(major > 0xfff) {
1382 ERROR("Major %d out of range in device node %s, "
1383 "truncating to %d\n", major, filename,
1384 major & 0xfff);
1385 major &= 0xfff;
1386 }
1387 if(minor > 0xfffff) {
1388 ERROR("Minor %d out of range in device node %s, "
1389 "truncating to %d\n", minor, filename,
1390 minor & 0xfffff);
1391 minor &= 0xfffff;
1392 }
1393 inode = get_inode(sizeof(*dev));
1394 dev->nlink = nlink;
1395 dev->rdev = (major << 8) | (minor & 0xff) |
1396 ((minor & ~0xff) << 12);
1397 dev->xattr = xattr;
1398 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1399 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1400 }
plougher1f413c82005-11-18 00:02:14 +00001401 else if(type == SQUASHFS_SYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001402 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
plougher1f413c82005-11-18 00:02:14 +00001403 int byte;
1404 char buff[65536];
plougher5ae6e952010-12-31 20:44:34 +00001405 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
plougher1f413c82005-11-18 00:02:14 +00001406
plougher5cf38b82010-12-16 04:55:32 +00001407 byte = readlink(filename, buff, 65536);
1408 if(byte == -1) {
plougherfd57dfe2009-03-30 01:17:52 +00001409 ERROR("Failed to read symlink %s, creating empty "
1410 "symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001411 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001412 }
1413
1414 if(byte == 65536) {
plougher50b31762009-03-31 04:14:46 +00001415 ERROR("Symlink %s is greater than 65536 bytes! "
1416 "Creating empty symlink\n", filename);
plougher29e37092007-04-15 01:24:51 +00001417 byte = 0;
plougher1f413c82005-11-18 00:02:14 +00001418 }
1419
1420 inode = get_inode(sizeof(*symlink) + byte);
1421 symlink->nlink = nlink;
plougher1f413c82005-11-18 00:02:14 +00001422 symlink->symlink_size = byte;
plougherac28cd12010-02-24 02:25:03 +00001423 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1424 strncpy(inode + off, buff, byte);
plougherfd57dfe2009-03-30 01:17:52 +00001425 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1426 nlink);
plougher1f413c82005-11-18 00:02:14 +00001427 }
ploughere6e0e1b2010-05-12 17:17:06 +00001428 else if(type == SQUASHFS_LSYMLINK_TYPE) {
plougher5ae6e952010-12-31 20:44:34 +00001429 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
ploughere6e0e1b2010-05-12 17:17:06 +00001430 int byte;
1431 char buff[65536];
plougher5ae6e952010-12-31 20:44:34 +00001432 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
ploughere6e0e1b2010-05-12 17:17:06 +00001433
plougherdf2b9aa2010-12-16 04:56:23 +00001434 byte = readlink(filename, buff, 65536);
1435 if(byte == -1) {
ploughere6e0e1b2010-05-12 17:17:06 +00001436 ERROR("Failed to read symlink %s, creating empty "
1437 "symlink\n", filename);
1438 byte = 0;
1439 }
1440
1441 if(byte == 65536) {
1442 ERROR("Symlink %s is greater than 65536 bytes! "
1443 "Creating empty symlink\n", filename);
1444 byte = 0;
1445 }
1446
1447 inode = get_inode(sizeof(*symlink) + byte +
1448 sizeof(unsigned int));
1449 symlink->nlink = nlink;
1450 symlink->symlink_size = byte;
1451 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1452 strncpy(inode + off, buff, byte);
1453 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1454 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1455 nlink);
1456 }
plougher1f413c82005-11-18 00:02:14 +00001457 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
ploughere56b9862010-12-31 10:58:35 +00001458 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
plougher1f413c82005-11-18 00:02:14 +00001459
1460 inode = get_inode(sizeof(*ipc));
1461 ipc->nlink = nlink;
plougherac28cd12010-02-24 02:25:03 +00001462 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
plougher50b31762009-03-31 04:14:46 +00001463 TRACE("ipc inode, type %s, nlink %d\n", type ==
1464 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougherc5d69322010-05-12 19:28:38 +00001465 }
1466 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
plougheraa0d1222010-12-31 20:06:24 +00001467 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
plougherc5d69322010-05-12 19:28:38 +00001468
1469 inode = get_inode(sizeof(*ipc));
1470 ipc->nlink = nlink;
1471 ipc->xattr = xattr;
1472 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1473 TRACE("ipc inode, type %s, nlink %d\n", type ==
1474 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
plougher1f413c82005-11-18 00:02:14 +00001475 } else
rlougher8f7d0b82007-11-08 15:33:29 +00001476 BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
plougher1f413c82005-11-18 00:02:14 +00001477
1478 *i_no = MKINODE(inode);
1479 inode_count ++;
1480
plougherfd57dfe2009-03-30 01:17:52 +00001481 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1482 base->uid, base->guid);
plougher1f413c82005-11-18 00:02:14 +00001483
1484 return TRUE;
1485}
1486
1487
plougher50b31762009-03-31 04:14:46 +00001488void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1489 int type, struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001490{
plougher8cb05cd2005-12-11 23:32:35 +00001491 unsigned char *buff;
plougher9b393552010-12-31 20:55:43 +00001492 struct squashfs_dir_entry idir;
plougher1f413c82005-11-18 00:02:14 +00001493 unsigned int start_block = inode >> 16;
1494 unsigned int offset = inode & 0xffff;
plougher43d49082010-12-16 05:01:15 +00001495 unsigned int size = strlen(name);
plougher9b393552010-12-31 20:55:43 +00001496 size_t name_off = offsetof(struct squashfs_dir_entry, name);
plougher1f413c82005-11-18 00:02:14 +00001497
plougher43d49082010-12-16 05:01:15 +00001498 if(size > SQUASHFS_NAME_LEN) {
plougher1f413c82005-11-18 00:02:14 +00001499 size = SQUASHFS_NAME_LEN;
plougher50b31762009-03-31 04:14:46 +00001500 ERROR("Filename is greater than %d characters, truncating! ..."
1501 "\n", SQUASHFS_NAME_LEN);
plougher1f413c82005-11-18 00:02:14 +00001502 }
1503
plougher9b393552010-12-31 20:55:43 +00001504 if(dir->p + sizeof(struct squashfs_dir_entry) + size +
plougher520e1a12010-12-31 10:44:38 +00001505 sizeof(struct squashfs_dir_header)
1506 >= dir->buff + dir->size) {
plougherfd57dfe2009-03-30 01:17:52 +00001507 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1508 if(buff == NULL) {
plougher50b31762009-03-31 04:14:46 +00001509 BAD_ERROR("Out of memory reallocating directory buffer"
1510 "\n");
plougher1f413c82005-11-18 00:02:14 +00001511 }
1512
1513 dir->p = (dir->p - dir->buff) + buff;
1514 if(dir->entry_count_p)
plougherfd57dfe2009-03-30 01:17:52 +00001515 dir->entry_count_p = (dir->entry_count_p - dir->buff +
1516 buff);
plougher1f413c82005-11-18 00:02:14 +00001517 dir->index_count_p = dir->index_count_p - dir->buff + buff;
1518 dir->buff = buff;
1519 }
1520
plougherfd57dfe2009-03-30 01:17:52 +00001521 if(dir->entry_count == 256 || start_block != dir->start_block ||
1522 ((dir->entry_count_p != NULL) &&
plougher9b393552010-12-31 20:55:43 +00001523 ((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001524 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
plougher50b31762009-03-31 04:14:46 +00001525 ((long long) inode_number - dir->inode_number) > 32767
1526 || ((long long) inode_number - dir->inode_number)
1527 < -32768) {
plougher1f413c82005-11-18 00:02:14 +00001528 if(dir->entry_count_p) {
plougher520e1a12010-12-31 10:44:38 +00001529 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001530
plougher9b393552010-12-31 20:55:43 +00001531 if((dir->p + sizeof(struct squashfs_dir_entry) + size -
plougherfd57dfe2009-03-30 01:17:52 +00001532 dir->index_count_p) >
1533 SQUASHFS_METADATA_SIZE) {
1534 if(dir->i_count % I_COUNT_SIZE == 0) {
1535 dir->index = realloc(dir->index,
1536 (dir->i_count + I_COUNT_SIZE) *
1537 sizeof(struct cached_dir_index));
1538 if(dir->index == NULL)
1539 BAD_ERROR("Out of memory in "
1540 "directory index table "
1541 "reallocation!\n");
1542 }
1543 dir->index[dir->i_count].index.index =
1544 dir->p - dir->buff;
plougher1f413c82005-11-18 00:02:14 +00001545 dir->index[dir->i_count].index.size = size - 1;
1546 dir->index[dir->i_count++].name = name;
plougher2bd2b722010-12-31 10:52:15 +00001547 dir->i_size += sizeof(struct squashfs_dir_index)
1548 + size;
plougher1f413c82005-11-18 00:02:14 +00001549 dir->index_count_p = dir->p;
1550 }
1551
1552 dir_header.count = dir->entry_count - 1;
1553 dir_header.start_block = dir->start_block;
1554 dir_header.inode_number = dir->inode_number;
plougherfd57dfe2009-03-30 01:17:52 +00001555 SQUASHFS_SWAP_DIR_HEADER(&dir_header,
plougherac28cd12010-02-24 02:25:03 +00001556 dir->entry_count_p);
plougher1f413c82005-11-18 00:02:14 +00001557
1558 }
1559
1560
1561 dir->entry_count_p = dir->p;
1562 dir->start_block = start_block;
1563 dir->entry_count = 0;
1564 dir->inode_number = inode_number;
plougher520e1a12010-12-31 10:44:38 +00001565 dir->p += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001566 }
1567
plougher1f413c82005-11-18 00:02:14 +00001568 idir.offset = offset;
1569 idir.type = type;
1570 idir.size = size - 1;
1571 idir.inode_number = ((long long) inode_number - dir->inode_number);
plougherac28cd12010-02-24 02:25:03 +00001572 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1573 strncpy((char *) dir->p + name_off, name, size);
plougher9b393552010-12-31 20:55:43 +00001574 dir->p += sizeof(struct squashfs_dir_entry) + size;
plougher1f413c82005-11-18 00:02:14 +00001575 dir->entry_count ++;
1576}
1577
1578
plougherfd57dfe2009-03-30 01:17:52 +00001579void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1580 struct directory *dir)
plougher1f413c82005-11-18 00:02:14 +00001581{
1582 unsigned int dir_size = dir->p - dir->buff;
plougher4627ca32010-12-16 05:03:55 +00001583 int data_space = directory_cache_size - directory_cache_bytes;
plougher1f413c82005-11-18 00:02:14 +00001584 unsigned int directory_block, directory_offset, i_count, index;
1585 unsigned short c_byte;
1586
1587 if(data_space < dir_size) {
plougherfd57dfe2009-03-30 01:17:52 +00001588 int realloc_size = directory_cache_size == 0 ?
1589 ((dir_size + SQUASHFS_METADATA_SIZE) &
1590 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
plougher1f413c82005-11-18 00:02:14 +00001591
plougher17248ca2010-07-27 00:24:35 +00001592 void *dc = realloc(directory_data_cache,
plougherfd57dfe2009-03-30 01:17:52 +00001593 directory_cache_size + realloc_size);
plougher17248ca2010-07-27 00:24:35 +00001594 if(dc == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001595 goto failed;
1596 }
1597 directory_cache_size += realloc_size;
plougher17248ca2010-07-27 00:24:35 +00001598 directory_data_cache = dc;
plougher1f413c82005-11-18 00:02:14 +00001599 }
1600
1601 if(dir_size) {
plougher520e1a12010-12-31 10:44:38 +00001602 struct squashfs_dir_header dir_header;
plougher1f413c82005-11-18 00:02:14 +00001603
1604 dir_header.count = dir->entry_count - 1;
1605 dir_header.start_block = dir->start_block;
1606 dir_header.inode_number = dir->inode_number;
plougherac28cd12010-02-24 02:25:03 +00001607 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
plougherfd57dfe2009-03-30 01:17:52 +00001608 memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1609 dir_size);
plougher1f413c82005-11-18 00:02:14 +00001610 }
1611 directory_offset = directory_cache_bytes;
1612 directory_block = directory_bytes;
1613 directory_cache_bytes += dir_size;
1614 i_count = 0;
1615 index = SQUASHFS_METADATA_SIZE - directory_offset;
1616
1617 while(1) {
plougherfd57dfe2009-03-30 01:17:52 +00001618 while(i_count < dir->i_count &&
1619 dir->index[i_count].index.index < index)
plougher50b31762009-03-31 04:14:46 +00001620 dir->index[i_count++].index.start_block =
1621 directory_bytes;
plougher1f413c82005-11-18 00:02:14 +00001622 index += SQUASHFS_METADATA_SIZE;
1623
1624 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1625 break;
1626
plougherfd57dfe2009-03-30 01:17:52 +00001627 if((directory_size - directory_bytes) <
1628 ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
plougher79d665a2010-07-27 00:19:23 +00001629 void *dt = realloc(directory_table,
plougher50b31762009-03-31 04:14:46 +00001630 directory_size + (SQUASHFS_METADATA_SIZE << 1)
1631 + 2);
plougher79d665a2010-07-27 00:19:23 +00001632 if(dt == NULL) {
plougher1f413c82005-11-18 00:02:14 +00001633 goto failed;
1634 }
1635 directory_size += SQUASHFS_METADATA_SIZE << 1;
plougher79d665a2010-07-27 00:19:23 +00001636 directory_table = dt;
plougher1f413c82005-11-18 00:02:14 +00001637 }
1638
plougher50b31762009-03-31 04:14:46 +00001639 c_byte = mangle(directory_table + directory_bytes +
1640 BLOCK_OFFSET, directory_data_cache,
1641 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1642 noI, 0);
plougherfd57dfe2009-03-30 01:17:52 +00001643 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1644 c_byte);
plougherac28cd12010-02-24 02:25:03 +00001645 SQUASHFS_SWAP_SHORTS(&c_byte,
1646 directory_table + directory_bytes, 1);
plougher50b31762009-03-31 04:14:46 +00001647 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1648 BLOCK_OFFSET;
plougher1b899fc2008-08-07 01:24:06 +00001649 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
plougher14dd5f32010-08-02 18:20:03 +00001650 memmove(directory_data_cache, directory_data_cache +
plougherfd57dfe2009-03-30 01:17:52 +00001651 SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1652 SQUASHFS_METADATA_SIZE);
plougher1f413c82005-11-18 00:02:14 +00001653 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1654 }
1655
plougher3c6bdb52010-05-01 02:30:59 +00001656 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1657 dir_size + 3, directory_block, directory_offset, NULL, NULL,
1658 dir, 0);
plougher1f413c82005-11-18 00:02:14 +00001659
1660#ifdef SQUASHFS_TRACE
plougher1f288f62009-02-21 03:05:52 +00001661 {
plougher1f413c82005-11-18 00:02:14 +00001662 unsigned char *dirp;
1663 int count;
1664
1665 TRACE("Directory contents of inode 0x%llx\n", *inode);
1666 dirp = dir->buff;
1667 while(dirp < dir->p) {
1668 char buffer[SQUASHFS_NAME_LEN + 1];
plougher9b393552010-12-31 20:55:43 +00001669 struct squashfs_dir_entry idir, *idirp;
plougher520e1a12010-12-31 10:44:38 +00001670 struct squashfs_dir_header dirh;
1671 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
plougher360514a2009-03-30 03:01:38 +00001672 &dirh);
plougher1f288f62009-02-21 03:05:52 +00001673 count = dirh.count + 1;
plougher520e1a12010-12-31 10:44:38 +00001674 dirp += sizeof(struct squashfs_dir_header);
plougher1f413c82005-11-18 00:02:14 +00001675
plougher50b31762009-03-31 04:14:46 +00001676 TRACE("\tStart block 0x%x, count %d\n",
1677 dirh.start_block, count);
plougher1f413c82005-11-18 00:02:14 +00001678
1679 while(count--) {
plougher9b393552010-12-31 20:55:43 +00001680 idirp = (struct squashfs_dir_entry *) dirp;
plougher1f288f62009-02-21 03:05:52 +00001681 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
plougher1f413c82005-11-18 00:02:14 +00001682 strncpy(buffer, idirp->name, idir.size + 1);
1683 buffer[idir.size + 1] = '\0';
plougher50b31762009-03-31 04:14:46 +00001684 TRACE("\t\tname %s, inode offset 0x%x, type "
1685 "%d\n", buffer, idir.offset, idir.type);
plougher9b393552010-12-31 20:55:43 +00001686 dirp += sizeof(struct squashfs_dir_entry) + idir.size +
ploughere8b26f62010-12-16 05:06:00 +00001687 1;
plougher1f413c82005-11-18 00:02:14 +00001688 }
1689 }
1690 }
1691#endif
1692 dir_count ++;
1693
plougher29e37092007-04-15 01:24:51 +00001694 return;
plougher1f413c82005-11-18 00:02:14 +00001695
1696failed:
1697 BAD_ERROR("Out of memory in directory table reallocation!\n");
1698}
1699
1700
plougher76c64082008-03-08 01:32:23 +00001701struct file_buffer *get_fragment(struct fragment *fragment)
plougher1f413c82005-11-18 00:02:14 +00001702{
plougher8ed84b92010-12-31 10:37:24 +00001703 struct squashfs_fragment_entry *disk_fragment;
plougher1d065e92010-06-18 03:58:27 +00001704 int res, size;
plougher76c64082008-03-08 01:32:23 +00001705 long long start_block;
1706 struct file_buffer *buffer, *compressed_buffer;
plougher5507dd92006-11-06 00:43:10 +00001707
plougher76c64082008-03-08 01:32:23 +00001708 if(fragment->index == SQUASHFS_INVALID_FRAG)
1709 return NULL;
plougher5507dd92006-11-06 00:43:10 +00001710
plougher76c64082008-03-08 01:32:23 +00001711 buffer = cache_lookup(fragment_buffer, fragment->index);
plougher1b899fc2008-08-07 01:24:06 +00001712 if(buffer)
plougher76c64082008-03-08 01:32:23 +00001713 return buffer;
plougher76c64082008-03-08 01:32:23 +00001714
plougherfd57dfe2009-03-30 01:17:52 +00001715 compressed_buffer = cache_lookup(writer_buffer, fragment->index +
1716 FRAG_INDEX);
plougher2ea89142008-03-11 01:34:19 +00001717
plougher76c64082008-03-08 01:32:23 +00001718 buffer = cache_get(fragment_buffer, fragment->index, 1);
plougher5507dd92006-11-06 00:43:10 +00001719
1720 pthread_mutex_lock(&fragment_mutex);
plougher5507dd92006-11-06 00:43:10 +00001721 disk_fragment = &fragment_table[fragment->index];
1722 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
plougher76c64082008-03-08 01:32:23 +00001723 start_block = disk_fragment->start_block;
1724 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001725
plougher0f464442008-03-31 00:27:56 +00001726 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
plougher1d065e92010-06-18 03:58:27 +00001727 int error;
plougher76c64082008-03-08 01:32:23 +00001728 char *data;
plougher1f413c82005-11-18 00:02:14 +00001729
plougher76c64082008-03-08 01:32:23 +00001730 if(compressed_buffer)
1731 data = compressed_buffer->data;
plougher49b57a92009-03-31 03:23:05 +00001732 else
1733 data = read_from_disk(start_block, size);
plougher1f413c82005-11-18 00:02:14 +00001734
plougherb48442b2010-12-31 07:57:54 +00001735 res = compressor_uncompress(comp, buffer->data, data, size,
1736 block_size, &error);
ploughera175ce22009-07-30 04:43:27 +00001737 if(res == -1)
1738 BAD_ERROR("%s uncompress failed with error code %d\n",
1739 comp->name, error);
plougher76c64082008-03-08 01:32:23 +00001740 } else if(compressed_buffer)
1741 memcpy(buffer->data, compressed_buffer->data, size);
plougher1d065e92010-06-18 03:58:27 +00001742 else {
1743 res = read_fs_bytes(fd, start_block, size, buffer->data);
1744 if(res == 0)
1745 EXIT_MKSQUASHFS();
1746 }
plougher1f413c82005-11-18 00:02:14 +00001747
plougher03859fa2009-03-31 03:18:18 +00001748 cache_block_put(compressed_buffer);
1749
plougher76c64082008-03-08 01:32:23 +00001750 return buffer;
plougher1f413c82005-11-18 00:02:14 +00001751}
1752
plougher2ea89142008-03-11 01:34:19 +00001753
1754struct frag_locked {
1755 struct file_buffer *buffer;
1756 int c_byte;
1757 int fragment;
1758 struct frag_locked *fragment_prev;
1759 struct frag_locked *fragment_next;
1760};
1761
1762int fragments_locked = FALSE;
1763struct frag_locked *frag_locked_list = NULL;
1764
1765INSERT_LIST(fragment, struct frag_locked)
1766REMOVE_LIST(fragment, struct frag_locked)
1767
plougher4e8484a2008-03-15 23:30:16 +00001768int lock_fragments()
plougher5507dd92006-11-06 00:43:10 +00001769{
plougher4e8484a2008-03-15 23:30:16 +00001770 int count;
plougher5507dd92006-11-06 00:43:10 +00001771 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00001772 fragments_locked = TRUE;
plougher4e8484a2008-03-15 23:30:16 +00001773 count = fragments_outstanding;
plougher2ea89142008-03-11 01:34:19 +00001774 pthread_mutex_unlock(&fragment_mutex);
plougher4e8484a2008-03-15 23:30:16 +00001775 return count;
plougher2ea89142008-03-11 01:34:19 +00001776}
1777
1778
1779void unlock_fragments()
1780{
1781 struct frag_locked *entry;
1782 int compressed_size;
1783
1784 pthread_mutex_lock(&fragment_mutex);
1785 while(frag_locked_list) {
1786 entry = frag_locked_list;
1787 remove_fragment_list(&frag_locked_list, entry);
1788 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
1789 fragment_table[entry->fragment].size = entry->c_byte;
1790 fragment_table[entry->fragment].start_block = bytes;
1791 entry->buffer->block = bytes;
1792 bytes += compressed_size;
1793 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00001794 queue_put(to_writer, entry->buffer);
plougher50b31762009-03-31 04:14:46 +00001795 TRACE("fragment_locked writing fragment %d, compressed size %d"
1796 "\n", entry->fragment, compressed_size);
plougher2ea89142008-03-11 01:34:19 +00001797 free(entry);
1798 }
1799 fragments_locked = FALSE;
1800 pthread_mutex_unlock(&fragment_mutex);
1801}
1802
1803
plougherb7a66812010-07-21 01:06:59 +00001804void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
plougher17b269c2009-03-30 01:33:07 +00001805 int fragment)
plougher2ea89142008-03-11 01:34:19 +00001806{
1807 struct frag_locked *entry = malloc(sizeof(struct frag_locked));
1808 if(entry == NULL)
plougherb7a66812010-07-21 01:06:59 +00001809 BAD_ERROR("Out of memory in add_pending fragment\n");
plougher2ea89142008-03-11 01:34:19 +00001810 entry->buffer = write_buffer;
1811 entry->c_byte = c_byte;
1812 entry->fragment = fragment;
1813 entry->fragment_prev = entry->fragment_next = NULL;
1814 pthread_mutex_lock(&fragment_mutex);
1815 insert_fragment_list(&frag_locked_list, entry);
plougher5507dd92006-11-06 00:43:10 +00001816 pthread_mutex_unlock(&fragment_mutex);
1817}
1818
1819
Phillip Lougher04b7b532011-06-11 02:14:15 +01001820void write_fragment(struct file_buffer *fragment)
plougher1f413c82005-11-18 00:02:14 +00001821{
Phillip Lougher04b7b532011-06-11 02:14:15 +01001822 if(fragment == NULL)
plougher1f413c82005-11-18 00:02:14 +00001823 return;
1824
plougher5507dd92006-11-06 00:43:10 +00001825 pthread_mutex_lock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001826 fragment_table[fragment->block].unused = 0;
1827 fragments_outstanding ++;
1828 queue_put(to_frag, fragment);
1829 pthread_mutex_unlock(&fragment_mutex);
1830}
1831
1832
1833struct file_buffer *allocate_fragment()
1834{
1835 struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
1836
1837 pthread_mutex_lock(&fragment_mutex);
1838
plougher5507dd92006-11-06 00:43:10 +00001839 if(fragments % FRAG_SIZE == 0) {
plougherfa89c332010-07-27 00:27:15 +00001840 void *ft = realloc(fragment_table, (fragments +
plougher8ed84b92010-12-31 10:37:24 +00001841 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
plougherfa89c332010-07-27 00:27:15 +00001842 if(ft == NULL) {
plougher5507dd92006-11-06 00:43:10 +00001843 pthread_mutex_unlock(&fragment_mutex);
plougher1f413c82005-11-18 00:02:14 +00001844 BAD_ERROR("Out of memory in fragment table\n");
plougher5507dd92006-11-06 00:43:10 +00001845 }
plougherfa89c332010-07-27 00:27:15 +00001846 fragment_table = ft;
plougher5507dd92006-11-06 00:43:10 +00001847 }
Phillip Lougherb9508be2011-06-13 02:25:51 +01001848
1849 fragment->size = 0;
1850 fragment->block = fragments ++;
1851
plougher5507dd92006-11-06 00:43:10 +00001852 pthread_mutex_unlock(&fragment_mutex);
Phillip Lougherb9508be2011-06-13 02:25:51 +01001853
1854 return fragment;
plougher5507dd92006-11-06 00:43:10 +00001855}
1856
ploughereb6eac92008-02-26 01:50:48 +00001857
plougher1f413c82005-11-18 00:02:14 +00001858static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001859struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1860 struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00001861{
1862 struct fragment *ffrg;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001863 struct file_buffer **fragment;
plougher1f413c82005-11-18 00:02:14 +00001864
plougher5507dd92006-11-06 00:43:10 +00001865 if(file_buffer == NULL || file_buffer->size == 0)
plougher1f413c82005-11-18 00:02:14 +00001866 return &empty_fragment;
1867
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001868 fragment = eval_frag_actions(dir_ent);
1869
1870 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1871 write_fragment(*fragment);
1872 *fragment = NULL;
Phillip Lougher04b7b532011-06-11 02:14:15 +01001873 }
plougher1f413c82005-11-18 00:02:14 +00001874
ploughere7e6e832010-12-16 05:08:06 +00001875 ffrg = malloc(sizeof(struct fragment));
1876 if(ffrg == NULL)
plougher1f413c82005-11-18 00:02:14 +00001877 BAD_ERROR("Out of memory in fragment block allocation!\n");
1878
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001879 if(*fragment == NULL)
1880 *fragment = allocate_fragment();
plougher5507dd92006-11-06 00:43:10 +00001881
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001882 ffrg->index = (*fragment)->block;
1883 ffrg->offset = (*fragment)->size;
plougher5507dd92006-11-06 00:43:10 +00001884 ffrg->size = file_buffer->size;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001885 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
plougher17b269c2009-03-30 01:33:07 +00001886 file_buffer->size);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01001887 (*fragment)->size += file_buffer->size;
plougher1f413c82005-11-18 00:02:14 +00001888
1889 return ffrg;
1890}
1891
1892
ploughera0a49c32010-08-11 01:47:59 +00001893long long generic_write_table(int length, void *buffer, int length2,
1894 void *buffer2, int uncompressed)
plougher1f413c82005-11-18 00:02:14 +00001895{
plougher17b269c2009-03-30 01:33:07 +00001896 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1897 SQUASHFS_METADATA_SIZE;
plougher0e453652006-11-06 01:49:35 +00001898 long long list[meta_blocks], start_bytes;
plougherbadfac62007-11-12 03:29:41 +00001899 int compressed_size, i;
plougher1f413c82005-11-18 00:02:14 +00001900 unsigned short c_byte;
plougher0e453652006-11-06 01:49:35 +00001901 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1902
plougher82ab2332009-04-21 00:21:21 +00001903#ifdef SQUASHFS_TRACE
plougher0e453652006-11-06 01:49:35 +00001904 long long obytes = bytes;
plougher40d8b952010-02-12 16:26:32 +00001905 int olength = length;
plougher82ab2332009-04-21 00:21:21 +00001906#endif
plougher1f413c82005-11-18 00:02:14 +00001907
1908 for(i = 0; i < meta_blocks; i++) {
plougher17b269c2009-03-30 01:33:07 +00001909 int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1910 SQUASHFS_METADATA_SIZE : length;
1911 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1912 SQUASHFS_METADATA_SIZE , avail_bytes,
1913 SQUASHFS_METADATA_SIZE, uncompressed, 0);
plougherac28cd12010-02-24 02:25:03 +00001914 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
plougher1f413c82005-11-18 00:02:14 +00001915 list[i] = bytes;
plougher50b31762009-03-31 04:14:46 +00001916 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1917 BLOCK_OFFSET;
plougher17b269c2009-03-30 01:33:07 +00001918 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1919 compressed_size);
plougher0dd6f122009-03-29 21:43:57 +00001920 write_destination(fd, bytes, compressed_size, cbuffer);
plougher1f413c82005-11-18 00:02:14 +00001921 bytes += compressed_size;
plougher10f7d572010-07-20 02:14:04 +00001922 total_bytes += avail_bytes;
plougher0e453652006-11-06 01:49:35 +00001923 length -= avail_bytes;
plougher1f413c82005-11-18 00:02:14 +00001924 }
1925
ploughere6e0e1b2010-05-12 17:17:06 +00001926 start_bytes = bytes;
1927 if(length2) {
ploughera0a49c32010-08-11 01:47:59 +00001928 write_destination(fd, bytes, length2, buffer2);
ploughere6e0e1b2010-05-12 17:17:06 +00001929 bytes += length2;
plougher10f7d572010-07-20 02:14:04 +00001930 total_bytes += length2;
ploughere6e0e1b2010-05-12 17:17:06 +00001931 }
1932
plougher1f288f62009-02-21 03:05:52 +00001933 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
plougher29e2ace2010-12-31 08:50:00 +00001934 write_destination(fd, bytes, sizeof(list), list);
plougher1f413c82005-11-18 00:02:14 +00001935 bytes += sizeof(list);
plougher10f7d572010-07-20 02:14:04 +00001936 total_bytes += sizeof(list);
plougher1f413c82005-11-18 00:02:14 +00001937
plougher40d8b952010-02-12 16:26:32 +00001938 TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1939 olength, bytes - obytes);
plougher0e453652006-11-06 01:49:35 +00001940
plougher1f413c82005-11-18 00:02:14 +00001941 return start_bytes;
1942}
1943
1944
plougher0e453652006-11-06 01:49:35 +00001945long long write_fragment_table()
1946{
1947 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
plougher8ed84b92010-12-31 10:37:24 +00001948 struct squashfs_fragment_entry p[fragments];
plougher0e453652006-11-06 01:49:35 +00001949 int i;
1950
plougher17b269c2009-03-30 01:33:07 +00001951 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1952 frag_bytes);
plougherac28cd12010-02-24 02:25:03 +00001953 for(i = 0; i < fragments; i++) {
plougher50b31762009-03-31 04:14:46 +00001954 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1955 "size %d\n", i, fragment_table[i].start_block,
plougher17b269c2009-03-30 01:33:07 +00001956 fragment_table[i].size);
plougherac28cd12010-02-24 02:25:03 +00001957 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p + i);
plougher0e453652006-11-06 01:49:35 +00001958 }
1959
ploughera0a49c32010-08-11 01:47:59 +00001960 return generic_write_table(frag_bytes, p, 0, NULL, noF);
plougher0e453652006-11-06 01:49:35 +00001961}
1962
1963
plougher1f413c82005-11-18 00:02:14 +00001964char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher5507dd92006-11-06 00:43:10 +00001965char *read_from_disk(long long start, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001966{
plougher1d065e92010-06-18 03:58:27 +00001967 int res;
1968
1969 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
1970 if(res == 0)
1971 EXIT_MKSQUASHFS();
1972
plougher1f413c82005-11-18 00:02:14 +00001973 return read_from_file_buffer;
1974}
1975
1976
plougher1b899fc2008-08-07 01:24:06 +00001977char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
1978char *read_from_disk2(long long start, unsigned int avail_bytes)
1979{
plougher1d065e92010-06-18 03:58:27 +00001980 int res;
1981
1982 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
1983 if(res == 0)
1984 EXIT_MKSQUASHFS();
1985
plougher1b899fc2008-08-07 01:24:06 +00001986 return read_from_file_buffer2;
1987}
1988
1989
plougher1f413c82005-11-18 00:02:14 +00001990/*
1991 * Compute 16 bit BSD checksum over the data
1992 */
plougher5507dd92006-11-06 00:43:10 +00001993unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
plougher1f413c82005-11-18 00:02:14 +00001994{
plougher5507dd92006-11-06 00:43:10 +00001995 unsigned char *b = (unsigned char *) buff;
plougher1f413c82005-11-18 00:02:14 +00001996
plougher5507dd92006-11-06 00:43:10 +00001997 while(bytes --) {
1998 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1999 chksum += *b++;
plougher1f413c82005-11-18 00:02:14 +00002000 }
2001
2002 return chksum;
2003}
2004
2005
plougher17b269c2009-03-30 01:33:07 +00002006unsigned short get_checksum_disk(long long start, long long l,
2007 unsigned int *blocks)
plougher5507dd92006-11-06 00:43:10 +00002008{
2009 unsigned short chksum = 0;
2010 unsigned int bytes;
plougher57e6d182008-05-06 23:51:29 +00002011 struct file_buffer *write_buffer;
2012 int i;
plougher5507dd92006-11-06 00:43:10 +00002013
plougher57e6d182008-05-06 23:51:29 +00002014 for(i = 0; l; i++) {
2015 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
2016 if(bytes == 0) /* sparse block */
2017 continue;
2018 write_buffer = cache_lookup(writer_buffer, start);
2019 if(write_buffer) {
plougher50b31762009-03-31 04:14:46 +00002020 chksum = get_checksum(write_buffer->data, bytes,
2021 chksum);
plougher57e6d182008-05-06 23:51:29 +00002022 cache_block_put(write_buffer);
2023 } else
plougher50b31762009-03-31 04:14:46 +00002024 chksum = get_checksum(read_from_disk(start, bytes),
2025 bytes, chksum);
plougher5507dd92006-11-06 00:43:10 +00002026 l -= bytes;
plougher5507dd92006-11-06 00:43:10 +00002027 start += bytes;
2028 }
2029
2030 return chksum;
2031}
2032
2033
plougher5507dd92006-11-06 00:43:10 +00002034unsigned short get_checksum_mem(char *buff, int bytes)
2035{
2036 return get_checksum(buff, bytes, 0);
2037}
2038
2039
2040unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
2041{
2042 if(file_buffer == NULL)
2043 return 0;
2044 else
2045 return get_checksum(file_buffer->data, file_buffer->size, 0);
2046}
2047
2048
plougher5507dd92006-11-06 00:43:10 +00002049#define DUP_HASH(a) (a & 0xffff)
plougher17b269c2009-03-30 01:33:07 +00002050void add_file(long long start, long long file_size, long long file_bytes,
plougher50b31762009-03-31 04:14:46 +00002051 unsigned int *block_listp, int blocks, unsigned int fragment,
2052 int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00002053{
2054 struct fragment *frg;
plougher058eae42006-01-30 14:27:44 +00002055 unsigned int *block_list = block_listp;
plougher5507dd92006-11-06 00:43:10 +00002056 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher058eae42006-01-30 14:27:44 +00002057
plougher5507dd92006-11-06 00:43:10 +00002058 if(!duplicate_checking || file_size == 0)
plougher1f413c82005-11-18 00:02:14 +00002059 return;
2060
plougher5507dd92006-11-06 00:43:10 +00002061 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
2062 if(file_size != dupl_ptr->file_size)
2063 continue;
2064 if(blocks != 0 && start != dupl_ptr->start)
2065 continue;
2066 if(fragment != dupl_ptr->fragment->index)
2067 continue;
plougher17b269c2009-03-30 01:33:07 +00002068 if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
2069 dupl_ptr->fragment->offset || bytes !=
2070 dupl_ptr->fragment->size))
plougher5507dd92006-11-06 00:43:10 +00002071 continue;
2072 return;
2073 }
2074
plougher3bb279c2010-12-16 05:10:03 +00002075 frg = malloc(sizeof(struct fragment));
2076 if(frg == NULL)
plougher1f413c82005-11-18 00:02:14 +00002077 BAD_ERROR("Out of memory in fragment block allocation!\n");
2078
2079 frg->index = fragment;
2080 frg->offset = offset;
2081 frg->size = bytes;
plougher1f413c82005-11-18 00:02:14 +00002082
plougher5507dd92006-11-06 00:43:10 +00002083 add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
2084}
plougher1f413c82005-11-18 00:02:14 +00002085
plougher1f413c82005-11-18 00:02:14 +00002086
plougher5507dd92006-11-06 00:43:10 +00002087int pre_duplicate(long long file_size)
plougher1f413c82005-11-18 00:02:14 +00002088{
plougher5507dd92006-11-06 00:43:10 +00002089 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
plougher1f413c82005-11-18 00:02:14 +00002090
2091 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher5507dd92006-11-06 00:43:10 +00002092 if(dupl_ptr->file_size == file_size)
2093 return TRUE;
plougher1f413c82005-11-18 00:02:14 +00002094
plougher5507dd92006-11-06 00:43:10 +00002095 return FALSE;
2096}
2097
2098
2099int pre_duplicate_frag(long long file_size, unsigned short checksum)
2100{
2101 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2102
2103 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher17b269c2009-03-30 01:33:07 +00002104 if(file_size == dupl_ptr->file_size && file_size ==
2105 dupl_ptr->fragment->size) {
plougher5507dd92006-11-06 00:43:10 +00002106 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002107 struct file_buffer *frag_buffer =
2108 get_fragment(dupl_ptr->fragment);
2109 dupl_ptr->checksum =
2110 get_checksum_disk(dupl_ptr->start,
2111 dupl_ptr->bytes, dupl_ptr->block_list);
2112 dupl_ptr->fragment_checksum =
2113 get_checksum_mem(frag_buffer->data +
2114 dupl_ptr->fragment->offset, file_size);
plougher76c64082008-03-08 01:32:23 +00002115 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002116 dupl_ptr->checksum_flag = TRUE;
plougher1f413c82005-11-18 00:02:14 +00002117 }
plougher5507dd92006-11-06 00:43:10 +00002118 if(dupl_ptr->fragment_checksum == checksum)
2119 return TRUE;
2120 }
plougher1f413c82005-11-18 00:02:14 +00002121
plougher5507dd92006-11-06 00:43:10 +00002122 return FALSE;
2123}
2124
2125
plougher17b269c2009-03-30 01:33:07 +00002126struct file_info *add_non_dup(long long file_size, long long bytes,
2127 unsigned int *block_list, long long start, struct fragment *fragment,
2128 unsigned short checksum, unsigned short fragment_checksum,
2129 int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002130{
plougher51ef9ae2010-12-16 05:14:28 +00002131 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
plougher5507dd92006-11-06 00:43:10 +00002132
plougher51ef9ae2010-12-16 05:14:28 +00002133 if(dupl_ptr == NULL) {
plougher5507dd92006-11-06 00:43:10 +00002134 BAD_ERROR("Out of memory in dup_files allocation!\n");
2135 }
2136
2137 dupl_ptr->file_size = file_size;
2138 dupl_ptr->bytes = bytes;
2139 dupl_ptr->block_list = block_list;
2140 dupl_ptr->start = start;
2141 dupl_ptr->fragment = fragment;
2142 dupl_ptr->checksum = checksum;
2143 dupl_ptr->fragment_checksum = fragment_checksum;
2144 dupl_ptr->checksum_flag = checksum_flag;
2145 dupl_ptr->next = dupl[DUP_HASH(file_size)];
2146 dupl[DUP_HASH(file_size)] = dupl_ptr;
2147 dup_files ++;
2148
2149 return dupl_ptr;
2150}
2151
2152
plougher17b269c2009-03-30 01:33:07 +00002153struct file_info *duplicate(long long file_size, long long bytes,
2154 unsigned int **block_list, long long *start, struct fragment **fragment,
2155 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2156 unsigned short fragment_checksum, int checksum_flag)
plougher5507dd92006-11-06 00:43:10 +00002157{
2158 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2159 int frag_bytes = file_buffer ? file_buffer->size : 0;
2160
2161 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
plougher16111452010-07-22 05:12:18 +00002162 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2163 && frag_bytes == dupl_ptr->fragment->size) {
plougher1b899fc2008-08-07 01:24:06 +00002164 long long target_start, dup_start = dupl_ptr->start;
plougher5507dd92006-11-06 00:43:10 +00002165 int block;
2166
plougher17b269c2009-03-30 01:33:07 +00002167 if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2168 sizeof(unsigned int)) != 0)
plougherfbf9f752007-08-12 05:02:24 +00002169 continue;
2170
plougher5507dd92006-11-06 00:43:10 +00002171 if(checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002172 checksum = get_checksum_disk(*start, bytes,
2173 *block_list);
2174 fragment_checksum =
2175 get_checksum_mem_buffer(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002176 checksum_flag = TRUE;
2177 }
2178
2179 if(dupl_ptr->checksum_flag == FALSE) {
plougher17b269c2009-03-30 01:33:07 +00002180 struct file_buffer *frag_buffer =
2181 get_fragment(dupl_ptr->fragment);
2182 dupl_ptr->checksum =
2183 get_checksum_disk(dupl_ptr->start,
2184 dupl_ptr->bytes, dupl_ptr->block_list);
2185 dupl_ptr->fragment_checksum =
2186 get_checksum_mem(frag_buffer->data +
2187 dupl_ptr->fragment->offset, frag_bytes);
plougher76c64082008-03-08 01:32:23 +00002188 cache_block_put(frag_buffer);
plougher5507dd92006-11-06 00:43:10 +00002189 dupl_ptr->checksum_flag = TRUE;
2190 }
2191
plougher17b269c2009-03-30 01:33:07 +00002192 if(checksum != dupl_ptr->checksum ||
2193 fragment_checksum !=
2194 dupl_ptr->fragment_checksum)
plougher5507dd92006-11-06 00:43:10 +00002195 continue;
2196
plougher1b899fc2008-08-07 01:24:06 +00002197 target_start = *start;
plougher5507dd92006-11-06 00:43:10 +00002198 for(block = 0; block < blocks; block ++) {
plougher17b269c2009-03-30 01:33:07 +00002199 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2200 ((*block_list)[block]);
plougher1b899fc2008-08-07 01:24:06 +00002201 struct file_buffer *target_buffer = NULL;
2202 struct file_buffer *dup_buffer = NULL;
2203 char *target_data, *dup_data;
plougher0f464442008-03-31 00:27:56 +00002204 int res;
plougher5507dd92006-11-06 00:43:10 +00002205
plougher1b899fc2008-08-07 01:24:06 +00002206 if(size == 0)
plougherfbf9f752007-08-12 05:02:24 +00002207 continue;
plougher17b269c2009-03-30 01:33:07 +00002208 target_buffer = cache_lookup(writer_buffer,
2209 target_start);
plougher1b899fc2008-08-07 01:24:06 +00002210 if(target_buffer)
2211 target_data = target_buffer->data;
2212 else
plougher50b31762009-03-31 04:14:46 +00002213 target_data =
2214 read_from_disk(target_start,
plougher17b269c2009-03-30 01:33:07 +00002215 size);
plougher5507dd92006-11-06 00:43:10 +00002216
plougher360514a2009-03-30 03:01:38 +00002217 dup_buffer = cache_lookup(writer_buffer,
2218 dup_start);
plougher1b899fc2008-08-07 01:24:06 +00002219 if(dup_buffer)
2220 dup_data = dup_buffer->data;
2221 else
plougher360514a2009-03-30 03:01:38 +00002222 dup_data = read_from_disk2(dup_start,
2223 size);
plougher1b899fc2008-08-07 01:24:06 +00002224
2225 res = memcmp(target_data, dup_data, size);
2226 cache_block_put(target_buffer);
2227 cache_block_put(dup_buffer);
plougher0f464442008-03-31 00:27:56 +00002228 if(res != 0)
plougher5507dd92006-11-06 00:43:10 +00002229 break;
plougher1b899fc2008-08-07 01:24:06 +00002230 target_start += size;
2231 dup_start += size;
plougher5507dd92006-11-06 00:43:10 +00002232 }
2233 if(block == blocks) {
plougher17b269c2009-03-30 01:33:07 +00002234 struct file_buffer *frag_buffer =
2235 get_fragment(dupl_ptr->fragment);
plougher5507dd92006-11-06 00:43:10 +00002236
plougher17b269c2009-03-30 01:33:07 +00002237 if(frag_bytes == 0 ||
2238 memcmp(file_buffer->data,
2239 frag_buffer->data +
2240 dupl_ptr->fragment->offset,
2241 frag_bytes) == 0) {
plougher50b31762009-03-31 04:14:46 +00002242 TRACE("Found duplicate file, start "
2243 "0x%llx, size %lld, checksum "
2244 "0x%x, fragment %d, size %d, "
2245 "offset %d, checksum 0x%x\n",
2246 dupl_ptr->start,
plougher17b269c2009-03-30 01:33:07 +00002247 dupl_ptr->bytes,
2248 dupl_ptr->checksum,
2249 dupl_ptr->fragment->index,
2250 frag_bytes,
2251 dupl_ptr->fragment->offset,
2252 fragment_checksum);
plougher1f413c82005-11-18 00:02:14 +00002253 *block_list = dupl_ptr->block_list;
2254 *start = dupl_ptr->start;
2255 *fragment = dupl_ptr->fragment;
plougher76c64082008-03-08 01:32:23 +00002256 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002257 return 0;
2258 }
plougher76c64082008-03-08 01:32:23 +00002259 cache_block_put(frag_buffer);
plougher1f413c82005-11-18 00:02:14 +00002260 }
2261 }
2262
2263
plougher17b269c2009-03-30 01:33:07 +00002264 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2265 checksum, fragment_checksum, checksum_flag);
plougher1f413c82005-11-18 00:02:14 +00002266}
2267
2268
Phillip Lougher2504b082011-09-07 02:28:45 +01002269inline int is_fragment(struct inode_info *inode)
2270{
2271 int file_size = inode->buf.st_size;
2272
Phillip Lougher63f531f2011-09-10 04:03:32 +01002273 /*
2274 * If this block is to be compressed differently to the
2275 * fragment compression then it cannot be a fragment
2276 */
2277 if(inode->noF != noF)
2278 return FALSE;
2279
Phillip Lougher2504b082011-09-07 02:28:45 +01002280 return !inode->no_fragments && (file_size < block_size ||
2281 (inode->always_use_fragments && file_size & (block_size - 1)));
2282}
2283
2284
plougher00d08172009-09-03 10:17:44 +00002285static int seq = 0;
2286void reader_read_process(struct dir_ent *dir_ent)
2287{
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002288 struct inode_info *inode = dir_ent->inode;
plougher00d08172009-09-03 10:17:44 +00002289 struct file_buffer *prev_buffer = NULL, *file_buffer;
plougherba674e82009-09-10 03:50:00 +00002290 int status, res, byte, count = 0;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002291 int file = get_pseudo_file(inode->pseudo_id)->fd;
2292 int child = get_pseudo_file(inode->pseudo_id)->child;
plougher00d08172009-09-03 10:17:44 +00002293 long long bytes = 0;
2294
2295 while(1) {
2296 file_buffer = cache_get(reader_buffer, 0, 0);
2297 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002298 file_buffer->noD = inode->noD;
plougher00d08172009-09-03 10:17:44 +00002299
2300 byte = read_bytes(file, file_buffer->data, block_size);
2301 if(byte == -1)
2302 goto read_err;
2303
2304 file_buffer->size = byte;
2305 file_buffer->file_size = -1;
2306 file_buffer->block = count ++;
2307 file_buffer->error = FALSE;
2308 file_buffer->fragment = FALSE;
2309 bytes += byte;
2310
2311 if(byte == 0)
2312 break;
2313
plougher286b6b32009-09-19 03:29:27 +00002314 /*
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002315 * Update progress bar size. This is done
plougher286b6b32009-09-19 03:29:27 +00002316 * on every block rather than waiting for all blocks to be
2317 * read incase write_file_process() is running in parallel
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002318 * with this. Otherwise the current progress bar position
2319 * may get ahead of the progress bar size.
plougher286b6b32009-09-19 03:29:27 +00002320 */
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002321 progress_bar_size(1);
plougher286b6b32009-09-19 03:29:27 +00002322
plougher00d08172009-09-03 10:17:44 +00002323 if(prev_buffer)
2324 queue_put(from_reader, prev_buffer);
2325 prev_buffer = file_buffer;
2326 }
2327
plougher54d67292009-09-19 03:26:27 +00002328 /*
2329 * Update inode file size now that the size of the dynamic pseudo file
2330 * is known. This is needed for the -info option.
2331 */
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002332 inode->buf.st_size = bytes;
plougher54d67292009-09-19 03:26:27 +00002333
plougherba674e82009-09-10 03:50:00 +00002334 res = waitpid(child, &status, 0);
plougherd87d8d12009-09-10 04:08:16 +00002335 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
plougherba674e82009-09-10 03:50:00 +00002336 goto read_err;
2337
plougher00d08172009-09-03 10:17:44 +00002338 if(prev_buffer == NULL)
2339 prev_buffer = file_buffer;
2340 else {
2341 cache_block_put(file_buffer);
2342 seq --;
2343 }
2344 prev_buffer->file_size = bytes;
Phillip Lougher2504b082011-09-07 02:28:45 +01002345 prev_buffer->fragment = is_fragment(inode);
plougher00d08172009-09-03 10:17:44 +00002346 queue_put(from_reader, prev_buffer);
2347
2348 return;
2349
2350read_err:
2351 if(prev_buffer) {
2352 cache_block_put(file_buffer);
2353 seq --;
2354 file_buffer = prev_buffer;
2355 }
2356 file_buffer->error = TRUE;
2357 queue_put(from_deflate, file_buffer);
2358}
2359
2360
plougher5507dd92006-11-06 00:43:10 +00002361void reader_read_file(struct dir_ent *dir_ent)
plougher1f413c82005-11-18 00:02:14 +00002362{
plougher018d2b32007-04-23 03:01:48 +00002363 struct stat *buf = &dir_ent->inode->buf, buf2;
plougher5507dd92006-11-06 00:43:10 +00002364 struct file_buffer *file_buffer;
Phillip Lougher2504b082011-09-07 02:28:45 +01002365 int blocks, byte, count, expected, file;
plougher018d2b32007-04-23 03:01:48 +00002366 long long bytes, read_size;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002367 struct inode_info *inode = dir_ent->inode;
plougher5507dd92006-11-06 00:43:10 +00002368
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002369 if(inode->read)
plougher5507dd92006-11-06 00:43:10 +00002370 return;
2371
Phillip Lougher9b6e3412011-09-05 02:58:41 +01002372 inode->read = TRUE;
plougher018d2b32007-04-23 03:01:48 +00002373again:
2374 bytes = 0;
2375 count = 0;
2376 file_buffer = NULL;
2377 read_size = buf->st_size;
2378 blocks = (read_size + block_size - 1) >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002379
Phillip Lougher494479f2012-02-03 15:45:41 +00002380 file = open(pathname_reader(dir_ent), O_RDONLY);
plougherc1d258e2010-12-16 05:16:45 +00002381 if(file == -1) {
plougher1e380702010-08-11 01:52:49 +00002382 file_buffer = cache_get(reader_buffer, 0, 0);
2383 file_buffer->sequence = seq ++;
plougher5507dd92006-11-06 00:43:10 +00002384 goto read_err;
plougher1e380702010-08-11 01:52:49 +00002385 }
plougher5507dd92006-11-06 00:43:10 +00002386
plougher018d2b32007-04-23 03:01:48 +00002387 do {
plougher110799c2009-03-30 01:50:40 +00002388 expected = read_size - ((long long) count * block_size) >
plougher50b31762009-03-31 04:14:46 +00002389 block_size ? block_size :
2390 read_size - ((long long) count * block_size);
plougher018d2b32007-04-23 03:01:48 +00002391
2392 if(file_buffer)
2393 queue_put(from_reader, file_buffer);
plougher0f464442008-03-31 00:27:56 +00002394 file_buffer = cache_get(reader_buffer, 0, 0);
plougher00d08172009-09-03 10:17:44 +00002395 file_buffer->sequence = seq ++;
Phillip Lougher63f531f2011-09-10 04:03:32 +01002396 file_buffer->noD = inode->noD;
plougher5507dd92006-11-06 00:43:10 +00002397
ploughera4c24ed2010-08-11 02:08:38 +00002398 /*
2399 * Always try to read block_size bytes from the file rather
2400 * than expected bytes (which will be less than the block_size
2401 * at the file tail) to check that the file hasn't grown
2402 * since being stated. If it is longer (or shorter) than
2403 * expected, then restat, and try again. Note the special
2404 * case where the file is an exact multiple of the block_size
2405 * is dealt with later.
2406 */
plougher110799c2009-03-30 01:50:40 +00002407 byte = file_buffer->size = read_bytes(file, file_buffer->data,
2408 block_size);
plougher018d2b32007-04-23 03:01:48 +00002409
plougher018d2b32007-04-23 03:01:48 +00002410 file_buffer->file_size = read_size;
2411
ploughera4c24ed2010-08-11 02:08:38 +00002412 if(byte == -1)
2413 goto read_err;
2414
plougher018d2b32007-04-23 03:01:48 +00002415 if(byte != expected)
2416 goto restat;
2417
2418 file_buffer->block = count;
plougher5507dd92006-11-06 00:43:10 +00002419 file_buffer->error = FALSE;
Phillip Lougher2504b082011-09-07 02:28:45 +01002420 file_buffer->fragment = FALSE;
plougher018d2b32007-04-23 03:01:48 +00002421
2422 bytes += byte;
2423 count ++;
2424 } while(count < blocks);
2425
2426 if(read_size != bytes)
2427 goto restat;
2428
2429 if(expected == block_size) {
ploughera4c24ed2010-08-11 02:08:38 +00002430 /*
2431 * Special case where we've not tried to read past the end of
2432 * the file. We expect to get EOF, i.e. the file isn't larger
2433 * than we expect.
2434 */
plougher018d2b32007-04-23 03:01:48 +00002435 char buffer;
ploughera4c24ed2010-08-11 02:08:38 +00002436 int res;
plougher018d2b32007-04-23 03:01:48 +00002437
ploughera4c24ed2010-08-11 02:08:38 +00002438 res = read_bytes(file, &buffer, 1);
2439 if(res == -1)
2440 goto read_err;
2441
2442 if(res != 0)
plougher018d2b32007-04-23 03:01:48 +00002443 goto restat;
plougher5507dd92006-11-06 00:43:10 +00002444 }
2445
Phillip Lougher2504b082011-09-07 02:28:45 +01002446 file_buffer->fragment = is_fragment(inode);
plougher1b899fc2008-08-07 01:24:06 +00002447 queue_put(from_reader, file_buffer);
plougher018d2b32007-04-23 03:01:48 +00002448
plougher5507dd92006-11-06 00:43:10 +00002449 close(file);
plougher5507dd92006-11-06 00:43:10 +00002450
2451 return;
2452
plougher018d2b32007-04-23 03:01:48 +00002453restat:
2454 fstat(file, &buf2);
2455 close(file);
2456 if(read_size != buf2.st_size) {
2457 memcpy(buf, &buf2, sizeof(struct stat));
2458 file_buffer->error = 2;
2459 queue_put(from_deflate, file_buffer);
2460 goto again;
2461 }
plougher1e380702010-08-11 01:52:49 +00002462read_err:
2463 file_buffer->error = TRUE;
2464 queue_put(from_deflate, file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002465}
2466
2467
2468void reader_scan(struct dir_info *dir) {
Phillip Lougherbf338362012-08-22 05:24:36 +01002469 struct dir_ent *dir_ent = dir->list;
plougher5507dd92006-11-06 00:43:10 +00002470
Phillip Lougherbf338362012-08-22 05:24:36 +01002471 for(; dir_ent; dir_ent = dir_ent->next) {
plougher5507dd92006-11-06 00:43:10 +00002472 struct stat *buf = &dir_ent->inode->buf;
ploughera326c182009-08-29 05:41:45 +00002473 if(dir_ent->inode->root_entry)
plougher5507dd92006-11-06 00:43:10 +00002474 continue;
2475
plougherb3977eb2010-05-02 02:08:48 +00002476 if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
plougher00d08172009-09-03 10:17:44 +00002477 reader_read_process(dir_ent);
2478 continue;
2479 }
2480
plougher5507dd92006-11-06 00:43:10 +00002481 switch(buf->st_mode & S_IFMT) {
2482 case S_IFREG:
2483 reader_read_file(dir_ent);
2484 break;
2485 case S_IFDIR:
2486 reader_scan(dir_ent->dir);
2487 break;
2488 }
2489 }
2490}
2491
2492
2493void *reader(void *arg)
2494{
2495 int oldstate;
2496
2497 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2498 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2499
2500 if(!sorted)
2501 reader_scan(queue_get(to_reader));
2502 else {
2503 int i;
2504 struct priority_entry *entry;
2505
2506 queue_get(to_reader);
2507 for(i = 65535; i >= 0; i--)
plougher16111452010-07-22 05:12:18 +00002508 for(entry = priority_list[i]; entry;
2509 entry = entry->next)
plougher5507dd92006-11-06 00:43:10 +00002510 reader_read_file(entry->dir);
2511 }
rloughere4873e02007-11-08 17:50:42 +00002512
plougher5aa18162007-12-13 12:15:21 +00002513 thread[0] = 0;
2514
rloughere4873e02007-11-08 17:50:42 +00002515 pthread_exit(NULL);
plougher5507dd92006-11-06 00:43:10 +00002516}
2517
2518
2519void *writer(void *arg)
2520{
2521 int write_error = FALSE;
2522 int oldstate;
2523
2524 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2525 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2526
2527 while(1) {
2528 struct file_buffer *file_buffer = queue_get(to_writer);
2529 off_t off;
2530
2531 if(file_buffer == NULL) {
plougher110799c2009-03-30 01:50:40 +00002532 queue_put(from_writer,
plougherc2a5ae12010-12-31 08:35:28 +00002533 write_error ? &write_error : NULL);
plougher5507dd92006-11-06 00:43:10 +00002534 continue;
2535 }
2536
2537 off = file_buffer->block;
2538
2539 pthread_mutex_lock(&pos_mutex);
2540
2541 if(!write_error && lseek(fd, off, SEEK_SET) == -1) {
plougher110799c2009-03-30 01:50:40 +00002542 ERROR("Lseek on destination failed because %s\n",
2543 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002544 write_error = TRUE;
2545 }
2546
plougher110799c2009-03-30 01:50:40 +00002547 if(!write_error && write_bytes(fd, file_buffer->data,
2548 file_buffer->size) == -1) {
2549 ERROR("Write on destination failed because %s\n",
2550 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002551 write_error = TRUE;
2552 }
2553 pthread_mutex_unlock(&pos_mutex);
2554
ploughereb6eac92008-02-26 01:50:48 +00002555 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002556 }
2557}
2558
2559
plougher5b09fd42007-08-06 10:28:41 +00002560int all_zero(struct file_buffer *file_buffer)
2561{
2562 int i;
2563 long entries = file_buffer->size / sizeof(long);
2564 long *p = (long *) file_buffer->data;
2565
2566 for(i = 0; i < entries && p[i] == 0; i++);
2567
2568 if(i == entries) {
plougher110799c2009-03-30 01:50:40 +00002569 for(i = file_buffer->size & ~(sizeof(long) - 1);
plougher50b31762009-03-31 04:14:46 +00002570 i < file_buffer->size && file_buffer->data[i] == 0;
2571 i++);
plougher5b09fd42007-08-06 10:28:41 +00002572
2573 return i == file_buffer->size;
2574 }
2575
2576 return 0;
2577}
2578
2579
plougher5507dd92006-11-06 00:43:10 +00002580void *deflator(void *arg)
2581{
plougher7b8ee502009-07-29 07:54:30 +00002582 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002583 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002584
2585 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2586 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2587
plougher13fdddf2010-11-24 01:23:41 +00002588 res = compressor_init(comp, &stream, block_size, 1);
2589 if(res)
2590 BAD_ERROR("deflator:: compressor_init failed\n");
2591
plougher5507dd92006-11-06 00:43:10 +00002592 while(1) {
2593 struct file_buffer *file_buffer = queue_get(from_reader);
plougher1b899fc2008-08-07 01:24:06 +00002594 struct file_buffer *write_buffer;
plougher5507dd92006-11-06 00:43:10 +00002595
Phillip Lougher48854382011-09-09 03:36:55 +01002596 if(file_buffer->file_size == 0) {
2597 file_buffer->c_byte = 0;
2598 queue_put(from_deflate, file_buffer);
2599 } else if(sparse_files && all_zero(file_buffer)) {
plougher1b899fc2008-08-07 01:24:06 +00002600 file_buffer->c_byte = 0;
2601 queue_put(from_deflate, file_buffer);
2602 } else if(file_buffer->fragment) {
2603 file_buffer->c_byte = file_buffer->size;
2604 queue_put(from_deflate, file_buffer);
2605 } else {
2606 write_buffer = cache_get(writer_buffer, 0, 0);
plougher13fdddf2010-11-24 01:23:41 +00002607 write_buffer->c_byte = mangle2(stream,
plougher50b31762009-03-31 04:14:46 +00002608 write_buffer->data, file_buffer->data,
Phillip Lougher63f531f2011-09-10 04:03:32 +01002609 file_buffer->size, block_size,
2610 file_buffer->noD, 1);
plougher1b899fc2008-08-07 01:24:06 +00002611 write_buffer->sequence = file_buffer->sequence;
2612 write_buffer->file_size = file_buffer->file_size;
2613 write_buffer->block = file_buffer->block;
plougher110799c2009-03-30 01:50:40 +00002614 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2615 (write_buffer->c_byte);
plougher1b899fc2008-08-07 01:24:06 +00002616 write_buffer->fragment = FALSE;
2617 write_buffer->error = FALSE;
2618 cache_block_put(file_buffer);
2619 queue_put(from_deflate, write_buffer);
2620 }
plougher5507dd92006-11-06 00:43:10 +00002621 }
2622}
2623
2624
2625void *frag_deflator(void *arg)
2626{
plougher7b8ee502009-07-29 07:54:30 +00002627 void *stream = NULL;
plougher13fdddf2010-11-24 01:23:41 +00002628 int res, oldstate;
plougher5507dd92006-11-06 00:43:10 +00002629
2630 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2631 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2632
plougher13fdddf2010-11-24 01:23:41 +00002633 res = compressor_init(comp, &stream, block_size, 1);
2634 if(res)
2635 BAD_ERROR("frag_deflator:: compressor_init failed\n");
2636
plougher5507dd92006-11-06 00:43:10 +00002637 while(1) {
2638 int c_byte, compressed_size;
2639 struct file_buffer *file_buffer = queue_get(to_frag);
plougher110799c2009-03-30 01:50:40 +00002640 struct file_buffer *write_buffer =
plougher50b31762009-03-31 04:14:46 +00002641 cache_get(writer_buffer, file_buffer->block +
2642 FRAG_INDEX, 1);
plougher5507dd92006-11-06 00:43:10 +00002643
plougher13fdddf2010-11-24 01:23:41 +00002644 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
plougher110799c2009-03-30 01:50:40 +00002645 file_buffer->size, block_size, noF, 1);
plougher5507dd92006-11-06 00:43:10 +00002646 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
plougherd036a312008-03-08 01:38:27 +00002647 write_buffer->size = compressed_size;
plougherd1139d52008-04-28 03:07:07 +00002648 pthread_mutex_lock(&fragment_mutex);
plougher2ea89142008-03-11 01:34:19 +00002649 if(fragments_locked == FALSE) {
plougher2ea89142008-03-11 01:34:19 +00002650 fragment_table[file_buffer->block].size = c_byte;
2651 fragment_table[file_buffer->block].start_block = bytes;
2652 write_buffer->block = bytes;
2653 bytes += compressed_size;
2654 fragments_outstanding --;
plougher2ea89142008-03-11 01:34:19 +00002655 queue_put(to_writer, write_buffer);
plougher57501912009-09-20 02:20:42 +00002656 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002657 TRACE("Writing fragment %lld, uncompressed size %d, "
2658 "compressed size %d\n", file_buffer->block,
2659 file_buffer->size, compressed_size);
plougherd1139d52008-04-28 03:07:07 +00002660 } else {
2661 pthread_mutex_unlock(&fragment_mutex);
plougher110799c2009-03-30 01:50:40 +00002662 add_pending_fragment(write_buffer, c_byte,
2663 file_buffer->block);
plougherd1139d52008-04-28 03:07:07 +00002664 }
ploughereb6eac92008-02-26 01:50:48 +00002665 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002666 }
2667}
2668
2669
2670#define HASH_ENTRIES 256
2671#define BLOCK_HASH(a) (a % HASH_ENTRIES)
2672struct file_buffer *block_hash[HASH_ENTRIES];
2673
2674void push_buffer(struct file_buffer *file_buffer)
2675{
plougher0f464442008-03-31 00:27:56 +00002676 int hash = BLOCK_HASH(file_buffer->sequence);
plougher5507dd92006-11-06 00:43:10 +00002677
2678 file_buffer->next = block_hash[hash];
2679 block_hash[hash] = file_buffer;
2680}
2681
2682
2683struct file_buffer *get_file_buffer(struct queue *queue)
2684{
plougher0f464442008-03-31 00:27:56 +00002685 static unsigned int sequence = 0;
2686 int hash = BLOCK_HASH(sequence);
plougher5507dd92006-11-06 00:43:10 +00002687 struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
2688
2689 for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
plougher0f464442008-03-31 00:27:56 +00002690 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002691 break;
2692
2693 if(file_buffer) {
2694 if(prev)
2695 prev->next = file_buffer->next;
2696 else
2697 block_hash[hash] = file_buffer->next;
2698 } else {
2699 while(1) {
2700 file_buffer = queue_get(queue);
plougher0f464442008-03-31 00:27:56 +00002701 if(file_buffer->sequence == sequence)
plougher5507dd92006-11-06 00:43:10 +00002702 break;
2703 push_buffer(file_buffer);
2704 }
2705 }
2706
plougher0f464442008-03-31 00:27:56 +00002707 sequence ++;
plougher5507dd92006-11-06 00:43:10 +00002708
2709 return file_buffer;
2710}
2711
2712
plougher110799c2009-03-30 01:50:40 +00002713void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2714 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002715{
2716 file_count ++;
2717 *duplicate_file = FALSE;
plougherc1ace522010-05-01 03:00:45 +00002718 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2719 NULL, &empty_fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002720}
2721
2722
plougher50b31762009-03-31 04:14:46 +00002723void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2724 int size, int *duplicate_file, struct file_buffer *file_buffer,
plougher360514a2009-03-30 03:01:38 +00002725 unsigned short checksum)
plougher5507dd92006-11-06 00:43:10 +00002726{
plougher5507dd92006-11-06 00:43:10 +00002727 struct file_info *dupl_ptr;
plougher1f413c82005-11-18 00:02:14 +00002728 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002729 unsigned int *block_listp = NULL;
2730 long long start = 0;
plougherf9c72b12006-01-23 13:52:40 +00002731
plougher50b31762009-03-31 04:14:46 +00002732 dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
2733 file_buffer, 0, 0, checksum, TRUE);
plougher1f413c82005-11-18 00:02:14 +00002734
plougher5507dd92006-11-06 00:43:10 +00002735 if(dupl_ptr) {
2736 *duplicate_file = FALSE;
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002737 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002738 dupl_ptr->fragment = fragment;
2739 } else
2740 *duplicate_file = TRUE;
2741
ploughereb6eac92008-02-26 01:50:48 +00002742 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002743
2744 total_bytes += size;
2745 file_count ++;
2746
plougher35a10602008-04-21 02:58:16 +00002747 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002748
plougherc1ace522010-05-01 03:00:45 +00002749 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002750 0, NULL, fragment, NULL, 0);
plougher5507dd92006-11-06 00:43:10 +00002751}
2752
2753
plougher110799c2009-03-30 01:50:40 +00002754void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
2755 struct file_buffer *file_buffer, int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002756{
2757 struct fragment *fragment;
2758 unsigned short checksum;
plougher5507dd92006-11-06 00:43:10 +00002759
2760 checksum = get_checksum_mem_buffer(file_buffer);
2761
plougher29e37092007-04-15 01:24:51 +00002762 if(pre_duplicate_frag(size, checksum)) {
plougher110799c2009-03-30 01:50:40 +00002763 write_file_frag_dup(inode, dir_ent, size, duplicate_file,
2764 file_buffer, checksum);
plougher29e37092007-04-15 01:24:51 +00002765 return;
2766 }
plougher5507dd92006-11-06 00:43:10 +00002767
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002768 fragment = get_and_fill_fragment(file_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00002769
ploughereb6eac92008-02-26 01:50:48 +00002770 cache_block_put(file_buffer);
plougher5507dd92006-11-06 00:43:10 +00002771
2772 if(duplicate_checking)
2773 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
2774
2775 total_bytes += size;
2776 file_count ++;
2777
2778 *duplicate_file = FALSE;
2779
plougher35a10602008-04-21 02:58:16 +00002780 inc_progress_bar();
plougher02bc3bc2007-02-25 12:12:01 +00002781
plougherc1ace522010-05-01 03:00:45 +00002782 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
plougher3c6bdb52010-05-01 02:30:59 +00002783 0, NULL, fragment, NULL, 0);
plougher29e37092007-04-15 01:24:51 +00002784
plougher018d2b32007-04-23 03:01:48 +00002785 return;
plougher5507dd92006-11-06 00:43:10 +00002786}
2787
2788
plougher00d08172009-09-03 10:17:44 +00002789int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2790 struct file_buffer *read_buffer, int *duplicate_file)
2791{
2792 long long read_size, file_bytes, start;
2793 struct fragment *fragment;
2794 unsigned int *block_list = NULL;
2795 int block = 0, status;
2796 long long sparse = 0;
2797 struct file_buffer *fragment_buffer = NULL;
2798
2799 *duplicate_file = FALSE;
2800
2801 lock_fragments();
2802
2803 file_bytes = 0;
2804 start = bytes;
2805 while (1) {
2806 read_size = read_buffer->file_size;
2807 if(read_buffer->fragment && read_buffer->c_byte)
2808 fragment_buffer = read_buffer;
2809 else {
2810 block_list = realloc(block_list, (block + 1) *
2811 sizeof(unsigned int));
2812 if(block_list == NULL)
2813 BAD_ERROR("Out of memory allocating block_list"
2814 "\n");
2815 block_list[block ++] = read_buffer->c_byte;
2816 if(read_buffer->c_byte) {
2817 read_buffer->block = bytes;
2818 bytes += read_buffer->size;
2819 cache_rehash(read_buffer, read_buffer->block);
2820 file_bytes += read_buffer->size;
2821 queue_put(to_writer, read_buffer);
2822 } else {
2823 sparse += read_buffer->size;
2824 cache_block_put(read_buffer);
2825 }
2826 }
plougher286b6b32009-09-19 03:29:27 +00002827 inc_progress_bar();
plougher00d08172009-09-03 10:17:44 +00002828
2829 if(read_size != -1)
2830 break;
2831
2832 read_buffer = get_file_buffer(from_deflate);
2833 if(read_buffer->error)
2834 goto read_err;
2835 }
2836
2837 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002838 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher00d08172009-09-03 10:17:44 +00002839 cache_block_put(fragment_buffer);
2840
2841 if(duplicate_checking)
2842 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2843 0, 0, FALSE);
2844 file_count ++;
2845 total_bytes += read_size;
2846
plougherc1ace522010-05-01 03:00:45 +00002847 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2848 block, block_list, fragment, NULL, sparse);
plougher00d08172009-09-03 10:17:44 +00002849
2850 if(duplicate_checking == FALSE)
2851 free(block_list);
2852
2853 return 0;
2854
2855read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002856 dec_progress_bar(block);
plougher00d08172009-09-03 10:17:44 +00002857 status = read_buffer->error;
2858 bytes = start;
2859 if(!block_device) {
2860 int res;
2861
2862 queue_put(to_writer, NULL);
2863 if(queue_get(from_writer) != 0)
2864 EXIT_MKSQUASHFS();
2865 res = ftruncate(fd, bytes);
2866 if(res != 0)
2867 BAD_ERROR("Failed to truncate dest file because %s\n",
2868 strerror(errno));
2869 }
2870 unlock_fragments();
2871 free(block_list);
2872 cache_block_put(read_buffer);
2873 return status;
2874}
2875
2876
plougher110799c2009-03-30 01:50:40 +00002877int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002878 long long read_size, struct file_buffer *read_buffer,
2879 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002880{
plougher23377982007-11-12 04:04:48 +00002881 long long file_bytes, start;
plougher5507dd92006-11-06 00:43:10 +00002882 struct fragment *fragment;
plougher5507dd92006-11-06 00:43:10 +00002883 unsigned int *block_list;
plougher1b899fc2008-08-07 01:24:06 +00002884 int block, status;
2885 int blocks = (read_size + block_size - 1) >> block_log;
2886 long long sparse = 0;
2887 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002888
plougher29e37092007-04-15 01:24:51 +00002889 *duplicate_file = FALSE;
2890
plougher87139622010-12-16 05:19:30 +00002891 block_list = malloc(blocks * sizeof(unsigned int));
2892 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00002893 BAD_ERROR("Out of memory allocating block_list\n");
plougher1f413c82005-11-18 00:02:14 +00002894
plougher2ea89142008-03-11 01:34:19 +00002895 lock_fragments();
plougher1f413c82005-11-18 00:02:14 +00002896
plougher5507dd92006-11-06 00:43:10 +00002897 file_bytes = 0;
2898 start = bytes;
plougher1b899fc2008-08-07 01:24:06 +00002899 for(block = 0; block < blocks;) {
2900 if(read_buffer->fragment && read_buffer->c_byte) {
2901 fragment_buffer = read_buffer;
2902 blocks = read_size >> block_log;
plougher018d2b32007-04-23 03:01:48 +00002903 } else {
plougher1b899fc2008-08-07 01:24:06 +00002904 block_list[block] = read_buffer->c_byte;
2905 if(read_buffer->c_byte) {
2906 read_buffer->block = bytes;
2907 bytes += read_buffer->size;
2908 cache_rehash(read_buffer, read_buffer->block);
2909 file_bytes += read_buffer->size;
2910 queue_put(to_writer, read_buffer);
2911 } else {
2912 sparse += read_buffer->size;
2913 cache_block_put(read_buffer);
2914 }
2915 }
2916 inc_progress_bar();
2917
2918 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00002919 read_buffer = get_file_buffer(from_deflate);
2920 if(read_buffer->error)
2921 goto read_err;
2922 }
plougher1f413c82005-11-18 00:02:14 +00002923 }
2924
plougher2ea89142008-03-11 01:34:19 +00002925 unlock_fragments();
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01002926 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher1b899fc2008-08-07 01:24:06 +00002927 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00002928
plougher1f413c82005-11-18 00:02:14 +00002929 if(duplicate_checking)
plougher50b31762009-03-31 04:14:46 +00002930 add_non_dup(read_size, file_bytes, block_list, start, fragment,
2931 0, 0, FALSE);
plougher1f413c82005-11-18 00:02:14 +00002932 file_count ++;
plougher5507dd92006-11-06 00:43:10 +00002933 total_bytes += read_size;
plougher29e37092007-04-15 01:24:51 +00002934
plougher360514a2009-03-30 03:01:38 +00002935 /*
2936 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00002937 * a smaller block count on stat calls to sparse files. This is
2938 * to ensure intelligent applications like cp correctly handle the
2939 * file as a sparse file. If the file in the original filesystem isn't
2940 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00002941 * report it as non-sparse on stat calls to preserve semantics
2942 */
plougher1b899fc2008-08-07 01:24:06 +00002943 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2944 sparse = 0;
2945
plougherc1ace522010-05-01 03:00:45 +00002946 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2947 blocks, block_list, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00002948
plougher5507dd92006-11-06 00:43:10 +00002949 if(duplicate_checking == FALSE)
plougherf9c72b12006-01-23 13:52:40 +00002950 free(block_list);
plougher29e37092007-04-15 01:24:51 +00002951
plougher018d2b32007-04-23 03:01:48 +00002952 return 0;
plougher1f413c82005-11-18 00:02:14 +00002953
2954read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01002955 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00002956 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00002957 bytes = start;
2958 if(!block_device) {
plougher12a159a2009-03-03 11:06:34 +00002959 int res;
2960
plougher5507dd92006-11-06 00:43:10 +00002961 queue_put(to_writer, NULL);
2962 if(queue_get(from_writer) != 0)
2963 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00002964 res = ftruncate(fd, bytes);
2965 if(res != 0)
2966 BAD_ERROR("Failed to truncate dest file because %s\n",
2967 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00002968 }
plougher2ea89142008-03-11 01:34:19 +00002969 unlock_fragments();
plougherf9c72b12006-01-23 13:52:40 +00002970 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00002971 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00002972 return status;
plougher1f413c82005-11-18 00:02:14 +00002973}
2974
2975
plougher110799c2009-03-30 01:50:40 +00002976int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
plougher50b31762009-03-31 04:14:46 +00002977 long long read_size, struct file_buffer *read_buffer,
2978 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00002979{
plougher29e37092007-04-15 01:24:51 +00002980 int block, thresh;
plougher1b899fc2008-08-07 01:24:06 +00002981 long long file_bytes, dup_start, start;
plougher5507dd92006-11-06 00:43:10 +00002982 struct fragment *fragment;
2983 struct file_info *dupl_ptr;
2984 int blocks = (read_size + block_size - 1) >> block_log;
2985 unsigned int *block_list, *block_listp;
plougher1b899fc2008-08-07 01:24:06 +00002986 struct file_buffer **buffer_list;
plougher4e8484a2008-03-15 23:30:16 +00002987 int status, num_locked_fragments;
plougher1b899fc2008-08-07 01:24:06 +00002988 long long sparse = 0;
2989 struct file_buffer *fragment_buffer = NULL;
plougher5507dd92006-11-06 00:43:10 +00002990
plougher50b31762009-03-31 04:14:46 +00002991 block_list = malloc(blocks * sizeof(unsigned int));
2992 if(block_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00002993 BAD_ERROR("Out of memory allocating block_list\n");
2994 block_listp = block_list;
2995
plougher50b31762009-03-31 04:14:46 +00002996 buffer_list = malloc(blocks * sizeof(struct file_buffer *));
2997 if(buffer_list == NULL)
plougher5507dd92006-11-06 00:43:10 +00002998 BAD_ERROR("Out of memory allocating file block list\n");
2999
plougher4e8484a2008-03-15 23:30:16 +00003000 num_locked_fragments = lock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003001
3002 file_bytes = 0;
plougher1b899fc2008-08-07 01:24:06 +00003003 start = dup_start = bytes;
plougher110799c2009-03-30 01:50:40 +00003004 thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
3005 blocks - (writer_buffer_size - num_locked_fragments): 0;
plougher1b899fc2008-08-07 01:24:06 +00003006
3007 for(block = 0; block < blocks;) {
3008 if(read_buffer->fragment && read_buffer->c_byte) {
3009 fragment_buffer = read_buffer;
3010 blocks = read_size >> block_log;
3011 } else {
3012 block_list[block] = read_buffer->c_byte;
3013
3014 if(read_buffer->c_byte) {
3015 read_buffer->block = bytes;
3016 bytes += read_buffer->size;
3017 file_bytes += read_buffer->size;
3018 cache_rehash(read_buffer, read_buffer->block);
3019 if(block < thresh) {
3020 buffer_list[block] = NULL;
3021 queue_put(to_writer, read_buffer);
3022 } else
3023 buffer_list[block] = read_buffer;
3024 } else {
3025 buffer_list[block] = NULL;
3026 sparse += read_buffer->size;
3027 cache_block_put(read_buffer);
3028 }
3029 }
3030 inc_progress_bar();
3031
3032 if(++block < blocks) {
plougher018d2b32007-04-23 03:01:48 +00003033 read_buffer = get_file_buffer(from_deflate);
3034 if(read_buffer->error)
3035 goto read_err;
3036 }
plougher5507dd92006-11-06 00:43:10 +00003037 }
3038
plougher110799c2009-03-30 01:50:40 +00003039 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
3040 &fragment, fragment_buffer, blocks, 0, 0, FALSE);
plougher5507dd92006-11-06 00:43:10 +00003041
3042 if(dupl_ptr) {
3043 *duplicate_file = FALSE;
3044 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003045 if(buffer_list[block])
3046 queue_put(to_writer, buffer_list[block]);
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01003047 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
plougher5507dd92006-11-06 00:43:10 +00003048 dupl_ptr->fragment = fragment;
3049 } else {
3050 *duplicate_file = TRUE;
3051 for(block = thresh; block < blocks; block ++)
plougher1b899fc2008-08-07 01:24:06 +00003052 cache_block_put(buffer_list[block]);
3053 bytes = start;
3054 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003055 int res;
3056
plougher1b899fc2008-08-07 01:24:06 +00003057 queue_put(to_writer, NULL);
3058 if(queue_get(from_writer) != 0)
3059 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003060 res = ftruncate(fd, bytes);
3061 if(res != 0)
3062 BAD_ERROR("Failed to truncate dest file because"
3063 " %s\n", strerror(errno));
plougher1b899fc2008-08-07 01:24:06 +00003064 }
plougher5507dd92006-11-06 00:43:10 +00003065 }
3066
plougher2ea89142008-03-11 01:34:19 +00003067 unlock_fragments();
plougher1b899fc2008-08-07 01:24:06 +00003068 cache_block_put(fragment_buffer);
plougher5507dd92006-11-06 00:43:10 +00003069 free(buffer_list);
3070 file_count ++;
3071 total_bytes += read_size;
3072
plougher360514a2009-03-30 03:01:38 +00003073 /*
3074 * sparse count is needed to ensure squashfs correctly reports a
plougher1b899fc2008-08-07 01:24:06 +00003075 * a smaller block count on stat calls to sparse files. This is
3076 * to ensure intelligent applications like cp correctly handle the
3077 * file as a sparse file. If the file in the original filesystem isn't
3078 * stored as a sparse file then still store it sparsely in squashfs, but
plougher360514a2009-03-30 03:01:38 +00003079 * report it as non-sparse on stat calls to preserve semantics
3080 */
plougher1b899fc2008-08-07 01:24:06 +00003081 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
3082 sparse = 0;
3083
plougherc1ace522010-05-01 03:00:45 +00003084 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
3085 dup_start, blocks, block_listp, fragment, NULL, sparse);
plougher29e37092007-04-15 01:24:51 +00003086
plougher5507dd92006-11-06 00:43:10 +00003087 if(*duplicate_file == TRUE)
3088 free(block_list);
plougher29e37092007-04-15 01:24:51 +00003089
plougher018d2b32007-04-23 03:01:48 +00003090 return 0;
plougher5507dd92006-11-06 00:43:10 +00003091
3092read_err:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003093 dec_progress_bar(block);
plougher018d2b32007-04-23 03:01:48 +00003094 status = read_buffer->error;
plougher1b899fc2008-08-07 01:24:06 +00003095 bytes = start;
3096 if(thresh && !block_device) {
plougher12a159a2009-03-03 11:06:34 +00003097 int res;
3098
plougher5507dd92006-11-06 00:43:10 +00003099 queue_put(to_writer, NULL);
3100 if(queue_get(from_writer) != 0)
3101 EXIT_MKSQUASHFS();
plougher12a159a2009-03-03 11:06:34 +00003102 res = ftruncate(fd, bytes);
3103 if(res != 0)
3104 BAD_ERROR("Failed to truncate dest file because %s\n",
3105 strerror(errno));
plougher5507dd92006-11-06 00:43:10 +00003106 }
plougher2ea89142008-03-11 01:34:19 +00003107 unlock_fragments();
plougher5507dd92006-11-06 00:43:10 +00003108 for(blocks = thresh; blocks < block; blocks ++)
plougher1b899fc2008-08-07 01:24:06 +00003109 cache_block_put(buffer_list[blocks]);
plougher5507dd92006-11-06 00:43:10 +00003110 free(buffer_list);
3111 free(block_list);
ploughereb6eac92008-02-26 01:50:48 +00003112 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003113 return status;
plougher5507dd92006-11-06 00:43:10 +00003114}
3115
3116
plougher110799c2009-03-30 01:50:40 +00003117void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
3118 int *duplicate_file)
plougher5507dd92006-11-06 00:43:10 +00003119{
plougher018d2b32007-04-23 03:01:48 +00003120 int status;
3121 struct file_buffer *read_buffer;
3122 long long read_size;
plougher5507dd92006-11-06 00:43:10 +00003123
plougher018d2b32007-04-23 03:01:48 +00003124again:
3125 read_buffer = get_file_buffer(from_deflate);
plougher1b899fc2008-08-07 01:24:06 +00003126
plougher23377982007-11-12 04:04:48 +00003127 status = read_buffer->error;
3128 if(status) {
ploughereb6eac92008-02-26 01:50:48 +00003129 cache_block_put(read_buffer);
plougher018d2b32007-04-23 03:01:48 +00003130 goto file_err;
3131 }
3132
3133 read_size = read_buffer->file_size;
plougher5507dd92006-11-06 00:43:10 +00003134
plougher00d08172009-09-03 10:17:44 +00003135 if(read_size == -1)
3136 status = write_file_process(inode, dir_ent, read_buffer,
3137 duplicate_file);
3138 else if(read_size == 0) {
plougher29e37092007-04-15 01:24:51 +00003139 write_file_empty(inode, dir_ent, duplicate_file);
ploughereb6eac92008-02-26 01:50:48 +00003140 cache_block_put(read_buffer);
plougher1b899fc2008-08-07 01:24:06 +00003141 } else if(read_buffer->fragment && read_buffer->c_byte)
plougher110799c2009-03-30 01:50:40 +00003142 write_file_frag(inode, dir_ent, read_size, read_buffer,
3143 duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003144 else if(pre_duplicate(read_size))
plougher110799c2009-03-30 01:50:40 +00003145 status = write_file_blocks_dup(inode, dir_ent, read_size,
3146 read_buffer, duplicate_file);
plougher29e37092007-04-15 01:24:51 +00003147 else
plougher50b31762009-03-31 04:14:46 +00003148 status = write_file_blocks(inode, dir_ent, read_size,
3149 read_buffer, duplicate_file);
plougher5507dd92006-11-06 00:43:10 +00003150
plougher018d2b32007-04-23 03:01:48 +00003151file_err:
3152 if(status == 2) {
plougher50b31762009-03-31 04:14:46 +00003153 ERROR("File %s changed size while reading filesystem, "
Phillip Lougher494479f2012-02-03 15:45:41 +00003154 "attempting to re-read\n", pathname(dir_ent));
plougher018d2b32007-04-23 03:01:48 +00003155 goto again;
3156 } else if(status == 1) {
plougher110799c2009-03-30 01:50:40 +00003157 ERROR("Failed to read file %s, creating empty file\n",
Phillip Lougher494479f2012-02-03 15:45:41 +00003158 pathname(dir_ent));
plougher29e37092007-04-15 01:24:51 +00003159 write_file_empty(inode, dir_ent, duplicate_file);
3160 }
plougher5507dd92006-11-06 00:43:10 +00003161}
3162
3163
plougher44d54ef2010-02-08 22:13:49 +00003164#define BUFF_SIZE 8192
3165char b_buffer[BUFF_SIZE];
plougher1f413c82005-11-18 00:02:14 +00003166char *name;
3167char *basename_r();
3168
3169char *getbase(char *pathname)
3170{
3171 char *result;
3172
3173 if(*pathname != '/') {
plougher44d54ef2010-02-08 22:13:49 +00003174 result = getcwd(b_buffer, BUFF_SIZE);
3175 if(result == NULL)
3176 return NULL;
3177 strcat(strcat(b_buffer, "/"), pathname);
plougher1f413c82005-11-18 00:02:14 +00003178 } else
3179 strcpy(b_buffer, pathname);
3180 name = b_buffer;
3181 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3182 return NULL;
3183 else
3184 return result;
3185}
3186
3187
3188char *basename_r()
3189{
3190 char *s;
3191 char *p;
3192 int n = 1;
3193
3194 for(;;) {
3195 s = name;
3196 if(*name == '\0')
3197 return NULL;
3198 if(*name != '/') {
3199 while(*name != '\0' && *name != '/') name++;
3200 n = name - s;
3201 }
3202 while(*name == '/') name++;
3203 if(strncmp(s, ".", n) == 0)
3204 continue;
plougher110799c2009-03-30 01:50:40 +00003205 if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3206 ((p = basename_r()) == NULL)) {
plougher1f413c82005-11-18 00:02:14 +00003207 s[n] = '\0';
3208 return s;
3209 }
3210 if(strcmp(p, "..") == 0)
3211 continue;
3212 return p;
3213 }
3214}
3215
3216
Phillip Lougher81204c22012-07-25 03:30:30 +01003217struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
plougher1f413c82005-11-18 00:02:14 +00003218{
Phillip Lougherd6577802012-10-04 19:14:33 +01003219 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3220 struct inode_info *inode;
plougher1f413c82005-11-18 00:02:14 +00003221
Phillip Lougherd6577802012-10-04 19:14:33 +01003222 /*
3223 * Look-up inode in hash table, if it already exists we have a
3224 * hard-link, so increment the nlink count and return it.
3225 * Don't do the look-up for directories because we don't hard-link
3226 * directories.
3227 */
3228 if ((buf->st_mode & S_IFMT) != S_IFDIR) {
3229 for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
3230 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3231 inode->nlink ++;
3232 return inode;
3233 }
plougher1f413c82005-11-18 00:02:14 +00003234 }
plougher1f413c82005-11-18 00:02:14 +00003235 }
3236
plougher288f6852010-12-16 05:22:55 +00003237 inode = malloc(sizeof(struct inode_info));
3238 if(inode == NULL)
plougher50b31762009-03-31 04:14:46 +00003239 BAD_ERROR("Out of memory in inode hash table entry allocation"
3240 "\n");
plougher1f413c82005-11-18 00:02:14 +00003241
3242 memcpy(&inode->buf, buf, sizeof(struct stat));
plougher5507dd92006-11-06 00:43:10 +00003243 inode->read = FALSE;
ploughera326c182009-08-29 05:41:45 +00003244 inode->root_entry = FALSE;
Phillip Lougher81204c22012-07-25 03:30:30 +01003245 inode->pseudo_file = pseudo;
3246 inode->pseudo_id = id;
plougher1f413c82005-11-18 00:02:14 +00003247 inode->inode = SQUASHFS_INVALID_BLK;
3248 inode->nlink = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003249 inode->inode_number = 0;
plougherdc86c3c2007-12-05 02:15:10 +00003250
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003251 /*
3252 * Copy filesystem wide defaults into inode, these filesystem
3253 * wide defaults may be altered on an individual inode basis by
3254 * user specified actions
3255 *
3256 */
3257 inode->no_fragments = no_fragments;
3258 inode->always_use_fragments = always_use_fragments;
Phillip Lougher63f531f2011-09-10 04:03:32 +01003259 inode->noD = noD;
3260 inode->noF = noF;
Phillip Lougher9b6e3412011-09-05 02:58:41 +01003261
plougherdc86c3c2007-12-05 02:15:10 +00003262 if((buf->st_mode & S_IFMT) == S_IFREG)
Phillip Lougher3b89ee82012-10-18 23:55:37 +01003263 progress_bar_size((buf->st_size + block_size - 1) >> block_log);
plougherdc86c3c2007-12-05 02:15:10 +00003264
Phillip Lougherd6577802012-10-04 19:14:33 +01003265 inode->next = inode_info[ino_hash];
3266 inode_info[ino_hash] = inode;
plougher1f413c82005-11-18 00:02:14 +00003267
3268 return inode;
3269}
3270
3271
Phillip Lougher81204c22012-07-25 03:30:30 +01003272inline struct inode_info *lookup_inode(struct stat *buf)
3273{
3274 return lookup_inode2(buf, 0, 0);
3275}
3276
3277
Phillip Lougher539c2b12012-07-30 20:14:52 +01003278inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3279{
3280 if (inode->inode_number == 0)
3281 inode->inode_number = use_this ? : inode_no ++;
3282}
3283
3284
Phillip Lougher494479f2012-02-03 15:45:41 +00003285inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3286 char *nonstandard_pathname, struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003287{
Phillip Lougher494479f2012-02-03 15:45:41 +00003288 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3289 if(dir_ent == NULL)
3290 BAD_ERROR("Out of memory in linux_opendir\n");
3291
3292 dir_ent->name = name;
3293 dir_ent->source_name = source_name;
3294 dir_ent->nonstandard_pathname = nonstandard_pathname;
3295 dir_ent->our_dir = dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003296 dir_ent->next = NULL;
Phillip Lougher494479f2012-02-03 15:45:41 +00003297
3298 return dir_ent;
3299}
3300
3301
3302inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3303 struct inode_info *inode_info)
3304{
3305 struct dir_info *dir = dir_ent->our_dir;
3306
plougher1f413c82005-11-18 00:02:14 +00003307 if(sub_dir)
Phillip Lougher494479f2012-02-03 15:45:41 +00003308 sub_dir->dir_ent = dir_ent;
3309 dir_ent->inode = inode_info;
3310 dir_ent->dir = sub_dir;
3311
Phillip Lougherbf338362012-08-22 05:24:36 +01003312 dir_ent->next = dir->list;
3313 dir->list = dir_ent;
3314 dir->count++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003315}
3316
3317
3318inline void add_dir_entry2(char *name, char *source_name,
3319 char *nonstandard_pathname, struct dir_info *sub_dir,
3320 struct inode_info *inode_info, struct dir_info *dir)
3321{
3322 struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3323 nonstandard_pathname, dir);
3324
3325
3326 add_dir_entry(dir_ent, sub_dir, inode_info);
plougher1f413c82005-11-18 00:02:14 +00003327}
3328
3329
Phillip Lougher10a4b572012-02-18 23:26:10 +00003330inline void free_dir_entry(struct dir_ent *dir_ent)
3331{
Phillip Loughereb92b192012-10-01 03:39:00 +01003332 if(dir_ent->name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003333 free(dir_ent->name);
3334
Phillip Loughereb92b192012-10-01 03:39:00 +01003335 if(dir_ent->source_name)
Phillip Lougher10a4b572012-02-18 23:26:10 +00003336 free(dir_ent->source_name);
3337
3338 free(dir_ent);
3339}
3340
3341
Phillip Lougherad0f9212011-12-31 00:55:51 +00003342inline void add_excluded(struct dir_info *dir)
3343{
3344 dir->excluded ++;
3345}
3346
3347
plougher1f413c82005-11-18 00:02:14 +00003348
Phillip Lougherabc3b492012-07-29 02:53:35 +01003349void dir_scan(squashfs_inode *inode, char *pathname,
3350 struct dir_ent *(_readdir)(struct dir_info *))
3351{
3352 struct stat buf;
3353 struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
3354 struct dir_ent *dir_ent;
3355
3356 if(dir_info == NULL)
3357 return;
3358
Phillip Lougher24eeb772012-10-13 01:56:24 +01003359 dir_scan2(dir_info, pseudo);
Phillip Lougher23d83622012-10-14 02:35:22 +01003360 dir_scan3(dir_info, dir_info);
3361 do_move_actions();
3362 dir_scan4(dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003363
Phillip Lougherd0fe1d52012-10-09 03:34:34 +01003364 dir_ent = create_dir_entry("", NULL, pathname,
Phillip Lougher1eae83d2012-09-26 02:12:45 +01003365 scan1_opendir("", "", 0));
Phillip Lougherabc3b492012-07-29 02:53:35 +01003366
3367 if(pathname[0] == '\0') {
3368 /*
3369 * dummy top level directory, if multiple sources specified on
3370 * command line
3371 */
3372 memset(&buf, 0, sizeof(buf));
3373 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3374 buf.st_uid = getuid();
3375 buf.st_gid = getgid();
3376 buf.st_mtime = time(NULL);
3377 buf.st_dev = 0;
3378 buf.st_ino = 0;
3379 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3380 } else {
3381 if(lstat(pathname, &buf) == -1) {
3382 ERROR("Cannot stat dir/file %s because %s, ignoring",
3383 pathname, strerror(errno));
3384 return;
3385 }
3386 dir_ent->inode = lookup_inode(&buf);
3387 }
3388
Phillip Lougher539c2b12012-07-30 20:14:52 +01003389 alloc_inode_no(dir_ent->inode, root_inode_number);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003390 dir_ent->dir = dir_info;
3391 dir_info->dir_ent = dir_ent;
3392
Andy Lutomirski3f31dcf2012-09-21 18:08:08 -07003393 eval_actions(dir_ent);
3394
Phillip Lougherabc3b492012-07-29 02:53:35 +01003395 if(sorted) {
3396 int res = generate_file_priorities(dir_info, 0,
3397 &dir_info->dir_ent->inode->buf);
3398
3399 if(res == FALSE)
3400 BAD_ERROR("generate_file_priorities failed\n");
3401 }
3402 queue_put(to_reader, dir_info);
3403 if(sorted)
3404 sort_files_and_write(dir_info);
3405 if(progress)
3406 enable_progress_bar();
Phillip Lougher23d83622012-10-14 02:35:22 +01003407 dir_scan5(inode, dir_info);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003408 dir_ent->inode->inode = *inode;
3409 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
plougher1f413c82005-11-18 00:02:14 +00003410}
3411
3412
Phillip Lougherabc3b492012-07-29 02:53:35 +01003413/*
3414 * dir_scan1 routines...
3415 * This scans the source directories into memory for processing
3416 */
Phillip Lougherb38c1722012-02-09 23:26:19 +00003417struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
plougher1f413c82005-11-18 00:02:14 +00003418{
plougher1f413c82005-11-18 00:02:14 +00003419 struct dir_info *dir;
3420
plougher6da792b2010-12-16 05:25:39 +00003421 dir = malloc(sizeof(struct dir_info));
3422 if(dir == NULL)
plougherfbfdda72010-07-21 01:09:14 +00003423 BAD_ERROR("Out of memory in scan1_opendir\n");
plougher1f413c82005-11-18 00:02:14 +00003424
3425 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
3426 free(dir);
3427 return NULL;
3428 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003429 dir->pathname = pathname;
Phillip Lougherb38c1722012-02-09 23:26:19 +00003430 dir->subpath = subpath;
Phillip Lougherded70fa2011-12-25 02:14:58 +00003431 dir->count = 0;
3432 dir->directory_count = 0;
plougher1f413c82005-11-18 00:02:14 +00003433 dir->dir_is_ldir = TRUE;
3434 dir->list = NULL;
Phillip Lougher0b5a1242011-12-25 03:22:42 +00003435 dir->depth = depth;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003436 dir->excluded = 0;
plougher1f413c82005-11-18 00:02:14 +00003437
3438 return dir;
3439}
3440
3441
Phillip Lougher494479f2012-02-03 15:45:41 +00003442struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003443{
plougher1f413c82005-11-18 00:02:14 +00003444 static int index = 0;
3445
plougher11266ba2010-12-16 05:34:30 +00003446 if(dir->count < old_root_entries) {
3447 int i;
3448
plougher1f413c82005-11-18 00:02:14 +00003449 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003450 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003451 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003452 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003453 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003454 }
plougher11266ba2010-12-16 05:34:30 +00003455 }
plougher1f413c82005-11-18 00:02:14 +00003456
3457 while(index < source) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003458 char *basename = NULL;
3459 char *dir_name = getbase(source_path[index]);
Phillip Lougherbf338362012-08-22 05:24:36 +01003460 int pass = 1, res;
plougher89fe2c72010-12-16 05:31:34 +00003461
Phillip Lougherc73ed322012-10-01 03:25:41 +01003462 if(dir_name == NULL) {
plougher110799c2009-03-30 01:50:40 +00003463 ERROR("Bad source directory %s - skipping ...\n",
3464 source_path[index]);
plougher1f413c82005-11-18 00:02:14 +00003465 index ++;
3466 continue;
3467 }
Phillip Lougherc73ed322012-10-01 03:25:41 +01003468 dir_name = strdup(dir_name);
plougher1f413c82005-11-18 00:02:14 +00003469 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003470 struct dir_ent *dir_ent = dir->list;
3471
3472 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3473 dir_ent = dir_ent->next);
3474 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003475 break;
plougher50b31762009-03-31 04:14:46 +00003476 ERROR("Source directory entry %s already used! - trying"
3477 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003478 if(pass == 1)
3479 basename = dir_name;
3480 else
Phillip Lougherb38c1722012-02-09 23:26:19 +00003481 free(dir_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003482 res = asprintf(&dir_name, "%s_%d", basename, pass++);
3483 if(res == -1)
3484 BAD_ERROR("asprintf failed in "
3485 "scan1_encomp_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003486 ERROR("%s\n", dir_name);
3487 }
Phillip Lougherb38c1722012-02-09 23:26:19 +00003488 return create_dir_entry(dir_name, basename,
3489 source_path[index ++], dir);
plougher1f413c82005-11-18 00:02:14 +00003490 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003491 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003492}
3493
3494
Phillip Lougher494479f2012-02-03 15:45:41 +00003495struct dir_ent *scan1_single_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003496{
3497 struct dirent *d_name;
plougher4925e172010-12-16 05:45:54 +00003498 int i;
plougher1f413c82005-11-18 00:02:14 +00003499
plougher4925e172010-12-16 05:45:54 +00003500 if(dir->count < old_root_entries) {
plougher1f413c82005-11-18 00:02:14 +00003501 for(i = 0; i < old_root_entries; i++) {
ploughera326c182009-08-29 05:41:45 +00003502 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
plougher1f413c82005-11-18 00:02:14 +00003503 dir->directory_count ++;
Phillip Lougher494479f2012-02-03 15:45:41 +00003504 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
ploughera326c182009-08-29 05:41:45 +00003505 &old_root_entry[i].inode, dir);
plougher1f413c82005-11-18 00:02:14 +00003506 }
plougher4925e172010-12-16 05:45:54 +00003507 }
plougher1f413c82005-11-18 00:02:14 +00003508
3509 if((d_name = readdir(dir->linuxdir)) != NULL) {
Phillip Lougherc73ed322012-10-01 03:25:41 +01003510 char *basename = NULL;
3511 char *dir_name = strdup(d_name->d_name);
Phillip Lougher494479f2012-02-03 15:45:41 +00003512 int pass = 1, res;
plougher4925e172010-12-16 05:45:54 +00003513
plougher1f413c82005-11-18 00:02:14 +00003514 for(;;) {
Phillip Lougherbf338362012-08-22 05:24:36 +01003515 struct dir_ent *dir_ent = dir->list;
3516
3517 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3518 dir_ent = dir_ent->next);
3519 if(dir_ent == NULL)
plougher1f413c82005-11-18 00:02:14 +00003520 break;
plougher50b31762009-03-31 04:14:46 +00003521 ERROR("Source directory entry %s already used! - trying"
3522 " ", dir_name);
Phillip Lougherc73ed322012-10-01 03:25:41 +01003523 if (pass == 1)
3524 basename = dir_name;
3525 else
Phillip Lougher494479f2012-02-03 15:45:41 +00003526 free(dir_name);
3527 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3528 if(res == -1)
3529 BAD_ERROR("asprintf failed in "
3530 "scan1_single_readdir\n");
plougher1f413c82005-11-18 00:02:14 +00003531 ERROR("%s\n", dir_name);
3532 }
Phillip Lougher494479f2012-02-03 15:45:41 +00003533 return create_dir_entry(dir_name, basename, NULL, dir);
plougher1f413c82005-11-18 00:02:14 +00003534 }
3535
Phillip Lougher494479f2012-02-03 15:45:41 +00003536 return NULL;
plougher1f413c82005-11-18 00:02:14 +00003537}
3538
3539
Phillip Lougher494479f2012-02-03 15:45:41 +00003540struct dir_ent *scan1_readdir(struct dir_info *dir)
plougher1f413c82005-11-18 00:02:14 +00003541{
plougher480d9bf2010-12-18 02:28:39 +00003542 struct dirent *d_name = readdir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003543
Phillip Lougher494479f2012-02-03 15:45:41 +00003544 return d_name ?
3545 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3546 NULL;
plougher1f413c82005-11-18 00:02:14 +00003547}
3548
3549
plougher1f413c82005-11-18 00:02:14 +00003550void scan1_freedir(struct dir_info *dir)
3551{
plougherfbed12b2006-02-07 12:45:53 +00003552 if(dir->pathname[0] != '\0')
3553 closedir(dir->linuxdir);
plougher1f413c82005-11-18 00:02:14 +00003554}
3555
3556
Phillip Lougherb38c1722012-02-09 23:26:19 +00003557struct dir_info *dir_scan1(char *filename, char *subpath,
3558 struct pathnames *paths,
Phillip Lougher494479f2012-02-03 15:45:41 +00003559 struct dir_ent *(_readdir)(struct dir_info *), int depth)
plougher1f413c82005-11-18 00:02:14 +00003560{
Phillip Lougherb38c1722012-02-09 23:26:19 +00003561 struct dir_info *dir = scan1_opendir(filename, subpath, depth);
Phillip Lougher494479f2012-02-03 15:45:41 +00003562 struct dir_ent *dir_ent;
plougher1f413c82005-11-18 00:02:14 +00003563
plougher360b6e42010-12-18 02:40:28 +00003564 if(dir == NULL) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003565 ERROR("Could not open %s, skipping...\n", filename);
plougher1f413c82005-11-18 00:02:14 +00003566 goto error;
3567 }
3568
Phillip Lougher494479f2012-02-03 15:45:41 +00003569 while((dir_ent = _readdir(dir))) {
plougher360b6e42010-12-18 02:40:28 +00003570 struct dir_info *sub_dir;
3571 struct stat buf;
3572 struct pathnames *new;
Phillip Lougher494479f2012-02-03 15:45:41 +00003573 char *filename = pathname(dir_ent);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003574 char *subpath = subpathname(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003575 char *dir_name = dir_ent->name;
plougher1f413c82005-11-18 00:02:14 +00003576
Phillip Lougher494479f2012-02-03 15:45:41 +00003577 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003578 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003579 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003580 }
plougher1f413c82005-11-18 00:02:14 +00003581
3582 if(lstat(filename, &buf) == -1) {
plougher110799c2009-03-30 01:50:40 +00003583 ERROR("Cannot stat dir/file %s because %s, ignoring",
3584 filename, strerror(errno));
Phillip Lougher10a4b572012-02-18 23:26:10 +00003585 free_dir_entry(dir_ent);
plougher1f413c82005-11-18 00:02:14 +00003586 continue;
3587 }
plougher29e37092007-04-15 01:24:51 +00003588
3589 if((buf.st_mode & S_IFMT) != S_IFREG &&
3590 (buf.st_mode & S_IFMT) != S_IFDIR &&
3591 (buf.st_mode & S_IFMT) != S_IFLNK &&
3592 (buf.st_mode & S_IFMT) != S_IFCHR &&
3593 (buf.st_mode & S_IFMT) != S_IFBLK &&
3594 (buf.st_mode & S_IFMT) != S_IFIFO &&
3595 (buf.st_mode & S_IFMT) != S_IFSOCK) {
plougher50b31762009-03-31 04:14:46 +00003596 ERROR("File %s has unrecognised filetype %d, ignoring"
3597 "\n", filename, buf.st_mode & S_IFMT);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003598 free_dir_entry(dir_ent);
plougher29e37092007-04-15 01:24:51 +00003599 continue;
3600 }
3601
Phillip Lougherad0f9212011-12-31 00:55:51 +00003602 if((old_exclude && old_excluded(filename, &buf)) ||
3603 excluded(paths, dir_name, &new) ||
Phillip Lougherb4f4b0d2012-02-20 02:30:26 +00003604 eval_exclude_actions(dir_name, filename, subpath,
3605 &buf, depth)) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003606 add_excluded(dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003607 free_dir_entry(dir_ent);
Phillip Lougher10d8de02011-08-29 00:14:48 +01003608 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003609 }
plougher1f413c82005-11-18 00:02:14 +00003610
3611 if((buf.st_mode & S_IFMT) == S_IFDIR) {
Phillip Lougher494479f2012-02-03 15:45:41 +00003612 filename = strdup(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003613 subpath = strdup(subpath);
3614 sub_dir = dir_scan1(filename, subpath, new,
3615 scan1_readdir, depth + 1);
Phillip Lougher494479f2012-02-03 15:45:41 +00003616 if(sub_dir == NULL) {
Phillip Lougher10a4b572012-02-18 23:26:10 +00003617 free_dir_entry(dir_ent);
Phillip Lougher494479f2012-02-03 15:45:41 +00003618 free(filename);
Phillip Lougherb38c1722012-02-09 23:26:19 +00003619 free(subpath);
plougher1f413c82005-11-18 00:02:14 +00003620 continue;
Phillip Lougher494479f2012-02-03 15:45:41 +00003621 }
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003622
Phillip Lougherb4f4b0d2012-02-20 02:30:26 +00003623 if(eval_empty_actions(dir_name, filename, subpath, &buf,
3624 depth, sub_dir)) {
Phillip Lougherad0f9212011-12-31 00:55:51 +00003625 add_excluded(dir);
Phillip Lougherb2e9a402012-02-19 00:20:22 +00003626 free(sub_dir);
Phillip Lougher10a4b572012-02-18 23:26:10 +00003627 free_dir_entry(dir_ent);
Phillip Lougherb2e9a402012-02-19 00:20:22 +00003628 free(filename);
3629 free(subpath);
Phillip Lougher6a78a2d2011-12-28 03:54:19 +00003630 continue;
Phillip Lougherad0f9212011-12-31 00:55:51 +00003631 }
3632
plougher1f413c82005-11-18 00:02:14 +00003633 dir->directory_count ++;
3634 } else
3635 sub_dir = NULL;
3636
Phillip Lougher494479f2012-02-03 15:45:41 +00003637 add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
plougher1f413c82005-11-18 00:02:14 +00003638 }
3639
3640 scan1_freedir(dir);
plougher1f413c82005-11-18 00:02:14 +00003641
3642error:
3643 return dir;
3644}
3645
plougher2ea89142008-03-11 01:34:19 +00003646
Phillip Lougherabc3b492012-07-29 02:53:35 +01003647/*
3648 * dir_scan2 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003649 * This processes most actions and any pseudo files
Phillip Lougherabc3b492012-07-29 02:53:35 +01003650 */
Phillip Lougherbf338362012-08-22 05:24:36 +01003651struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003652{
Phillip Lougherbf338362012-08-22 05:24:36 +01003653 if (dir_ent == NULL)
3654 dir_ent = dir->list;
3655 else
3656 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003657
Phillip Lougherbf338362012-08-22 05:24:36 +01003658 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3659
3660 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003661}
3662
3663
3664struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3665{
Phillip Lougherbf338362012-08-22 05:24:36 +01003666 struct dir_ent *dir_ent = dir->list;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003667
Phillip Lougherbf338362012-08-22 05:24:36 +01003668 for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3669 dir_ent = dir_ent->next);
Phillip Lougherabc3b492012-07-29 02:53:35 +01003670
Phillip Lougherbf338362012-08-22 05:24:36 +01003671 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003672}
3673
3674
Phillip Lougher24eeb772012-10-13 01:56:24 +01003675void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
plougher43244f22009-04-05 02:04:51 +00003676{
Phillip Lougherbf338362012-08-22 05:24:36 +01003677 struct dir_ent *dir_ent = NULL;
plougher43244f22009-04-05 02:04:51 +00003678 struct pseudo_entry *pseudo_ent;
3679 struct stat buf;
plougher82ab2332009-04-21 00:21:21 +00003680 static int pseudo_ino = 1;
plougher43244f22009-04-05 02:04:51 +00003681
Phillip Lougherbf338362012-08-22 05:24:36 +01003682 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
plougher43244f22009-04-05 02:04:51 +00003683 struct inode_info *inode_info = dir_ent->inode;
3684 struct stat *buf = &inode_info->buf;
3685 char *name = dir_ent->name;
3686
Phillip Lougher89d757c2011-09-20 00:33:19 +01003687 eval_actions(dir_ent);
3688
plougher43244f22009-04-05 02:04:51 +00003689 if((buf->st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher24eeb772012-10-13 01:56:24 +01003690 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
plougher43244f22009-04-05 02:04:51 +00003691 }
3692
3693 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3694 dir_ent = scan2_lookup(dir, pseudo_ent->name);
plougherdcd66c52010-09-17 03:44:17 +00003695 if(pseudo_ent->dev->type == 'm') {
plougherb34f9f62009-04-26 02:08:42 +00003696 struct stat *buf;
3697 if(dir_ent == NULL) {
plougherdcd66c52010-09-17 03:44:17 +00003698 ERROR("Pseudo modify file \"%s\" does not exist "
plougherf0dc2382010-05-01 23:55:06 +00003699 "in source filesystem. Ignoring.\n",
plougherb34f9f62009-04-26 02:08:42 +00003700 pseudo_ent->pathname);
3701 continue;
3702 }
ploughera326c182009-08-29 05:41:45 +00003703 if(dir_ent->inode->root_entry) {
plougherdcd66c52010-09-17 03:44:17 +00003704 ERROR("Pseudo modify file \"%s\" is a pre-existing"
plougherb34f9f62009-04-26 02:08:42 +00003705 " file in the filesystem being appended"
3706 " to. It cannot be modified. "
plougherf0dc2382010-05-01 23:55:06 +00003707 "Ignoring.\n", pseudo_ent->pathname);
plougherb34f9f62009-04-26 02:08:42 +00003708 continue;
3709 }
3710 buf = &dir_ent->inode->buf;
3711 buf->st_mode = (buf->st_mode & S_IFMT) |
3712 pseudo_ent->dev->mode;
3713 buf->st_uid = pseudo_ent->dev->uid;
3714 buf->st_gid = pseudo_ent->dev->gid;
3715 continue;
3716 }
3717
plougher43244f22009-04-05 02:04:51 +00003718 if(dir_ent) {
plougherf0dc2382010-05-01 23:55:06 +00003719 if(dir_ent->inode->root_entry)
3720 ERROR("Pseudo file \"%s\" is a pre-existing"
3721 " file in the filesystem being appended"
3722 " to. Ignoring.\n",
3723 pseudo_ent->pathname);
3724 else
3725 ERROR("Pseudo file \"%s\" exists in source "
plougherdcd66c52010-09-17 03:44:17 +00003726 "filesystem \"%s\".\nIgnoring, "
plougherf0dc2382010-05-01 23:55:06 +00003727 "exclude it (-e/-ef) to override.\n",
3728 pseudo_ent->pathname,
Phillip Lougher494479f2012-02-03 15:45:41 +00003729 pathname(dir_ent));
plougher43244f22009-04-05 02:04:51 +00003730 continue;
3731 }
3732
plougher43244f22009-04-05 02:04:51 +00003733 memset(&buf, 0, sizeof(buf));
3734 buf.st_mode = pseudo_ent->dev->mode;
3735 buf.st_uid = pseudo_ent->dev->uid;
3736 buf.st_gid = pseudo_ent->dev->gid;
3737 buf.st_rdev = makedev(pseudo_ent->dev->major,
3738 pseudo_ent->dev->minor);
plougher7e58f4d2009-04-05 12:06:19 +00003739 buf.st_mtime = time(NULL);
plougher1a3fbf22009-04-05 12:04:16 +00003740 buf.st_ino = pseudo_ino ++;
plougher43244f22009-04-05 02:04:51 +00003741
Phillip Lougher5d579292012-10-13 01:37:16 +01003742 if(pseudo_ent->dev->type == 'd') {
3743 struct dir_ent *dir_ent =
3744 create_dir_entry(pseudo_ent->name, NULL,
3745 pseudo_ent->pathname, dir);
3746 char *subpath = strdup(subpathname(dir_ent));
3747 struct dir_info *sub_dir = scan1_opendir("", subpath,
Phillip Lougher24eeb772012-10-13 01:56:24 +01003748 dir->depth + 1);
Phillip Lougher5d579292012-10-13 01:37:16 +01003749 if(sub_dir == NULL) {
3750 ERROR("Could not create pseudo directory \"%s\""
3751 ", skipping...\n",
3752 pseudo_ent->pathname);
3753 free(subpath);
3754 pseudo_ino --;
3755 continue;
3756 }
Phillip Lougher24eeb772012-10-13 01:56:24 +01003757 dir_scan2(sub_dir, pseudo_ent->pseudo);
Phillip Lougher5d579292012-10-13 01:37:16 +01003758 dir->directory_count ++;
3759 add_dir_entry(dir_ent, sub_dir,
3760 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3761 } else if(pseudo_ent->dev->type == 'f') {
plougher00d08172009-09-03 10:17:44 +00003762#ifdef USE_TMP_FILE
plougher4ab7e512009-05-05 02:35:58 +00003763 struct stat buf2;
3764 int res = stat(pseudo_ent->dev->filename, &buf2);
3765 if(res == -1) {
3766 ERROR("Stat on pseudo file \"%s\" failed, "
3767 "skipping...", pseudo_ent->pathname);
Phillip Lougher5d579292012-10-13 01:37:16 +01003768 pseudo_ino --;
plougher4ab7e512009-05-05 02:35:58 +00003769 continue;
3770 }
3771 buf.st_size = buf2.st_size;
Phillip Lougher494479f2012-02-03 15:45:41 +00003772 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003773 pseudo_ent->dev->filename, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003774 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougher00d08172009-09-03 10:17:44 +00003775#else
Phillip Lougher494479f2012-02-03 15:45:41 +00003776 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003777 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003778 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3779 pseudo_ent->dev->pseudo_id), dir);
plougher00d08172009-09-03 10:17:44 +00003780#endif
plougherb85e9ad2010-05-02 01:46:12 +00003781 } else {
Phillip Lougher494479f2012-02-03 15:45:41 +00003782 add_dir_entry2(pseudo_ent->name, NULL,
Phillip Lougher5d579292012-10-13 01:37:16 +01003783 pseudo_ent->pathname, NULL,
Phillip Lougher81204c22012-07-25 03:30:30 +01003784 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
plougherb85e9ad2010-05-02 01:46:12 +00003785 }
plougher43244f22009-04-05 02:04:51 +00003786 }
plougher43244f22009-04-05 02:04:51 +00003787}
3788
3789
Phillip Lougherabc3b492012-07-29 02:53:35 +01003790/*
3791 * dir_scan3 routines...
Phillip Lougher23d83622012-10-14 02:35:22 +01003792 * This processes the move action
3793 */
3794void dir_scan3(struct dir_info *root, struct dir_info *dir)
3795{
3796 struct dir_ent *dir_ent = NULL;
3797
3798 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3799
3800 eval_move_actions(root, dir_ent);
3801
3802 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3803 dir_scan3(root, dir_ent->dir);
3804 }
3805}
3806/*
3807 * dir_scan4 routines...
Phillip Lougher539c2b12012-07-30 20:14:52 +01003808 * This sorts every directory and computes the inode numbers
3809 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003810
Phillip Lougher242242e2012-08-24 04:15:36 +01003811/*
3812 * Bottom up linked list merge sort.
3813 *
3814 * Qsort and other O(n log n) algorithms work well with arrays but not
3815 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand
3816 * is not ideal for arrays (as it needs an additonal n storage locations
3817 * as sorting is not done in place), but it is ideal for linked lists because
3818 * it doesn't require any extra storage,
3819 */
Phillip Lougher539c2b12012-07-30 20:14:52 +01003820void sort_directory(struct dir_info *dir)
3821{
Phillip Lougher242242e2012-08-24 04:15:36 +01003822 struct dir_ent *cur, *l1, *l2, *next;
3823 int len1, len2, stride = 1;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003824
Phillip Lougher242242e2012-08-24 04:15:36 +01003825 if(dir->count < 2)
Phillip Lougherbf338362012-08-22 05:24:36 +01003826 return;
3827
Phillip Lougher242242e2012-08-24 04:15:36 +01003828 /*
3829 * We can consider our linked-list to be made up of stride length
3830 * sublists. Eacn iteration around this loop merges adjacent
3831 * stride length sublists into larger 2*stride sublists. We stop
3832 * when stride becomes equal to the entire list.
3833 *
3834 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
3835 * these 1 element sublists are merged into 2 element sublists, which
3836 * are then merged into 4 element sublists and so on.
3837 */
3838 do {
3839 l2 = dir->list; /* head of current linked list */
3840 cur = NULL; /* empty output list */
Phillip Lougherbf338362012-08-22 05:24:36 +01003841
Phillip Lougher242242e2012-08-24 04:15:36 +01003842 /*
3843 * Iterate through the linked list, merging adjacent sublists.
3844 * On each interation l2 points to the next sublist pair to be
3845 * merged (if there's only one sublist left this is simply added
3846 * to the output list)
3847 */
3848 while(l2) {
3849 l1 = l2;
3850 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
3851 len2 = stride;
Phillip Lougherbf338362012-08-22 05:24:36 +01003852
Phillip Lougher242242e2012-08-24 04:15:36 +01003853 /*
3854 * l1 points to first sublist.
3855 * l2 points to second sublist.
3856 * Merge them onto the output list
3857 */
3858 while(len1 && l2 && len2) {
3859 if(strcmp(l1->name, l2->name) <= 0) {
3860 next = l1;
3861 l1 = l1->next;
3862 len1 --;
3863 } else {
3864 next = l2;
3865 l2 = l2->next;
3866 len2 --;
3867 }
3868
3869 if(cur) {
3870 cur->next = next;
3871 cur = next;
3872 } else
3873 dir->list = cur = next;
3874 }
3875 /*
3876 * One sublist is now empty, copy the other one onto the
3877 * output list
3878 */
3879 for(; len1; len1 --, l1 = l1->next) {
3880 if(cur) {
3881 cur->next = l1;
3882 cur = l1;
3883 } else
3884 dir->list = cur = l1;
3885 }
3886 for(; l2 && len2; len2 --, l2 = l2->next) {
3887 if(cur) {
3888 cur->next = l2;
3889 cur = l2;
3890 } else
3891 dir->list = cur = l2;
3892 }
3893 }
3894 cur->next = NULL;
3895 stride = stride << 1;
3896 } while(stride < dir->count);
Phillip Lougher539c2b12012-07-30 20:14:52 +01003897}
3898
3899
Phillip Lougher23d83622012-10-14 02:35:22 +01003900void dir_scan4(struct dir_info *dir)
Phillip Lougher539c2b12012-07-30 20:14:52 +01003901{
Phillip Lougher23d83622012-10-14 02:35:22 +01003902 struct dir_ent *dir_ent;
3903 unsigned int byte_count = 0;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003904
3905 sort_directory(dir);
3906
Phillip Lougher23d83622012-10-14 02:35:22 +01003907 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
3908 byte_count += strlen(dir_ent->name) +
3909 sizeof(struct squashfs_dir_entry);
3910
3911 if(dir_ent->inode->root_entry)
3912 continue;
3913
Phillip Lougher539c2b12012-07-30 20:14:52 +01003914 alloc_inode_no(dir_ent->inode, 0);
Phillip Lougher23d83622012-10-14 02:35:22 +01003915
Phillip Lougher539c2b12012-07-30 20:14:52 +01003916 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
Phillip Lougher23d83622012-10-14 02:35:22 +01003917 dir_scan4(dir_ent->dir);
Phillip Lougher539c2b12012-07-30 20:14:52 +01003918 }
Phillip Lougher23d83622012-10-14 02:35:22 +01003919
3920 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
3921 dir->dir_is_ldir = FALSE;
Phillip Lougher539c2b12012-07-30 20:14:52 +01003922}
3923
3924
3925/*
Phillip Lougher23d83622012-10-14 02:35:22 +01003926 * dir_scan5 routines...
Phillip Lougherabc3b492012-07-29 02:53:35 +01003927 * This generates the filesystem metadata and writes it out to the destination
3928 */
Phillip Lougher23d83622012-10-14 02:35:22 +01003929void scan5_init_dir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003930{
3931 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
3932 if(dir->buff == NULL) {
3933 BAD_ERROR("Out of memory allocating directory buffer\n");
3934 }
3935
3936 dir->size = SQUASHFS_METADATA_SIZE;
3937 dir->p = dir->index_count_p = dir->buff;
3938 dir->entry_count = 256;
3939 dir->entry_count_p = NULL;
3940 dir->index = NULL;
3941 dir->i_count = dir->i_size = 0;
3942}
3943
3944
Phillip Lougher23d83622012-10-14 02:35:22 +01003945struct dir_ent *scan5_readdir(struct directory *dir, struct dir_info *dir_info,
Phillip Lougherbf338362012-08-22 05:24:36 +01003946 struct dir_ent *dir_ent)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003947{
Phillip Lougherbf338362012-08-22 05:24:36 +01003948 if (dir_ent == NULL)
3949 dir_ent = dir_info->list;
3950 else
3951 dir_ent = dir_ent->next;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003952
Phillip Lougherbf338362012-08-22 05:24:36 +01003953 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
3954 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
3955 dir_ent->name, dir_ent->inode->type, dir);
3956
3957 return dir_ent;
Phillip Lougherabc3b492012-07-29 02:53:35 +01003958}
3959
3960
Phillip Lougher23d83622012-10-14 02:35:22 +01003961void scan5_freedir(struct directory *dir)
Phillip Lougherabc3b492012-07-29 02:53:35 +01003962{
3963 if(dir->index)
3964 free(dir->index);
3965 free(dir->buff);
3966}
3967
3968
Phillip Lougher23d83622012-10-14 02:35:22 +01003969void dir_scan5(squashfs_inode *inode, struct dir_info *dir_info)
plougher1f413c82005-11-18 00:02:14 +00003970{
3971 int squashfs_type;
plougher1f413c82005-11-18 00:02:14 +00003972 int duplicate_file;
plougher1f413c82005-11-18 00:02:14 +00003973 struct directory dir;
Phillip Lougherbf338362012-08-22 05:24:36 +01003974 struct dir_ent *dir_ent = NULL;
plougher1f413c82005-11-18 00:02:14 +00003975
Phillip Lougher23d83622012-10-14 02:35:22 +01003976 scan5_init_dir(&dir);
plougher1f413c82005-11-18 00:02:14 +00003977
Phillip Lougher23d83622012-10-14 02:35:22 +01003978 while((dir_ent = scan5_readdir(&dir, dir_info, dir_ent)) != NULL) {
Phillip Lougher0a670882012-10-05 04:09:13 +01003979 struct stat *buf = &dir_ent->inode->buf;
plougher1f413c82005-11-18 00:02:14 +00003980
3981 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
3982 switch(buf->st_mode & S_IFMT) {
3983 case S_IFREG:
3984 squashfs_type = SQUASHFS_FILE_TYPE;
plougher110799c2009-03-30 01:50:40 +00003985 write_file(inode, dir_ent,
3986 &duplicate_file);
3987 INFO("file %s, uncompressed size %lld "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01003988 "bytes %s\n",
3989 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00003990 (long long) buf->st_size,
3991 duplicate_file ? "DUPLICATE" :
3992 "");
plougher1f413c82005-11-18 00:02:14 +00003993 break;
3994
3995 case S_IFDIR:
3996 squashfs_type = SQUASHFS_DIR_TYPE;
Phillip Lougher23d83622012-10-14 02:35:22 +01003997 dir_scan5(inode, dir_ent->dir);
plougher1f413c82005-11-18 00:02:14 +00003998 break;
3999
4000 case S_IFLNK:
4001 squashfs_type = SQUASHFS_SYMLINK_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004002 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004003 squashfs_type, 0, 0, 0, NULL,
4004 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004005 INFO("symbolic link %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004006 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004007 sym_count ++;
4008 break;
4009
4010 case S_IFCHR:
4011 squashfs_type = SQUASHFS_CHRDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004012 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004013 squashfs_type, 0, 0, 0, NULL,
4014 NULL, NULL, 0);
4015 INFO("character device %s inode 0x%llx"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004016 "\n", subpathname(dir_ent),
4017 *inode);
plougher1f413c82005-11-18 00:02:14 +00004018 dev_count ++;
4019 break;
4020
4021 case S_IFBLK:
4022 squashfs_type = SQUASHFS_BLKDEV_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004023 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004024 squashfs_type, 0, 0, 0, NULL,
4025 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004026 INFO("block device %s inode 0x%llx\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004027 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004028 dev_count ++;
4029 break;
4030
4031 case S_IFIFO:
4032 squashfs_type = SQUASHFS_FIFO_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004033 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004034 squashfs_type, 0, 0, 0, NULL,
4035 NULL, NULL, 0);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004036 INFO("fifo %s inode 0x%llx\n",
4037 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004038 fifo_count ++;
4039 break;
4040
4041 case S_IFSOCK:
4042 squashfs_type = SQUASHFS_SOCKET_TYPE;
plougher3c6bdb52010-05-01 02:30:59 +00004043 create_inode(inode, NULL, dir_ent,
plougher50b31762009-03-31 04:14:46 +00004044 squashfs_type, 0, 0, 0, NULL,
4045 NULL, NULL, 0);
plougherb3604122009-03-30 02:07:20 +00004046 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004047 "0x%llx\n",
4048 subpathname(dir_ent), *inode);
plougher1f413c82005-11-18 00:02:14 +00004049 sock_count ++;
4050 break;
4051
plougher23377982007-11-12 04:04:48 +00004052 default:
plougherb3604122009-03-30 02:07:20 +00004053 BAD_ERROR("%s unrecognised file type, "
Phillip Lougher494479f2012-02-03 15:45:41 +00004054 "mode is %x\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004055 subpathname(dir_ent),
plougherb3604122009-03-30 02:07:20 +00004056 buf->st_mode);
plougher29e37092007-04-15 01:24:51 +00004057 }
4058 dir_ent->inode->inode = *inode;
plougher1f413c82005-11-18 00:02:14 +00004059 dir_ent->inode->type = squashfs_type;
4060 } else {
4061 *inode = dir_ent->inode->inode;
4062 squashfs_type = dir_ent->inode->type;
plougher04b0d5f2006-02-10 00:42:06 +00004063 switch(squashfs_type) {
4064 case SQUASHFS_FILE_TYPE:
4065 if(!sorted)
plougher50b31762009-03-31 04:14:46 +00004066 INFO("file %s, uncompressed "
4067 "size %lld bytes LINK"
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004068 "\n",
4069 subpathname(dir_ent),
plougher82ab2332009-04-21 00:21:21 +00004070 (long long)
plougher50b31762009-03-31 04:14:46 +00004071 buf->st_size);
plougher04b0d5f2006-02-10 00:42:06 +00004072 break;
4073 case SQUASHFS_SYMLINK_TYPE:
plougherb3604122009-03-30 02:07:20 +00004074 INFO("symbolic link %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004075 "LINK\n", subpathname(dir_ent),
4076 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004077 break;
4078 case SQUASHFS_CHRDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004079 INFO("character device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004080 "LINK\n", subpathname(dir_ent),
4081 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004082 break;
plougher5507dd92006-11-06 00:43:10 +00004083 case SQUASHFS_BLKDEV_TYPE:
plougherb3604122009-03-30 02:07:20 +00004084 INFO("block device %s inode 0x%llx "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004085 "LINK\n", subpathname(dir_ent),
4086 *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004087 break;
4088 case SQUASHFS_FIFO_TYPE:
plougherb3604122009-03-30 02:07:20 +00004089 INFO("fifo %s inode 0x%llx LINK\n",
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004090 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004091 break;
4092 case SQUASHFS_SOCKET_TYPE:
plougher50b31762009-03-31 04:14:46 +00004093 INFO("unix domain socket %s inode "
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004094 "0x%llx LINK\n",
4095 subpathname(dir_ent), *inode);
plougher04b0d5f2006-02-10 00:42:06 +00004096 break;
4097 }
plougher1f413c82005-11-18 00:02:14 +00004098 }
4099
Phillip Lougher0366aec2012-10-05 04:06:04 +01004100 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
4101 squashfs_type, &dir);
plougher35a10602008-04-21 02:58:16 +00004102 update_progress_bar();
plougher1f413c82005-11-18 00:02:14 +00004103 }
4104
plougher29e37092007-04-15 01:24:51 +00004105 write_dir(inode, dir_info, &dir);
Phillip Lougher4980d7f2012-10-05 03:47:12 +01004106 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
4107 *inode);
plougher1f413c82005-11-18 00:02:14 +00004108
Phillip Lougher23d83622012-10-14 02:35:22 +01004109 scan5_freedir(&dir);
plougher1f413c82005-11-18 00:02:14 +00004110}
4111
4112
4113unsigned int slog(unsigned int block)
4114{
4115 int i;
4116
plougher4c99cb72007-06-14 21:46:31 +00004117 for(i = 12; i <= 20; i++)
plougher1f413c82005-11-18 00:02:14 +00004118 if(block == (1 << i))
4119 return i;
4120 return 0;
4121}
4122
4123
plougher8f8e1a12007-10-18 02:50:21 +00004124int old_excluded(char *filename, struct stat *buf)
plougher1f413c82005-11-18 00:02:14 +00004125{
4126 int i;
4127
4128 for(i = 0; i < exclude; i++)
plougherb3604122009-03-30 02:07:20 +00004129 if((exclude_paths[i].st_dev == buf->st_dev) &&
4130 (exclude_paths[i].st_ino == buf->st_ino))
plougher1f413c82005-11-18 00:02:14 +00004131 return TRUE;
4132 return FALSE;
4133}
4134
4135
4136#define ADD_ENTRY(buf) \
plougher360514a2009-03-30 03:01:38 +00004137 if(exclude % EXCLUDE_SIZE == 0) { \
4138 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4139 * sizeof(struct exclude_info)); \
4140 if(exclude_paths == NULL) \
4141 BAD_ERROR("Out of memory in exclude dir/file table\n"); \
4142 } \
4143 exclude_paths[exclude].st_dev = buf.st_dev; \
plougher1f413c82005-11-18 00:02:14 +00004144 exclude_paths[exclude++].st_ino = buf.st_ino;
plougher8f8e1a12007-10-18 02:50:21 +00004145int old_add_exclude(char *path)
plougher1f413c82005-11-18 00:02:14 +00004146{
4147 int i;
plougher91fbb302008-05-06 02:29:36 +00004148 char filename[4096];
plougher1f413c82005-11-18 00:02:14 +00004149 struct stat buf;
4150
plougherb3604122009-03-30 02:07:20 +00004151 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4152 strncmp(path, "../", 3) == 0) {
plougher1f413c82005-11-18 00:02:14 +00004153 if(lstat(path, &buf) == -1) {
plougherb3604122009-03-30 02:07:20 +00004154 ERROR("Cannot stat exclude dir/file %s because %s, "
4155 "ignoring", path, strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004156 return TRUE;
4157 }
4158 ADD_ENTRY(buf);
4159 return TRUE;
4160 }
4161
4162 for(i = 0; i < source; i++) {
4163 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
4164 if(lstat(filename, &buf) == -1) {
plougher91fbb302008-05-06 02:29:36 +00004165 if(!(errno == ENOENT || errno == ENOTDIR))
plougherb3604122009-03-30 02:07:20 +00004166 ERROR("Cannot stat exclude dir/file %s because "
plougher50b31762009-03-31 04:14:46 +00004167 "%s, ignoring", filename,
4168 strerror(errno));
plougher1f413c82005-11-18 00:02:14 +00004169 continue;
4170 }
4171 ADD_ENTRY(buf);
4172 }
4173 return TRUE;
4174}
4175
4176
plougherb3604122009-03-30 02:07:20 +00004177void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4178 int type)
plougher1f413c82005-11-18 00:02:14 +00004179{
plougherb3604122009-03-30 02:07:20 +00004180 old_root_entry = realloc(old_root_entry,
4181 sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4182 if(old_root_entry == NULL)
plougher360514a2009-03-30 03:01:38 +00004183 BAD_ERROR("Out of memory in old root directory entries "
4184 "reallocation\n");
plougher1f413c82005-11-18 00:02:14 +00004185
ploughera326c182009-08-29 05:41:45 +00004186 old_root_entry[old_root_entries].name = strdup(name);
4187 old_root_entry[old_root_entries].inode.inode = inode;
4188 old_root_entry[old_root_entries].inode.inode_number = inode_number;
4189 old_root_entry[old_root_entries].inode.type = type;
4190 old_root_entry[old_root_entries++].inode.root_entry = TRUE;
plougher1f413c82005-11-18 00:02:14 +00004191}
4192
4193
plougher5741d792010-09-04 03:20:50 +00004194void initialise_threads(int readb_mbytes, int writeb_mbytes,
4195 int fragmentb_mbytes)
plougher5507dd92006-11-06 00:43:10 +00004196{
4197 int i;
4198 sigset_t sigmask, old_mask;
plougher5741d792010-09-04 03:20:50 +00004199 int reader_buffer_size = readb_mbytes << (20 - block_log);
4200 int fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
4201
4202 /*
4203 * writer_buffer_size is global because it is needed in
4204 * write_file_blocks_dup()
4205 */
4206 writer_buffer_size = writeb_mbytes << (20 - block_log);
plougher5507dd92006-11-06 00:43:10 +00004207
4208 sigemptyset(&sigmask);
4209 sigaddset(&sigmask, SIGINT);
4210 sigaddset(&sigmask, SIGQUIT);
4211 if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4212 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4213
4214 signal(SIGUSR1, sigusr1_handler);
4215
4216 if(processors == -1) {
4217#ifndef linux
4218 int mib[2];
4219 size_t len = sizeof(processors);
4220
4221 mib[0] = CTL_HW;
4222#ifdef HW_AVAILCPU
4223 mib[1] = HW_AVAILCPU;
4224#else
4225 mib[1] = HW_NCPU;
4226#endif
4227
4228 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
plougher360514a2009-03-30 03:01:38 +00004229 ERROR("Failed to get number of available processors. "
4230 "Defaulting to 1\n");
plougher5507dd92006-11-06 00:43:10 +00004231 processors = 1;
4232 }
4233#else
plougher9cc26b72010-08-17 01:05:55 +00004234 processors = sysconf(_SC_NPROCESSORS_ONLN);
plougher5507dd92006-11-06 00:43:10 +00004235#endif
4236 }
4237
plougherf2d2a842010-12-18 02:43:48 +00004238 thread = malloc((2 + processors * 2) * sizeof(pthread_t));
4239 if(thread == NULL)
plougher5507dd92006-11-06 00:43:10 +00004240 BAD_ERROR("Out of memory allocating thread descriptors\n");
plougher91fbb302008-05-06 02:29:36 +00004241 deflator_thread = &thread[2];
plougher5507dd92006-11-06 00:43:10 +00004242 frag_deflator_thread = &deflator_thread[processors];
4243
4244 to_reader = queue_init(1);
4245 from_reader = queue_init(reader_buffer_size);
4246 to_writer = queue_init(writer_buffer_size);
4247 from_writer = queue_init(1);
4248 from_deflate = queue_init(reader_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004249 to_frag = queue_init(fragment_buffer_size);
ploughereb6eac92008-02-26 01:50:48 +00004250 reader_buffer = cache_init(block_size, reader_buffer_size);
4251 writer_buffer = cache_init(block_size, writer_buffer_size);
plougher76c64082008-03-08 01:32:23 +00004252 fragment_buffer = cache_init(block_size, fragment_buffer_size);
plougher5507dd92006-11-06 00:43:10 +00004253 pthread_create(&thread[0], NULL, reader, NULL);
4254 pthread_create(&thread[1], NULL, writer, NULL);
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004255 init_progress_bar();
plougher5507dd92006-11-06 00:43:10 +00004256 pthread_mutex_init(&fragment_mutex, NULL);
4257 pthread_cond_init(&fragment_waiting, NULL);
4258
4259 for(i = 0; i < processors; i++) {
plougher50b31762009-03-31 04:14:46 +00004260 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
4261 0)
plougher5507dd92006-11-06 00:43:10 +00004262 BAD_ERROR("Failed to create thread\n");
plougher360514a2009-03-30 03:01:38 +00004263 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4264 NULL) != 0)
plougher5507dd92006-11-06 00:43:10 +00004265 BAD_ERROR("Failed to create thread\n");
4266 }
4267
4268 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4269 processors == 1 ? "" : "s");
4270
4271 if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
4272 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4273}
4274
4275
plougher0e453652006-11-06 01:49:35 +00004276long long write_inode_lookup_table()
4277{
4278 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
plougher44f03282010-07-27 00:31:36 +00004279 void *it;
plougher02bc3bc2007-02-25 12:12:01 +00004280
4281 if(inode_count == sinode_count)
4282 goto skip_inode_hash_table;
plougher0e453652006-11-06 01:49:35 +00004283
plougher44f03282010-07-27 00:31:36 +00004284 it = realloc(inode_lookup_table, lookup_bytes);
4285 if(it == NULL)
plougher0e453652006-11-06 01:49:35 +00004286 BAD_ERROR("Out of memory in write_inode_table\n");
plougher44f03282010-07-27 00:31:36 +00004287 inode_lookup_table = it;
plougher0e453652006-11-06 01:49:35 +00004288
plougher0e453652006-11-06 01:49:35 +00004289 for(i = 0; i < INODE_HASH_SIZE; i ++) {
4290 struct inode_info *inode = inode_info[i];
4291
4292 for(inode = inode_info[i]; inode; inode = inode->next) {
plougher0e453652006-11-06 01:49:35 +00004293
Phillip Lougher539c2b12012-07-30 20:14:52 +01004294 inode_number = get_inode_no(inode);
plougher0e453652006-11-06 01:49:35 +00004295
plougher360514a2009-03-30 03:01:38 +00004296 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4297 &inode_lookup_table[inode_number - 1], 1);
plougher0e453652006-11-06 01:49:35 +00004298
plougher0e453652006-11-06 01:49:35 +00004299 }
4300 }
4301
plougher02bc3bc2007-02-25 12:12:01 +00004302skip_inode_hash_table:
ploughera0a49c32010-08-11 01:47:59 +00004303 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4304 noI);
plougher0e453652006-11-06 01:49:35 +00004305}
4306
plougher2ea89142008-03-11 01:34:19 +00004307
plougher8f8e1a12007-10-18 02:50:21 +00004308char *get_component(char *target, char *targname)
4309{
4310 while(*target == '/')
rlougherc4ebcf52007-11-08 17:52:49 +00004311 target ++;
plougher8f8e1a12007-10-18 02:50:21 +00004312
4313 while(*target != '/' && *target!= '\0')
4314 *targname ++ = *target ++;
4315
4316 *targname = '\0';
4317
4318 return target;
4319}
4320
4321
4322void free_path(struct pathname *paths)
4323{
4324 int i;
4325
4326 for(i = 0; i < paths->names; i++) {
4327 if(paths->name[i].paths)
4328 free_path(paths->name[i].paths);
4329 free(paths->name[i].name);
4330 if(paths->name[i].preg) {
4331 regfree(paths->name[i].preg);
4332 free(paths->name[i].preg);
4333 }
4334 }
4335
4336 free(paths);
4337}
4338
4339
4340struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4341{
4342 char targname[1024];
4343 int i, error;
4344
4345 target = get_component(target, targname);
4346
4347 if(paths == NULL) {
plougherdec6ef12010-12-18 02:47:53 +00004348 paths = malloc(sizeof(struct pathname));
4349 if(paths == NULL)
plougher8f8e1a12007-10-18 02:50:21 +00004350 BAD_ERROR("failed to allocate paths\n");
4351
4352 paths->names = 0;
4353 paths->name = NULL;
4354 }
4355
4356 for(i = 0; i < paths->names; i++)
4357 if(strcmp(paths->name[i].name, targname) == 0)
4358 break;
4359
4360 if(i == paths->names) {
4361 /* allocate new name entry */
4362 paths->names ++;
plougherb3604122009-03-30 02:07:20 +00004363 paths->name = realloc(paths->name, (i + 1) *
4364 sizeof(struct path_entry));
plougher6f2a8262010-07-27 00:37:19 +00004365 if(paths->name == NULL)
4366 BAD_ERROR("Out of memory in add path\n");
plougher8f8e1a12007-10-18 02:50:21 +00004367 paths->name[i].name = strdup(targname);
4368 paths->name[i].paths = NULL;
4369 if(use_regex) {
4370 paths->name[i].preg = malloc(sizeof(regex_t));
plougher5c60eab2010-07-21 01:12:19 +00004371 if(paths->name[i].preg == NULL)
4372 BAD_ERROR("Out of memory in add_path\n");
plougherb3604122009-03-30 02:07:20 +00004373 error = regcomp(paths->name[i].preg, targname,
4374 REG_EXTENDED|REG_NOSUB);
plougher23377982007-11-12 04:04:48 +00004375 if(error) {
plougher8f8e1a12007-10-18 02:50:21 +00004376 char str[1024];
4377
4378 regerror(error, paths->name[i].preg, str, 1024);
plougherb3604122009-03-30 02:07:20 +00004379 BAD_ERROR("invalid regex %s in export %s, "
plougher50b31762009-03-31 04:14:46 +00004380 "because %s\n", targname, alltarget,
4381 str);
plougher8f8e1a12007-10-18 02:50:21 +00004382 }
4383 } else
4384 paths->name[i].preg = NULL;
4385
4386 if(target[0] == '\0')
4387 /* at leaf pathname component */
4388 paths->name[i].paths = NULL;
4389 else
4390 /* recurse adding child components */
plougher50b31762009-03-31 04:14:46 +00004391 paths->name[i].paths = add_path(NULL, target,
4392 alltarget);
plougher8f8e1a12007-10-18 02:50:21 +00004393 } else {
4394 /* existing matching entry */
4395 if(paths->name[i].paths == NULL) {
plougher50b31762009-03-31 04:14:46 +00004396 /* No sub-directory which means this is the leaf
4397 * component of a pre-existing exclude which subsumes
4398 * the exclude currently being added, in which case stop
4399 * adding components */
plougher8f8e1a12007-10-18 02:50:21 +00004400 } else if(target[0] == '\0') {
plougherb3604122009-03-30 02:07:20 +00004401 /* at leaf pathname component and child components exist
plougher50b31762009-03-31 04:14:46 +00004402 * from more specific excludes, delete as they're
4403 * subsumed by this exclude */
plougher8f8e1a12007-10-18 02:50:21 +00004404 free_path(paths->name[i].paths);
4405 paths->name[i].paths = NULL;
4406 } else
4407 /* recurse adding child components */
4408 add_path(paths->name[i].paths, target, alltarget);
4409 }
4410
4411 return paths;
4412}
plougher2ea89142008-03-11 01:34:19 +00004413
4414
plougher05e50ef2007-10-23 12:34:20 +00004415void add_exclude(char *target)
plougher8f8e1a12007-10-18 02:50:21 +00004416{
plougher05e50ef2007-10-23 12:34:20 +00004417
plougherb3604122009-03-30 02:07:20 +00004418 if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4419 strncmp(target, "../", 3) == 0)
4420 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4421 "-wildcards or -regex options\n");
plougher05e50ef2007-10-23 12:34:20 +00004422 else if(strncmp(target, "... ", 4) == 0)
4423 stickypath = add_path(stickypath, target + 4, target + 4);
4424 else
4425 path = add_path(path, target, target);
plougher8f8e1a12007-10-18 02:50:21 +00004426}
4427
4428
4429void display_path(int depth, struct pathname *paths)
4430{
4431 int i, n;
4432
4433 if(paths == NULL)
4434 return;
4435
4436 for(i = 0; i < paths->names; i++) {
4437 for(n = 0; n < depth; n++)
4438 printf("\t");
4439 printf("%d: %s\n", depth, paths->name[i].name);
4440 display_path(depth + 1, paths->name[i].paths);
4441 }
4442}
4443
4444
4445void display_path2(struct pathname *paths, char *string)
4446{
4447 int i;
4448 char path[1024];
4449
4450 if(paths == NULL) {
4451 printf("%s\n", string);
4452 return;
4453 }
4454
4455 for(i = 0; i < paths->names; i++) {
4456 strcat(strcat(strcpy(path, string), "/"), paths->name[i].name);
4457 display_path2(paths->name[i].paths, path);
4458 }
4459}
4460
4461
plougherf9039c92007-10-22 03:54:16 +00004462struct pathnames *init_subdir()
plougher8f8e1a12007-10-18 02:50:21 +00004463{
ploughera2968ef2009-03-03 10:46:00 +00004464 struct pathnames *new = malloc(sizeof(struct pathnames));
plougherd86ee822010-07-21 01:14:26 +00004465 if(new == NULL)
4466 BAD_ERROR("Out of memory in init_subdir\n");
plougherf9039c92007-10-22 03:54:16 +00004467 new->count = 0;
4468 return new;
4469}
4470
4471
4472struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4473{
plougher6f2a8262010-07-27 00:37:19 +00004474 if(paths->count % PATHS_ALLOC_SIZE == 0) {
plougherb3604122009-03-30 02:07:20 +00004475 paths = realloc(paths, sizeof(struct pathnames *) +
4476 (paths->count + PATHS_ALLOC_SIZE) *
4477 sizeof(struct pathname *));
plougher6f2a8262010-07-27 00:37:19 +00004478 if(paths == NULL)
4479 BAD_ERROR("Out of memory in add_subdir\n");
4480 }
plougherf9039c92007-10-22 03:54:16 +00004481
4482 paths->path[paths->count++] = path;
4483 return paths;
4484}
4485
4486
4487void free_subdir(struct pathnames *paths)
4488{
4489 free(paths);
4490}
4491
4492
4493int excluded(struct pathnames *paths, char *name, struct pathnames **new)
4494{
4495 int i, n, res;
plougher8f8e1a12007-10-18 02:50:21 +00004496
plougherf9039c92007-10-22 03:54:16 +00004497 if(paths == NULL) {
4498 *new = NULL;
4499 return FALSE;
4500 }
plougher8f8e1a12007-10-18 02:50:21 +00004501
plougherf9039c92007-10-22 03:54:16 +00004502
4503 *new = init_subdir();
plougher806581a2007-10-23 15:41:30 +00004504 if(stickypath)
4505 *new = add_subdir(*new, stickypath);
plougherf9039c92007-10-22 03:54:16 +00004506
4507 for(n = 0; n < paths->count; n++) {
4508 struct pathname *path = paths->path[n];
4509
4510 for(i = 0; i < path->names; i++) {
4511 int match = use_regex ?
plougher50b31762009-03-31 04:14:46 +00004512 regexec(path->name[i].preg, name, (size_t) 0,
4513 NULL, 0) == 0 :
plougherb3604122009-03-30 02:07:20 +00004514 fnmatch(path->name[i].name, name,
plougher50b31762009-03-31 04:14:46 +00004515 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
4516 0;
plougherf9039c92007-10-22 03:54:16 +00004517
4518 if(match && path->name[i].paths == NULL) {
plougherb3604122009-03-30 02:07:20 +00004519 /* match on a leaf component, any subdirectories
4520 * in the filesystem should be excluded */
plougherf9039c92007-10-22 03:54:16 +00004521 res = TRUE;
4522 goto empty_set;
plougher8f8e1a12007-10-18 02:50:21 +00004523 }
4524
plougherf9039c92007-10-22 03:54:16 +00004525 if(match)
plougherb3604122009-03-30 02:07:20 +00004526 /* match on a non-leaf component, add any
plougher50b31762009-03-31 04:14:46 +00004527 * subdirectories to the new set of
4528 * subdirectories to scan for this name */
plougherf9039c92007-10-22 03:54:16 +00004529 *new = add_subdir(*new, path->name[i].paths);
4530 }
4531 }
4532
4533 if((*new)->count == 0) {
plougher50b31762009-03-31 04:14:46 +00004534 /* no matching names found, return empty new search set
4535 */
plougherf9039c92007-10-22 03:54:16 +00004536 res = FALSE;
4537 goto empty_set;
4538 }
4539
4540 /* one or more matches with sub-directories found (no leaf matches).
4541 * Return new set */
plougher8f8e1a12007-10-18 02:50:21 +00004542 return FALSE;
plougherf9039c92007-10-22 03:54:16 +00004543
4544empty_set:
4545 free_subdir(*new);
4546 *new = NULL;
4547 return res;
plougher8f8e1a12007-10-18 02:50:21 +00004548}
4549
4550
plougher99ac0cc2007-10-29 03:17:10 +00004551#define RECOVER_ID "Squashfs recovery file v1.0\n"
4552#define RECOVER_ID_SIZE 28
4553
plougher64e83fd2010-12-31 21:21:26 +00004554void write_recovery_data(struct squashfs_super_block *sBlk)
plougher99ac0cc2007-10-29 03:17:10 +00004555{
plougher1d065e92010-06-18 03:58:27 +00004556 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
plougher99ac0cc2007-10-29 03:17:10 +00004557 pid_t pid = getpid();
plougher44d54ef2010-02-08 22:13:49 +00004558 char *metadata;
plougher99ac0cc2007-10-29 03:17:10 +00004559 char header[] = RECOVER_ID;
4560
4561 if(recover == FALSE) {
4562 printf("No recovery data option specified.\n");
ploughereac18532007-10-29 05:26:06 +00004563 printf("Skipping saving recovery file.\n\n");
plougher99ac0cc2007-10-29 03:17:10 +00004564 return;
4565 }
4566
plougher1b879bc2010-12-18 02:49:42 +00004567 metadata = malloc(bytes);
4568 if(metadata == NULL)
plougher50b31762009-03-31 04:14:46 +00004569 BAD_ERROR("Failed to alloc metadata buffer in "
4570 "write_recovery_data\n");
plougher44d54ef2010-02-08 22:13:49 +00004571
plougher1d065e92010-06-18 03:58:27 +00004572 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
4573 if(res == 0)
4574 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004575
plougherb3604122009-03-30 02:07:20 +00004576 sprintf(recovery_file, "squashfs_recovery_%s_%d",
plougher44d54ef2010-02-08 22:13:49 +00004577 getbase(destination_file), pid);
plougherb3604122009-03-30 02:07:20 +00004578 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
4579 if(recoverfd == -1)
4580 BAD_ERROR("Failed to create recovery file, because %s. "
4581 "Aborting\n", strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004582
plougher628e7682009-03-29 22:12:24 +00004583 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
plougherb3604122009-03-30 02:07:20 +00004584 BAD_ERROR("Failed to write recovery file, because %s\n",
4585 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004586
plougher64e83fd2010-12-31 21:21:26 +00004587 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
plougherb3604122009-03-30 02:07:20 +00004588 BAD_ERROR("Failed to write recovery file, because %s\n",
4589 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004590
plougher628e7682009-03-29 22:12:24 +00004591 if(write_bytes(recoverfd, metadata, bytes) == -1)
plougherb3604122009-03-30 02:07:20 +00004592 BAD_ERROR("Failed to write recovery file, because %s\n",
4593 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004594
4595 close(recoverfd);
plougher44d54ef2010-02-08 22:13:49 +00004596 free(metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004597
4598 printf("Recovery file \"%s\" written\n", recovery_file);
4599 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
plougherb3604122009-03-30 02:07:20 +00004600 printf("mksquashfs dummy %s -recover %s\n", destination_file,
4601 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004602 printf("to restore filesystem\n\n");
4603}
4604
4605
4606void read_recovery_data(char *recovery_file, char *destination_file)
4607{
4608 int fd, recoverfd, bytes;
plougher64e83fd2010-12-31 21:21:26 +00004609 struct squashfs_super_block orig_sBlk, sBlk;
plougher99ac0cc2007-10-29 03:17:10 +00004610 char *metadata;
plougher8a8c4102009-03-29 22:28:49 +00004611 int res;
plougher99ac0cc2007-10-29 03:17:10 +00004612 struct stat buf;
4613 char header[] = RECOVER_ID;
4614 char header2[RECOVER_ID_SIZE];
4615
plougher9e9d9dc2010-12-18 02:53:57 +00004616 recoverfd = open(recovery_file, O_RDONLY);
4617 if(recoverfd == -1)
plougherb3604122009-03-30 02:07:20 +00004618 BAD_ERROR("Failed to open recovery file because %s\n",
4619 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004620
4621 if(stat(destination_file, &buf) == -1)
plougherb3604122009-03-30 02:07:20 +00004622 BAD_ERROR("Failed to stat destination file, because %s\n",
4623 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004624
plougher9e9d9dc2010-12-18 02:53:57 +00004625 fd = open(destination_file, O_RDWR);
4626 if(fd == -1)
plougherb3604122009-03-30 02:07:20 +00004627 BAD_ERROR("Failed to open destination file because %s\n",
4628 strerror(errno));
plougher99ac0cc2007-10-29 03:17:10 +00004629
plougher8a8c4102009-03-29 22:28:49 +00004630 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
4631 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004632 BAD_ERROR("Failed to read recovery file, because %s\n",
4633 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004634 if(res < RECOVER_ID_SIZE)
4635 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004636 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
4637 BAD_ERROR("Not a recovery file\n");
4638
plougher64e83fd2010-12-31 21:21:26 +00004639 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
plougher8a8c4102009-03-29 22:28:49 +00004640 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004641 BAD_ERROR("Failed to read recovery file, because %s\n",
4642 strerror(errno));
plougher64e83fd2010-12-31 21:21:26 +00004643 if(res < sizeof(struct squashfs_super_block))
plougher8a8c4102009-03-29 22:28:49 +00004644 BAD_ERROR("Recovery file appears to be truncated\n");
plougher99ac0cc2007-10-29 03:17:10 +00004645
plougher64e83fd2010-12-31 21:21:26 +00004646 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
plougher1d065e92010-06-18 03:58:27 +00004647 if(res == 0)
4648 EXIT_MKSQUASHFS();
plougher99ac0cc2007-10-29 03:17:10 +00004649
plougherb3604122009-03-30 02:07:20 +00004650 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
plougher64e83fd2010-12-31 21:21:26 +00004651 sizeof(struct squashfs_super_block) - 4) != 0)
plougherb3604122009-03-30 02:07:20 +00004652 BAD_ERROR("Recovery file and destination file do not seem to "
4653 "match\n");
plougher99ac0cc2007-10-29 03:17:10 +00004654
4655 bytes = sBlk.bytes_used - sBlk.inode_table_start;
4656
plougher9e9d9dc2010-12-18 02:53:57 +00004657 metadata = malloc(bytes);
4658 if(metadata == NULL)
plougherb3604122009-03-30 02:07:20 +00004659 BAD_ERROR("Failed to alloc metadata buffer in "
4660 "read_recovery_data\n");
plougher99ac0cc2007-10-29 03:17:10 +00004661
plougher8a8c4102009-03-29 22:28:49 +00004662 res = read_bytes(recoverfd, metadata, bytes);
4663 if(res == -1)
plougherb3604122009-03-30 02:07:20 +00004664 BAD_ERROR("Failed to read recovery file, because %s\n",
4665 strerror(errno));
plougher8a8c4102009-03-29 22:28:49 +00004666 if(res < bytes)
plougher99ac0cc2007-10-29 03:17:10 +00004667 BAD_ERROR("Recovery file appears to be truncated\n");
4668
plougher64e83fd2010-12-31 21:21:26 +00004669 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
plougher99ac0cc2007-10-29 03:17:10 +00004670
plougher0dd6f122009-03-29 21:43:57 +00004671 write_destination(fd, sBlk.inode_table_start, bytes, metadata);
plougher99ac0cc2007-10-29 03:17:10 +00004672
4673 close(recoverfd);
4674 close(fd);
4675
plougherb3604122009-03-30 02:07:20 +00004676 printf("Successfully wrote recovery file \"%s\". Exiting\n",
4677 recovery_file);
plougher99ac0cc2007-10-29 03:17:10 +00004678
4679 exit(0);
4680}
4681
4682
plougher1f413c82005-11-18 00:02:14 +00004683#define VERSION() \
Phillip Lougher3b89ee82012-10-18 23:55:37 +01004684 printf("mksquashfs version 4.2-CVS (2012/10/18)\n");\
Phillip Lougherb38c1722012-02-09 23:26:19 +00004685 printf("copyright (C) 2012 Phillip Lougher "\
plougher16111452010-07-22 05:12:18 +00004686 "<phillip@lougher.demon.co.uk>\n\n"); \
4687 printf("This program is free software; you can redistribute it and/or"\
4688 "\n");\
4689 printf("modify it under the terms of the GNU General Public License"\
4690 "\n");\
4691 printf("as published by the Free Software Foundation; either version "\
4692 "2,\n");\
plougher1f413c82005-11-18 00:02:14 +00004693 printf("or (at your option) any later version.\n\n");\
plougher16111452010-07-22 05:12:18 +00004694 printf("This program is distributed in the hope that it will be "\
4695 "useful,\n");\
4696 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
4697 "of\n");\
4698 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
4699 "\n");\
plougher1f413c82005-11-18 00:02:14 +00004700 printf("GNU General Public License for more details.\n");
4701int main(int argc, char *argv[])
4702{
plougher324978d2006-02-27 04:53:29 +00004703 struct stat buf, source_buf;
plougher13fdddf2010-11-24 01:23:41 +00004704 int res, i;
plougher64e83fd2010-12-31 21:21:26 +00004705 struct squashfs_super_block sBlk;
plougher1f413c82005-11-18 00:02:14 +00004706 char *b, *root_name = NULL;
plougher6c65b032008-08-07 09:13:24 +00004707 int nopad = FALSE, keep_as_directory = FALSE;
plougher1f413c82005-11-18 00:02:14 +00004708 squashfs_inode inode;
plougherb3604122009-03-30 02:07:20 +00004709 int readb_mbytes = READER_BUFFER_DEFAULT,
4710 writeb_mbytes = WRITER_BUFFER_DEFAULT,
4711 fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
plougher1f413c82005-11-18 00:02:14 +00004712
plougher1f413c82005-11-18 00:02:14 +00004713 block_log = slog(block_size);
4714 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
4715 VERSION();
4716 exit(0);
4717 }
4718 for(i = 1; i < argc && argv[i][0] != '-'; i++);
4719 if(i < 3)
4720 goto printOptions;
4721 source_path = argv + 1;
4722 source = i - 2;
plougher4da4bd42010-11-21 05:01:54 +00004723 /*
4724 * lookup default compressor. Note the Makefile ensures the default
4725 * compressor has been built, and so we don't need to to check
4726 * for failure here
4727 */
plougher5c2adaf2010-11-22 01:00:15 +00004728 comp = lookup_compressor(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00004729 for(; i < argc; i++) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01004730 if(strcmp(argv[i], "-action") == 0) {
4731 if(++i == argc) {
4732 ERROR("%s: -action missing action\n",
4733 argv[0]);
4734 exit(1);
4735 }
4736 res = parse_action(argv[i]);
4737 if(res == 0)
4738 exit(1);
4739
4740 } else if(strcmp(argv[i], "-comp") == 0) {
plougherc5d59872010-11-22 01:36:01 +00004741 if(compressor_opts_parsed) {
4742 ERROR("%s: -comp must appear before -X options"
4743 "\n", argv[0]);
4744 exit(1);
4745 }
plougherae9dcd82009-08-01 02:59:38 +00004746 if(++i == argc) {
4747 ERROR("%s: -comp missing compression type\n",
4748 argv[0]);
4749 exit(1);
4750 }
plougher5c2adaf2010-11-22 01:00:15 +00004751 comp = lookup_compressor(argv[i]);
plougher4da4bd42010-11-21 05:01:54 +00004752 if(!comp->supported) {
plougherc5d59872010-11-22 01:36:01 +00004753 ERROR("%s: Compressor \"%s\" is not supported!"
4754 "\n", argv[0], argv[i]);
4755 ERROR("%s: Compressors available:\n", argv[0]);
plougher4da4bd42010-11-21 05:01:54 +00004756 display_compressors("", COMP_DEFAULT);
4757 exit(1);
4758 }
plougherb5576ea2010-11-22 01:06:53 +00004759
4760 } else if(strncmp(argv[i], "-X", 2) == 0) {
4761 int args = compressor_options(comp, argv + i, argc - i);
plougherd8865672010-11-27 05:05:49 +00004762 if(args < 0) {
4763 if(args == -1) {
4764 ERROR("%s: Unrecognised compressor"
4765 " option %s\n", argv[0],
4766 argv[i]);
4767 ERROR("%s: Did you forget to specify"
4768 " -comp, or specify it after"
4769 " the compressor specific"
4770 " option?\n", argv[0]);
4771 }
plougherb5576ea2010-11-22 01:06:53 +00004772 exit(1);
4773 }
4774 i += args;
plougherc5d59872010-11-22 01:36:01 +00004775 compressor_opts_parsed = 1;
plougherb5576ea2010-11-22 01:06:53 +00004776
plougherae9dcd82009-08-01 02:59:38 +00004777 } else if(strcmp(argv[i], "-pf") == 0) {
plougher43244f22009-04-05 02:04:51 +00004778 if(++i == argc) {
4779 ERROR("%s: -pf missing filename\n", argv[0]);
4780 exit(1);
4781 }
plougher620b7172009-09-10 04:17:48 +00004782 if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004783 exit(1);
plougher43244f22009-04-05 02:04:51 +00004784 } else if(strcmp(argv[i], "-p") == 0) {
4785 if(++i == argc) {
4786 ERROR("%s: -p missing pseudo file definition\n",
4787 argv[0]);
4788 exit(1);
4789 }
plougher620b7172009-09-10 04:17:48 +00004790 if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
plougher43244f22009-04-05 02:04:51 +00004791 exit(1);
plougher43244f22009-04-05 02:04:51 +00004792 } else if(strcmp(argv[i], "-recover") == 0) {
plougher99ac0cc2007-10-29 03:17:10 +00004793 if(++i == argc) {
plougherb3604122009-03-30 02:07:20 +00004794 ERROR("%s: -recover missing recovery file\n",
4795 argv[0]);
plougher99ac0cc2007-10-29 03:17:10 +00004796 exit(1);
4797 }
4798 read_recovery_data(argv[i], argv[source + 1]);
4799 } else if(strcmp(argv[i], "-no-recovery") == 0)
4800 recover = FALSE;
4801 else if(strcmp(argv[i], "-wildcards") == 0) {
plougher934a9ed2007-10-19 00:21:10 +00004802 old_exclude = FALSE;
4803 use_regex = FALSE;
4804 } else if(strcmp(argv[i], "-regex") == 0) {
4805 old_exclude = FALSE;
4806 use_regex = TRUE;
4807 } else if(strcmp(argv[i], "-no-sparse") == 0)
plougher1f54edc2007-08-12 23:13:36 +00004808 sparse_files = FALSE;
4809 else if(strcmp(argv[i], "-no-progress") == 0)
plougher02bc3bc2007-02-25 12:12:01 +00004810 progress = FALSE;
4811 else if(strcmp(argv[i], "-no-exports") == 0)
4812 exportable = FALSE;
plougher0e453652006-11-06 01:49:35 +00004813 else if(strcmp(argv[i], "-processors") == 0) {
plougher360514a2009-03-30 03:01:38 +00004814 if((++i == argc) || (processors =
4815 strtol(argv[i], &b, 10), *b != '\0')) {
4816 ERROR("%s: -processors missing or invalid "
4817 "processor number\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004818 exit(1);
4819 }
4820 if(processors < 1) {
plougher360514a2009-03-30 03:01:38 +00004821 ERROR("%s: -processors should be 1 or larger\n",
4822 argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004823 exit(1);
4824 }
plougher0e453652006-11-06 01:49:35 +00004825 } else if(strcmp(argv[i], "-read-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004826 if((++i == argc) || (readb_mbytes =
4827 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004828 ERROR("%s: -read-queue missing or invalid "
4829 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004830 exit(1);
4831 }
4832 if(readb_mbytes < 1) {
plougher360514a2009-03-30 03:01:38 +00004833 ERROR("%s: -read-queue should be 1 megabyte or "
4834 "larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004835 exit(1);
4836 }
plougher0e453652006-11-06 01:49:35 +00004837 } else if(strcmp(argv[i], "-write-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004838 if((++i == argc) || (writeb_mbytes =
4839 strtol(argv[i], &b, 10), *b != '\0')) {
plougher50b31762009-03-31 04:14:46 +00004840 ERROR("%s: -write-queue missing or invalid "
4841 "queue size\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004842 exit(1);
4843 }
4844 if(writeb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004845 ERROR("%s: -write-queue should be 1 megabyte "
4846 "or larger\n", argv[0]);
plougher5507dd92006-11-06 00:43:10 +00004847 exit(1);
4848 }
plougher217bad82008-04-05 11:36:41 +00004849 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
plougher360514a2009-03-30 03:01:38 +00004850 if((++i == argc) ||
4851 (fragmentb_mbytes =
4852 strtol(argv[i], &b, 10), *b != '\0')) {
4853 ERROR("%s: -fragment-queue missing or invalid "
4854 "queue size\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004855 exit(1);
4856 }
4857 if(fragmentb_mbytes < 1) {
plougher50b31762009-03-31 04:14:46 +00004858 ERROR("%s: -fragment-queue should be 1 "
4859 "megabyte or larger\n", argv[0]);
plougher217bad82008-04-05 11:36:41 +00004860 exit(1);
4861 }
plougher5507dd92006-11-06 00:43:10 +00004862 } else if(strcmp(argv[i], "-b") == 0) {
plougher4c99cb72007-06-14 21:46:31 +00004863 if(++i == argc) {
4864 ERROR("%s: -b missing block size\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004865 exit(1);
4866 }
plougher4c99cb72007-06-14 21:46:31 +00004867 block_size = strtol(argv[i], &b, 10);
4868 if(*b == 'm' || *b == 'M')
4869 block_size *= 1048576;
4870 else if(*b == 'k' || *b == 'K')
4871 block_size *= 1024;
4872 else if(*b != '\0') {
4873 ERROR("%s: -b invalid block size\n", argv[0]);
4874 exit(1);
4875 }
plougher1f413c82005-11-18 00:02:14 +00004876 if((block_log = slog(block_size)) == 0) {
plougher50b31762009-03-31 04:14:46 +00004877 ERROR("%s: -b block size not power of two or "
4878 "not between 4096 and 1Mbyte\n",
4879 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004880 exit(1);
4881 }
4882 } else if(strcmp(argv[i], "-ef") == 0) {
4883 if(++i == argc) {
4884 ERROR("%s: -ef missing filename\n", argv[0]);
4885 exit(1);
4886 }
plougher9b5bf8c2006-03-20 18:43:33 +00004887 } else if(strcmp(argv[i], "-no-duplicates") == 0)
plougher1f413c82005-11-18 00:02:14 +00004888 duplicate_checking = FALSE;
4889
4890 else if(strcmp(argv[i], "-no-fragments") == 0)
4891 no_fragments = TRUE;
4892
4893 else if(strcmp(argv[i], "-always-use-fragments") == 0)
4894 always_use_fragments = TRUE;
4895
4896 else if(strcmp(argv[i], "-sort") == 0) {
4897 if(++i == argc) {
4898 ERROR("%s: -sort missing filename\n", argv[0]);
4899 exit(1);
4900 }
4901 } else if(strcmp(argv[i], "-all-root") == 0 ||
4902 strcmp(argv[i], "-root-owned") == 0)
4903 global_uid = global_gid = 0;
4904
4905 else if(strcmp(argv[i], "-force-uid") == 0) {
4906 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004907 ERROR("%s: -force-uid missing uid or user\n",
4908 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004909 exit(1);
4910 }
4911 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004912 if(global_uid < 0 || global_uid >
4913 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004914 ERROR("%s: -force-uid uid out of range"
4915 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004916 exit(1);
4917 }
4918 } else {
4919 struct passwd *uid = getpwnam(argv[i]);
4920 if(uid)
4921 global_uid = uid->pw_uid;
4922 else {
plougher360514a2009-03-30 03:01:38 +00004923 ERROR("%s: -force-uid invalid uid or "
4924 "unknown user\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004925 exit(1);
4926 }
4927 }
4928 } else if(strcmp(argv[i], "-force-gid") == 0) {
4929 if(++i == argc) {
plougher360514a2009-03-30 03:01:38 +00004930 ERROR("%s: -force-gid missing gid or group\n",
4931 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004932 exit(1);
4933 }
4934 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
plougher360514a2009-03-30 03:01:38 +00004935 if(global_gid < 0 || global_gid >
4936 (((long long) 1 << 32) - 1)) {
plougher50b31762009-03-31 04:14:46 +00004937 ERROR("%s: -force-gid gid out of range"
4938 "\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004939 exit(1);
4940 }
4941 } else {
4942 struct group *gid = getgrnam(argv[i]);
4943 if(gid)
4944 global_gid = gid->gr_gid;
4945 else {
plougher360514a2009-03-30 03:01:38 +00004946 ERROR("%s: -force-gid invalid gid or "
4947 "unknown group\n", argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004948 exit(1);
4949 }
4950 }
4951 } else if(strcmp(argv[i], "-noI") == 0 ||
4952 strcmp(argv[i], "-noInodeCompression") == 0)
4953 noI = TRUE;
4954
4955 else if(strcmp(argv[i], "-noD") == 0 ||
4956 strcmp(argv[i], "-noDataCompression") == 0)
4957 noD = TRUE;
4958
4959 else if(strcmp(argv[i], "-noF") == 0 ||
4960 strcmp(argv[i], "-noFragmentCompression") == 0)
4961 noF = TRUE;
4962
plougherb99d7832010-05-19 01:57:34 +00004963 else if(strcmp(argv[i], "-noX") == 0 ||
4964 strcmp(argv[i], "-noXattrCompression") == 0)
4965 noX = TRUE;
4966
plougherce564c62010-05-19 03:01:49 +00004967 else if(strcmp(argv[i], "-no-xattrs") == 0)
4968 no_xattrs = TRUE;
plougher6d89ac22010-05-19 02:59:23 +00004969
plougher30281c82010-08-25 05:06:11 +00004970 else if(strcmp(argv[i], "-xattrs") == 0)
4971 no_xattrs = FALSE;
4972
plougher1f413c82005-11-18 00:02:14 +00004973 else if(strcmp(argv[i], "-nopad") == 0)
4974 nopad = TRUE;
4975
plougher91fbb302008-05-06 02:29:36 +00004976 else if(strcmp(argv[i], "-info") == 0) {
4977 silent = FALSE;
4978 progress = FALSE;
4979 }
plougher1f413c82005-11-18 00:02:14 +00004980
4981 else if(strcmp(argv[i], "-e") == 0)
4982 break;
4983
4984 else if(strcmp(argv[i], "-noappend") == 0)
4985 delete = TRUE;
4986
4987 else if(strcmp(argv[i], "-keep-as-directory") == 0)
4988 keep_as_directory = TRUE;
4989
4990 else if(strcmp(argv[i], "-root-becomes") == 0) {
4991 if(++i == argc) {
plougher50b31762009-03-31 04:14:46 +00004992 ERROR("%s: -root-becomes: missing name\n",
4993 argv[0]);
plougher1f413c82005-11-18 00:02:14 +00004994 exit(1);
4995 }
4996 root_name = argv[i];
4997 } else if(strcmp(argv[i], "-version") == 0) {
4998 VERSION();
4999 } else {
5000 ERROR("%s: invalid option\n\n", argv[0]);
5001printOptions:
plougher360514a2009-03-30 03:01:38 +00005002 ERROR("SYNTAX:%s source1 source2 ... dest [options] "
5003 "[-e list of exclude\ndirs/files]\n", argv[0]);
plougher37632562009-08-07 19:09:01 +00005004 ERROR("\nFilesystem build options:\n");
plougherff5ea8b2009-08-07 19:33:10 +00005005 ERROR("-comp <comp>\t\tselect <comp> compression\n");
plougher13df1782009-08-29 01:05:34 +00005006 ERROR("\t\t\tCompressors available:\n");
plougher764dab52009-08-24 18:28:04 +00005007 display_compressors("\t\t\t", COMP_DEFAULT);
plougher50b31762009-03-31 04:14:46 +00005008 ERROR("-b <block_size>\t\tset data block to "
5009 "<block_size>. Default %d bytes\n",
5010 SQUASHFS_FILE_SIZE);
plougher37632562009-08-07 19:09:01 +00005011 ERROR("-no-exports\t\tdon't make the filesystem "
5012 "exportable via NFS\n");
5013 ERROR("-no-sparse\t\tdon't detect sparse files\n");
plougher07d25c22010-08-25 17:41:57 +00005014 ERROR("-no-xattrs\t\tdon't store extended attributes"
plougher30281c82010-08-25 05:06:11 +00005015 NOXOPT_STR "\n");
plougher07d25c22010-08-25 17:41:57 +00005016 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
plougher30281c82010-08-25 05:06:11 +00005017 "\n");
plougher1f413c82005-11-18 00:02:14 +00005018 ERROR("-noI\t\t\tdo not compress inode table\n");
5019 ERROR("-noD\t\t\tdo not compress data blocks\n");
5020 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
plougher16111452010-07-22 05:12:18 +00005021 ERROR("-noX\t\t\tdo not compress extended "
5022 "attributes\n");
plougher1f413c82005-11-18 00:02:14 +00005023 ERROR("-no-fragments\t\tdo not use fragments\n");
plougher360514a2009-03-30 03:01:38 +00005024 ERROR("-always-use-fragments\tuse fragment blocks for "
5025 "files larger than block size\n");
5026 ERROR("-no-duplicates\t\tdo not perform duplicate "
5027 "checking\n");
plougher1f413c82005-11-18 00:02:14 +00005028 ERROR("-all-root\t\tmake all files owned by root\n");
5029 ERROR("-force-uid uid\t\tset all file uids to uid\n");
5030 ERROR("-force-gid gid\t\tset all file gids to gid\n");
plougher50b31762009-03-31 04:14:46 +00005031 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
5032 "of 4K\n");
plougher37632562009-08-07 19:09:01 +00005033 ERROR("-keep-as-directory\tif one source directory is "
5034 "specified, create a root\n");
5035 ERROR("\t\t\tdirectory containing that directory, "
5036 "rather than the\n");
5037 ERROR("\t\t\tcontents of the directory\n");
5038 ERROR("\nFilesystem filter options:\n");
plougher16111452010-07-22 05:12:18 +00005039 ERROR("-p <pseudo-definition>\tAdd pseudo file "
5040 "definition\n");
5041 ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
5042 "definitions\n");
plougher360514a2009-03-30 03:01:38 +00005043 ERROR("-sort <sort_file>\tsort files according to "
5044 "priorities in <sort_file>. One\n");
5045 ERROR("\t\t\tfile or dir with priority per line. "
5046 "Priority -32768 to\n");
plougher1f413c82005-11-18 00:02:14 +00005047 ERROR("\t\t\t32767, default priority 0\n");
plougher50b31762009-03-31 04:14:46 +00005048 ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
5049 " One per line\n");
plougher360514a2009-03-30 03:01:38 +00005050 ERROR("-wildcards\t\tAllow extended shell wildcards "
5051 "(globbing) to be used in\n\t\t\texclude "
5052 "dirs/files\n");
plougher50b31762009-03-31 04:14:46 +00005053 ERROR("-regex\t\t\tAllow POSIX regular expressions to "
5054 "be used in exclude\n\t\t\tdirs/files\n");
plougher37632562009-08-07 19:09:01 +00005055 ERROR("\nFilesystem append options:\n");
5056 ERROR("-noappend\t\tdo not append to existing "
5057 "filesystem\n");
5058 ERROR("-root-becomes <name>\twhen appending source "
5059 "files/directories, make the\n");
5060 ERROR("\t\t\toriginal root become a subdirectory in "
5061 "the new root\n");
5062 ERROR("\t\t\tcalled <name>, rather than adding the new "
5063 "source items\n");
5064 ERROR("\t\t\tto the original root\n");
5065 ERROR("\nMksquashfs runtime options:\n");
5066 ERROR("-version\t\tprint version, licence and "
5067 "copyright message\n");
5068 ERROR("-recover <name>\t\trecover filesystem data "
5069 "using recovery file <name>\n");
5070 ERROR("-no-recovery\t\tdon't generate a recovery "
5071 "file\n");
5072 ERROR("-info\t\t\tprint files written to filesystem\n");
5073 ERROR("-no-progress\t\tdon't display the progress "
5074 "bar\n");
5075 ERROR("-processors <number>\tUse <number> processors."
5076 " By default will use number of\n");
5077 ERROR("\t\t\tprocessors available\n");
5078 ERROR("-read-queue <size>\tSet input queue to <size> "
5079 "Mbytes. Default %d Mbytes\n",
5080 READER_BUFFER_DEFAULT);
5081 ERROR("-write-queue <size>\tSet output queue to <size> "
5082 "Mbytes. Default %d Mbytes\n",
5083 WRITER_BUFFER_DEFAULT);
plougher8bc376b2010-11-12 04:55:20 +00005084 ERROR("-fragment-queue <size>\tSet fragment queue to "
plougher37632562009-08-07 19:09:01 +00005085 "<size> Mbytes. Default %d Mbytes\n",
5086 FRAGMENT_BUFFER_DEFAULT);
5087 ERROR("\nMiscellaneous options:\n");
5088 ERROR("-root-owned\t\talternative name for -all-root"
5089 "\n");
5090 ERROR("-noInodeCompression\talternative name for -noI"
5091 "\n");
5092 ERROR("-noDataCompression\talternative name for -noD"
5093 "\n");
5094 ERROR("-noFragmentCompression\talternative name for "
5095 "-noF\n");
plougherb99d7832010-05-19 01:57:34 +00005096 ERROR("-noXattrCompression\talternative name for "
5097 "-noX\n");
plougher4fb66822010-12-08 02:49:28 +00005098 ERROR("\nCompressors available and compressor specific "
5099 "options:\n");
5100 display_compressor_usage(COMP_DEFAULT);
plougher1f413c82005-11-18 00:02:14 +00005101 exit(1);
5102 }
5103 }
5104
plougherb747f4f2010-12-25 04:05:47 +00005105 /*
5106 * Some compressors may need the options to be checked for validity
5107 * once all the options have been processed
5108 */
5109 res = compressor_options_post(comp, block_size);
5110 if(res)
5111 EXIT_MKSQUASHFS();
5112
plougher91fbb302008-05-06 02:29:36 +00005113 for(i = 0; i < source; i++)
5114 if(lstat(source_path[i], &source_buf) == -1) {
plougher360514a2009-03-30 03:01:38 +00005115 fprintf(stderr, "Cannot stat source directory \"%s\" "
plougher50b31762009-03-31 04:14:46 +00005116 "because %s\n", source_path[i],
5117 strerror(errno));
plougher91fbb302008-05-06 02:29:36 +00005118 EXIT_MKSQUASHFS();
5119 }
plougher324978d2006-02-27 04:53:29 +00005120
5121 destination_file = argv[source + 1];
plougher1f413c82005-11-18 00:02:14 +00005122 if(stat(argv[source + 1], &buf) == -1) {
5123 if(errno == ENOENT) { /* Does not exist */
plougher360514a2009-03-30 03:01:38 +00005124 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
plougher59dce672010-05-19 03:56:59 +00005125 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
plougher360514a2009-03-30 03:01:38 +00005126 if(fd == -1) {
plougher1f413c82005-11-18 00:02:14 +00005127 perror("Could not create destination file");
5128 exit(1);
5129 }
5130 delete = TRUE;
5131 } else {
5132 perror("Could not stat destination file");
5133 exit(1);
5134 }
5135
5136 } else {
5137 if(S_ISBLK(buf.st_mode)) {
5138 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
plougher50b31762009-03-31 04:14:46 +00005139 perror("Could not open block device as "
5140 "destination");
plougher1f413c82005-11-18 00:02:14 +00005141 exit(1);
5142 }
5143 block_device = 1;
5144
5145 } else if(S_ISREG(buf.st_mode)) {
plougher360514a2009-03-30 03:01:38 +00005146 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
5147 O_RDWR);
5148 if(fd == -1) {
plougher50b31762009-03-31 04:14:46 +00005149 perror("Could not open regular file for "
5150 "writing as destination");
plougher1f413c82005-11-18 00:02:14 +00005151 exit(1);
5152 }
plougher44d54ef2010-02-08 22:13:49 +00005153 }
plougher1f413c82005-11-18 00:02:14 +00005154 else {
5155 ERROR("Destination not block device or regular file\n");
5156 exit(1);
5157 }
5158
plougher324978d2006-02-27 04:53:29 +00005159 }
plougher1f413c82005-11-18 00:02:14 +00005160
plougher4c99cb72007-06-14 21:46:31 +00005161 signal(SIGTERM, sighandler2);
5162 signal(SIGINT, sighandler2);
plougher1f413c82005-11-18 00:02:14 +00005163
plougher16111452010-07-22 05:12:18 +00005164 /*
5165 * process the exclude files - must be done afer destination file has
5166 * been possibly created
5167 */
plougher1f413c82005-11-18 00:02:14 +00005168 for(i = source + 2; i < argc; i++)
5169 if(strcmp(argv[i], "-ef") == 0) {
5170 FILE *fd;
5171 char filename[16385];
5172 if((fd = fopen(argv[++i], "r")) == NULL) {
5173 perror("Could not open exclude file...");
plougher324978d2006-02-27 04:53:29 +00005174 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005175 }
5176 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
plougher8f8e1a12007-10-18 02:50:21 +00005177 if(old_exclude)
5178 old_add_exclude(filename);
5179 else
plougher05e50ef2007-10-23 12:34:20 +00005180 add_exclude(filename);
plougher1f413c82005-11-18 00:02:14 +00005181 fclose(fd);
5182 } else if(strcmp(argv[i], "-e") == 0)
5183 break;
plougher8b9a7f62009-08-01 22:52:45 +00005184 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005185 strcmp(argv[i], "-sort") == 0 ||
5186 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005187 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005188 i++;
5189
5190 if(i != argc) {
5191 if(++i == argc) {
5192 ERROR("%s: -e missing arguments\n", argv[0]);
plougher324978d2006-02-27 04:53:29 +00005193 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005194 }
plougher8f8e1a12007-10-18 02:50:21 +00005195 while(i < argc)
5196 if(old_exclude)
5197 old_add_exclude(argv[i++]);
5198 else
plougher05e50ef2007-10-23 12:34:20 +00005199 add_exclude(argv[i++]);
plougher1f413c82005-11-18 00:02:14 +00005200 }
5201
5202 /* process the sort files - must be done afer the exclude files */
5203 for(i = source + 2; i < argc; i++)
5204 if(strcmp(argv[i], "-sort") == 0) {
ploughere1c9a742010-07-21 16:59:05 +00005205 int res = read_sort_file(argv[++i], source,
5206 source_path);
5207 if(res == FALSE)
5208 BAD_ERROR("Failed to read sort file\n");
plougher1f413c82005-11-18 00:02:14 +00005209 sorted ++;
5210 } else if(strcmp(argv[i], "-e") == 0)
5211 break;
plougher8b9a7f62009-08-01 22:52:45 +00005212 else if(strcmp(argv[i], "-root-becomes") == 0 ||
plougher43244f22009-04-05 02:04:51 +00005213 strcmp(argv[i], "-ef") == 0 ||
5214 strcmp(argv[i], "-pf") == 0 ||
plougher8b9a7f62009-08-01 22:52:45 +00005215 strcmp(argv[i], "-comp") == 0)
plougher1f413c82005-11-18 00:02:14 +00005216 i++;
5217
plougher62d5b5c2008-08-16 01:49:42 +00005218#ifdef SQUASHFS_TRACE
5219 progress = FALSE;
5220#endif
5221
plougher4c99cb72007-06-14 21:46:31 +00005222 if(!delete) {
ploughera175ce22009-07-30 04:43:27 +00005223 comp = read_super(fd, &sBlk, argv[source + 1]);
5224 if(comp == NULL) {
plougher360514a2009-03-30 03:01:38 +00005225 ERROR("Failed to read existing filesystem - will not "
5226 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005227 ERROR("To force Mksquashfs to write to this block "
5228 "device or file use -noappend\n");
plougher4c99cb72007-06-14 21:46:31 +00005229 EXIT_MKSQUASHFS();
5230 }
plougher1f413c82005-11-18 00:02:14 +00005231
plougher1f413c82005-11-18 00:02:14 +00005232 block_log = slog(block_size = sBlk.block_size);
5233 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
5234 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
5235 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
plougher89c7a512010-12-15 08:35:51 +00005236 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
plougher1f413c82005-11-18 00:02:14 +00005237 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
5238 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
5239 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
plougher0e453652006-11-06 01:49:35 +00005240 exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
plougherafae8252010-12-15 09:12:58 +00005241 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
plougher3d7e5182010-12-25 01:49:42 +00005242 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
plougher4c99cb72007-06-14 21:46:31 +00005243 }
5244
plougher5741d792010-09-04 03:20:50 +00005245 initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
plougher4c99cb72007-06-14 21:46:31 +00005246
plougher13fdddf2010-11-24 01:23:41 +00005247 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
5248 if(res)
5249 BAD_ERROR("compressor_init failed\n");
5250
plougher4c99cb72007-06-14 21:46:31 +00005251 if(delete) {
plougher3d7e5182010-12-25 01:49:42 +00005252 int size;
Phillip Loughera45c9d22011-02-20 04:24:07 +00005253 void *comp_data = compressor_dump_options(comp, block_size,
5254 &size);
plougher3d7e5182010-12-25 01:49:42 +00005255
plougherdf6d8f02009-03-20 03:10:00 +00005256 printf("Creating %d.%d filesystem on %s, block size %d.\n",
plougher978f5882010-12-28 04:34:30 +00005257 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
plougher3d7e5182010-12-25 01:49:42 +00005258
plougher871c72a2010-12-25 04:17:27 +00005259 /*
5260 * store any compressor specific options after the superblock,
5261 * and set the COMP_OPT flag to show that the filesystem has
5262 * compressor specfic options
5263 */
plougher3d7e5182010-12-25 01:49:42 +00005264 if(comp_data) {
5265 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
5266
5267 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
plougher64e83fd2010-12-31 21:21:26 +00005268 write_destination(fd, sizeof(struct squashfs_super_block),
plougher29e2ace2010-12-31 08:50:00 +00005269 sizeof(c_byte), &c_byte);
plougher64e83fd2010-12-31 21:21:26 +00005270 write_destination(fd, sizeof(struct squashfs_super_block) +
plougher8e4dad42010-12-28 05:56:22 +00005271 sizeof(c_byte), size, comp_data);
plougher64e83fd2010-12-31 21:21:26 +00005272 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
plougher3d7e5182010-12-25 01:49:42 +00005273 + size;
5274 comp_opts = TRUE;
plougher3d7e5182010-12-25 01:49:42 +00005275 } else
plougher64e83fd2010-12-31 21:21:26 +00005276 bytes = sizeof(struct squashfs_super_block);
plougher4c99cb72007-06-14 21:46:31 +00005277 } else {
plougher360514a2009-03-30 03:01:38 +00005278 unsigned int last_directory_block, inode_dir_offset,
5279 inode_dir_file_size, root_inode_size,
plougher50b31762009-03-31 04:14:46 +00005280 inode_dir_start_block, uncompressed_data,
5281 compressed_data, inode_dir_inode_number,
5282 inode_dir_parent_inode;
plougher360514a2009-03-30 03:01:38 +00005283 unsigned int root_inode_start =
5284 SQUASHFS_INODE_BLK(sBlk.root_inode),
5285 root_inode_offset =
5286 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
plougher4c99cb72007-06-14 21:46:31 +00005287
plougher360514a2009-03-30 03:01:38 +00005288 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
5289 &data_cache, &directory_table,
5290 &directory_data_cache, &last_directory_block,
5291 &inode_dir_offset, &inode_dir_file_size,
5292 &root_inode_size, &inode_dir_start_block,
5293 &file_count, &sym_count, &dev_count, &dir_count,
5294 &fifo_count, &sock_count, &total_bytes,
5295 &total_inode_bytes, &total_directory_bytes,
plougher50b31762009-03-31 04:14:46 +00005296 &inode_dir_inode_number,
5297 &inode_dir_parent_inode, add_old_root_entry,
5298 &fragment_table, &inode_lookup_table)) == 0) {
plougher360514a2009-03-30 03:01:38 +00005299 ERROR("Failed to read existing filesystem - will not "
5300 "overwrite - ABORTING!\n");
plougher50b31762009-03-31 04:14:46 +00005301 ERROR("To force Mksquashfs to write to this block "
5302 "device or file use -noappend\n");
plougher324978d2006-02-27 04:53:29 +00005303 EXIT_MKSQUASHFS();
plougher1f413c82005-11-18 00:02:14 +00005304 }
plougher6f2a8262010-07-27 00:37:19 +00005305 if((fragments = sBlk.fragments)) {
plougher360514a2009-03-30 03:01:38 +00005306 fragment_table = realloc((char *) fragment_table,
plougher50b31762009-03-31 04:14:46 +00005307 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
plougher8ed84b92010-12-31 10:37:24 +00005308 * sizeof(struct squashfs_fragment_entry));
plougher6f2a8262010-07-27 00:37:19 +00005309 if(fragment_table == NULL)
5310 BAD_ERROR("Out of memory in save filesystem state\n");
5311 }
plougher1f413c82005-11-18 00:02:14 +00005312
plougher50b31762009-03-31 04:14:46 +00005313 printf("Appending to existing %d.%d filesystem on %s, block "
plougher978f5882010-12-28 04:34:30 +00005314 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
plougher360514a2009-03-30 03:01:38 +00005315 block_size);
plougher89c7a512010-12-15 08:35:51 +00005316 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
plougherbb988032009-08-06 08:46:34 +00005317 "-always-use-fragments,\n-exportable and -comp options "
5318 "ignored\n");
plougher360514a2009-03-30 03:01:38 +00005319 printf("\nIf appending is not wanted, please re-run with "
5320 "-noappend specified!\n\n");
plougher1f413c82005-11-18 00:02:14 +00005321
plougher360514a2009-03-30 03:01:38 +00005322 compressed_data = (inode_dir_offset + inode_dir_file_size) &
5323 ~(SQUASHFS_METADATA_SIZE - 1);
5324 uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
5325 (SQUASHFS_METADATA_SIZE - 1);
plougher1f413c82005-11-18 00:02:14 +00005326
5327 /* save original filesystem state for restoring ... */
5328 sfragments = fragments;
5329 sbytes = bytes;
5330 sinode_count = sBlk.inodes;
plougher23377982007-11-12 04:04:48 +00005331 scache_bytes = root_inode_offset + root_inode_size;
5332 sdirectory_cache_bytes = uncompressed_data;
ploughera2968ef2009-03-03 10:46:00 +00005333 sdata_cache = malloc(scache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005334 if(sdata_cache == NULL)
5335 BAD_ERROR("Out of memory in save filesystem state\n");
ploughera2968ef2009-03-03 10:46:00 +00005336 sdirectory_data_cache = malloc(sdirectory_cache_bytes);
plougher332e43d2010-07-21 01:18:30 +00005337 if(sdirectory_data_cache == NULL)
5338 BAD_ERROR("Out of memory in save filesystem state\n");
plougher1f413c82005-11-18 00:02:14 +00005339 memcpy(sdata_cache, data_cache, scache_bytes);
plougher360514a2009-03-30 03:01:38 +00005340 memcpy(sdirectory_data_cache, directory_data_cache +
5341 compressed_data, sdirectory_cache_bytes);
plougher1f413c82005-11-18 00:02:14 +00005342 sinode_bytes = root_inode_start;
plougher1f413c82005-11-18 00:02:14 +00005343 stotal_bytes = total_bytes;
5344 stotal_inode_bytes = total_inode_bytes;
plougher50b31762009-03-31 04:14:46 +00005345 stotal_directory_bytes = total_directory_bytes +
5346 compressed_data;
plougher1f413c82005-11-18 00:02:14 +00005347 sfile_count = file_count;
5348 ssym_count = sym_count;
5349 sdev_count = dev_count;
5350 sdir_count = dir_count + 1;
5351 sfifo_count = fifo_count;
5352 ssock_count = sock_count;
5353 sdup_files = dup_files;
plougher1b899fc2008-08-07 01:24:06 +00005354 sid_count = id_count;
plougher99ac0cc2007-10-29 03:17:10 +00005355 write_recovery_data(&sBlk);
plougher21f63b32010-07-18 03:59:04 +00005356 if(save_xattrs() == FALSE)
plougher16111452010-07-22 05:12:18 +00005357 BAD_ERROR("Failed to save xattrs from existing "
5358 "filesystem\n");
plougher1f413c82005-11-18 00:02:14 +00005359 restore = TRUE;
5360 if(setjmp(env))
5361 goto restore_filesystem;
5362 signal(SIGTERM, sighandler);
5363 signal(SIGINT, sighandler);
plougher0dd6f122009-03-29 21:43:57 +00005364 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
plougher1f413c82005-11-18 00:02:14 +00005365
plougher360514a2009-03-30 03:01:38 +00005366 /*
5367 * set the filesystem state up to be able to append to the
plougher50b31762009-03-31 04:14:46 +00005368 * original filesystem. The filesystem state differs depending
5369 * on whether we're appending to the original root directory, or
5370 * if the original root directory becomes a sub-directory
5371 * (root-becomes specified on command line, here root_name !=
5372 * NULL)
plougher1f413c82005-11-18 00:02:14 +00005373 */
5374 inode_bytes = inode_size = root_inode_start;
5375 directory_size = last_directory_block;
5376 cache_size = root_inode_offset + root_inode_size;
5377 directory_cache_size = inode_dir_offset + inode_dir_file_size;
5378 if(root_name) {
plougherca2c93f2008-08-15 08:34:57 +00005379 sdirectory_bytes = last_directory_block;
5380 sdirectory_compressed_bytes = 0;
plougherdf70c3e2006-01-27 09:34:13 +00005381 root_inode_number = inode_dir_parent_inode;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005382 inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00005383 directory_bytes = last_directory_block;
5384 directory_cache_bytes = uncompressed_data;
plougher360514a2009-03-30 03:01:38 +00005385 memmove(directory_data_cache, directory_data_cache +
5386 compressed_data, uncompressed_data);
plougher1f413c82005-11-18 00:02:14 +00005387 cache_bytes = root_inode_offset + root_inode_size;
plougher360514a2009-03-30 03:01:38 +00005388 add_old_root_entry(root_name, sBlk.root_inode,
5389 inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00005390 total_directory_bytes += compressed_data;
5391 dir_count ++;
5392 } else {
plougher360514a2009-03-30 03:01:38 +00005393 sdirectory_compressed_bytes = last_directory_block -
5394 inode_dir_start_block;
5395 sdirectory_compressed =
5396 malloc(sdirectory_compressed_bytes);
plougher332e43d2010-07-21 01:18:30 +00005397 if(sdirectory_compressed == NULL)
plougher16111452010-07-22 05:12:18 +00005398 BAD_ERROR("Out of memory in save filesystem "
5399 "state\n");
plougher360514a2009-03-30 03:01:38 +00005400 memcpy(sdirectory_compressed, directory_table +
5401 inode_dir_start_block,
5402 sdirectory_compressed_bytes);
plougherca2c93f2008-08-15 08:34:57 +00005403 sdirectory_bytes = inode_dir_start_block;
plougherdf70c3e2006-01-27 09:34:13 +00005404 root_inode_number = inode_dir_inode_number;
Phillip Lougher539c2b12012-07-30 20:14:52 +01005405 inode_no = sBlk.inodes + 1;
plougher1f413c82005-11-18 00:02:14 +00005406 directory_bytes = inode_dir_start_block;
5407 directory_cache_bytes = inode_dir_offset;
5408 cache_bytes = root_inode_offset;
5409 }
5410
plougher360514a2009-03-30 03:01:38 +00005411 inode_count = file_count + dir_count + sym_count + dev_count +
5412 fifo_count + sock_count;
plougher801ba6a2010-02-01 03:12:59 +00005413
5414 /*
5415 * The default use freelist before growing cache policy behaves
5416 * poorly with appending - with many deplicates the caches
5417 * do not grow due to the fact that large queues of outstanding
5418 * fragments/writer blocks do not occur, leading to small caches
5419 * and un-uncessary performance loss to frequent cache
5420 * replacement in the small caches. Therefore with appending
5421 * change the policy to grow the caches before reusing blocks
5422 * from the freelist
5423 */
5424 first_freelist = FALSE;
plougher1f413c82005-11-18 00:02:14 +00005425 }
5426
plougher05e50ef2007-10-23 12:34:20 +00005427 if(path || stickypath) {
plougherf9039c92007-10-22 03:54:16 +00005428 paths = init_subdir();
plougher05e50ef2007-10-23 12:34:20 +00005429 if(path)
5430 paths = add_subdir(paths, path);
5431 if(stickypath)
5432 paths = add_subdir(paths, stickypath);
plougherf9039c92007-10-22 03:54:16 +00005433 }
5434
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005435 dump_actions();
5436
plougher360514a2009-03-30 03:01:38 +00005437 if(delete && !keep_as_directory && source == 1 &&
5438 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005439 dir_scan(&inode, source_path[0], scan1_readdir);
plougher50b31762009-03-31 04:14:46 +00005440 else if(!keep_as_directory && source == 1 &&
5441 S_ISDIR(source_buf.st_mode))
plougher1f413c82005-11-18 00:02:14 +00005442 dir_scan(&inode, source_path[0], scan1_single_readdir);
5443 else
5444 dir_scan(&inode, "", scan1_encomp_readdir);
5445 sBlk.root_inode = inode;
5446 sBlk.inodes = inode_count;
5447 sBlk.s_magic = SQUASHFS_MAGIC;
5448 sBlk.s_major = SQUASHFS_MAJOR;
plougher978f5882010-12-28 04:34:30 +00005449 sBlk.s_minor = SQUASHFS_MINOR;
plougher1f413c82005-11-18 00:02:14 +00005450 sBlk.block_size = block_size;
5451 sBlk.block_log = block_log;
plougher89c7a512010-12-15 08:35:51 +00005452 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
plougherafae8252010-12-15 09:12:58 +00005453 always_use_fragments, duplicate_checking, exportable,
plougher3d7e5182010-12-25 01:49:42 +00005454 no_xattrs, comp_opts);
plougher1f413c82005-11-18 00:02:14 +00005455 sBlk.mkfs_time = time(NULL);
5456
5457restore_filesystem:
Phillip Lougher3b89ee82012-10-18 23:55:37 +01005458 if(progress)
plougherc9b11db2008-05-06 23:59:15 +00005459 disable_progress_bar();
plougherc9b11db2008-05-06 23:59:15 +00005460
plougher1f413c82005-11-18 00:02:14 +00005461 sBlk.fragments = fragments;
plougher875bfef2010-08-12 23:48:41 +00005462 if(!restoring) {
Phillip Lougher4bcb7f82011-08-28 03:18:26 +01005463 struct file_buffer **fragment = NULL;
5464 while((fragment = get_frag_action(fragment)))
5465 write_fragment(*fragment);
plougher2ea89142008-03-11 01:34:19 +00005466 unlock_fragments();
5467 pthread_mutex_lock(&fragment_mutex);
5468 while(fragments_outstanding) {
5469 pthread_mutex_unlock(&fragment_mutex);
5470 sched_yield();
5471 pthread_mutex_lock(&fragment_mutex);
5472 }
plougher5507dd92006-11-06 00:43:10 +00005473 queue_put(to_writer, NULL);
5474 if(queue_get(from_writer) != 0)
5475 EXIT_MKSQUASHFS();
5476 }
5477
ploughere6e0e1b2010-05-12 17:17:06 +00005478 sBlk.no_ids = id_count;
plougher1f413c82005-11-18 00:02:14 +00005479 sBlk.inode_table_start = write_inodes();
5480 sBlk.directory_table_start = write_directories();
5481 sBlk.fragment_table_start = write_fragment_table();
plougher360514a2009-03-30 03:01:38 +00005482 sBlk.lookup_table_start = exportable ? write_inode_lookup_table() :
5483 SQUASHFS_INVALID_BLK;
ploughere6e0e1b2010-05-12 17:17:06 +00005484 sBlk.id_table_start = write_id_table();
5485 sBlk.xattr_id_table_start = write_xattrs();
plougher1f413c82005-11-18 00:02:14 +00005486
plougher0e453652006-11-06 01:49:35 +00005487 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk.inode_table_start);
plougher50b31762009-03-31 04:14:46 +00005488 TRACE("sBlk->directory_table_start 0x%llx\n",
5489 sBlk.directory_table_start);
plougher0e453652006-11-06 01:49:35 +00005490 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk.fragment_table_start);
5491 if(exportable)
plougher360514a2009-03-30 03:01:38 +00005492 TRACE("sBlk->lookup_table_start 0x%llx\n",
5493 sBlk.lookup_table_start);
plougher1f413c82005-11-18 00:02:14 +00005494
plougher1f413c82005-11-18 00:02:14 +00005495 sBlk.bytes_used = bytes;
plougher9fca3462008-10-27 00:34:35 +00005496
plougher8c4b7b92009-07-30 04:47:52 +00005497 sBlk.compression = comp->id;
plougher1f413c82005-11-18 00:02:14 +00005498
plougher1f288f62009-02-21 03:05:52 +00005499 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk);
plougher29e2ace2010-12-31 08:50:00 +00005500 write_destination(fd, SQUASHFS_START, sizeof(sBlk), &sBlk);
plougher1f413c82005-11-18 00:02:14 +00005501
5502 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00005503 char temp[4096] = {0};
plougher0dd6f122009-03-29 21:43:57 +00005504 write_destination(fd, bytes, 4096 - i, temp);
plougher1f413c82005-11-18 00:02:14 +00005505 }
5506
plougher99ac0cc2007-10-29 03:17:10 +00005507 close(fd);
5508
plougher11e7b1b2009-09-11 12:10:58 +00005509 delete_pseudo_files();
5510
plougher99ac0cc2007-10-29 03:17:10 +00005511 if(recovery_file[0] != '\0')
5512 unlink(recovery_file);
5513
plougher10f7d572010-07-20 02:14:04 +00005514 total_bytes += total_inode_bytes + total_directory_bytes +
plougher64e83fd2010-12-31 21:21:26 +00005515 sizeof(struct squashfs_super_block) + total_xattr_bytes;
plougher1f413c82005-11-18 00:02:14 +00005516
plougher62542fb2009-08-06 08:43:08 +00005517 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5518 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5519 SQUASHFS_MINOR, comp->name, block_size);
plougherb99d7832010-05-19 01:57:34 +00005520 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
plougherdf6d8f02009-03-20 03:10:00 +00005521 noD ? "uncompressed" : "compressed", noI ? "uncompressed" :
5522 "compressed", no_fragments ? "no" : noF ? "uncompressed" :
plougher16111452010-07-22 05:12:18 +00005523 "compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5524 "compressed");
plougher50b31762009-03-31 04:14:46 +00005525 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5526 "not ");
plougher360514a2009-03-30 03:01:38 +00005527 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5528 bytes / (1024.0 * 1024.0));
plougher1f413c82005-11-18 00:02:14 +00005529 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5530 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5531 printf("Inode table size %d bytes (%.2f Kbytes)\n",
5532 inode_bytes, inode_bytes / 1024.0);
5533 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005534 ((float) inode_bytes / total_inode_bytes) * 100.0,
5535 total_inode_bytes);
plougher1f413c82005-11-18 00:02:14 +00005536 printf("Directory table size %d bytes (%.2f Kbytes)\n",
5537 directory_bytes, directory_bytes / 1024.0);
5538 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
plougher360514a2009-03-30 03:01:38 +00005539 ((float) directory_bytes / total_directory_bytes) * 100.0,
5540 total_directory_bytes);
ploughere6e0e1b2010-05-12 17:17:06 +00005541 if(total_xattr_bytes) {
5542 printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5543 xattr_bytes, xattr_bytes / 1024.0);
5544 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5545 ((float) xattr_bytes / total_xattr_bytes) * 100.0,
5546 total_xattr_bytes);
5547 }
plougher1f413c82005-11-18 00:02:14 +00005548 if(duplicate_checking)
plougher360514a2009-03-30 03:01:38 +00005549 printf("Number of duplicate files found %d\n", file_count -
5550 dup_files);
plougher1f413c82005-11-18 00:02:14 +00005551 else
5552 printf("No duplicate files removed\n");
5553 printf("Number of inodes %d\n", inode_count);
5554 printf("Number of files %d\n", file_count);
5555 if(!no_fragments)
5556 printf("Number of fragments %d\n", fragments);
5557 printf("Number of symbolic links %d\n", sym_count);
5558 printf("Number of device nodes %d\n", dev_count);
5559 printf("Number of fifo nodes %d\n", fifo_count);
5560 printf("Number of socket nodes %d\n", sock_count);
5561 printf("Number of directories %d\n", dir_count);
plougher1b899fc2008-08-07 01:24:06 +00005562 printf("Number of ids (unique uids + gids) %d\n", id_count);
plougher1f413c82005-11-18 00:02:14 +00005563 printf("Number of uids %d\n", uid_count);
5564
plougher1b899fc2008-08-07 01:24:06 +00005565 for(i = 0; i < id_count; i++) {
5566 if(id_table[i]->flags & ISA_UID) {
5567 struct passwd *user = getpwuid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005568 printf("\t%s (%d)\n", user == NULL ? "unknown" :
5569 user->pw_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005570 }
plougher1f413c82005-11-18 00:02:14 +00005571 }
5572
5573 printf("Number of gids %d\n", guid_count);
5574
plougher1b899fc2008-08-07 01:24:06 +00005575 for(i = 0; i < id_count; i++) {
5576 if(id_table[i]->flags & ISA_GID) {
5577 struct group *group = getgrgid(id_table[i]->id);
plougher360514a2009-03-30 03:01:38 +00005578 printf("\t%s (%d)\n", group == NULL ? "unknown" :
5579 group->gr_name, id_table[i]->id);
plougher1b899fc2008-08-07 01:24:06 +00005580 }
plougher1f413c82005-11-18 00:02:14 +00005581 }
plougher99ac0cc2007-10-29 03:17:10 +00005582
plougher1f413c82005-11-18 00:02:14 +00005583 return 0;
5584}