and added missing files... I have git commit -a :-)
[bcm963xx.git] / hostTools / squashfs / mksquashfs.c
1 /*
2  * Create a squashfs filesystem.  This is a highly compressed read only filesystem.
3  *
4  * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2,
9  * or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * mksquashfs.c
21  */
22
23 #define TRUE 1
24 #include <pwd.h>
25 #include <grp.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <dirent.h>
34 #include <string.h>
35 #include <zlib.h>
36 #include <endian.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include <setjmp.h>
40 #include <sys/mman.h>
41
42 #include "mksquashfs.h"
43 #include <squashfs_fs.h>
44 /* BRCM begin */
45 #include "7zapi.h"
46 /* BRCM end */
47
48 #ifdef SQUASHFS_TRACE
49 #define TRACE(s, args...)               printf("mksquashfs: "s, ## args)
50 #else
51 #define TRACE(s, args...)
52 #endif
53
54 #define INFO(s, args...)                do { if(!silent) printf("mksquashfs: "s, ## args); } while(0)
55 #define ERROR(s, args...)               do { fprintf(stderr, s, ## args); } while(0)
56 #define EXIT_MKSQUASHFS()               do { if(restore)\
57                                         restorefs();\
58                                         exit(1); } while(0)
59 #define BAD_ERROR(s, args...)           do {\
60                                         fprintf(stderr, "FATAL ERROR:" s, ##args);\
61                                         EXIT_MKSQUASHFS();\
62                                         } while(0)
63
64 int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
65 int total_compressed = 0, total_uncompressed = 0;
66
67 int fd;
68
69 /* superblock attributes */
70 int noI = 0, noD = 0, check_data = 0, block_size = SQUASHFS_FILE_SIZE, block_log;
71 unsigned short uid_count = 0, guid_count = 0;
72 squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
73 int block_offset;
74
75 /* write position within data section */
76 unsigned int bytes = 0, total_bytes = 0;
77
78 /* in memory directory table - possibly compressed */
79 char *directory_table = NULL;
80 unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
81
82 /* cached directory table */
83 char *directory_data_cache = NULL;
84 unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
85
86 /* in memory inode table - possibly compressed */
87 char *inode_table = NULL;
88 unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
89
90 /* cached inode table */
91 char *data_cache = NULL;
92 unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
93
94 /* in memory directory header */
95 struct directory {
96         unsigned int            start_block;
97         unsigned int            size;
98         unsigned char           *buff;
99         unsigned char           *p;
100         unsigned int            entry_count;
101         squashfs_dir_header     *entry_count_p;
102 };
103
104 struct file_info *dupl[65536], *frag_dups[65536];
105 int dup_files = 0;
106
107 int swap, silent = TRUE;
108 int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
109
110 /* list of exclude dirs/files */
111 struct exclude_info {
112         dev_t                   st_dev;
113         ino_t                   st_ino;
114 };
115
116 #define EXCLUDE_SIZE 8192
117 int exclude = 0;
118 struct exclude_info *exclude_paths = NULL;
119 int excluded(char *filename, struct stat *buf);
120
121 /* fragment block data structures */
122 int fragments = 0;
123 static char *fragment_data;
124 static int fragment_size = 0;
125 struct fragment {
126         unsigned int            index;
127         int                     offset;
128         int                     size;
129 };
130
131
132 #define FRAG_SIZE 32768
133 squashfs_fragment_entry *fragment_table = NULL;
134
135 /* list of source dirs/files */
136 int source = 0;
137 char **source_path;
138
139 /* list of root directory entries read from original filesystem */
140 int old_root_entries = 0;
141 struct old_root_entry_info {
142         char                    name[SQUASHFS_NAME_LEN + 1];
143         squashfs_inode          inode;
144         int                     type;
145 };
146
147 /* in memory file info */
148 struct file_info {
149         unsigned int            bytes;
150         unsigned short          checksum;
151         unsigned int            start;
152         unsigned int            *block_list;
153         struct file_info        *next;
154         struct fragment         *fragment;
155         unsigned short          fragment_checksum;
156 };
157
158 /* count of how many times SIGINT or SIGQUIT has been sent */
159 int interrupted = 0;
160
161 /* restore orignal filesystem state if appending to existing filesystem is cancelled */
162 jmp_buf env;
163 char *sdata_cache, *sdirectory_data_cache;
164 unsigned int sbytes, sinode_bytes, scache_bytes, sdirectory_bytes,
165         sdirectory_cache_bytes, suid_count, sguid_count,
166         stotal_bytes, stotal_inode_bytes, stotal_directory_bytes,
167         sinode_count, sfile_count, ssym_count, sdev_count,
168         sdir_count, sdup_files;
169 int sfragments;
170 int restore = 0;
171
172 /*flag whether destination file is a block device */
173 int block_device = 0;
174
175 /* flag indicating whether files are sorted using sort list(s) */
176 int sorted = 0;
177
178 long long global_uid = -1, global_gid = -1;
179
180 /* structure to used to pass in a pointer or an integer
181  * to duplicate buffer read helper functions.
182  */
183 struct duplicate_buffer_handle {
184         unsigned char   *ptr;
185         unsigned int    start;
186 };
187
188 struct old_root_entry_info *old_root_entry;
189 void add_old_root_entry(char *name, squashfs_inode inode, int type);
190 extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
191 extern int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **inode_table, int *inode_bytes,
192                 char **data_cache, int *cache_bytes, int *cache_size, char **directory_table, int *directory_bytes,
193                 char **directory_data_cache, int *directory_cache_bytes, int *directory_cache_size,
194                 int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
195                 squashfs_uid *uids, unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
196                 unsigned int *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
197                 void (push_directory_entry)(char *, squashfs_inode, int), squashfs_fragment_entry **fragment_table);
198 squashfs_inode get_sorted_inode(struct stat *buf);
199 int read_sort_file(char *filename, int source, char *source_path[]);
200 void sort_files_and_write(int source, char *source_path[]);
201 struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, int bytes, unsigned int **block_list, int *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes);
202
203 #define FALSE 0
204
205 #define MKINODE(A)      ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
206
207 /* BRCM begin */
208 #define LZMA    0
209 #define GZIP    1
210 int compress_algorithm = LZMA; 
211 /* BRCM end */
212
213 void restorefs()
214 {
215         ERROR("Exiting - restoring original filesystem!\n\n");
216         bytes = sbytes;
217         memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
218         memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
219         inode_bytes = sinode_bytes;
220         directory_bytes = sdirectory_bytes;
221         uid_count = suid_count;
222         guid_count = sguid_count;
223         total_bytes = stotal_bytes;
224         total_inode_bytes = stotal_inode_bytes;
225         total_directory_bytes = stotal_directory_bytes;
226         inode_count = sinode_count;
227         file_count = sfile_count;
228         sym_count = ssym_count;
229         dev_count = sdev_count;
230         dir_count = sdir_count;
231         dup_files = sdup_files;
232         fragments = sfragments;
233         fragment_size = 0;
234         longjmp(env, 1);
235 }
236
237
238 void sighandler()
239 {
240         if(interrupted == 1)
241                 restorefs();
242         else {
243                 ERROR("Interrupting will restore original filesystem!\n");
244                 ERROR("Interrupt again to quit\n");
245                 interrupted ++;
246         }
247 }
248
249
250 unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
251 {
252         unsigned long c_byte;
253         unsigned int res;
254
255         /* BRCM begin */
256         if (compress_algorithm == GZIP) {
257                 c_byte = block_size << 1;
258                 if(!uncompressed && (res = compress2(d, &c_byte, s, size, 9)) != Z_OK) {
259                         if(res == Z_MEM_ERROR)
260                                 BAD_ERROR("zlib::compress failed, not enough memory\n");
261                         else if(res == Z_BUF_ERROR)
262                                 BAD_ERROR("zlib::compress failed, not enough room in output buffer\n");
263                         else
264                                 BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
265                         return 0;
266                 }                       
267         }
268
269         if (compress_algorithm == LZMA) {
270                 unsigned lzma_algo;
271                 unsigned lzma_dictsize;
272                 unsigned lzma_fastbytes;
273                 int opt_compression_level = 1;
274
275                 c_byte = block_size << 3;
276                 switch (opt_compression_level) {
277                 case 1 :
278                         lzma_algo = 1;
279                         lzma_dictsize = 1 << 20;
280                         lzma_fastbytes = 64;
281                         break;
282                 case 2 :
283                         lzma_algo = 2;
284                         lzma_dictsize = 1 << 22;
285                         lzma_fastbytes = 128;
286                         break;
287                 case 3 :
288                         lzma_algo = 2;
289                         lzma_dictsize = 1 << 24;
290                         lzma_fastbytes = 255;
291                         break;
292                 default :
293                         BAD_ERROR("Invalid LZMA compression level. Must be 1,2,3.");
294                         return 0;
295                 }
296                 if(!uncompressed && !(res = compress_lzma_7zapi((const unsigned char*)s, 
297                                                                 (unsigned)size, 
298                                                                 (unsigned char*)d,
299                                                                 (unsigned *)&c_byte,
300                                                                 lzma_algo, lzma_dictsize, lzma_fastbytes))) {
301                         /* this should NEVER happen */
302                         BAD_ERROR("Internal error - LZMA compression failed.\n");
303                         return 0;
304                 }
305                 //printf("LZMA: block_size=%d, in_size=%d, out_size=%d\n", block_size, size, c_byte);
306         }
307         /* BRCM end */
308         
309         if(uncompressed || c_byte >= size) {
310                 memcpy(d, s, size);
311                 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
312         }
313
314         return (unsigned int) c_byte;
315 }
316
317
318 squashfs_base_inode_header *get_inode(int req_size)
319 {
320         int data_space;
321         unsigned short c_byte;
322
323         while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
324                 if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
325                         if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
326                                         == NULL) {
327                                 goto failed;
328                         }
329                         inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
330                 }
331
332                 c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
333                                                                 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
334                 TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
335                 if(!swap)
336                         memcpy((void *) (inode_table + inode_bytes), (void *) &c_byte, sizeof(unsigned short));
337                 else
338                         SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
339                 if(check_data)
340                         *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
341                 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
342                 total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
343                 memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
344                 cache_bytes -= SQUASHFS_METADATA_SIZE;
345         }
346
347         data_space = (cache_size - cache_bytes);
348         if(data_space < req_size) {
349                         int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
350
351                         if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
352                                 goto failed;
353                         }
354                         cache_size += realloc_size;
355         }
356
357         cache_bytes += req_size;
358
359         return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
360
361 failed:
362         BAD_ERROR("Out of memory in inode table reallocation!\n");
363 }
364
365
366 void read_bytes(int fd, unsigned int byte, int bytes, char *buff)
367 {
368         off_t off = byte;
369
370         if(lseek(fd, off, SEEK_SET) == -1) {
371                 perror("Lseek on destination failed");
372                 EXIT_MKSQUASHFS();
373         }
374
375         if(read(fd, buff, bytes) == -1) {
376                 perror("Read on destination failed");
377                 EXIT_MKSQUASHFS();
378         }
379 }
380
381
382 void write_bytes(int fd, unsigned int byte, int bytes, char *buff)
383 {
384         off_t off = byte;
385
386         if(off + bytes > ((long long)1<<32) - 1 )
387                 BAD_ERROR("Filesystem greater than maximum size 2^32 - 1\n");
388
389         if(lseek(fd, off, SEEK_SET) == -1) {
390                 perror("Lseek on destination failed");
391                 EXIT_MKSQUASHFS();
392         }
393
394         if(write(fd, buff, bytes) == -1) {
395                 perror("Write on destination failed");
396                 EXIT_MKSQUASHFS();
397         }
398 }
399
400
401 unsigned int write_inodes()
402 {
403         unsigned short c_byte;
404         int avail_bytes;
405         char *datap = data_cache;
406         unsigned int start_bytes = bytes;
407
408         while(cache_bytes) {
409                 if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
410                         if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
411                                 BAD_ERROR("Out of memory in inode table reallocation!\n");
412                         }
413                         inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
414                 }
415                 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
416                 c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
417                 TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte);
418                 if(!swap)
419                         memcpy((void *) (inode_table + inode_bytes), (void *) &c_byte, sizeof(unsigned short));
420                 else
421                         SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1); 
422                 if(check_data)
423                         *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
424                 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
425                 total_inode_bytes += avail_bytes + block_offset;
426                 datap += avail_bytes;
427                 cache_bytes -= avail_bytes;
428         }
429
430         write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
431         bytes += inode_bytes;
432
433         return start_bytes;
434 }
435
436
437 unsigned int write_directories()
438 {
439         unsigned short c_byte;
440         int avail_bytes;
441         char *directoryp = directory_data_cache;
442         unsigned int start_bytes = bytes;
443
444         while(directory_cache_bytes) {
445                 if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
446                         if((directory_table = (char *) realloc(directory_table, directory_size +
447                                         ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
448                                 BAD_ERROR("Out of memory in directory table reallocation!\n");
449                         }
450                         directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
451                 }
452                 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
453                 c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
454                 TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
455                 if(!swap)
456                         memcpy((void *) (directory_table + directory_bytes), (void *) &c_byte, sizeof(unsigned short));
457                 else
458                         SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
459                 if(check_data)
460                         *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
461                 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
462                 total_directory_bytes += avail_bytes + block_offset;
463                 directoryp += avail_bytes;
464                 directory_cache_bytes -= avail_bytes;
465         }
466         write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
467         bytes += directory_bytes;
468
469         return start_bytes;
470 }
471
472
473 unsigned int get_uid(squashfs_uid uid)
474 {
475         int i;
476
477         for(i = 0; (i < uid_count) && uids[i] != uid; i++);
478         if(i == uid_count) {
479                 if(uid_count == SQUASHFS_UIDS) {
480                         ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
481                         i = 0;
482                 } else
483                         uids[uid_count++] = uid;
484         }
485
486         return i;
487 }
488
489
490 unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
491 {
492         int i;
493
494         if(uid == guid)
495                 return SQUASHFS_GUIDS;
496
497         for(i = 0; (i < guid_count) && guids[i] != guid; i++);
498         if(i == guid_count) {
499                 if(guid_count == SQUASHFS_GUIDS) {
500                         ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
501                         return SQUASHFS_GUIDS;
502                 } else
503                         guids[guid_count++] = guid;
504         }
505
506         return i;
507 }
508
509
510 squashfs_inode create_inode(char *filename, int type, int byte_size,
511 squashfs_block start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment)
512 {
513         squashfs_inode i_no;
514         struct stat buf;
515         squashfs_inode_header inode_header;
516         squashfs_base_inode_header *inode, *base = &inode_header.base;
517
518         if(filename[0] == '\0') {
519                 /* dummy top level directory, if multiple sources specified on command line */
520                 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
521                 buf.st_uid = getuid();
522                 buf.st_gid = getgid();
523                 buf.st_mtime = time(NULL);
524         } else if(lstat(filename, &buf) == -1) {
525                 char buffer[8192];
526                 sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename);
527                 perror(buffer);
528                 return SQUASHFS_INVALID;
529         }
530
531         base->mode = SQUASHFS_MODE(buf.st_mode);
532         base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf.st_uid : global_uid);
533         base->inode_type = type;
534         base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf.st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf.st_gid : global_gid);
535
536         if(type == SQUASHFS_FILE_TYPE) {
537                 int i;
538                 squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
539
540                 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
541                 inodep = (squashfs_reg_inode_header *) inode;
542                 reg->mtime = buf.st_mtime;
543                 reg->file_size = byte_size;
544                 reg->start_block = start_block;
545                 reg->fragment = fragment->index;
546                 reg->offset = fragment->offset;
547                 if(!swap) {
548                         memcpy((void *) inodep, (void *) reg, sizeof(*reg));
549                         memcpy((void *) inodep->block_list, block_list, offset * sizeof(unsigned int));
550                 } else {
551                         SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
552                         SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
553                 }
554                 TRACE("File inode, file_size %d, start_block %x, blocks %d, fragment %d, offset %d, size %d\n", byte_size,
555                         start_block, offset, fragment->index, fragment->offset, fragment->size);
556                 for(i = 0; i < offset; i++)
557                         TRACE("Block %d, size %d\n", i, block_list[i]);
558         }
559         else if(type == SQUASHFS_DIR_TYPE) {
560                 squashfs_dir_inode_header *dir = &inode_header.dir;
561
562                 inode = get_inode(sizeof(*dir));
563                 dir->mtime = buf.st_mtime;
564                 dir->file_size = byte_size;
565                 dir->offset = offset;
566                 dir->start_block = start_block;
567                 if(!swap)
568                         memcpy((void *) inode, (void *) dir, sizeof(*dir));
569                 else
570                         SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
571                 TRACE("Directory inode, file_size %d, start_block %x, offset %x\n", byte_size,
572                         start_block, offset);
573         }
574         else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
575                 squashfs_dev_inode_header *dev = &inode_header.dev;
576
577                 inode = get_inode(sizeof(*dev));
578                 dev->rdev = (unsigned short) ((major(buf.st_rdev) << 8) |
579                         (minor(buf.st_rdev) & 0xff));
580                 if(!swap)
581                         memcpy((void *) inode, (void *) dev, sizeof(*dev));
582                 else
583                         SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
584                 TRACE("Device inode, rdev %x\n", dev->rdev);
585         }
586         else if(type == SQUASHFS_SYMLINK_TYPE) {
587                 squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
588                 int byte;
589                 char buff[65536];
590
591                 if((byte = readlink(filename, buff, 65536)) == -1) {
592                         perror("Error in reading symbolic link, skipping...");
593                         return SQUASHFS_INVALID;
594                 }
595
596                 if(byte == 65536) {
597                         ERROR("Symlink is greater than 65536 bytes! skipping...");
598                         return SQUASHFS_INVALID;
599                 }
600
601                 inode = get_inode(sizeof(*symlink) + byte);
602                 inodep = (squashfs_symlink_inode_header *) inode;
603
604                 symlink->symlink_size = byte;
605                 if(!swap)
606                         memcpy((void *) inode, symlink, sizeof(*symlink));
607                 else
608                         SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
609                 strncpy(inodep->symlink, buff, byte);
610                 TRACE("Symbolic link inode, symlink_size %d\n",  byte);
611         }
612         else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
613                 squashfs_ipc_inode_header *ipc = &inode_header.ipc;
614
615                 inode = get_inode(sizeof(*ipc));
616                 if(!swap)
617                         memcpy((void *) inode, (void *) ipc, sizeof(*ipc));
618                 else
619                         SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
620                 TRACE("ipc inode, type %s %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket");
621         } else
622                 return SQUASHFS_INVALID;
623
624         i_no = MKINODE(inode);
625         inode_count ++;
626
627         TRACE("Created inode 0x%Lx, type %d, uid %d, guid %d\n", i_no, type, base->uid, base->guid);
628
629         return i_no;
630 }
631
632
633 void init_dir(struct directory *dir)
634 {
635         if((dir->buff = (char *)malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
636                 BAD_ERROR("Out of memory allocating directory buffer\n");
637         }
638
639         dir->size = SQUASHFS_METADATA_SIZE;
640         dir->p = dir->buff;
641         dir->entry_count = 256;
642         dir->entry_count_p = NULL;
643 }
644
645
646 void add_dir(squashfs_inode inode, char *name, int type, struct directory *dir)
647 {
648         char *buff;
649         squashfs_dir_entry idir, *idirp;
650         unsigned int start_block = inode >> 16;
651         unsigned int offset = inode & 0xffff;
652         unsigned int size;
653
654         if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
655                 size = SQUASHFS_NAME_LEN;
656                 ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
657         }
658
659         if(dir->p + sizeof(squashfs_dir_entry) + size + 6 >= dir->buff + dir->size) {
660                 if((buff = (char *) realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL)  {
661                         BAD_ERROR("Out of memory reallocating directory buffer\n");
662                 }
663
664                 dir->p = (dir->p - dir->buff) + buff;
665                 if(dir->entry_count_p) 
666                         dir->entry_count_p = (squashfs_dir_header *) (((unsigned char *) dir->entry_count_p) -
667                                 dir->buff + buff);
668                 dir->buff = buff;
669         }
670
671         if(dir->entry_count == 256 || start_block != dir->start_block) {
672                 if(dir->entry_count_p) {
673                         squashfs_dir_header dir_header;
674
675                         dir_header.count = dir->entry_count - 1;
676                         dir_header.start_block = dir->start_block;
677                         if(!swap)
678                                 memcpy((void *) dir->entry_count_p, (void *) &dir_header, sizeof(dir_header));
679                         else
680                                 SQUASHFS_SWAP_DIR_HEADER((&dir_header), dir->entry_count_p);
681                 }
682
683                 dir->entry_count_p = (squashfs_dir_header *) dir->p;
684                 dir->start_block = start_block;
685                 dir->entry_count = 0;
686                 dir->p += sizeof(squashfs_dir_header);
687         }
688
689         idirp = (squashfs_dir_entry *) dir->p;
690         idir.offset = offset;
691         idir.type = type;
692         idir.size = size - 1;
693         if(!swap)
694                 memcpy((void *) idirp, (void *) &idir, sizeof(idir));
695         else
696                 SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
697         strncpy(idirp->name, name, size);
698         dir->p += sizeof(squashfs_dir_entry) + size;
699         dir->entry_count ++;
700 }
701
702
703 squashfs_inode write_dir(char *filename, struct directory *dir)
704 {
705         squashfs_inode inode;
706         unsigned int dir_size;
707         int data_space;
708         unsigned short c_byte;
709
710         while(directory_cache_bytes >= SQUASHFS_METADATA_SIZE) {
711                 if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
712                         if((directory_table = (char *) realloc(directory_table,
713                                                         directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
714                                 goto failed;
715                         }
716                         directory_size += SQUASHFS_METADATA_SIZE << 1;
717                 }
718
719                 c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
720                                 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
721                 TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte);
722                 if(!swap)
723                         memcpy((void *) directory_table + directory_bytes, (void *) &c_byte, sizeof(unsigned short));
724                 else
725                         SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
726                 if(check_data)
727                         *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
728                 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
729                 total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
730                 memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
731                 directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
732         }
733
734         dir_size = dir->p - dir->buff;
735         data_space = (directory_cache_size - directory_cache_bytes);
736         if(data_space < dir_size) {
737                 int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
738
739                 if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
740                         goto failed;
741                 }
742                 directory_cache_size += realloc_size;
743         }
744
745         if(dir_size) {
746                 squashfs_dir_header dir_header;
747
748                 dir_header.count = dir->entry_count - 1;
749                 dir_header.start_block = dir->start_block;
750                 if(!swap)
751                         memcpy((void *) dir->entry_count_p, (void *) &dir_header, sizeof(dir_header));
752                 else
753                         SQUASHFS_SWAP_DIR_HEADER((&dir_header), dir->entry_count_p);
754                 memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
755         }
756
757         inode = create_inode(filename, SQUASHFS_DIR_TYPE, dir_size, directory_bytes, directory_cache_bytes, NULL, NULL);
758
759         directory_cache_bytes += dir_size;
760
761 #ifdef SQUASHFS_TRACE
762         if(!swap) {
763                 unsigned char *dirp;
764                 int count;
765
766                 TRACE("Directory contents of inode 0x%Lx\n", inode);
767                 dirp = dir->buff;
768                 while(dirp < dir->p) {
769                         char buffer[SQUASHFS_NAME_LEN + 1];
770                         squashfs_dir_entry idir, *idirp;
771                         squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
772                         count = dirh->count + 1;
773                         dirp += sizeof(squashfs_dir_header);
774
775                         TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
776
777                         while(count--) {
778                                 idirp = (squashfs_dir_entry *) dirp;
779                                 memcpy((char *) &idir, (char *) idirp, sizeof(idir));
780                                 strncpy(buffer, idirp->name, idir.size + 1);
781                                 buffer[idir.size + 1] = '\0';
782                                 TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
783                                                   idir.offset, idir.type);
784                                 dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
785                         }
786                 }
787         }
788 #endif
789         dir_count ++;
790
791         return inode;
792
793 failed:
794         BAD_ERROR("Out of memory in directory table reallocation!\n");
795 }
796
797
798 char *get_fragment(char *buffer, struct fragment *fragment)
799 {
800         if(fragment->index == fragments || fragment->index == SQUASHFS_INVALID_BLK)
801                 return fragment_data + fragment->offset;
802         else {
803                 squashfs_fragment_entry *disk_fragment = &fragment_table[fragment->index];
804                 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size), res;
805                 long bytes = block_size;
806
807                 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
808                         char cbuffer[block_size];
809
810                         read_bytes(fd, disk_fragment->start_block, size, cbuffer);
811
812                         if((res = uncompress(buffer, &bytes, (const char *) cbuffer, size)) != Z_OK) {
813                                 if(res == Z_MEM_ERROR)
814                                         BAD_ERROR("zlib::uncompress failed, not enough memory\n");
815                                 else if(res == Z_BUF_ERROR)
816                                         BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n");
817                                 else
818                                         BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res);
819                         }
820                 } else
821                         read_bytes(fd, disk_fragment->start_block, size, buffer);
822                 return buffer + fragment->offset;
823         }
824 }
825
826         
827 void write_fragment()
828 {
829         int compressed_size;
830         unsigned char buffer[block_size << 1];
831
832         if(fragment_size == 0)
833                 return;
834
835         if(fragments % FRAG_SIZE == 0)
836                 if((fragment_table = (squashfs_fragment_entry *) realloc(fragment_table, (fragments + FRAG_SIZE) * sizeof(squashfs_fragment_entry))) == NULL)
837                         BAD_ERROR("Out of memory in fragment table\n");
838         fragment_table[fragments].size = mangle(buffer, fragment_data, fragment_size, block_size, noF, 1);
839         fragment_table[fragments].start_block = bytes;
840         compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[fragments].size);
841         write_bytes(fd, bytes, compressed_size, buffer);
842         bytes += compressed_size;
843         total_uncompressed += fragment_size;
844         total_compressed += compressed_size;
845         TRACE("Writing fragment %d, uncompressed size %d, compressed size %d\n",fragments, fragment_size, compressed_size);
846         fragments ++;
847         fragment_size = 0;
848 }
849
850
851 static struct fragment empty_fragment = {SQUASHFS_INVALID_BLK, 0, 0};
852 struct fragment *get_and_fill_fragment(char *buff, int size)
853 {
854         struct fragment *ffrg;
855
856         if(size == 0)
857                 return &empty_fragment;
858
859         if(fragment_size + size > block_size)
860                 write_fragment();
861
862         if((ffrg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
863                 BAD_ERROR("Out of memory in fragment block allocation!\n");
864
865         ffrg->index = fragments;
866         ffrg->offset = fragment_size;
867         ffrg->size = size;
868         memcpy(fragment_data + fragment_size, buff, size);
869         fragment_size += size;
870
871         return ffrg;
872 }
873
874
875 unsigned int write_fragment_table()
876 {
877         unsigned int start_bytes, frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments),
878                 meta_blocks = SQUASHFS_FRAGMENT_INDEXES(fragments);
879         char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2], buffer[frag_bytes];
880         squashfs_fragment_entry *p = (squashfs_fragment_entry *) buffer;
881         unsigned short c_byte;
882         int i, compressed_size;
883         squashfs_fragment_index list[meta_blocks];
884
885         TRACE("write_fragment_table: fragments %d, frag_bytes %d, meta_blocks %d\n", fragments, frag_bytes, meta_blocks);
886         for(i = 0; i < fragments; i++, p++) {
887                 TRACE("write_fragment_table: fragment %d, start_block %x, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size);
888                 if(!swap)
889                         memcpy((void *) p, &fragment_table[i], sizeof(squashfs_fragment_entry));
890                 else
891                         SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p);
892         }
893
894         for(i = 0; i < meta_blocks; i++) {
895                 int avail_bytes = i == meta_blocks - 1 ? frag_bytes % SQUASHFS_METADATA_SIZE : SQUASHFS_METADATA_SIZE;
896                 c_byte = mangle(cbuffer + block_offset, buffer + i * SQUASHFS_METADATA_SIZE , avail_bytes, SQUASHFS_METADATA_SIZE, noF, 0);
897                 if(!swap)
898                         memcpy((void *) cbuffer, (void *) &c_byte, sizeof(unsigned short));
899                 else
900                         SQUASHFS_SWAP_SHORTS((&c_byte), cbuffer, 1);
901                 if(check_data)
902                         *((unsigned char *)(cbuffer + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
903                 list[i] = bytes;
904                 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
905                 write_bytes(fd, bytes, compressed_size, cbuffer);
906                 bytes += compressed_size;
907         }
908
909         if(!swap)
910                 write_bytes(fd, bytes, sizeof(list), (char *) list);
911         else {
912                 squashfs_fragment_index slist[meta_blocks];
913                 SQUASHFS_SWAP_FRAGMENT_INDEXES(list, slist, meta_blocks);
914                 write_bytes(fd, bytes, sizeof(list), (char *) slist);
915         }
916
917         start_bytes = bytes;
918         bytes += sizeof(list);
919
920         return start_bytes;
921 }
922
923
924 unsigned char *read_from_buffer(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
925 {
926         unsigned char *v = handle->ptr;
927         handle->ptr += avail_bytes;     
928         return v;
929 }
930
931
932 char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
933 unsigned char *read_from_file(struct duplicate_buffer_handle *handle, unsigned int avail_bytes)
934 {
935         read_bytes(fd, handle->start, avail_bytes, read_from_file_buffer);
936         handle->start += avail_bytes;
937         return read_from_file_buffer;
938 }
939
940
941 /*
942  * Compute 16 bit BSD checksum over the data
943  */
944 unsigned short get_checksum(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *handle, int l)
945 {
946         unsigned short chksum = 0;
947         unsigned int bytes = 0;
948         unsigned char *b;
949         struct duplicate_buffer_handle position = *handle;
950
951         while(l) {
952                 bytes = l > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : l;
953                 l -= bytes;
954                 b = get_next_file_block(&position, bytes);
955                 while(bytes--) {
956                         chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
957                         chksum += *b++;
958                 }
959         }
960
961         return chksum;
962 }
963
964
965 static unsigned int cached_frag = -1;
966 void add_file(int start, int file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes)
967 {
968         struct fragment *frg;
969         struct file_info *dupl_ptr;
970         char *datap;
971         struct duplicate_buffer_handle handle;
972         
973         if(!duplicate_checking)
974                 return;
975
976         if((frg = (struct fragment *) malloc(sizeof(struct fragment))) == NULL)
977                 BAD_ERROR("Out of memory in fragment block allocation!\n");
978
979         frg->index = fragment;
980         frg->offset = offset;
981         frg->size = bytes;
982         if(cached_frag == fragment)
983                 datap = fragment_data + offset;
984         else
985                 datap = get_fragment(fragment_data, frg);
986         handle.start = start;
987         if((dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &frg, datap, bytes)) != NULL)
988                 dupl_ptr->fragment = frg;
989         cached_frag = fragment;
990 }
991
992
993 struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, int bytes, unsigned int **block_list, int *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes)
994 {
995         unsigned short checksum = get_checksum(get_next_file_block, file_start, bytes);
996         struct duplicate_buffer_handle handle = { frag_data, 0 };
997         unsigned short fragment_checksum = get_checksum(read_from_buffer, &handle, frag_bytes);
998         struct file_info *dupl_ptr = bytes ? dupl[checksum] : frag_dups[fragment_checksum];
999
1000
1001         for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
1002                 if(bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size && fragment_checksum == dupl_ptr->fragment_checksum) {
1003                         unsigned char buffer1[SQUASHFS_FILE_MAX_SIZE];
1004                         unsigned int dup_bytes = dupl_ptr->bytes, dup_start = dupl_ptr->start;
1005                         struct duplicate_buffer_handle position = *file_start;
1006                         unsigned char *buffer;
1007                         while(dup_bytes) {
1008                                 int avail_bytes = dup_bytes > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : dup_bytes;
1009
1010                                 buffer = get_next_file_block(&position, avail_bytes);
1011                                 read_bytes(fd, dup_start, avail_bytes, buffer1);
1012                                 if(memcmp(buffer, buffer1, avail_bytes) != 0)
1013                                         break;
1014                                 dup_bytes -= avail_bytes;
1015                                 dup_start += avail_bytes;
1016                         }
1017                         if(dup_bytes == 0) {
1018                                 char frag_buffer1[block_size];
1019                                 char *fragment_buffer1 = get_fragment(frag_buffer1, dupl_ptr->fragment);
1020                                 if(frag_bytes == 0 || memcmp(frag_data, fragment_buffer1, frag_bytes) == 0) {
1021                                         TRACE("Found duplicate file, start 0x%x, size %d, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start,
1022                                                 dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum);
1023                                         *block_list = dupl_ptr->block_list;
1024                                         *start = dupl_ptr->start;
1025                                         *fragment = dupl_ptr->fragment;
1026                                         return 0;
1027                                 }
1028                         }
1029                 }
1030
1031
1032         if((dupl_ptr = (struct file_info *) malloc(sizeof(struct file_info))) == NULL) {
1033                 BAD_ERROR("Out of memory in dup_files allocation!\n");
1034         }
1035
1036         dupl_ptr->bytes = bytes;
1037         dupl_ptr->checksum = checksum;
1038         dupl_ptr->start = *start;
1039         dupl_ptr->fragment_checksum = fragment_checksum;
1040         if((dupl_ptr->block_list = (unsigned int *) malloc(blocks * sizeof(unsigned int))) == NULL) {
1041                 BAD_ERROR("Out of memory allocating block_list\n");
1042         }
1043         
1044         memcpy(dupl_ptr->block_list, *block_list, blocks * sizeof(unsigned int));
1045         dup_files ++;
1046         if(bytes) {
1047                 dupl_ptr->next = dupl[checksum];
1048                 dupl[checksum] = dupl_ptr;
1049         } else {
1050                 dupl_ptr->next = frag_dups[fragment_checksum];
1051                 frag_dups[fragment_checksum] = dupl_ptr;
1052         }
1053
1054         return dupl_ptr;
1055 }
1056
1057
1058 #define MINALLOCBYTES (1024 * 1024)
1059 squashfs_inode write_file(char *filename, long long size, int *duplicate_file)
1060 {
1061         unsigned int frag_bytes, file, start, file_bytes = 0, block = 0;
1062         unsigned int c_byte;
1063         long long read_size = (size > SQUASHFS_MAX_FILE_SIZE) ? SQUASHFS_MAX_FILE_SIZE : size;
1064         unsigned int blocks = (read_size + block_size - 1) >> block_log;
1065         unsigned int block_list[blocks], *block_listp = block_list;
1066         char buff[block_size], *c_buffer;
1067         int allocated_blocks = blocks, i, bbytes, whole_file = 1;
1068         struct fragment *fragment;
1069         struct file_info *dupl_ptr;
1070         struct duplicate_buffer_handle handle;
1071
1072         if(!no_fragments && (read_size < block_size || always_use_fragments)) {
1073                 allocated_blocks = blocks = read_size >> block_log;
1074                 frag_bytes = read_size % block_size;
1075         } else
1076                 frag_bytes = 0;
1077
1078         if(size > read_size)
1079                 ERROR("file %s truncated to %Ld bytes\n", filename, SQUASHFS_MAX_FILE_SIZE);
1080
1081         total_bytes += read_size;
1082         if((file = open(filename, O_RDONLY)) == -1) {
1083                 perror("Error in opening file, skipping...");
1084                 return SQUASHFS_INVALID;
1085         }
1086
1087         do {
1088                 if((c_buffer = (char *) malloc((allocated_blocks + 1) << block_log)) == NULL) {
1089                         TRACE("Out of memory allocating write_file buffer, allocated_blocks %d, blocks %d\n", allocated_blocks, blocks);
1090                         whole_file = 0;
1091                         if((allocated_blocks << (block_log - 1)) < MINALLOCBYTES)
1092                                 BAD_ERROR("Out of memory allocating write_file buffer, could not allocate %d blocks (%d Kbytes)\n", allocated_blocks, allocated_blocks << (block_log - 10));
1093                         allocated_blocks >>= 1;
1094                 }
1095         } while(!c_buffer);
1096
1097         for(start = bytes; block < blocks; file_bytes += bbytes) {
1098                 for(i = 0, bbytes = 0; (i < allocated_blocks) && (block < blocks); i++) {
1099                         int available_bytes = read_size - (block * block_size) > block_size ? block_size : read_size - (block * block_size);
1100                         if(read(file, buff, available_bytes) == -1)
1101                                 goto read_err;
1102                         c_byte = mangle(c_buffer + bbytes, buff, available_bytes, block_size, noD, 1);
1103                         block_list[block ++] = c_byte;
1104                         bbytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
1105                 }
1106                 if(!whole_file) {
1107                         write_bytes(fd, bytes, bbytes, c_buffer);
1108                         bytes += bbytes;
1109                 }
1110         }
1111
1112         if(frag_bytes != 0)
1113                 if(read(file, buff, frag_bytes) == -1)
1114                         goto read_err;
1115
1116         close(file);
1117         if(whole_file) {
1118                 handle.ptr = c_buffer;
1119                 if(duplicate_checking && (dupl_ptr = duplicate(read_from_buffer, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
1120                         *duplicate_file = TRUE;
1121                         goto wr_inode;
1122                 }
1123                 write_bytes(fd, bytes, file_bytes, c_buffer);
1124                 bytes += file_bytes;
1125         } else {
1126                 handle.start = start;
1127                 if(duplicate_checking && (dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &fragment, buff, frag_bytes)) == NULL) {
1128                         bytes = start;
1129                         if(!block_device)
1130                                 ftruncate(fd, bytes);
1131                         *duplicate_file = TRUE;
1132                         goto wr_inode;
1133                 }
1134         }
1135
1136         fragment = get_and_fill_fragment(buff, frag_bytes);
1137         if(duplicate_checking)
1138                 dupl_ptr->fragment = fragment;
1139
1140         *duplicate_file = FALSE;
1141
1142 wr_inode:
1143         free(c_buffer);
1144         file_count ++;
1145         return create_inode(filename, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment);
1146
1147 read_err:
1148         perror("Error in reading file, skipping...");
1149         free(c_buffer);
1150         return SQUASHFS_INVALID;
1151 }
1152
1153
1154 struct linuxdir {
1155         DIR     *linuxdir;
1156         char    pathname[8192];
1157 };
1158
1159
1160 void *linux_opendir(char *pathname, struct directory *dir)
1161 {
1162         struct linuxdir *linuxdir;
1163         if((linuxdir = malloc(sizeof(struct linuxdir))) == NULL)
1164                 return NULL;
1165         if((linuxdir->linuxdir = opendir(pathname)) == NULL) {
1166                 free(linuxdir);
1167                 return NULL;
1168         }
1169         strcpy(linuxdir->pathname, pathname);
1170         return (void *) linuxdir;
1171 }
1172
1173
1174 int linux_readdir(void *l, char *filename, char *dir_name)
1175 {
1176         struct dirent *d_name;
1177         struct linuxdir *linuxdir = (struct linuxdir *)l;
1178
1179         do {
1180                 if((d_name = readdir(linuxdir->linuxdir)) == NULL)
1181                         return FALSE;
1182         } while(strcmp(d_name->d_name, ".") == 0 || strcmp(d_name->d_name, "..") == 0);
1183         strcat(strcat(strcpy(filename, linuxdir->pathname), "/"), d_name->d_name);
1184         strcpy(dir_name, d_name->d_name);
1185         return TRUE;
1186 }
1187
1188
1189 void linux_closedir(void *linuxdir)
1190 {
1191         closedir(((struct linuxdir *)linuxdir)->linuxdir);
1192         free(linuxdir);
1193 }
1194
1195
1196 char b_buffer[8192];
1197 char *name;
1198 char *basename_r();
1199
1200 char *getbase(char *pathname)
1201 {
1202         char *result;
1203
1204         if(*pathname != '/') {
1205                 result = getenv("PWD");
1206                 strcat(strcat(strcpy(b_buffer, result), "/"), pathname);
1207         } else
1208                 strcpy(b_buffer, pathname);
1209         name = b_buffer;
1210         if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
1211                 return NULL;
1212         else
1213                 return result;
1214 }
1215
1216
1217 char *basename_r()
1218 {
1219         char *s;
1220         char *p;
1221         int n = 1;
1222
1223         for(;;) {
1224                 s = name;
1225                 if(*name == '\0')
1226                         return NULL;
1227                 if(*name != '/') {
1228                         while(*name != '\0' && *name != '/') name++;
1229                         n = name - s;
1230                 }
1231                 while(*name == '/') name++;
1232                 if(strncmp(s, ".", n) == 0)
1233                         continue;
1234                 if((*name == '\0') || (strncmp(s, "..", n) == 0) || ((p = basename_r()) == NULL)) {
1235                         s[n] = '\0';
1236                         return s;
1237                 }
1238                 if(strcmp(p, "..") == 0)
1239                         continue;
1240                 return p;
1241         }
1242 }
1243
1244
1245 char encomp_pathname[8192];
1246 int encomp_entry = 0;
1247
1248 void *encomp_opendir(char *pathname, struct directory *dir)
1249 {
1250         int i;
1251
1252         for(i = 0; i < old_root_entries; i++)
1253                 add_dir(old_root_entry[i].inode, old_root_entry[i].name, old_root_entry[i].type, dir);
1254
1255         return (void *)source_path;
1256 }
1257
1258
1259 int encomp_readdir(void *l, char *filename, char *dir_name)
1260 {
1261         char *basename;
1262         int n, pass = 1;
1263
1264         while(encomp_entry < source) {
1265                 if((basename = getbase(source_path[encomp_entry])) == NULL) {
1266                         ERROR("Bad source directory %s - skipping ...\n", source_path[encomp_entry]);
1267                         encomp_entry++;
1268                         continue;
1269                 }
1270                 strcpy(filename, source_path[encomp_entry]);
1271                 strcpy(dir_name, basename);
1272                 for(;;) {
1273                         for(n = 0; n < old_root_entries && strcmp(old_root_entry[n].name, dir_name) != 0; n++);
1274                         if(n == old_root_entries) {
1275                                 add_old_root_entry(dir_name, 0, 0);
1276                                 encomp_entry++;
1277                                 return TRUE;
1278                         }
1279                         ERROR("Source directory entry %s already used! - trying ", dir_name);
1280                         sprintf(dir_name, "%s_%d", basename, pass++);
1281                         ERROR("%s\n", dir_name);
1282                 }
1283         }
1284         return FALSE;
1285 }
1286
1287
1288 void encomp_closedir(void *linuxdir)
1289 {
1290 }
1291
1292
1293 void *single_opendir(char *pathname, struct directory *dir)
1294 {
1295         encomp_opendir(pathname, dir);
1296         return linux_opendir(pathname, dir);
1297 }
1298
1299
1300 int single_readdir(void *l, char *filename, char *dir_name)
1301 {
1302         int i, pass = 1;
1303         char name[SQUASHFS_NAME_LEN + 1];
1304
1305         if(linux_readdir(l, filename, dir_name) == FALSE)
1306                 return FALSE;
1307
1308         strcpy(name, dir_name);
1309         for(;;) {
1310                 for(i = 0; i < old_root_entries && strcmp(old_root_entry[i].name, dir_name) != 0; i++);
1311                 if(i == old_root_entries) {
1312                         add_old_root_entry(dir_name, 0, 0);
1313                         return TRUE;
1314                 }
1315                 ERROR("Source directory entry %s already used! - trying ", dir_name);
1316                 sprintf(dir_name, "%s_%d", name, pass++);
1317                 ERROR("%s\n", dir_name);
1318         }
1319 }
1320
1321
1322 squashfs_inode dir_scan(char *pathname, void* (_opendir)(char *, struct directory *), int (_readdir)(void *, char *, char *),
1323                 void (_closedir)(void *))
1324 {
1325         void *linuxdir;
1326         struct stat buf;
1327         char filename[8192], dir_name[8192];
1328         int squashfs_type;
1329         squashfs_inode inode = SQUASHFS_INVALID;
1330         struct directory dir;
1331         
1332         init_dir(&dir);
1333         if((linuxdir = _opendir(pathname, &dir)) == NULL) {
1334                 ERROR("Could not open %s, skipping...\n", pathname);
1335                 goto error;
1336         }
1337         
1338         while(_readdir(linuxdir, filename, dir_name) != FALSE) {
1339
1340                 if(lstat(filename, &buf) == -1) {
1341                         char buffer[8192];
1342                         sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename);
1343                         perror(buffer);
1344                         continue;
1345                 }
1346                 if(excluded(filename, &buf))
1347                         continue;
1348
1349                 switch(buf.st_mode & S_IFMT) {
1350                         case S_IFREG: {
1351                                 int duplicate_file;
1352
1353                                 squashfs_type = SQUASHFS_FILE_TYPE;
1354                                 if(!sorted) {
1355                                         inode = write_file(filename, buf.st_size, &duplicate_file);
1356                                         INFO("file %s, uncompressed size %Ld bytes, %s\n", filename, buf.st_size, duplicate_file ? "DUPLICATE" : "");
1357                                 } else
1358                                         inode = get_sorted_inode(&buf);
1359                                 break;
1360                         }
1361                         case S_IFDIR:
1362                                 squashfs_type = SQUASHFS_DIR_TYPE;
1363                                 inode = dir_scan(filename, linux_opendir, linux_readdir, linux_closedir);
1364                                 break;
1365
1366                         case S_IFLNK:
1367                                 squashfs_type = SQUASHFS_SYMLINK_TYPE;
1368                                 inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL);
1369                                 INFO("symbolic link %s inode 0x%Lx\n", dir_name, inode);
1370                                 sym_count ++;
1371                                 break;
1372
1373                         case S_IFCHR:
1374                                 squashfs_type = SQUASHFS_CHRDEV_TYPE;
1375                                 inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL);
1376                                 INFO("character device %s inode 0x%Lx\n", dir_name, inode);
1377                                 dev_count ++;
1378                                 break;
1379
1380                         case S_IFBLK:
1381                                 squashfs_type = SQUASHFS_BLKDEV_TYPE;
1382                                 inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL);
1383                                 INFO("block device %s inode 0x%Lx\n", dir_name, inode);
1384                                 dev_count ++;
1385                                 break;
1386
1387                         case S_IFIFO:
1388                                 squashfs_type = SQUASHFS_FIFO_TYPE;
1389                                 inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL);
1390                                 INFO("fifo %s inode 0x%Lx\n", dir_name, inode);
1391                                 fifo_count ++;
1392                                 break;
1393
1394                         case S_IFSOCK:
1395                                 squashfs_type = SQUASHFS_SOCKET_TYPE;
1396                                 inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL);
1397                                 INFO("unix domain socket %s inode 0x%Lx\n", dir_name, inode);
1398                                 sock_count ++;
1399                                 break;
1400
1401                          default:
1402                                 ERROR("%s unrecognised file type, mode is %x\n", filename, buf.st_mode);
1403                                 continue;
1404                         }
1405
1406                 if(inode != SQUASHFS_INVALID)
1407                         add_dir(inode, dir_name, squashfs_type, &dir);
1408         }
1409
1410         _closedir(linuxdir);
1411         inode = write_dir(pathname, &dir);
1412         INFO("directory %s inode 0x%Lx\n", pathname, inode);
1413
1414 error:
1415         free(dir.buff);
1416
1417         return inode;
1418 }
1419
1420
1421 unsigned int slog(unsigned int block)
1422 {
1423         int i;
1424
1425         for(i = 9; i <= 16; i++)
1426                 if(block == (1 << i))
1427                         return i;
1428         return 0;
1429 }
1430
1431
1432 int excluded(char *filename, struct stat *buf)
1433 {
1434         int i;
1435
1436         for(i = 0; i < exclude; i++)
1437                 if((exclude_paths[i].st_dev == buf->st_dev) && (exclude_paths[i].st_ino == buf->st_ino))
1438                         return TRUE;
1439         return FALSE;
1440 }
1441
1442
1443 #define ADD_ENTRY(buf) \
1444         if(exclude % EXCLUDE_SIZE == 0) {\
1445                 if((exclude_paths = (struct exclude_info *) realloc(exclude_paths, (exclude + EXCLUDE_SIZE) * sizeof(struct exclude_info))) == NULL)\
1446                         BAD_ERROR("Out of memory in exclude dir/file table\n");\
1447         }\
1448         exclude_paths[exclude].st_dev = buf.st_dev;\
1449         exclude_paths[exclude++].st_ino = buf.st_ino;
1450 int add_exclude(char *path)
1451 {
1452         int i;
1453         char buffer[4096], filename[4096];
1454         struct stat buf;
1455
1456         if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
1457                 if(lstat(path, &buf) == -1) {
1458                         sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", path);
1459                         perror(buffer);
1460                         return TRUE;
1461                 }
1462                 ADD_ENTRY(buf);
1463                 return TRUE;
1464         }
1465
1466         for(i = 0; i < source; i++) {
1467                 strcat(strcat(strcpy(filename, source_path[i]), "/"), path);
1468                 if(lstat(filename, &buf) == -1) {
1469                         if(!(errno == ENOENT || errno == ENOTDIR)) {
1470                                 sprintf(buffer, "Cannot stat exclude dir/file %s, ignoring", filename);
1471                                 perror(buffer);
1472                         }
1473                         continue;
1474                 }
1475                 ADD_ENTRY(buf);
1476         }
1477         return TRUE;
1478 }
1479
1480
1481 void add_old_root_entry(char *name, squashfs_inode inode, int type)
1482 {
1483         if((old_root_entry = (struct old_root_entry_info *) realloc(old_root_entry, sizeof(struct old_root_entry_info)
1484                                 * (old_root_entries + 1))) == NULL)
1485                 BAD_ERROR("Out of memory in old root directory entries reallocation\n");
1486
1487         strcpy(old_root_entry[old_root_entries].name, name);
1488         old_root_entry[old_root_entries].inode = inode;
1489         old_root_entry[old_root_entries++].type = type;
1490 }
1491
1492
1493 #define VERSION() \
1494         printf("mksquashfs version 2.0\n");\
1495         printf("copyright (C) 2004 Phillip Lougher (plougher@users.sourceforge.net)\n\n"); \
1496         printf("This program is free software; you can redistribute it and/or\n");\
1497         printf("modify it under the terms of the GNU General Public License\n");\
1498         printf("as published by the Free Software Foundation; either version 2,\n");\
1499         printf("or (at your option) any later version.\n\n");\
1500         printf("This program is distributed in the hope that it will be useful,\n");\
1501         printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
1502         printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
1503         printf("GNU General Public License for more details.\n");
1504 int main(int argc, char *argv[])
1505 {
1506         struct stat buf;
1507         int i;
1508         squashfs_super_block sBlk;
1509         char *b, *root_name = NULL;
1510         int be, nopad = FALSE, delete = FALSE, keep_as_directory = FALSE, orig_be;
1511
1512 #if __BYTE_ORDER == __BIG_ENDIAN
1513         be = TRUE;
1514 #else
1515         be = FALSE;
1516 #endif
1517
1518         block_log = slog(block_size);
1519         if(argc > 1 && strcmp(argv[1], "-version") == 0) {
1520                 VERSION();
1521                 exit(0);
1522         }
1523         for(i = 1; i < argc && argv[i][0] != '-'; i++);
1524         if(i < 3)
1525                 goto printOptions;
1526         source_path = argv + 1;
1527         source = i - 2;
1528         for(; i < argc; i++) {
1529                 if(strcmp(argv[i], "-b") == 0) {
1530                         if((++i == argc) || (block_size = strtol(argv[i], &b, 10), *b !='\0')) {
1531                                 ERROR("%s: -b missing or invalid block size\n", argv[0]);
1532                                 exit(1);
1533                         }
1534
1535                         if((block_log = slog(block_size)) == 0) {
1536                                 ERROR("%s: -b block size not power of two or not between 512 and 64K\n", argv[0]);
1537                                 exit(1);
1538                         }
1539                 } else if(strcmp(argv[i], "-ef") == 0) {
1540                         if(++i == argc) {
1541                                 ERROR("%s: -ef missing filename\n", argv[0]);
1542                                 exit(1);
1543                         }
1544                 } else if(strcmp(argv[i], "-no-duplicates") == 0)
1545                         duplicate_checking = FALSE;
1546
1547                 else if(strcmp(argv[i], "-no-fragments") == 0)
1548                         no_fragments = TRUE;
1549
1550                  else if(strcmp(argv[i], "-always-use-fragments") == 0)
1551                         always_use_fragments = TRUE;
1552
1553                  else if(strcmp(argv[i], "-sort") == 0) {
1554                         if(++i == argc) {
1555                                 ERROR("%s: -sort missing filename\n", argv[0]);
1556                                 exit(1);
1557                         }
1558                 } else if(strcmp(argv[i], "-all-root") == 0 ||
1559                                 strcmp(argv[i], "-root-owned") == 0)
1560                         global_uid = global_gid = 0;
1561
1562                 else if(strcmp(argv[i], "-force-uid") == 0) {
1563                         if(++i == argc) {
1564                                 ERROR("%s: -force-uid missing uid or user\n", argv[0]);
1565                                 exit(1);
1566                         }
1567                         if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
1568                                 if(global_uid < 0 || global_uid > (((long long) 1 << 32) - 1)) {
1569                                         ERROR("%s: -force-uid uid out of range\n", argv[0]);
1570                                         exit(1);
1571                                 }
1572                         } else {
1573                                 struct passwd *uid = getpwnam(argv[i]);
1574                                 if(uid)
1575                                         global_uid = uid->pw_uid;
1576                                 else {
1577                                         ERROR("%s: -force-uid invalid uid or unknown user\n", argv[0]);
1578                                         exit(1);
1579                                 }
1580                         }
1581                 } else if(strcmp(argv[i], "-force-gid") == 0) {
1582                         if(++i == argc) {
1583                                 ERROR("%s: -force-gid missing gid or group\n", argv[0]);
1584                                 exit(1);
1585                         }
1586                         if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
1587                                 if(global_gid < 0 || global_gid > (((long long) 1 << 32) - 1)) {
1588                                         ERROR("%s: -force-gid gid out of range\n", argv[0]);
1589                                         exit(1);
1590                                 }
1591                         } else {
1592                                 struct group *gid = getgrnam(argv[i]);
1593                                 if(gid)
1594                                         global_gid = gid->gr_gid;
1595                                 else {
1596                                         ERROR("%s: -force-gid invalid gid or unknown group\n", argv[0]);
1597                                         exit(1);
1598                                 }
1599                         }
1600                 } else if(strcmp(argv[i], "-noI") == 0 ||
1601                                 strcmp(argv[i], "-noInodeCompression") == 0)
1602                         noI = TRUE;
1603
1604                 else if(strcmp(argv[i], "-noD") == 0 ||
1605                                 strcmp(argv[i], "-noDataCompression") == 0)
1606                         noD = TRUE;
1607
1608                 else if(strcmp(argv[i], "-noF") == 0 ||
1609                                 strcmp(argv[i], "-noFragmentCompression") == 0)
1610                         noF = TRUE;
1611
1612                 else if(strcmp(argv[i], "-nopad") == 0)
1613                         nopad = TRUE;
1614
1615                 else if(strcmp(argv[i], "-check_data") == 0)
1616                         check_data = TRUE;
1617
1618                 else if(strcmp(argv[i], "-info") == 0)
1619                         silent = 0;
1620
1621                 else if(strcmp(argv[i], "-be") == 0)
1622                         be = TRUE;
1623
1624                 else if(strcmp(argv[i], "-le") == 0)
1625                         be = FALSE;
1626                 /* BRCM begin */        
1627                 else if(strcmp(argv[i], "-gzip") == 0)
1628                         compress_algorithm = GZIP;
1629                 
1630                 else if(strcmp(argv[i], "-lzma") == 0)
1631                         compress_algorithm = LZMA;
1632                 /* BRCM end */
1633                 
1634                 else if(strcmp(argv[i], "-e") == 0)
1635                         break;
1636
1637                 else if(strcmp(argv[i], "-noappend") == 0)
1638                         delete = TRUE;
1639
1640                 else if(strcmp(argv[i], "-keep-as-directory") == 0)
1641                         keep_as_directory = TRUE;
1642
1643                 else if(strcmp(argv[i], "-root-becomes") == 0) {
1644                         if(++i == argc) {
1645                                 ERROR("%s: -root-becomes: missing name\n", argv[0]);
1646                                 exit(1);
1647                         }       
1648                         root_name = argv[i];
1649                 } else if(strcmp(argv[i], "-version") == 0) {
1650                         VERSION();
1651                 } else {
1652                         ERROR("%s: invalid option\n\n", argv[0]);
1653 printOptions:
1654                         ERROR("SYNTAX:%s source1 source2 ...  dest [options] [-e list of exclude dirs/files]\n", argv[0]);
1655                         ERROR("\nOptions are\n");
1656                         ERROR("\t-info\t\t\t\tprint files written to filesystem\n");
1657                         ERROR("\t-sort sort file\t\t\tsort files according to priorities in sort file.  One file or dir\n");
1658                         ERROR("\t\t\t\t\twith priority per line.  Priority -32768 to 32767, default priority 0\n");
1659                         ERROR("\t-b block size\t\t\tsize of blocks in ");
1660                         ERROR("filesystem, default %d\n", SQUASHFS_FILE_SIZE);
1661                         ERROR("\t-noappend\t\t\tDo not append to existing filesystem on dest, write a new filesystem\n");
1662                         ERROR("\t\t\t\t\tThis is the default action if dest does not exist, or if no filesystem is on it\n");
1663                         ERROR("\t-keep-as-directory\t\tIf one source directory is specified, create a root directory\n");
1664                         ERROR("\t\t\t\t\tcontaining that directory, rather than the contents of the directory\n");
1665                         ERROR("\t-root-becomes name\t\tWhen appending source files/directories, make the original\n");
1666                         ERROR("\t\t\t\t\troot become a subdirectory in the new root called name, rather\n");
1667                         ERROR("\t\t\t\t\tthan adding the new source items to the original root\n");
1668                         ERROR("\t-noI -noInodeCompression\tdo not compress inode table\n");
1669                         ERROR("\t-noD -noDataCompression\t\tdo not compress data blocks\n");
1670                         ERROR("\t-noF -noFragmentCompression\tdo not compress fragment blocks\n");
1671                         ERROR("\t-no-duplicates\t\t\tdo not perform duplicate checking\n");
1672                         ERROR("\t-no-fragments\t\t\tdo not use fragments\n");
1673                         ERROR("\t-always-use-fragments\t\tuse fragment blocks for files larger than block size\n");
1674                         ERROR("\t-nopad\t\t\t\tdo not pad filesystem to a multiple of 4K\n");
1675                         ERROR("\t-check_data\t\t\tadd checkdata for greater filesystem checks\n");
1676                         ERROR("\t-le\t\t\t\tcreate a little endian filesystem\n");
1677                         ERROR("\t-be\t\t\t\tcreate a big endian filesystem\n");
1678                         /* BRCM begin */
1679                         ERROR("\t-gzip\t\t\t\tuse gzip compression\n");
1680                         ERROR("\t-lzma\t\t\t\tuse lzma compression(default)\n");                        
1681                         /* BRCM end */
1682                         ERROR("\t-ef exclude file\t\tfile is a list of exclude dirs/files - one per line\n");
1683                         ERROR("\t-all-root\t\t\toverride file uid/gid and make all file uid/gids owned by root\n");
1684                         ERROR("\t-root-owned\t\t\talternative name for -all-root\n");
1685                         ERROR("\t-force-uid uid\t\t\tset all file uids to uid\n");
1686                         ERROR("\t-force-gid gid\t\t\tset all file gids to gid\n");
1687                         ERROR("\t-version\t\t\tprint version, licence and copyright message\n");
1688                         exit(1);
1689                 }
1690         }
1691
1692         if(stat(argv[source + 1], &buf) == -1) {
1693                 if(errno == ENOENT) { /* Does not exist */
1694                         if((fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) {
1695                                 perror("Could not create destination file");
1696                                 exit(1);
1697                         }
1698                         delete = TRUE;
1699                 } else {
1700                         perror("Could not stat destination file");
1701                         exit(1);
1702                 }
1703
1704         } else {
1705                 if(S_ISBLK(buf.st_mode)) {
1706                         if((fd = open(argv[source + 1], O_RDWR)) == -1) {
1707                                 perror("Could not open block device as destination");
1708                                 exit(1);
1709                         }
1710                         block_device = 1;
1711
1712                 } else if(S_ISREG(buf.st_mode))  {
1713                         if((fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | O_RDWR)) == -1) {
1714                                 perror("Could not open regular file for writing as destination");
1715                                 exit(1);
1716                         }
1717                 }
1718                 else {
1719                         ERROR("Destination not block device or regular file\n");
1720                         exit(1);
1721                 }
1722
1723                 if(!delete) {
1724                         if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) {
1725                                 if(S_ISREG(buf.st_mode)) { /* reopen truncating file */
1726                                         close(fd);
1727                                         if((fd = open(argv[source + 1], O_TRUNC  | O_RDWR)) == -1) {
1728                                                 perror("Could not open regular file for writing as destination");
1729                                                 exit(1);
1730                                         }
1731                                 }
1732                                 delete = TRUE;
1733                         }
1734
1735                 }
1736         }
1737
1738         /* process the exclude files - must be done afer destination file has been possibly created */
1739         for(i = source + 2; i < argc; i++)
1740                 if(strcmp(argv[i], "-ef") == 0) {
1741                         FILE *fd;
1742                         char filename[16385];
1743                         if((fd = fopen(argv[++i], "r")) == NULL) {
1744                                 perror("Could not open exclude file...");
1745                                 exit(1);
1746                         }
1747                         while(fscanf(fd, "%16384[^\n]\n", filename) != EOF)
1748                                 add_exclude(filename);
1749                         fclose(fd);
1750                 } else if(strcmp(argv[i], "-e") == 0)
1751                         break;
1752                 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-sort") == 0)
1753                         i++;
1754
1755         if(i != argc) {
1756                 if(++i == argc) {
1757                         ERROR("%s: -e missing arguments\n", argv[0]);
1758                         exit(1);
1759                 }
1760                 while(i < argc && add_exclude(argv[i++]));
1761         }
1762
1763         /* process the sort files - must be done afer the exclude files  */
1764         for(i = source + 2; i < argc; i++)
1765                 if(strcmp(argv[i], "-sort") == 0) {
1766                         read_sort_file(argv[++i], source, source_path);
1767                         sorted ++;
1768                 } else if(strcmp(argv[i], "-e") == 0)
1769                         break;
1770                 else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0)
1771                         i++;
1772
1773         if((fragment_data = (char *) malloc(block_size)) == NULL)
1774                 BAD_ERROR("Out of memory allocating fragment_data");
1775
1776         if(delete) {
1777                 printf("Creating %s filesystem on %s, block size %d.\n",
1778                                 be ? "big endian" : "little endian", argv[source + 1], block_size);
1779                 bytes = sizeof(squashfs_super_block);
1780         } else {
1781                 be = orig_be;
1782                 block_log = slog(block_size = sBlk.block_size);
1783                 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
1784                 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
1785                 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
1786                 check_data = SQUASHFS_CHECK_DATA(sBlk.flags);
1787                 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
1788                 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
1789                 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
1790                 
1791                 fragments = SQUASHFS_INVALID_BLK;
1792                 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &inode_bytes, &data_cache,
1793                                 &cache_bytes, &cache_size, &directory_table, &directory_bytes,
1794                                 &directory_data_cache, &directory_cache_bytes, &directory_cache_size,
1795                                 &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count, (squashfs_uid *) uids, &uid_count,
1796                                 (squashfs_uid *) guids, &guid_count,
1797                                 &total_bytes, &total_inode_bytes, &total_directory_bytes, add_old_root_entry, &fragment_table)) == 0) {
1798                         ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n");
1799                         exit(1);
1800                 }
1801                 if((fragments = sBlk.fragments))
1802                         fragment_table = (squashfs_fragment_entry *) realloc((char *) fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(squashfs_fragment_entry)); 
1803
1804                 printf("Appending to existing %s squashfs filesystem on %s, block size %d\n", be ? "big endian" :
1805                         "little endian", argv[source + 1], block_size);
1806                 printf("All -be, -le, -b, -noI, noD, noF, -check_data, no-duplicates, no-fragments and always-use-fragments options ignored\n");
1807                 printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n");
1808
1809                 inode_size = inode_bytes;
1810                 directory_size = directory_bytes;
1811
1812                 /* save original filesystem state for restoring ... */
1813                 sfragments = fragments;
1814                 sbytes = bytes;
1815                 sinode_count = sBlk.inodes;
1816                 inode_count = file_count + dir_count + sym_count + dev_count;
1817                 sdata_cache = (char *)malloc(scache_bytes = cache_size);
1818                 sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes = directory_cache_size);
1819                 memcpy(sdata_cache, data_cache, scache_bytes);
1820                 memcpy(sdirectory_data_cache, directory_data_cache, sdirectory_cache_bytes);
1821                 sinode_bytes = inode_bytes;
1822                 sdirectory_bytes = directory_bytes;
1823                 suid_count = uid_count;
1824                 sguid_count = guid_count;
1825                 stotal_bytes = total_bytes;
1826                 stotal_inode_bytes = total_inode_bytes;
1827                 stotal_directory_bytes = total_directory_bytes;
1828                 sfile_count = file_count;
1829                 ssym_count = sym_count;
1830                 sdev_count = dev_count;
1831                 sdir_count = dir_count;
1832                 sdup_files = dup_files;
1833                 restore = TRUE;
1834                 if(setjmp(env))
1835                         goto restore_filesystem;
1836                 signal(SIGTERM, sighandler);
1837                 signal(SIGINT, sighandler);
1838                 write_bytes(fd, SQUASHFS_START, 4, "\0\0\0\0");
1839         }
1840
1841 #if __BYTE_ORDER == __BIG_ENDIAN
1842         swap = !be;
1843 #else
1844         swap = be;
1845 #endif
1846
1847         block_offset = check_data ? 3 : 2;
1848
1849         if(stat(source_path[0], &buf) == -1) {
1850                 perror("Cannot stat source directory");
1851                 EXIT_MKSQUASHFS();
1852         }
1853
1854         if(sorted)
1855                 sort_files_and_write(source, source_path);
1856
1857         if(delete && !keep_as_directory && source == 1 && S_ISDIR(buf.st_mode))
1858                 sBlk.root_inode = dir_scan(source_path[0], linux_opendir, linux_readdir, linux_closedir);
1859         else if(!keep_as_directory && source == 1 && S_ISDIR(buf.st_mode))
1860                 sBlk.root_inode = dir_scan(source_path[0], single_opendir, single_readdir, linux_closedir);
1861         else
1862                 sBlk.root_inode = dir_scan("", encomp_opendir, encomp_readdir, encomp_closedir);
1863         sBlk.inodes = inode_count;
1864         sBlk.s_magic = SQUASHFS_MAGIC;
1865         sBlk.s_major = SQUASHFS_MAJOR;
1866         sBlk.s_minor = SQUASHFS_MINOR;
1867         sBlk.block_size = block_size;
1868         sBlk.block_log = block_log;
1869         sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, check_data, noF, no_fragments, always_use_fragments, duplicate_checking);
1870         sBlk.mkfs_time = time(NULL);
1871
1872 restore_filesystem:
1873         write_fragment();
1874         sBlk.fragments = fragments;
1875         sBlk.inode_table_start = write_inodes();
1876         sBlk.directory_table_start = write_directories();
1877         sBlk.fragment_table_start = write_fragment_table();
1878
1879         TRACE("sBlk->inode_table_start 0x%x\n", sBlk.inode_table_start);
1880         TRACE("sBlk->directory_table_start 0x%x\n", sBlk.directory_table_start);
1881         TRACE("sBlk->fragment_table_start 0x%x\n", sBlk.fragment_table_start);
1882
1883         if(sBlk.no_uids = uid_count) {
1884                 if(!swap)
1885                         write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids);
1886                 else {
1887                         squashfs_uid uids_copy[uid_count];
1888
1889                         SQUASHFS_SWAP_DATA(uids, uids_copy, uid_count, sizeof(squashfs_uid) * 8);
1890                         write_bytes(fd, bytes, uid_count * sizeof(squashfs_uid), (char *) uids_copy);
1891                 }
1892                 sBlk.uid_start = bytes;
1893                 bytes += uid_count * sizeof(squashfs_uid);
1894         } else
1895                 sBlk.uid_start = 0;
1896
1897         if(sBlk.no_guids = guid_count) {
1898                 if(!swap)
1899                         write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids);
1900                 else {
1901                         squashfs_uid guids_copy[guid_count];
1902
1903                         SQUASHFS_SWAP_DATA(guids, guids_copy, guid_count, sizeof(squashfs_uid) * 8);
1904                         write_bytes(fd, bytes, guid_count * sizeof(squashfs_uid), (char *) guids_copy);
1905                 }
1906                 sBlk.guid_start = bytes;
1907                 bytes += guid_count * sizeof(squashfs_uid);
1908         } else
1909                 sBlk.guid_start = 0;
1910
1911         sBlk.bytes_used = bytes;
1912
1913         if(!swap)
1914                 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk);
1915         else {
1916                 squashfs_super_block sBlk_copy;
1917
1918                 SQUASHFS_SWAP_SUPER_BLOCK((&sBlk), &sBlk_copy); 
1919                 write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_copy);
1920         }
1921
1922         if(!nopad && (i = bytes & (4096 - 1))) {
1923                 unsigned char temp[4096] = {0};
1924                 write_bytes(fd, bytes, 4096 - i, temp);
1925         }
1926
1927         total_bytes += total_inode_bytes + total_directory_bytes + uid_count
1928                 * sizeof(unsigned short) + guid_count * sizeof(unsigned short) +
1929                 sizeof(squashfs_super_block);
1930
1931         printf("\n%s filesystem, data block size %d, %s data, %s metadata, %s fragments\n", be ?
1932                 "Big endian" : "Little endian", block_size, noI ? "uncompressed" : "compressed", noD ?
1933         "uncompressed" : "compressed", no_fragments ? "no" : noF ? "uncompressed" : "compressed");
1934         printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0));
1935         printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
1936                 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
1937         printf("Inode table size %d bytes (%.2f Kbytes)\n",
1938                 inode_bytes, inode_bytes / 1024.0);
1939         printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
1940                 ((float) inode_bytes / total_inode_bytes) * 100.0, total_inode_bytes);
1941         printf("Directory table size %d bytes (%.2f Kbytes)\n",
1942                 directory_bytes, directory_bytes / 1024.0);
1943         printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
1944                 ((float) directory_bytes / total_directory_bytes) * 100.0, total_directory_bytes);
1945         if(duplicate_checking)
1946                 printf("Number of duplicate files found %d\n", file_count - dup_files);
1947         else
1948                 printf("No duplicate files removed\n");
1949         printf("Number of inodes %d\n", inode_count);
1950         printf("Number of files %d\n", file_count);
1951         if(!no_fragments)
1952                 printf("Number of fragments %d\n", fragments);
1953         printf("Number of symbolic links  %d\n", sym_count);
1954         printf("Number of device nodes %d\n", dev_count);
1955         printf("Number of fifo nodes %d\n", fifo_count);
1956         printf("Number of socket nodes %d\n", sock_count);
1957         printf("Number of directories %d\n", dir_count);
1958         printf("Number of uids %d\n", uid_count);
1959
1960         for(i = 0; i < uid_count; i++) {
1961                 struct passwd *user = getpwuid(uids[i]);
1962                 printf("\t%s (%d)\n", user == NULL ? "unknown" : user->pw_name, uids[i]);
1963         }
1964
1965         printf("Number of gids %d\n", guid_count);
1966
1967         for(i = 0; i < guid_count; i++) {
1968                 struct group *group = getgrgid(guids[i]);
1969                 printf("\t%s (%d)\n", group == NULL ? "unknown" : group->gr_name, guids[i]);
1970         }
1971         close(fd);
1972         return 0;
1973 }