blob: 1a37f331e81148933294cab009eb8fb45a197111 [file] [log] [blame]
plougher1f413c82005-11-18 00:02:14 +00001/*
2 * Create a squashfs filesystem. This is a highly compressed read only filesystem.
3 *
plougher76959292006-01-24 08:56:38 +00004 * Copyright (c) 2002, 2003, 2004, 2005, 2006
plougherc2759612005-11-23 09:10:46 +00005 * Phillip Lougher <phillip@lougher.demon.co.uk>
plougher1f413c82005-11-18 00:02:14 +00006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * mksquashfs.c
22 */
23
24#define TRUE 1
plougher8cb05cd2005-12-11 23:32:35 +000025
plougher1f413c82005-11-18 00:02:14 +000026#include <pwd.h>
27#include <grp.h>
28#include <time.h>
29#include <unistd.h>
30#include <stdio.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <dirent.h>
36#include <string.h>
37#include <zlib.h>
plougher1f413c82005-11-18 00:02:14 +000038#include <stdlib.h>
39#include <signal.h>
40#include <setjmp.h>
41#include <sys/mman.h>
42
plougher68853292005-12-27 02:47:04 +000043#ifndef linux
plougher8cb05cd2005-12-11 23:32:35 +000044#define __BYTE_ORDER BYTE_ORDER
45#define __BIG_ENDIAN BIG_ENDIAN
46#define __LITTLE_ENDIAN LITTLE_ENDIAN
47#else
48#include <endian.h>
49#endif
50
plougher1f413c82005-11-18 00:02:14 +000051#include <squashfs_fs.h>
52#include "mksquashfs.h"
53#include "global.h"
54
55#ifdef SQUASHFS_TRACE
plougher8cb05cd2005-12-11 23:32:35 +000056#define TRACE(s, args...) do { \
57 printf("mksquashfs: "s, ## args); \
58 } while(0)
plougher1f413c82005-11-18 00:02:14 +000059#else
60#define TRACE(s, args...)
61#endif
62
63#define INFO(s, args...) do { if(!silent) printf("mksquashfs: "s, ## args); } while(0)
64#define ERROR(s, args...) do { fprintf(stderr, s, ## args); } while(0)
65#define EXIT_MKSQUASHFS() do { if(restore)\
66 restorefs();\
67 exit(1); } while(0)
68#define BAD_ERROR(s, args...) do {\
69 fprintf(stderr, "FATAL ERROR:" s, ##args);\
70 EXIT_MKSQUASHFS();\
71 } while(0)
72
73long long total_compressed = 0, total_uncompressed = 0;
74int fd;
75
76/* filesystem flags for building */
77int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
78int noI = 0, noD = 0, check_data = 0;
79int swap, silent = TRUE;
80long long global_uid = -1, global_gid = -1;
81
82/* superblock attributes */
83int block_size = SQUASHFS_FILE_SIZE, block_log;
84unsigned short uid_count = 0, guid_count = 0;
85squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
86int block_offset;
87int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
88
89/* write position within data section */
90long long bytes = 0, total_bytes = 0;
91
92/* in memory directory table - possibly compressed */
93char *directory_table = NULL;
94unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
95
96/* cached directory table */
97char *directory_data_cache = NULL;
98unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
99
100/* in memory inode table - possibly compressed */
101char *inode_table = NULL;
102unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
103
104/* cached inode table */
105char *data_cache = NULL;
106unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
107
108/* in memory directory data */
109#define I_COUNT_SIZE 128
110#define DIR_ENTRIES 32
111#define INODE_HASH_SIZE 65536
112#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
113#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
114
115struct cached_dir_index {
116 squashfs_dir_index index;
117 char *name;
118};
119
120struct directory {
121 unsigned int start_block;
122 unsigned int size;
123 unsigned char *buff;
124 unsigned char *p;
125 unsigned int entry_count;
126 unsigned char *entry_count_p;
127 unsigned int i_count;
128 unsigned int i_size;
129 struct cached_dir_index *index;
130 unsigned char *index_count_p;
131 unsigned int inode_number;
132};
133
134struct dir_info {
135 char *pathname;
136 unsigned int count;
137 unsigned int directory_count;
138 unsigned int current_count;
139 unsigned int byte_count;
140 char dir_is_ldir;
141 struct dir_ent *dir_ent;
142 struct dir_ent **list;
143 DIR *linuxdir;
144};
145
146struct dir_ent {
147 char *name;
148 char *pathname;
149 struct inode_info *inode;
150 struct dir_info *dir;
151 struct dir_info *our_dir;
152 struct old_root_entry_info *data;
153};
154
155struct inode_info {
156 unsigned int nlink;
157 struct stat buf;
158 squashfs_inode inode;
159 unsigned int type;
160 unsigned int inode_number;
161 struct inode_info *next;
162};
163
164struct inode_info *inode_info[INODE_HASH_SIZE];
165
166/* hash tables used to do fast duplicate searches in duplicate check */
167struct file_info *dupl[65536], *frag_dups[65536];
168int dup_files = 0;
169
170/* list of exclude dirs/files */
171struct exclude_info {
172 dev_t st_dev;
173 ino_t st_ino;
174};
175
176#define EXCLUDE_SIZE 8192
177int exclude = 0;
178struct exclude_info *exclude_paths = NULL;
179int excluded(char *filename, struct stat *buf);
180
181/* fragment block data structures */
182int fragments = 0;
183char fragment_data[SQUASHFS_FILE_SIZE];
184int fragment_size = 0;
185struct fragment {
186 unsigned int index;
187 int offset;
188 int size;
189};
190#define FRAG_SIZE 32768
191squashfs_fragment_entry *fragment_table = NULL;
192
193
194/* current inode number for directories and non directories */
195unsigned int dir_inode_no = 1;
196unsigned int inode_no = 0;
plougherdf70c3e2006-01-27 09:34:13 +0000197unsigned int root_inode_number = 0;
plougher1f413c82005-11-18 00:02:14 +0000198
199/* list of source dirs/files */
200int source = 0;
201char **source_path;
202
203/* list of root directory entries read from original filesystem */
204int old_root_entries = 0;
205struct old_root_entry_info {
206 char name[SQUASHFS_NAME_LEN + 1];
207 squashfs_inode inode;
208 int type;
209 int inode_number;
210};
211struct old_root_entry_info *old_root_entry;
212
213/* in memory file info */
214struct file_info {
plougherf9c72b12006-01-23 13:52:40 +0000215 long long bytes;
plougher1f413c82005-11-18 00:02:14 +0000216 unsigned short checksum;
217 long long start;
218 unsigned int *block_list;
219 struct file_info *next;
220 struct fragment *fragment;
221 unsigned short fragment_checksum;
222};
223
224/* count of how many times SIGINT or SIGQUIT has been sent */
225int interrupted = 0;
226
227/* restore orignal filesystem state if appending to existing filesystem is cancelled */
228jmp_buf env;
229char *sdata_cache, *sdirectory_data_cache;
230
231long long sbytes, stotal_bytes;
232
233unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
234 sdirectory_cache_bytes, suid_count, sguid_count,
235 stotal_inode_bytes, stotal_directory_bytes,
236 sinode_count, sfile_count, ssym_count, sdev_count,
237 sdir_count, sfifo_count, ssock_count, sdup_files;
238int sfragments;
239int restore = 0;
240
241/* flag whether destination file is a block device */
242int block_device = 0;
243
244/* flag indicating whether files are sorted using sort list(s) */
245int sorted = 0;
246
247/* structure to used to pass in a pointer or an integer
248 * to duplicate buffer read helper functions.
249 */
250struct duplicate_buffer_handle {
plougher8cb05cd2005-12-11 23:32:35 +0000251 char *ptr;
plougher1f413c82005-11-18 00:02:14 +0000252 long long start;
253};
254
plougherdf70c3e2006-01-27 09:34:13 +0000255void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type);
plougher1f413c82005-11-18 00:02:14 +0000256extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
257extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
plougherdf70c3e2006-01-27 09:34:13 +0000258 char **data_cache, char **cdirectory_table, char **directory_data_cache,
259 unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
260 unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
261 int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
262 unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
263 long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
264 unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
265 void (push_directory_entry)(char *, squashfs_inode, int, int),
plougher1f413c82005-11-18 00:02:14 +0000266 squashfs_fragment_entry **fragment_table);
267int get_sorted_inode(squashfs_inode *inode, struct stat *buf);
268int read_sort_file(char *filename, int source, char *source_path[]);
269void sort_files_and_write(int source, char *source_path[]);
plougherf9c72b12006-01-23 13:52:40 +0000270struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes);
plougher1f413c82005-11-18 00:02:14 +0000271struct dir_info *dir_scan1(char *, int (_readdir)(char *, char *, struct dir_info *));
272
273#define FALSE 0
274
275#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
276
277
278void restorefs()
279{
280 ERROR("Exiting - restoring original filesystem!\n\n");
281 bytes = sbytes;
282 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
283 memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
284 inode_bytes = sinode_bytes;
285 directory_bytes = sdirectory_bytes;
286 uid_count = suid_count;
287 guid_count = sguid_count;
288 total_bytes = stotal_bytes;
289 total_inode_bytes = stotal_inode_bytes;
290 total_directory_bytes = stotal_directory_bytes;
291 inode_count = sinode_count;
292 file_count = sfile_count;
293 sym_count = ssym_count;
294 dev_count = sdev_count;
295 dir_count = sdir_count;
296 fifo_count = sfifo_count;
297 sock_count = ssock_count;
298 dup_files = sdup_files;
299 fragments = sfragments;
300 fragment_size = 0;
301 longjmp(env, 1);
302}
303
304
305void sighandler()
306{
307 if(interrupted == 1)
308 restorefs();
309 else {
310 ERROR("Interrupting will restore original filesystem!\n");
311 ERROR("Interrupt again to quit\n");
312 interrupted ++;
313 }
314}
315
316
317unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
318{
319 unsigned long c_byte = block_size << 1;
320 unsigned int res;
321
plougher8cb05cd2005-12-11 23:32:35 +0000322 if(!uncompressed && (res = compress2((unsigned char *) d, &c_byte, (unsigned char *) s, size, 9)) != Z_OK) {
plougher1f413c82005-11-18 00:02:14 +0000323 if(res == Z_MEM_ERROR)
324 BAD_ERROR("zlib::compress failed, not enough memory\n");
325 else if(res == Z_BUF_ERROR)
326 BAD_ERROR("zlib::compress failed, not enough room in output buffer\n");
327 else
328 BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
329 return 0;
330 }
331
332 if(uncompressed || c_byte >= size) {
333 memcpy(d, s, size);
334 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
335 }
336
337 return (unsigned int) c_byte;
338}
339
340
341squashfs_base_inode_header *get_inode(int req_size)
342{
343 int data_space;
344 unsigned short c_byte;
345
346 while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
347 if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
348 if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
349 == NULL) {
350 goto failed;
351 }
352 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
353 }
354
355 c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
356 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
357 TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
358 if(!swap)
359 memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
360 else
361 SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
362 if(check_data)
363 *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
364 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
365 total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
366 memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
367 cache_bytes -= SQUASHFS_METADATA_SIZE;
368 }
369
370 data_space = (cache_size - cache_bytes);
371 if(data_space < req_size) {
372 int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
373
374 if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
375 goto failed;
376 }
377 cache_size += realloc_size;
378 }
379
380 cache_bytes += req_size;
381
382 return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
383
384failed:
385 BAD_ERROR("Out of memory in inode table reallocation!\n");
386}
387
388
389void read_bytes(int fd, long long byte, int bytes, char *buff)
390{
391 off_t off = byte;
392
393 if(lseek(fd, off, SEEK_SET) == -1) {
394 perror("Lseek on destination failed");
395 EXIT_MKSQUASHFS();
396 }
397
398 if(read(fd, buff, bytes) == -1) {
399 perror("Read on destination failed");
400 EXIT_MKSQUASHFS();
401 }
402}
403
404
405void write_bytes(int fd, long long byte, int bytes, char *buff)
406{
407 off_t off = byte;
408/*
409 if(off + bytes > ((long long)1<<32) - 1 )
410 BAD_ERROR("Filesystem greater than maximum size 2^32 - 1\n");
411*/
412
413 if(lseek(fd, off, SEEK_SET) == -1) {
414 perror("Lseek on destination failed");
415 EXIT_MKSQUASHFS();
416 }
417
418 if(write(fd, buff, bytes) == -1) {
419 perror("Write on destination failed");
420 EXIT_MKSQUASHFS();
421 }
422}
423
424
425long long write_inodes()
426{
427 unsigned short c_byte;
428 int avail_bytes;
429 char *datap = data_cache;
430 long long start_bytes = bytes;
431
432 while(cache_bytes) {
433 if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
434 if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
435 BAD_ERROR("Out of memory in inode table reallocation!\n");
436 }
437 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
438 }
439 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
440 c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
441 TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
442 if(!swap)
443 memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
444 else
445 SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
446 if(check_data)
447 *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
448 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
449 total_inode_bytes += avail_bytes + block_offset;
450 datap += avail_bytes;
451 cache_bytes -= avail_bytes;
452 }
453
454 write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
455 bytes += inode_bytes;
456
457 return start_bytes;
458}
459
460
461long long write_directories()
462{
463 unsigned short c_byte;
464 int avail_bytes;
465 char *directoryp = directory_data_cache;
466 long long start_bytes = bytes;
467
468 while(directory_cache_bytes) {
469 if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
470 if((directory_table = (char *) realloc(directory_table, directory_size +
471 ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
472 BAD_ERROR("Out of memory in directory table reallocation!\n");
473 }
474 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
475 }
476 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
477 c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
478 TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
479 if(!swap)
480 memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
481 else
482 SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
483 if(check_data)
484 *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
485 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
486 total_directory_bytes += avail_bytes + block_offset;
487 directoryp += avail_bytes;
488 directory_cache_bytes -= avail_bytes;
489 }
490 write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
491 bytes += directory_bytes;
492
493 return start_bytes;
494}
495
496
497unsigned int get_uid(squashfs_uid uid)
498{
499 int i;
500
501 for(i = 0; (i < uid_count) && uids[i] != uid; i++);
502 if(i == uid_count) {
503 if(uid_count == SQUASHFS_UIDS) {
504 ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
505 i = 0;
506 } else
507 uids[uid_count++] = uid;
508 }
509
510 return i;
511}
512
513
514unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
515{
516 int i;
517
518 if(uid == guid)
519 return SQUASHFS_GUIDS;
520
521 for(i = 0; (i < guid_count) && guids[i] != guid; i++);
522 if(i == guid_count) {
523 if(guid_count == SQUASHFS_GUIDS) {
524 ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
525 return SQUASHFS_GUIDS;
526 } else
527 guids[guid_count++] = guid;
528 }
529
530 return i;
531}
532
533
plougher751d4972005-12-21 04:23:40 +0000534int create_inode(squashfs_inode *i_no, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in)
plougher1f413c82005-11-18 00:02:14 +0000535{
536 struct stat *buf = &dir_ent->inode->buf;
537 squashfs_inode_header inode_header;
538 squashfs_base_inode_header *inode, *base = &inode_header.base;
539 char *filename = dir_ent->pathname;
540 int nlink = dir_ent->inode->nlink;
541 int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
542
543 base->mode = SQUASHFS_MODE(buf->st_mode);
544 base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid);
545 base->inode_type = type;
546 base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid);
547 base->mtime = buf->st_mtime;
548 base->inode_number = inode_number;
549
550 if(type == SQUASHFS_FILE_TYPE) {
551 int i;
552 squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
553
554 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
555 inodep = (squashfs_reg_inode_header *) inode;
556 /*reg->atime = buf.st_mtime;
557 reg->ctime = buf.st_mtime;*/
558 reg->file_size = byte_size;
559 reg->start_block = start_block;
560 reg->fragment = fragment->index;
561 reg->offset = fragment->offset;
562 if(!swap) {
563 memcpy(inodep, reg, sizeof(*reg));
564 memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
565 } else {
566 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
567 SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
568 }
plougher751d4972005-12-21 04:23:40 +0000569 TRACE("File inode, file_size %d, start_block %llx, blocks %d, fragment %d, offset %d, size %d\n", (int) byte_size,
plougher1f413c82005-11-18 00:02:14 +0000570 start_block, offset, fragment->index, fragment->offset, fragment->size);
571 for(i = 0; i < offset; i++)
572 TRACE("Block %d, size %d\n", i, block_list[i]);
573 }
574 else if(type == SQUASHFS_LREG_TYPE) {
575 int i;
576 squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep;
577
578 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
579 inodep = (squashfs_lreg_inode_header *) inode;
580 /*reg->atime = buf.st_mtime;
581 reg->ctime = buf.st_mtime;*/
582 reg->nlink = nlink;
583 reg->file_size = byte_size;
584 reg->start_block = start_block;
585 reg->fragment = fragment->index;
586 reg->offset = fragment->offset;
587 if(!swap) {
588 memcpy(inodep, reg, sizeof(*reg));
589 memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
590 } else {
591 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep);
592 SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
593 }
plougher751d4972005-12-21 04:23:40 +0000594 TRACE("Long file inode, file_size %lld, start_block %llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size,
plougher1f413c82005-11-18 00:02:14 +0000595 start_block, offset, fragment->index, fragment->offset, fragment->size, nlink);
596 for(i = 0; i < offset; i++)
597 TRACE("Block %d, size %d\n", i, block_list[i]);
598 }
599 else if(type == SQUASHFS_LDIR_TYPE) {
600 int i;
601 unsigned char *p;
602 squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep;
603 struct cached_dir_index *index = dir_in->index;
604 unsigned int i_count = dir_in->i_count;
605 unsigned int i_size = dir_in->i_size;
606
607 if(byte_size >= 1 << 27)
608 BAD_ERROR("directory greater than 2^27-1 bytes!\n");
609
610 inode = get_inode(sizeof(*dir) + i_size);
611 inodep = (squashfs_ldir_inode_header *) inode;
612 dir->inode_type = SQUASHFS_LDIR_TYPE;
613 /*dir->atime = buf.st_mtime;
614 dir->ctime = buf.st_mtime;*/
615 dir->nlink = dir_ent->dir->directory_count + 2;
616 dir->file_size = byte_size;
617 dir->offset = offset;
618 dir->start_block = start_block;
619 dir->i_count = i_count;
620 dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
621
622 if(!swap)
623 memcpy(inode, dir, sizeof(*dir));
624 else
625 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
626 p = (unsigned char *) inodep->index;
627 for(i = 0; i < i_count; i++) {
628 if(!swap)
629 memcpy(p, &index[i].index, sizeof(squashfs_dir_index));
630 else
631 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
632 memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1);
633 p += sizeof(squashfs_dir_index) + index[i].index.size + 1;
634 }
plougher751d4972005-12-21 04:23:40 +0000635 TRACE("Long directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size,
plougher1f413c82005-11-18 00:02:14 +0000636 start_block, offset, dir_ent->dir->directory_count + 2);
637 }
638 else if(type == SQUASHFS_DIR_TYPE) {
639 squashfs_dir_inode_header *dir = &inode_header.dir;
640
641 inode = get_inode(sizeof(*dir));
642 /*dir->atime = buf.st_mtime;
643 dir->ctime = buf.st_mtime;*/
644 dir->nlink = dir_ent->dir->directory_count + 2;
645 dir->file_size = byte_size;
646 dir->offset = offset;
647 dir->start_block = start_block;
648 dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
649 if(!swap)
650 memcpy(inode, dir, sizeof(*dir));
651 else
652 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
plougher751d4972005-12-21 04:23:40 +0000653 TRACE("Directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size,
plougher1f413c82005-11-18 00:02:14 +0000654 start_block, offset, dir_ent->dir->directory_count + 2);
655 }
656 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
657 squashfs_dev_inode_header *dev = &inode_header.dev;
658
659 inode = get_inode(sizeof(*dev));
660 dev->nlink = nlink;
661 dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) |
662 (minor(buf->st_rdev) & 0xff));
663 if(!swap)
664 memcpy(inode, dev, sizeof(*dev));
665 else
666 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
667 TRACE("Device inode, rdev %x, nlink %d\n", dev->rdev, nlink);
668 }
669 else if(type == SQUASHFS_SYMLINK_TYPE) {
670 squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
671 int byte;
672 char buff[65536];
673
674 if((byte = readlink(filename, buff, 65536)) == -1) {
675 perror("Error in reading symbolic link, skipping...");
676 return FALSE;
677 }
678
679 if(byte == 65536) {
680 ERROR("Symlink is greater than 65536 bytes! skipping...");
681 return FALSE;
682 }
683
684 inode = get_inode(sizeof(*symlink) + byte);
685 symlink->nlink = nlink;
686 inodep = (squashfs_symlink_inode_header *) inode;
687 symlink->symlink_size = byte;
688 if(!swap)
689 memcpy(inode, symlink, sizeof(*symlink));
690 else
691 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
692 strncpy(inodep->symlink, buff, byte);
693 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink);
694 }
695 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
696 squashfs_ipc_inode_header *ipc = &inode_header.ipc;
697
698 inode = get_inode(sizeof(*ipc));
699 ipc->nlink = nlink;
700 if(!swap)
701 memcpy(inode, ipc, sizeof(*ipc));
702 else
703 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
704 TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
705 } else
706 return FALSE;
707
708 *i_no = MKINODE(inode);
709 inode_count ++;
710
711 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid);
712
713 return TRUE;
714}
715
716
717void scan2_init_dir(struct directory *dir)
718{
plougher8cb05cd2005-12-11 23:32:35 +0000719 if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000720 BAD_ERROR("Out of memory allocating directory buffer\n");
721 }
722
723 dir->size = SQUASHFS_METADATA_SIZE;
724 dir->p = dir->index_count_p = dir->buff;
725 dir->entry_count = 256;
726 dir->entry_count_p = NULL;
727 dir->index = NULL;
728 dir->i_count = dir->i_size = 0;
729}
730
731
732void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir)
733{
plougher8cb05cd2005-12-11 23:32:35 +0000734 unsigned char *buff;
plougher1f413c82005-11-18 00:02:14 +0000735 squashfs_dir_entry idir, *idirp;
736 unsigned int start_block = inode >> 16;
737 unsigned int offset = inode & 0xffff;
738 unsigned int size;
739
740 if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
741 size = SQUASHFS_NAME_LEN;
742 ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
743 }
744
745 if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
plougher8cb05cd2005-12-11 23:32:35 +0000746 if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) {
plougher1f413c82005-11-18 00:02:14 +0000747 BAD_ERROR("Out of memory reallocating directory buffer\n");
748 }
749
750 dir->p = (dir->p - dir->buff) + buff;
751 if(dir->entry_count_p)
752 dir->entry_count_p = (dir->entry_count_p - dir->buff + buff);
753 dir->index_count_p = dir->index_count_p - dir->buff + buff;
754 dir->buff = buff;
755 }
756
757 if(dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long) inode_number - dir->inode_number) > 32767 || ((long long) inode_number - dir->inode_number) < - 32768) {
758 if(dir->entry_count_p) {
759 squashfs_dir_header dir_header;
760
761 if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) {
762 if(dir->i_count % I_COUNT_SIZE == 0)
763 if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL)
764 BAD_ERROR("Out of memory in directory index table reallocation!\n");
765 dir->index[dir->i_count].index.index = dir->p - dir->buff;
766 dir->index[dir->i_count].index.size = size - 1;
767 dir->index[dir->i_count++].name = name;
768 dir->i_size += sizeof(squashfs_dir_index) + size;
769 dir->index_count_p = dir->p;
770 }
771
772 dir_header.count = dir->entry_count - 1;
773 dir_header.start_block = dir->start_block;
774 dir_header.inode_number = dir->inode_number;
775 if(!swap)
776 memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
777 else
778 SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
779
780 }
781
782
783 dir->entry_count_p = dir->p;
784 dir->start_block = start_block;
785 dir->entry_count = 0;
786 dir->inode_number = inode_number;
787 dir->p += sizeof(squashfs_dir_header);
788 }
789
790 idirp = (squashfs_dir_entry *) dir->p;
791 idir.offset = offset;
792 idir.type = type;
793 idir.size = size - 1;
794 idir.inode_number = ((long long) inode_number - dir->inode_number);
795 if(!swap)
796 memcpy(idirp, &idir, sizeof(idir));
797 else
798 SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
799 strncpy(idirp->name, name, size);
800 dir->p += sizeof(squashfs_dir_entry) + size;
801 dir->entry_count ++;
802}
803
804
805int write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir)
806{
807 unsigned int dir_size = dir->p - dir->buff;
808 int data_space = (directory_cache_size - directory_cache_bytes);
809 unsigned int directory_block, directory_offset, i_count, index;
810 unsigned short c_byte;
811
812 if(data_space < dir_size) {
813 int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
814
815 if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
816 goto failed;
817 }
818 directory_cache_size += realloc_size;
819 }
820
821 if(dir_size) {
822 squashfs_dir_header dir_header;
823
824 dir_header.count = dir->entry_count - 1;
825 dir_header.start_block = dir->start_block;
826 dir_header.inode_number = dir->inode_number;
827 if(!swap)
828 memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
829 else
830 SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
831 memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
832 }
833 directory_offset = directory_cache_bytes;
834 directory_block = directory_bytes;
835 directory_cache_bytes += dir_size;
836 i_count = 0;
837 index = SQUASHFS_METADATA_SIZE - directory_offset;
838
839 while(1) {
840 while(i_count < dir->i_count && dir->index[i_count].index.index < index)
841 dir->index[i_count++].index.start_block = directory_bytes;
842 index += SQUASHFS_METADATA_SIZE;
843
844 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
845 break;
846
847 if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
848 if((directory_table = (char *) realloc(directory_table,
849 directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
850 goto failed;
851 }
852 directory_size += SQUASHFS_METADATA_SIZE << 1;
853 }
854
855 c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
856 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
857 TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
858 if(!swap)
859 memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
860 else
861 SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
862 if(check_data)
863 *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
864 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
865 total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
866 memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
867 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
868 }
869
870 if(dir_info->dir_is_ldir) {
871 if(create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir) == FALSE)
872 return FALSE;
873 } else {
874 if(create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL) == FALSE)
875 return FALSE;
876 }
877
878#ifdef SQUASHFS_TRACE
879 if(!swap) {
880 unsigned char *dirp;
881 int count;
882
883 TRACE("Directory contents of inode 0x%llx\n", *inode);
884 dirp = dir->buff;
885 while(dirp < dir->p) {
886 char buffer[SQUASHFS_NAME_LEN + 1];
887 squashfs_dir_entry idir, *idirp;
888 squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
889 count = dirh->count + 1;
890 dirp += sizeof(squashfs_dir_header);
891
892 TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
893
894 while(count--) {
895 idirp = (squashfs_dir_entry *) dirp;
896 memcpy((char *) &idir, (char *) idirp, sizeof(idir));
897 strncpy(buffer, idirp->name, idir.size + 1);
898 buffer[idir.size + 1] = '\0';
899 TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
900 idir.offset, idir.type);
901 dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
902 }
903 }
904 }
905#endif
906 dir_count ++;
907
908 return TRUE;
909
910failed:
911 BAD_ERROR("Out of memory in directory table reallocation!\n");
912}
913
914
915char *get_fragment(char *buffer, struct fragment *fragment)
916{
917 squashfs_fragment_entry *disk_fragment = &fragment_table[fragment->index];
918 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
919
920 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
921 int res;
plougher8cb05cd2005-12-11 23:32:35 +0000922 unsigned long bytes = block_size;
plougher1f413c82005-11-18 00:02:14 +0000923 char cbuffer[block_size];
924
925 read_bytes(fd, disk_fragment->start_block, size, cbuffer);
926
plougher8cb05cd2005-12-11 23:32:35 +0000927 if((res = uncompress((unsigned char *) buffer, &bytes, (const unsigned char *) cbuffer, size)) != Z_OK) {
plougher1f413c82005-11-18 00:02:14 +0000928 if(res == Z_MEM_ERROR)
929 BAD_ERROR("zlib::uncompress failed, not enough memory\n");
930 else if(res == Z_BUF_ERROR)
931 BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n");
932 else
933 BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res);
934 }
935 } else
936 read_bytes(fd, disk_fragment->start_block, size, buffer);
937
938 return buffer + fragment->offset;
939}
940
941
942void write_fragment()
943{
944 int compressed_size;
plougher8cb05cd2005-12-11 23:32:35 +0000945 char buffer[block_size << 1];
plougher1f413c82005-11-18 00:02:14 +0000946
947 if(fragment_size == 0)
948 return;
949
950 if(fragments % FRAG_SIZE == 0)
951 if((fragment_table = (squashfs_fragment_entry *) realloc(fragment_table, (fragments + FRAG_SIZE) * sizeof(squashfs_fragment_entry))) == NULL)
952 BAD_ERROR("Out of memory in fragment table\n");
953 fragment_table[fragments].size = mangle(buffer, fragment_data, fragment_size, block_size, noF, 1);
954 fragment_table[fragments].start_block = bytes;
955 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[fragments].size);
956 write_bytes(fd, bytes, compressed_size, buffer);
957 bytes += compressed_size;
958 total_uncompressed += fragment_size;
959 total_compressed += compressed_size;
960 TRACE("Writing fragment %d, uncompressed size %d, compressed size %d\n",fragments, fragment_size, compressed_size);
961 fragments ++;
962 fragment_size = 0;
963}
964
965
966static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
967struct fragment *get_and_fill_fragment(char *buff, int size)
968{
969 struct fragment *ffrg;
970
971 if(size == 0)
972 return &empty_fragment;
973
974 if(fragment_size + size > block_size)
975 write_fragment();
976
977 if((ffrg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
978 BAD_ERROR("Out of memory in fragment block allocation!\n");
979
980 ffrg->index = fragments;
981 ffrg->offset = fragment_size;
982 ffrg->size = size;
983 memcpy(fragment_data + fragment_size, buff, size);
984 fragment_size += size;
985
986 return ffrg;
987}
988
989
990long long write_fragment_table()
991{
992 long long start_bytes;
993 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments),
994 meta_blocks = SQUASHFS_FRAGMENT_INDEXES(fragments);
995 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2], buffer[frag_bytes];
996 squashfs_fragment_entry *p = (squashfs_fragment_entry *) buffer;
997 unsigned short c_byte;
998 int i, compressed_size;
999 squashfs_fragment_index list[meta_blocks];
1000
1001 TRACE("write_fragment_table: fragments %d, frag_bytes %d, meta_blocks %d\n", fragments, frag_bytes, meta_blocks);
1002 for(i = 0; i < fragments; i++, p++) {
1003 TRACE("write_fragment_table: fragment %d, start_block %llx, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size);
1004 if(!swap)
1005 memcpy(p, &fragment_table[i], sizeof(squashfs_fragment_entry));
1006 else
1007 SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p);
1008 }
1009
1010 for(i = 0; i < meta_blocks; i++) {
1011 int avail_bytes = i == meta_blocks - 1 ? frag_bytes % SQUASHFS_METADATA_SIZE : SQUASHFS_METADATA_SIZE;
1012 c_byte = mangle(cbuffer + block_offset, buffer + i * SQUASHFS_METADATA_SIZE , avail_bytes, SQUASHFS_METADATA_SIZE, noF, 0);
1013 if(!swap)
1014 memcpy(cbuffer, &c_byte, sizeof(unsigned short));
1015 else
1016 SQUASHFS_SWAP_SHORTS((&c_byte), cbuffer, 1);
1017 if(check_data)
1018 *((unsigned char *)(cbuffer + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
1019 list[i] = bytes;
1020 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
1021 write_bytes(fd, bytes, compressed_size, cbuffer);
1022 bytes += compressed_size;
1023 }
1024
1025 if(!swap)
1026 write_bytes(fd, bytes, sizeof(list), (char *) list);
1027 else {
1028 squashfs_fragment_index slist[meta_blocks];
1029 SQUASHFS_SWAP_FRAGMENT_INDEXES(list, slist, meta_blocks);
1030 write_bytes(fd, bytes, sizeof(list), (char *) slist);
1031 }
1032
1033 start_bytes = bytes;
1034 bytes += sizeof(list);
1035
1036 return start_bytes;
1037}
1038
1039
plougher8cb05cd2005-12-11 23:32:35 +00001040char *read_from_buffer(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001041{
plougher8cb05cd2005-12-11 23:32:35 +00001042 char *v = handle->ptr;
plougher1f413c82005-11-18 00:02:14 +00001043 handle->ptr += avail_bytes;
1044 return v;
1045}
1046
1047
1048char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
plougher8cb05cd2005-12-11 23:32:35 +00001049char *read_from_file(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
plougher1f413c82005-11-18 00:02:14 +00001050{
1051 read_bytes(fd, handle->start, avail_bytes, read_from_file_buffer);
1052 handle->start += avail_bytes;
1053 return read_from_file_buffer;
1054}
1055
1056
1057/*
1058 * Compute 16 bit BSD checksum over the data
1059 */
plougherf9c72b12006-01-23 13:52:40 +00001060unsigned short get_checksum(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *handle, long long l)
plougher1f413c82005-11-18 00:02:14 +00001061{
1062 unsigned short chksum = 0;
1063 unsigned int bytes = 0;
1064 unsigned char *b;
1065 struct duplicate_buffer_handle position = *handle;
1066
1067 while(l) {
1068 bytes = l > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : l;
1069 l -= bytes;
plougher8cb05cd2005-12-11 23:32:35 +00001070 b = (unsigned char *) get_next_file_block(&position, bytes);
plougher1f413c82005-11-18 00:02:14 +00001071 while(bytes--) {
1072 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1073 chksum += *b++;
1074 }
1075 }
1076
1077 return chksum;
1078}
1079
1080
1081int cached_frag = -1;
plougher4c9b0902006-01-25 09:16:18 +00001082void add_file(long long start, long long file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes)
plougher1f413c82005-11-18 00:02:14 +00001083{
1084 struct fragment *frg;
1085 struct file_info *dupl_ptr;
1086 char *datap;
1087 struct duplicate_buffer_handle handle;
plougher058eae42006-01-30 14:27:44 +00001088 unsigned int *block_list = block_listp;
1089
plougher1f413c82005-11-18 00:02:14 +00001090 if(!duplicate_checking)
1091 return;
1092
1093 if((frg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
1094 BAD_ERROR("Out of memory in fragment block allocation!\n");
1095
1096 frg->index = fragment;
1097 frg->offset = offset;
1098 frg->size = bytes;
1099 if(fragment == cached_frag || fragment == SQUASHFS_INVALID_FRAG)
1100 datap = fragment_data + offset;
1101 else
1102 datap = get_fragment(fragment_data, frg);
1103 handle.start = start;
1104 if((dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &frg, datap, bytes)) != NULL)
1105 dupl_ptr->fragment = frg;
plougher058eae42006-01-30 14:27:44 +00001106 else
1107 free(block_list);
plougher1f413c82005-11-18 00:02:14 +00001108 cached_frag = fragment;
1109}
1110
1111
1112char cached_fragment[SQUASHFS_FILE_SIZE];
1113int cached_frag1 = -1;
1114
plougherf9c72b12006-01-23 13:52:40 +00001115struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes)
plougher1f413c82005-11-18 00:02:14 +00001116{
1117 unsigned short checksum = get_checksum(get_next_file_block, file_start, bytes);
1118 struct duplicate_buffer_handle handle = { frag_data, 0 };
1119 unsigned short fragment_checksum = get_checksum(read_from_buffer, &handle, frag_bytes);
1120 struct file_info *dupl_ptr = bytes ? dupl[checksum] : frag_dups[fragment_checksum];
1121
1122
1123 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
1124 if(bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size && fragment_checksum == dupl_ptr->fragment_checksum) {
plougher8cb05cd2005-12-11 23:32:35 +00001125 char buffer1[SQUASHFS_FILE_MAX_SIZE];
plougherf9c72b12006-01-23 13:52:40 +00001126 long long dup_bytes = dupl_ptr->bytes;
plougher1f413c82005-11-18 00:02:14 +00001127 long long dup_start = dupl_ptr->start;
1128 struct duplicate_buffer_handle position = *file_start;
plougher8cb05cd2005-12-11 23:32:35 +00001129 char *buffer;
plougher1f413c82005-11-18 00:02:14 +00001130 while(dup_bytes) {
1131 int avail_bytes = dup_bytes > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : dup_bytes;
1132
1133 buffer = get_next_file_block(&position, avail_bytes);
1134 read_bytes(fd, dup_start, avail_bytes, buffer1);
1135 if(memcmp(buffer, buffer1, avail_bytes) != 0)
1136 break;
1137 dup_bytes -= avail_bytes;
1138 dup_start += avail_bytes;
1139 }
1140 if(dup_bytes == 0) {
1141 char *fragment_buffer1;
1142
1143 if(dupl_ptr->fragment->index == fragments || dupl_ptr->fragment->index == SQUASHFS_INVALID_FRAG)
1144 fragment_buffer1 = fragment_data + dupl_ptr->fragment->offset;
1145 else if(dupl_ptr->fragment->index == cached_frag1)
1146 fragment_buffer1 = cached_fragment + dupl_ptr->fragment->offset;
1147 else {
1148 fragment_buffer1 = get_fragment(cached_fragment, dupl_ptr->fragment);
1149 cached_frag1 = dupl_ptr->fragment->index;
1150 }
1151
1152 if(frag_bytes == 0 || memcmp(frag_data, fragment_buffer1, frag_bytes) == 0) {
plougherf9c72b12006-01-23 13:52:40 +00001153 TRACE("Found duplicate file, start 0x%llx, size %lld, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start,
plougher1f413c82005-11-18 00:02:14 +00001154 dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum);
1155 *block_list = dupl_ptr->block_list;
1156 *start = dupl_ptr->start;
1157 *fragment = dupl_ptr->fragment;
1158 return 0;
1159 }
1160 }
1161 }
1162
1163
1164 if((dupl_ptr = (struct file_info *) malloc(sizeof(struct file_info))) == NULL) {
1165 BAD_ERROR("Out of memory in dup_files allocation!\n");
1166 }
1167
1168 dupl_ptr->bytes = bytes;
1169 dupl_ptr->checksum = checksum;
1170 dupl_ptr->start = *start;
1171 dupl_ptr->fragment_checksum = fragment_checksum;
plougherf9c72b12006-01-23 13:52:40 +00001172 dupl_ptr->block_list = *block_list;
1173
plougher1f413c82005-11-18 00:02:14 +00001174 dup_files ++;
1175 if(bytes) {
1176 dupl_ptr->next = dupl[checksum];
1177 dupl[checksum] = dupl_ptr;
1178 } else {
1179 dupl_ptr->next = frag_dups[fragment_checksum];
1180 frag_dups[fragment_checksum] = dupl_ptr;
1181 }
1182
1183 return dupl_ptr;
1184}
1185
1186
1187#define MINALLOCBYTES (1024 * 1024)
1188int write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *duplicate_file)
1189{
plougherf9c72b12006-01-23 13:52:40 +00001190 int block = 0, i, file, whole_file = 1, status;
1191 unsigned int c_byte, frag_bytes;
1192 long long bbytes, file_bytes = 0, start;
1193 char buff[block_size], *c_buffer = NULL, *filename = dir_ent->pathname;
plougher1f413c82005-11-18 00:02:14 +00001194 struct fragment *fragment;
1195 struct file_info *dupl_ptr = NULL;
1196 struct duplicate_buffer_handle handle;
plougherf9c72b12006-01-23 13:52:40 +00001197 long long read_size = (size > SQUASHFS_MAX_FILE_SIZE) ? SQUASHFS_MAX_FILE_SIZE : size;
1198 int blocks = (read_size + block_size - 1) >> block_log, allocated_blocks = blocks;
1199 unsigned int *block_list, *block_listp;
1200
1201 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL)
1202 BAD_ERROR("Out of memory allocating block_list\n");
1203 block_listp = block_list;
plougher1f413c82005-11-18 00:02:14 +00001204
1205 if(!no_fragments && (read_size < block_size || always_use_fragments)) {
1206 allocated_blocks = blocks = read_size >> block_log;
1207 frag_bytes = read_size % block_size;
1208 } else
1209 frag_bytes = 0;
1210
1211 if(size > read_size)
1212 ERROR("file %s truncated to %lld bytes\n", filename, SQUASHFS_MAX_FILE_SIZE);
1213
1214 total_bytes += read_size;
plougherf9c72b12006-01-23 13:52:40 +00001215 if((file = open(filename, O_RDONLY)) == -1)
1216 goto read_err;
plougher1f413c82005-11-18 00:02:14 +00001217
1218 do {
plougherf9c72b12006-01-23 13:52:40 +00001219 long long bytes = (((long long) allocated_blocks) + 1) << block_log;
1220 if(bytes != ((size_t) bytes) || (c_buffer = (char *) malloc(bytes)) == NULL) {
1221 TRACE("Out of memory allocating write_file buffer, allocated_blocks %ld, blocks %d\n", allocated_blocks, blocks);
plougher1f413c82005-11-18 00:02:14 +00001222 whole_file = 0;
plougherf9c72b12006-01-23 13:52:40 +00001223 if(bytes < MINALLOCBYTES)
1224 BAD_ERROR("Out of memory allocating write_file buffer, could not allocate %ld blocks (%d Kbytes)\n", allocated_blocks, allocated_blocks << (block_log - 10));
plougher1f413c82005-11-18 00:02:14 +00001225 allocated_blocks >>= 1;
1226 }
1227 } while(!c_buffer);
1228
1229 for(start = bytes; block < blocks; file_bytes += bbytes) {
1230 for(i = 0, bbytes = 0; (i < allocated_blocks) && (block < blocks); i++) {
1231 int available_bytes = read_size - (block * block_size) > block_size ? block_size : read_size - (block * block_size);
1232 if(read(file, buff, available_bytes) == -1)
1233 goto read_err;
1234 c_byte = mangle(c_buffer + bbytes, buff, available_bytes, block_size, noD, 1);
1235 block_list[block ++] = c_byte;
1236 bbytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
1237 }
1238 if(!whole_file) {
1239 write_bytes(fd, bytes, bbytes, c_buffer);
1240 bytes += bbytes;
1241 }
1242 }
1243
1244 if(frag_bytes != 0)
1245 if(read(file, buff, frag_bytes) == -1)
1246 goto read_err;
1247
1248 close(file);
1249 if(whole_file) {
1250 handle.ptr = c_buffer;
1251 if(duplicate_checking && (dupl_ptr = duplicate(read_from_buffer, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
1252 *duplicate_file = TRUE;
1253 goto wr_inode;
1254 }
1255 write_bytes(fd, bytes, file_bytes, c_buffer);
1256 bytes += file_bytes;
1257 } else {
1258 handle.start = start;
1259 if(duplicate_checking && (dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
1260 bytes = start;
1261 if(!block_device)
1262 ftruncate(fd, bytes);
1263 *duplicate_file = TRUE;
1264 goto wr_inode;
1265 }
1266 }
1267
1268 fragment = get_and_fill_fragment(buff, frag_bytes);
1269 if(duplicate_checking)
1270 dupl_ptr->fragment = fragment;
1271
1272 *duplicate_file = FALSE;
1273
1274wr_inode:
1275 free(c_buffer);
1276 file_count ++;
1277 if(dir_ent->inode->nlink == 1 && read_size < ((long long) (1<<30) - 1))
plougherf9c72b12006-01-23 13:52:40 +00001278 status = create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
plougher1f413c82005-11-18 00:02:14 +00001279 else
plougherf9c72b12006-01-23 13:52:40 +00001280 status = create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size, start, blocks, block_listp, fragment, NULL);
1281 if(duplicate_checking == FALSE || *duplicate_file == TRUE)
1282 free(block_list);
1283 return status;
plougher1f413c82005-11-18 00:02:14 +00001284
1285read_err:
1286 perror("Error in reading file, skipping...");
1287 free(c_buffer);
plougherf9c72b12006-01-23 13:52:40 +00001288 free(block_list);
plougher1f413c82005-11-18 00:02:14 +00001289 return FALSE;
1290}
1291
1292
1293char b_buffer[8192];
1294char *name;
1295char *basename_r();
1296
1297char *getbase(char *pathname)
1298{
1299 char *result;
1300
1301 if(*pathname != '/') {
1302 result = getenv("PWD");
1303 strcat(strcat(strcpy(b_buffer, result), "/"), pathname);
1304 } else
1305 strcpy(b_buffer, pathname);
1306 name = b_buffer;
1307 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
1308 return NULL;
1309 else
1310 return result;
1311}
1312
1313
1314char *basename_r()
1315{
1316 char *s;
1317 char *p;
1318 int n = 1;
1319
1320 for(;;) {
1321 s = name;
1322 if(*name == '\0')
1323 return NULL;
1324 if(*name != '/') {
1325 while(*name != '\0' && *name != '/') name++;
1326 n = name - s;
1327 }
1328 while(*name == '/') name++;
1329 if(strncmp(s, ".", n) == 0)
1330 continue;
1331 if((*name == '\0') || (strncmp(s, "..", n) == 0) || ((p = basename_r()) == NULL)) {
1332 s[n] = '\0';
1333 return s;
1334 }
1335 if(strcmp(p, "..") == 0)
1336 continue;
1337 return p;
1338 }
1339}
1340
1341
1342struct inode_info *lookup_inode(struct stat *buf)
1343{
1344 int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino);
1345 struct inode_info *inode = inode_info[inode_hash];
1346
1347 while(inode != NULL) {
1348 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
1349 inode->nlink ++;
1350 return inode;
1351 }
1352 inode = inode->next;
1353 }
1354
1355 if((inode = malloc(sizeof(struct inode_info))) == NULL)
1356 BAD_ERROR("Out of memory in inode hash table entry allocation\n");
1357
1358 memcpy(&inode->buf, buf, sizeof(struct stat));
1359 inode->inode = SQUASHFS_INVALID_BLK;
1360 inode->nlink = 1;
1361 if((buf->st_mode & S_IFMT) == S_IFDIR)
1362 inode->inode_number = dir_inode_no ++;
1363 else
1364 inode->inode_number = inode_no ++;
1365
1366 inode->next = inode_info[inode_hash];
1367 inode_info[inode_hash] = inode;
1368
1369 return inode;
1370}
1371
1372
1373inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir)
1374{
1375 if((dir->count % DIR_ENTRIES) == 0)
1376 if((dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) * sizeof(struct dir_ent *))) == NULL)
1377 BAD_ERROR("Out of memory in add_dir_entry\n");
1378
1379 if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL)
1380 BAD_ERROR("Out of memory in linux_opendir\n");
1381
1382 if(sub_dir)
1383 sub_dir->dir_ent = dir->list[dir->count];
1384 dir->list[dir->count]->name = strdup(name);
1385 dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) : NULL;
1386 dir->list[dir->count]->inode = inode_info;
1387 dir->list[dir->count]->dir = sub_dir;
1388 dir->list[dir->count]->our_dir = dir;
1389 dir->list[dir->count++]->data = data;
1390 dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
1391}
1392
1393
1394int compare_name(const void *ent1_ptr, const void *ent2_ptr)
1395{
1396 struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr);
1397 struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr);
1398
1399 return strcmp(ent1->name, ent2->name);
1400}
1401
1402
1403void sort_directory(struct dir_info *dir)
1404{
1405 qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name);
1406
1407 if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE))
1408 dir->dir_is_ldir = FALSE;
1409}
1410
1411
1412struct dir_info *scan1_opendir(char *pathname)
1413{
1414 DIR *linuxdir;
1415 struct dirent *d_name;
1416 struct dir_info *dir;
1417
1418 if((dir = malloc(sizeof(struct dir_info))) == NULL)
1419 return NULL;
1420
1421 if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) {
1422 free(dir);
1423 return NULL;
1424 }
1425 dir->pathname = strdup(pathname);
1426 dir->count = dir->directory_count = dir->current_count = dir->byte_count = 0;
1427 dir->dir_is_ldir = TRUE;
1428 dir->list = NULL;
1429
1430 return dir;
1431}
1432
1433
1434int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir)
1435{
1436 int i, n, pass;
1437 char *basename;
1438 static int index = 0;
1439
1440 if(dir->count < old_root_entries)
1441 for(i = 0; i < old_root_entries; i++) {
1442 if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
1443 dir->directory_count ++;
1444 add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
1445 }
1446
1447 while(index < source) {
1448 if((basename = getbase(source_path[index])) == NULL) {
1449 ERROR("Bad source directory %s - skipping ...\n", source_path[index]);
1450 index ++;
1451 continue;
1452 }
1453 strcpy(dir_name, basename);
1454 pass = 1;
1455 for(;;) {
1456 for(n = 0; n < dir->count && strcmp(dir->list[n]->name, dir_name) != 0; n++);
1457 if(n == dir->count)
1458 break;
1459 ERROR("Source directory entry %s already used! - trying ", dir_name);
1460 sprintf(dir_name, "%s_%d", basename, pass++);
1461 ERROR("%s\n", dir_name);
1462 }
1463 strcpy(pathname, source_path[index ++]);
1464 return 1;
1465 }
1466 return 0;
1467}
1468
1469
1470int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir)
1471{
1472 struct dirent *d_name;
1473 int i, pass;
1474
1475 if(dir->count < old_root_entries)
1476 for(i = 0; i < old_root_entries; i++) {
1477 if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
1478 dir->directory_count ++;
1479 add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir);
1480 }
1481
1482 if((d_name = readdir(dir->linuxdir)) != NULL) {
1483 strcpy(dir_name, d_name->d_name);
1484 pass = 1;
1485 for(;;) {
1486 for(i = 0; i < dir->count && strcmp(dir->list[i]->name, dir_name) != 0; i++);
1487 if(i == dir->count)
1488 break;
1489 ERROR("Source directory entry %s already used! - trying ", dir_name);
1490 sprintf(dir_name, "%s_%d", d_name->d_name, pass++);
1491 ERROR("%s\n", dir_name);
1492 }
1493 strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
1494 return 1;
1495 }
1496
1497 return 0;
1498}
1499
1500
1501int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir)
1502{
1503 struct dirent *d_name;
1504
1505 if((d_name = readdir(dir->linuxdir)) != NULL) {
1506 strcpy(dir_name, d_name->d_name);
1507 strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name);
1508#if 0
1509 if(strcmp(dir_name, "..") == 0)
1510 printf("%s %lld\n", pathname, d_name->d_ino);
1511#endif
1512 return 1;
1513 }
1514
1515 return 0;
1516}
1517
1518
1519struct dir_ent *scan2_readdir(struct directory *dir, struct dir_info *dir_info)
1520{
1521 int current_count;
1522
1523 while((current_count = dir_info->current_count++) < dir_info->count)
1524 if(dir_info->list[current_count]->data)
1525 add_dir(dir_info->list[current_count]->data->inode, dir_info->list[current_count]->data->inode_number,
1526 dir_info->list[current_count]->name, dir_info->list[current_count]->data->type, dir);
1527 else
1528 return dir_info->list[current_count];
1529 return FALSE;
1530}
1531
1532
1533void scan1_freedir(struct dir_info *dir)
1534{
1535 closedir(dir->linuxdir);
1536}
1537
1538
1539void scan2_freedir(struct directory *dir)
1540{
1541 if(dir->index)
1542 free(dir->index);
1543 free(dir->buff);
1544}
1545
1546
1547void dir_scan(squashfs_inode *inode, char *pathname, int (_readdir)(char *, char *, struct dir_info *))
1548{
1549 struct dir_info *dir_info = dir_scan1(pathname, _readdir);
1550 struct dir_ent *dir_ent;
1551 struct inode_info *inode_info;
1552
1553 if(dir_info == NULL)
1554 return;
1555
1556 if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL)
1557 BAD_ERROR("Out of memory in dir_scan\n");
1558
1559 if((inode_info = malloc(sizeof(struct inode_info))) == NULL)
1560 BAD_ERROR("Out of memory in dir_scan\n");
1561
1562 dir_ent->name = dir_ent->pathname = strdup(pathname);
1563 dir_ent->dir = dir_info;
1564 dir_ent->inode = inode_info;
1565 dir_ent->our_dir = NULL;
1566 dir_ent->data = NULL;
1567 inode_info->nlink = 1;
plougherdf70c3e2006-01-27 09:34:13 +00001568 inode_info->inode_number = root_inode_number ? root_inode_number : dir_inode_no++;
plougher1f413c82005-11-18 00:02:14 +00001569 dir_info->dir_ent = dir_ent;
1570
1571 if(pathname[0] == '\0') {
1572 /* dummy top level directory, if multiple sources specified on command line */
1573 inode_info->buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
1574 inode_info->buf.st_uid = getuid();
1575 inode_info->buf.st_gid = getgid();
1576 inode_info->buf.st_mtime = time(NULL);
1577 } else if(lstat(pathname, &inode_info->buf) == -1) {
1578 char buffer[8192];
1579 sprintf(buffer, "Cannot stat dir/file %s, ignoring", pathname);
1580 perror(buffer);
1581 return;
1582 }
1583 dir_scan2(inode, dir_info);
1584}
1585
1586
1587struct dir_info *dir_scan1(char *pathname, int (_readdir)(char *, char *, struct dir_info *))
1588{
1589 struct dir_info *dir, *sub_dir;
1590 struct stat buf;
1591 char filename[8192], dir_name[8192];
1592
1593 if((dir = scan1_opendir(pathname)) == NULL) {
1594 ERROR("Could not open %s, skipping...\n", pathname);
1595 goto error;
1596 }
1597
1598 while(_readdir(filename, dir_name, dir) != FALSE) {
1599
1600 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)
1601 continue;
1602
1603 if(lstat(filename, &buf) == -1) {
1604 char buffer[8192];
1605 sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename);
1606 perror(buffer);
1607 continue;
1608 }
1609 if(excluded(filename, &buf))
1610 continue;
1611
1612 if((buf.st_mode & S_IFMT) == S_IFDIR) {
1613 if((sub_dir = dir_scan1(filename, scan1_readdir)) == NULL)
1614 continue;
1615 dir->directory_count ++;
1616 } else
1617 sub_dir = NULL;
1618
1619 add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf), NULL, dir);
1620 }
1621
1622 scan1_freedir(dir);
1623 sort_directory(dir);
1624
1625error:
1626 return dir;
1627}
1628
1629
1630int dir_scan2(squashfs_inode *inode, struct dir_info *dir_info)
1631{
1632 int squashfs_type;
1633 int result = FALSE;
1634 int duplicate_file;
1635 char *pathname = dir_info->pathname;
1636 struct directory dir;
1637 struct dir_ent *dir_ent;
1638
1639 scan2_init_dir(&dir);
1640
1641 while((dir_ent = scan2_readdir(&dir, dir_info)) != NULL) {
1642 struct inode_info *inode_info = dir_ent->inode;
1643 struct stat *buf = &inode_info->buf;
1644 char *filename = dir_ent->pathname;
1645 char *dir_name = dir_ent->name;
1646 unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
1647
1648 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
1649 switch(buf->st_mode & S_IFMT) {
1650 case S_IFREG:
1651 squashfs_type = SQUASHFS_FILE_TYPE;
1652 if(!sorted) {
1653 result = write_file(inode, dir_ent, buf->st_size, &duplicate_file);
1654 INFO("file %s, uncompressed size %lld bytes, %s\n", filename, buf->st_size, duplicate_file ? "DUPLICATE" : "");
1655 } else
1656 result = get_sorted_inode(inode, buf);
1657 break;
1658
1659 case S_IFDIR:
1660 squashfs_type = SQUASHFS_DIR_TYPE;
1661 result = dir_scan2(inode, dir_ent->dir);
1662 break;
1663
1664 case S_IFLNK:
1665 squashfs_type = SQUASHFS_SYMLINK_TYPE;
1666 result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
1667 INFO("symbolic link %s inode 0x%llx\n", dir_name, *inode);
1668 sym_count ++;
1669 break;
1670
1671 case S_IFCHR:
1672 squashfs_type = SQUASHFS_CHRDEV_TYPE;
1673 result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
1674 INFO("character device %s inode 0x%llx\n", dir_name, *inode);
1675 dev_count ++;
1676 break;
1677
1678 case S_IFBLK:
1679 squashfs_type = SQUASHFS_BLKDEV_TYPE;
1680 result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
1681 INFO("block device %s inode 0x%llx\n", dir_name, *inode);
1682 dev_count ++;
1683 break;
1684
1685 case S_IFIFO:
1686 squashfs_type = SQUASHFS_FIFO_TYPE;
1687 result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
1688 INFO("fifo %s inode 0x%llx\n", dir_name, *inode);
1689 fifo_count ++;
1690 break;
1691
1692 case S_IFSOCK:
1693 squashfs_type = SQUASHFS_SOCKET_TYPE;
1694 result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL);
1695 INFO("unix domain socket %s inode 0x%llx\n", dir_name, *inode);
1696 sock_count ++;
1697 break;
1698
1699 default:
1700 ERROR("%s unrecognised file type, mode is %x\n", filename, buf->st_mode);
1701 result = FALSE;
1702 }
1703 dir_ent->inode->inode = *inode;
1704 dir_ent->inode->type = squashfs_type;
1705 } else {
1706 *inode = dir_ent->inode->inode;
1707 squashfs_type = dir_ent->inode->type;
1708 result = TRUE;
1709 }
1710
1711
1712 if(result)
1713 add_dir(*inode, inode_number, dir_name, squashfs_type, &dir);
1714 }
1715
1716 result = write_dir(inode, dir_info, &dir);
1717 INFO("directory %s inode 0x%llx\n", pathname, *inode);
1718
1719 scan2_freedir(&dir);
1720
1721 return result;
1722}
1723
1724
1725unsigned int slog(unsigned int block)
1726{
1727 int i;
1728
1729 for(i = 9; i <= 16; i++)
1730 if(block == (1 << i))
1731 return i;
1732 return 0;
1733}
1734
1735
1736int excluded(char *filename, struct stat *buf)
1737{
1738 int i;
1739
1740 for(i = 0; i < exclude; i++)
1741 if((exclude_paths[i].st_dev == buf->st_dev) && (exclude_paths[i].st_ino == buf->st_ino))
1742 return TRUE;
1743 return FALSE;
1744}
1745
1746
1747#define ADD_ENTRY(buf) \
1748 if(exclude % EXCLUDE_SIZE == 0) {\
1749 if((exclude_paths = (struct exclude_info *) realloc(exclude_paths, (exclude + EXCLUDE_SIZE) * sizeof(struct exclude_info))) == NULL)\
1750 BAD_ERROR("Out of memory in exclude dir/file table\n");\
1751 }\
1752 exclude_paths[exclude].st_dev = buf.st_dev;\
1753 exclude_paths[exclude++].st_ino = buf.st_ino;
1754int add_exclude(char *path)
1755{
1756 int i;
1757 char buffer[4096], filename[4096];
1758 struct stat buf;
1759
1760 if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
1761 if(lstat(path, &buf) == -1) {
1762 sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", path);
1763 perror(buffer);
1764 return TRUE;
1765 }
1766 ADD_ENTRY(buf);
1767 return TRUE;
1768 }
1769
1770 for(i = 0; i < source; i++) {
1771 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
1772 if(lstat(filename, &buf) == -1) {
1773 if(!(errno == ENOENT || errno == ENOTDIR)) {
1774 sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", filename);
1775 perror(buffer);
1776 }
1777 continue;
1778 }
1779 ADD_ENTRY(buf);
1780 }
1781 return TRUE;
1782}
1783
1784
plougherdf70c3e2006-01-27 09:34:13 +00001785void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type)
plougher1f413c82005-11-18 00:02:14 +00001786{
1787 if((old_root_entry = (struct old_root_entry_info *) realloc(old_root_entry, sizeof(struct old_root_entry_info)
1788 * (old_root_entries + 1))) == NULL)
1789 BAD_ERROR("Out of memory in old root directory entries reallocation\n");
1790
1791 strcpy(old_root_entry[old_root_entries].name, name);
1792 old_root_entry[old_root_entries].inode = inode;
plougherdf70c3e2006-01-27 09:34:13 +00001793 old_root_entry[old_root_entries].inode_number = inode_number;
plougher1f413c82005-11-18 00:02:14 +00001794 old_root_entry[old_root_entries++].type = type;
1795}
1796
1797
1798#define VERSION() \
plougher76959292006-01-24 08:56:38 +00001799 printf("mksquashfs version 3.0prerelease (2006/1/24)\n");\
1800 printf("copyright (C) 2006 Phillip Lougher (phillip@lougher.demon.co.uk)\n\n"); \
plougher1f413c82005-11-18 00:02:14 +00001801 printf("This program is free software; you can redistribute it and/or\n");\
1802 printf("modify it under the terms of the GNU General Public License\n");\
1803 printf("as published by the Free Software Foundation; either version 2,\n");\
1804 printf("or (at your option) any later version.\n\n");\
1805 printf("This program is distributed in the hope that it will be useful,\n");\
1806 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
1807 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\
1808 printf("GNU General Public License for more details.\n");
1809int main(int argc, char *argv[])
1810{
1811 struct stat buf;
1812 int i;
1813 squashfs_super_block sBlk;
1814 char *b, *root_name = NULL;
1815 int be, nopad = FALSE, delete = FALSE, keep_as_directory = FALSE, orig_be;
1816 squashfs_inode inode;
1817
1818#if __BYTE_ORDER == __BIG_ENDIAN
1819 be = TRUE;
1820#else
1821 be = FALSE;
1822#endif
1823
1824 block_log = slog(block_size);
1825 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
1826 VERSION();
1827 exit(0);
1828 }
1829 for(i = 1; i < argc && argv[i][0] != '-'; i++);
1830 if(i < 3)
1831 goto printOptions;
1832 source_path = argv + 1;
1833 source = i - 2;
1834 for(; i < argc; i++) {
1835 if(strcmp(argv[i], "-b") == 0) {
1836 if((++i == argc) || (block_size = strtol(argv[i], &b, 10), *b !='\0')) {
1837 ERROR("%s: -b missing or invalid block size\n", argv[0]);
1838 exit(1);
1839 }
1840
1841 if((block_log = slog(block_size)) == 0) {
1842 ERROR("%s: -b block size not power of two or not between 512 and 64K\n", argv[0]);
1843 exit(1);
1844 }
1845 } else if(strcmp(argv[i], "-ef") == 0) {
1846 if(++i == argc) {
1847 ERROR("%s: -ef missing filename\n", argv[0]);
1848 exit(1);
1849 }
1850 } else if(strcmp(argv[i], "-2.0") == 0)
1851 ERROR("Not supported\n");
1852 else if(strcmp(argv[i], "-no-duplicates") == 0)
1853 duplicate_checking = FALSE;
1854
1855 else if(strcmp(argv[i], "-no-fragments") == 0)
1856 no_fragments = TRUE;
1857
1858 else if(strcmp(argv[i], "-always-use-fragments") == 0)
1859 always_use_fragments = TRUE;
1860
1861 else if(strcmp(argv[i], "-sort") == 0) {
1862 if(++i == argc) {
1863 ERROR("%s: -sort missing filename\n", argv[0]);
1864 exit(1);
1865 }
1866 } else if(strcmp(argv[i], "-all-root") == 0 ||
1867 strcmp(argv[i], "-root-owned") == 0)
1868 global_uid = global_gid = 0;
1869
1870 else if(strcmp(argv[i], "-force-uid") == 0) {
1871 if(++i == argc) {
1872 ERROR("%s: -force-uid missing uid or user\n", argv[0]);
1873 exit(1);
1874 }
1875 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
1876 if(global_uid < 0 || global_uid > (((long long) 1 << 32) - 1)) {
1877 ERROR("%s: -force-uid uid out of range\n", argv[0]);
1878 exit(1);
1879 }
1880 } else {
1881 struct passwd *uid = getpwnam(argv[i]);
1882 if(uid)
1883 global_uid = uid->pw_uid;
1884 else {
1885 ERROR("%s: -force-uid invalid uid or unknown user\n", argv[0]);
1886 exit(1);
1887 }
1888 }
1889 } else if(strcmp(argv[i], "-force-gid") == 0) {
1890 if(++i == argc) {
1891 ERROR("%s: -force-gid missing gid or group\n", argv[0]);
1892 exit(1);
1893 }
1894 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
1895 if(global_gid < 0 || global_gid > (((long long) 1 << 32) - 1)) {
1896 ERROR("%s: -force-gid gid out of range\n", argv[0]);
1897 exit(1);
1898 }
1899 } else {
1900 struct group *gid = getgrnam(argv[i]);
1901 if(gid)
1902 global_gid = gid->gr_gid;
1903 else {
1904 ERROR("%s: -force-gid invalid gid or unknown group\n", argv[0]);
1905 exit(1);
1906 }
1907 }
1908 } else if(strcmp(argv[i], "-noI") == 0 ||
1909 strcmp(argv[i], "-noInodeCompression") == 0)
1910 noI = TRUE;
1911
1912 else if(strcmp(argv[i], "-noD") == 0 ||
1913 strcmp(argv[i], "-noDataCompression") == 0)
1914 noD = TRUE;
1915
1916 else if(strcmp(argv[i], "-noF") == 0 ||
1917 strcmp(argv[i], "-noFragmentCompression") == 0)
1918 noF = TRUE;
1919
1920 else if(strcmp(argv[i], "-nopad") == 0)
1921 nopad = TRUE;
1922
1923 else if(strcmp(argv[i], "-check_data") == 0)
1924 check_data = TRUE;
1925
1926 else if(strcmp(argv[i], "-info") == 0)
1927 silent = 0;
1928
1929 else if(strcmp(argv[i], "-be") == 0)
1930 be = TRUE;
1931
1932 else if(strcmp(argv[i], "-le") == 0)
1933 be = FALSE;
1934
1935 else if(strcmp(argv[i], "-e") == 0)
1936 break;
1937
1938 else if(strcmp(argv[i], "-noappend") == 0)
1939 delete = TRUE;
1940
1941 else if(strcmp(argv[i], "-keep-as-directory") == 0)
1942 keep_as_directory = TRUE;
1943
1944 else if(strcmp(argv[i], "-root-becomes") == 0) {
1945 if(++i == argc) {
1946 ERROR("%s: -root-becomes: missing name\n", argv[0]);
1947 exit(1);
1948 }
1949 root_name = argv[i];
1950 } else if(strcmp(argv[i], "-version") == 0) {
1951 VERSION();
1952 } else {
1953 ERROR("%s: invalid option\n\n", argv[0]);
1954printOptions:
1955 ERROR("SYNTAX:%s source1 source2 ... dest [options] [-e list of exclude\ndirs/files]\n", argv[0]);
1956 ERROR("\nOptions are\n");
1957 ERROR("-version\t\tprint version, licence and copyright message\n");
1958 ERROR("-info\t\t\tprint files written to filesystem\n");
1959 ERROR("-b <block_size>\t\tset data block to <block_size>. Default %d bytes\n", SQUASHFS_FILE_SIZE);
1960 ERROR("-2.0\t\t\tcreate a 2.0 filesystem\n");
1961 ERROR("-noI\t\t\tdo not compress inode table\n");
1962 ERROR("-noD\t\t\tdo not compress data blocks\n");
1963 ERROR("-noF\t\t\tdo not compress fragment blocks\n");
1964 ERROR("-no-fragments\t\tdo not use fragments\n");
1965 ERROR("-always-use-fragments\tuse fragment blocks for files larger than block size\n");
1966 ERROR("-no-duplicates\t\tdo not perform duplicate checking\n");
1967 ERROR("-noappend\t\tdo not append to existing filesystem\n");
1968 ERROR("-keep-as-directory\tif one source directory is specified, create a root\n");
1969 ERROR("\t\t\tdirectory containing that directory, rather than the\n");
1970 ERROR("\t\t\tcontents of the directory\n");
1971 ERROR("-root-becomes <name>\twhen appending source files/directories, make the\n");
1972 ERROR("\t\t\toriginal root become a subdirectory in the new root\n");
1973 ERROR("\t\t\tcalled <name>, rather than adding the new source items\n");
1974 ERROR("\t\t\tto the original root\n");
1975 ERROR("-all-root\t\tmake all files owned by root\n");
1976 ERROR("-force-uid uid\t\tset all file uids to uid\n");
1977 ERROR("-force-gid gid\t\tset all file gids to gid\n");
1978 ERROR("-le\t\t\tcreate a little endian filesystem\n");
1979 ERROR("-be\t\t\tcreate a big endian filesystem\n");
1980 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple of 4K\n");
1981 ERROR("-check_data\t\tadd checkdata for greater filesystem checks\n");
1982 ERROR("-root-owned\t\talternative name for -all-root\n");
1983 ERROR("-noInodeCompression\talternative name for -noI\n");
1984 ERROR("-noDataCompression\talternative name for -noD\n");
1985 ERROR("-noFragmentCompression\talternative name for -noF\n");
1986 ERROR("-sort <sort_file>\tsort files according to priorities in <sort_file>. One\n");
1987 ERROR("\t\t\tfile or dir with priority per line. Priority -32768 to\n");
1988 ERROR("\t\t\t32767, default priority 0\n");
1989 ERROR("-ef <exclude_file>\tlist of exclude dirs/files. One per line\n");
1990 exit(1);
1991 }
1992 }
1993
1994 if(stat(argv[source + 1], &buf) == -1) {
1995 if(errno == ENOENT) { /* Does not exist */
1996 if((fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) {
1997 perror("Could not create destination file");
1998 exit(1);
1999 }
2000 delete = TRUE;
2001 } else {
2002 perror("Could not stat destination file");
2003 exit(1);
2004 }
2005
2006 } else {
2007 if(S_ISBLK(buf.st_mode)) {
2008 if((fd = open(argv[source + 1], O_RDWR)) == -1) {
2009 perror("Could not open block device as destination");
2010 exit(1);
2011 }
2012 block_device = 1;
2013
2014 } else if(S_ISREG(buf.st_mode)) {
2015 if((fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | O_RDWR)) == -1) {
2016 perror("Could not open regular file for writing as destination");
2017 exit(1);
2018 }
2019 }
2020 else {
2021 ERROR("Destination not block device or regular file\n");
2022 exit(1);
2023 }
2024
2025 if(!delete) {
plougher1f413c82005-11-18 00:02:14 +00002026 if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) {
2027 if(S_ISREG(buf.st_mode)) { /* reopen truncating file */
2028 close(fd);
2029 if((fd = open(argv[source + 1], O_TRUNC | O_RDWR)) == -1) {
2030 perror("Could not open regular file for writing as destination");
2031 exit(1);
2032 }
2033 }
2034 delete = TRUE;
2035 }
2036
2037 }
2038 }
2039
2040 /* process the exclude files - must be done afer destination file has been possibly created */
2041 for(i = source + 2; i < argc; i++)
2042 if(strcmp(argv[i], "-ef") == 0) {
2043 FILE *fd;
2044 char filename[16385];
2045 if((fd = fopen(argv[++i], "r")) == NULL) {
2046 perror("Could not open exclude file...");
2047 exit(1);
2048 }
2049 while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
2050 add_exclude(filename);
2051 fclose(fd);
2052 } else if(strcmp(argv[i], "-e") == 0)
2053 break;
2054 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-sort") == 0)
2055 i++;
2056
2057 if(i != argc) {
2058 if(++i == argc) {
2059 ERROR("%s: -e missing arguments\n", argv[0]);
2060 exit(1);
2061 }
2062 while(i < argc && add_exclude(argv[i++]));
2063 }
2064
2065 /* process the sort files - must be done afer the exclude files */
2066 for(i = source + 2; i < argc; i++)
2067 if(strcmp(argv[i], "-sort") == 0) {
2068 read_sort_file(argv[++i], source, source_path);
2069 sorted ++;
2070 } else if(strcmp(argv[i], "-e") == 0)
2071 break;
2072 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0)
2073 i++;
2074
2075 if(delete) {
2076 printf("Creating %s %d.%d filesystem on %s, block size %d.\n",
2077 be ? "big endian" : "little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
2078 bytes = sizeof(squashfs_super_block);
2079 } else {
2080 unsigned int last_directory_block, inode_dir_offset, inode_dir_file_size, root_inode_size,
plougherdf70c3e2006-01-27 09:34:13 +00002081 inode_dir_start_block, uncompressed_data, compressed_data, inode_dir_inode_number,
2082 inode_dir_parent_inode;
2083 unsigned int root_inode_start = SQUASHFS_INODE_BLK(sBlk.root_inode), root_inode_offset =
plougher1f413c82005-11-18 00:02:14 +00002084 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
2085
2086 be = orig_be;
2087 block_log = slog(block_size = sBlk.block_size);
2088 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
2089 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
2090 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
2091 check_data = SQUASHFS_CHECK_DATA(sBlk.flags);
2092 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
2093 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
2094 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
2095
2096 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &data_cache,
2097 &directory_table, &directory_data_cache, &last_directory_block, &inode_dir_offset,
2098 &inode_dir_file_size, &root_inode_size, &inode_dir_start_block,
2099 &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count,
2100 (squashfs_uid *) uids, &uid_count, (squashfs_uid *) guids, &guid_count,
plougherdf70c3e2006-01-27 09:34:13 +00002101 &total_bytes, &total_inode_bytes, &total_directory_bytes, &inode_dir_inode_number,
2102 &inode_dir_parent_inode, add_old_root_entry, &fragment_table)) == 0) {
plougher1f413c82005-11-18 00:02:14 +00002103 ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
2104 exit(1);
2105 }
2106 if((fragments = sBlk.fragments))
2107 fragment_table = (squashfs_fragment_entry *) realloc((char *) fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(squashfs_fragment_entry));
2108
2109 printf("Appending to existing %s %d.%d filesystem on %s, block size %d\n", be ? "big endian" :
2110 "little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
2111 printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments and -2.0 options ignored\n");
2112 printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n");
2113
2114 compressed_data = inode_dir_offset + inode_dir_file_size & ~(SQUASHFS_METADATA_SIZE - 1);
2115 uncompressed_data = inode_dir_offset + inode_dir_file_size & (SQUASHFS_METADATA_SIZE - 1);
2116
2117 /* save original filesystem state for restoring ... */
2118 sfragments = fragments;
2119 sbytes = bytes;
2120 sinode_count = sBlk.inodes;
2121 sdata_cache = (char *)malloc(scache_bytes = root_inode_offset + root_inode_size);
2122 sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes = uncompressed_data);
2123 memcpy(sdata_cache, data_cache, scache_bytes);
2124 memcpy(sdirectory_data_cache, directory_data_cache + compressed_data, sdirectory_cache_bytes);
2125 sinode_bytes = root_inode_start;
2126 sdirectory_bytes = last_directory_block;
2127 suid_count = uid_count;
2128 sguid_count = guid_count;
2129 stotal_bytes = total_bytes;
2130 stotal_inode_bytes = total_inode_bytes;
2131 stotal_directory_bytes = total_directory_bytes + compressed_data;
2132 sfile_count = file_count;
2133 ssym_count = sym_count;
2134 sdev_count = dev_count;
2135 sdir_count = dir_count + 1;
2136 sfifo_count = fifo_count;
2137 ssock_count = sock_count;
2138 sdup_files = dup_files;
2139 restore = TRUE;
2140 if(setjmp(env))
2141 goto restore_filesystem;
2142 signal(SIGTERM, sighandler);
2143 signal(SIGINT, sighandler);
2144 write_bytes(fd, SQUASHFS_START, 4, "\0\0\0\0");
2145
2146 /* set the filesystem state up to be able to append to the original filesystem. The filesystem state
2147 * differs depending on whether we're appending to the original root directory, or if the original
2148 * root directory becomes a sub-directory (root-becomes specified on command line, here root_name != NULL)
2149 */
2150 inode_bytes = inode_size = root_inode_start;
2151 directory_size = last_directory_block;
2152 cache_size = root_inode_offset + root_inode_size;
2153 directory_cache_size = inode_dir_offset + inode_dir_file_size;
2154 if(root_name) {
plougherdf70c3e2006-01-27 09:34:13 +00002155 root_inode_number = inode_dir_parent_inode;
2156 dir_inode_no = sBlk.inodes + 2;
plougher1f413c82005-11-18 00:02:14 +00002157 directory_bytes = last_directory_block;
2158 directory_cache_bytes = uncompressed_data;
2159 memmove(directory_data_cache, directory_data_cache + compressed_data, uncompressed_data);
2160 cache_bytes = root_inode_offset + root_inode_size;
plougherdf70c3e2006-01-27 09:34:13 +00002161 add_old_root_entry(root_name, sBlk.root_inode, inode_dir_inode_number, SQUASHFS_DIR_TYPE);
plougher1f413c82005-11-18 00:02:14 +00002162 total_directory_bytes += compressed_data;
2163 dir_count ++;
2164 } else {
plougherdf70c3e2006-01-27 09:34:13 +00002165 root_inode_number = inode_dir_inode_number;
2166 dir_inode_no = sBlk.inodes;
plougher1f413c82005-11-18 00:02:14 +00002167 directory_bytes = inode_dir_start_block;
2168 directory_cache_bytes = inode_dir_offset;
2169 cache_bytes = root_inode_offset;
2170 }
2171
2172 inode_count = file_count + dir_count + sym_count + dev_count + fifo_count + sock_count;
2173 }
2174
2175#if __BYTE_ORDER == __BIG_ENDIAN
2176 swap = !be;
2177#else
2178 swap = be;
2179#endif
2180
2181 block_offset = check_data ? 3 : 2;
2182
2183 if(stat(source_path[0], &buf) == -1) {
2184 perror("Cannot stat source directory");
2185 EXIT_MKSQUASHFS();
2186 }
2187
2188 if(sorted)
2189 sort_files_and_write(source, source_path);
2190
2191 if(delete && !keep_as_directory && source == 1 && S_ISDIR(buf.st_mode))
2192 dir_scan(&inode, source_path[0], scan1_readdir);
2193 else if(!keep_as_directory && source == 1 && S_ISDIR(buf.st_mode))
2194 dir_scan(&inode, source_path[0], scan1_single_readdir);
2195 else
2196 dir_scan(&inode, "", scan1_encomp_readdir);
2197 sBlk.root_inode = inode;
2198 sBlk.inodes = inode_count;
2199 sBlk.s_magic = SQUASHFS_MAGIC;
2200 sBlk.s_major = SQUASHFS_MAJOR;
2201 sBlk.s_minor = SQUASHFS_MINOR;
2202 sBlk.block_size = block_size;
2203 sBlk.block_log = block_log;
2204 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, check_data, noF, no_fragments, always_use_fragments, duplicate_checking);
2205 sBlk.mkfs_time = time(NULL);
2206
2207restore_filesystem:
2208 write_fragment();
2209 sBlk.fragments = fragments;
2210 sBlk.inode_table_start = write_inodes();
2211 sBlk.directory_table_start = write_directories();
2212 sBlk.fragment_table_start = write_fragment_table();
2213
2214 TRACE("sBlk->inode_table_start 0x%x\n", sBlk.inode_table_start);
2215 TRACE("sBlk->directory_table_start 0x%x\n", sBlk.directory_table_start);
2216 TRACE("sBlk->fragment_table_start 0x%x\n", sBlk.fragment_table_start);
2217
2218 if(sBlk.no_uids = uid_count) {
2219 if(!swap)
2220 write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids);
2221 else {
2222 squashfs_uid uids_copy[uid_count];
2223
2224 SQUASHFS_SWAP_DATA(uids, uids_copy, uid_count, sizeof(squashfs_uid) * 8);
2225 write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids_copy);
2226 }
2227 sBlk.uid_start = bytes;
2228 bytes += uid_count * sizeof(squashfs_uid);
2229 } else
2230 sBlk.uid_start = 0;
2231
2232 if(sBlk.no_guids = guid_count) {
2233 if(!swap)
2234 write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids);
2235 else {
2236 squashfs_uid guids_copy[guid_count];
2237
2238 SQUASHFS_SWAP_DATA(guids, guids_copy, guid_count, sizeof(squashfs_uid) * 8);
2239 write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids_copy);
2240 }
2241 sBlk.guid_start = bytes;
2242 bytes += guid_count * sizeof(squashfs_uid);
2243 } else
2244 sBlk.guid_start = 0;
2245
2246 sBlk.bytes_used = bytes;
2247
2248 sBlk.unused = SQUASHFS_INVALID_BLK;
2249
2250 if(!swap)
2251 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk);
2252 else {
2253 squashfs_super_block sBlk_copy;
2254
2255 SQUASHFS_SWAP_SUPER_BLOCK((&sBlk), &sBlk_copy);
2256 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_copy);
2257 }
2258
2259 if(!nopad && (i = bytes & (4096 - 1))) {
plougher8cb05cd2005-12-11 23:32:35 +00002260 char temp[4096] = {0};
plougher1f413c82005-11-18 00:02:14 +00002261 write_bytes(fd, bytes, 4096 - i, temp);
2262 }
2263
2264 total_bytes += total_inode_bytes + total_directory_bytes + uid_count
2265 * sizeof(unsigned short) + guid_count * sizeof(unsigned short) +
2266 sizeof(squashfs_super_block);
2267
2268 printf("\n%s filesystem, data block size %d, %s data, %s metadata, %s fragments\n", be ?
2269 "Big endian" : "Little endian", block_size, noD ? "uncompressed" : "compressed", noI ?
2270 "uncompressed" : "compressed", no_fragments ? "no" : noF ? "uncompressed" : "compressed");
2271 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0));
2272 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
2273 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
2274 printf("Inode table size %d bytes (%.2f Kbytes)\n",
2275 inode_bytes, inode_bytes / 1024.0);
2276 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
2277 ((float) inode_bytes / total_inode_bytes) * 100.0, total_inode_bytes);
2278 printf("Directory table size %d bytes (%.2f Kbytes)\n",
2279 directory_bytes, directory_bytes / 1024.0);
2280 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
2281 ((float) directory_bytes / total_directory_bytes) * 100.0, total_directory_bytes);
2282 if(duplicate_checking)
2283 printf("Number of duplicate files found %d\n", file_count - dup_files);
2284 else
2285 printf("No duplicate files removed\n");
2286 printf("Number of inodes %d\n", inode_count);
2287 printf("Number of files %d\n", file_count);
2288 if(!no_fragments)
2289 printf("Number of fragments %d\n", fragments);
2290 printf("Number of symbolic links %d\n", sym_count);
2291 printf("Number of device nodes %d\n", dev_count);
2292 printf("Number of fifo nodes %d\n", fifo_count);
2293 printf("Number of socket nodes %d\n", sock_count);
2294 printf("Number of directories %d\n", dir_count);
2295 printf("Number of uids %d\n", uid_count);
2296
2297 for(i = 0; i < uid_count; i++) {
2298 struct passwd *user = getpwuid(uids[i]);
2299 printf("\t%s (%d)\n", user == NULL ? "unknown" : user->pw_name, uids[i]);
2300 }
2301
2302 printf("Number of gids %d\n", guid_count);
2303
2304 for(i = 0; i < guid_count; i++) {
2305 struct group *group = getgrgid(guids[i]);
2306 printf("\t%s (%d)\n", group == NULL ? "unknown" : group->gr_name, guids[i]);
2307 }
2308 close(fd);
2309 return 0;
2310}