PageRenderTime 35ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/kernel-2.6/102-mksquashfs.patch

http://wl500g.googlecode.com/
Patch | 2086 lines | 2086 code | 0 blank | 0 comment | 0 complexity | 769d52ee7edea26ee2430209a2ce1890 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. diff -BurpN linux-2.6.22.orig/scripts/squashfs/Makefile linux-2.6.22/scripts/squashfs/Makefile
  2. --- linux-2.6.22.orig/scripts/squashfs/Makefile 1970-01-01 00:00:00.000000000 +0000
  3. +++ linux-2.6.22/scripts/squashfs/Makefile 2009-10-24 17:47:57.000000000 +0000
  4. @@ -0,0 +1,22 @@
  5. +INCLUDEDIR = $(SRCBASE)/linux/linux-2.6/include/linux
  6. +
  7. +CFLAGS := -I. -idirafter$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2
  8. +
  9. +all: mksquashfs unsquashfs
  10. +
  11. +mksquashfs: mksquashfs.o read_fs.o sort.o
  12. + $(CC) mksquashfs.o read_fs.o sort.o -lz -lpthread -lm -o $@
  13. +
  14. +mksquashfs.o: mksquashfs.c mksquashfs.h global.h sort.h
  15. +
  16. +read_fs.o: read_fs.c read_fs.h global.h
  17. +
  18. +sort.o: sort.c global.h sort.h
  19. +
  20. +unsquashfs: unsquashfs.o
  21. + $(CC) unsquashfs.o -lz -lpthread -lm -o $@
  22. +
  23. +unsquashfs.o: unsquashfs.c read_fs.h global.h
  24. +
  25. +clean:
  26. + -rm -f *.o mksquashfs unsquashfs
  27. diff -BurpN linux-2.6.22.orig/scripts/squashfs/global.h linux-2.6.22/scripts/squashfs/global.h
  28. --- linux-2.6.22.orig/scripts/squashfs/global.h 1970-01-01 00:00:00.000000000 +0000
  29. +++ linux-2.6.22/scripts/squashfs/global.h 2008-08-20 04:45:40.000000000 +0000
  30. @@ -0,0 +1,74 @@
  31. +#ifndef GLOBAL_H
  32. +#define GLOBAL_H
  33. +
  34. +/*
  35. + * Squashfs
  36. + *
  37. + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
  38. + * Phillip Lougher <phillip@lougher.demon.co.uk>
  39. + *
  40. + * This program is free software; you can redistribute it and/or
  41. + * modify it under the terms of the GNU General Public License
  42. + * as published by the Free Software Foundation; either version 2,
  43. + * or (at your option) any later version.
  44. + *
  45. + * This program is distributed in the hope that it will be useful,
  46. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  47. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  48. + * GNU General Public License for more details.
  49. + *
  50. + * You should have received a copy of the GNU General Public License
  51. + * along with this program; if not, write to the Free Software
  52. + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  53. + *
  54. + * global.h
  55. + */
  56. +
  57. +typedef struct squashfs_super_block squashfs_super_block;
  58. +typedef struct squashfs_dir_index squashfs_dir_index;
  59. +typedef struct squashfs_base_inode_header squashfs_base_inode_header;
  60. +typedef struct squashfs_ipc_inode_header squashfs_ipc_inode_header;
  61. +typedef struct squashfs_dev_inode_header squashfs_dev_inode_header;
  62. +typedef struct squashfs_symlink_inode_header squashfs_symlink_inode_header;
  63. +typedef struct squashfs_reg_inode_header squashfs_reg_inode_header;
  64. +typedef struct squashfs_lreg_inode_header squashfs_lreg_inode_header;
  65. +typedef struct squashfs_dir_inode_header squashfs_dir_inode_header;
  66. +typedef struct squashfs_ldir_inode_header squashfs_ldir_inode_header;
  67. +typedef struct squashfs_dir_entry squashfs_dir_entry;
  68. +typedef struct squashfs_dir_header squashfs_dir_header;
  69. +typedef struct squashfs_fragment_entry squashfs_fragment_entry;
  70. +typedef union squashfs_inode_header squashfs_inode_header;
  71. +
  72. +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
  73. +typedef struct squashfs_dir_index_1 squashfs_dir_index_1;
  74. +typedef struct squashfs_base_inode_header_1 squashfs_base_inode_header_1;
  75. +typedef struct squashfs_ipc_inode_header_1 squashfs_ipc_inode_header_1;
  76. +typedef struct squashfs_dev_inode_header_1 squashfs_dev_inode_header_1;
  77. +typedef struct squashfs_symlink_inode_header_1 squashfs_symlink_inode_header_1;
  78. +typedef struct squashfs_reg_inode_header_1 squashfs_reg_inode_header_1;
  79. +typedef struct squashfs_dir_inode_header_1 squashfs_dir_inode_header_1;
  80. +typedef union squashfs_inode_header_1 squashfs_inode_header_1;
  81. +#endif
  82. +
  83. +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
  84. +typedef struct squashfs_dir_index_2 squashfs_dir_index_2;
  85. +typedef struct squashfs_base_inode_header_2 squashfs_base_inode_header_2;
  86. +typedef struct squashfs_ipc_inode_header_2 squashfs_ipc_inode_header_2;
  87. +typedef struct squashfs_dev_inode_header_2 squashfs_dev_inode_header_2;
  88. +typedef struct squashfs_symlink_inode_header_2 squashfs_symlink_inode_header_2;
  89. +typedef struct squashfs_reg_inode_header_2 squashfs_reg_inode_header_2;
  90. +typedef struct squashfs_lreg_inode_header_2 squashfs_lreg_inode_header_2;
  91. +typedef struct squashfs_dir_inode_header_2 squashfs_dir_inode_header_2;
  92. +typedef struct squashfs_ldir_inode_header_2 squashfs_ldir_inode_header_2;
  93. +typedef struct squashfs_dir_entry_2 squashfs_dir_entry_2;
  94. +typedef struct squashfs_dir_header_2 squashfs_dir_header_2;
  95. +typedef struct squashfs_fragment_entry_2 squashfs_fragment_entry_2;
  96. +typedef union squashfs_inode_header_2 squashfs_inode_header_2;
  97. +#endif
  98. +
  99. +typedef unsigned int squashfs_uid;
  100. +typedef long long squashfs_fragment_index;
  101. +typedef squashfs_inode_t squashfs_inode;
  102. +typedef squashfs_block_t squashfs_block;
  103. +
  104. +#endif
  105. diff -BurpN linux-2.6.22.orig/scripts/squashfs/mksquashfs.c linux-2.6.22/scripts/squashfs/mksquashfs.c
  106. --- linux-2.6.22.orig/scripts/squashfs/mksquashfs.c 1970-01-01 00:00:00.000000000 +0000
  107. +++ linux-2.6.22/scripts/squashfs/mksquashfs.c 2008-08-26 07:01:39.000000000 +0000
  108. @@ -0,0 +1,4223 @@
  109. +/*
  110. + * Create a squashfs filesystem. This is a highly compressed read only filesystem.
  111. + *
  112. + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
  113. + * Phillip Lougher <phillip@lougher.demon.co.uk>
  114. + *
  115. + * This program is free software; you can redistribute it and/or
  116. + * modify it under the terms of the GNU General Public License
  117. + * as published by the Free Software Foundation; either version 2,
  118. + * or (at your option) any later version.
  119. + *
  120. + * This program is distributed in the hope that it will be useful,
  121. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  122. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  123. + * GNU General Public License for more details.
  124. + *
  125. + * You should have received a copy of the GNU General Public License
  126. + * along with this program; if not, write to the Free Software
  127. + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  128. + *
  129. + * mksquashfs.c
  130. + */
  131. +
  132. +#define FALSE 0
  133. +#define TRUE 1
  134. +
  135. +#include <pwd.h>
  136. +#include <grp.h>
  137. +#include <time.h>
  138. +#include <unistd.h>
  139. +#include <stdio.h>
  140. +#include <sys/time.h>
  141. +#include <sys/types.h>
  142. +#include <sys/stat.h>
  143. +#include <fcntl.h>
  144. +#include <errno.h>
  145. +#include <dirent.h>
  146. +#include <string.h>
  147. +#include <zlib.h>
  148. +#include <stdlib.h>
  149. +#include <signal.h>
  150. +#include <setjmp.h>
  151. +#include <sys/ioctl.h>
  152. +#include <sys/types.h>
  153. +#include <sys/mman.h>
  154. +#include <pthread.h>
  155. +#include <math.h>
  156. +#include <regex.h>
  157. +#include <fnmatch.h>
  158. +
  159. +#ifndef linux
  160. +#define __BYTE_ORDER BYTE_ORDER
  161. +#define __BIG_ENDIAN BIG_ENDIAN
  162. +#define __LITTLE_ENDIAN LITTLE_ENDIAN
  163. +#include <sys/sysctl.h>
  164. +#else
  165. +#include <endian.h>
  166. +#include <sys/sysinfo.h>
  167. +#endif
  168. +
  169. +#include <squashfs_fs.h>
  170. +#include "mksquashfs.h"
  171. +#include "global.h"
  172. +#include "sort.h"
  173. +
  174. +#ifdef SQUASHFS_TRACE
  175. +#define TRACE(s, args...) do { \
  176. + if(progress_enabled) \
  177. + printf("\n"); \
  178. + printf("mksquashfs: "s, ## args); \
  179. + } while(0)
  180. +#else
  181. +#define TRACE(s, args...)
  182. +#endif
  183. +
  184. +#define INFO(s, args...) do {\
  185. + if(!silent)\
  186. + printf("mksquashfs: "s, ## args);\
  187. + } while(0)
  188. +#define ERROR(s, args...) do {\
  189. + pthread_mutex_lock(&progress_mutex); \
  190. + if(progress_enabled) \
  191. + fprintf(stderr, "\n"); \
  192. + fprintf(stderr, s, ## args);\
  193. + pthread_mutex_unlock(&progress_mutex); \
  194. + } while(0)
  195. +#define EXIT_MKSQUASHFS() do {\
  196. + if(restore)\
  197. + restorefs();\
  198. + if(delete && destination_file && !block_device)\
  199. + unlink(destination_file);\
  200. + exit(1);\
  201. + } while(0)
  202. +#define BAD_ERROR(s, args...) do {\
  203. + pthread_mutex_lock(&progress_mutex); \
  204. + if(progress_enabled) \
  205. + fprintf(stderr, "\n"); \
  206. + fprintf(stderr, "FATAL ERROR:" s, ##args);\
  207. + pthread_mutex_unlock(&progress_mutex); \
  208. + EXIT_MKSQUASHFS();\
  209. + } while(0)
  210. +
  211. +int delete = FALSE;
  212. +int fd;
  213. +int cur_uncompressed = 0, estimated_uncompressed = 0;
  214. +int columns;
  215. +
  216. +/* filesystem flags for building */
  217. +int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
  218. +int noI = 0, noD = 0, check_data = 0;
  219. +int swap, silent = TRUE;
  220. +long long global_uid = -1, global_gid = -1;
  221. +int exportable = TRUE;
  222. +int progress = TRUE;
  223. +int progress_enabled = FALSE;
  224. +int sparse_files = TRUE;
  225. +int old_exclude = TRUE;
  226. +int use_regex = FALSE;
  227. +
  228. +/* superblock attributes */
  229. +int block_size = SQUASHFS_FILE_SIZE, block_log;
  230. +unsigned short uid_count = 0, guid_count = 0;
  231. +squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
  232. +int block_offset;
  233. +int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
  234. +
  235. +/* write position within data section */
  236. +long long bytes = 0, total_bytes = 0;
  237. +
  238. +/* in memory directory table - possibly compressed */
  239. +char *directory_table = NULL;
  240. +unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
  241. +
  242. +/* cached directory table */
  243. +char *directory_data_cache = NULL;
  244. +unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
  245. +
  246. +/* in memory inode table - possibly compressed */
  247. +char *inode_table = NULL;
  248. +unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
  249. +
  250. +/* cached inode table */
  251. +char *data_cache = NULL;
  252. +unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
  253. +
  254. +/* inode lookup table */
  255. +squashfs_inode *inode_lookup_table = NULL;
  256. +
  257. +/* in memory directory data */
  258. +#define I_COUNT_SIZE 128
  259. +#define DIR_ENTRIES 32
  260. +#define INODE_HASH_SIZE 65536
  261. +#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
  262. +#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
  263. +
  264. +struct cached_dir_index {
  265. + squashfs_dir_index index;
  266. + char *name;
  267. +};
  268. +
  269. +struct directory {
  270. + unsigned int start_block;
  271. + unsigned int size;
  272. + unsigned char *buff;
  273. + unsigned char *p;
  274. + unsigned int entry_count;
  275. + unsigned char *entry_count_p;
  276. + unsigned int i_count;
  277. + unsigned int i_size;
  278. + struct cached_dir_index *index;
  279. + unsigned char *index_count_p;
  280. + unsigned int inode_number;
  281. +};
  282. +
  283. +struct inode_info *inode_info[INODE_HASH_SIZE];
  284. +
  285. +/* hash tables used to do fast duplicate searches in duplicate check */
  286. +struct file_info *dupl[65536];
  287. +int dup_files = 0;
  288. +
  289. +/* exclude file handling */
  290. +/* list of exclude dirs/files */
  291. +struct exclude_info {
  292. + dev_t st_dev;
  293. + ino_t st_ino;
  294. +};
  295. +
  296. +#define EXCLUDE_SIZE 8192
  297. +int exclude = 0;
  298. +struct exclude_info *exclude_paths = NULL;
  299. +int old_excluded(char *filename, struct stat *buf);
  300. +
  301. +struct path_entry {
  302. + char *name;
  303. + regex_t *preg;
  304. + struct pathname *paths;
  305. +};
  306. +
  307. +struct pathname {
  308. + int names;
  309. + struct path_entry *name;
  310. +};
  311. +
  312. +struct pathnames {
  313. + int count;
  314. + struct pathname *path[0];
  315. +};
  316. +#define PATHS_ALLOC_SIZE 10
  317. +
  318. +struct pathnames *paths = NULL;
  319. +struct pathname *path = NULL;
  320. +struct pathname *stickypath = NULL;
  321. +int excluded(struct pathnames *paths, char *name, struct pathnames **new);
  322. +
  323. +/* fragment block data structures */
  324. +int fragments = 0;
  325. +struct file_buffer *fragment_data = NULL;
  326. +int fragment_size = 0;
  327. +
  328. +struct fragment {
  329. + unsigned int index;
  330. + int offset;
  331. + int size;
  332. +};
  333. +
  334. +#define FRAG_SIZE 32768
  335. +#define FRAG_INDEX (1LL << 32)
  336. +
  337. +squashfs_fragment_entry *fragment_table = NULL;
  338. +int fragments_outstanding = 0;
  339. +
  340. +/* current inode number for directories and non directories */
  341. +unsigned int dir_inode_no = 1;
  342. +unsigned int inode_no = 0;
  343. +unsigned int root_inode_number = 0;
  344. +
  345. +/* list of source dirs/files */
  346. +int source = 0;
  347. +char **source_path;
  348. +
  349. +/* list of root directory entries read from original filesystem */
  350. +int old_root_entries = 0;
  351. +struct old_root_entry_info {
  352. + char name[SQUASHFS_NAME_LEN + 1];
  353. + squashfs_inode inode;
  354. + int type;
  355. + int inode_number;
  356. +};
  357. +struct old_root_entry_info *old_root_entry;
  358. +
  359. +/* in memory file info */
  360. +struct file_info {
  361. + long long file_size;
  362. + long long bytes;
  363. + unsigned short checksum;
  364. + unsigned short fragment_checksum;
  365. + long long start;
  366. + unsigned int *block_list;
  367. + struct file_info *next;
  368. + struct fragment *fragment;
  369. + char checksum_flag;
  370. +};
  371. +
  372. +/* count of how many times SIGINT or SIGQUIT has been sent */
  373. +int interrupted = 0;
  374. +
  375. +/* restore orignal filesystem state if appending to existing filesystem is cancelled */
  376. +jmp_buf env;
  377. +char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
  378. +
  379. +long long sbytes, stotal_bytes;
  380. +
  381. +unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
  382. + sdirectory_cache_bytes, sdirectory_compressed_bytes, suid_count, sguid_count,
  383. + stotal_inode_bytes, stotal_directory_bytes,
  384. + sinode_count = 0, sfile_count, ssym_count, sdev_count,
  385. + sdir_count, sfifo_count, ssock_count, sdup_files;
  386. +int sfragments;
  387. +int restore = 0;
  388. +int threads;
  389. +
  390. +/* flag whether destination file is a block device */
  391. +int block_device = 0;
  392. +
  393. +/* flag indicating whether files are sorted using sort list(s) */
  394. +int sorted = 0;
  395. +
  396. +/* save destination file name for deleting on error */
  397. +char *destination_file = NULL;
  398. +
  399. +/* recovery file for abnormal exit on appending */
  400. +char recovery_file[1024] = "";
  401. +int recover = TRUE;
  402. +
  403. +/* struct describing a cache entry passed between threads */
  404. +struct file_buffer {
  405. + struct cache *cache;
  406. + int keep;
  407. + long long file_size;
  408. + long long index;
  409. + long long block;
  410. + long long sequence;
  411. + int size;
  412. + int c_byte;
  413. + int used;
  414. + int fragment;
  415. + int error;
  416. + struct file_buffer *hash_next;
  417. + struct file_buffer *hash_prev;
  418. + struct file_buffer *free_next;
  419. + struct file_buffer *free_prev;
  420. + struct file_buffer *next;
  421. + char data[0];
  422. +};
  423. +
  424. +
  425. +/* struct describing queues used to pass data between threads */
  426. +struct queue {
  427. + int size;
  428. + int readp;
  429. + int writep;
  430. + pthread_mutex_t mutex;
  431. + pthread_cond_t empty;
  432. + pthread_cond_t full;
  433. + void **data;
  434. +};
  435. +
  436. +/* describes the list of blocks in a file which is a possible
  437. + duplicate. For each block, it indicates whether the block is
  438. + in memory or on disk */
  439. +struct buffer_list {
  440. + long long start;
  441. + int size;
  442. + struct file_buffer *read_buffer;
  443. +};
  444. +
  445. +struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
  446. +struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate, *to_frag;
  447. +pthread_t *thread, *deflator_thread, *frag_deflator_thread, progress_thread;
  448. +pthread_mutex_t fragment_mutex;
  449. +pthread_cond_t fragment_waiting;
  450. +pthread_mutex_t pos_mutex;
  451. +pthread_mutex_t progress_mutex;
  452. +pthread_cond_t progress_wait;
  453. +int rotate = 0;
  454. +
  455. +/* user options that control parallelisation */
  456. +int processors = -1;
  457. +/* default size of output buffer in Mbytes */
  458. +#define WRITER_BUFFER_DEFAULT 512
  459. +/* default size of input buffer in Mbytes */
  460. +#define READER_BUFFER_DEFAULT 64
  461. +/* default size of fragment buffer in Mbytes */
  462. +#define FRAGMENT_BUFFER_DEFAULT 64
  463. +int writer_buffer_size;
  464. +int reader_buffer_size;
  465. +int fragment_buffer_size;
  466. +
  467. +void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type);
  468. +extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
  469. +extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
  470. + char **data_cache, char **cdirectory_table, char **directory_data_cache,
  471. + unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
  472. + unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
  473. + int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
  474. + unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
  475. + long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
  476. + unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
  477. + void (push_directory_entry)(char *, squashfs_inode, int, int),
  478. + squashfs_fragment_entry **fragment_table, squashfs_inode **inode_lookup_table);
  479. +extern int read_sort_file(char *filename, int source, char *source_path[]);
  480. +extern void sort_files_and_write(struct dir_info *dir);
  481. +struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, struct buffer_list *buffer_list, int blocks, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
  482. +struct dir_info *dir_scan1(char *, struct pathnames *, int (_readdir)(char *, char *, struct dir_info *));
  483. +void dir_scan2(squashfs_inode *inode, struct dir_info *dir_info);
  484. +struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
  485. +extern void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf);
  486. +extern struct priority_entry *priority_list[65536];
  487. +void progress_bar(long long current, long long max, int columns);
  488. +
  489. +
  490. +struct queue *queue_init(int size)
  491. +{
  492. + struct queue *queue = malloc(sizeof(struct queue));
  493. +
  494. + if(queue == NULL)
  495. + return NULL;
  496. +
  497. + if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
  498. + free(queue);
  499. + return NULL;
  500. + }
  501. +
  502. + queue->size = size + 1;
  503. + queue->readp = queue->writep = 0;
  504. + pthread_mutex_init(&queue->mutex, NULL);
  505. + pthread_cond_init(&queue->empty, NULL);
  506. + pthread_cond_init(&queue->full, NULL);
  507. +
  508. + return queue;
  509. +}
  510. +
  511. +
  512. +void queue_put(struct queue *queue, void *data)
  513. +{
  514. + int nextp;
  515. +
  516. + pthread_mutex_lock(&queue->mutex);
  517. +
  518. + while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
  519. + pthread_cond_wait(&queue->full, &queue->mutex);
  520. +
  521. + queue->data[queue->writep] = data;
  522. + queue->writep = nextp;
  523. + pthread_cond_signal(&queue->empty);
  524. + pthread_mutex_unlock(&queue->mutex);
  525. +}
  526. +
  527. +
  528. +void *queue_get(struct queue *queue)
  529. +{
  530. + void *data;
  531. + pthread_mutex_lock(&queue->mutex);
  532. +
  533. + while(queue->readp == queue->writep)
  534. + pthread_cond_wait(&queue->empty, &queue->mutex);
  535. +
  536. + data = queue->data[queue->readp];
  537. + queue->readp = (queue->readp + 1) % queue->size;
  538. + pthread_cond_signal(&queue->full);
  539. + pthread_mutex_unlock(&queue->mutex);
  540. +
  541. + return data;
  542. +}
  543. +
  544. +
  545. +/* Cache status struct. Caches are used to keep
  546. + track of memory buffers passed between different threads */
  547. +struct cache {
  548. + int max_buffers;
  549. + int count;
  550. + int buffer_size;
  551. + pthread_mutex_t mutex;
  552. + pthread_cond_t wait_for_free;
  553. + struct file_buffer *free_list;
  554. + struct file_buffer *hash_table[65536];
  555. +};
  556. +
  557. +
  558. +#define INSERT_LIST(NAME, TYPE) \
  559. +void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
  560. + if(*list) { \
  561. + entry->NAME##_next = *list; \
  562. + entry->NAME##_prev = (*list)->NAME##_prev; \
  563. + (*list)->NAME##_prev->NAME##_next = entry; \
  564. + (*list)->NAME##_prev = entry; \
  565. + } else { \
  566. + *list = entry; \
  567. + entry->NAME##_prev = entry->NAME##_next = entry; \
  568. + } \
  569. +}
  570. +
  571. +
  572. +#define REMOVE_LIST(NAME, TYPE) \
  573. +void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
  574. + if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
  575. + /* only this entry in the list */ \
  576. + *list = NULL; \
  577. + } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
  578. + /* more than one entry in the list */ \
  579. + entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
  580. + entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
  581. + if(*list == entry) \
  582. + *list = entry->NAME##_next; \
  583. + } \
  584. + entry->NAME##_prev = entry->NAME##_next = NULL; \
  585. +}
  586. +
  587. +
  588. +#define CALCULATE_HASH(start) (start & 0xffff) \
  589. +
  590. +
  591. +/* Called with the cache mutex held */
  592. +void insert_hash_table(struct cache *cache, struct file_buffer *entry)
  593. +{
  594. + int hash = CALCULATE_HASH(entry->index);
  595. +
  596. + entry->hash_next = cache->hash_table[hash];
  597. + cache->hash_table[hash] = entry;
  598. + entry->hash_prev = NULL;
  599. + if(entry->hash_next)
  600. + entry->hash_next->hash_prev = entry;
  601. +}
  602. +
  603. +
  604. +/* Called with the cache mutex held */
  605. +void remove_hash_table(struct cache *cache, struct file_buffer *entry)
  606. +{
  607. + if(entry->hash_prev)
  608. + entry->hash_prev->hash_next = entry->hash_next;
  609. + else
  610. + cache->hash_table[CALCULATE_HASH(entry->index)] = entry->hash_next;
  611. + if(entry->hash_next)
  612. + entry->hash_next->hash_prev = entry->hash_prev;
  613. +
  614. + entry->hash_prev = entry->hash_next = NULL;
  615. +}
  616. +
  617. +
  618. +/* Called with the cache mutex held */
  619. +INSERT_LIST(free, struct file_buffer)
  620. +
  621. +/* Called with the cache mutex held */
  622. +REMOVE_LIST(free, struct file_buffer)
  623. +
  624. +
  625. +struct cache *cache_init(int buffer_size, int max_buffers)
  626. +{
  627. + struct cache *cache = malloc(sizeof(struct cache));
  628. +
  629. + if(cache == NULL)
  630. + return NULL;
  631. +
  632. + cache->max_buffers = max_buffers;
  633. + cache->buffer_size = buffer_size;
  634. + cache->count = 0;
  635. + cache->free_list = NULL;
  636. + memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
  637. + pthread_mutex_init(&cache->mutex, NULL);
  638. + pthread_cond_init(&cache->wait_for_free, NULL);
  639. +
  640. + return cache;
  641. +}
  642. +
  643. +
  644. +struct file_buffer *cache_lookup(struct cache *cache, long long index)
  645. +{
  646. + /* Lookup block in the cache, if found return with usage count
  647. + * incremented, if not found return NULL */
  648. + int hash = CALCULATE_HASH(index);
  649. + struct file_buffer *entry;
  650. +
  651. + pthread_mutex_lock(&cache->mutex);
  652. +
  653. + for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
  654. + if(entry->index == index)
  655. + break;
  656. +
  657. + if(entry) {
  658. + /* found the block in the cache, increment used count and
  659. + * if necessary remove from free list so it won't disappear
  660. + */
  661. + entry->used ++;
  662. + remove_free_list(&cache->free_list, entry);
  663. + }
  664. +
  665. + pthread_mutex_unlock(&cache->mutex);
  666. +
  667. + return entry;
  668. +}
  669. +
  670. +
  671. +#define GET_FREELIST 1
  672. +
  673. +struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
  674. +{
  675. + /* Get a free block out of the cache indexed on index. */
  676. + struct file_buffer *entry;
  677. +
  678. + pthread_mutex_lock(&cache->mutex);
  679. +
  680. + while(1) {
  681. + /* first try to get a block from the free list */
  682. +#ifdef GET_FREELIST
  683. + if(cache->free_list) {
  684. + /* a block on the free_list is a "keep" block */
  685. + entry = cache->free_list;
  686. + remove_free_list(&cache->free_list, entry);
  687. + remove_hash_table(cache, entry);
  688. + break;
  689. + } else
  690. +#endif
  691. + if(cache->count < cache->max_buffers) {
  692. + /* next try to allocate new block */
  693. + entry = malloc(sizeof(struct file_buffer) + cache->buffer_size);
  694. + if(entry == NULL)
  695. + goto failed;
  696. + entry->cache = cache;
  697. + entry->free_prev = entry->free_next = NULL;
  698. + cache->count ++;
  699. + break;
  700. + } else
  701. +#ifndef GET_FREELIST
  702. + if(cache->free_list) {
  703. + /* a block on the free_list is a "keep" block */
  704. + entry = cache->free_list;
  705. + remove_free_list(&cache->free_list, entry);
  706. + remove_hash_table(cache, entry);
  707. + break;
  708. + }
  709. +#endif
  710. + /* wait for a block */
  711. + pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
  712. + }
  713. +
  714. + /* initialise block and if a keep block insert into the hash table */
  715. + entry->used = 1;
  716. + entry->error = FALSE;
  717. + entry->keep = keep;
  718. + if(keep) {
  719. + entry->index = index;
  720. + insert_hash_table(cache, entry);
  721. + }
  722. + pthread_mutex_unlock(&cache->mutex);
  723. +
  724. + return entry;
  725. +
  726. +failed:
  727. + pthread_mutex_unlock(&cache->mutex);
  728. + return NULL;
  729. +}
  730. +
  731. +
  732. +void cache_rehash(struct file_buffer *entry, long long index)
  733. +{
  734. + struct cache *cache = entry->cache;
  735. +
  736. + pthread_mutex_lock(&cache->mutex);
  737. + if(entry->keep)
  738. + remove_hash_table(cache, entry);
  739. + entry->keep = TRUE;
  740. + entry->index = index;
  741. + insert_hash_table(cache, entry);
  742. + pthread_mutex_unlock(&cache->mutex);
  743. +}
  744. +
  745. +
  746. +void cache_block_put(struct file_buffer *entry)
  747. +{
  748. + struct cache *cache;
  749. +
  750. + /* finished with this cache entry, once the usage count reaches zero it
  751. + * can be reused and if a keep block put onto the free list. As keep
  752. + * blocks remain accessible via the hash table they can be found getting a
  753. + * new lease of life before they are reused. */
  754. +
  755. + if(entry == NULL)
  756. + return;
  757. +
  758. + cache = entry->cache;
  759. +
  760. + pthread_mutex_lock(&cache->mutex);
  761. +
  762. + entry->used --;
  763. + if(entry->used == 0) {
  764. + if(entry->keep)
  765. + insert_free_list(&cache->free_list, entry);
  766. + else {
  767. + free(entry);
  768. + cache->count --;
  769. + }
  770. +
  771. + /* One or more threads may be waiting on this block */
  772. + pthread_cond_signal(&cache->wait_for_free);
  773. + }
  774. +
  775. + pthread_mutex_unlock(&cache->mutex);
  776. +}
  777. +
  778. +
  779. +#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
  780. +
  781. +
  782. +inline void inc_progress_bar()
  783. +{
  784. + cur_uncompressed ++;
  785. +}
  786. +
  787. +
  788. +inline void update_progress_bar()
  789. +{
  790. + pthread_mutex_lock(&progress_mutex);
  791. + pthread_cond_signal(&progress_wait);
  792. + pthread_mutex_unlock(&progress_mutex);
  793. +}
  794. +
  795. +
  796. +inline void waitforthread(int i)
  797. +{
  798. + TRACE("Waiting for thread %d\n", i);
  799. + while(thread[i] != 0)
  800. + sched_yield();
  801. +}
  802. +
  803. +
  804. +void restorefs()
  805. +{
  806. + int i;
  807. +
  808. + if(thread == NULL || thread[0] == 0)
  809. + return;
  810. +
  811. + ERROR("Exiting - restoring original filesystem!\n\n");
  812. +
  813. + for(i = 0; i < 2 + processors * 2; i++)
  814. + if(thread[i])
  815. + pthread_kill(thread[i], SIGUSR1);
  816. + for(i = 0; i < 2 + processors * 2; i++)
  817. + waitforthread(i);
  818. + TRACE("All threads in signal handler\n");
  819. + bytes = sbytes;
  820. + memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
  821. + memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
  822. + inode_bytes = sinode_bytes;
  823. + directory_bytes = sdirectory_bytes;
  824. + memcpy(directory_table + directory_bytes, sdirectory_compressed, sdirectory_compressed_bytes);
  825. + directory_bytes += sdirectory_compressed_bytes;
  826. + uid_count = suid_count;
  827. + guid_count = sguid_count;
  828. + total_bytes = stotal_bytes;
  829. + total_inode_bytes = stotal_inode_bytes;
  830. + total_directory_bytes = stotal_directory_bytes;
  831. + inode_count = sinode_count;
  832. + file_count = sfile_count;
  833. + sym_count = ssym_count;
  834. + dev_count = sdev_count;
  835. + dir_count = sdir_count;
  836. + fifo_count = sfifo_count;
  837. + sock_count = ssock_count;
  838. + dup_files = sdup_files;
  839. + fragments = sfragments;
  840. + fragment_size = 0;
  841. + longjmp(env, 1);
  842. +}
  843. +
  844. +
  845. +void sighandler()
  846. +{
  847. + if(++interrupted > 2)
  848. + return;
  849. + if(interrupted == 2)
  850. + restorefs();
  851. + else {
  852. + ERROR("Interrupting will restore original filesystem!\n");
  853. + ERROR("Interrupt again to quit\n");
  854. + }
  855. +}
  856. +
  857. +
  858. +void sighandler2()
  859. +{
  860. + EXIT_MKSQUASHFS();
  861. +}
  862. +
  863. +
  864. +void sigusr1_handler()
  865. +{
  866. + int i;
  867. + sigset_t sigmask;
  868. + pthread_t thread_id = pthread_self();
  869. +
  870. + for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
  871. + thread[i] = (pthread_t) 0;
  872. +
  873. + TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
  874. +
  875. + sigemptyset(&sigmask);
  876. + sigaddset(&sigmask, SIGINT);
  877. + sigaddset(&sigmask, SIGQUIT);
  878. + sigaddset(&sigmask, SIGUSR1);
  879. + while(1) {
  880. + sigsuspend(&sigmask);
  881. + TRACE("After wait in sigusr1_handler :(\n");
  882. + }
  883. +}
  884. +
  885. +
  886. +void sigwinch_handler()
  887. +{
  888. + struct winsize winsize;
  889. +
  890. + if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
  891. + printf("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n");
  892. + columns = 80;
  893. + } else
  894. + columns = winsize.ws_col;
  895. +}
  896. +
  897. +
  898. +void sigalrm_handler()
  899. +{
  900. + rotate = (rotate + 1) % 4;
  901. +}
  902. +
  903. +
  904. +unsigned int mangle2(z_stream **strm, char *d, char *s, int size, int block_size, int uncompressed, int data_block)
  905. +{
  906. + unsigned long c_byte;
  907. + unsigned int res;
  908. + z_stream *stream = *strm;
  909. +
  910. + if(uncompressed)
  911. + goto notcompressed;
  912. +
  913. + if(stream == NULL) {
  914. + if((stream = *strm = malloc(sizeof(z_stream))) == NULL)
  915. + BAD_ERROR("mangle::compress failed, not enough memory\n");
  916. +
  917. + stream->zalloc = Z_NULL;
  918. + stream->zfree = Z_NULL;
  919. + stream->opaque = 0;
  920. +
  921. + if((res = deflateInit(stream, 9)) != Z_OK) {
  922. + if(res == Z_MEM_ERROR)
  923. + BAD_ERROR("zlib::compress failed, not enough memory\n");
  924. + else if(res == Z_STREAM_ERROR)
  925. + BAD_ERROR("zlib::compress failed, not a valid compression level\n");
  926. + else if(res == Z_VERSION_ERROR)
  927. + BAD_ERROR("zlib::compress failed, incorrect zlib version\n");
  928. + else
  929. + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
  930. + }
  931. + } else if((res = deflateReset(stream)) != Z_OK) {
  932. + if(res == Z_STREAM_ERROR)
  933. + BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
  934. + else
  935. + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
  936. + }
  937. +
  938. + stream->next_in = (unsigned char *) s;
  939. + stream->avail_in = size;
  940. + stream->next_out = (unsigned char *) d;
  941. + stream->avail_out = block_size;
  942. +
  943. + res = deflate(stream, Z_FINISH);
  944. + if(res != Z_STREAM_END && res != Z_OK) {
  945. + if(res == Z_STREAM_ERROR)
  946. + BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
  947. + else if(res == Z_BUF_ERROR)
  948. + BAD_ERROR("zlib::compress failed, no progress possible\n");
  949. + else
  950. + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
  951. + }
  952. +
  953. + c_byte = stream->total_out;
  954. +
  955. + if(res != Z_STREAM_END || c_byte >= size) {
  956. +notcompressed:
  957. + memcpy(d, s, size);
  958. + return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
  959. + }
  960. +
  961. + return (unsigned int) c_byte;
  962. +}
  963. +
  964. +
  965. +unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
  966. +{
  967. + static z_stream *stream = NULL;
  968. +
  969. + return mangle2(&stream, d, s, size, block_size, uncompressed, data_block);
  970. +}
  971. +
  972. +
  973. +squashfs_base_inode_header *get_inode(int req_size)
  974. +{
  975. + int data_space;
  976. + unsigned short c_byte;
  977. +
  978. + while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
  979. + if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
  980. + if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
  981. + == NULL) {
  982. + goto failed;
  983. + }
  984. + inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
  985. + }
  986. +
  987. + c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
  988. + SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
  989. + TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
  990. + if(!swap)
  991. + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
  992. + else
  993. + SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
  994. + if(check_data)
  995. + *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
  996. + inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
  997. + total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
  998. + memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
  999. + cache_bytes -= SQUASHFS_METADATA_SIZE;
  1000. + }
  1001. +
  1002. + data_space = (cache_size - cache_bytes);
  1003. + if(data_space < req_size) {
  1004. + int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
  1005. +
  1006. + if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
  1007. + goto failed;
  1008. + }
  1009. + cache_size += realloc_size;
  1010. + }
  1011. +
  1012. + cache_bytes += req_size;
  1013. +
  1014. + return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
  1015. +
  1016. +failed:
  1017. + BAD_ERROR("Out of memory in inode table reallocation!\n");
  1018. +}
  1019. +
  1020. +
  1021. +void read_bytes(int fd, long long byte, int bytes, char *buff)
  1022. +{
  1023. + off_t off = byte;
  1024. +
  1025. + pthread_mutex_lock(&pos_mutex);
  1026. + if(lseek(fd, off, SEEK_SET) == -1)
  1027. + BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
  1028. +
  1029. + if(read(fd, buff, bytes) == -1)
  1030. + BAD_ERROR("Read on destination failed because %s\n", strerror(errno));
  1031. + pthread_mutex_unlock(&pos_mutex);
  1032. +}
  1033. +
  1034. +
  1035. +void write_bytes(int fd, long long byte, int bytes, char *buff)
  1036. +{
  1037. + off_t off = byte;
  1038. +
  1039. + if(interrupted < 2)
  1040. + pthread_mutex_lock(&pos_mutex);
  1041. +
  1042. + if(lseek(fd, off, SEEK_SET) == -1)
  1043. + BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
  1044. +
  1045. + if(write(fd, buff, bytes) == -1)
  1046. + BAD_ERROR("Write on destination failed because %s\n", strerror(errno));
  1047. +
  1048. + if(interrupted < 2)
  1049. + pthread_mutex_unlock(&pos_mutex);
  1050. +}
  1051. +
  1052. +
  1053. +long long write_inodes()
  1054. +{
  1055. + unsigned short c_byte;
  1056. + int avail_bytes;
  1057. + char *datap = data_cache;
  1058. + long long start_bytes = bytes;
  1059. +
  1060. + while(cache_bytes) {
  1061. + if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
  1062. + if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
  1063. + BAD_ERROR("Out of memory in inode table reallocation!\n");
  1064. + }
  1065. + inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
  1066. + }
  1067. + avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
  1068. + c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
  1069. + TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
  1070. + if(!swap)
  1071. + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
  1072. + else
  1073. + SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
  1074. + if(check_data)
  1075. + *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
  1076. + inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
  1077. + total_inode_bytes += avail_bytes + block_offset;
  1078. + datap += avail_bytes;
  1079. + cache_bytes -= avail_bytes;
  1080. + }
  1081. +
  1082. + write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
  1083. + bytes += inode_bytes;
  1084. +
  1085. + return start_bytes;
  1086. +}
  1087. +
  1088. +
  1089. +long long write_directories()
  1090. +{
  1091. + unsigned short c_byte;
  1092. + int avail_bytes;
  1093. + char *directoryp = directory_data_cache;
  1094. + long long start_bytes = bytes;
  1095. +
  1096. + while(directory_cache_bytes) {
  1097. + if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
  1098. + if((directory_table = (char *) realloc(directory_table, directory_size +
  1099. + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
  1100. + BAD_ERROR("Out of memory in directory table reallocation!\n");
  1101. + }
  1102. + directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
  1103. + }
  1104. + avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
  1105. + c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
  1106. + TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
  1107. + if(!swap)
  1108. + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
  1109. + else
  1110. + SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
  1111. + if(check_data)
  1112. + *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
  1113. + directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
  1114. + total_directory_bytes += avail_bytes + block_offset;
  1115. + directoryp += avail_bytes;
  1116. + directory_cache_bytes -= avail_bytes;
  1117. + }
  1118. + write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
  1119. + bytes += directory_bytes;
  1120. +
  1121. + return start_bytes;
  1122. +}
  1123. +
  1124. +
  1125. +unsigned int get_uid(squashfs_uid uid)
  1126. +{
  1127. + int i;
  1128. +
  1129. + for(i = 0; (i < uid_count) && uids[i] != uid; i++);
  1130. + if(i == uid_count) {
  1131. + if(uid_count == SQUASHFS_UIDS) {
  1132. + ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
  1133. + i = 0;
  1134. + } else
  1135. + uids[uid_count++] = uid;
  1136. + }
  1137. +
  1138. + return i;
  1139. +}
  1140. +
  1141. +
  1142. +unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
  1143. +{
  1144. + int i;
  1145. +
  1146. + if(uid == guid)
  1147. + return SQUASHFS_GUIDS;
  1148. +
  1149. + for(i = 0; (i < guid_count) && guids[i] != guid; i++);
  1150. + if(i == guid_count) {
  1151. + if(guid_count == SQUASHFS_GUIDS) {
  1152. + ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
  1153. + return SQUASHFS_GUIDS;
  1154. + } else
  1155. + guids[guid_count++] = guid;
  1156. + }
  1157. +
  1158. + return i;
  1159. +}
  1160. +
  1161. +
  1162. +int 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)
  1163. +{
  1164. + struct stat *buf = &dir_ent->inode->buf;
  1165. + squashfs_inode_header inode_header;
  1166. + squashfs_base_inode_header *inode, *base = &inode_header.base;
  1167. + char *filename = dir_ent->pathname;
  1168. + int nlink = dir_ent->inode->nlink;
  1169. + int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
  1170. +
  1171. + base->mode = SQUASHFS_MODE(buf->st_mode);
  1172. + base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid);
  1173. + base->inode_type = type;
  1174. + base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid);
  1175. + base->mtime = buf->st_mtime;
  1176. + base->inode_number = inode_number;
  1177. +
  1178. + if(type == SQUASHFS_FILE_TYPE) {
  1179. + int i;
  1180. + squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
  1181. +
  1182. + inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
  1183. + inodep = (squashfs_reg_inode_header *) inode;
  1184. + reg->file_size = byte_size;
  1185. + reg->start_block = start_block;
  1186. + reg->fragment = fragment->index;
  1187. + reg->offset = fragment->offset;
  1188. + if(!swap) {
  1189. + memcpy(inodep, reg, sizeof(*reg));
  1190. + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
  1191. + } else {
  1192. + SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
  1193. + SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
  1194. + }
  1195. + TRACE("File inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d\n", byte_size,
  1196. + start_block, offset, fragment->index, fragment->offset, fragment->size);
  1197. + for(i = 0; i < offset; i++)
  1198. + TRACE("Block %d, size %d\n", i, block_list[i]);
  1199. + }
  1200. + else if(type == SQUASHFS_LREG_TYPE) {
  1201. + int i;
  1202. + squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep;
  1203. +
  1204. + inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
  1205. + inodep = (squashfs_lreg_inode_header *) inode;
  1206. + reg->nlink = nlink;
  1207. + reg->file_size = byte_size;
  1208. + reg->start_block = start_block;
  1209. + reg->fragment = fragment->index;
  1210. + reg->offset = fragment->offset;
  1211. + if(!swap) {
  1212. + memcpy(inodep, reg, sizeof(*reg));
  1213. + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
  1214. + } else {
  1215. + SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep);
  1216. + SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
  1217. + }
  1218. + TRACE("Long file inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size,
  1219. + start_block, offset, fragment->index, fragment->offset, fragment->size, nlink);
  1220. + for(i = 0; i < offset; i++)
  1221. + TRACE("Block %d, size %d\n", i, block_list[i]);
  1222. + }
  1223. + else if(type == SQUASHFS_LDIR_TYPE) {
  1224. + int i;
  1225. + unsigned char *p;
  1226. + squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep;
  1227. + struct cached_dir_index *index = dir_in->index;
  1228. + unsigned int i_count = dir_in->i_count;
  1229. + unsigned int i_size = dir_in->i_size;
  1230. +
  1231. + if(byte_size >= 1 << 27)
  1232. + BAD_ERROR("directory greater than 2^27-1 bytes!\n");
  1233. +
  1234. + inode = get_inode(sizeof(*dir) + i_size);
  1235. + inodep = (squashfs_ldir_inode_header *) inode;
  1236. + dir->inode_type = SQUASHFS_LDIR_TYPE;
  1237. + dir->nlink = dir_ent->dir->directory_count + 2;
  1238. + dir->file_size = byte_size;
  1239. + dir->offset = offset;
  1240. + dir->start_block = start_block;
  1241. + dir->i_count = i_count;
  1242. + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
  1243. +
  1244. + if(!swap)
  1245. + memcpy(inode, dir, sizeof(*dir));
  1246. + else
  1247. + SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
  1248. + p = (unsigned char *) inodep->index;
  1249. + for(i = 0; i < i_count; i++) {
  1250. + if(!swap)
  1251. + memcpy(p, &index[i].index, sizeof(squashfs_dir_index));
  1252. + else
  1253. + SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
  1254. + memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1);
  1255. + p += sizeof(squashfs_dir_index) + index[i].index.size + 1;
  1256. + }
  1257. + TRACE("Long directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
  1258. + start_block, offset, dir_ent->dir->directory_count + 2);
  1259. + }
  1260. + else if(type == SQUASHFS_DIR_TYPE) {
  1261. + squashfs_dir_inode_header *dir = &inode_header.dir;
  1262. +
  1263. + inode = get_inode(sizeof(*dir));
  1264. + dir->nlink = dir_ent->dir->directory_count + 2;
  1265. + dir->file_size = byte_size;
  1266. + dir->offset = offset;
  1267. + dir->start_block = start_block;
  1268. + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
  1269. + if(!swap)
  1270. + memcpy(inode, dir, sizeof(*dir));
  1271. + else
  1272. + SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
  1273. + TRACE("Directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
  1274. + start_block, offset, dir_ent->dir->directory_count + 2);
  1275. + }
  1276. + else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
  1277. + squashfs_dev_inode_header *dev = &inode_header.dev;
  1278. +
  1279. + inode = get_inode(sizeof(*dev));
  1280. + dev->nlink = nlink;
  1281. + dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) |
  1282. + (minor(buf->st_rdev) & 0xff));
  1283. + if(!swap)
  1284. + memcpy(inode, dev, sizeof(*dev));
  1285. + else
  1286. + SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
  1287. + TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
  1288. + }
  1289. + else if(type == SQUASHFS_SYMLINK_TYPE) {
  1290. + squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
  1291. + int byte;
  1292. + char buff[65536];
  1293. +
  1294. + if((byte = readlink(filename, buff, 65536)) == -1) {
  1295. + ERROR("Failed to read symlink %s, creating empty symlink\n", filename);
  1296. + byte = 0;
  1297. + }
  1298. +
  1299. + if(byte == 65536) {
  1300. + ERROR("Symlink %s is greater than 65536 bytes! Creating empty symlink\n", filename);
  1301. + byte = 0;
  1302. + }
  1303. +
  1304. + inode = get_inode(sizeof(*symlink) + byte);
  1305. + symlink->nlink = nlink;
  1306. + inodep = (squashfs_symlink_inode_header *) inode;
  1307. + symlink->symlink_size = byte;
  1308. + if(!swap)
  1309. + memcpy(inode, symlink, sizeof(*symlink));
  1310. + else
  1311. + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
  1312. + strncpy(inodep->symlink, buff, byte);
  1313. + TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink);
  1314. + }
  1315. + else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
  1316. + squashfs_ipc_inode_header *ipc = &inode_header.ipc;
  1317. +
  1318. + inode = get_inode(sizeof(*ipc));
  1319. + ipc->nlink = nlink;
  1320. + if(!swap)
  1321. + memcpy(inode, ipc, sizeof(*ipc));
  1322. + else
  1323. + SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
  1324. + TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
  1325. + } else
  1326. + BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
  1327. +
  1328. + *i_no = MKINODE(inode);
  1329. + inode_count ++;
  1330. +
  1331. + TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid);
  1332. +
  1333. + return TRUE;
  1334. +}
  1335. +
  1336. +
  1337. +void scan2_init_dir(struct directory *dir)
  1338. +{
  1339. + if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
  1340. + BAD_ERROR("Out of memory allocating directory buffer\n");
  1341. + }
  1342. +
  1343. + dir->size = SQUASHFS_METADATA_SIZE;
  1344. + dir->p = dir->index_count_p = dir->buff;
  1345. + dir->entry_count = 256;
  1346. + dir->entry_count_p = NULL;
  1347. + dir->index = NULL;
  1348. + dir->i_count = dir->i_size = 0;
  1349. +}
  1350. +
  1351. +
  1352. +void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir)
  1353. +{
  1354. + unsigned char *buff;
  1355. + squashfs_dir_entry idir, *idirp;
  1356. + unsigned int start_block = inode >> 16;
  1357. + unsigned int offset = inode & 0xffff;
  1358. + unsigned int size;
  1359. +
  1360. + if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
  1361. + size = SQUASHFS_NAME_LEN;
  1362. + ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
  1363. + }
  1364. +
  1365. + if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
  1366. + if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) {
  1367. + BAD_ERROR("Out of memory reallocating directory buffer\n");
  1368. + }
  1369. +
  1370. + dir->p = (dir->p - dir->buff) + buff;
  1371. + if(dir->entry_count_p)
  1372. + dir->entry_count_p = (dir->entry_count_p - dir->buff + buff);
  1373. + dir->index_count_p = dir->index_count_p - dir->buff + buff;
  1374. + dir->buff = buff;
  1375. + }
  1376. +
  1377. + 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) {
  1378. + if(dir->entry_count_p) {
  1379. + squashfs_dir_header dir_header;
  1380. +
  1381. + if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) {
  1382. + if(dir->i_count % I_COUNT_SIZE == 0)
  1383. + if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL)
  1384. + BAD_ERROR("Out of memory in directory index table reallocation!\n");
  1385. + dir->index[dir->i_count].index.index = dir->p - dir->buff;
  1386. + dir->index[dir->i_count].index.size = size - 1;
  1387. + dir->index[dir->i_count++].name = name;
  1388. + dir->i_size += sizeof(squashfs_dir_index) + size;
  1389. + dir->index_count_p = dir->p;
  1390. + }
  1391. +
  1392. + dir_header.count = dir->entry_count - 1;
  1393. + dir_header.start_block = dir->start_block;
  1394. + dir_header.inode_number = dir->inode_number;
  1395. + if(!swap)
  1396. + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
  1397. + else
  1398. + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
  1399. +
  1400. + }
  1401. +
  1402. +
  1403. + dir->entry_count_p = dir->p;
  1404. + dir->start_block = start_block;
  1405. + dir->entry_count = 0;
  1406. + dir->inode_number = inode_number;
  1407. + dir->p += sizeof(squashfs_dir_header);
  1408. + }
  1409. +
  1410. + idirp = (squashfs_dir_entry *) dir->p;
  1411. + idir.offset = offset;
  1412. + idir.type = type;
  1413. + idir.size = size - 1;
  1414. + idir.inode_number = ((long long) inode_number - dir->inode_number);
  1415. + if(!swap)
  1416. + memcpy(idirp, &idir, sizeof(idir));
  1417. + else
  1418. + SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
  1419. + strncpy(idirp->name, name, size);
  1420. + dir->p += sizeof(squashfs_dir_entry) + size;
  1421. + dir->entry_count ++;
  1422. +}
  1423. +
  1424. +
  1425. +void write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir)
  1426. +{
  1427. + unsigned int dir_size = dir->p - dir->buff;
  1428. + int data_space = (directory_cache_size - directory_cache_bytes);
  1429. + unsigned int directory_block, directory_offset, i_count, index;
  1430. + unsigned short c_byte;
  1431. +
  1432. + if(data_space < dir_size) {
  1433. + int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
  1434. +
  1435. + if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
  1436. + goto failed;
  1437. + }
  1438. + directory_cache_size += realloc_size;
  1439. + }
  1440. +
  1441. + if(dir_size) {
  1442. + squashfs_dir_header dir_header;
  1443. +
  1444. + dir_header.count = dir->entry_count - 1;
  1445. + dir_header.start_block = dir->start_block;
  1446. + dir_header.inode_number = dir->inode_number;
  1447. + if(!swap)
  1448. + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
  1449. + else
  1450. + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
  1451. + memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
  1452. + }
  1453. + directory_offset = directory_cache_bytes;
  1454. + directory_block = directory_bytes;
  1455. + directory_cache_bytes += dir_size;
  1456. + i_count = 0;
  1457. + index = SQUASHFS_METADATA_SIZE - directory_offset;
  1458. +
  1459. + while(1) {
  1460. + while(i_count < dir->i_count && dir->index[i_count].index.index < index)
  1461. + dir->index[i_count++].index.start_block = directory_bytes;
  1462. + index += SQUASHFS_METADATA_SIZE;
  1463. +
  1464. + if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
  1465. + break;
  1466. +
  1467. + if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
  1468. + if((directory_table = (char *) realloc(directory_table,
  1469. + directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
  1470. + goto failed;
  1471. + }
  1472. + directory_size += SQUASHFS_METADATA_SIZE << 1;
  1473. + }
  1474. +
  1475. + c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
  1476. + SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
  1477. + TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
  1478. + if(!swap)
  1479. + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
  1480. + else
  1481. + SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
  1482. + if(check_data)
  1483. + *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
  1484. + directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
  1485. + total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
  1486. + memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
  1487. + directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
  1488. + }
  1489. +
  1490. + if(dir_info->dir_is_ldir)
  1491. + create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir);
  1492. + else
  1493. + create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL);
  1494. +
  1495. +#ifdef SQUASHFS_TRACE
  1496. + if(!swap) {
  1497. + unsigned char *dirp;
  1498. + int count;
  1499. +
  1500. + TRACE("Directory contents of inode 0x%llx\n", *inode);
  1501. + dirp = dir->buff;
  1502. + while(dirp < dir->p) {
  1503. + char buffer[SQUASHFS_NAME_LEN + 1];
  1504. + squashfs_dir_entry idir, *idirp;
  1505. + squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
  1506. + count = dirh->count + 1;
  1507. + dirp += sizeof(squashfs_dir_header);
  1508. +
  1509. + TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
  1510. +
  1511. + while(count--) {
  1512. + idirp = (squashfs_dir_entry *) dirp;
  1513. + memcpy((char *) &idir, (char *) idirp, sizeof(idir));
  1514. + strncpy(buffer, idirp->name, idir.size + 1);
  1515. + buffer[idir.size + 1] = '\0';
  1516. + TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
  1517. + idir.offset, idir.type);
  1518. + dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
  1519. + }
  1520. + }
  1521. + }
  1522. +#endif
  1523. + dir_count ++;
  1524. +
  1525. + return;
  1526. +
  1527. +failed:
  1528. + BAD_ERROR("Out of memory in directory table reallocation!\n");
  1529. +}
  1530. +
  1531. +
  1532. +struct file_buffer *get_fragment(struct fragment *fragment)
  1533. +{
  1534. + squashfs_fragment_entry *disk_fragment;
  1535. + int size;
  1536. + long long start_block;
  1537. + struct file_buffer *buffer, *compressed_buffer;
  1538. +
  1539. + if(fragment->index == SQUASHFS_INVALID_FRAG)
  1540. + return NULL;
  1541. +
  1542. + buffer = cache_lookup(fragment_buffer, fragment->index);
  1543. + if(buffer)
  1544. + return buffer;
  1545. +
  1546. + compressed_buffer = cache_lookup(writer_buffer, fragment->index + FRAG_INDEX);
  1547. +
  1548. + buffer = cache_get(fragment_buffer, fragment->index, 1);
  1549. +
  1550. + pthread_mutex_lock(&fragment_mutex);
  1551. + disk_fragment = &fragment_table[fragment->index];
  1552. + size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
  1553. + start_block = disk_fragment->start_block;
  1554. + pthread_mutex_unlock(&fragment_mutex);
  1555. +
  1556. + if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
  1557. + int res;
  1558. + unsigned long bytes = block_size;
  1559. + char *data;
  1560. + char cbuffer[block_size];
  1561. +
  1562. + if(compressed_buffer)
  1563. + data = compressed_buffer->data;
  1564. + else {
  1565. + data = cbuffer;
  1566. + read_bytes(fd, start_block, size, data);
  1567. + }
  1568. +
  1569. + if((res = uncompress((unsigned char

Large files files are truncated, but you can click here to view the full file