· 11 years ago · Jul 24, 2015, 10:50 AM
1diff -Nru squashfs-tools-4.2+20130409/action.c squashfs-tools-4.3+20140919/action.c
2--- squashfs-tools-4.2+20130409/action.c 2013-05-09 10:39:11.000000000 +0200
3+++ squashfs-tools-4.3+20140919/action.c 2015-07-20 21:03:05.000000000 +0200
4@@ -2,7 +2,7 @@
5 * Create a squashfs filesystem. This is a highly compressed read only
6 * filesystem.
7 *
8- * Copyright (c) 2011, 2012, 2013
9+ * Copyright (c) 2011, 2012, 2013, 2014
10 * Phillip Lougher <phillip@squashfs.org.uk>
11 *
12 * This program is free software; you can redistribute it and/or
13@@ -53,12 +53,15 @@
14 static struct action *exclude_spec = NULL;
15 static struct action *empty_spec = NULL;
16 static struct action *move_spec = NULL;
17+static struct action *prune_spec = NULL;
18 static struct action *other_spec = NULL;
19 static int fragment_count = 0;
20 static int exclude_count = 0;
21 static int empty_count = 0;
22 static int move_count = 0;
23+static int prune_count = 0;
24 static int other_count = 0;
25+static struct action_entry *parsing_action;
26
27 static struct file_buffer *def_fragment = NULL;
28
29@@ -198,12 +201,34 @@
30 /*
31 * Expression parser
32 */
33+static void free_parse_tree(struct expr *expr)
34+{
35+ if(expr->type == ATOM_TYPE) {
36+ int i;
37+
38+ for(i = 0; i < expr->atom.test->args; i++)
39+ free(expr->atom.argv[i]);
40+
41+ free(expr->atom.argv);
42+ } else if (expr->type == UNARY_TYPE)
43+ free_parse_tree(expr->unary_op.expr);
44+ else {
45+ free_parse_tree(expr->expr_op.lhs);
46+ free_parse_tree(expr->expr_op.rhs);
47+ }
48+
49+ free(expr);
50+}
51+
52+
53 static struct expr *create_expr(struct expr *lhs, int op, struct expr *rhs)
54 {
55 struct expr *expr;
56
57- if (rhs == NULL)
58+ if (rhs == NULL) {
59+ free_parse_tree(lhs);
60 return NULL;
61+ }
62
63 expr = malloc(sizeof(*expr));
64 if (expr == NULL)
65@@ -239,8 +264,8 @@
66
67 static struct expr *parse_test(char *name)
68 {
69- char *string;
70- int token;
71+ char *string, **argv = NULL;
72+ int token, args = 0;
73 int i;
74 struct test_entry *test;
75 struct expr *expr;
76@@ -249,12 +274,20 @@
77 if (strcmp(name, test_table[i].name) == 0)
78 break;
79
80- if (test_table[i].args == -1) {
81+ test = &test_table[i];
82+
83+ if (test->args == -1) {
84 SYNTAX_ERROR("Non-existent test \"%s\"\n", name);
85 return NULL;
86 }
87
88- test = &test_table[i];
89+ if(parsing_action->type == EXCLUDE_ACTION && !test->exclude_ok) {
90+ fprintf(stderr, "Failed to parse action \"%s\"\n", source);
91+ fprintf(stderr, "Test \"%s\" cannot be used in exclude "
92+ "actions\n", name);
93+ fprintf(stderr, "Use prune action instead ...\n");
94+ return NULL;
95+ }
96
97 expr = malloc(sizeof(*expr));
98 if (expr == NULL)
99@@ -262,55 +295,68 @@
100
101 expr->type = ATOM_TYPE;
102
103- expr->atom.argv = malloc(test->args * sizeof(char *));
104- if (expr->atom.argv == NULL)
105- MEM_ERROR();
106-
107 expr->atom.test = test;
108 expr->atom.data = NULL;
109
110 /*
111- * If the test has no arguments, allow it to be typed
112- * without brackets
113+ * If the test has no arguments, then go straight to checking if there's
114+ * enough arguments
115 */
116- if (test->args == 0) {
117- token = peek_token(&string);
118+ token = peek_token(&string);
119
120- if (token != TOK_OPEN_BRACKET)
121+ if (token != TOK_OPEN_BRACKET)
122 goto skip_args;
123- }
124-
125- token = get_token(&string);
126
127- if (token != TOK_OPEN_BRACKET) {
128- SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n",
129- TOK_TO_STR(token, string));
130- goto failed;
131- }
132+ get_token(&string);
133
134- for (i = 0; i < test->args; i++) {
135- token = get_token(&string);
136+ /*
137+ * speculatively read all the arguments, and then see if the
138+ * number of arguments read is the number expected, this handles
139+ * tests with a variable number of arguments
140+ */
141+ token = get_token(&string);
142+ if (token == TOK_CLOSE_BRACKET)
143+ goto skip_args;
144
145+ while(1) {
146 if (token != TOK_STRING) {
147 SYNTAX_ERROR("Unexpected token \"%s\", expected "
148 "argument\n", TOK_TO_STR(token, string));
149 goto failed;
150 }
151
152- expr->atom.argv[i] = strdup(string);
153+ argv = realloc(argv, (args + 1) * sizeof(char *));
154+ if (argv == NULL)
155+ MEM_ERROR();
156+
157+ argv[args ++ ] = strdup(string);
158+
159+ token = get_token(&string);
160
161- if (i + 1 < test->args) {
162- token = get_token(&string);
163+ if (token == TOK_CLOSE_BRACKET)
164+ break;
165
166- if (token != TOK_COMMA) {
167- SYNTAX_ERROR("Unexpected token \"%s\", "
168- "expected \",\"\n",
169- TOK_TO_STR(token, string));
170+ if (token != TOK_COMMA) {
171+ SYNTAX_ERROR("Unexpected token \"%s\", expected "
172+ "\",\" or \")\"\n", TOK_TO_STR(token, string));
173 goto failed;
174- }
175 }
176+ token = get_token(&string);
177+ }
178+
179+skip_args:
180+ /*
181+ * expected number of arguments?
182+ */
183+ if(test->args != -2 && args != test->args) {
184+ SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
185+ "got %d\n", test->args, args);
186+ goto failed;
187 }
188
189+ expr->atom.args = args;
190+ expr->atom.argv = argv;
191+
192 if (test->parse_args) {
193 int res = test->parse_args(test, &expr->atom);
194
195@@ -318,19 +364,10 @@
196 goto failed;
197 }
198
199- token = get_token(&string);
200-
201- if (token != TOK_CLOSE_BRACKET) {
202- SYNTAX_ERROR("Unexpected token \"%s\", expected \")\"\n",
203- TOK_TO_STR(token, string));
204- goto failed;
205- }
206-
207-skip_args:
208 return expr;
209
210 failed:
211- free(expr->atom.argv);
212+ free(argv);
213 free(expr);
214 return NULL;
215 }
216@@ -367,6 +404,7 @@
217
218 if (op == TOK_EOF) {
219 if (subexp) {
220+ free_parse_tree(expr);
221 SYNTAX_ERROR("Expected \"&&\", \"||\" or "
222 "\")\", got EOF\n");
223 return NULL;
224@@ -376,6 +414,7 @@
225
226 if (op == TOK_CLOSE_BRACKET) {
227 if (!subexp) {
228+ free_parse_tree(expr);
229 SYNTAX_ERROR("Unexpected \")\", expected "
230 "\"&&\", \"!!\" or EOF\n");
231 return NULL;
232@@ -384,6 +423,7 @@
233 }
234
235 if (op != TOK_AND && op != TOK_OR) {
236+ free_parse_tree(expr);
237 SYNTAX_ERROR("Unexpected token \"%s\", expected "
238 "\"&&\" or \"||\"\n", TOK_TO_STR(op, string));
239 return NULL;
240@@ -399,7 +439,7 @@
241 /*
242 * Action parser
243 */
244-int parse_action(char *s)
245+int parse_action(char *s, int verbose)
246 {
247 char *string, **argv = NULL;
248 int i, token, args = 0;
249@@ -501,6 +541,7 @@
250 goto failed;
251 }
252
253+ parsing_action = action;
254 expr = parse_expr(0);
255
256 if (expr == NULL)
257@@ -526,6 +567,10 @@
258 spec_count = move_count ++;
259 spec_list = &move_spec;
260 break;
261+ case PRUNE_ACTION:
262+ spec_count = prune_count ++;
263+ spec_list = &prune_spec;
264+ break;
265 default:
266 spec_count = other_count ++;
267 spec_list = &other_spec;
268@@ -542,6 +587,7 @@
269 (*spec_list)[spec_count].argv = argv;
270 (*spec_list)[spec_count].expr = expr;
271 (*spec_list)[spec_count].data = data;
272+ (*spec_list)[spec_count].verbose = verbose;
273
274 return 1;
275
276@@ -551,68 +597,133 @@
277 }
278
279
280-static void dump_parse_tree(struct expr *expr)
281-{
282- if(expr->type == ATOM_TYPE) {
283- int i;
284+/*
285+ * Evaluate expressions
286+ */
287
288- printf("%s(", expr->atom.test->name);
289- for(i = 0; i < expr->atom.test->args; i++) {
290- printf("%s", expr->atom.argv[i]);
291- if (i + 1 < expr->atom.test->args)
292- printf(",");
293- }
294- printf(")");
295- } else if (expr->type == UNARY_TYPE) {
296- printf("%s", token_table[expr->unary_op.op].string);
297- dump_parse_tree(expr->unary_op.expr);
298- } else {
299- printf("(");
300- dump_parse_tree(expr->expr_op.lhs);
301- printf("%s", token_table[expr->expr_op.op].string);
302- dump_parse_tree(expr->expr_op.rhs);
303- printf(")");
304+#define ALLOC_SZ 128
305+
306+#define LOG_ENABLE 0
307+#define LOG_DISABLE 1
308+#define LOG_PRINT 2
309+#define LOG_ENABLED 3
310+
311+char *_expr_log(char *string, int cmnd)
312+{
313+ static char *expr_msg = NULL;
314+ static int cur_size = 0, alloc_size = 0;
315+ int size;
316+
317+ switch(cmnd) {
318+ case LOG_ENABLE:
319+ expr_msg = malloc(ALLOC_SZ);
320+ alloc_size = ALLOC_SZ;
321+ cur_size = 0;
322+ return expr_msg;
323+ case LOG_DISABLE:
324+ free(expr_msg);
325+ alloc_size = cur_size = 0;
326+ return expr_msg = NULL;
327+ case LOG_ENABLED:
328+ return expr_msg;
329+ default:
330+ if(expr_msg == NULL)
331+ return NULL;
332+ break;
333+ }
334+
335+ /* if string is empty append '\0' */
336+ size = strlen(string) ? : 1;
337+
338+ if(alloc_size - cur_size < size) {
339+ /* buffer too small, expand */
340+ alloc_size = (cur_size + size + ALLOC_SZ - 1) & ~(ALLOC_SZ - 1);
341+
342+ expr_msg = realloc(expr_msg, alloc_size);
343+ if(expr_msg == NULL)
344+ MEM_ERROR();
345 }
346+
347+ memcpy(expr_msg + cur_size, string, size);
348+ cur_size += size;
349+
350+ return expr_msg;
351 }
352
353
354-void dump_action_list(struct action *spec_list, int spec_count)
355+char *expr_log_cmnd(int cmnd)
356+{
357+ return _expr_log(NULL, cmnd);
358+}
359+
360+
361+char *expr_log(char *string)
362+{
363+ return _expr_log(string, LOG_PRINT);
364+}
365+
366+
367+void expr_log_atom(struct atom *atom)
368 {
369 int i;
370
371- for (i = 0; i < spec_count; i++) {
372- printf("%s", spec_list[i].action->name);
373- if (spec_list[i].action->args) {
374- int n;
375+ if(atom->test->handle_logging)
376+ return;
377
378- printf("(");
379- for (n = 0; n < spec_list[i].action->args; n++) {
380- printf("%s", spec_list[i].argv[n]);
381- if (n + 1 < spec_list[i].action->args)
382- printf(",");
383- }
384- printf(")");
385+ expr_log(atom->test->name);
386+
387+ if(atom->args) {
388+ expr_log("(");
389+ for(i = 0; i < atom->args; i++) {
390+ expr_log(atom->argv[i]);
391+ if (i + 1 < atom->args)
392+ expr_log(",");
393 }
394- printf("=");
395- dump_parse_tree(spec_list[i].expr);
396- printf("\n");
397+ expr_log(")");
398 }
399 }
400
401
402-void dump_actions()
403+void expr_log_match(int match)
404 {
405- dump_action_list(exclude_spec, exclude_count);
406- dump_action_list(fragment_spec, fragment_count);
407- dump_action_list(other_spec, other_count);
408- dump_action_list(move_spec, move_count);
409- dump_action_list(empty_spec, empty_count);
410+ if(match)
411+ expr_log("=True");
412+ else
413+ expr_log("=False");
414+}
415+
416+
417+static int eval_expr_log(struct expr *expr, struct action_data *action_data)
418+{
419+ int match;
420+
421+ switch (expr->type) {
422+ case ATOM_TYPE:
423+ expr_log_atom(&expr->atom);
424+ match = expr->atom.test->fn(&expr->atom, action_data);
425+ expr_log_match(match);
426+ break;
427+ case UNARY_TYPE:
428+ expr_log("!");
429+ match = !eval_expr_log(expr->unary_op.expr, action_data);
430+ break;
431+ default:
432+ expr_log("(");
433+ match = eval_expr_log(expr->expr_op.lhs, action_data);
434+
435+ if ((expr->expr_op.op == TOK_AND && match) ||
436+ (expr->expr_op.op == TOK_OR && !match)) {
437+ expr_log(token_table[expr->expr_op.op].string);
438+ match = eval_expr_log(expr->expr_op.rhs, action_data);
439+ }
440+ expr_log(")");
441+ break;
442+ }
443+
444+ return match;
445 }
446
447
448-/*
449- * Evaluate expressions
450- */
451 static int eval_expr(struct expr *expr, struct action_data *action_data)
452 {
453 int match;
454@@ -637,6 +748,49 @@
455 }
456
457
458+static int eval_expr_top(struct action *action, struct action_data *action_data)
459+{
460+ if(action->verbose) {
461+ int match, n;
462+
463+ expr_log_cmnd(LOG_ENABLE);
464+
465+ if(action_data->subpath)
466+ expr_log(action_data->subpath);
467+
468+ expr_log("=");
469+ expr_log(action->action->name);
470+
471+ if(action->args) {
472+ expr_log("(");
473+ for (n = 0; n < action->args; n++) {
474+ expr_log(action->argv[n]);
475+ if(n + 1 < action->args)
476+ expr_log(",");
477+ }
478+ expr_log(")");
479+ }
480+
481+ expr_log("@");
482+
483+ match = eval_expr_log(action->expr, action_data);
484+
485+ /*
486+ * Print the evaluated expression log, if the
487+ * result matches the logging specified
488+ */
489+ if((match && (action->verbose & ACTION_LOG_TRUE)) || (!match
490+ && (action->verbose & ACTION_LOG_FALSE)))
491+ progressbar_info("%s\n", expr_log(""));
492+
493+ expr_log_cmnd(LOG_DISABLE);
494+
495+ return match;
496+ } else
497+ return eval_expr(action->expr, action_data);
498+}
499+
500+
501 /*
502 * Read action file, passing each line to parse_action() for
503 * parsing.
504@@ -648,9 +802,65 @@
505 *
506 * Blank lines and comment lines indicated by # are supported.
507 */
508-int read_action_file(char *filename)
509+int parse_action_true(char *s)
510+{
511+ return parse_action(s, ACTION_LOG_TRUE);
512+}
513+
514+
515+int parse_action_false(char *s)
516+{
517+ return parse_action(s, ACTION_LOG_FALSE);
518+}
519+
520+
521+int parse_action_verbose(char *s)
522+{
523+ return parse_action(s, ACTION_LOG_VERBOSE);
524+}
525+
526+
527+int parse_action_nonverbose(char *s)
528+{
529+ return parse_action(s, ACTION_LOG_NONE);
530+}
531+
532+
533+int read_action_file(char *filename, int verbose)
534+{
535+ switch(verbose) {
536+ case ACTION_LOG_TRUE:
537+ return read_file(filename, "action", parse_action_true);
538+ case ACTION_LOG_FALSE:
539+ return read_file(filename, "action", parse_action_false);
540+ case ACTION_LOG_VERBOSE:
541+ return read_file(filename, "action", parse_action_verbose);
542+ default:
543+ return read_file(filename, "action", parse_action_nonverbose);
544+ }
545+}
546+
547+
548+/*
549+ * helper to evaluate whether action/test acts on this file type
550+ */
551+static int file_type_match(int st_mode, int type)
552 {
553- return read_file(filename, "action", parse_action);
554+ switch(type) {
555+ case ACTION_DIR:
556+ return S_ISDIR(st_mode);
557+ case ACTION_REG:
558+ return S_ISREG(st_mode);
559+ case ACTION_ALL:
560+ return S_ISREG(st_mode) || S_ISDIR(st_mode) ||
561+ S_ISCHR(st_mode) || S_ISBLK(st_mode) ||
562+ S_ISFIFO(st_mode) || S_ISSOCK(st_mode);
563+ case ACTION_LNK:
564+ return S_ISLNK(st_mode);
565+ case ACTION_ALL_LNK:
566+ default:
567+ return 1;
568+ }
569 }
570
571
572@@ -663,53 +873,65 @@
573 }
574
575
576-void eval_actions(struct dir_ent *dir_ent)
577+void eval_actions(struct dir_info *root, struct dir_ent *dir_ent)
578 {
579 int i, match;
580 struct action_data action_data;
581- int file_type = dir_ent->inode->buf.st_mode & S_IFMT;
582+ int st_mode = dir_ent->inode->buf.st_mode;
583
584 action_data.name = dir_ent->name;
585- action_data.pathname = pathname(dir_ent);
586- action_data.subpath = subpathname(dir_ent);
587+ action_data.pathname = strdup(pathname(dir_ent));
588+ action_data.subpath = strdup(subpathname(dir_ent));
589 action_data.buf = &dir_ent->inode->buf;
590 action_data.depth = dir_ent->our_dir->depth;
591+ action_data.dir_ent = dir_ent;
592+ action_data.root = root;
593
594 for (i = 0; i < other_count; i++) {
595 struct action *action = &other_spec[i];
596
597- if ((action->action->file_types & file_type) == 0)
598+ if (!file_type_match(st_mode, action->action->file_types))
599 /* action does not operate on this file type */
600 continue;
601
602- match = eval_expr(action->expr, &action_data);
603+ match = eval_expr_top(action, &action_data);
604
605 if (match)
606 action->action->run_action(action, dir_ent);
607 }
608+
609+ free(action_data.pathname);
610+ free(action_data.subpath);
611 }
612
613
614 /*
615 * Fragment specific action code
616 */
617-void *eval_frag_actions(struct dir_ent *dir_ent)
618+void *eval_frag_actions(struct dir_info *root, struct dir_ent *dir_ent)
619 {
620 int i, match;
621 struct action_data action_data;
622
623 action_data.name = dir_ent->name;
624- action_data.pathname = pathname(dir_ent);
625- action_data.subpath = subpathname(dir_ent);
626+ action_data.pathname = strdup(pathname(dir_ent));
627+ action_data.subpath = strdup(subpathname(dir_ent));
628 action_data.buf = &dir_ent->inode->buf;
629 action_data.depth = dir_ent->our_dir->depth;
630+ action_data.dir_ent = dir_ent;
631+ action_data.root = root;
632
633 for (i = 0; i < fragment_count; i++) {
634- match = eval_expr(fragment_spec[i].expr, &action_data);
635- if (match)
636+ match = eval_expr_top(&fragment_spec[i], &action_data);
637+ if (match) {
638+ free(action_data.pathname);
639+ free(action_data.subpath);
640 return &fragment_spec[i].data;
641+ }
642 }
643
644+ free(action_data.pathname);
645+ free(action_data.subpath);
646 return &def_fragment;
647 }
648
649@@ -747,7 +969,7 @@
650
651
652 int eval_exclude_actions(char *name, char *pathname, char *subpath,
653- struct stat *buf, int depth)
654+ struct stat *buf, int depth, struct dir_ent *dir_ent)
655 {
656 int i, match = 0;
657 struct action_data action_data;
658@@ -757,9 +979,10 @@
659 action_data.subpath = subpath;
660 action_data.buf = buf;
661 action_data.depth = depth;
662+ action_data.dir_ent = dir_ent;
663
664 for (i = 0; i < exclude_count && !match; i++)
665- match = eval_expr(exclude_spec[i].expr, &action_data);
666+ match = eval_expr_top(&exclude_spec[i], &action_data);
667
668 return match;
669 }
670@@ -823,8 +1046,8 @@
671 long long uid = strtoll(arg, &b, 10);
672
673 if (*b == '\0') {
674- if (uid < 0 || uid >= (1LL < 32)) {
675- SYNTAX_ERROR("action: uid out of range\n");
676+ if (uid < 0 || uid >= (1LL << 32)) {
677+ SYNTAX_ERROR("Uid out of range\n");
678 return -1;
679 }
680 } else {
681@@ -833,7 +1056,7 @@
682 if (passwd)
683 uid = passwd->pw_uid;
684 else {
685- SYNTAX_ERROR("action: invalid uid or unknown user\n");
686+ SYNTAX_ERROR("Invalid uid or unknown user\n");
687 return -1;
688 }
689 }
690@@ -847,8 +1070,8 @@
691 long long gid = strtoll(arg, &b, 10);
692
693 if (*b == '\0') {
694- if (gid < 0 || gid >= (1LL < 32)) {
695- SYNTAX_ERROR("action: gid out of range\n");
696+ if (gid < 0 || gid >= (1LL << 32)) {
697+ SYNTAX_ERROR("Gid out of range\n");
698 return -1;
699 }
700 } else {
701@@ -857,7 +1080,7 @@
702 if (group)
703 gid = group->gr_gid;
704 else {
705- SYNTAX_ERROR("action: invalid gid or unknown user\n");
706+ SYNTAX_ERROR("Invalid gid or unknown group\n");
707 return -1;
708 }
709 }
710@@ -964,29 +1187,37 @@
711 /*
712 * Mode specific action code
713 */
714-static int parse_octal_mode_args(unsigned int mode, int bytes, int args,
715- char **argv, void **data)
716+static int parse_octal_mode_args(int args, char **argv,
717+ void **data)
718 {
719+ int n, bytes;
720+ unsigned int mode;
721 struct mode_data *mode_data;
722
723+ /* octal mode number? */
724+ n = sscanf(argv[0], "%o%n", &mode, &bytes);
725+ if (n == 0)
726+ return -1; /* not an octal number arg */
727+
728+
729 /* check there's no trailing junk */
730 if (argv[0][bytes] != '\0') {
731 SYNTAX_ERROR("Unexpected trailing bytes after octal "
732 "mode number\n");
733- return 0;
734+ return 0; /* bad octal number arg */
735 }
736
737 /* check there's only one argument */
738 if (args > 1) {
739 SYNTAX_ERROR("Octal mode number is first argument, "
740 "expected one argument, got %d\n", args);
741- return 0;
742+ return 0; /* bad octal number arg */
743 }
744
745 /* check mode is within range */
746 if (mode > 07777) {
747 SYNTAX_ERROR("Octal mode %o is out of range\n", mode);
748- return 0;
749+ return 0; /* bad octal number arg */
750 }
751
752 mode_data = malloc(sizeof(struct mode_data));
753@@ -1003,19 +1234,17 @@
754
755
756 /*
757- * Parse symbolic mode of format [ugoa]+[+-=]PERMS
758+ * Parse symbolic mode of format [ugoa]*[[+-=]PERMS]+
759 * PERMS = [rwxXst]+ or [ugo]
760 */
761-static struct mode_data *parse_sym_mode_arg(char *arg)
762+static int parse_sym_mode_arg(char *arg, struct mode_data **head,
763+ struct mode_data **cur)
764 {
765- struct mode_data *mode_data = malloc(sizeof(*mode_data));
766- int mode = 0;
767+ struct mode_data *mode_data;
768+ int mode;
769 int mask = 0;
770 int op;
771- char X = 0;
772-
773- if (mode_data == NULL)
774- MEM_ERROR();
775+ char X;
776
777 if (arg[0] != 'u' && arg[0] != 'g' && arg[0] != 'o' && arg[0] != 'a') {
778 /* no ownership specifiers, default to a */
779@@ -1045,130 +1274,138 @@
780 }
781
782 parse_operation:
783- switch(*arg) {
784- case '+':
785- op = ACTION_MODE_ADD;
786- break;
787- case '-':
788- op = ACTION_MODE_REM;
789- break;
790- case '=':
791- op = ACTION_MODE_SET;
792- break;
793- default:
794- SYNTAX_ERROR("Action mode: Expected one of '+', '-' or '=', "
795- "got '%c'\n", *arg);
796+ /* trap a symbolic mode with just an ownership specification */
797+ if(*arg == '\0') {
798+ SYNTAX_ERROR("Expected one of '+', '-' or '=', got EOF\n");
799 goto failed;
800 }
801
802- arg ++;
803+ while(*arg != '\0') {
804+ mode = 0;
805+ X = 0;
806
807- /* Parse PERMS */
808- if (*arg == 'u' || *arg == 'g' || *arg == 'o') {
809- /* PERMS = [ugo] */
810- mode = - *arg;
811- if (*++arg != '\0') {
812- SYNTAX_ERROR("Action mode: permission 'u', 'g' or 'o' "
813- "has trailing characters\n");
814+ switch(*arg) {
815+ case '+':
816+ op = ACTION_MODE_ADD;
817+ break;
818+ case '-':
819+ op = ACTION_MODE_REM;
820+ break;
821+ case '=':
822+ op = ACTION_MODE_SET;
823+ break;
824+ default:
825+ SYNTAX_ERROR("Expected one of '+', '-' or '=', got "
826+ "'%c'\n", *arg);
827 goto failed;
828 }
829- } else {
830- /* PERMS = [rwxXst]+ */
831- while(*arg != '\0') {
832- switch(*arg) {
833- case 'r':
834- mode |= 0444;
835- break;
836- case 'w':
837- mode |= 0222;
838- break;
839- case 'x':
840- mode |= 0111;
841- break;
842- case 's':
843- mode |= 06000;
844- break;
845- case 't':
846- mode |= 01000;
847- break;
848- case 'X':
849- X = 1;
850- break;
851- default:
852- SYNTAX_ERROR("Action mode: unrecognised "
853- "permission '%c'\n", *arg);
854- goto failed;
855- }
856-
857+
858+ arg ++;
859+
860+ /* Parse PERMS */
861+ if (*arg == 'u' || *arg == 'g' || *arg == 'o') {
862+ /* PERMS = [ugo] */
863+ mode = - *arg;
864 arg ++;
865+ } else {
866+ /* PERMS = [rwxXst]* */
867+ while(1) {
868+ switch(*arg) {
869+ case 'r':
870+ mode |= 0444;
871+ break;
872+ case 'w':
873+ mode |= 0222;
874+ break;
875+ case 'x':
876+ mode |= 0111;
877+ break;
878+ case 's':
879+ mode |= 06000;
880+ break;
881+ case 't':
882+ mode |= 01000;
883+ break;
884+ case 'X':
885+ X = 1;
886+ break;
887+ case '+':
888+ case '-':
889+ case '=':
890+ case '\0':
891+ mode &= mask;
892+ goto perms_parsed;
893+ default:
894+ SYNTAX_ERROR("Unrecognised permission "
895+ "'%c'\n", *arg);
896+ goto failed;
897+ }
898+
899+ arg ++;
900+ }
901 }
902- mode &= mask;
903- }
904+
905+perms_parsed:
906+ mode_data = malloc(sizeof(*mode_data));
907+ if (mode_data == NULL)
908+ MEM_ERROR();
909
910- mode_data->operation = op;
911- mode_data->mode = mode;
912- mode_data->mask = mask;
913- mode_data->X = X;
914- mode_data->next = NULL;
915+ mode_data->operation = op;
916+ mode_data->mode = mode;
917+ mode_data->mask = mask;
918+ mode_data->X = X;
919+ mode_data->next = NULL;
920+
921+ if (*cur) {
922+ (*cur)->next = mode_data;
923+ *cur = mode_data;
924+ } else
925+ *head = *cur = mode_data;
926+ }
927
928- return mode_data;
929+ return 1;
930
931 failed:
932- free(mode_data);
933- return NULL;
934+ return 0;
935 }
936
937
938 static int parse_sym_mode_args(struct action_entry *action, int args,
939 char **argv, void **data)
940 {
941- int i;
942+ int i, res = 1;
943 struct mode_data *head = NULL, *cur = NULL;
944
945- for (i = 0; i < args; i++) {
946- struct mode_data *entry = parse_sym_mode_arg(argv[i]);
947-
948- if (entry == NULL)
949- return 0;
950-
951- if (cur) {
952- cur->next = entry;
953- cur = entry;
954- } else
955- head = cur = entry;
956- }
957+ for (i = 0; i < args && res; i++)
958+ res = parse_sym_mode_arg(argv[i], &head, &cur);
959
960 *data = head;
961
962- return 1;
963+ return res;
964 }
965
966
967 static int parse_mode_args(struct action_entry *action, int args,
968 char **argv, void **data)
969 {
970- int n, bytes;
971- unsigned int mode;
972+ int res;
973
974 if (args == 0) {
975 SYNTAX_ERROR("Mode action expects one or more arguments\n");
976 return 0;
977 }
978
979- /* octal mode number? */
980- n = sscanf(argv[0], "%o%n", &mode, &bytes);
981-
982- if(n >= 1)
983- return parse_octal_mode_args(mode, bytes, args, argv, data);
984- else
985+ res = parse_octal_mode_args(args, argv, data);
986+ if(res >= 0)
987+ /* Got an octal mode argument */
988+ return res;
989+ else /* not an octal mode argument */
990 return parse_sym_mode_args(action, args, argv, data);
991 }
992
993
994-static void mode_action(struct action *action, struct dir_ent *dir_ent)
995+static int mode_execute(struct mode_data *mode_data, int st_mode)
996 {
997- struct stat *buf = &dir_ent->inode->buf;
998- struct mode_data *mode_data = action->data;
999 int mode = 0;
1000
1001 for (;mode_data; mode_data = mode_data->next) {
1002@@ -1176,20 +1413,20 @@
1003 /* 'u', 'g' or 'o' */
1004 switch(-mode_data->mode) {
1005 case 'u':
1006- mode = (buf->st_mode >> 6) & 07;
1007+ mode = (st_mode >> 6) & 07;
1008 break;
1009 case 'g':
1010- mode = (buf->st_mode >> 3) & 07;
1011+ mode = (st_mode >> 3) & 07;
1012 break;
1013 case 'o':
1014- mode = buf->st_mode & 07;
1015+ mode = st_mode & 07;
1016 break;
1017 }
1018 mode = ((mode << 6) | (mode << 3) | mode) &
1019 mode_data->mask;
1020 } else if (mode_data->X &&
1021- ((buf->st_mode & S_IFMT) == S_IFDIR ||
1022- (buf->st_mode & 0111)))
1023+ ((st_mode & S_IFMT) == S_IFDIR ||
1024+ (st_mode & 0111)))
1025 /* X permission, only takes effect if inode is a
1026 * directory or x is set for some owner */
1027 mode = mode_data->mode | (0111 & mode_data->mask);
1028@@ -1198,18 +1435,27 @@
1029
1030 switch(mode_data->operation) {
1031 case ACTION_MODE_OCT:
1032- buf->st_mode = (buf->st_mode & ~S_IFMT) | mode;
1033+ st_mode = (st_mode & S_IFMT) | mode;
1034 break;
1035 case ACTION_MODE_SET:
1036- buf->st_mode = (buf->st_mode & ~mode_data->mask) | mode;
1037+ st_mode = (st_mode & ~mode_data->mask) | mode;
1038 break;
1039 case ACTION_MODE_ADD:
1040- buf->st_mode |= mode;
1041+ st_mode |= mode;
1042 break;
1043 case ACTION_MODE_REM:
1044- buf->st_mode &= ~mode;
1045+ st_mode &= ~mode;
1046 }
1047 }
1048+
1049+ return st_mode;
1050+}
1051+
1052+
1053+static void mode_action(struct action *action, struct dir_ent *dir_ent)
1054+{
1055+ dir_ent->inode->buf.st_mode = mode_execute(action->data,
1056+ dir_ent->inode->buf.st_mode);
1057 }
1058
1059
1060@@ -1257,7 +1503,7 @@
1061 }
1062
1063
1064-int eval_empty_actions(struct dir_ent *dir_ent)
1065+int eval_empty_actions(struct dir_info *root, struct dir_ent *dir_ent)
1066 {
1067 int i, match = 0;
1068 struct action_data action_data;
1069@@ -1271,10 +1517,12 @@
1070 return 0;
1071
1072 action_data.name = dir_ent->name;
1073- action_data.pathname = pathname(dir_ent);
1074- action_data.subpath = subpathname(dir_ent);
1075+ action_data.pathname = strdup(pathname(dir_ent));
1076+ action_data.subpath = strdup(subpathname(dir_ent));
1077 action_data.buf = &dir_ent->inode->buf;
1078 action_data.depth = dir_ent->our_dir->depth;
1079+ action_data.dir_ent = dir_ent;
1080+ action_data.root = root;
1081
1082 for (i = 0; i < empty_count && !match; i++) {
1083 data = empty_spec[i].data;
1084@@ -1297,9 +1545,12 @@
1085 (data->val == EMPTY_SOURCE && dir->excluded))
1086 continue;
1087
1088- match = eval_expr(empty_spec[i].expr, &action_data);
1089+ match = eval_expr_top(&empty_spec[i], &action_data);
1090 }
1091
1092+ free(action_data.pathname);
1093+ free(action_data.subpath);
1094+
1095 return match;
1096 }
1097
1098@@ -1510,10 +1761,12 @@
1099 struct move_ent *move = NULL;
1100
1101 action_data.name = dir_ent->name;
1102- action_data.pathname = pathname(dir_ent);
1103- action_data.subpath = subpathname(dir_ent);
1104+ action_data.pathname = strdup(pathname(dir_ent));
1105+ action_data.subpath = strdup(subpathname(dir_ent));
1106 action_data.buf = &dir_ent->inode->buf;
1107 action_data.depth = dir_ent->our_dir->depth;
1108+ action_data.dir_ent = dir_ent;
1109+ action_data.root = root;
1110
1111 /*
1112 * Evaluate each move action against the current file. For any
1113@@ -1526,7 +1779,7 @@
1114 */
1115 for (i = 0; i < move_count; i++) {
1116 struct action *action = &move_spec[i];
1117- int match = eval_expr(action->expr, &action_data);
1118+ int match = eval_expr_top(action, &action_data);
1119
1120 if(match) {
1121 if(move == NULL) {
1122@@ -1553,7 +1806,7 @@
1123 */
1124 if(move->ops == 0) {
1125 free(move);
1126- return;
1127+ goto finish;
1128 }
1129
1130 dest = (move->ops & ACTION_MOVE_MOVE) ?
1131@@ -1568,7 +1821,7 @@
1132 action_data.subpath, conf_path);
1133 free(conf_path);
1134 free(move);
1135- return;
1136+ goto finish;
1137 }
1138
1139 /*
1140@@ -1582,11 +1835,15 @@
1141 action_data.subpath, conf_path);
1142 free(conf_path);
1143 free(move);
1144- return;
1145+ goto finish;
1146 }
1147 move->next = move_list;
1148 move_list = move;
1149 }
1150+
1151+finish:
1152+ free(action_data.pathname);
1153+ free(action_data.subpath);
1154 }
1155
1156
1157@@ -1714,6 +1971,46 @@
1158
1159
1160 /*
1161+ * Prune specific action code
1162+ */
1163+int prune_actions()
1164+{
1165+ return prune_count;
1166+}
1167+
1168+
1169+int eval_prune_actions(struct dir_info *root, struct dir_ent *dir_ent)
1170+{
1171+ int i, match = 0;
1172+ struct action_data action_data;
1173+
1174+ action_data.name = dir_ent->name;
1175+ action_data.pathname = strdup(pathname(dir_ent));
1176+ action_data.subpath = strdup(subpathname(dir_ent));
1177+ action_data.buf = &dir_ent->inode->buf;
1178+ action_data.depth = dir_ent->our_dir->depth;
1179+ action_data.dir_ent = dir_ent;
1180+ action_data.root = root;
1181+
1182+ for (i = 0; i < prune_count && !match; i++)
1183+ match = eval_expr_top(&prune_spec[i], &action_data);
1184+
1185+ free(action_data.pathname);
1186+ free(action_data.subpath);
1187+
1188+ return match;
1189+}
1190+
1191+
1192+/*
1193+ * Noop specific action code
1194+ */
1195+static void noop_action(struct action *action, struct dir_ent *dir_ent)
1196+{
1197+}
1198+
1199+
1200+/*
1201 * General test evaluation code
1202 */
1203
1204@@ -1768,13 +2065,13 @@
1205 switch (end[0]) {
1206 case 'g':
1207 case 'G':
1208- *size *= 1024;
1209+ number *= 1024;
1210 case 'm':
1211 case 'M':
1212- *size *= 1024;
1213+ number *= 1024;
1214 case 'k':
1215 case 'K':
1216- *size *= 1024;
1217+ number *= 1024;
1218
1219 if (end[1] != '\0') {
1220 *error = "Trailing junk after size specifier";
1221@@ -1873,7 +2170,7 @@
1222 static int NAME##_fn(struct atom *atom, struct action_data *action_data) \
1223 { \
1224 /* test operates on MATCH file types only */ \
1225- if (!(action_data->buf->st_mode & MATCH)) \
1226+ if (!file_type_match(action_data->buf->st_mode, MATCH)) \
1227 return 0; \
1228 \
1229 CODE \
1230@@ -1992,6 +2289,12 @@
1231 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
1232 }
1233
1234+/*
1235+ * Inode attribute test operations using generic
1236+ * TEST_VAR_FN(test name, file scope, attribute name) macro.
1237+ * This is for tests that do not need to be specially handled in any way.
1238+ * They just take a variable and compare it against a number.
1239+ */
1240 TEST_VAR_FN(filesize, ACTION_REG, action_data->buf->st_size)
1241
1242 TEST_VAR_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
1243@@ -2008,9 +2311,7 @@
1244
1245 TEST_VAR_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
1246
1247-TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
1248-
1249-TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
1250+TEST_VAR_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
1251
1252 TEST_VAR_FN(depth, ACTION_ALL_LNK, action_data->depth)
1253
1254@@ -2036,6 +2337,98 @@
1255
1256 TEST_VAR_RANGE_FN(depth, ACTION_ALL_LNK, action_data->depth)
1257
1258+TEST_VAR_RANGE_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
1259+
1260+/*
1261+ * uid specific test code
1262+ */
1263+TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
1264+
1265+static int parse_uid_arg(struct test_entry *test, struct atom *atom)
1266+{
1267+ struct test_number_arg *number;
1268+ long long size;
1269+ int range;
1270+ char *error;
1271+
1272+ if(parse_number(atom->argv[0], &size, &range, &error)) {
1273+ /* managed to fully parse argument as a number */
1274+ if(size < 0 || size > (((long long) 1 << 32) - 1)) {
1275+ TEST_SYNTAX_ERROR(test, 1, "Numeric uid out of "
1276+ "range\n");
1277+ return 0;
1278+ }
1279+ } else {
1280+ /* couldn't parse (fully) as a number, is it a user name? */
1281+ struct passwd *uid = getpwnam(atom->argv[0]);
1282+ if(uid) {
1283+ size = uid->pw_uid;
1284+ range = NUM_EQ;
1285+ } else {
1286+ TEST_SYNTAX_ERROR(test, 1, "Invalid uid or unknown "
1287+ "user\n");
1288+ return 0;
1289+ }
1290+ }
1291+
1292+ number = malloc(sizeof(*number));
1293+ if(number == NULL)
1294+ MEM_ERROR();
1295+
1296+ number->range = range;
1297+ number->size= size;
1298+
1299+ atom->data = number;
1300+
1301+ return 1;
1302+}
1303+
1304+
1305+/*
1306+ * gid specific test code
1307+ */
1308+TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
1309+
1310+static int parse_gid_arg(struct test_entry *test, struct atom *atom)
1311+{
1312+ struct test_number_arg *number;
1313+ long long size;
1314+ int range;
1315+ char *error;
1316+
1317+ if(parse_number(atom->argv[0], &size, &range, &error)) {
1318+ /* managed to fully parse argument as a number */
1319+ if(size < 0 || size > (((long long) 1 << 32) - 1)) {
1320+ TEST_SYNTAX_ERROR(test, 1, "Numeric gid out of "
1321+ "range\n");
1322+ return 0;
1323+ }
1324+ } else {
1325+ /* couldn't parse (fully) as a number, is it a group name? */
1326+ struct group *gid = getgrnam(atom->argv[0]);
1327+ if(gid) {
1328+ size = gid->gr_gid;
1329+ range = NUM_EQ;
1330+ } else {
1331+ TEST_SYNTAX_ERROR(test, 1, "Invalid gid or unknown "
1332+ "group\n");
1333+ return 0;
1334+ }
1335+ }
1336+
1337+ number = malloc(sizeof(*number));
1338+ if(number == NULL)
1339+ MEM_ERROR();
1340+
1341+ number->range = range;
1342+ number->size= size;
1343+
1344+ atom->data = number;
1345+
1346+ return 1;
1347+}
1348+
1349+
1350 /*
1351 * Type test specific code
1352 */
1353@@ -2116,6 +2509,7 @@
1354 char str[1024]; /* overflow safe */
1355
1356 regerror(res, preg, str, 1024);
1357+ free(preg);
1358 TEST_SYNTAX_ERROR(test, 0, "invalid regex \"%s\" because "
1359 "\"%s\"\n", atom->argv[0], str);
1360 return 0;
1361@@ -2265,37 +2659,583 @@
1362 }
1363
1364
1365+/*
1366+ * Symbolic link specific test code
1367+ */
1368+
1369+/*
1370+ * Walk the supplied pathname and return the directory entry corresponding
1371+ * to the pathname. If any symlinks are encountered whilst walking the
1372+ * pathname, then recursively walk these, to obtain the fully
1373+ * dereferenced canonicalised directory entry.
1374+ *
1375+ * If follow_path fails to walk a pathname either because a component
1376+ * doesn't exist, it is a non directory component when a directory
1377+ * component is expected, a symlink with an absolute path is encountered,
1378+ * or a symlink is encountered which cannot be recursively walked due to
1379+ * the above failures, then return NULL.
1380+ */
1381+static struct dir_ent *follow_path(struct dir_info *dir, char *pathname)
1382+{
1383+ char *comp, *path = pathname;
1384+ struct dir_ent *dir_ent = NULL;
1385+
1386+ /* We cannot follow absolute paths */
1387+ if(pathname[0] == '/')
1388+ return NULL;
1389+
1390+ for(comp = get_comp(&path); comp; free(comp), comp = get_comp(&path)) {
1391+ if(strcmp(comp, ".") == 0)
1392+ continue;
1393+
1394+ if(strcmp(comp, "..") == 0) {
1395+ /* Move to parent if we're not in the root directory */
1396+ if(dir->depth > 1) {
1397+ dir = dir->dir_ent->our_dir;
1398+ dir_ent = NULL; /* lazily eval at loop exit */
1399+ continue;
1400+ } else
1401+ /* Failed to walk pathname */
1402+ return NULL;
1403+ }
1404+
1405+ /* Lookup comp in current directory */
1406+ dir_ent = lookup_comp(comp, dir);
1407+ if(dir_ent == NULL)
1408+ /* Doesn't exist, failed to walk pathname */
1409+ return NULL;
1410+
1411+ if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFLNK) {
1412+ /* Symbolic link, try to walk it */
1413+ dir_ent = follow_path(dir, dir_ent->inode->symlink);
1414+ if(dir_ent == NULL)
1415+ /* Failed to follow symlink */
1416+ return NULL;
1417+ }
1418+
1419+ if((dir_ent->inode->buf.st_mode & S_IFMT) != S_IFDIR)
1420+ /* Cannot walk further */
1421+ break;
1422+
1423+ dir = dir_ent->dir;
1424+ }
1425+
1426+ /* We will have exited the loop either because we've processed
1427+ * all the components, which means we've successfully walked the
1428+ * pathname, or because we've hit a non-directory, in which case
1429+ * it's success if this is the leaf component */
1430+ if(comp) {
1431+ free(comp);
1432+ comp = get_comp(&path);
1433+ free(comp);
1434+ if(comp != NULL)
1435+ /* Not a leaf component */
1436+ return NULL;
1437+ } else {
1438+ /* Fully walked pathname, dir_ent contains correct value unless
1439+ * we've walked to the parent ("..") in which case we need
1440+ * to resolve it here */
1441+ if(!dir_ent)
1442+ dir_ent = dir->dir_ent;
1443+ }
1444+
1445+ return dir_ent;
1446+}
1447+
1448+
1449+static int exists_fn(struct atom *atom, struct action_data *action_data)
1450+{
1451+ /*
1452+ * Test if a symlink exists within the output filesystem, that is,
1453+ * the symlink has a relative path, and the relative path refers
1454+ * to an entry within the output filesystem.
1455+ *
1456+ * This test function evaluates the path for symlinks - that is it
1457+ * follows any symlinks in the path (and any symlinks that it contains
1458+ * etc.), to discover the fully dereferenced canonicalised relative
1459+ * path.
1460+ *
1461+ * If any symlinks within the path do not exist or are absolute
1462+ * then the symlink is considered to not exist, as it cannot be
1463+ * fully dereferenced.
1464+ *
1465+ * exists operates on symlinks only, other files by definition
1466+ * exist
1467+ */
1468+ if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
1469+ return 1;
1470+
1471+ /* dereference the symlink, and return TRUE if it exists */
1472+ return follow_path(action_data->dir_ent->our_dir,
1473+ action_data->dir_ent->inode->symlink) ? 1 : 0;
1474+}
1475+
1476+
1477+static int absolute_fn(struct atom *atom, struct action_data *action_data)
1478+{
1479+ /*
1480+ * Test if a symlink has an absolute path, which by definition
1481+ * means the symbolic link may be broken (even if the absolute path
1482+ * does point into the filesystem being squashed, because the resultant
1483+ * filesystem can be mounted/unsquashed anywhere, it is unlikely the
1484+ * absolute path will still point to the right place). If you know that
1485+ * an absolute symlink will point to the right place then you don't need
1486+ * to use this function, and/or these symlinks can be excluded by
1487+ * use of other test operators.
1488+ *
1489+ * absolute operates on symlinks only, other files by definition
1490+ * don't have problems
1491+ */
1492+ if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
1493+ return 0;
1494+
1495+ return action_data->dir_ent->inode->symlink[0] == '/';
1496+}
1497+
1498+
1499+static int parse_expr_argX(struct test_entry *test, struct atom *atom,
1500+ int argno)
1501+{
1502+ /* Call parse_expr to parse argument, which should be an expression */
1503+
1504+ /* save the current parser state */
1505+ char *save_cur_ptr = cur_ptr;
1506+ char *save_source = source;
1507+
1508+ cur_ptr = source = atom->argv[argno];
1509+ atom->data = parse_expr(0);
1510+
1511+ cur_ptr = save_cur_ptr;
1512+ source = save_source;
1513+
1514+ if(atom->data == NULL) {
1515+ /* parse_expr(0) will have reported the exact syntax error,
1516+ * but, because we recursively evaluated the expression, it
1517+ * will have been reported without the context of the stat
1518+ * test(). So here additionally report our failure to parse
1519+ * the expression in the stat() test to give context */
1520+ TEST_SYNTAX_ERROR(test, 0, "Failed to parse expression\n");
1521+ return 0;
1522+ }
1523+
1524+ return 1;
1525+}
1526+
1527+
1528+static int parse_expr_arg0(struct test_entry *test, struct atom *atom)
1529+{
1530+ return parse_expr_argX(test, atom, 0);
1531+}
1532+
1533+
1534+static int parse_expr_arg1(struct test_entry *test, struct atom *atom)
1535+{
1536+ return parse_expr_argX(test, atom, 1);
1537+}
1538+
1539+
1540+static int stat_fn(struct atom *atom, struct action_data *action_data)
1541+{
1542+ struct stat buf;
1543+ struct action_data eval_action;
1544+ int match, res;
1545+
1546+ /* evaluate the expression using the context of the inode
1547+ * pointed to by the symlink. This allows the inode attributes
1548+ * of the file pointed to by the symlink to be evaluated, rather
1549+ * than the symlink itself.
1550+ *
1551+ * Note, stat() deliberately does not evaluate the pathname, name or
1552+ * depth of the symlink, these are left with the symlink values.
1553+ * This allows stat() to be used on any symlink, rather than
1554+ * just symlinks which are contained (if the symlink is *not*
1555+ * contained then pathname, name and depth are meaningless as they
1556+ * are relative to the filesystem being squashed). */
1557+
1558+ /* if this isn't a symlink then stat will just return the current
1559+ * information, i.e. stat(expr) == expr. This is harmless and
1560+ * is better than returning TRUE or FALSE in a non symlink case */
1561+ res = stat(action_data->pathname, &buf);
1562+ if(res == -1) {
1563+ if(expr_log_cmnd(LOG_ENABLED)) {
1564+ expr_log(atom->test->name);
1565+ expr_log("(");
1566+ expr_log_match(0);
1567+ expr_log(")");
1568+ }
1569+ return 0;
1570+ }
1571+
1572+ /* fill in the inode values of the file pointed to by the
1573+ * symlink, but, leave everything else the same */
1574+ memcpy(&eval_action, action_data, sizeof(struct action_data));
1575+ eval_action.buf = &buf;
1576+
1577+ if(expr_log_cmnd(LOG_ENABLED)) {
1578+ expr_log(atom->test->name);
1579+ expr_log("(");
1580+ match = eval_expr_log(atom->data, &eval_action);
1581+ expr_log(")");
1582+ } else
1583+ match = eval_expr(atom->data, &eval_action);
1584+
1585+ return match;
1586+}
1587+
1588+
1589+static int readlink_fn(struct atom *atom, struct action_data *action_data)
1590+{
1591+ int match = 0;
1592+ struct dir_ent *dir_ent;
1593+ struct action_data eval_action;
1594+
1595+ /* Dereference the symlink and evaluate the expression in the
1596+ * context of the file pointed to by the symlink.
1597+ * All attributes are updated to refer to the file that is pointed to.
1598+ * Thus the inode attributes, pathname, name and depth all refer to
1599+ * the dereferenced file, and not the symlink.
1600+ *
1601+ * If the symlink cannot be dereferenced because it doesn't exist in
1602+ * the output filesystem, or due to some other failure to
1603+ * walk the pathname (see follow_path above), then FALSE is returned.
1604+ *
1605+ * If you wish to evaluate the inode attributes of symlinks which
1606+ * exist in the source filestem (but not in the output filesystem then
1607+ * use stat instead (see above).
1608+ *
1609+ * readlink operates on symlinks only */
1610+ if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
1611+ goto finish;
1612+
1613+ /* dereference the symlink, and get the directory entry it points to */
1614+ dir_ent = follow_path(action_data->dir_ent->our_dir,
1615+ action_data->dir_ent->inode->symlink);
1616+ if(dir_ent == NULL)
1617+ goto finish;
1618+
1619+ eval_action.name = dir_ent->name;
1620+ eval_action.pathname = strdup(pathname(dir_ent));
1621+ eval_action.subpath = strdup(subpathname(dir_ent));
1622+ eval_action.buf = &dir_ent->inode->buf;
1623+ eval_action.depth = dir_ent->our_dir->depth;
1624+ eval_action.dir_ent = dir_ent;
1625+ eval_action.root = action_data->root;
1626+
1627+ if(expr_log_cmnd(LOG_ENABLED)) {
1628+ expr_log(atom->test->name);
1629+ expr_log("(");
1630+ match = eval_expr_log(atom->data, &eval_action);
1631+ expr_log(")");
1632+ } else
1633+ match = eval_expr(atom->data, &eval_action);
1634+
1635+ free(eval_action.pathname);
1636+ free(eval_action.subpath);
1637+
1638+ return match;
1639+
1640+finish:
1641+ if(expr_log_cmnd(LOG_ENABLED)) {
1642+ expr_log(atom->test->name);
1643+ expr_log("(");
1644+ expr_log_match(0);
1645+ expr_log(")");
1646+ }
1647+
1648+ return 0;
1649+}
1650+
1651+
1652+static int eval_fn(struct atom *atom, struct action_data *action_data)
1653+{
1654+ int match;
1655+ char *path = atom->argv[0];
1656+ struct dir_ent *dir_ent = action_data->dir_ent;
1657+ struct stat *buf = action_data->buf;
1658+ struct action_data eval_action;
1659+
1660+ /* Follow path (arg1) and evaluate the expression (arg2)
1661+ * in the context of the file discovered. All attributes are updated
1662+ * to refer to the file that is pointed to.
1663+ *
1664+ * This test operation allows you to add additional context to the
1665+ * evaluation of the file being scanned, such as "if current file is
1666+ * XXX and the parent is YYY, then ..." Often times you need or
1667+ * want to test a combination of file status
1668+ *
1669+ * If the file referenced by the path does not exist in
1670+ * the output filesystem, or some other failure is experienced in
1671+ * walking the path (see follow_path above), then FALSE is returned.
1672+ *
1673+ * If you wish to evaluate the inode attributes of files which
1674+ * exist in the source filestem (but not in the output filesystem then
1675+ * use stat instead (see above). */
1676+
1677+ /* try to follow path, and get the directory entry it points to */
1678+ if(path[0] == '/') {
1679+ /* absolute, walk from root - first skip the leading / */
1680+ while(path[0] == '/')
1681+ path ++;
1682+ if(path[0] == '\0')
1683+ dir_ent = action_data->root->dir_ent;
1684+ else
1685+ dir_ent = follow_path(action_data->root, path);
1686+ } else {
1687+ /* relative, if first component is ".." walk from parent,
1688+ * otherwise walk from dir_ent.
1689+ * Note: this has to be handled here because follow_path
1690+ * will quite correctly refuse to execute ".." on anything
1691+ * which isn't a directory */
1692+ if(strncmp(path, "..", 2) == 0 && (path[2] == '\0' ||
1693+ path[2] == '/')) {
1694+ /* walk from parent */
1695+ path += 2;
1696+ while(path[0] == '/')
1697+ path ++;
1698+ if(path[0] == '\0')
1699+ dir_ent = dir_ent->our_dir->dir_ent;
1700+ else
1701+ dir_ent = follow_path(dir_ent->our_dir, path);
1702+ } else if(!file_type_match(buf->st_mode, ACTION_DIR))
1703+ dir_ent = NULL;
1704+ else
1705+ dir_ent = follow_path(dir_ent->dir, path);
1706+ }
1707+
1708+ if(dir_ent == NULL) {
1709+ if(expr_log_cmnd(LOG_ENABLED)) {
1710+ expr_log(atom->test->name);
1711+ expr_log("(");
1712+ expr_log(atom->argv[0]);
1713+ expr_log(",");
1714+ expr_log_match(0);
1715+ expr_log(")");
1716+ }
1717+
1718+ return 0;
1719+ }
1720+
1721+ eval_action.name = dir_ent->name;
1722+ eval_action.pathname = strdup(pathname(dir_ent));
1723+ eval_action.subpath = strdup(subpathname(dir_ent));
1724+ eval_action.buf = &dir_ent->inode->buf;
1725+ eval_action.depth = dir_ent->our_dir->depth;
1726+ eval_action.dir_ent = dir_ent;
1727+ eval_action.root = action_data->root;
1728+
1729+ if(expr_log_cmnd(LOG_ENABLED)) {
1730+ expr_log(atom->test->name);
1731+ expr_log("(");
1732+ expr_log(eval_action.subpath);
1733+ expr_log(",");
1734+ match = eval_expr_log(atom->data, &eval_action);
1735+ expr_log(")");
1736+ } else
1737+ match = eval_expr(atom->data, &eval_action);
1738+
1739+ free(eval_action.pathname);
1740+ free(eval_action.subpath);
1741+
1742+ return match;
1743+}
1744+
1745+
1746+/*
1747+ * Perm specific test code
1748+ */
1749+static int parse_perm_args(struct test_entry *test, struct atom *atom)
1750+{
1751+ int res = 1, mode, op, i;
1752+ char *arg;
1753+ struct mode_data *head = NULL, *cur = NULL;
1754+ struct perm_data *perm_data;
1755+
1756+ if(atom->args == 0) {
1757+ TEST_SYNTAX_ERROR(test, 0, "One or more arguments expected\n");
1758+ return 0;
1759+ }
1760+
1761+ switch(atom->argv[0][0]) {
1762+ case '-':
1763+ op = PERM_ALL;
1764+ arg = atom->argv[0] + 1;
1765+ break;
1766+ case '/':
1767+ op = PERM_ANY;
1768+ arg = atom->argv[0] + 1;
1769+ break;
1770+ default:
1771+ op = PERM_EXACT;
1772+ arg = atom->argv[0];
1773+ break;
1774+ }
1775+
1776+ /* try to parse as an octal number */
1777+ res = parse_octal_mode_args(atom->args, atom->argv, (void **) &head);
1778+ if(res == -1) {
1779+ /* parse as sym mode argument */
1780+ for(i = 0; i < atom->args && res; i++, arg = atom->argv[i])
1781+ res = parse_sym_mode_arg(arg, &head, &cur);
1782+ }
1783+
1784+ if (res == 0)
1785+ goto finish;
1786+
1787+ /*
1788+ * Evaluate the symbolic mode against a permission of 0000 octal
1789+ */
1790+ mode = mode_execute(head, 0);
1791+
1792+ perm_data = malloc(sizeof(struct perm_data));
1793+ if (perm_data == NULL)
1794+ MEM_ERROR();
1795+
1796+ perm_data->op = op;
1797+ perm_data->mode = mode;
1798+
1799+ atom->data = perm_data;
1800+
1801+finish:
1802+ while(head) {
1803+ struct mode_data *tmp = head;
1804+ head = head->next;
1805+ free(tmp);
1806+ }
1807+
1808+ return res;
1809+}
1810+
1811+
1812+static int perm_fn(struct atom *atom, struct action_data *action_data)
1813+{
1814+ struct perm_data *perm_data = atom->data;
1815+ struct stat *buf = action_data->buf;
1816+
1817+ switch(perm_data->op) {
1818+ case PERM_EXACT:
1819+ return (buf->st_mode & ~S_IFMT) == perm_data->mode;
1820+ case PERM_ALL:
1821+ return (buf->st_mode & perm_data->mode) == perm_data->mode;
1822+ case PERM_ANY:
1823+ default:
1824+ /*
1825+ * if no permission bits are set in perm_data->mode match
1826+ * on any file, this is to be consistent with find, which
1827+ * does this to be consistent with the behaviour of
1828+ * -perm -000
1829+ */
1830+ return perm_data->mode == 0 || (buf->st_mode & perm_data->mode);
1831+ }
1832+}
1833+
1834+
1835+#ifdef SQUASHFS_TRACE
1836+static void dump_parse_tree(struct expr *expr)
1837+{
1838+ int i;
1839+
1840+ if(expr->type == ATOM_TYPE) {
1841+ printf("%s", expr->atom.test->name);
1842+ if(expr->atom.args) {
1843+ printf("(");
1844+ for(i = 0; i < expr->atom.args; i++) {
1845+ printf("%s", expr->atom.argv[i]);
1846+ if (i + 1 < expr->atom.args)
1847+ printf(",");
1848+ }
1849+ printf(")");
1850+ }
1851+ } else if (expr->type == UNARY_TYPE) {
1852+ printf("%s", token_table[expr->unary_op.op].string);
1853+ dump_parse_tree(expr->unary_op.expr);
1854+ } else {
1855+ printf("(");
1856+ dump_parse_tree(expr->expr_op.lhs);
1857+ printf("%s", token_table[expr->expr_op.op].string);
1858+ dump_parse_tree(expr->expr_op.rhs);
1859+ printf(")");
1860+ }
1861+}
1862+
1863+
1864+void dump_action_list(struct action *spec_list, int spec_count)
1865+{
1866+ int i;
1867+
1868+ for (i = 0; i < spec_count; i++) {
1869+ printf("%s", spec_list[i].action->name);
1870+ if (spec_list[i].args) {
1871+ int n;
1872+
1873+ printf("(");
1874+ for (n = 0; n < spec_list[i].args; n++) {
1875+ printf("%s", spec_list[i].argv[n]);
1876+ if (n + 1 < spec_list[i].args)
1877+ printf(",");
1878+ }
1879+ printf(")");
1880+ }
1881+ printf("=");
1882+ dump_parse_tree(spec_list[i].expr);
1883+ printf("\n");
1884+ }
1885+}
1886+
1887+
1888+void dump_actions()
1889+{
1890+ dump_action_list(exclude_spec, exclude_count);
1891+ dump_action_list(fragment_spec, fragment_count);
1892+ dump_action_list(other_spec, other_count);
1893+ dump_action_list(move_spec, move_count);
1894+ dump_action_list(empty_spec, empty_count);
1895+}
1896+#else
1897+void dump_actions()
1898+{
1899+}
1900+#endif
1901+
1902+
1903 static struct test_entry test_table[] = {
1904- { "name", 1, name_fn},
1905- { "pathname", 1, pathname_fn, check_pathname},
1906- { "subpathname", 1, subpathname_fn, check_pathname},
1907- { "filesize", 1, filesize_fn, parse_number_arg},
1908- { "dirsize", 1, dirsize_fn, parse_number_arg},
1909- { "size", 1, size_fn, parse_number_arg},
1910- { "inode", 1, inode_fn, parse_number_arg},
1911- { "nlink", 1, nlink_fn, parse_number_arg},
1912- { "fileblocks", 1, fileblocks_fn, parse_number_arg},
1913- { "dirblocks", 1, dirblocks_fn, parse_number_arg},
1914- { "blocks", 1, blocks_fn, parse_number_arg},
1915- { "gid", 1, gid_fn, parse_number_arg},
1916- { "uid", 1, uid_fn, parse_number_arg},
1917- { "depth", 1, depth_fn, parse_number_arg},
1918- { "filesize_range", 2, filesize_range_fn, parse_range_args},
1919- { "dirsize_range", 2, dirsize_range_fn, parse_range_args},
1920- { "size_range", 2, size_range_fn, parse_range_args},
1921- { "inode_range", 2, inode_range_fn, parse_range_args},
1922- { "nlink_range", 2, nlink_range_fn, parse_range_args},
1923- { "fileblocks_range", 2, fileblocks_range_fn, parse_range_args},
1924- { "dirblocks_range", 2, dirblocks_range_fn, parse_range_args},
1925- { "blocks_range", 2, blocks_range_fn, parse_range_args},
1926- { "gid_range", 2, gid_range_fn, parse_range_args},
1927- { "uid_range", 2, uid_range_fn, parse_range_args},
1928- { "depth_range", 2, depth_range_fn, parse_range_args},
1929- { "type", 1, type_fn, parse_type_arg},
1930- { "true", 0, true_fn, NULL},
1931- { "false", 0, false_fn, NULL},
1932- { "file", 1, file_fn, parse_file_arg},
1933- { "exec", 1, exec_fn, NULL},
1934+ { "name", 1, name_fn, NULL, 1},
1935+ { "pathname", 1, pathname_fn, check_pathname, 1, 0},
1936+ { "subpathname", 1, subpathname_fn, check_pathname, 1, 0},
1937+ { "filesize", 1, filesize_fn, parse_number_arg, 1, 0},
1938+ { "dirsize", 1, dirsize_fn, parse_number_arg, 1, 0},
1939+ { "size", 1, size_fn, parse_number_arg, 1, 0},
1940+ { "inode", 1, inode_fn, parse_number_arg, 1, 0},
1941+ { "nlink", 1, nlink_fn, parse_number_arg, 1, 0},
1942+ { "fileblocks", 1, fileblocks_fn, parse_number_arg, 1, 0},
1943+ { "dirblocks", 1, dirblocks_fn, parse_number_arg, 1, 0},
1944+ { "blocks", 1, blocks_fn, parse_number_arg, 1, 0},
1945+ { "gid", 1, gid_fn, parse_gid_arg, 1, 0},
1946+ { "uid", 1, uid_fn, parse_uid_arg, 1, 0},
1947+ { "depth", 1, depth_fn, parse_number_arg, 1, 0},
1948+ { "dircount", 1, dircount_fn, parse_number_arg, 0, 0},
1949+ { "filesize_range", 2, filesize_range_fn, parse_range_args, 1, 0},
1950+ { "dirsize_range", 2, dirsize_range_fn, parse_range_args, 1, 0},
1951+ { "size_range", 2, size_range_fn, parse_range_args, 1, 0},
1952+ { "inode_range", 2, inode_range_fn, parse_range_args, 1, 0},
1953+ { "nlink_range", 2, nlink_range_fn, parse_range_args, 1, 0},
1954+ { "fileblocks_range", 2, fileblocks_range_fn, parse_range_args, 1, 0},
1955+ { "dirblocks_range", 2, dirblocks_range_fn, parse_range_args, 1, 0},
1956+ { "blocks_range", 2, blocks_range_fn, parse_range_args, 1, 0},
1957+ { "gid_range", 2, gid_range_fn, parse_range_args, 1, 0},
1958+ { "uid_range", 2, uid_range_fn, parse_range_args, 1, 0},
1959+ { "depth_range", 2, depth_range_fn, parse_range_args, 1, 0},
1960+ { "dircount_range", 2, dircount_range_fn, parse_range_args, 0, 0},
1961+ { "type", 1, type_fn, parse_type_arg, 1, 0},
1962+ { "true", 0, true_fn, NULL, 1, 0},
1963+ { "false", 0, false_fn, NULL, 1, 0},
1964+ { "file", 1, file_fn, parse_file_arg, 1, 0},
1965+ { "exec", 1, exec_fn, NULL, 1, 0},
1966+ { "exists", 0, exists_fn, NULL, 0, 0},
1967+ { "absolute", 0, absolute_fn, NULL, 0, 0},
1968+ { "stat", 1, stat_fn, parse_expr_arg0, 1, 1},
1969+ { "readlink", 1, readlink_fn, parse_expr_arg0, 0, 1},
1970+ { "eval", 2, eval_fn, parse_expr_arg1, 0, 1},
1971+ { "perm", -2, perm_fn, parse_perm_args, 1, 0},
1972 { "", -1 }
1973 };
1974
1975@@ -2318,6 +3258,9 @@
1976 { "guid", GUID_ACTION, 2, ACTION_ALL_LNK, parse_guid_args, guid_action},
1977 { "mode", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
1978 { "empty", EMPTY_ACTION, -2, ACTION_DIR, parse_empty_args, NULL},
1979- { "move", MOVE_ACTION, -2, ACTION_ALL_LNK, NULL, NULL},
1980+ { "move", MOVE_ACTION, 1, ACTION_ALL_LNK, NULL, NULL},
1981+ { "prune", PRUNE_ACTION, 0, ACTION_ALL_LNK, NULL, NULL},
1982+ { "chmod", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
1983+ { "noop", NOOP_ACTION, 0, ACTION_ALL, NULL, noop_action },
1984 { "", 0, -1, 0, NULL, NULL}
1985 };
1986diff -Nru squashfs-tools-4.2+20130409/action.h squashfs-tools-4.3+20140919/action.h
1987--- squashfs-tools-4.2+20130409/action.h 2013-05-09 10:39:11.000000000 +0200
1988+++ squashfs-tools-4.3+20140919/action.h 2015-07-20 21:03:05.000000000 +0200
1989@@ -1,8 +1,10 @@
1990+#ifndef ACTION_H
1991+#define ACTION_H
1992 /*
1993 * Create a squashfs filesystem. This is a highly compressed read only
1994 * filesystem.
1995 *
1996- * Copyright (c) 2011, 2012, 2013
1997+ * Copyright (c) 2011, 2012, 2013, 2014
1998 * Phillip Lougher <phillip@squashfs.org.uk>
1999 *
2000 * This program is free software; you can redistribute it and/or
2001@@ -72,6 +74,7 @@
2002 fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
2003 fprintf(stderr, "Syntax error: "S, ##ARGS); \
2004 fprintf(stderr, "Got here \"%s\"\n", src); \
2005+ free(src); \
2006 }
2007
2008 #define TEST_SYNTAX_ERROR(TEST, ARG, S, ARGS...) { \
2009@@ -81,6 +84,7 @@
2010 fprintf(stderr, "Syntax error in \"%s()\", arg %d: "S, TEST->name, \
2011 ARG, ##ARGS); \
2012 fprintf(stderr, "Got here \"%s\"\n", src); \
2013+ free(src); \
2014 }
2015
2016 struct expr;
2017@@ -94,6 +98,7 @@
2018
2019 struct atom {
2020 struct test_entry *test;
2021+ int args;
2022 char **argv;
2023 void *data;
2024 };
2025@@ -139,6 +144,8 @@
2026 int args;
2027 int (*fn)(struct atom *, struct action_data *);
2028 int (*parse_args)(struct test_entry *, struct atom *);
2029+ int exclude_ok;
2030+ int handle_logging;
2031 };
2032
2033
2034@@ -168,15 +175,28 @@
2035 #define MODE_ACTION 11
2036 #define EMPTY_ACTION 12
2037 #define MOVE_ACTION 13
2038+#define PRUNE_ACTION 14
2039+#define NOOP_ACTION 15
2040
2041 /*
2042 * Define what file types each action operates over
2043 */
2044-#define ACTION_DIR S_IFDIR
2045-#define ACTION_REG S_IFREG
2046-#define ACTION_ALL_LNK (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | \
2047- S_IFIFO | S_IFLNK)
2048-#define ACTION_ALL (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | S_IFIFO)
2049+#define ACTION_DIR 1
2050+#define ACTION_REG 2
2051+#define ACTION_ALL_LNK 3
2052+#define ACTION_ALL 4
2053+#define ACTION_LNK 5
2054+
2055+
2056+/*
2057+ * Action logging requested, specified by the various
2058+ * -action, -true-action, -false-action and -verbose-action
2059+ * options
2060+ */
2061+#define ACTION_LOG_NONE 0
2062+#define ACTION_LOG_TRUE 1
2063+#define ACTION_LOG_FALSE 2
2064+#define ACTION_LOG_VERBOSE ACTION_LOG_TRUE | ACTION_LOG_FALSE
2065
2066 struct action_entry {
2067 char *name;
2068@@ -194,6 +214,8 @@
2069 char *pathname;
2070 char *subpath;
2071 struct stat *buf;
2072+ struct dir_ent *dir_ent;
2073+ struct dir_info *root;
2074 };
2075
2076
2077@@ -204,6 +226,7 @@
2078 char **argv;
2079 struct expr *expr;
2080 void *data;
2081+ int verbose;
2082 };
2083
2084
2085@@ -269,20 +292,37 @@
2086
2087
2088 /*
2089+ * Perm test function specific definitions
2090+ */
2091+#define PERM_ALL 1
2092+#define PERM_ANY 2
2093+#define PERM_EXACT 3
2094+
2095+struct perm_data {
2096+ int op;
2097+ int mode;
2098+};
2099+
2100+
2101+/*
2102 * External function definitions
2103 */
2104-extern int parse_action(char *);
2105+extern int parse_action(char *, int verbose);
2106 extern void dump_actions();
2107-extern void *eval_frag_actions(struct dir_ent *);
2108+extern void *eval_frag_actions(struct dir_info *, struct dir_ent *);
2109 extern void *get_frag_action(void *);
2110-extern int eval_exclude_actions(char *, char *, char *, struct stat *, int);
2111-extern void eval_actions(struct dir_ent *);
2112-extern int eval_empty_actions(struct dir_ent *dir_ent);
2113+extern int eval_exclude_actions(char *, char *, char *, struct stat *, int,
2114+ struct dir_ent *);
2115+extern void eval_actions(struct dir_info *, struct dir_ent *);
2116+extern int eval_empty_actions(struct dir_info *, struct dir_ent *dir_ent);
2117 extern void eval_move_actions(struct dir_info *, struct dir_ent *);
2118+extern int eval_prune_actions(struct dir_info *, struct dir_ent *);
2119 extern void do_move_actions();
2120 extern int read_bytes(int, void *, int);
2121 extern int actions();
2122 extern int move_actions();
2123 extern int empty_actions();
2124-extern int read_action_file(char *);
2125+extern int read_action_file(char *, int);
2126 extern int exclude_actions();
2127+extern int prune_actions();
2128+#endif
2129diff -Nru squashfs-tools-4.2+20130409/caches-queues-lists.c squashfs-tools-4.3+20140919/caches-queues-lists.c
2130--- squashfs-tools-4.2+20130409/caches-queues-lists.c 2013-05-09 10:39:11.000000000 +0200
2131+++ squashfs-tools-4.3+20140919/caches-queues-lists.c 2015-07-20 21:03:05.000000000 +0200
2132@@ -2,7 +2,7 @@
2133 * Create a squashfs filesystem. This is a highly compressed read only
2134 * filesystem.
2135 *
2136- * Copyright (c) 2013
2137+ * Copyright (c) 2013, 2014
2138 * Phillip Lougher <phillip@squashfs.org.uk>
2139 *
2140 * This program is free software; you can redistribute it and/or
2141@@ -25,12 +25,11 @@
2142 #include <pthread.h>
2143 #include <stdlib.h>
2144 #include <string.h>
2145+#include <stdio.h>
2146
2147 #include "error.h"
2148 #include "caches-queues-lists.h"
2149
2150-int first_freelist = 1;
2151-
2152 extern int add_overflow(int, int);
2153 extern int multiply_overflow(int, int);
2154
2155@@ -98,37 +97,182 @@
2156 }
2157
2158
2159-#define CALCULATE_HASH(start) (start & 0xffff) \
2160+int queue_empty(struct queue *queue)
2161+{
2162+ int empty;
2163
2164+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2165+ pthread_mutex_lock(&queue->mutex);
2166
2167-/* Called with the cache mutex held */
2168-void insert_hash_table(struct cache *cache, struct file_buffer *entry)
2169+ empty = queue->readp == queue->writep;
2170+
2171+ pthread_cleanup_pop(1);
2172+
2173+ return empty;
2174+}
2175+
2176+
2177+void queue_flush(struct queue *queue)
2178+{
2179+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2180+ pthread_mutex_lock(&queue->mutex);
2181+
2182+ queue->readp = queue->writep;
2183+
2184+ pthread_cleanup_pop(1);
2185+}
2186+
2187+
2188+void dump_queue(struct queue *queue)
2189 {
2190- int hash = CALCULATE_HASH(entry->index);
2191+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2192+ pthread_mutex_lock(&queue->mutex);
2193+
2194+ printf("\tMax size %d, size %d%s\n", queue->size - 1,
2195+ queue->readp <= queue->writep ? queue->writep - queue->readp :
2196+ queue->size - queue->readp + queue->writep,
2197+ queue->readp == queue->writep ? " (EMPTY)" :
2198+ ((queue->writep + 1) % queue->size) == queue->readp ?
2199+ " (FULL)" : "");
2200
2201- entry->hash_next = cache->hash_table[hash];
2202- cache->hash_table[hash] = entry;
2203- entry->hash_prev = NULL;
2204- if(entry->hash_next)
2205- entry->hash_next->hash_prev = entry;
2206+ pthread_cleanup_pop(1);
2207 }
2208
2209
2210+/* define seq queue hash tables */
2211+#define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N)
2212+
2213+/* Called with the seq queue mutex held */
2214+INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq)
2215+
2216 /* Called with the cache mutex held */
2217-void remove_hash_table(struct cache *cache, struct file_buffer *entry)
2218+REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq);
2219+
2220+static unsigned int sequence = 0;
2221+
2222+
2223+struct seq_queue *seq_queue_init()
2224+{
2225+ struct seq_queue *queue = malloc(sizeof(struct seq_queue));
2226+ if(queue == NULL)
2227+ MEM_ERROR();
2228+
2229+ memset(queue, 0, sizeof(struct seq_queue));
2230+
2231+ pthread_mutex_init(&queue->mutex, NULL);
2232+ pthread_cond_init(&queue->wait, NULL);
2233+
2234+ return queue;
2235+}
2236+
2237+
2238+void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry)
2239 {
2240- if(entry->hash_prev)
2241- entry->hash_prev->hash_next = entry->hash_next;
2242+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2243+ pthread_mutex_lock(&queue->mutex);
2244+
2245+ insert_seq_hash_table(queue, entry);
2246+
2247+ if(entry->fragment)
2248+ queue->fragment_count ++;
2249 else
2250- cache->hash_table[CALCULATE_HASH(entry->index)] =
2251- entry->hash_next;
2252- if(entry->hash_next)
2253- entry->hash_next->hash_prev = entry->hash_prev;
2254+ queue->block_count ++;
2255+
2256+ if(entry->sequence == sequence)
2257+ pthread_cond_signal(&queue->wait);
2258
2259- entry->hash_prev = entry->hash_next = NULL;
2260+ pthread_cleanup_pop(1);
2261 }
2262
2263
2264+struct file_buffer *seq_queue_get(struct seq_queue *queue)
2265+{
2266+ /*
2267+ * Look-up buffer matching sequence in the queue, if found return
2268+ * it, otherwise wait until it arrives
2269+ */
2270+ int hash = CALCULATE_SEQ_HASH(sequence);
2271+ struct file_buffer *entry;
2272+
2273+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2274+ pthread_mutex_lock(&queue->mutex);
2275+
2276+ while(1) {
2277+ for(entry = queue->hash_table[hash]; entry;
2278+ entry = entry->seq_next)
2279+ if(entry->sequence == sequence)
2280+ break;
2281+
2282+ if(entry) {
2283+ /*
2284+ * found the buffer in the queue, decrement the
2285+ * appropriate count, and remove from hash list
2286+ */
2287+ if(entry->fragment)
2288+ queue->fragment_count --;
2289+ else
2290+ queue->block_count --;
2291+
2292+ remove_seq_hash_table(queue, entry);
2293+
2294+ sequence ++;
2295+
2296+ break;
2297+ }
2298+
2299+ /* entry not found, wait for it to arrive */
2300+ pthread_cond_wait(&queue->wait, &queue->mutex);
2301+ }
2302+
2303+ pthread_cleanup_pop(1);
2304+
2305+ return entry;
2306+}
2307+
2308+
2309+void seq_queue_flush(struct seq_queue *queue)
2310+{
2311+ int i;
2312+
2313+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2314+ pthread_mutex_lock(&queue->mutex);
2315+
2316+ for(i = 0; i < HASH_SIZE; i++)
2317+ queue->hash_table[i] = NULL;
2318+
2319+ queue->fragment_count = queue->block_count = 0;
2320+
2321+ pthread_cleanup_pop(1);
2322+}
2323+
2324+
2325+void dump_seq_queue(struct seq_queue *queue, int fragment_queue)
2326+{
2327+ int size;
2328+
2329+ pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
2330+ pthread_mutex_lock(&queue->mutex);
2331+
2332+ size = fragment_queue ? queue->fragment_count : queue->block_count;
2333+
2334+ printf("\tMax size unlimited, size %d%s\n", size,
2335+ size == 0 ? " (EMPTY)" : "");
2336+
2337+ pthread_cleanup_pop(1);
2338+}
2339+
2340+
2341+/* define cache hash tables */
2342+#define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N))
2343+
2344+/* Called with the cache mutex held */
2345+INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash)
2346+
2347+/* Called with the cache mutex held */
2348+REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash);
2349+
2350+/* define cache free list */
2351+
2352 /* Called with the cache mutex held */
2353 INSERT_LIST(free, struct file_buffer)
2354
2355@@ -136,7 +280,8 @@
2356 REMOVE_LIST(free, struct file_buffer)
2357
2358
2359-struct cache *cache_init(int buffer_size, int max_buffers)
2360+struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup,
2361+ int first_freelist)
2362 {
2363 struct cache *cache = malloc(sizeof(struct cache));
2364
2365@@ -146,10 +291,38 @@
2366 cache->max_buffers = max_buffers;
2367 cache->buffer_size = buffer_size;
2368 cache->count = 0;
2369+ cache->used = 0;
2370 cache->free_list = NULL;
2371+
2372+ /*
2373+ * The cache will grow up to max_buffers in size in response to
2374+ * an increase in readhead/number of buffers in flight. But
2375+ * once the outstanding buffers gets returned, we can either elect
2376+ * to shrink the cache, or to put the freed blocks onto a free list.
2377+ *
2378+ * For the caches where we want to do lookup (fragment/writer),
2379+ * a don't shrink policy is best, for the reader cache it
2380+ * makes no sense to keep buffers around longer than necessary as
2381+ * we don't do any lookup on those blocks.
2382+ */
2383+ cache->noshrink_lookup = noshrink_lookup;
2384+
2385+ /*
2386+ * The default use freelist before growing cache policy behaves
2387+ * poorly with appending - with many duplicates the caches
2388+ * do not grow due to the fact that large queues of outstanding
2389+ * fragments/writer blocks do not occur, leading to small caches
2390+ * and un-uncessary performance loss to frequent cache
2391+ * replacement in the small caches. Therefore with appending
2392+ * change the policy to grow the caches before reusing blocks
2393+ * from the freelist
2394+ */
2395+ cache->first_freelist = first_freelist;
2396+
2397 memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
2398 pthread_mutex_init(&cache->mutex, NULL);
2399 pthread_cond_init(&cache->wait_for_free, NULL);
2400+ pthread_cond_init(&cache->wait_for_unlock, NULL);
2401
2402 return cache;
2403 }
2404@@ -159,7 +332,7 @@
2405 {
2406 /* Lookup block in the cache, if found return with usage count
2407 * incremented, if not found return NULL */
2408- int hash = CALCULATE_HASH(index);
2409+ int hash = CALCULATE_CACHE_HASH(index);
2410 struct file_buffer *entry;
2411
2412 pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2413@@ -173,8 +346,11 @@
2414 /* found the block in the cache, increment used count and
2415 * if necessary remove from free list so it won't disappear
2416 */
2417+ if(entry->used == 0) {
2418+ remove_free_list(&cache->free_list, entry);
2419+ cache->used ++;
2420+ }
2421 entry->used ++;
2422- remove_free_list(&cache->free_list, entry);
2423 }
2424
2425 pthread_cleanup_pop(1);
2426@@ -183,50 +359,76 @@
2427 }
2428
2429
2430-struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
2431+static struct file_buffer *cache_freelist(struct cache *cache)
2432 {
2433- /* Get a free block out of the cache indexed on index. */
2434- struct file_buffer *entry;
2435+ struct file_buffer *entry = cache->free_list;
2436+
2437+ remove_free_list(&cache->free_list, entry);
2438+
2439+ /* a block on the free_list is hashed */
2440+ remove_cache_hash_table(cache, entry);
2441
2442+ cache->used ++;
2443+ return entry;
2444+}
2445+
2446+
2447+static struct file_buffer *cache_alloc(struct cache *cache)
2448+{
2449+ struct file_buffer *entry = malloc(sizeof(struct file_buffer) +
2450+ cache->buffer_size);
2451+ if(entry == NULL)
2452+ MEM_ERROR();
2453+
2454+ entry->cache = cache;
2455+ entry->free_prev = entry->free_next = NULL;
2456+ cache->count ++;
2457+ return entry;
2458+}
2459+
2460+
2461+static struct file_buffer *_cache_get(struct cache *cache, long long index,
2462+ int hash)
2463+{
2464+ /* Get a free block out of the cache indexed on index. */
2465+ struct file_buffer *entry = NULL;
2466+
2467 pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2468 pthread_mutex_lock(&cache->mutex);
2469
2470 while(1) {
2471- /* first try to get a block from the free list */
2472- if(first_freelist && cache->free_list) {
2473- /* a block on the free_list is a "keep" block */
2474- entry = cache->free_list;
2475- remove_free_list(&cache->free_list, entry);
2476- remove_hash_table(cache, entry);
2477- break;
2478- } else if(cache->count < cache->max_buffers) {
2479- /* next try to allocate new block */
2480- entry = malloc(sizeof(struct file_buffer) +
2481- cache->buffer_size);
2482- if(entry == NULL)
2483- MEM_ERROR();
2484- entry->cache = cache;
2485- entry->free_prev = entry->free_next = NULL;
2486- cache->count ++;
2487- break;
2488- } else if(!first_freelist && cache->free_list) {
2489- /* a block on the free_list is a "keep" block */
2490- entry = cache->free_list;
2491- remove_free_list(&cache->free_list, entry);
2492- remove_hash_table(cache, entry);
2493+ if(cache->noshrink_lookup) {
2494+ /* first try to get a block from the free list */
2495+ if(cache->first_freelist && cache->free_list)
2496+ entry = cache_freelist(cache);
2497+ else if(cache->count < cache->max_buffers) {
2498+ entry = cache_alloc(cache);
2499+ cache->used ++;
2500+ } else if(!cache->first_freelist && cache->free_list)
2501+ entry = cache_freelist(cache);
2502+ } else { /* shrinking non-lookup cache */
2503+ if(cache->count < cache->max_buffers) {
2504+ entry = cache_alloc(cache);
2505+ if(cache->count > cache->max_count)
2506+ cache->max_count = cache->count;
2507+ }
2508+ }
2509+
2510+ if(entry)
2511 break;
2512- } else
2513- /* wait for a block */
2514- pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
2515+
2516+ /* wait for a block */
2517+ pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
2518 }
2519
2520- /* initialise block and if a keep block insert into the hash table */
2521+ /* initialise block and if hash is set insert into the hash table */
2522 entry->used = 1;
2523+ entry->locked = FALSE;
2524+ entry->wait_on_unlock = FALSE;
2525 entry->error = FALSE;
2526- entry->keep = keep;
2527- if(keep) {
2528+ if(hash) {
2529 entry->index = index;
2530- insert_hash_table(cache, entry);
2531+ insert_cache_hash_table(cache, entry);
2532 }
2533
2534 pthread_cleanup_pop(1);
2535@@ -235,17 +437,28 @@
2536 }
2537
2538
2539-void cache_rehash(struct file_buffer *entry, long long index)
2540+struct file_buffer *cache_get(struct cache *cache, long long index)
2541+{
2542+ return _cache_get(cache, index, 1);
2543+}
2544+
2545+
2546+struct file_buffer *cache_get_nohash(struct cache *cache)
2547+{
2548+ return _cache_get(cache, 0, 0);
2549+}
2550+
2551+
2552+void cache_hash(struct file_buffer *entry, long long index)
2553 {
2554 struct cache *cache = entry->cache;
2555
2556 pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2557 pthread_mutex_lock(&cache->mutex);
2558- if(entry->keep)
2559- remove_hash_table(cache, entry);
2560- entry->keep = TRUE;
2561+
2562 entry->index = index;
2563- insert_hash_table(cache, entry);
2564+ insert_cache_hash_table(cache, entry);
2565+
2566 pthread_cleanup_pop(1);
2567 }
2568
2569@@ -254,10 +467,16 @@
2570 {
2571 struct cache *cache;
2572
2573- /* finished with this cache entry, once the usage count reaches zero it
2574- * can be reused and if a keep block put onto the free list. As keep
2575- * blocks remain accessible via the hash table they can be found
2576- * getting a new lease of life before they are reused. */
2577+ /*
2578+ * Finished with this cache entry, once the usage count reaches zero it
2579+ * can be reused.
2580+ *
2581+ * If noshrink_lookup is set, put the block onto the free list.
2582+ * As blocks remain accessible via the hash table they can be found
2583+ * getting a new lease of life before they are reused.
2584+ *
2585+ * if noshrink_lookup is not set then shrink the cache.
2586+ */
2587
2588 if(entry == NULL)
2589 return;
2590@@ -269,9 +488,10 @@
2591
2592 entry->used --;
2593 if(entry->used == 0) {
2594- if(entry->keep)
2595+ if(cache->noshrink_lookup) {
2596 insert_free_list(&cache->free_list, entry);
2597- else {
2598+ cache->used --;
2599+ } else {
2600 free(entry);
2601 cache->count --;
2602 }
2603@@ -281,4 +501,144 @@
2604 }
2605
2606 pthread_cleanup_pop(1);
2607+}
2608+
2609+
2610+void dump_cache(struct cache *cache)
2611+{
2612+ pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2613+ pthread_mutex_lock(&cache->mutex);
2614+
2615+ if(cache->noshrink_lookup)
2616+ printf("\tMax buffers %d, Current size %d, Used %d, %s\n",
2617+ cache->max_buffers, cache->count, cache->used,
2618+ cache->free_list ? "Free buffers" : "No free buffers");
2619+ else
2620+ printf("\tMax buffers %d, Current size %d, Maximum historical "
2621+ "size %d\n", cache->max_buffers, cache->count,
2622+ cache->max_count);
2623+
2624+ pthread_cleanup_pop(1);
2625+}
2626+
2627+
2628+struct file_buffer *cache_get_nowait(struct cache *cache, long long index)
2629+{
2630+ struct file_buffer *entry = NULL;
2631+ /*
2632+ * block doesn't exist, create it, but return it with the
2633+ * locked flag set, so nothing tries to use it while it doesn't
2634+ * contain data.
2635+ *
2636+ * If there's no space in the cache then return NULL.
2637+ */
2638+
2639+ pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2640+ pthread_mutex_lock(&cache->mutex);
2641+
2642+ /* first try to get a block from the free list */
2643+ if(cache->first_freelist && cache->free_list)
2644+ entry = cache_freelist(cache);
2645+ else if(cache->count < cache->max_buffers) {
2646+ entry = cache_alloc(cache);
2647+ cache->used ++;
2648+ } else if(!cache->first_freelist && cache->free_list)
2649+ entry = cache_freelist(cache);
2650+
2651+ if(entry) {
2652+ /* initialise block and insert into the hash table */
2653+ entry->used = 1;
2654+ entry->locked = TRUE;
2655+ entry->wait_on_unlock = FALSE;
2656+ entry->error = FALSE;
2657+ entry->index = index;
2658+ insert_cache_hash_table(cache, entry);
2659+ }
2660+
2661+ pthread_cleanup_pop(1);
2662+
2663+ return entry;
2664+}
2665+
2666+
2667+struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index,
2668+ char *locked)
2669+{
2670+ /*
2671+ * Lookup block in the cache, if found return it with the locked flag
2672+ * indicating whether it is currently locked. In both cases increment
2673+ * the used count.
2674+ *
2675+ * If it doesn't exist in the cache return NULL;
2676+ */
2677+ int hash = CALCULATE_CACHE_HASH(index);
2678+ struct file_buffer *entry;
2679+
2680+ pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2681+ pthread_mutex_lock(&cache->mutex);
2682+
2683+ /* first check if the entry already exists */
2684+ for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
2685+ if(entry->index == index)
2686+ break;
2687+
2688+ if(entry) {
2689+ if(entry->used == 0) {
2690+ remove_free_list(&cache->free_list, entry);
2691+ cache->used ++;
2692+ }
2693+ entry->used ++;
2694+ *locked = entry->locked;
2695+ }
2696+
2697+ pthread_cleanup_pop(1);
2698+
2699+ return entry;
2700+}
2701+
2702+
2703+void cache_wait_unlock(struct file_buffer *buffer)
2704+{
2705+ struct cache *cache = buffer->cache;
2706+
2707+ pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2708+ pthread_mutex_lock(&cache->mutex);
2709+
2710+ while(buffer->locked) {
2711+ /*
2712+ * another thread is filling this in, wait until it
2713+ * becomes unlocked. Used has been incremented to ensure it
2714+ * doesn't get reused. By definition a block can't be
2715+ * locked and unused, and so we don't need to worry
2716+ * about it being on the freelist now, but, it may
2717+ * become unused when unlocked unless used is
2718+ * incremented
2719+ */
2720+ buffer->wait_on_unlock = TRUE;
2721+ pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex);
2722+ }
2723+
2724+ pthread_cleanup_pop(1);
2725+}
2726+
2727+
2728+void cache_unlock(struct file_buffer *entry)
2729+{
2730+ struct cache *cache = entry->cache;
2731+
2732+ /*
2733+ * Unlock this locked cache entry. If anything is waiting for this
2734+ * to become unlocked, wake it up.
2735+ */
2736+ pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
2737+ pthread_mutex_lock(&cache->mutex);
2738+
2739+ entry->locked = FALSE;
2740+
2741+ if(entry->wait_on_unlock) {
2742+ entry->wait_on_unlock = FALSE;
2743+ pthread_cond_broadcast(&cache->wait_for_unlock);
2744+ }
2745+
2746+ pthread_cleanup_pop(1);
2747 }
2748diff -Nru squashfs-tools-4.2+20130409/caches-queues-lists.h squashfs-tools-4.3+20140919/caches-queues-lists.h
2749--- squashfs-tools-4.2+20130409/caches-queues-lists.h 2013-05-09 10:39:11.000000000 +0200
2750+++ squashfs-tools-4.3+20140919/caches-queues-lists.h 2015-07-20 21:03:05.000000000 +0200
2751@@ -1,8 +1,10 @@
2752+#ifndef CACHES_QUEUES_LISTS_H
2753+#define CACHES_QUEUES_LISTS_H
2754 /*
2755 * Create a squashfs filesystem. This is a highly compressed read only
2756 * filesystem.
2757 *
2758- * Copyright (c) 2013
2759+ * Copyright (c) 2013, 2014
2760 * Phillip Lougher <phillip@squashfs.org.uk>
2761 *
2762 * This program is free software; you can redistribute it and/or
2763@@ -22,24 +24,104 @@
2764 * caches-queues-lists.h
2765 */
2766
2767+#define INSERT_LIST(NAME, TYPE) \
2768+void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
2769+ if(*list) { \
2770+ entry->NAME##_next = *list; \
2771+ entry->NAME##_prev = (*list)->NAME##_prev; \
2772+ (*list)->NAME##_prev->NAME##_next = entry; \
2773+ (*list)->NAME##_prev = entry; \
2774+ } else { \
2775+ *list = entry; \
2776+ entry->NAME##_prev = entry->NAME##_next = entry; \
2777+ } \
2778+}
2779+
2780+
2781+#define REMOVE_LIST(NAME, TYPE) \
2782+void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
2783+ if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
2784+ /* only this entry in the list */ \
2785+ *list = NULL; \
2786+ } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
2787+ /* more than one entry in the list */ \
2788+ entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
2789+ entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
2790+ if(*list == entry) \
2791+ *list = entry->NAME##_next; \
2792+ } \
2793+ entry->NAME##_prev = entry->NAME##_next = NULL; \
2794+}
2795+
2796+
2797+#define INSERT_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
2798+void insert_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
2799+{ \
2800+ int hash = HASH_FUNCTION(entry->FIELD); \
2801+\
2802+ entry->LINK##_next = container->hash_table[hash]; \
2803+ container->hash_table[hash] = entry; \
2804+ entry->LINK##_prev = NULL; \
2805+ if(entry->LINK##_next) \
2806+ entry->LINK##_next->LINK##_prev = entry; \
2807+}
2808+
2809+
2810+#define REMOVE_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
2811+void remove_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
2812+{ \
2813+ if(entry->LINK##_prev) \
2814+ entry->LINK##_prev->LINK##_next = entry->LINK##_next; \
2815+ else \
2816+ container->hash_table[HASH_FUNCTION(entry->FIELD)] = \
2817+ entry->LINK##_next; \
2818+ if(entry->LINK##_next) \
2819+ entry->LINK##_next->LINK##_prev = entry->LINK##_prev; \
2820+\
2821+ entry->LINK##_prev = entry->LINK##_next = NULL; \
2822+}
2823+
2824+#define HASH_SIZE 65536
2825+#define CALCULATE_HASH(n) ((n) & 0xffff)
2826+
2827+
2828 /* struct describing a cache entry passed between threads */
2829 struct file_buffer {
2830- struct cache *cache;
2831- struct file_buffer *hash_next;
2832- struct file_buffer *hash_prev;
2833- struct file_buffer *free_next;
2834- struct file_buffer *free_prev;
2835- struct file_buffer *next;
2836+ union {
2837+ long long index;
2838+ long long sequence;
2839+ };
2840 long long file_size;
2841- long long index;
2842- long long block;
2843- long long sequence;
2844+ union {
2845+ long long block;
2846+ unsigned short checksum;
2847+ };
2848+ struct cache *cache;
2849+ union {
2850+ struct file_info *dupl_start;
2851+ struct file_buffer *hash_next;
2852+ };
2853+ union {
2854+ int duplicate;
2855+ struct file_buffer *hash_prev;
2856+ };
2857+ union {
2858+ struct {
2859+ struct file_buffer *free_next;
2860+ struct file_buffer *free_prev;
2861+ };
2862+ struct {
2863+ struct file_buffer *seq_next;
2864+ struct file_buffer *seq_prev;
2865+ };
2866+ };
2867 int size;
2868 int c_byte;
2869- char keep;
2870 char used;
2871 char fragment;
2872 char error;
2873+ char locked;
2874+ char wait_on_unlock;
2875 char noD;
2876 char data[0];
2877 };
2878@@ -57,59 +139,62 @@
2879 };
2880
2881
2882+/*
2883+ * struct describing seq_queues used to pass data between the read
2884+ * thread and the deflate and main threads
2885+ */
2886+struct seq_queue {
2887+ int fragment_count;
2888+ int block_count;
2889+ struct file_buffer *hash_table[HASH_SIZE];
2890+ pthread_mutex_t mutex;
2891+ pthread_cond_t wait;
2892+};
2893+
2894+
2895 /* Cache status struct. Caches are used to keep
2896 track of memory buffers passed between different threads */
2897 struct cache {
2898 int max_buffers;
2899 int count;
2900 int buffer_size;
2901+ int noshrink_lookup;
2902+ int first_freelist;
2903+ union {
2904+ int used;
2905+ int max_count;
2906+ };
2907 pthread_mutex_t mutex;
2908 pthread_cond_t wait_for_free;
2909+ pthread_cond_t wait_for_unlock;
2910 struct file_buffer *free_list;
2911- struct file_buffer *hash_table[65536];
2912+ struct file_buffer *hash_table[HASH_SIZE];
2913 };
2914
2915
2916-#define INSERT_LIST(NAME, TYPE) \
2917-void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
2918- if(*list) { \
2919- entry->NAME##_next = *list; \
2920- entry->NAME##_prev = (*list)->NAME##_prev; \
2921- (*list)->NAME##_prev->NAME##_next = entry; \
2922- (*list)->NAME##_prev = entry; \
2923- } else { \
2924- *list = entry; \
2925- entry->NAME##_prev = entry->NAME##_next = entry; \
2926- } \
2927-}
2928-
2929-
2930-#define REMOVE_LIST(NAME, TYPE) \
2931-void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
2932- if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
2933- /* only this entry in the list */ \
2934- *list = NULL; \
2935- } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
2936- /* more than one entry in the list */ \
2937- entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
2938- entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
2939- if(*list == entry) \
2940- *list = entry->NAME##_next; \
2941- } \
2942- entry->NAME##_prev = entry->NAME##_next = NULL; \
2943-}
2944-
2945 extern struct queue *queue_init(int);
2946 extern void queue_put(struct queue *, void *);
2947 extern void *queue_get(struct queue *);
2948-extern struct cache *cache_init(int, int);
2949+extern int queue_empty(struct queue *);
2950+extern void queue_flush(struct queue *);
2951+extern void dump_queue(struct queue *);
2952+extern struct seq_queue *seq_queue_init();
2953+extern void seq_queue_put(struct seq_queue *, struct file_buffer *);
2954+extern void dump_seq_queue(struct seq_queue *, int);
2955+extern struct file_buffer *seq_queue_get(struct seq_queue *);
2956+extern void seq_queue_flush(struct seq_queue *);
2957+extern struct cache *cache_init(int, int, int, int);
2958 extern struct file_buffer *cache_lookup(struct cache *, long long);
2959-extern struct file_buffer *cache_get(struct cache *, long long, int);
2960-extern void cache_rehash(struct file_buffer *, long long);
2961+extern struct file_buffer *cache_get(struct cache *, long long);
2962+extern struct file_buffer *cache_get_nohash(struct cache *);
2963+extern void cache_hash(struct file_buffer *, long long);
2964 extern void cache_block_put(struct file_buffer *);
2965-
2966-//extern void insert_free_list(struct file_buffer **, struct file_buffer *);
2967-//extern void remove_free_list(struct file_buffer **, struct file_buffer *);
2968+extern void dump_cache(struct cache *);
2969+extern struct file_buffer *cache_get_nowait(struct cache *, long long);
2970+extern struct file_buffer *cache_lookup_nowait(struct cache *, long long,
2971+ char *);
2972+extern void cache_wait_unlock(struct file_buffer *);
2973+extern void cache_unlock(struct file_buffer *);
2974
2975 extern int first_freelist;
2976-
2977+#endif
2978diff -Nru squashfs-tools-4.2+20130409/compressor.c squashfs-tools-4.3+20140919/compressor.c
2979--- squashfs-tools-4.2+20130409/compressor.c 2013-05-09 10:39:11.000000000 +0200
2980+++ squashfs-tools-4.3+20140919/compressor.c 2015-07-20 21:03:05.000000000 +0200
2981@@ -49,6 +49,14 @@
2982 extern struct compressor lzo_comp_ops;
2983 #endif
2984
2985+#ifndef LZ4_SUPPORT
2986+static struct compressor lz4_comp_ops = {
2987+ LZ4_COMPRESSION, "lz4"
2988+};
2989+#else
2990+extern struct compressor lz4_comp_ops;
2991+#endif
2992+
2993 #ifndef XZ_SUPPORT
2994 static struct compressor xz_comp_ops = {
2995 XZ_COMPRESSION, "xz"
2996@@ -67,6 +75,7 @@
2997 &gzip_comp_ops,
2998 &lzma_comp_ops,
2999 &lzo_comp_ops,
3000+ &lz4_comp_ops,
3001 &xz_comp_ops,
3002 &unknown_comp_ops
3003 };
3004diff -Nru squashfs-tools-4.2+20130409/compressor.h squashfs-tools-4.3+20140919/compressor.h
3005--- squashfs-tools-4.2+20130409/compressor.h 2013-05-09 10:39:11.000000000 +0200
3006+++ squashfs-tools-4.3+20140919/compressor.h 2015-07-20 21:03:05.000000000 +0200
3007@@ -1,6 +1,8 @@
3008+#ifndef COMPRESSOR_H
3009+#define COMPRESSOR_H
3010 /*
3011 *
3012- * Copyright (c) 2009, 2010, 2011, 2012, 2013
3013+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
3014 * Phillip Lougher <phillip@squashfs.org.uk>
3015 *
3016 * This program is free software; you can redistribute it and/or
3017@@ -31,6 +33,7 @@
3018 int (*options_post)(int);
3019 void *(*dump_options)(int, int *);
3020 int (*extract_options)(int, void *, int);
3021+ int (*check_options)(int, void *, int);
3022 void (*display_options)(void *, int);
3023 void (*usage)();
3024 };
3025@@ -64,9 +67,8 @@
3026
3027
3028 /*
3029- * For the following functions, please see xz_wrapper.c for
3030- * commented examples of how they are used (xz is currently
3031- * the only compressor that uses compression options).
3032+ * For the following functions please see the lzo, lz4 or xz
3033+ * compressors for commented examples of how they are used.
3034 */
3035 static inline int compressor_options(struct compressor *comp, char *argv[],
3036 int argc)
3037@@ -104,9 +106,19 @@
3038 }
3039
3040
3041+static inline int compressor_check_options(struct compressor *comp,
3042+ int block_size, void *buffer, int size)
3043+{
3044+ if(comp->check_options == NULL)
3045+ return 0;
3046+ return comp->check_options(block_size, buffer, size);
3047+}
3048+
3049+
3050 static inline void compressor_display_options(struct compressor *comp,
3051 void *buffer, int size)
3052 {
3053 if(comp->display_options != NULL)
3054 comp->display_options(buffer, size);
3055 }
3056+#endif
3057diff -Nru squashfs-tools-4.2+20130409/debian/changelog squashfs-tools-4.3+20140919/debian/changelog
3058--- squashfs-tools-4.2+20130409/debian/changelog 2013-09-18 10:22:27.000000000 +0200
3059+++ squashfs-tools-4.3+20140919/debian/changelog 2015-07-20 22:44:05.000000000 +0200
3060@@ -1,3 +1,11 @@
3061+squashfs-tools (1:4.3+20140919-0) unstable; urgency=low
3062+
3063+ * Merging upstream version 4.3+20140919.
3064+ * Fix for CVE 2015-4645/4646
3065+ * Updates man pages
3066+
3067+ -- Romeo Papa <romeopapa@caramail.com> Mon, 20 Jul 2015 21:28:12 +0200
3068+
3069 squashfs-tools (1:4.2+20130409-2) unstable; urgency=low
3070
3071 * New maintainer (closes: #723600).
3072diff -Nru squashfs-tools-4.2+20130409/debian/manpages/mksquashfs.1 squashfs-tools-4.3+20140919/debian/manpages/mksquashfs.1
3073--- squashfs-tools-4.2+20130409/debian/manpages/mksquashfs.1 2013-05-09 22:22:49.000000000 +0200
3074+++ squashfs-tools-4.3+20140919/debian/manpages/mksquashfs.1 2015-07-20 22:44:05.000000000 +0200
3075@@ -1,4 +1,4 @@
3076-.TH MKSQUASHFS 1 "2012\-06\-30" "4.2" "create and append squashfs filesystems"
3077+.TH MKSQUASHFS 1 "2014\-05\-13" "4.3" "create and append squashfs filesystems"
3078
3079 .SH NAME
3080 mksquashfs \- tool to create and append to squashfs filesystems
3081@@ -15,9 +15,9 @@
3082
3083 .SS Filesystem build options
3084 .IP "\-comp \fICOMPRESSION\fR" 4
3085-select \fICOMPRESSION\fR compression. Compressors available: gzip (default), lzo, xz.
3086+select \fICOMPRESSION\fR compression. Compressors available: gzip (default), lzma (no kernel support), lzo, lz4 and xz.
3087 .IP "\-b \fIBLOCK_SIZE\fR"
3088-set data block to \fIBLOCK_SIZE\fR. Default 131072 bytes.
3089+set data block to \fIBLOCK_SIZE\fR. Default 131072 bytes. Optionally K or M can be used as a suffix to specify kilobytes or megabytes, respectively.
3090 .IP "\-no\-exports" 4
3091 don't make the filesystem exportable via NFS.
3092 .IP "\-no\-sparse" 4
3093@@ -74,6 +74,8 @@
3094 .SS Mksquashfs runtime options:
3095 .IP "\-version" 4
3096 print version, licence and copyright message.
3097+.IP "\-exit\-on\-error" 4
3098+treat normally ignored errors as fatal.
3099 .IP "\-recover \fINAME\fR" 4
3100 recover filesystem data using recovery file \fINAME\fR.
3101 .IP "\-no\-recovery" 4
3102@@ -82,14 +84,18 @@
3103 print files written to filesystem.
3104 .IP "\-no\-progress" 4
3105 don't display the progress bar.
3106+.IP "\-progress" 4
3107+display progress bar when using the \-info option.
3108 .IP "\-processors \fINUMBER\fR" 4
3109 Use \fINUMBER\fR processors. By default will use number of processors available.
3110+.IP "\-mem \fISIZE\fR" 4
3111+Use \fISIZE\fR physical memory. Optionally K or M can be used as a suffix for kilobytes or megabytes, respectively. Default 25% of memory.
3112 .IP "\-read\-queue \fISIZE\fR" 4
3113-Set input queue to \fISIZE\fR Mbytes. Default 64 Mbytes.
3114+Deprecated. Use \-mem instead.
3115 .IP "\-write\-queue \fISIZE\fR" 4
3116-Set output queue to \fISIZE\fR Mbytes. Default 512 Mbytes.
3117+Deprecated. Use \-mem instead.
3118 .IP "\-fragment\-queue \fISIZE\fR" 4
3119-Set fragment queue to \fISIZE\fR Mbytes. Default 64 Mbytes.
3120+Deprecated. Use \-mem instead.
3121
3122 .SS Miscellaneous options
3123 .IP "\-root\-owned" 4
3124@@ -102,11 +108,27 @@
3125 alternative name for \-noF.
3126 .IP "\-noXattrCompression" 4
3127 alternative name for \-noX.
3128+.IP "\-Xhelp" 4
3129+print compressor options for selected compressor
3130
3131 .SS Compressors available and compressor specific options
3132-.IP "gzip (no options) (default)"
3133-.IP "lzo (no options)"
3134-.IP "xz"
3135+.IP "gzip (default)"
3136+.IP "\-Xcompression-level \fIcompression\-level\fR" 4
3137+\fIcompression\-level\fR should be 1 .. 9 (default 9)
3138+.IP "\-Xwindow\-size \fIwindow\-size\fR" 4
3139+\fIwindow\-size\fR should be 8 .. 15 (default 15)
3140+.IP "\-Xstrategy strategy1,strategy2,...,strategyN" 4
3141+Compress using strategy1,strategy2,...,strategyN in turn and choose the best compression. Available strategies: default, filtered, huffman_only, run_length_encoded and fixed
3142+.IP "lzmz (no options) (no kernel support)" 4
3143+.IP "lzo" 4
3144+.IP "\-Xalgorithm \fIalgorithm\fR" 4
3145+Where \fIalgorithm\fR is one of: lzo1x_1, lzo1x_1_11, lzo1x_1_12, lzo1x_1_15 or lzo1x_999. (default lzo1x_999)
3146+.IP "\-Xcompression\-level \fIcompression\-level\fR" 4
3147+\fIcompression\-level\fR should be 1 .. 9 (default 8)
3148+.IP "lz4" 4
3149+.IP "\-Xhc"
3150+Compress using LZ4 High Compression
3151+.IP "xz" 4
3152 .IP "\-Xbcj filter1,filter2,...,filterN" 4
3153 Compress using filter1,filter2,...,filterN in turn (in addition to no filter), and choose the best compression. Available filters: x86, arm, armthumb, powerpc, sparc, ia64.
3154 .IP "\-Xdict\-size \fIDICT_SIZE\fR" 4
3155@@ -119,6 +141,6 @@
3156 More information about mksquashfs and the squashfs filesystem can be found at <\fIhttp://squashfs.sourceforge.net/\fR>.
3157
3158 .SH AUTHOR
3159-squashfs was written by Phillip Lougher <\fIphillip@squashfs.org.uk\fR>.
3160+squashfs was written by Phillip Lougher <\fIplougher@users.sourceforge.net\fR>.
3161 .PP
3162-This manual page was written by Daniel Baumann <\fImail@daniel\-baumann.ch\fR>.
3163+This manual page was written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. With some updates for 4.3 for use with Fedora and Debian.
3164diff -Nru squashfs-tools-4.2+20130409/debian/manpages/unsquashfs.1 squashfs-tools-4.3+20140919/debian/manpages/unsquashfs.1
3165--- squashfs-tools-4.2+20130409/debian/manpages/unsquashfs.1 2013-05-09 22:22:49.000000000 +0200
3166+++ squashfs-tools-4.3+20140919/debian/manpages/unsquashfs.1 2015-07-20 22:44:05.000000000 +0200
3167@@ -1,4 +1,4 @@
3168-.TH UNSQUASHFS 1 "2012\-06\-30" "4.2" "uncompress squashfs filesystems"
3169+.TH UNSQUASHFS 1 "2014\-05\-13" "4.3" "uncompress squashfs filesystems"
3170
3171 .SH NAME
3172 mksquashfs \- tool to uncompress squashfs filesystems
3173@@ -22,6 +22,8 @@
3174 don't extract xattrs in file system.
3175 .IP "\-x, \-xattrs" 4
3176 extract xattrs in file system (default).
3177+.IP "\-u, \-user\-xattrs" 4
3178+only extract user xattrs in file system. Enables extracting xattrs.
3179 .IP "\-p \fINUMBER\fR, \-processors \fINUMBER\fR" 4
3180 use \fINUMBER\fR processors. By default will use number of processors available.
3181 .IP "\-i, \-info" 4
3182@@ -38,7 +40,7 @@
3183 display filesystem superblock information.
3184 .IP "\-e \fIEXTRACT_FILE\fR, \-ef \fIEXTRACT_FILE\fR" 4
3185 list of directories or files to extract. One per line.
3186-.IP "\-da \fISIZE\fR, \-data-queue \fISIZE\fR" 4
3187+.IP "\-da \fISIZE\fR, \-data\-queue \fISIZE\fR" 4
3188 Set data queue to \fISIZE\fR Mbytes. Default 256 Mbytes.
3189 .IP "\-fr \fISIZE\fR, \-frag\-queue \fISIZE\fR" 4
3190 Set fragment queue to \fISIZE\fR Mbytes. Default 256 Mbytes.
3191@@ -47,7 +49,9 @@
3192
3193 .SS Decompressors available
3194 .IP "gzip" 4
3195+.IP "lzma" 4
3196 .IP "lzo" 4
3197+.IP "lz4" 4
3198 .IP "xz" 4
3199
3200 .SH SEE ALSO
3201@@ -57,6 +61,6 @@
3202 More information about unsquashfs and the squashfs filesystem can be found at <\fIhttp://squashfs.sourceforge.net/\fR>.
3203
3204 .SH AUTHOR
3205-squashfs was written by Phillip Lougher <\fIphillip@squashfs.org.uk\fR>.
3206+squashfs was written by Phillip Lougher <\fIplougher@users.sourceforge.net\fR>.
3207 .PP
3208-This manual page was written by Daniel Baumann <\fImail@daniel\-baumann.ch\fR>.
3209+This manual page was written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. With some updates for 4.3 for use with Fedora and Debian.
3210diff -Nru squashfs-tools-4.2+20130409/debian/patches/0001-kfreebsd.patch squashfs-tools-4.3+20140919/debian/patches/0001-kfreebsd.patch
3211--- squashfs-tools-4.2+20130409/debian/patches/0001-kfreebsd.patch 2013-05-09 22:25:25.000000000 +0200
3212+++ squashfs-tools-4.3+20140919/debian/patches/0001-kfreebsd.patch 1970-01-01 01:00:00.000000000 +0100
3213@@ -1,103 +0,0 @@
3214-Author: Cyril Brulebois <kibi@debian.org>
3215-Description: Fixes FTBFS on kfreebsd (Closes: #557174).
3216-
3217-Index: squashfs-tools/mksquashfs.c
3218-===================================================================
3219---- squashfs-tools.orig/mksquashfs.c 2013-05-09 20:25:19.000000000 +0000
3220-+++ squashfs-tools/mksquashfs.c 2013-05-09 20:25:19.000000000 +0000
3221-@@ -51,7 +51,7 @@
3222- #include <limits.h>
3223- #include <ctype.h>
3224-
3225--#ifndef linux
3226-+#if !defined(linux) && !defined(__GLIBC__)
3227- #define __BYTE_ORDER BYTE_ORDER
3228- #define __BIG_ENDIAN BIG_ENDIAN
3229- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3230-@@ -4038,7 +4038,7 @@
3231- BAD_ERROR("Failed to set signal mask in intialise_threads\n");
3232-
3233- if(processors == -1) {
3234--#ifndef linux
3235-+#if !defined(linux) && !defined(__GLIBC__)
3236- int mib[2];
3237- size_t len = sizeof(processors);
3238-
3239-Index: squashfs-tools/read_fs.c
3240-===================================================================
3241---- squashfs-tools.orig/read_fs.c 2013-05-09 20:25:19.000000000 +0000
3242-+++ squashfs-tools/read_fs.c 2013-05-09 20:25:19.000000000 +0000
3243-@@ -34,7 +34,7 @@
3244- #include <sys/mman.h>
3245- #include <limits.h>
3246-
3247--#ifndef linux
3248-+#if !defined(linux) && !defined(__GLIBC__)
3249- #define __BYTE_ORDER BYTE_ORDER
3250- #define __BIG_ENDIAN BIG_ENDIAN
3251- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3252-Index: squashfs-tools/read_xattrs.c
3253-===================================================================
3254---- squashfs-tools.orig/read_xattrs.c 2013-05-09 20:25:19.000000000 +0000
3255-+++ squashfs-tools/read_xattrs.c 2013-05-09 20:25:19.000000000 +0000
3256-@@ -31,7 +31,7 @@
3257- #include <stdio.h>
3258- #include <string.h>
3259-
3260--#ifndef linux
3261-+#if !defined(linux) && !defined(__GLIBC__)
3262- #define __BYTE_ORDER BYTE_ORDER
3263- #define __BIG_ENDIAN BIG_ENDIAN
3264- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3265-Index: squashfs-tools/swap.c
3266-===================================================================
3267---- squashfs-tools.orig/swap.c 2013-05-09 20:25:19.000000000 +0000
3268-+++ squashfs-tools/swap.c 2013-05-09 20:25:19.000000000 +0000
3269-@@ -19,7 +19,7 @@
3270- * swap.c
3271- */
3272-
3273--#ifndef linux
3274-+#if !defined(linux) && !defined(__GLIBC__)
3275- #define __BYTE_ORDER BYTE_ORDER
3276- #define __BIG_ENDIAN BIG_ENDIAN
3277- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3278-Index: squashfs-tools/unsquashfs.c
3279-===================================================================
3280---- squashfs-tools.orig/unsquashfs.c 2013-05-09 20:25:19.000000000 +0000
3281-+++ squashfs-tools/unsquashfs.c 2013-05-09 20:25:19.000000000 +0000
3282-@@ -2104,7 +2104,7 @@
3283- "\n");
3284-
3285- if(processors == -1) {
3286--#ifndef linux
3287-+#if !defined(linux) && !defined(__GLIBC__)
3288- int mib[2];
3289- size_t len = sizeof(processors);
3290-
3291-Index: squashfs-tools/unsquashfs.h
3292-===================================================================
3293---- squashfs-tools.orig/unsquashfs.h 2013-05-09 20:25:19.000000000 +0000
3294-+++ squashfs-tools/unsquashfs.h 2013-05-09 20:25:19.000000000 +0000
3295-@@ -45,7 +45,7 @@
3296- #include <sys/ioctl.h>
3297- #include <sys/time.h>
3298-
3299--#ifndef linux
3300-+#if !defined(linux) && !defined(__GLIBC__)
3301- #define __BYTE_ORDER BYTE_ORDER
3302- #define __BIG_ENDIAN BIG_ENDIAN
3303- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3304-Index: squashfs-tools/xz_wrapper.h
3305-===================================================================
3306---- squashfs-tools.orig/xz_wrapper.h 2013-05-09 20:25:19.000000000 +0000
3307-+++ squashfs-tools/xz_wrapper.h 2013-05-09 20:25:19.000000000 +0000
3308-@@ -24,7 +24,7 @@
3309- *
3310- */
3311-
3312--#ifndef linux
3313-+#if !defined(linux) && !defined(__GLIBC__)
3314- #define __BYTE_ORDER BYTE_ORDER
3315- #define __BIG_ENDIAN BIG_ENDIAN
3316- #define __LITTLE_ENDIAN LITTLE_ENDIAN
3317diff -Nru squashfs-tools-4.2+20130409/debian/patches/cve-2015-4646 squashfs-tools-4.3+20140919/debian/patches/cve-2015-4646
3318--- squashfs-tools-4.2+20130409/debian/patches/cve-2015-4646 1970-01-01 01:00:00.000000000 +0100
3319+++ squashfs-tools-4.3+20140919/debian/patches/cve-2015-4646 2015-07-20 22:29:13.000000000 +0200
3320@@ -0,0 +1,47 @@
3321+Description: CVE-2015-4645 integer overflow in read_fragment_table_4
3322+ Integer overflow issue was reported in squashfs-tools.
3323+ Following code in unsquash-4.c overflows the bytes variable, so that the allocation of fragments_bytes[] has an erroneous size.
3324+
3325+ int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
3326+ ...
3327+ fragment_table = malloc(bytes)
3328+ .
3329+ squashfs-tools (1:4.3+20140919-0) unstable; urgency=low
3330+ .
3331+ * Fixes https://security-tracker.debian.org/tracker/CVE-2015-4645
3332+ * Fixes https://security-tracker.debian.org/tracker/CVE-2015-4646
3333+
3334+Author: Romeo Papa <romeopapa@caramail.com>
3335+Origin: upstream, https://github.com/gcanalesb/sasquatch/commit/6777e08cc38bc780d27c69c1d8c272867b74524f
3336+Bug: https://github.com/devttys0/sasquatch/pull/5
3337+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2015-4646
3338+Bug-Fedora: http://people.canonical.com/~ubuntu-security/cve/2015/CVE-2015-4646.html
3339+Last-Update: 2015-06-17
3340+
3341+--- squashfs-tools-4.3+20140919.orig/unsquash-4.c
3342++++ squashfs-tools-4.3+20140919/unsquash-4.c
3343+@@ -31,9 +31,9 @@ static unsigned int *id_table;
3344+ int read_fragment_table_4(long long *directory_table_end)
3345+ {
3346+ int res, i;
3347+- int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
3348+- int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments);
3349+- long long fragment_table_index[indexes];
3350++ size_t bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
3351++ size_t indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments);
3352++ long long *fragment_table_index;
3353+
3354+ TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
3355+ "from 0x%llx\n", sBlk.s.fragments, indexes,
3356+@@ -44,6 +44,11 @@ int read_fragment_table_4(long long *dir
3357+ return TRUE;
3358+ }
3359+
3360++ fragment_table_index = malloc(indexes*sizeof(long long));
3361++ if(fragment_table_index == NULL)
3362++ EXIT_UNSQUASH("read_fragment_table: failed to allocate "
3363++ "fragment table index\n");
3364++
3365+ fragment_table = malloc(bytes);
3366+ if(fragment_table == NULL)
3367+ EXIT_UNSQUASH("read_fragment_table: failed to allocate "
3368diff -Nru squashfs-tools-4.2+20130409/debian/patches/series squashfs-tools-4.3+20140919/debian/patches/series
3369--- squashfs-tools-4.2+20130409/debian/patches/series 2013-05-09 22:22:49.000000000 +0200
3370+++ squashfs-tools-4.3+20140919/debian/patches/series 2015-07-20 22:30:50.000000000 +0200
3371@@ -1 +1 @@
3372-0001-kfreebsd.patch
3373+cve-2015-4646
3374diff -Nru squashfs-tools-4.2+20130409/error.h squashfs-tools-4.3+20140919/error.h
3375--- squashfs-tools-4.2+20130409/error.h 2013-05-09 10:39:11.000000000 +0200
3376+++ squashfs-tools-4.3+20140919/error.h 2015-07-20 21:03:05.000000000 +0200
3377@@ -1,8 +1,10 @@
3378+#ifndef ERROR_H
3379+#define ERROR_H
3380 /*
3381 * Create a squashfs filesystem. This is a highly compressed read only
3382 * filesystem.
3383 *
3384- * Copyright (c) 2012, 2013
3385+ * Copyright (c) 2012, 2013, 2014
3386 * Phillip Lougher <phillip@squashfs.org.uk>
3387 *
3388 * This program is free software; you can redistribute it and/or
3389@@ -22,6 +24,8 @@
3390 * error.h
3391 */
3392
3393+extern int exit_on_error;
3394+
3395 extern void prep_exit();
3396 extern void progressbar_error(char *fmt, ...);
3397 extern void progressbar_info(char *fmt, ...);
3398@@ -46,6 +50,23 @@
3399 progressbar_error(s, ## args); \
3400 } while(0)
3401
3402+#define ERROR_START(s, args...) \
3403+ do { \
3404+ disable_progress_bar(); \
3405+ fprintf(stderr, s, ## args); \
3406+ } while(0)
3407+
3408+#define ERROR_EXIT(s, args...) \
3409+ do {\
3410+ if (exit_on_error) { \
3411+ fprintf(stderr, "\n"); \
3412+ EXIT_MKSQUASHFS(); \
3413+ } else { \
3414+ fprintf(stderr, s, ## args); \
3415+ enable_progress_bar(); \
3416+ } \
3417+ } while(0)
3418+
3419 #define EXIT_MKSQUASHFS() \
3420 do {\
3421 prep_exit();\
3422@@ -66,3 +87,4 @@
3423 __func__); \
3424 EXIT_MKSQUASHFS();\
3425 } while(0)
3426+#endif
3427diff -Nru squashfs-tools-4.2+20130409/gzip_wrapper.c squashfs-tools-4.3+20140919/gzip_wrapper.c
3428--- squashfs-tools-4.2+20130409/gzip_wrapper.c 2013-05-09 10:39:11.000000000 +0200
3429+++ squashfs-tools-4.3+20140919/gzip_wrapper.c 2015-07-20 21:03:05.000000000 +0200
3430@@ -1,5 +1,5 @@
3431 /*
3432- * Copyright (c) 2009, 2010, 2013
3433+ * Copyright (c) 2009, 2010, 2013, 2014
3434 * Phillip Lougher <phillip@squashfs.org.uk>
3435 *
3436 * This program is free software; you can redistribute it and/or
3437@@ -17,34 +17,376 @@
3438 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3439 *
3440 * gzip_wrapper.c
3441+ *
3442+ * Support for ZLIB compression http://www.zlib.net
3443 */
3444
3445+#include <stdio.h>
3446+#include <string.h>
3447 #include <stdlib.h>
3448 #include <zlib.h>
3449
3450 #include "squashfs_fs.h"
3451+#include "gzip_wrapper.h"
3452 #include "compressor.h"
3453
3454-static int gzip_init(void **strm, int block_size, int flags)
3455+static struct strategy strategy[] = {
3456+ { "default", Z_DEFAULT_STRATEGY, 0 },
3457+ { "filtered", Z_FILTERED, 0 },
3458+ { "huffman_only", Z_HUFFMAN_ONLY, 0 },
3459+ { "run_length_encoded", Z_RLE, 0 },
3460+ { "fixed", Z_FIXED, 0 },
3461+ { NULL, 0, 0 }
3462+};
3463+
3464+static int strategy_count = 0;
3465+
3466+/* default compression level */
3467+static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
3468+
3469+/* default window size */
3470+static int window_size = GZIP_DEFAULT_WINDOW_SIZE;
3471+
3472+/*
3473+ * This function is called by the options parsing code in mksquashfs.c
3474+ * to parse any -X compressor option.
3475+ *
3476+ * This function returns:
3477+ * >=0 (number of additional args parsed) on success
3478+ * -1 if the option was unrecognised, or
3479+ * -2 if the option was recognised, but otherwise bad in
3480+ * some way (e.g. invalid parameter)
3481+ *
3482+ * Note: this function sets internal compressor state, but does not
3483+ * pass back the results of the parsing other than success/failure.
3484+ * The gzip_dump_options() function is called later to get the options in
3485+ * a format suitable for writing to the filesystem.
3486+ */
3487+static int gzip_options(char *argv[], int argc)
3488 {
3489- int res;
3490- z_stream *stream;
3491+ if(strcmp(argv[0], "-Xcompression-level") == 0) {
3492+ if(argc < 2) {
3493+ fprintf(stderr, "gzip: -Xcompression-level missing "
3494+ "compression level\n");
3495+ fprintf(stderr, "gzip: -Xcompression-level it "
3496+ "should be 1 >= n <= 9\n");
3497+ goto failed;
3498+ }
3499+
3500+ compression_level = atoi(argv[1]);
3501+ if(compression_level < 1 || compression_level > 9) {
3502+ fprintf(stderr, "gzip: -Xcompression-level invalid, it "
3503+ "should be 1 >= n <= 9\n");
3504+ goto failed;
3505+ }
3506+
3507+ return 1;
3508+ } else if(strcmp(argv[0], "-Xwindow-size") == 0) {
3509+ if(argc < 2) {
3510+ fprintf(stderr, "gzip: -Xwindow-size missing window "
3511+ " size\n");
3512+ fprintf(stderr, "gzip: -Xwindow-size <window-size>\n");
3513+ goto failed;
3514+ }
3515+
3516+ window_size = atoi(argv[1]);
3517+ if(window_size < 8 || window_size > 15) {
3518+ fprintf(stderr, "gzip: -Xwindow-size invalid, it "
3519+ "should be 8 >= n <= 15\n");
3520+ goto failed;
3521+ }
3522+
3523+ return 1;
3524+ } else if(strcmp(argv[0], "-Xstrategy") == 0) {
3525+ char *name;
3526+ int i;
3527+
3528+ if(argc < 2) {
3529+ fprintf(stderr, "gzip: -Xstrategy missing "
3530+ "strategies\n");
3531+ goto failed;
3532+ }
3533+
3534+ name = argv[1];
3535+ while(name[0] != '\0') {
3536+ for(i = 0; strategy[i].name; i++) {
3537+ int n = strlen(strategy[i].name);
3538+ if((strncmp(name, strategy[i].name, n) == 0) &&
3539+ (name[n] == '\0' ||
3540+ name[n] == ',')) {
3541+ if(strategy[i].selected == 0) {
3542+ strategy[i].selected = 1;
3543+ strategy_count++;
3544+ }
3545+ name += name[n] == ',' ? n + 1 : n;
3546+ break;
3547+ }
3548+ }
3549+ if(strategy[i].name == NULL) {
3550+ fprintf(stderr, "gzip: -Xstrategy unrecognised "
3551+ "strategy\n");
3552+ goto failed;
3553+ }
3554+ }
3555+
3556+ return 1;
3557+ }
3558+
3559+ return -1;
3560+
3561+failed:
3562+ return -2;
3563+}
3564+
3565+
3566+/*
3567+ * This function is called after all options have been parsed.
3568+ * It is used to do post-processing on the compressor options using
3569+ * values that were not expected to be known at option parse time.
3570+ *
3571+ * This function returns 0 on successful post processing, or
3572+ * -1 on error
3573+ */
3574+static int gzip_options_post(int block_size)
3575+{
3576+ if(strategy_count == 1 && strategy[0].selected) {
3577+ strategy_count = 0;
3578+ strategy[0].selected = 0;
3579+ }
3580+
3581+ return 0;
3582+}
3583+
3584+
3585+/*
3586+ * This function is called by mksquashfs to dump the parsed
3587+ * compressor options in a format suitable for writing to the
3588+ * compressor options field in the filesystem (stored immediately
3589+ * after the superblock).
3590+ *
3591+ * This function returns a pointer to the compression options structure
3592+ * to be stored (and the size), or NULL if there are no compression
3593+ * options
3594+ *
3595+ */
3596+static void *gzip_dump_options(int block_size, int *size)
3597+{
3598+ static struct gzip_comp_opts comp_opts;
3599+ int i, strategies = 0;
3600+
3601+ /*
3602+ * If default compression options of:
3603+ * compression-level: 8 and
3604+ * window-size: 15 and
3605+ * strategy_count == 0 then
3606+ * don't store a compression options structure (this is compatible
3607+ * with the legacy implementation of GZIP for Squashfs)
3608+ */
3609+ if(compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL &&
3610+ window_size == GZIP_DEFAULT_WINDOW_SIZE &&
3611+ strategy_count == 0)
3612+ return NULL;
3613+
3614+ for(i = 0; strategy[i].name; i++)
3615+ strategies |= strategy[i].selected << i;
3616+
3617+ comp_opts.compression_level = compression_level;
3618+ comp_opts.window_size = window_size;
3619+ comp_opts.strategy = strategies;
3620+
3621+ SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
3622+
3623+ *size = sizeof(comp_opts);
3624+ return &comp_opts;
3625+}
3626+
3627+
3628+/*
3629+ * This function is a helper specifically for the append mode of
3630+ * mksquashfs. Its purpose is to set the internal compressor state
3631+ * to the stored compressor options in the passed compressor options
3632+ * structure.
3633+ *
3634+ * In effect this function sets up the compressor options
3635+ * to the same state they were when the filesystem was originally
3636+ * generated, this is to ensure on appending, the compressor uses
3637+ * the same compression options that were used to generate the
3638+ * original filesystem.
3639+ *
3640+ * Note, even if there are no compressor options, this function is still
3641+ * called with an empty compressor structure (size == 0), to explicitly
3642+ * set the default options, this is to ensure any user supplied
3643+ * -X options on the appending mksquashfs command line are over-ridden
3644+ *
3645+ * This function returns 0 on sucessful extraction of options, and
3646+ * -1 on error
3647+ */
3648+static int gzip_extract_options(int block_size, void *buffer, int size)
3649+{
3650+ struct gzip_comp_opts *comp_opts = buffer;
3651+ int i;
3652+
3653+ if(size == 0) {
3654+ /* Set default values */
3655+ compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
3656+ window_size = GZIP_DEFAULT_WINDOW_SIZE;
3657+ strategy_count = 0;
3658+ return 0;
3659+ }
3660+
3661+ /* we expect a comp_opts structure of sufficient size to be present */
3662+ if(size < sizeof(*comp_opts))
3663+ goto failed;
3664+
3665+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
3666+
3667+ /* Check comp_opts structure for correctness */
3668+ if(comp_opts->compression_level < 1 ||
3669+ comp_opts->compression_level > 9) {
3670+ fprintf(stderr, "gzip: bad compression level in "
3671+ "compression options structure\n");
3672+ goto failed;
3673+ }
3674+ compression_level = comp_opts->compression_level;
3675
3676- stream = *strm = malloc(sizeof(z_stream));
3677- if(stream == NULL)
3678+ if(comp_opts->window_size < 8 ||
3679+ comp_opts->window_size > 15) {
3680+ fprintf(stderr, "gzip: bad window size in "
3681+ "compression options structure\n");
3682 goto failed;
3683+ }
3684+ window_size = comp_opts->window_size;
3685+
3686+ strategy_count = 0;
3687+ for(i = 0; strategy[i].name; i++) {
3688+ if((comp_opts->strategy >> i) & 1) {
3689+ strategy[i].selected = 1;
3690+ strategy_count ++;
3691+ } else
3692+ strategy[i].selected = 0;
3693+ }
3694+
3695+ return 0;
3696+
3697+failed:
3698+ fprintf(stderr, "gzip: error reading stored compressor options from "
3699+ "filesystem!\n");
3700+
3701+ return -1;
3702+}
3703+
3704+
3705+void gzip_display_options(void *buffer, int size)
3706+{
3707+ struct gzip_comp_opts *comp_opts = buffer;
3708+ int i, printed;
3709+
3710+ /* we expect a comp_opts structure of sufficient size to be present */
3711+ if(size < sizeof(*comp_opts))
3712+ goto failed;
3713+
3714+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
3715+
3716+ /* Check comp_opts structure for correctness */
3717+ if(comp_opts->compression_level < 1 ||
3718+ comp_opts->compression_level > 9) {
3719+ fprintf(stderr, "gzip: bad compression level in "
3720+ "compression options structure\n");
3721+ goto failed;
3722+ }
3723+ printf("\tcompression-level %d\n", comp_opts->compression_level);
3724+
3725+ if(comp_opts->window_size < 8 ||
3726+ comp_opts->window_size > 15) {
3727+ fprintf(stderr, "gzip: bad window size in "
3728+ "compression options structure\n");
3729+ goto failed;
3730+ }
3731+ printf("\twindow-size %d\n", comp_opts->window_size);
3732+
3733+ for(i = 0, printed = 0; strategy[i].name; i++) {
3734+ if((comp_opts->strategy >> i) & 1) {
3735+ if(printed)
3736+ printf(", ");
3737+ else
3738+ printf("\tStrategies selected: ");
3739+ printf("%s", strategy[i].name);
3740+ printed = 1;
3741+ }
3742+ }
3743+
3744+ if(!printed)
3745+ printf("\tStrategies selected: default\n");
3746+ else
3747+ printf("\n");
3748+
3749+ return;
3750+
3751+failed:
3752+ fprintf(stderr, "gzip: error reading stored compressor options from "
3753+ "filesystem!\n");
3754+}
3755
3756- stream->zalloc = Z_NULL;
3757- stream->zfree = Z_NULL;
3758- stream->opaque = 0;
3759
3760- res = deflateInit(stream, 9);
3761+/*
3762+ * This function is called by mksquashfs to initialise the
3763+ * compressor, before compress() is called.
3764+ *
3765+ * This function returns 0 on success, and
3766+ * -1 on error
3767+ */
3768+static int gzip_init(void **strm, int block_size, int datablock)
3769+{
3770+ int i, j, res;
3771+ struct gzip_stream *stream;
3772+
3773+ if(!datablock || !strategy_count) {
3774+ stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy));
3775+ if(stream == NULL)
3776+ goto failed;
3777+
3778+ stream->strategies = 1;
3779+ stream->strategy[0].strategy = Z_DEFAULT_STRATEGY;
3780+ } else {
3781+ stream = malloc(sizeof(*stream) +
3782+ sizeof(struct gzip_strategy) * strategy_count);
3783+ if(stream == NULL)
3784+ goto failed;
3785+
3786+ memset(stream->strategy, 0, sizeof(struct gzip_strategy) *
3787+ strategy_count);
3788+
3789+ stream->strategies = strategy_count;
3790+
3791+ for(i = 0, j = 0; strategy[i].name; i++) {
3792+ if(!strategy[i].selected)
3793+ continue;
3794+
3795+ stream->strategy[j].strategy = strategy[i].strategy;
3796+ if(j) {
3797+ stream->strategy[j].buffer = malloc(block_size);
3798+ if(stream->strategy[j].buffer == NULL)
3799+ goto failed2;
3800+ }
3801+ j++;
3802+ }
3803+ }
3804+
3805+ stream->stream.zalloc = Z_NULL;
3806+ stream->stream.zfree = Z_NULL;
3807+ stream->stream.opaque = 0;
3808+
3809+ res = deflateInit2(&stream->stream, compression_level, Z_DEFLATED,
3810+ window_size, 8, stream->strategy[0].strategy);
3811 if(res != Z_OK)
3812 goto failed2;
3813
3814+ *strm = stream;
3815 return 0;
3816
3817 failed2:
3818+ for(i = 1; i < stream->strategies; i++)
3819+ free(stream->strategy[i].buffer);
3820 free(stream);
3821 failed:
3822 return -1;
3823@@ -54,29 +396,51 @@
3824 static int gzip_compress(void *strm, void *d, void *s, int size, int block_size,
3825 int *error)
3826 {
3827- int res;
3828- z_stream *stream = strm;
3829-
3830- res = deflateReset(stream);
3831- if(res != Z_OK)
3832- goto failed;
3833-
3834- stream->next_in = s;
3835- stream->avail_in = size;
3836- stream->next_out = d;
3837- stream->avail_out = block_size;
3838+ int i, res;
3839+ struct gzip_stream *stream = strm;
3840+ struct gzip_strategy *selected = NULL;
3841+
3842+ stream->strategy[0].buffer = d;
3843+
3844+ for(i = 0; i < stream->strategies; i++) {
3845+ struct gzip_strategy *strategy = &stream->strategy[i];
3846+
3847+ res = deflateReset(&stream->stream);
3848+ if(res != Z_OK)
3849+ goto failed;
3850+
3851+ stream->stream.next_in = s;
3852+ stream->stream.avail_in = size;
3853+ stream->stream.next_out = strategy->buffer;
3854+ stream->stream.avail_out = block_size;
3855+
3856+ if(stream->strategies > 1) {
3857+ res = deflateParams(&stream->stream,
3858+ compression_level, strategy->strategy);
3859+ if(res != Z_OK)
3860+ goto failed;
3861+ }
3862+
3863+ res = deflate(&stream->stream, Z_FINISH);
3864+ strategy->length = stream->stream.total_out;
3865+ if(res == Z_STREAM_END) {
3866+ if(!selected || selected->length > strategy->length)
3867+ selected = strategy;
3868+ } else if(res != Z_OK)
3869+ goto failed;
3870+ }
3871
3872- res = deflate(stream, Z_FINISH);
3873- if(res == Z_STREAM_END)
3874- /*
3875- * Success, return the compressed size.
3876- */
3877- return (int) stream->total_out;
3878- if(res == Z_OK)
3879+ if(!selected)
3880 /*
3881 * Output buffer overflow. Return out of buffer space
3882 */
3883 return 0;
3884+
3885+ if(selected->buffer != d)
3886+ memcpy(d, selected->buffer, selected->length);
3887+
3888+ return (int) selected->length;
3889+
3890 failed:
3891 /*
3892 * All other errors return failure, with the compressor
3893@@ -94,8 +458,29 @@
3894
3895 res = uncompress(d, &bytes, s, size);
3896
3897- *error = res;
3898- return res == Z_OK ? (int) bytes : -1;
3899+ if(res == Z_OK)
3900+ return (int) bytes;
3901+ else {
3902+ *error = res;
3903+ return -1;
3904+ }
3905+}
3906+
3907+
3908+void gzip_usage()
3909+{
3910+ fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
3911+ fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
3912+ "%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL);
3913+ fprintf(stderr, "\t -Xwindow-size <window-size>\n");
3914+ fprintf(stderr, "\t\t<window-size> should be 8 .. 15 (default "
3915+ "%d)\n", GZIP_DEFAULT_WINDOW_SIZE);
3916+ fprintf(stderr, "\t -Xstrategy strategy1,strategy2,...,strategyN\n");
3917+ fprintf(stderr, "\t\tCompress using strategy1,strategy2,...,strategyN"
3918+ " in turn\n");
3919+ fprintf(stderr, "\t\tand choose the best compression.\n");
3920+ fprintf(stderr, "\t\tAvailable strategies: default, filtered, "
3921+ "huffman_only,\n\t\trun_length_encoded and fixed\n");
3922 }
3923
3924
3925@@ -103,10 +488,13 @@
3926 .init = gzip_init,
3927 .compress = gzip_compress,
3928 .uncompress = gzip_uncompress,
3929- .options = NULL,
3930- .usage = NULL,
3931+ .options = gzip_options,
3932+ .options_post = gzip_options_post,
3933+ .dump_options = gzip_dump_options,
3934+ .extract_options = gzip_extract_options,
3935+ .display_options = gzip_display_options,
3936+ .usage = gzip_usage,
3937 .id = ZLIB_COMPRESSION,
3938 .name = "gzip",
3939 .supported = 1
3940 };
3941-
3942diff -Nru squashfs-tools-4.2+20130409/gzip_wrapper.h squashfs-tools-4.3+20140919/gzip_wrapper.h
3943--- squashfs-tools-4.2+20130409/gzip_wrapper.h 1970-01-01 01:00:00.000000000 +0100
3944+++ squashfs-tools-4.3+20140919/gzip_wrapper.h 2015-07-20 21:03:05.000000000 +0200
3945@@ -0,0 +1,75 @@
3946+#ifndef GZIP_WRAPPER_H
3947+#define GZIP_WRAPPER_H
3948+/*
3949+ * Squashfs
3950+ *
3951+ * Copyright (c) 2014
3952+ * Phillip Lougher <phillip@squashfs.org.uk>
3953+ *
3954+ * This program is free software; you can redistribute it and/or
3955+ * modify it under the terms of the GNU General Public License
3956+ * as published by the Free Software Foundation; either version 2,
3957+ * or (at your option) any later version.
3958+ *
3959+ * This program is distributed in the hope that it will be useful,
3960+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3961+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3962+ * GNU General Public License for more details.
3963+ *
3964+ * You should have received a copy of the GNU General Public License
3965+ * along with this program; if not, write to the Free Software
3966+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3967+ *
3968+ * gzip_wrapper.h
3969+ *
3970+ */
3971+
3972+#ifndef linux
3973+#define __BYTE_ORDER BYTE_ORDER
3974+#define __BIG_ENDIAN BIG_ENDIAN
3975+#define __LITTLE_ENDIAN LITTLE_ENDIAN
3976+#else
3977+#include <endian.h>
3978+#endif
3979+
3980+#if __BYTE_ORDER == __BIG_ENDIAN
3981+extern unsigned int inswap_le16(unsigned short);
3982+extern unsigned int inswap_le32(unsigned int);
3983+
3984+#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
3985+ (s)->compression_level = inswap_le32((s)->compression_level); \
3986+ (s)->window_size = inswap_le16((s)->window_size); \
3987+ (s)->strategy = inswap_le16((s)->strategy); \
3988+}
3989+#else
3990+#define SQUASHFS_INSWAP_COMP_OPTS(s)
3991+#endif
3992+
3993+/* Default compression */
3994+#define GZIP_DEFAULT_COMPRESSION_LEVEL 9
3995+#define GZIP_DEFAULT_WINDOW_SIZE 15
3996+
3997+struct gzip_comp_opts {
3998+ int compression_level;
3999+ short window_size;
4000+ short strategy;
4001+};
4002+
4003+struct strategy {
4004+ char *name;
4005+ int strategy;
4006+ int selected;
4007+};
4008+
4009+struct gzip_strategy {
4010+ int strategy;
4011+ int length;
4012+ void *buffer;
4013+};
4014+
4015+struct gzip_stream {
4016+ z_stream stream;
4017+ int strategies;
4018+ struct gzip_strategy strategy[0];
4019+};
4020+#endif
4021diff -Nru squashfs-tools-4.2+20130409/info.c squashfs-tools-4.3+20140919/info.c
4022--- squashfs-tools-4.2+20130409/info.c 2013-05-09 10:39:11.000000000 +0200
4023+++ squashfs-tools-4.3+20140919/info.c 2015-07-20 21:03:05.000000000 +0200
4024@@ -2,7 +2,7 @@
4025 * Create a squashfs filesystem. This is a highly compressed read only
4026 * filesystem.
4027 *
4028- * Copyright (c) 2013
4029+ * Copyright (c) 2013, 2014
4030 * Phillip Lougher <phillip@squashfs.org.uk>
4031 *
4032 * This program is free software; you can redistribute it and/or
4033@@ -35,55 +35,142 @@
4034 #include <dirent.h>
4035 #include <sys/types.h>
4036 #include <sys/stat.h>
4037+#include <string.h>
4038
4039 #include "squashfs_fs.h"
4040 #include "mksquashfs.h"
4041 #include "error.h"
4042+#include "progressbar.h"
4043+#include "caches-queues-lists.h"
4044
4045 static int silent = 0;
4046-static struct dir_ent *dir_ent = NULL;
4047+static struct dir_ent *ent = NULL;
4048
4049 pthread_t info_thread;
4050
4051
4052 void disable_info()
4053 {
4054- dir_ent = NULL;
4055+ ent = NULL;
4056 }
4057
4058
4059-void update_info(struct dir_ent *ent)
4060+void update_info(struct dir_ent *dir_ent)
4061 {
4062- dir_ent = ent;
4063+ ent = dir_ent;
4064+}
4065+
4066+
4067+void print_filename()
4068+{
4069+ struct dir_ent *dir_ent = ent;
4070+
4071+ if(dir_ent == NULL)
4072+ return;
4073+
4074+ if(dir_ent->our_dir->subpath[0] != '\0')
4075+ INFO("%s/%s\n", dir_ent->our_dir->subpath, dir_ent->name);
4076+ else
4077+ INFO("/%s\n", dir_ent->name);
4078+}
4079+
4080+
4081+void dump_state()
4082+{
4083+ disable_progress_bar();
4084+
4085+ printf("Queue and Cache status dump\n");
4086+ printf("===========================\n");
4087+
4088+ printf("file buffer queue (reader thread -> deflate thread(s))\n");
4089+ dump_queue(to_deflate);
4090+
4091+ printf("uncompressed fragment queue (reader thread -> fragment"
4092+ " thread(s))\n");
4093+ dump_queue(to_process_frag);
4094+
4095+ printf("processed fragment queue (fragment thread(s) -> main"
4096+ " thread)\n");
4097+ dump_seq_queue(to_main, 1);
4098+
4099+ printf("compressed block queue (deflate thread(s) -> main thread)\n");
4100+ dump_seq_queue(to_main, 0);
4101+
4102+ printf("uncompressed packed fragment queue (main thread -> fragment"
4103+ " deflate thread(s))\n");
4104+ dump_queue(to_frag);
4105+
4106+
4107+ printf("locked frag queue (compressed frags waiting while multi-block"
4108+ " file is written)\n");
4109+ dump_queue(locked_fragment);
4110+
4111+ printf("compressed block queue (main & fragment deflate threads(s) ->"
4112+ " writer thread)\n");
4113+ dump_queue(to_writer);
4114+
4115+ printf("read cache (uncompressed blocks read by reader thread)\n");
4116+ dump_cache(reader_buffer);
4117+
4118+ printf("block write cache (compressed blocks waiting for the writer"
4119+ " thread)\n");
4120+ dump_cache(bwriter_buffer);
4121+ printf("fragment write cache (compressed fragments waiting for the"
4122+ " writer thread)\n");
4123+ dump_cache(fwriter_buffer);
4124+
4125+ printf("fragment cache (frags waiting to be compressed by fragment"
4126+ " deflate thread(s))\n");
4127+ dump_cache(fragment_buffer);
4128+
4129+ printf("fragment reserve cache (avoids pipeline stall if frag cache"
4130+ " full in dup check)\n");
4131+ dump_cache(reserve_cache);
4132+
4133+ enable_progress_bar();
4134 }
4135
4136
4137 void *info_thrd(void *arg)
4138 {
4139 sigset_t sigmask;
4140- int sig, res;
4141- char *subpath;
4142+ struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
4143+ int sig, waiting = 0;
4144
4145 sigemptyset(&sigmask);
4146 sigaddset(&sigmask, SIGQUIT);
4147+ sigaddset(&sigmask, SIGHUP);
4148
4149 while(1) {
4150- sigwait(&sigmask, &sig);
4151-
4152- if(dir_ent == NULL)
4153- continue;
4154-
4155- if(dir_ent->our_dir->subpath[0] != '\0')
4156- res = asprintf(&subpath, "%s/%s",
4157- dir_ent->our_dir->subpath, dir_ent->name);
4158+ if(waiting)
4159+ sig = sigtimedwait(&sigmask, NULL, ×pec);
4160 else
4161- res = asprintf(&subpath, "/%s", dir_ent->name);
4162-
4163- if(res < 0)
4164- printf("asprintf failed in info_thrd\n");
4165+ sig = sigwaitinfo(&sigmask, NULL);
4166
4167- INFO("%s\n", subpath);
4168- free(subpath);
4169+ if(sig == -1) {
4170+ switch(errno) {
4171+ case EAGAIN:
4172+ /* interval timed out */
4173+ waiting = 0;
4174+ /* FALLTHROUGH */
4175+ case EINTR:
4176+ /* if waiting, the wait will be longer, but
4177+ that's OK */
4178+ continue;
4179+ default:
4180+ BAD_ERROR("sigtimedwait/sigwaitinfo failed "
4181+ "because %s\n", strerror(errno));
4182+ }
4183+ }
4184+
4185+ if(sig == SIGQUIT && !waiting) {
4186+ print_filename();
4187+
4188+ /* set one second interval period, if ^\ received
4189+ within then, dump queue and cache status */
4190+ waiting = 1;
4191+ } else
4192+ dump_state();
4193 }
4194 }
4195
4196diff -Nru squashfs-tools-4.2+20130409/info.h squashfs-tools-4.3+20140919/info.h
4197--- squashfs-tools-4.2+20130409/info.h 2013-05-09 10:39:11.000000000 +0200
4198+++ squashfs-tools-4.3+20140919/info.h 2015-07-20 21:03:05.000000000 +0200
4199@@ -1,8 +1,10 @@
4200+#ifndef INFO_H
4201+#define INFO_H
4202 /*
4203 * Create a squashfs filesystem. This is a highly compressed read only
4204 * filesystem.
4205 *
4206- * Copyright (c) 2013
4207+ * Copyright (c) 2013, 2014
4208 * Phillip Lougher <phillip@squashfs.org.uk>
4209 *
4210 * This program is free software; you can redistribute it and/or
4211@@ -23,5 +25,6 @@
4212 */
4213
4214 extern void disable_info();
4215-extern void update_info();
4216+extern void update_info(struct dir_ent *);
4217 extern void init_info();
4218+#endif
4219diff -Nru squashfs-tools-4.2+20130409/lz4_wrapper.c squashfs-tools-4.3+20140919/lz4_wrapper.c
4220--- squashfs-tools-4.2+20130409/lz4_wrapper.c 1970-01-01 01:00:00.000000000 +0100
4221+++ squashfs-tools-4.3+20140919/lz4_wrapper.c 2015-07-20 21:03:05.000000000 +0200
4222@@ -0,0 +1,283 @@
4223+/*
4224+ * Copyright (c) 2013
4225+ * Phillip Lougher <phillip@squashfs.org.uk>
4226+ *
4227+ * This program is free software; you can redistribute it and/or
4228+ * modify it under the terms of the GNU General Public License
4229+ * as published by the Free Software Foundation; either version 2,
4230+ * or (at your option) any later version.
4231+ *
4232+ * This program is distributed in the hope that it will be useful,
4233+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4234+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4235+ * GNU General Public License for more details.
4236+ *
4237+ * You should have received a copy of the GNU General Public License
4238+ * along with this program; if not, write to the Free Software
4239+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4240+ *
4241+ * lz4_wrapper.c
4242+ *
4243+ * Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html
4244+ */
4245+
4246+#include <stdio.h>
4247+#include <string.h>
4248+#include <stdlib.h>
4249+#include <lz4.h>
4250+#include <lz4hc.h>
4251+
4252+#include "squashfs_fs.h"
4253+#include "lz4_wrapper.h"
4254+#include "compressor.h"
4255+
4256+static int hc = 0;
4257+
4258+/*
4259+ * This function is called by the options parsing code in mksquashfs.c
4260+ * to parse any -X compressor option.
4261+ *
4262+ * This function returns:
4263+ * >=0 (number of additional args parsed) on success
4264+ * -1 if the option was unrecognised, or
4265+ * -2 if the option was recognised, but otherwise bad in
4266+ * some way (e.g. invalid parameter)
4267+ *
4268+ * Note: this function sets internal compressor state, but does not
4269+ * pass back the results of the parsing other than success/failure.
4270+ * The lz4_dump_options() function is called later to get the options in
4271+ * a format suitable for writing to the filesystem.
4272+ */
4273+static int lz4_options(char *argv[], int argc)
4274+{
4275+ if(strcmp(argv[0], "-Xhc") == 0) {
4276+ hc = 1;
4277+ return 0;
4278+ }
4279+
4280+ return -1;
4281+}
4282+
4283+
4284+/*
4285+ * This function is called by mksquashfs to dump the parsed
4286+ * compressor options in a format suitable for writing to the
4287+ * compressor options field in the filesystem (stored immediately
4288+ * after the superblock).
4289+ *
4290+ * This function returns a pointer to the compression options structure
4291+ * to be stored (and the size), or NULL if there are no compression
4292+ * options
4293+ *
4294+ * Currently LZ4 always returns a comp_opts structure, with
4295+ * the version indicating LZ4_LEGACY stream fomat. This is to
4296+ * easily accomodate changes in the kernel code to different
4297+ * stream formats
4298+ */
4299+static void *lz4_dump_options(int block_size, int *size)
4300+{
4301+ static struct lz4_comp_opts comp_opts;
4302+
4303+ comp_opts.version = LZ4_LEGACY;
4304+ comp_opts.flags = hc ? LZ4_HC : 0;
4305+ SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
4306+
4307+ *size = sizeof(comp_opts);
4308+ return &comp_opts;
4309+}
4310+
4311+
4312+/*
4313+ * This function is a helper specifically for the append mode of
4314+ * mksquashfs. Its purpose is to set the internal compressor state
4315+ * to the stored compressor options in the passed compressor options
4316+ * structure.
4317+ *
4318+ * In effect this function sets up the compressor options
4319+ * to the same state they were when the filesystem was originally
4320+ * generated, this is to ensure on appending, the compressor uses
4321+ * the same compression options that were used to generate the
4322+ * original filesystem.
4323+ *
4324+ * Note, even if there are no compressor options, this function is still
4325+ * called with an empty compressor structure (size == 0), to explicitly
4326+ * set the default options, this is to ensure any user supplied
4327+ * -X options on the appending mksquashfs command line are over-ridden
4328+ *
4329+ * This function returns 0 on sucessful extraction of options, and
4330+ * -1 on error
4331+ */
4332+static int lz4_extract_options(int block_size, void *buffer, int size)
4333+{
4334+ struct lz4_comp_opts *comp_opts = buffer;
4335+
4336+ /* we expect a comp_opts structure to be present */
4337+ if(size < sizeof(*comp_opts))
4338+ goto failed;
4339+
4340+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
4341+
4342+ /* we expect the stream format to be LZ4_LEGACY */
4343+ if(comp_opts->version != LZ4_LEGACY) {
4344+ fprintf(stderr, "lz4: unknown LZ4 version\n");
4345+ goto failed;
4346+ }
4347+
4348+ /*
4349+ * Check compression flags, currently only LZ4_HC ("high compression")
4350+ * can be set.
4351+ */
4352+ if(comp_opts->flags == LZ4_HC)
4353+ hc = 1;
4354+ else if(comp_opts->flags != 0) {
4355+ fprintf(stderr, "lz4: unknown LZ4 flags\n");
4356+ goto failed;
4357+ }
4358+
4359+ return 0;
4360+
4361+failed:
4362+ fprintf(stderr, "lz4: error reading stored compressor options from "
4363+ "filesystem!\n");
4364+
4365+ return -1;
4366+}
4367+
4368+
4369+/*
4370+ * This function is a helper specifically for unsquashfs.
4371+ * Its purpose is to check that the compression options are
4372+ * understood by this version of LZ4.
4373+ *
4374+ * This is important for LZ4 because the format understood by the
4375+ * Linux kernel may change from the already obsolete legacy format
4376+ * currently supported.
4377+ *
4378+ * If this does happen, then this version of LZ4 will not be able to decode
4379+ * the newer format. So we need to check for this.
4380+ *
4381+ * This function returns 0 on sucessful checking of options, and
4382+ * -1 on error
4383+ */
4384+static int lz4_check_options(int block_size, void *buffer, int size)
4385+{
4386+ struct lz4_comp_opts *comp_opts = buffer;
4387+
4388+ /* we expect a comp_opts structure to be present */
4389+ if(size < sizeof(*comp_opts))
4390+ goto failed;
4391+
4392+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
4393+
4394+ /* we expect the stream format to be LZ4_LEGACY */
4395+ if(comp_opts->version != LZ4_LEGACY) {
4396+ fprintf(stderr, "lz4: unknown LZ4 version\n");
4397+ goto failed;
4398+ }
4399+
4400+ return 0;
4401+
4402+failed:
4403+ fprintf(stderr, "lz4: error reading stored compressor options from "
4404+ "filesystem!\n");
4405+ return -1;
4406+}
4407+
4408+
4409+void lz4_display_options(void *buffer, int size)
4410+{
4411+ struct lz4_comp_opts *comp_opts = buffer;
4412+
4413+ /* check passed comp opts struct is of the correct length */
4414+ if(size < sizeof(*comp_opts))
4415+ goto failed;
4416+
4417+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
4418+
4419+ /* we expect the stream format to be LZ4_LEGACY */
4420+ if(comp_opts->version != LZ4_LEGACY) {
4421+ fprintf(stderr, "lz4: unknown LZ4 version\n");
4422+ goto failed;
4423+ }
4424+
4425+ /*
4426+ * Check compression flags, currently only LZ4_HC ("high compression")
4427+ * can be set.
4428+ */
4429+ if(comp_opts->flags & ~LZ4_FLAGS_MASK) {
4430+ fprintf(stderr, "lz4: unknown LZ4 flags\n");
4431+ goto failed;
4432+ }
4433+
4434+ if(comp_opts->flags & LZ4_HC)
4435+ printf("\tHigh Compression option specified (-Xhc)\n");
4436+
4437+ return;
4438+
4439+failed:
4440+ fprintf(stderr, "lz4: error reading stored compressor options from "
4441+ "filesystem!\n");
4442+}
4443+
4444+
4445+static int lz4_compress(void *strm, void *dest, void *src, int size,
4446+ int block_size, int *error)
4447+{
4448+ int res;
4449+
4450+ if(hc)
4451+ res = LZ4_compressHC_limitedOutput(src, dest, size, block_size);
4452+ else
4453+ res = LZ4_compress_limitedOutput(src, dest, size, block_size);
4454+
4455+ if(res == 0) {
4456+ /*
4457+ * Output buffer overflow. Return out of buffer space
4458+ */
4459+ return 0;
4460+ } else if(res < 0) {
4461+ /*
4462+ * All other errors return failure, with the compressor
4463+ * specific error code in *error
4464+ */
4465+ *error = res;
4466+ return -1;
4467+ }
4468+
4469+ return res;
4470+}
4471+
4472+
4473+static int lz4_uncompress(void *dest, void *src, int size, int outsize,
4474+ int *error)
4475+{
4476+ int res = LZ4_decompress_safe(src, dest, size, outsize);
4477+ if(res < 0) {
4478+ *error = res;
4479+ return -1;
4480+ }
4481+
4482+ return res;
4483+}
4484+
4485+
4486+void lz4_usage()
4487+{
4488+ fprintf(stderr, "\t -Xhc\n");
4489+ fprintf(stderr, "\t\tCompress using LZ4 High Compression\n");
4490+}
4491+
4492+
4493+struct compressor lz4_comp_ops = {
4494+ .compress = lz4_compress,
4495+ .uncompress = lz4_uncompress,
4496+ .options = lz4_options,
4497+ .dump_options = lz4_dump_options,
4498+ .extract_options = lz4_extract_options,
4499+ .check_options = lz4_check_options,
4500+ .display_options = lz4_display_options,
4501+ .usage = lz4_usage,
4502+ .id = LZ4_COMPRESSION,
4503+ .name = "lz4",
4504+ .supported = 1
4505+};
4506diff -Nru squashfs-tools-4.2+20130409/lz4_wrapper.h squashfs-tools-4.3+20140919/lz4_wrapper.h
4507--- squashfs-tools-4.2+20130409/lz4_wrapper.h 1970-01-01 01:00:00.000000000 +0100
4508+++ squashfs-tools-4.3+20140919/lz4_wrapper.h 2015-07-20 21:03:05.000000000 +0200
4509@@ -0,0 +1,61 @@
4510+#ifndef LZ4_WRAPPER_H
4511+#define LZ4_WRAPPER_H
4512+/*
4513+ * Squashfs
4514+ *
4515+ * Copyright (c) 2013
4516+ * Phillip Lougher <phillip@squashfs.org.uk>
4517+ *
4518+ * This program is free software; you can redistribute it and/or
4519+ * modify it under the terms of the GNU General Public License
4520+ * as published by the Free Software Foundation; either version 2,
4521+ * or (at your option) any later version.
4522+ *
4523+ * This program is distributed in the hope that it will be useful,
4524+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4525+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4526+ * GNU General Public License for more details.
4527+ *
4528+ * You should have received a copy of the GNU General Public License
4529+ * along with this program; if not, write to the Free Software
4530+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4531+ *
4532+ * lz4_wrapper.h
4533+ *
4534+ */
4535+
4536+#ifndef linux
4537+#define __BYTE_ORDER BYTE_ORDER
4538+#define __BIG_ENDIAN BIG_ENDIAN
4539+#define __LITTLE_ENDIAN LITTLE_ENDIAN
4540+#else
4541+#include <endian.h>
4542+#endif
4543+
4544+#if __BYTE_ORDER == __BIG_ENDIAN
4545+extern unsigned int inswap_le32(unsigned int);
4546+
4547+#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
4548+ (s)->version = inswap_le32((s)->version); \
4549+ (s)->flags = inswap_le32((s)->flags); \
4550+}
4551+#else
4552+#define SQUASHFS_INSWAP_COMP_OPTS(s)
4553+#endif
4554+
4555+/*
4556+ * Define the various stream formats recognised.
4557+ * Currently omly legacy stream format is supported by the
4558+ * kernel
4559+ */
4560+#define LZ4_LEGACY 1
4561+#define LZ4_FLAGS_MASK 1
4562+
4563+/* Define the compression flags recognised. */
4564+#define LZ4_HC 1
4565+
4566+struct lz4_comp_opts {
4567+ int version;
4568+ int flags;
4569+};
4570+#endif
4571diff -Nru squashfs-tools-4.2+20130409/lzma_wrapper.c squashfs-tools-4.3+20140919/lzma_wrapper.c
4572--- squashfs-tools-4.2+20130409/lzma_wrapper.c 2013-05-09 10:39:11.000000000 +0200
4573+++ squashfs-tools-4.3+20140919/lzma_wrapper.c 2015-07-20 21:03:05.000000000 +0200
4574@@ -99,8 +99,12 @@
4575 res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src,
4576 LZMA_PROPS_SIZE);
4577
4578- *error = res;
4579- return res == SZ_OK ? outlen : -1;
4580+ if(res == SZ_OK)
4581+ return outlen;
4582+ else {
4583+ *error = res;
4584+ return -1;
4585+ }
4586 }
4587
4588
4589diff -Nru squashfs-tools-4.2+20130409/lzo_wrapper.c squashfs-tools-4.3+20140919/lzo_wrapper.c
4590--- squashfs-tools-4.2+20130409/lzo_wrapper.c 2013-05-09 10:39:11.000000000 +0200
4591+++ squashfs-tools-4.3+20140919/lzo_wrapper.c 2015-07-20 21:03:05.000000000 +0200
4592@@ -1,8 +1,5 @@
4593 /*
4594- * Copyright (c) 2010 LG Electronics
4595- * Chan Jeong <chan.jeong@lge.com>
4596- *
4597- * All modifications Copyright (c) 2010, 2013
4598+ * Copyright (c) 2013, 2014
4599 * Phillip Lougher <phillip@squashfs.org.uk>
4600 *
4601 * This program is free software; you can redistribute it and/or
4602@@ -20,44 +17,319 @@
4603 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4604 *
4605 * lzo_wrapper.c
4606+ *
4607+ * Support for LZO compression http://www.oberhumer.com/opensource/lzo
4608 */
4609
4610-#include <stdlib.h>
4611+#include <stdio.h>
4612 #include <string.h>
4613-
4614+#include <stdlib.h>
4615 #include <lzo/lzoconf.h>
4616 #include <lzo/lzo1x.h>
4617
4618 #include "squashfs_fs.h"
4619+#include "lzo_wrapper.h"
4620 #include "compressor.h"
4621
4622-/* worst-case expansion calculation during compression,
4623- see LZO FAQ for more information */
4624-#define LZO_OUTPUT_BUFFER_SIZE(size) (size + (size/16) + 64 + 3)
4625-
4626-struct lzo_stream {
4627- lzo_voidp wrkmem;
4628- lzo_bytep out;
4629+static struct lzo_algorithm lzo[] = {
4630+ { "lzo1x_1", LZO1X_1_MEM_COMPRESS, lzo1x_1_compress },
4631+ { "lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS, lzo1x_1_11_compress },
4632+ { "lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS, lzo1x_1_12_compress },
4633+ { "lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS, lzo1x_1_15_compress },
4634+ { "lzo1x_999", LZO1X_999_MEM_COMPRESS, lzo1x_999_wrapper },
4635+ { NULL, 0, NULL }
4636 };
4637
4638+/* default LZO compression algorithm and compression level */
4639+static int algorithm = SQUASHFS_LZO1X_999;
4640+static int compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
4641+
4642+/* user specified compression level */
4643+static int user_comp_level = -1;
4644+
4645+
4646+/*
4647+ * This function is called by the options parsing code in mksquashfs.c
4648+ * to parse any -X compressor option.
4649+ *
4650+ * This function returns:
4651+ * >=0 (number of additional args parsed) on success
4652+ * -1 if the option was unrecognised, or
4653+ * -2 if the option was recognised, but otherwise bad in
4654+ * some way (e.g. invalid parameter)
4655+ *
4656+ * Note: this function sets internal compressor state, but does not
4657+ * pass back the results of the parsing other than success/failure.
4658+ * The lzo_dump_options() function is called later to get the options in
4659+ * a format suitable for writing to the filesystem.
4660+ */
4661+static int lzo_options(char *argv[], int argc)
4662+{
4663+ int i;
4664+
4665+ if(strcmp(argv[0], "-Xalgorithm") == 0) {
4666+ if(argc < 2) {
4667+ fprintf(stderr, "lzo: -Xalgorithm missing algorithm\n");
4668+ fprintf(stderr, "lzo: -Xalgorithm <algorithm>\n");
4669+ goto failed2;
4670+ }
4671+
4672+ for(i = 0; lzo[i].name; i++) {
4673+ if(strcmp(argv[1], lzo[i].name) == 0) {
4674+ algorithm = i;
4675+ return 1;
4676+ }
4677+ }
4678+
4679+ fprintf(stderr, "lzo: -Xalgorithm unrecognised algorithm\n");
4680+ goto failed2;
4681+ } else if(strcmp(argv[0], "-Xcompression-level") == 0) {
4682+ if(argc < 2) {
4683+ fprintf(stderr, "lzo: -Xcompression-level missing "
4684+ "compression level\n");
4685+ fprintf(stderr, "lzo: -Xcompression-level it "
4686+ "should be 1 >= n <= 9\n");
4687+ goto failed;
4688+ }
4689+
4690+ user_comp_level = atoi(argv[1]);
4691+ if(user_comp_level < 1 || user_comp_level > 9) {
4692+ fprintf(stderr, "lzo: -Xcompression-level invalid, it "
4693+ "should be 1 >= n <= 9\n");
4694+ goto failed;
4695+ }
4696+
4697+ return 1;
4698+ }
4699+
4700+ return -1;
4701
4702-static int squashfs_lzo_init(void **strm, int block_size, int flags)
4703+failed:
4704+ return -2;
4705+
4706+failed2:
4707+ fprintf(stderr, "lzo: compression algorithm should be one of:\n");
4708+ for(i = 0; lzo[i].name; i++)
4709+ fprintf(stderr, "\t%s\n", lzo[i].name);
4710+ return -2;
4711+}
4712+
4713+
4714+/*
4715+ * This function is called after all options have been parsed.
4716+ * It is used to do post-processing on the compressor options using
4717+ * values that were not expected to be known at option parse time.
4718+ *
4719+ * In this case the LZO algorithm may not be known until after the
4720+ * compression level has been set (-Xalgorithm used after -Xcompression-level)
4721+ *
4722+ * This function returns 0 on successful post processing, or
4723+ * -1 on error
4724+ */
4725+static int lzo_options_post(int block_size)
4726+{
4727+ /*
4728+ * Use of compression level only makes sense for
4729+ * LZO1X_999 algorithm
4730+ */
4731+ if(user_comp_level != -1) {
4732+ if(algorithm != SQUASHFS_LZO1X_999) {
4733+ fprintf(stderr, "lzo: -Xcompression-level not "
4734+ "supported by selected %s algorithm\n",
4735+ lzo[algorithm].name);
4736+ fprintf(stderr, "lzo: -Xcompression-level is only "
4737+ "applicable for the lzo1x_999 algorithm\n");
4738+ goto failed;
4739+ }
4740+ compression_level = user_comp_level;
4741+ }
4742+
4743+ return 0;
4744+
4745+failed:
4746+ return -1;
4747+}
4748+
4749+
4750+/*
4751+ * This function is called by mksquashfs to dump the parsed
4752+ * compressor options in a format suitable for writing to the
4753+ * compressor options field in the filesystem (stored immediately
4754+ * after the superblock).
4755+ *
4756+ * This function returns a pointer to the compression options structure
4757+ * to be stored (and the size), or NULL if there are no compression
4758+ * options
4759+ *
4760+ */
4761+static void *lzo_dump_options(int block_size, int *size)
4762+{
4763+ static struct lzo_comp_opts comp_opts;
4764+
4765+ /*
4766+ * If default compression options of SQUASHFS_LZO1X_999 and
4767+ * compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then
4768+ * don't store a compression options structure (this is compatible
4769+ * with the legacy implementation of LZO for Squashfs)
4770+ */
4771+ if(algorithm == SQUASHFS_LZO1X_999 &&
4772+ compression_level == SQUASHFS_LZO1X_999_COMP_DEFAULT)
4773+ return NULL;
4774+
4775+ comp_opts.algorithm = algorithm;
4776+ comp_opts.compression_level = algorithm == SQUASHFS_LZO1X_999 ?
4777+ compression_level : 0;
4778+
4779+ SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
4780+
4781+ *size = sizeof(comp_opts);
4782+ return &comp_opts;
4783+}
4784+
4785+
4786+/*
4787+ * This function is a helper specifically for the append mode of
4788+ * mksquashfs. Its purpose is to set the internal compressor state
4789+ * to the stored compressor options in the passed compressor options
4790+ * structure.
4791+ *
4792+ * In effect this function sets up the compressor options
4793+ * to the same state they were when the filesystem was originally
4794+ * generated, this is to ensure on appending, the compressor uses
4795+ * the same compression options that were used to generate the
4796+ * original filesystem.
4797+ *
4798+ * Note, even if there are no compressor options, this function is still
4799+ * called with an empty compressor structure (size == 0), to explicitly
4800+ * set the default options, this is to ensure any user supplied
4801+ * -X options on the appending mksquashfs command line are over-ridden
4802+ *
4803+ * This function returns 0 on sucessful extraction of options, and
4804+ * -1 on error
4805+ */
4806+static int lzo_extract_options(int block_size, void *buffer, int size)
4807+{
4808+ struct lzo_comp_opts *comp_opts = buffer;
4809+
4810+ if(size == 0) {
4811+ /* Set default values */
4812+ algorithm = SQUASHFS_LZO1X_999;
4813+ compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
4814+ return 0;
4815+ }
4816+
4817+ /* we expect a comp_opts structure of sufficient size to be present */
4818+ if(size < sizeof(*comp_opts))
4819+ goto failed;
4820+
4821+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
4822+
4823+ /* Check comp_opts structure for correctness */
4824+ switch(comp_opts->algorithm) {
4825+ case SQUASHFS_LZO1X_1:
4826+ case SQUASHFS_LZO1X_1_11:
4827+ case SQUASHFS_LZO1X_1_12:
4828+ case SQUASHFS_LZO1X_1_15:
4829+ if(comp_opts->compression_level != 0) {
4830+ fprintf(stderr, "lzo: bad compression level in "
4831+ "compression options structure\n");
4832+ goto failed;
4833+ }
4834+ break;
4835+ case SQUASHFS_LZO1X_999:
4836+ if(comp_opts->compression_level < 1 ||
4837+ comp_opts->compression_level > 9) {
4838+ fprintf(stderr, "lzo: bad compression level in "
4839+ "compression options structure\n");
4840+ goto failed;
4841+ }
4842+ compression_level = comp_opts->compression_level;
4843+ break;
4844+ default:
4845+ fprintf(stderr, "lzo: bad algorithm in compression options "
4846+ "structure\n");
4847+ goto failed;
4848+ }
4849+
4850+ algorithm = comp_opts->algorithm;
4851+
4852+ return 0;
4853+
4854+failed:
4855+ fprintf(stderr, "lzo: error reading stored compressor options from "
4856+ "filesystem!\n");
4857+
4858+ return -1;
4859+}
4860+
4861+
4862+void lzo_display_options(void *buffer, int size)
4863+{
4864+ struct lzo_comp_opts *comp_opts = buffer;
4865+
4866+ /* we expect a comp_opts structure of sufficient size to be present */
4867+ if(size < sizeof(*comp_opts))
4868+ goto failed;
4869+
4870+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
4871+
4872+ /* Check comp_opts structure for correctness */
4873+ switch(comp_opts->algorithm) {
4874+ case SQUASHFS_LZO1X_1:
4875+ case SQUASHFS_LZO1X_1_11:
4876+ case SQUASHFS_LZO1X_1_12:
4877+ case SQUASHFS_LZO1X_1_15:
4878+ printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
4879+ break;
4880+ case SQUASHFS_LZO1X_999:
4881+ if(comp_opts->compression_level < 1 ||
4882+ comp_opts->compression_level > 9) {
4883+ fprintf(stderr, "lzo: bad compression level in "
4884+ "compression options structure\n");
4885+ goto failed;
4886+ }
4887+ printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
4888+ printf("\tcompression level %d\n",
4889+ comp_opts->compression_level);
4890+ break;
4891+ default:
4892+ fprintf(stderr, "lzo: bad algorithm in compression options "
4893+ "structure\n");
4894+ goto failed;
4895+ }
4896+
4897+ return;
4898+
4899+failed:
4900+ fprintf(stderr, "lzo: error reading stored compressor options from "
4901+ "filesystem!\n");
4902+}
4903+
4904+
4905+/*
4906+ * This function is called by mksquashfs to initialise the
4907+ * compressor, before compress() is called.
4908+ *
4909+ * This function returns 0 on success, and
4910+ * -1 on error
4911+ */
4912+static int squashfs_lzo_init(void **strm, int block_size, int datablock)
4913 {
4914 struct lzo_stream *stream;
4915
4916- if((stream = *strm = malloc(sizeof(struct lzo_stream))) == NULL)
4917+ stream = *strm = malloc(sizeof(struct lzo_stream));
4918+ if(stream == NULL)
4919 goto failed;
4920- /* work memory for compression */
4921- if((stream->wrkmem = malloc(LZO1X_999_MEM_COMPRESS)) == NULL)
4922+
4923+ stream->workspace = malloc(lzo[algorithm].size);
4924+ if(stream->workspace == NULL)
4925 goto failed2;
4926- /* temporal output buffer */
4927- if((stream->out = malloc(LZO_OUTPUT_BUFFER_SIZE(block_size))) == NULL)
4928- goto failed3;
4929
4930- return 0;
4931+ stream->buffer = malloc(LZO_MAX_EXPANSION(block_size));
4932+ if(stream->buffer != NULL)
4933+ return 0;
4934
4935-failed3:
4936- free(stream->wrkmem);
4937+ free(stream->workspace);
4938 failed2:
4939 free(stream);
4940 failed:
4941@@ -65,47 +337,89 @@
4942 }
4943
4944
4945-static int lzo_compress(void *strm, void *d, void *s, int size, int block_size,
4946- int *error)
4947+static int lzo_compress(void *strm, void *dest, void *src, int size,
4948+ int block_size, int *error)
4949 {
4950 int res;
4951- lzo_uint outlen;
4952+ lzo_uint compsize, orig_size = size;
4953 struct lzo_stream *stream = strm;
4954
4955- res = lzo1x_999_compress(s, size, stream->out, &outlen, stream->wrkmem);
4956+ res = lzo[algorithm].compress(src, size, stream->buffer, &compsize,
4957+ stream->workspace);
4958 if(res != LZO_E_OK)
4959- goto failed;
4960- if(outlen >= size)
4961- /*
4962- * Output buffer overflow. Return out of buffer space
4963- */
4964- return 0;
4965+ goto failed;
4966
4967- /*
4968- * Success, return the compressed size.
4969+ /* Successful compression, however, we need to check that
4970+ * the compressed size is not larger than the available
4971+ * buffer space. Normally in other compressor APIs they take
4972+ * a destination buffer size, and overflows return an error.
4973+ * With LZO it lacks a destination size and so we must output
4974+ * to a temporary buffer large enough to accomodate any
4975+ * result, and explictly check here for overflow
4976 */
4977- memcpy(d, stream->out, outlen);
4978- return outlen;
4979+ if(compsize > block_size)
4980+ return 0;
4981+
4982+ res = lzo1x_optimize(stream->buffer, compsize, src, &orig_size, NULL);
4983+
4984+ if (res != LZO_E_OK || orig_size != size)
4985+ goto failed;
4986+
4987+ memcpy(dest, stream->buffer, compsize);
4988+ return compsize;
4989
4990 failed:
4991- /*
4992- * All other errors return failure, with the compressor
4993- * specific error code in *error
4994- */
4995+ /* fail, compressor specific error code returned in error */
4996 *error = res;
4997 return -1;
4998 }
4999
5000
5001-static int lzo_uncompress(void *d, void *s, int size, int outsize, int *error)
5002+static int lzo_uncompress(void *dest, void *src, int size, int outsize,
5003+ int *error)
5004 {
5005 int res;
5006- lzo_uint bytes = outsize;
5007+ lzo_uint outlen = outsize;
5008
5009- res = lzo1x_decompress_safe(s, size, d, &bytes, NULL);
5010+ res = lzo1x_decompress_safe(src, size, dest, &outlen, NULL);
5011+ if(res != LZO_E_OK) {
5012+ *error = res;
5013+ return -1;
5014+ }
5015
5016- *error = res;
5017- return res == LZO_E_OK ? bytes : -1;
5018+ return outlen;
5019+}
5020+
5021+
5022+void lzo_usage()
5023+{
5024+ int i;
5025+
5026+ fprintf(stderr, "\t -Xalgorithm <algorithm>\n");
5027+ fprintf(stderr, "\t\tWhere <algorithm> is one of:\n");
5028+
5029+ for(i = 0; lzo[i].name; i++)
5030+ fprintf(stderr, "\t\t\t%s%s\n", lzo[i].name,
5031+ i == SQUASHFS_LZO1X_999 ? " (default)" : "");
5032+
5033+ fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
5034+ fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
5035+ "%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT);
5036+ fprintf(stderr, "\t\tOnly applies to lzo1x_999 algorithm\n");
5037+}
5038+
5039+
5040+/*
5041+ * Helper function for lzo1x_999 compression algorithm.
5042+ * All other lzo1x_xxx compressors do not take a compression level,
5043+ * so we need to wrap lzo1x_999 to pass the compression level which
5044+ * is applicable to it
5045+ */
5046+int lzo1x_999_wrapper(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst,
5047+ lzo_uintp compsize, lzo_voidp workspace)
5048+{
5049+ return lzo1x_999_compress_level(src, src_len, dst, compsize,
5050+ workspace, NULL, 0, 0, compression_level);
5051 }
5052
5053
5054@@ -113,10 +427,13 @@
5055 .init = squashfs_lzo_init,
5056 .compress = lzo_compress,
5057 .uncompress = lzo_uncompress,
5058- .options = NULL,
5059- .usage = NULL,
5060+ .options = lzo_options,
5061+ .options_post = lzo_options_post,
5062+ .dump_options = lzo_dump_options,
5063+ .extract_options = lzo_extract_options,
5064+ .display_options = lzo_display_options,
5065+ .usage = lzo_usage,
5066 .id = LZO_COMPRESSION,
5067 .name = "lzo",
5068 .supported = 1
5069 };
5070-
5071diff -Nru squashfs-tools-4.2+20130409/lzo_wrapper.h squashfs-tools-4.3+20140919/lzo_wrapper.h
5072--- squashfs-tools-4.2+20130409/lzo_wrapper.h 1970-01-01 01:00:00.000000000 +0100
5073+++ squashfs-tools-4.3+20140919/lzo_wrapper.h 2015-07-20 21:03:05.000000000 +0200
5074@@ -0,0 +1,78 @@
5075+#ifndef LZO_WRAPPER_H
5076+#define LZO_WRAPPER_H
5077+/*
5078+ * Squashfs
5079+ *
5080+ * Copyright (c) 2013
5081+ * Phillip Lougher <phillip@squashfs.org.uk>
5082+ *
5083+ * This program is free software; you can redistribute it and/or
5084+ * modify it under the terms of the GNU General Public License
5085+ * as published by the Free Software Foundation; either version 2,
5086+ * or (at your option) any later version.
5087+ *
5088+ * This program is distributed in the hope that it will be useful,
5089+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5090+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5091+ * GNU General Public License for more details.
5092+ *
5093+ * You should have received a copy of the GNU General Public License
5094+ * along with this program; if not, write to the Free Software
5095+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5096+ *
5097+ * lzo_wrapper.h
5098+ *
5099+ */
5100+
5101+#ifndef linux
5102+#define __BYTE_ORDER BYTE_ORDER
5103+#define __BIG_ENDIAN BIG_ENDIAN
5104+#define __LITTLE_ENDIAN LITTLE_ENDIAN
5105+#else
5106+#include <endian.h>
5107+#endif
5108+
5109+#if __BYTE_ORDER == __BIG_ENDIAN
5110+extern unsigned int inswap_le32(unsigned int);
5111+
5112+#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
5113+ (s)->algorithm = inswap_le32((s)->algorithm); \
5114+ (s)->compression_level = inswap_le32((s)->compression_level); \
5115+}
5116+#else
5117+#define SQUASHFS_INSWAP_COMP_OPTS(s)
5118+#endif
5119+
5120+/* Define the compression flags recognised. */
5121+#define SQUASHFS_LZO1X_1 0
5122+#define SQUASHFS_LZO1X_1_11 1
5123+#define SQUASHFS_LZO1X_1_12 2
5124+#define SQUASHFS_LZO1X_1_15 3
5125+#define SQUASHFS_LZO1X_999 4
5126+
5127+/* Default compression level used by SQUASHFS_LZO1X_999 */
5128+#define SQUASHFS_LZO1X_999_COMP_DEFAULT 8
5129+
5130+struct lzo_comp_opts {
5131+ int algorithm;
5132+ int compression_level;
5133+};
5134+
5135+struct lzo_algorithm {
5136+ char *name;
5137+ int size;
5138+ int (*compress) (const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
5139+ lzo_voidp);
5140+};
5141+
5142+struct lzo_stream {
5143+ void *workspace;
5144+ void *buffer;
5145+};
5146+
5147+#define LZO_MAX_EXPANSION(size) (size + (size / 16) + 64 + 3)
5148+
5149+int lzo1x_999_wrapper(const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
5150+ lzo_voidp);
5151+
5152+#endif
5153diff -Nru squashfs-tools-4.2+20130409/Makefile squashfs-tools-4.3+20140919/Makefile
5154--- squashfs-tools-4.2+20130409/Makefile 2013-05-09 10:39:11.000000000 +0200
5155+++ squashfs-tools-4.3+20140919/Makefile 2015-07-20 21:03:05.000000000 +0200
5156@@ -40,6 +40,20 @@
5157 #LZO_SUPPORT = 1
5158 #LZO_DIR = /usr/local
5159
5160+
5161+########### Building LZ4 support #############
5162+#
5163+# Yann Collet's LZ4 tools are supported
5164+# LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html
5165+# LZ4 source repository: http://code.google.com/p/lz4
5166+#
5167+# To build configure the tools using cmake to build shared libraries,
5168+# install and uncomment
5169+# the LZ4_SUPPORT line below.
5170+#
5171+#LZ4_SUPPORT = 1
5172+
5173+
5174 ########### Building LZMA support #############
5175 #
5176 # LZMA1 compression.
5177@@ -96,12 +110,12 @@
5178 INCLUDEDIR = -I.
5179 INSTALL_DIR = /usr/local/bin
5180
5181-MKSQUASHFS_OBJS = mksquashfs.o read_fs.o sort.o swap.o pseudo.o compressor.o \
5182- action.o progressbar.o read_file.o info.o restore.o \
5183+MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
5184+ sort.o progressbar.o read_file.o info.o restore.o process_fragments.o \
5185 caches-queues-lists.o
5186
5187 UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
5188- unsquash-4.o swap.o compressor.o
5189+ unsquash-4.o swap.o compressor.o unsquashfs_info.o
5190
5191 CFLAGS ?= -O2
5192 CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
5193@@ -155,6 +169,14 @@
5194 COMPRESSORS += lzo
5195 endif
5196
5197+ifeq ($(LZ4_SUPPORT),1)
5198+CFLAGS += -DLZ4_SUPPORT
5199+MKSQUASHFS_OBJS += lz4_wrapper.o
5200+UNSQUASHFS_OBJS += lz4_wrapper.o
5201+LIBS += -llz4
5202+COMPRESSORS += lz4
5203+endif
5204+
5205 ifeq ($(XATTR_SUPPORT),1)
5206 ifeq ($(XATTR_DEFAULT),1)
5207 CFLAGS += -DXATTR_SUPPORT -DXATTR_DEFAULT
5208@@ -187,14 +209,16 @@
5209 # At least one compressor must have been selected
5210 #
5211 ifndef COMPRESSORS
5212-$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ or LZO!")
5213+$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ, LZO or \
5214+ LZ4!")
5215 endif
5216
5217 #
5218 # COMP_DEFAULT must be a selected compressor
5219 #
5220 ifeq (, $(findstring $(COMP_DEFAULT), $(COMPRESSORS)))
5221-$(error "COMP_DEFAULT isn't selected to be built!")
5222+$(error "COMP_DEFAULT is set to ${COMP_DEFAULT}, which isn't selected to be \
5223+ built!")
5224 endif
5225
5226 .PHONY: all
5227@@ -203,45 +227,53 @@
5228 mksquashfs: $(MKSQUASHFS_OBJS)
5229 $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(MKSQUASHFS_OBJS) $(LIBS) -o $@
5230
5231-mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h sort.h squashfs_swap.h \
5232- xattr.h pseudo.h compressor.h action.h progressbar.h
5233+mksquashfs.o: Makefile mksquashfs.c squashfs_fs.h squashfs_swap.h mksquashfs.h \
5234+ sort.h pseudo.h compressor.h xattr.h action.h error.h progressbar.h \
5235+ info.h caches-queues-lists.h read_fs.h restore.h process_fragments.h
5236
5237-read_fs.o: read_fs.c squashfs_fs.h read_fs.h squashfs_swap.h compressor.h \
5238- xattr.h
5239+read_fs.o: read_fs.c squashfs_fs.h squashfs_swap.h compressor.h xattr.h \
5240+ error.h mksquashfs.h
5241
5242-sort.o: sort.c squashfs_fs.h sort.h mksquashfs.h
5243+sort.o: sort.c squashfs_fs.h mksquashfs.h sort.h error.h progressbar.h
5244
5245 swap.o: swap.c
5246
5247-pseudo.o: pseudo.c pseudo.h
5248+pseudo.o: pseudo.c pseudo.h error.h progressbar.h
5249
5250-compressor.o: compressor.c compressor.h squashfs_fs.h
5251+compressor.o: Makefile compressor.c compressor.h squashfs_fs.h
5252
5253-xattr.o: xattr.c xattr.h squashfs_fs.h squashfs_swap.h mksquashfs.h
5254+xattr.o: xattr.c squashfs_fs.h squashfs_swap.h mksquashfs.h xattr.h error.h \
5255+ progressbar.h
5256
5257-read_xattrs.o: read_xattrs.c xattr.h squashfs_fs.h squashfs_swap.h read_fs.h
5258+read_xattrs.o: read_xattrs.c squashfs_fs.h squashfs_swap.h xattr.h error.h
5259
5260-action.o: action.h squashfs_fs.h mksquashfs.h
5261+action.o: action.c squashfs_fs.h mksquashfs.h action.h error.h
5262
5263-progressbar.o: progressbar.c
5264+progressbar.o: progressbar.c error.h
5265
5266-read_file.o: read_file.c
5267+read_file.o: read_file.c error.h
5268
5269-info.o: info.c
5270+info.o: info.c squashfs_fs.h mksquashfs.h error.h progressbar.h \
5271+ caches-queues-lists.h
5272
5273-restore.o: restore.c
5274+restore.o: restore.c caches-queues-lists.h squashfs_fs.h mksquashfs.h error.h \
5275+ progressbar.h info.h
5276
5277-caches-queues-lists.o: caches-queues-lists.c
5278+process_fragments.o: process_fragments.c process_fragments.h
5279
5280-gzip_wrapper.o: gzip_wrapper.c compressor.h squashfs_fs.h
5281+caches-queues-lists.o: caches-queues-lists.c error.h caches-queues-lists.h
5282+
5283+gzip_wrapper.o: gzip_wrapper.c squashfs_fs.h gzip_wrapper.h compressor.h
5284
5285 lzma_wrapper.o: lzma_wrapper.c compressor.h squashfs_fs.h
5286
5287 lzma_xz_wrapper.o: lzma_xz_wrapper.c compressor.h squashfs_fs.h
5288
5289-lzo_wrapper.o: lzo_wrapper.c compressor.h squashfs_fs.h
5290+lzo_wrapper.o: lzo_wrapper.c squashfs_fs.h lzo_wrapper.h compressor.h
5291+
5292+lz4_wrapper.o: lz4_wrapper.c squashfs_fs.h lz4_wrapper.h compressor.h
5293
5294-xz_wrapper.o: xz_wrapper.c compressor.h squashfs_fs.h
5295+xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
5296
5297 unsquashfs: $(UNSQUASHFS_OBJS)
5298 $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
5299@@ -260,6 +292,7 @@
5300
5301 unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h
5302
5303+unsquashfs_info.o: unsquashfs.h squashfs_fs.h
5304
5305 .PHONY: clean
5306 clean:
5307diff -Nru squashfs-tools-4.2+20130409/mksquashfs.c squashfs-tools-4.3+20140919/mksquashfs.c
5308--- squashfs-tools-4.2+20130409/mksquashfs.c 2013-05-09 10:39:11.000000000 +0200
5309+++ squashfs-tools-4.3+20140919/mksquashfs.c 2015-07-20 21:03:05.000000000 +0200
5310@@ -3,7 +3,7 @@
5311 * filesystem.
5312 *
5313 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
5314- * 2012, 2013
5315+ * 2012, 2013, 2014
5316 * Phillip Lougher <phillip@squashfs.org.uk>
5317 *
5318 * This program is free software; you can redistribute it and/or
5319@@ -73,6 +73,9 @@
5320 #include "progressbar.h"
5321 #include "info.h"
5322 #include "caches-queues-lists.h"
5323+#include "read_fs.h"
5324+#include "restore.h"
5325+#include "process_fragments.h"
5326
5327 int delete = FALSE;
5328 int fd;
5329@@ -80,17 +83,23 @@
5330
5331 /* filesystem flags for building */
5332 int comp_opts = FALSE;
5333-int no_xattrs = XATTR_DEF, noX = 0;
5334-int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
5335-int noI = 0, noD = 0;
5336+int no_xattrs = XATTR_DEF;
5337+int noX = FALSE;
5338+int duplicate_checking = TRUE;
5339+int noF = FALSE;
5340+int no_fragments = FALSE;
5341+int always_use_fragments = FALSE;
5342+int noI = FALSE;
5343+int noD = FALSE;
5344 int silent = TRUE;
5345-long long global_uid = -1, global_gid = -1;
5346 int exportable = TRUE;
5347-int progress = TRUE;
5348 int sparse_files = TRUE;
5349 int old_exclude = TRUE;
5350 int use_regex = FALSE;
5351 int nopad = FALSE;
5352+int exit_on_error = FALSE;
5353+
5354+long long global_uid = -1, global_gid = -1;
5355
5356 /* superblock attributes */
5357 int block_size = SQUASHFS_FILE_SIZE, block_log;
5358@@ -186,21 +195,15 @@
5359 struct pathname *stickypath = NULL;
5360 int excluded(char *name, struct pathnames *paths, struct pathnames **new);
5361
5362-/* fragment block data structures */
5363 int fragments = 0;
5364
5365-struct fragment {
5366- unsigned int index;
5367- int offset;
5368- int size;
5369-};
5370-
5371 #define FRAG_SIZE 32768
5372-#define FRAG_INDEX (1LL << 32)
5373
5374 struct squashfs_fragment_entry *fragment_table = NULL;
5375 int fragments_outstanding = 0;
5376
5377+int fragments_locked = FALSE;
5378+
5379 /* current inode number for directories and non directories */
5380 unsigned int inode_no = 1;
5381 unsigned int root_inode_number = 0;
5382@@ -217,21 +220,9 @@
5383 };
5384 struct old_root_entry_info *old_root_entry;
5385
5386-/* in memory file info */
5387-struct file_info {
5388- long long file_size;
5389- long long bytes;
5390- unsigned short checksum;
5391- unsigned short fragment_checksum;
5392- long long start;
5393- unsigned int *block_list;
5394- struct file_info *next;
5395- struct fragment *fragment;
5396- char checksum_flag;
5397-};
5398-
5399 /* restore orignal filesystem state if appending to existing filesystem is
5400 * cancelled */
5401+int appending = FALSE;
5402 char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
5403
5404 long long sbytes, stotal_bytes;
5405@@ -245,10 +236,10 @@
5406 int threads;
5407
5408 /* flag whether destination file is a block device */
5409-int block_device = 0;
5410+int block_device = FALSE;
5411
5412 /* flag indicating whether files are sorted using sort list(s) */
5413-int sorted = 0;
5414+int sorted = FALSE;
5415
5416 /* save destination file name for deleting on error */
5417 char *destination_file = NULL;
5418@@ -257,93 +248,67 @@
5419 char *recovery_file = NULL;
5420 int recover = TRUE;
5421
5422-/* in memory uid tables */
5423-#define ID_ENTRIES 256
5424-#define ID_HASH(id) (id & (ID_ENTRIES - 1))
5425-#define ISA_UID 1
5426-#define ISA_GID 2
5427-struct id {
5428- unsigned int id;
5429- int index;
5430- char flags;
5431- struct id *next;
5432-};
5433 struct id *id_hash_table[ID_ENTRIES];
5434 struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
5435 unsigned int uid_count = 0, guid_count = 0;
5436 unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
5437
5438-struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
5439-struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
5440- *to_frag;
5441-pthread_t *thread, *deflator_thread, *frag_deflator_thread;
5442+struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
5443+struct cache *bwriter_buffer, *fwriter_buffer;
5444+struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
5445+ *to_frag, *locked_fragment, *to_process_frag;
5446+struct seq_queue *to_main;
5447+pthread_t reader_thread, writer_thread, main_thread;
5448+pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
5449 pthread_t *restore_thread = NULL;
5450-pthread_mutex_t fragment_mutex;
5451-pthread_cond_t fragment_waiting;
5452-pthread_mutex_t pos_mutex;
5453+pthread_mutex_t fragment_mutex = PTHREAD_MUTEX_INITIALIZER;
5454+pthread_mutex_t pos_mutex = PTHREAD_MUTEX_INITIALIZER;
5455+pthread_mutex_t dup_mutex = PTHREAD_MUTEX_INITIALIZER;
5456
5457 /* user options that control parallelisation */
5458 int processors = -1;
5459-/* default size of output buffer in Mbytes */
5460-#define WRITER_BUFFER_DEFAULT 512
5461-/* default size of input buffer in Mbytes */
5462-#define READER_BUFFER_DEFAULT 64
5463-/* default size of fragment buffer in Mbytes */
5464-#define FRAGMENT_BUFFER_DEFAULT 64
5465-int writer_buffer_size;
5466+int bwriter_size;
5467
5468 /* compression operations */
5469-static struct compressor *comp;
5470-int compressor_opts_parsed = 0;
5471+struct compressor *comp = NULL;
5472+int compressor_opt_parsed = FALSE;
5473 void *stream = NULL;
5474
5475 /* xattr stats */
5476 unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
5477
5478-char *read_from_disk(long long start, unsigned int avail_bytes);
5479+/* fragment to file mapping used when appending */
5480+int append_fragments = 0;
5481+struct append_file **file_mapping;
5482+
5483+/* root of the in-core directory structure */
5484+struct dir_info *root_dir;
5485+
5486+static char *read_from_disk(long long start, unsigned int avail_bytes);
5487 void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
5488 int type);
5489-extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
5490- char *source);
5491-extern long long read_filesystem(char *root_name, int fd,
5492- struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
5493- char **cdirectory_table, char **directory_data_cache,
5494- unsigned int *last_directory_block, unsigned int *inode_dir_offset,
5495- unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
5496- unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
5497- int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
5498- long long *uncompressed_file, unsigned int *uncompressed_inode,
5499- unsigned int *uncompressed_directory,
5500- unsigned int *inode_dir_inode_number,
5501- unsigned int *inode_dir_parent_inode,
5502- void (push_directory_entry)(char *, squashfs_inode, int, int),
5503- struct squashfs_fragment_entry **fragment_table,
5504- squashfs_inode **inode_lookup_table);
5505-extern int read_sort_file(char *filename, int source, char *source_path[]);
5506-extern void sort_files_and_write(struct dir_info *dir);
5507 struct file_info *duplicate(long long file_size, long long bytes,
5508 unsigned int **block_list, long long *start, struct fragment **fragment,
5509 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
5510- unsigned short fragment_checksum, int checksum_flag);
5511+ int checksum_flag);
5512 struct dir_info *dir_scan1(char *, char *, struct pathnames *,
5513 struct dir_ent *(_readdir)(struct dir_info *), int);
5514 void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
5515-void dir_scan3(struct dir_info *root, struct dir_info *dir);
5516+void dir_scan3(struct dir_info *dir);
5517 void dir_scan4(struct dir_info *dir);
5518 void dir_scan5(struct dir_info *dir);
5519-void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info);
5520+void dir_scan6(struct dir_info *dir);
5521+void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info);
5522 struct file_info *add_non_dup(long long file_size, long long bytes,
5523 unsigned int *block_list, long long start, struct fragment *fragment,
5524 unsigned short checksum, unsigned short fragment_checksum,
5525- int checksum_flag);
5526-extern void generate_file_priorities(struct dir_info *dir, int priority,
5527- struct stat *buf);
5528-extern struct priority_entry *priority_list[65536];
5529+ int checksum_flag, int checksum_frag_flag);
5530 long long generic_write_table(int, void *, int, void *, int);
5531 void restorefs();
5532 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
5533-extern pthread_t *init_restore_thread(pthread_t);
5534 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
5535+unsigned short get_checksum_mem(char *buff, int bytes);
5536+void check_usable_phys_mem(int total_mem);
5537
5538
5539 void prep_exit()
5540@@ -360,12 +325,14 @@
5541 exit(1);
5542 } else {
5543 /* signal the restore thread to restore */
5544- kill(getpid(), SIGUSR1);
5545+ pthread_kill(*restore_thread, SIGUSR1);
5546 pthread_exit(NULL);
5547 }
5548- }
5549- if(delete && destination_file && !block_device)
5550- unlink(destination_file);
5551+ } else if(delete) {
5552+ if(destination_file && !block_device)
5553+ unlink(destination_file);
5554+ } else if(recovery_file)
5555+ unlink(recovery_file);
5556 }
5557
5558
5559@@ -387,22 +354,20 @@
5560 }
5561
5562
5563+int multiply_overflowll(long long a, int multiplier)
5564+{
5565+ return (LLONG_MAX / multiplier) < a;
5566+}
5567+
5568+
5569 #define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
5570 + (((char *)A) - data_cache)))
5571
5572
5573 void restorefs()
5574 {
5575- int i;
5576-
5577 ERROR("Exiting - restoring original filesystem!\n\n");
5578
5579- for(i = 0; i < 2 + processors * 2; i++)
5580- pthread_cancel(thread[i]);
5581- for(i = 0; i < 2 + processors * 2; i++)
5582- pthread_join(thread[i], NULL);
5583-
5584- TRACE("All threads in signal handler\n");
5585 bytes = sbytes;
5586 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
5587 memcpy(directory_data_cache, sdirectory_data_cache,
5588@@ -555,15 +520,11 @@
5589 ERROR("read_fs_bytes: Lseek on destination failed because %s, "
5590 "offset=0x%llx\n", strerror(errno), off);
5591 res = 0;
5592- goto mutex_unlock;
5593- }
5594-
5595- if(read_bytes(fd, buff, bytes) < bytes) {
5596+ } else if(read_bytes(fd, buff, bytes) < bytes) {
5597 ERROR("Read on destination failed\n");
5598 res = 0;
5599 }
5600
5601-mutex_unlock:
5602 pthread_cleanup_pop(1);
5603 return res;
5604 }
5605@@ -1076,56 +1037,28 @@
5606 }
5607 else if(type == SQUASHFS_SYMLINK_TYPE) {
5608 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
5609- int byte;
5610- char buff[65536]; /* overflow safe */
5611+ int byte = strlen(dir_ent->inode->symlink);
5612 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
5613
5614- byte = readlink(filename, buff, 65536);
5615- if(byte == -1) {
5616- ERROR("Failed to read symlink %s, creating empty "
5617- "symlink\n", filename);
5618- byte = 0;
5619- }
5620-
5621- if(byte == 65536) {
5622- ERROR("Symlink %s is greater than 65536 bytes! "
5623- "Creating empty symlink\n", filename);
5624- byte = 0;
5625- }
5626-
5627 inode = get_inode(sizeof(*symlink) + byte);
5628 symlink->nlink = nlink;
5629 symlink->symlink_size = byte;
5630 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
5631- strncpy(inode + off, buff, byte);
5632+ strncpy(inode + off, dir_ent->inode->symlink, byte);
5633 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
5634 nlink);
5635 }
5636 else if(type == SQUASHFS_LSYMLINK_TYPE) {
5637 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
5638- int byte;
5639- char buff[65536]; /* overflow safe */
5640+ int byte = strlen(dir_ent->inode->symlink);
5641 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
5642
5643- byte = readlink(filename, buff, 65536);
5644- if(byte == -1) {
5645- ERROR("Failed to read symlink %s, creating empty "
5646- "symlink\n", filename);
5647- byte = 0;
5648- }
5649-
5650- if(byte == 65536) {
5651- ERROR("Symlink %s is greater than 65536 bytes! "
5652- "Creating empty symlink\n", filename);
5653- byte = 0;
5654- }
5655-
5656 inode = get_inode(sizeof(*symlink) + byte +
5657 sizeof(unsigned int));
5658 symlink->nlink = nlink;
5659 symlink->symlink_size = byte;
5660 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
5661- strncpy(inode + off, buff, byte);
5662+ strncpy(inode + off, dir_ent->inode->symlink, byte);
5663 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
5664 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
5665 nlink);
5666@@ -1363,28 +1296,82 @@
5667 }
5668
5669
5670-struct file_buffer *get_fragment(struct fragment *fragment)
5671+static struct file_buffer *get_fragment(struct fragment *fragment)
5672 {
5673 struct squashfs_fragment_entry *disk_fragment;
5674- int res, size;
5675- long long start_block;
5676 struct file_buffer *buffer, *compressed_buffer;
5677+ long long start_block;
5678+ int res, size, index = fragment->index;
5679+ char locked;
5680+
5681+ /*
5682+ * Lookup fragment block in cache.
5683+ * If the fragment block doesn't exist, then get the compressed version
5684+ * from the writer cache or off disk, and decompress it.
5685+ *
5686+ * This routine has two things which complicate the code:
5687+ *
5688+ * 1. Multiple threads can simultaneously lookup/create the
5689+ * same buffer. This means a buffer needs to be "locked"
5690+ * when it is being filled in, to prevent other threads from
5691+ * using it when it is not ready. This is because we now do
5692+ * fragment duplicate checking in parallel.
5693+ * 2. We have two caches which need to be checked for the
5694+ * presence of fragment blocks: the normal fragment cache
5695+ * and a "reserve" cache. The reserve cache is used to
5696+ * prevent an unnecessary pipeline stall when the fragment cache
5697+ * is full of fragments waiting to be compressed.
5698+ */
5699
5700 if(fragment->index == SQUASHFS_INVALID_FRAG)
5701 return NULL;
5702
5703- buffer = cache_lookup(fragment_buffer, fragment->index);
5704- if(buffer)
5705- return buffer;
5706+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
5707+ pthread_mutex_lock(&dup_mutex);
5708
5709- compressed_buffer = cache_lookup(writer_buffer, fragment->index +
5710- FRAG_INDEX);
5711+again:
5712+ buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
5713+ if(buffer) {
5714+ pthread_mutex_unlock(&dup_mutex);
5715+ if(locked)
5716+ /* got a buffer being filled in. Wait for it */
5717+ cache_wait_unlock(buffer);
5718+ goto finished;
5719+ }
5720+
5721+ /* not in fragment cache, is it in the reserve cache? */
5722+ buffer = cache_lookup_nowait(reserve_cache, index, &locked);
5723+ if(buffer) {
5724+ pthread_mutex_unlock(&dup_mutex);
5725+ if(locked)
5726+ /* got a buffer being filled in. Wait for it */
5727+ cache_wait_unlock(buffer);
5728+ goto finished;
5729+ }
5730+
5731+ /* in neither cache, try to get it from the fragment cache */
5732+ buffer = cache_get_nowait(fragment_buffer, index);
5733+ if(!buffer) {
5734+ /*
5735+ * no room, get it from the reserve cache, this is
5736+ * dimensioned so it will always have space (no more than
5737+ * processors + 1 can have an outstanding reserve buffer)
5738+ */
5739+ buffer = cache_get_nowait(reserve_cache, index);
5740+ if(!buffer) {
5741+ /* failsafe */
5742+ ERROR("no space in reserve cache\n");
5743+ goto again;
5744+ }
5745+ }
5746+
5747+ pthread_mutex_unlock(&dup_mutex);
5748
5749- buffer = cache_get(fragment_buffer, fragment->index, 1);
5750+ compressed_buffer = cache_lookup(fwriter_buffer, index);
5751
5752 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
5753 pthread_mutex_lock(&fragment_mutex);
5754- disk_fragment = &fragment_table[fragment->index];
5755+ disk_fragment = &fragment_table[index];
5756 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
5757 start_block = disk_fragment->start_block;
5758 pthread_cleanup_pop(1);
5759@@ -1395,8 +1382,14 @@
5760
5761 if(compressed_buffer)
5762 data = compressed_buffer->data;
5763- else
5764+ else {
5765 data = read_from_disk(start_block, size);
5766+ if(data == NULL) {
5767+ ERROR("Failed to read fragment from output"
5768+ " filesystem\n");
5769+ BAD_ERROR("Output filesystem corrupted?\n");
5770+ }
5771+ }
5772
5773 res = compressor_uncompress(comp, buffer->data, data, size,
5774 block_size, &error);
5775@@ -1414,58 +1407,95 @@
5776 }
5777 }
5778
5779+ cache_unlock(buffer);
5780 cache_block_put(compressed_buffer);
5781
5782+finished:
5783+ pthread_cleanup_pop(0);
5784+
5785 return buffer;
5786 }
5787
5788
5789-struct frag_locked {
5790- struct file_buffer *buffer;
5791- int c_byte;
5792- int fragment;
5793- struct frag_locked *fragment_prev;
5794- struct frag_locked *fragment_next;
5795-};
5796+unsigned short get_fragment_checksum(struct file_info *file)
5797+{
5798+ struct file_buffer *frag_buffer;
5799+ struct append_file *append;
5800+ int res, index = file->fragment->index;
5801+ unsigned short checksum;
5802
5803-int fragments_locked = FALSE;
5804-struct frag_locked *frag_locked_list = NULL;
5805+ if(index == SQUASHFS_INVALID_FRAG)
5806+ return 0;
5807+
5808+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
5809+ pthread_mutex_lock(&dup_mutex);
5810+ res = file->have_frag_checksum;
5811+ checksum = file->fragment_checksum;
5812+ pthread_cleanup_pop(1);
5813+
5814+ if(res)
5815+ return checksum;
5816+
5817+ frag_buffer = get_fragment(file->fragment);
5818+
5819+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
5820+
5821+ for(append = file_mapping[index]; append; append = append->next) {
5822+ int offset = append->file->fragment->offset;
5823+ int size = append->file->fragment->size;
5824+ unsigned short cksum =
5825+ get_checksum_mem(frag_buffer->data + offset, size);
5826
5827-INSERT_LIST(fragment, struct frag_locked)
5828-REMOVE_LIST(fragment, struct frag_locked)
5829+ if(file == append->file)
5830+ checksum = cksum;
5831
5832-int lock_fragments()
5833+ pthread_mutex_lock(&dup_mutex);
5834+ append->file->fragment_checksum = cksum;
5835+ append->file->have_frag_checksum = TRUE;
5836+ pthread_mutex_unlock(&dup_mutex);
5837+ }
5838+
5839+ cache_block_put(frag_buffer);
5840+ pthread_cleanup_pop(0);
5841+
5842+ return checksum;
5843+}
5844+
5845+
5846+void lock_fragments()
5847 {
5848- int count;
5849 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
5850 pthread_mutex_lock(&fragment_mutex);
5851 fragments_locked = TRUE;
5852- count = fragments_outstanding;
5853 pthread_cleanup_pop(1);
5854- return count;
5855 }
5856
5857
5858 void unlock_fragments()
5859 {
5860- struct frag_locked *entry;
5861- int compressed_size;
5862+ int frg, size;
5863+ struct file_buffer *write_buffer;
5864
5865 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
5866 pthread_mutex_lock(&fragment_mutex);
5867- while(frag_locked_list) {
5868- entry = frag_locked_list;
5869- remove_fragment_list(&frag_locked_list, entry);
5870- compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
5871- fragment_table[entry->fragment].size = entry->c_byte;
5872- fragment_table[entry->fragment].start_block = bytes;
5873- entry->buffer->block = bytes;
5874- bytes += compressed_size;
5875+
5876+ /*
5877+ * Note queue_empty() is inherently racy with respect to concurrent
5878+ * queue get and pushes. We avoid this because we're holding the
5879+ * fragment_mutex which ensures no other threads can be using the
5880+ * queue at this time.
5881+ */
5882+ while(!queue_empty(locked_fragment)) {
5883+ write_buffer = queue_get(locked_fragment);
5884+ frg = write_buffer->block;
5885+ size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size);
5886+ fragment_table[frg].start_block = bytes;
5887+ write_buffer->block = bytes;
5888+ bytes += size;
5889 fragments_outstanding --;
5890- queue_put(to_writer, entry->buffer);
5891+ queue_put(to_writer, write_buffer);
5892 TRACE("fragment_locked writing fragment %d, compressed size %d"
5893- "\n", entry->fragment, compressed_size);
5894- free(entry);
5895+ "\n", frg, size);
5896 }
5897 fragments_locked = FALSE;
5898 pthread_cleanup_pop(1);
5899@@ -1475,14 +1505,10 @@
5900 void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
5901 int fragment)
5902 {
5903- struct frag_locked *entry = malloc(sizeof(struct frag_locked));
5904- if(entry == NULL)
5905- MEM_ERROR();
5906- entry->buffer = write_buffer;
5907- entry->c_byte = c_byte;
5908- entry->fragment = fragment;
5909- entry->fragment_prev = entry->fragment_next = NULL;
5910- insert_fragment_list(&frag_locked_list, entry);
5911+ fragment_table[fragment].size = c_byte;
5912+ write_buffer->block = fragment;
5913+
5914+ queue_put(locked_fragment, write_buffer);
5915 }
5916
5917
5918@@ -1502,7 +1528,7 @@
5919
5920 struct file_buffer *allocate_fragment()
5921 {
5922- struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
5923+ struct file_buffer *fragment = cache_get(fragment_buffer, fragments);
5924
5925 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
5926 pthread_mutex_lock(&fragment_mutex);
5927@@ -1543,7 +1569,7 @@
5928 if(file_buffer == NULL || file_buffer->size == 0)
5929 return &empty_fragment;
5930
5931- fragment = eval_frag_actions(dir_ent);
5932+ fragment = eval_frag_actions(root_dir, dir_ent);
5933
5934 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
5935 write_fragment(*fragment);
5936@@ -1645,15 +1671,13 @@
5937
5938
5939 char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
5940-char *read_from_disk(long long start, unsigned int avail_bytes)
5941+static char *read_from_disk(long long start, unsigned int avail_bytes)
5942 {
5943 int res;
5944
5945 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
5946- if(res == 0) {
5947- ERROR("Failed to read data from output filesystem\n");
5948- BAD_ERROR("Output filesystem corrupted?\n");
5949- }
5950+ if(res == 0)
5951+ return NULL;
5952
5953 return read_from_file_buffer;
5954 }
5955@@ -1665,10 +1689,8 @@
5956 int res;
5957
5958 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
5959- if(res == 0) {
5960- ERROR("Failed to read data from output filesystem\n");
5961- BAD_ERROR("Output filesystem corrupted?\n");
5962- }
5963+ if(res == 0)
5964+ return NULL;
5965
5966 return read_from_file_buffer2;
5967 }
5968@@ -1702,14 +1724,22 @@
5969 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
5970 if(bytes == 0) /* sparse block */
5971 continue;
5972- write_buffer = cache_lookup(writer_buffer, start);
5973+ write_buffer = cache_lookup(bwriter_buffer, start);
5974 if(write_buffer) {
5975 chksum = get_checksum(write_buffer->data, bytes,
5976 chksum);
5977 cache_block_put(write_buffer);
5978- } else
5979- chksum = get_checksum(read_from_disk(start, bytes),
5980- bytes, chksum);
5981+ } else {
5982+ void *data = read_from_disk(start, bytes);
5983+ if(data == NULL) {
5984+ ERROR("Failed to checksum data from output"
5985+ " filesystem\n");
5986+ BAD_ERROR("Output filesystem corrupted?\n");
5987+ }
5988+
5989+ chksum = get_checksum(data, bytes, chksum);
5990+ }
5991+
5992 l -= bytes;
5993 start += bytes;
5994 }
5995@@ -1741,6 +1771,8 @@
5996 struct fragment *frg;
5997 unsigned int *block_list = block_listp;
5998 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
5999+ struct append_file *append_file;
6000+ struct file_info *file;
6001
6002 if(!duplicate_checking || file_size == 0)
6003 return;
6004@@ -1767,44 +1799,29 @@
6005 frg->offset = offset;
6006 frg->size = bytes;
6007
6008- add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
6009-}
6010-
6011+ file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0,
6012+ FALSE, FALSE);
6013
6014-int pre_duplicate(long long file_size)
6015-{
6016- struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
6017+ if(fragment == SQUASHFS_INVALID_FRAG)
6018+ return;
6019
6020- for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
6021- if(dupl_ptr->file_size == file_size)
6022- return TRUE;
6023+ append_file = malloc(sizeof(struct append_file));
6024+ if(append_file == NULL)
6025+ MEM_ERROR();
6026
6027- return FALSE;
6028+ append_file->file = file;
6029+ append_file->next = file_mapping[fragment];
6030+ file_mapping[fragment] = append_file;
6031 }
6032
6033
6034-int pre_duplicate_frag(long long file_size, unsigned short checksum)
6035+int pre_duplicate(long long file_size)
6036 {
6037 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
6038
6039 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
6040- if(file_size == dupl_ptr->file_size && file_size ==
6041- dupl_ptr->fragment->size) {
6042- if(dupl_ptr->checksum_flag == FALSE) {
6043- struct file_buffer *frag_buffer =
6044- get_fragment(dupl_ptr->fragment);
6045- dupl_ptr->checksum =
6046- get_checksum_disk(dupl_ptr->start,
6047- dupl_ptr->bytes, dupl_ptr->block_list);
6048- dupl_ptr->fragment_checksum =
6049- get_checksum_mem(frag_buffer->data +
6050- dupl_ptr->fragment->offset, file_size);
6051- cache_block_put(frag_buffer);
6052- dupl_ptr->checksum_flag = TRUE;
6053- }
6054- if(dupl_ptr->fragment_checksum == checksum)
6055- return TRUE;
6056- }
6057+ if(dupl_ptr->file_size == file_size)
6058+ return TRUE;
6059
6060 return FALSE;
6061 }
6062@@ -1813,7 +1830,7 @@
6063 struct file_info *add_non_dup(long long file_size, long long bytes,
6064 unsigned int *block_list, long long start, struct fragment *fragment,
6065 unsigned short checksum, unsigned short fragment_checksum,
6066- int checksum_flag)
6067+ int checksum_flag, int checksum_frag_flag)
6068 {
6069 struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
6070
6071@@ -1827,22 +1844,74 @@
6072 dupl_ptr->fragment = fragment;
6073 dupl_ptr->checksum = checksum;
6074 dupl_ptr->fragment_checksum = fragment_checksum;
6075- dupl_ptr->checksum_flag = checksum_flag;
6076+ dupl_ptr->have_frag_checksum = checksum_frag_flag;
6077+ dupl_ptr->have_checksum = checksum_flag;
6078+
6079+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
6080+ pthread_mutex_lock(&dup_mutex);
6081 dupl_ptr->next = dupl[DUP_HASH(file_size)];
6082 dupl[DUP_HASH(file_size)] = dupl_ptr;
6083 dup_files ++;
6084+ pthread_cleanup_pop(1);
6085
6086 return dupl_ptr;
6087 }
6088
6089
6090+struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put)
6091+{
6092+ struct file_info *dupl_ptr;
6093+ struct file_buffer *buffer;
6094+ struct file_info *dupl_start = file_buffer->dupl_start;
6095+ long long file_size = file_buffer->file_size;
6096+ unsigned short checksum = file_buffer->checksum;
6097+ int res;
6098+
6099+ if(file_buffer->duplicate) {
6100+ TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
6101+ "checksum 0x%x\n", dupl_start->fragment->index,
6102+ file_size, dupl_start->fragment->offset, checksum);
6103+ *dont_put = TRUE;
6104+ return dupl_start->fragment;
6105+ } else {
6106+ *dont_put = FALSE;
6107+ dupl_ptr = dupl[DUP_HASH(file_size)];
6108+ }
6109+
6110+ for(; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) {
6111+ if(file_size == dupl_ptr->file_size && file_size ==
6112+ dupl_ptr->fragment->size) {
6113+ if(get_fragment_checksum(dupl_ptr) == checksum) {
6114+ buffer = get_fragment(dupl_ptr->fragment);
6115+ res = memcmp(file_buffer->data, buffer->data +
6116+ dupl_ptr->fragment->offset, file_size);
6117+ cache_block_put(buffer);
6118+ if(res == 0)
6119+ break;
6120+ }
6121+ }
6122+ }
6123+
6124+ if(!dupl_ptr || dupl_ptr == dupl_start)
6125+ return NULL;
6126+
6127+ TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
6128+ "checksum 0x%x\n", dupl_ptr->fragment->index, file_size,
6129+ dupl_ptr->fragment->offset, checksum);
6130+
6131+ return dupl_ptr->fragment;
6132+}
6133+
6134+
6135 struct file_info *duplicate(long long file_size, long long bytes,
6136 unsigned int **block_list, long long *start, struct fragment **fragment,
6137 struct file_buffer *file_buffer, int blocks, unsigned short checksum,
6138- unsigned short fragment_checksum, int checksum_flag)
6139+ int checksum_flag)
6140 {
6141 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
6142 int frag_bytes = file_buffer ? file_buffer->size : 0;
6143+ unsigned short fragment_checksum = file_buffer ?
6144+ file_buffer->checksum : 0;
6145
6146 for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
6147 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
6148@@ -1857,27 +1926,19 @@
6149 if(checksum_flag == FALSE) {
6150 checksum = get_checksum_disk(*start, bytes,
6151 *block_list);
6152- fragment_checksum =
6153- get_checksum_mem_buffer(file_buffer);
6154 checksum_flag = TRUE;
6155 }
6156
6157- if(dupl_ptr->checksum_flag == FALSE) {
6158- struct file_buffer *frag_buffer =
6159- get_fragment(dupl_ptr->fragment);
6160+ if(!dupl_ptr->have_checksum) {
6161 dupl_ptr->checksum =
6162 get_checksum_disk(dupl_ptr->start,
6163 dupl_ptr->bytes, dupl_ptr->block_list);
6164- dupl_ptr->fragment_checksum =
6165- get_checksum_mem(frag_buffer->data +
6166- dupl_ptr->fragment->offset, frag_bytes);
6167- cache_block_put(frag_buffer);
6168- dupl_ptr->checksum_flag = TRUE;
6169+ dupl_ptr->have_checksum = TRUE;
6170 }
6171
6172 if(checksum != dupl_ptr->checksum ||
6173 fragment_checksum !=
6174- dupl_ptr->fragment_checksum)
6175+ get_fragment_checksum(dupl_ptr))
6176 continue;
6177
6178 target_start = *start;
6179@@ -1891,22 +1952,36 @@
6180
6181 if(size == 0)
6182 continue;
6183- target_buffer = cache_lookup(writer_buffer,
6184+ target_buffer = cache_lookup(bwriter_buffer,
6185 target_start);
6186 if(target_buffer)
6187 target_data = target_buffer->data;
6188- else
6189+ else {
6190 target_data =
6191 read_from_disk(target_start,
6192 size);
6193+ if(target_data == NULL) {
6194+ ERROR("Failed to read data from"
6195+ " output filesystem\n");
6196+ BAD_ERROR("Output filesystem"
6197+ " corrupted?\n");
6198+ }
6199+ }
6200
6201- dup_buffer = cache_lookup(writer_buffer,
6202+ dup_buffer = cache_lookup(bwriter_buffer,
6203 dup_start);
6204 if(dup_buffer)
6205 dup_data = dup_buffer->data;
6206- else
6207+ else {
6208 dup_data = read_from_disk2(dup_start,
6209 size);
6210+ if(dup_data == NULL) {
6211+ ERROR("Failed to read data from"
6212+ " output filesystem\n");
6213+ BAD_ERROR("Output filesystem"
6214+ " corrupted?\n");
6215+ }
6216+ }
6217
6218 res = memcmp(target_data, dup_data, size);
6219 cache_block_put(target_buffer);
6220@@ -1948,13 +2023,13 @@
6221
6222
6223 return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
6224- checksum, fragment_checksum, checksum_flag);
6225+ checksum, fragment_checksum, checksum_flag, TRUE);
6226 }
6227
6228
6229 inline int is_fragment(struct inode_info *inode)
6230 {
6231- int file_size = inode->buf.st_size;
6232+ off_t file_size = inode->buf.st_size;
6233
6234 /*
6235 * If this block is to be compressed differently to the
6236@@ -1963,33 +2038,57 @@
6237 if(inode->noF != noF)
6238 return FALSE;
6239
6240- return !inode->no_fragments && (file_size < block_size ||
6241+ return !inode->no_fragments && file_size && (file_size < block_size ||
6242 (inode->always_use_fragments && file_size & (block_size - 1)));
6243 }
6244
6245
6246+void put_file_buffer(struct file_buffer *file_buffer)
6247+{
6248+ /*
6249+ * Decide where to send the file buffer:
6250+ * - compressible non-fragment blocks go to the deflate threads,
6251+ * - fragments go to the process fragment threads,
6252+ * - all others go directly to the main thread
6253+ */
6254+ if(file_buffer->error) {
6255+ file_buffer->fragment = 0;
6256+ seq_queue_put(to_main, file_buffer);
6257+ } else if (file_buffer->file_size == 0)
6258+ seq_queue_put(to_main, file_buffer);
6259+ else if(file_buffer->fragment)
6260+ queue_put(to_process_frag, file_buffer);
6261+ else
6262+ queue_put(to_deflate, file_buffer);
6263+}
6264+
6265+
6266 static int seq = 0;
6267 void reader_read_process(struct dir_ent *dir_ent)
6268 {
6269+ long long bytes = 0;
6270 struct inode_info *inode = dir_ent->inode;
6271 struct file_buffer *prev_buffer = NULL, *file_buffer;
6272- int status, res, byte, count = 0;
6273- int file = get_pseudo_file(inode->pseudo_id)->fd;
6274- int child = get_pseudo_file(inode->pseudo_id)->child;
6275- long long bytes = 0;
6276+ int status, byte, res, child;
6277+ int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child);
6278+
6279+ if(!file) {
6280+ file_buffer = cache_get_nohash(reader_buffer);
6281+ file_buffer->sequence = seq ++;
6282+ goto read_err;
6283+ }
6284
6285 while(1) {
6286- file_buffer = cache_get(reader_buffer, 0, 0);
6287+ file_buffer = cache_get_nohash(reader_buffer);
6288 file_buffer->sequence = seq ++;
6289 file_buffer->noD = inode->noD;
6290
6291 byte = read_bytes(file, file_buffer->data, block_size);
6292 if(byte == -1)
6293- goto read_err;
6294+ goto read_err2;
6295
6296 file_buffer->size = byte;
6297 file_buffer->file_size = -1;
6298- file_buffer->block = count ++;
6299 file_buffer->error = FALSE;
6300 file_buffer->fragment = FALSE;
6301 bytes += byte;
6302@@ -2007,7 +2106,7 @@
6303 progress_bar_size(1);
6304
6305 if(prev_buffer)
6306- queue_put(from_reader, prev_buffer);
6307+ put_file_buffer(prev_buffer);
6308 prev_buffer = file_buffer;
6309 }
6310
6311@@ -2018,6 +2117,8 @@
6312 inode->buf.st_size = bytes;
6313
6314 res = waitpid(child, &status, 0);
6315+ close(file);
6316+
6317 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
6318 goto read_err;
6319
6320@@ -2029,10 +2130,12 @@
6321 }
6322 prev_buffer->file_size = bytes;
6323 prev_buffer->fragment = is_fragment(inode);
6324- queue_put(from_reader, prev_buffer);
6325+ put_file_buffer(prev_buffer);
6326
6327 return;
6328
6329+read_err2:
6330+ close(file);
6331 read_err:
6332 if(prev_buffer) {
6333 cache_block_put(file_buffer);
6334@@ -2040,7 +2143,7 @@
6335 file_buffer = prev_buffer;
6336 }
6337 file_buffer->error = TRUE;
6338- queue_put(from_deflate, file_buffer);
6339+ put_file_buffer(file_buffer);
6340 }
6341
6342
6343@@ -2048,7 +2151,7 @@
6344 {
6345 struct stat *buf = &dir_ent->inode->buf, buf2;
6346 struct file_buffer *file_buffer;
6347- int blocks, byte, count, expected, file, res;
6348+ int blocks, file, res;
6349 long long bytes, read_size;
6350 struct inode_info *inode = dir_ent->inode;
6351
6352@@ -2058,28 +2161,22 @@
6353 inode->read = TRUE;
6354 again:
6355 bytes = 0;
6356- count = 0;
6357- file_buffer = NULL;
6358 read_size = buf->st_size;
6359 blocks = (read_size + block_size - 1) >> block_log;
6360
6361 file = open(pathname_reader(dir_ent), O_RDONLY);
6362 if(file == -1) {
6363- file_buffer = cache_get(reader_buffer, 0, 0);
6364+ file_buffer = cache_get_nohash(reader_buffer);
6365 file_buffer->sequence = seq ++;
6366 goto read_err2;
6367 }
6368
6369 do {
6370- expected = read_size - ((long long) count * block_size) >
6371- block_size ? block_size :
6372- read_size - ((long long) count * block_size);
6373-
6374- if(file_buffer)
6375- queue_put(from_reader, file_buffer);
6376- file_buffer = cache_get(reader_buffer, 0, 0);
6377+ file_buffer = cache_get_nohash(reader_buffer);
6378+ file_buffer->file_size = read_size;
6379 file_buffer->sequence = seq ++;
6380 file_buffer->noD = inode->noD;
6381+ file_buffer->error = FALSE;
6382
6383 /*
6384 * Always try to read block_size bytes from the file rather
6385@@ -2090,29 +2187,28 @@
6386 * case where the file is an exact multiple of the block_size
6387 * is dealt with later.
6388 */
6389- byte = file_buffer->size = read_bytes(file, file_buffer->data,
6390+ file_buffer->size = read_bytes(file, file_buffer->data,
6391 block_size);
6392-
6393- file_buffer->file_size = read_size;
6394-
6395- if(byte == -1)
6396+ if(file_buffer->size == -1)
6397 goto read_err;
6398
6399- if(byte != expected)
6400- goto restat;
6401+ bytes += file_buffer->size;
6402
6403- file_buffer->block = count;
6404- file_buffer->error = FALSE;
6405- file_buffer->fragment = FALSE;
6406+ if(blocks > 1) {
6407+ /* non-tail block should be exactly block_size */
6408+ if(file_buffer->size < block_size)
6409+ goto restat;
6410
6411- bytes += byte;
6412- count ++;
6413- } while(count < blocks);
6414+ file_buffer->fragment = FALSE;
6415+ put_file_buffer(file_buffer);
6416+ }
6417+ } while(-- blocks > 0);
6418
6419+ /* Overall size including tail should match */
6420 if(read_size != bytes)
6421 goto restat;
6422
6423- if(expected == block_size) {
6424+ if(read_size && read_size % block_size == 0) {
6425 /*
6426 * Special case where we've not tried to read past the end of
6427 * the file. We expect to get EOF, i.e. the file isn't larger
6428@@ -2130,7 +2226,7 @@
6429 }
6430
6431 file_buffer->fragment = is_fragment(inode);
6432- queue_put(from_reader, file_buffer);
6433+ put_file_buffer(file_buffer);
6434
6435 close(file);
6436
6437@@ -2139,7 +2235,7 @@
6438 restat:
6439 res = fstat(file, &buf2);
6440 if(res == -1) {
6441- ERROR("Cannot stat dir/file %s because %s, ignoring\n",
6442+ ERROR("Cannot stat dir/file %s because %s\n",
6443 pathname_reader(dir_ent), strerror(errno));
6444 goto read_err;
6445 }
6446@@ -2148,14 +2244,14 @@
6447 close(file);
6448 memcpy(buf, &buf2, sizeof(struct stat));
6449 file_buffer->error = 2;
6450- queue_put(from_deflate, file_buffer);
6451+ put_file_buffer(file_buffer);
6452 goto again;
6453 }
6454 read_err:
6455 close(file);
6456 read_err2:
6457 file_buffer->error = TRUE;
6458- queue_put(from_deflate, file_buffer);
6459+ put_file_buffer(file_buffer);
6460 }
6461
6462
6463@@ -2261,6 +2357,7 @@
6464
6465 void *deflator(void *arg)
6466 {
6467+ struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer);
6468 void *stream = NULL;
6469 int res;
6470
6471@@ -2269,20 +2366,12 @@
6472 BAD_ERROR("deflator:: compressor_init failed\n");
6473
6474 while(1) {
6475- struct file_buffer *file_buffer = queue_get(from_reader);
6476- struct file_buffer *write_buffer;
6477+ struct file_buffer *file_buffer = queue_get(to_deflate);
6478
6479- if(file_buffer->file_size == 0) {
6480+ if(sparse_files && all_zero(file_buffer)) {
6481 file_buffer->c_byte = 0;
6482- queue_put(from_deflate, file_buffer);
6483- } else if(sparse_files && all_zero(file_buffer)) {
6484- file_buffer->c_byte = 0;
6485- queue_put(from_deflate, file_buffer);
6486- } else if(file_buffer->fragment) {
6487- file_buffer->c_byte = file_buffer->size;
6488- queue_put(from_deflate, file_buffer);
6489+ seq_queue_put(to_main, file_buffer);
6490 } else {
6491- write_buffer = cache_get(writer_buffer, 0, 0);
6492 write_buffer->c_byte = mangle2(stream,
6493 write_buffer->data, file_buffer->data,
6494 file_buffer->size, block_size,
6495@@ -2295,7 +2384,8 @@
6496 write_buffer->fragment = FALSE;
6497 write_buffer->error = FALSE;
6498 cache_block_put(file_buffer);
6499- queue_put(from_deflate, write_buffer);
6500+ seq_queue_put(to_main, write_buffer);
6501+ write_buffer = cache_get_nohash(bwriter_buffer);
6502 }
6503 }
6504 }
6505@@ -2310,18 +2400,18 @@
6506 if(res)
6507 BAD_ERROR("frag_deflator:: compressor_init failed\n");
6508
6509+ pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
6510+
6511 while(1) {
6512 int c_byte, compressed_size;
6513 struct file_buffer *file_buffer = queue_get(to_frag);
6514 struct file_buffer *write_buffer =
6515- cache_get(writer_buffer, file_buffer->block +
6516- FRAG_INDEX, 1);
6517+ cache_get(fwriter_buffer, file_buffer->block);
6518
6519 c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
6520 file_buffer->size, block_size, noF, 1);
6521 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
6522 write_buffer->size = compressed_size;
6523- pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
6524 pthread_mutex_lock(&fragment_mutex);
6525 if(fragments_locked == FALSE) {
6526 fragment_table[file_buffer->block].size = c_byte;
6527@@ -2330,137 +2420,73 @@
6528 bytes += compressed_size;
6529 fragments_outstanding --;
6530 queue_put(to_writer, write_buffer);
6531+ pthread_mutex_unlock(&fragment_mutex);
6532 TRACE("Writing fragment %lld, uncompressed size %d, "
6533 "compressed size %d\n", file_buffer->block,
6534 file_buffer->size, compressed_size);
6535- } else
6536+ } else {
6537 add_pending_fragment(write_buffer, c_byte,
6538 file_buffer->block);
6539- pthread_cleanup_pop(1);
6540+ pthread_mutex_unlock(&fragment_mutex);
6541+ }
6542 cache_block_put(file_buffer);
6543 }
6544-}
6545-
6546
6547-#define HASH_ENTRIES 256
6548-#define BLOCK_HASH(a) (a % HASH_ENTRIES)
6549-struct file_buffer *block_hash[HASH_ENTRIES];
6550-
6551-void push_buffer(struct file_buffer *file_buffer)
6552-{
6553- int hash = BLOCK_HASH(file_buffer->sequence);
6554-
6555- file_buffer->next = block_hash[hash];
6556- block_hash[hash] = file_buffer;
6557+ pthread_cleanup_pop(0);
6558 }
6559
6560
6561-struct file_buffer *get_file_buffer(struct queue *queue)
6562+struct file_buffer *get_file_buffer()
6563 {
6564- static unsigned int sequence = 0;
6565- int hash = BLOCK_HASH(sequence);
6566- struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
6567-
6568- for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
6569- if(file_buffer->sequence == sequence)
6570- break;
6571-
6572- if(file_buffer) {
6573- if(prev)
6574- prev->next = file_buffer->next;
6575- else
6576- block_hash[hash] = file_buffer->next;
6577- } else {
6578- while(1) {
6579- file_buffer = queue_get(queue);
6580- if(file_buffer->sequence == sequence)
6581- break;
6582- push_buffer(file_buffer);
6583- }
6584- }
6585-
6586- sequence ++;
6587+ struct file_buffer *file_buffer = seq_queue_get(to_main);
6588
6589 return file_buffer;
6590 }
6591
6592
6593 void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
6594- int *duplicate_file)
6595+ struct file_buffer *file_buffer, int *duplicate_file)
6596 {
6597 file_count ++;
6598 *duplicate_file = FALSE;
6599+ cache_block_put(file_buffer);
6600 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
6601 NULL, &empty_fragment, NULL, 0);
6602 }
6603
6604
6605-void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
6606- int size, int *duplicate_file, struct file_buffer *file_buffer,
6607- unsigned short checksum)
6608-{
6609- struct file_info *dupl_ptr;
6610- struct fragment *fragment;
6611- unsigned int *block_listp = NULL;
6612- long long start = 0;
6613-
6614- dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
6615- file_buffer, 0, 0, checksum, TRUE);
6616-
6617- if(dupl_ptr) {
6618- *duplicate_file = FALSE;
6619- fragment = get_and_fill_fragment(file_buffer, dir_ent);
6620- dupl_ptr->fragment = fragment;
6621- } else
6622- *duplicate_file = TRUE;
6623-
6624- cache_block_put(file_buffer);
6625-
6626- total_bytes += size;
6627- file_count ++;
6628-
6629- inc_progress_bar();
6630-
6631- create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
6632- 0, NULL, fragment, NULL, 0);
6633-}
6634-
6635-
6636-void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
6637+void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent,
6638 struct file_buffer *file_buffer, int *duplicate_file)
6639 {
6640+ int size = file_buffer->file_size;
6641 struct fragment *fragment;
6642- unsigned short checksum;
6643-
6644- checksum = get_checksum_mem_buffer(file_buffer);
6645+ unsigned short checksum = file_buffer->checksum;
6646+ char dont_put;
6647
6648- if(pre_duplicate_frag(size, checksum)) {
6649- write_file_frag_dup(inode, dir_ent, size, duplicate_file,
6650- file_buffer, checksum);
6651- return;
6652+ fragment = frag_duplicate(file_buffer, &dont_put);
6653+ *duplicate_file = !fragment;
6654+ if(!fragment) {
6655+ fragment = get_and_fill_fragment(file_buffer, dir_ent);
6656+ if(duplicate_checking)
6657+ add_non_dup(size, 0, NULL, 0, fragment, 0, checksum,
6658+ TRUE, TRUE);
6659 }
6660-
6661- fragment = get_and_fill_fragment(file_buffer, dir_ent);
6662-
6663- cache_block_put(file_buffer);
6664
6665- if(duplicate_checking)
6666- add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
6667+ if(dont_put)
6668+ free(file_buffer);
6669+ else
6670+ cache_block_put(file_buffer);
6671
6672 total_bytes += size;
6673 file_count ++;
6674
6675- *duplicate_file = FALSE;
6676-
6677 inc_progress_bar();
6678
6679 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
6680 0, NULL, fragment, NULL, 0);
6681
6682- if(duplicate_checking == FALSE)
6683+ if(!duplicate_checking)
6684 free_fragment(fragment);
6685-
6686- return;
6687 }
6688
6689
6690@@ -2482,7 +2508,7 @@
6691 start = bytes;
6692 while (1) {
6693 read_size = read_buffer->file_size;
6694- if(read_buffer->fragment && read_buffer->c_byte)
6695+ if(read_buffer->fragment)
6696 fragment_buffer = read_buffer;
6697 else {
6698 block_list = realloc(block_list, (block + 1) *
6699@@ -2493,7 +2519,7 @@
6700 if(read_buffer->c_byte) {
6701 read_buffer->block = bytes;
6702 bytes += read_buffer->size;
6703- cache_rehash(read_buffer, read_buffer->block);
6704+ cache_hash(read_buffer, read_buffer->block);
6705 file_bytes += read_buffer->size;
6706 queue_put(to_writer, read_buffer);
6707 } else {
6708@@ -2506,18 +2532,19 @@
6709 if(read_size != -1)
6710 break;
6711
6712- read_buffer = get_file_buffer(from_deflate);
6713+ read_buffer = get_file_buffer();
6714 if(read_buffer->error)
6715 goto read_err;
6716 }
6717
6718 unlock_fragments();
6719 fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
6720- cache_block_put(fragment_buffer);
6721
6722 if(duplicate_checking)
6723 add_non_dup(read_size, file_bytes, block_list, start, fragment,
6724- 0, 0, FALSE);
6725+ 0, fragment_buffer ? fragment_buffer->checksum : 0,
6726+ FALSE, TRUE);
6727+ cache_block_put(fragment_buffer);
6728 file_count ++;
6729 total_bytes += read_size;
6730
6731@@ -2553,42 +2580,57 @@
6732 }
6733
6734
6735-int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
6736- long long read_size, struct file_buffer *read_buffer,
6737- int *duplicate_file)
6738+int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
6739+ struct file_buffer *read_buffer, int *duplicate_file)
6740 {
6741- long long file_bytes, start;
6742+ int block, thresh;
6743+ long long read_size = read_buffer->file_size;
6744+ long long file_bytes, dup_start, start;
6745 struct fragment *fragment;
6746- unsigned int *block_list;
6747- int block, status;
6748+ struct file_info *dupl_ptr;
6749 int blocks = (read_size + block_size - 1) >> block_log;
6750- long long sparse = 0;
6751+ unsigned int *block_list, *block_listp;
6752+ struct file_buffer **buffer_list;
6753+ int status;
6754+ long long sparse = 0;
6755 struct file_buffer *fragment_buffer = NULL;
6756
6757- *duplicate_file = FALSE;
6758-
6759 block_list = malloc(blocks * sizeof(unsigned int));
6760 if(block_list == NULL)
6761 MEM_ERROR();
6762+ block_listp = block_list;
6763+
6764+ buffer_list = malloc(blocks * sizeof(struct file_buffer *));
6765+ if(buffer_list == NULL)
6766+ MEM_ERROR();
6767
6768 lock_fragments();
6769
6770 file_bytes = 0;
6771- start = bytes;
6772+ start = dup_start = bytes;
6773+ thresh = blocks > bwriter_size ? blocks - bwriter_size : 0;
6774+
6775 for(block = 0; block < blocks;) {
6776- if(read_buffer->fragment && read_buffer->c_byte) {
6777+ if(read_buffer->fragment) {
6778 block_list[block] = 0;
6779+ buffer_list[block] = NULL;
6780 fragment_buffer = read_buffer;
6781 blocks = read_size >> block_log;
6782 } else {
6783 block_list[block] = read_buffer->c_byte;
6784+
6785 if(read_buffer->c_byte) {
6786 read_buffer->block = bytes;
6787 bytes += read_buffer->size;
6788- cache_rehash(read_buffer, read_buffer->block);
6789 file_bytes += read_buffer->size;
6790- queue_put(to_writer, read_buffer);
6791+ cache_hash(read_buffer, read_buffer->block);
6792+ if(block < thresh) {
6793+ buffer_list[block] = NULL;
6794+ queue_put(to_writer, read_buffer);
6795+ } else
6796+ buffer_list[block] = read_buffer;
6797 } else {
6798+ buffer_list[block] = NULL;
6799 sparse += read_buffer->size;
6800 cache_block_put(read_buffer);
6801 }
6802@@ -2596,19 +2638,43 @@
6803 inc_progress_bar();
6804
6805 if(++block < blocks) {
6806- read_buffer = get_file_buffer(from_deflate);
6807+ read_buffer = get_file_buffer();
6808 if(read_buffer->error)
6809 goto read_err;
6810 }
6811 }
6812
6813+ dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
6814+ &fragment, fragment_buffer, blocks, 0, FALSE);
6815+
6816+ if(dupl_ptr) {
6817+ *duplicate_file = FALSE;
6818+ for(block = thresh; block < blocks; block ++)
6819+ if(buffer_list[block])
6820+ queue_put(to_writer, buffer_list[block]);
6821+ fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
6822+ dupl_ptr->fragment = fragment;
6823+ } else {
6824+ *duplicate_file = TRUE;
6825+ for(block = thresh; block < blocks; block ++)
6826+ cache_block_put(buffer_list[block]);
6827+ bytes = start;
6828+ if(thresh && !block_device) {
6829+ int res;
6830+
6831+ queue_put(to_writer, NULL);
6832+ if(queue_get(from_writer) != 0)
6833+ EXIT_MKSQUASHFS();
6834+ res = ftruncate(fd, bytes);
6835+ if(res != 0)
6836+ BAD_ERROR("Failed to truncate dest file because"
6837+ " %s\n", strerror(errno));
6838+ }
6839+ }
6840+
6841 unlock_fragments();
6842- fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
6843 cache_block_put(fragment_buffer);
6844-
6845- if(duplicate_checking)
6846- add_non_dup(read_size, file_bytes, block_list, start, fragment,
6847- 0, 0, FALSE);
6848+ free(buffer_list);
6849 file_count ++;
6850 total_bytes += read_size;
6851
6852@@ -2623,13 +2689,11 @@
6853 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
6854 sparse = 0;
6855
6856- create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
6857- blocks, block_list, fragment, NULL, sparse);
6858+ create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
6859+ dup_start, blocks, block_listp, fragment, NULL, sparse);
6860
6861- if(duplicate_checking == FALSE) {
6862+ if(*duplicate_file == TRUE)
6863 free(block_list);
6864- free_fragment(fragment);
6865- }
6866
6867 return 0;
6868
6869@@ -2637,7 +2701,7 @@
6870 dec_progress_bar(block);
6871 status = read_buffer->error;
6872 bytes = start;
6873- if(!block_device) {
6874+ if(thresh && !block_device) {
6875 int res;
6876
6877 queue_put(to_writer, NULL);
6878@@ -2649,64 +2713,54 @@
6879 strerror(errno));
6880 }
6881 unlock_fragments();
6882+ for(blocks = thresh; blocks < block; blocks ++)
6883+ cache_block_put(buffer_list[blocks]);
6884+ free(buffer_list);
6885 free(block_list);
6886 cache_block_put(read_buffer);
6887 return status;
6888 }
6889
6890
6891-int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
6892- long long read_size, struct file_buffer *read_buffer,
6893- int *duplicate_file)
6894+int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
6895+ struct file_buffer *read_buffer, int *dup)
6896 {
6897- int block, thresh;
6898- long long file_bytes, dup_start, start;
6899+ long long read_size = read_buffer->file_size;
6900+ long long file_bytes, start;
6901 struct fragment *fragment;
6902- struct file_info *dupl_ptr;
6903+ unsigned int *block_list;
6904+ int block, status;
6905 int blocks = (read_size + block_size - 1) >> block_log;
6906- unsigned int *block_list, *block_listp;
6907- struct file_buffer **buffer_list;
6908- int status, num_locked_fragments;
6909 long long sparse = 0;
6910 struct file_buffer *fragment_buffer = NULL;
6911
6912+ if(pre_duplicate(read_size))
6913+ return write_file_blocks_dup(inode, dir_ent, read_buffer, dup);
6914+
6915+ *dup = FALSE;
6916+
6917 block_list = malloc(blocks * sizeof(unsigned int));
6918 if(block_list == NULL)
6919 MEM_ERROR();
6920- block_listp = block_list;
6921
6922- buffer_list = malloc(blocks * sizeof(struct file_buffer *));
6923- if(buffer_list == NULL)
6924- MEM_ERROR();
6925-
6926- num_locked_fragments = lock_fragments();
6927+ lock_fragments();
6928
6929 file_bytes = 0;
6930- start = dup_start = bytes;
6931- thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
6932- blocks - (writer_buffer_size - num_locked_fragments): 0;
6933-
6934+ start = bytes;
6935 for(block = 0; block < blocks;) {
6936- if(read_buffer->fragment && read_buffer->c_byte) {
6937+ if(read_buffer->fragment) {
6938 block_list[block] = 0;
6939- buffer_list[block] = NULL;
6940 fragment_buffer = read_buffer;
6941 blocks = read_size >> block_log;
6942 } else {
6943 block_list[block] = read_buffer->c_byte;
6944-
6945 if(read_buffer->c_byte) {
6946 read_buffer->block = bytes;
6947 bytes += read_buffer->size;
6948+ cache_hash(read_buffer, read_buffer->block);
6949 file_bytes += read_buffer->size;
6950- cache_rehash(read_buffer, read_buffer->block);
6951- if(block < thresh) {
6952- buffer_list[block] = NULL;
6953- queue_put(to_writer, read_buffer);
6954- } else
6955- buffer_list[block] = read_buffer;
6956+ queue_put(to_writer, read_buffer);
6957 } else {
6958- buffer_list[block] = NULL;
6959 sparse += read_buffer->size;
6960 cache_block_put(read_buffer);
6961 }
6962@@ -2714,43 +2768,20 @@
6963 inc_progress_bar();
6964
6965 if(++block < blocks) {
6966- read_buffer = get_file_buffer(from_deflate);
6967+ read_buffer = get_file_buffer();
6968 if(read_buffer->error)
6969 goto read_err;
6970 }
6971 }
6972
6973- dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
6974- &fragment, fragment_buffer, blocks, 0, 0, FALSE);
6975-
6976- if(dupl_ptr) {
6977- *duplicate_file = FALSE;
6978- for(block = thresh; block < blocks; block ++)
6979- if(buffer_list[block])
6980- queue_put(to_writer, buffer_list[block]);
6981- fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
6982- dupl_ptr->fragment = fragment;
6983- } else {
6984- *duplicate_file = TRUE;
6985- for(block = thresh; block < blocks; block ++)
6986- cache_block_put(buffer_list[block]);
6987- bytes = start;
6988- if(thresh && !block_device) {
6989- int res;
6990-
6991- queue_put(to_writer, NULL);
6992- if(queue_get(from_writer) != 0)
6993- EXIT_MKSQUASHFS();
6994- res = ftruncate(fd, bytes);
6995- if(res != 0)
6996- BAD_ERROR("Failed to truncate dest file because"
6997- " %s\n", strerror(errno));
6998- }
6999- }
7000-
7001 unlock_fragments();
7002+ fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
7003+
7004+ if(duplicate_checking)
7005+ add_non_dup(read_size, file_bytes, block_list, start, fragment,
7006+ 0, fragment_buffer ? fragment_buffer->checksum : 0,
7007+ FALSE, TRUE);
7008 cache_block_put(fragment_buffer);
7009- free(buffer_list);
7010 file_count ++;
7011 total_bytes += read_size;
7012
7013@@ -2765,11 +2796,13 @@
7014 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
7015 sparse = 0;
7016
7017- create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
7018- dup_start, blocks, block_listp, fragment, NULL, sparse);
7019+ create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
7020+ blocks, block_list, fragment, NULL, sparse);
7021
7022- if(*duplicate_file == TRUE)
7023+ if(duplicate_checking == FALSE) {
7024 free(block_list);
7025+ free_fragment(fragment);
7026+ }
7027
7028 return 0;
7029
7030@@ -2777,7 +2810,7 @@
7031 dec_progress_bar(block);
7032 status = read_buffer->error;
7033 bytes = start;
7034- if(thresh && !block_device) {
7035+ if(!block_device) {
7036 int res;
7037
7038 queue_put(to_writer, NULL);
7039@@ -2789,58 +2822,40 @@
7040 strerror(errno));
7041 }
7042 unlock_fragments();
7043- for(blocks = thresh; blocks < block; blocks ++)
7044- cache_block_put(buffer_list[blocks]);
7045- free(buffer_list);
7046 free(block_list);
7047 cache_block_put(read_buffer);
7048 return status;
7049 }
7050
7051
7052-void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
7053- int *duplicate_file)
7054+void write_file(squashfs_inode *inode, struct dir_ent *dir, int *dup)
7055 {
7056 int status;
7057 struct file_buffer *read_buffer;
7058- long long read_size;
7059
7060 again:
7061- read_buffer = get_file_buffer(from_deflate);
7062-
7063+ read_buffer = get_file_buffer();
7064 status = read_buffer->error;
7065- if(status) {
7066- cache_block_put(read_buffer);
7067- goto file_err;
7068- }
7069-
7070- read_size = read_buffer->file_size;
7071
7072- if(read_size == -1)
7073- status = write_file_process(inode, dir_ent, read_buffer,
7074- duplicate_file);
7075- else if(read_size == 0) {
7076- write_file_empty(inode, dir_ent, duplicate_file);
7077+ if(status)
7078 cache_block_put(read_buffer);
7079- } else if(read_buffer->fragment && read_buffer->c_byte)
7080- write_file_frag(inode, dir_ent, read_size, read_buffer,
7081- duplicate_file);
7082- else if(pre_duplicate(read_size))
7083- status = write_file_blocks_dup(inode, dir_ent, read_size,
7084- read_buffer, duplicate_file);
7085+ else if(read_buffer->file_size == -1)
7086+ status = write_file_process(inode, dir, read_buffer, dup);
7087+ else if(read_buffer->file_size == 0)
7088+ write_file_empty(inode, dir, read_buffer, dup);
7089+ else if(read_buffer->fragment && read_buffer->c_byte)
7090+ write_file_frag(inode, dir, read_buffer, dup);
7091 else
7092- status = write_file_blocks(inode, dir_ent, read_size,
7093- read_buffer, duplicate_file);
7094+ status = write_file_blocks(inode, dir, read_buffer, dup);
7095
7096-file_err:
7097 if(status == 2) {
7098 ERROR("File %s changed size while reading filesystem, "
7099- "attempting to re-read\n", pathname(dir_ent));
7100+ "attempting to re-read\n", pathname(dir));
7101 goto again;
7102 } else if(status == 1) {
7103- ERROR("Failed to read file %s, creating empty file\n",
7104- pathname(dir_ent));
7105- write_file_empty(inode, dir_ent, duplicate_file);
7106+ ERROR_START("Failed to read file %s", pathname(dir));
7107+ ERROR_EXIT(", creating empty file\n");
7108+ write_file_empty(inode, dir, NULL, dup);
7109 }
7110 }
7111
7112@@ -2921,7 +2936,8 @@
7113 }
7114
7115
7116-struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
7117+struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id,
7118+ char *symlink, int bytes)
7119 {
7120 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
7121 struct inode_info *inode;
7122@@ -2941,10 +2957,12 @@
7123 }
7124 }
7125
7126- inode = malloc(sizeof(struct inode_info));
7127+ inode = malloc(sizeof(struct inode_info) + bytes);
7128 if(inode == NULL)
7129 MEM_ERROR();
7130
7131+ if(bytes)
7132+ memcpy(&inode->symlink, symlink, bytes);
7133 memcpy(&inode->buf, buf, sizeof(struct stat));
7134 inode->read = FALSE;
7135 inode->root_entry = FALSE;
7136@@ -2965,9 +2983,6 @@
7137 inode->noD = noD;
7138 inode->noF = noF;
7139
7140- if((buf->st_mode & S_IFMT) == S_IFREG)
7141- progress_bar_size((buf->st_size + block_size - 1) >> block_log);
7142-
7143 inode->next = inode_info[ino_hash];
7144 inode_info[ino_hash] = inode;
7145
7146@@ -2975,6 +2990,12 @@
7147 }
7148
7149
7150+struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
7151+{
7152+ return lookup_inode3(buf, pseudo, id, NULL, 0);
7153+}
7154+
7155+
7156 inline struct inode_info *lookup_inode(struct stat *buf)
7157 {
7158 return lookup_inode2(buf, 0, 0);
7159@@ -2983,8 +3004,12 @@
7160
7161 inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
7162 {
7163- if (inode->inode_number == 0)
7164+ if (inode->inode_number == 0) {
7165 inode->inode_number = use_this ? : inode_no ++;
7166+ if((inode->buf.st_mode & S_IFMT) == S_IFREG)
7167+ progress_bar_size((inode->buf.st_size + block_size - 1)
7168+ >> block_log);
7169+ }
7170 }
7171
7172
7173@@ -2999,6 +3024,7 @@
7174 dir_ent->source_name = source_name;
7175 dir_ent->nonstandard_pathname = nonstandard_pathname;
7176 dir_ent->our_dir = dir;
7177+ dir_ent->inode = NULL;
7178 dir_ent->next = NULL;
7179
7180 return dir_ent;
7181@@ -3041,6 +3067,15 @@
7182 if(dir_ent->source_name)
7183 free(dir_ent->source_name);
7184
7185+ if(dir_ent->nonstandard_pathname)
7186+ free(dir_ent->nonstandard_pathname);
7187+
7188+ /* if this entry has been associated with an inode, then we need
7189+ * to update the inode nlink count. Orphaned inodes are harmless, and
7190+ * is easier to leave them than go to the bother of deleting them */
7191+ if(dir_ent->inode && !dir_ent->inode->root_entry)
7192+ dir_ent->inode->nlink --;
7193+
7194 free(dir_ent);
7195 }
7196
7197@@ -3051,42 +3086,18 @@
7198 }
7199
7200
7201-
7202 void dir_scan(squashfs_inode *inode, char *pathname,
7203- struct dir_ent *(_readdir)(struct dir_info *))
7204+ struct dir_ent *(_readdir)(struct dir_info *), int progress)
7205 {
7206 struct stat buf;
7207- struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
7208 struct dir_ent *dir_ent;
7209
7210- if(dir_info == NULL)
7211+ root_dir = dir_scan1(pathname, "", paths, _readdir, 1);
7212+ if(root_dir == NULL)
7213 return;
7214
7215- /*
7216- * Process most actions and any pseudo files
7217- */
7218- if(actions() || get_pseudo())
7219- dir_scan2(dir_info, get_pseudo());
7220-
7221- /*
7222- * Process move actions
7223- */
7224- if(move_actions()) {
7225- dir_scan3(dir_info, dir_info);
7226- do_move_actions();
7227- }
7228-
7229- /*
7230- * Process empty actions
7231- */
7232- if(empty_actions())
7233- dir_scan4(dir_info);
7234-
7235- /*
7236- * Sort directories and compute the inode numbers
7237- */
7238- dir_scan5(dir_info);
7239-
7240+ /* Create root directory dir_ent and associated inode, and connect
7241+ * it to the root directory dir_info structure */
7242 dir_ent = create_dir_entry("", NULL, pathname,
7243 scan1_opendir("", "", 0));
7244
7245@@ -3111,21 +3122,69 @@
7246 dir_ent->inode = lookup_inode(&buf);
7247 }
7248
7249+ dir_ent->dir = root_dir;
7250+ root_dir->dir_ent = dir_ent;
7251+
7252+ /*
7253+ * Process most actions and any pseudo files
7254+ */
7255+ if(actions() || get_pseudo())
7256+ dir_scan2(root_dir, get_pseudo());
7257+
7258+ /*
7259+ * Process move actions
7260+ */
7261+ if(move_actions()) {
7262+ dir_scan3(root_dir);
7263+ do_move_actions();
7264+ }
7265+
7266+ /*
7267+ * Process prune actions
7268+ */
7269+ if(prune_actions())
7270+ dir_scan4(root_dir);
7271+
7272+ /*
7273+ * Process empty actions
7274+ */
7275+ if(empty_actions())
7276+ dir_scan5(root_dir);
7277+
7278+ /*
7279+ * Sort directories and compute the inode numbers
7280+ */
7281+ dir_scan6(root_dir);
7282+
7283 alloc_inode_no(dir_ent->inode, root_inode_number);
7284- dir_ent->dir = dir_info;
7285- dir_info->dir_ent = dir_ent;
7286
7287- eval_actions(dir_ent);
7288+ eval_actions(root_dir, dir_ent);
7289
7290 if(sorted)
7291- generate_file_priorities(dir_info, 0,
7292- &dir_info->dir_ent->inode->buf);
7293- queue_put(to_reader, dir_info);
7294+ generate_file_priorities(root_dir, 0,
7295+ &root_dir->dir_ent->inode->buf);
7296+
7297+ if(appending) {
7298+ sigset_t sigmask;
7299+
7300+ restore_thread = init_restore_thread();
7301+ sigemptyset(&sigmask);
7302+ sigaddset(&sigmask, SIGINT);
7303+ sigaddset(&sigmask, SIGTERM);
7304+ sigaddset(&sigmask, SIGUSR1);
7305+ if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
7306+ BAD_ERROR("Failed to set signal mask\n");
7307+ write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
7308+ }
7309+
7310+ queue_put(to_reader, root_dir);
7311+
7312+ set_progressbar_state(progress);
7313+
7314 if(sorted)
7315- sort_files_and_write(dir_info);
7316- if(progress)
7317- enable_progress_bar();
7318- dir_scan6(inode, dir_info);
7319+ sort_files_and_write(root_dir);
7320+
7321+ dir_scan7(inode, root_dir);
7322 dir_ent->inode->inode = *inode;
7323 dir_ent->inode->type = SQUASHFS_DIR_TYPE;
7324 }
7325@@ -3187,8 +3246,9 @@
7326 int pass = 1, res;
7327
7328 if(dir_name == NULL) {
7329- ERROR("Bad source directory %s - skipping ...\n",
7330+ ERROR_START("Bad source directory %s",
7331 source_path[index]);
7332+ ERROR_EXIT(" - skipping ...\n");
7333 index ++;
7334 continue;
7335 }
7336@@ -3213,7 +3273,7 @@
7337 ERROR("%s\n", dir_name);
7338 }
7339 return create_dir_entry(dir_name, basename,
7340- source_path[index ++], dir);
7341+ strdup(source_path[index ++]), dir);
7342 }
7343 return NULL;
7344 }
7345@@ -3289,7 +3349,8 @@
7346 struct dir_ent *dir_ent;
7347
7348 if(dir == NULL) {
7349- ERROR("Could not open %s, skipping...\n", filename);
7350+ ERROR_START("Could not open %s", filename);
7351+ ERROR_EXIT(", skipping...\n");
7352 return NULL;
7353 }
7354
7355@@ -3307,8 +3368,9 @@
7356 }
7357
7358 if(lstat(filename, &buf) == -1) {
7359- ERROR("Cannot stat dir/file %s because %s, ignoring\n",
7360+ ERROR_START("Cannot stat dir/file %s because %s",
7361 filename, strerror(errno));
7362+ ERROR_EXIT(", ignoring\n");
7363 free_dir_entry(dir_ent);
7364 continue;
7365 }
7366@@ -3320,8 +3382,9 @@
7367 (buf.st_mode & S_IFMT) != S_IFBLK &&
7368 (buf.st_mode & S_IFMT) != S_IFIFO &&
7369 (buf.st_mode & S_IFMT) != S_IFSOCK) {
7370- ERROR("File %s has unrecognised filetype %d, ignoring"
7371- "\n", filename, buf.st_mode & S_IFMT);
7372+ ERROR_START("File %s has unrecognised filetype %d",
7373+ filename, buf.st_mode & S_IFMT);
7374+ ERROR_EXIT(", ignoring\n");
7375 free_dir_entry(dir_ent);
7376 continue;
7377 }
7378@@ -3337,30 +3400,53 @@
7379 subpath = subpathname(dir_ent);
7380
7381 if(eval_exclude_actions(dir_name, filename, subpath,
7382- &buf, depth)) {
7383+ &buf, depth, dir_ent)) {
7384 add_excluded(dir);
7385 free_dir_entry(dir_ent);
7386 continue;
7387 }
7388 }
7389
7390- if((buf.st_mode & S_IFMT) == S_IFDIR) {
7391+ switch(buf.st_mode & S_IFMT) {
7392+ case S_IFDIR:
7393 if(subpath == NULL)
7394 subpath = subpathname(dir_ent);
7395
7396 sub_dir = dir_scan1(filename, subpath, new,
7397 scan1_readdir, depth + 1);
7398- if(sub_dir == NULL) {
7399+ if(sub_dir) {
7400+ dir->directory_count ++;
7401+ add_dir_entry(dir_ent, sub_dir,
7402+ lookup_inode(&buf));
7403+ } else
7404 free_dir_entry(dir_ent);
7405- free(new);
7406- continue;
7407+ break;
7408+ case S_IFLNK: {
7409+ int byte;
7410+ static char buff[65536]; /* overflow safe */
7411+
7412+ byte = readlink(filename, buff, 65536);
7413+ if(byte == -1) {
7414+ ERROR_START("Failed to read symlink %s",
7415+ filename);
7416+ ERROR_EXIT(", ignoring\n");
7417+ } else if(byte == 65536) {
7418+ ERROR_START("Symlink %s is greater than 65536 "
7419+ "bytes!", filename);
7420+ ERROR_EXIT(", ignoring\n");
7421+ } else {
7422+ /* readlink doesn't 0 terminate the returned
7423+ * path */
7424+ buff[byte] = '\0';
7425+ add_dir_entry(dir_ent, NULL, lookup_inode3(&buf,
7426+ 0, 0, buff, byte + 1));
7427 }
7428+ break;
7429+ }
7430+ default:
7431+ add_dir_entry(dir_ent, NULL, lookup_inode(&buf));
7432+ }
7433
7434- dir->directory_count ++;
7435- } else
7436- sub_dir = NULL;
7437-
7438- add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
7439 free(new);
7440 }
7441
7442@@ -3410,7 +3496,7 @@
7443 struct stat *buf = &inode_info->buf;
7444 char *name = dir_ent->name;
7445
7446- eval_actions(dir_ent);
7447+ eval_actions(root_dir, dir_ent);
7448
7449 if((buf->st_mode & S_IFMT) == S_IFDIR)
7450 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
7451@@ -3421,16 +3507,18 @@
7452 if(pseudo_ent->dev->type == 'm') {
7453 struct stat *buf;
7454 if(dir_ent == NULL) {
7455- ERROR("Pseudo modify file \"%s\" does not exist "
7456- "in source filesystem. Ignoring.\n",
7457+ ERROR_START("Pseudo modify file \"%s\" does "
7458+ "not exist in source filesystem.",
7459 pseudo_ent->pathname);
7460+ ERROR_EXIT(" Ignoring.\n");
7461 continue;
7462 }
7463 if(dir_ent->inode->root_entry) {
7464- ERROR("Pseudo modify file \"%s\" is a pre-existing"
7465- " file in the filesystem being appended"
7466- " to. It cannot be modified. "
7467- "Ignoring.\n", pseudo_ent->pathname);
7468+ ERROR_START("Pseudo modify file \"%s\" is a "
7469+ "pre-existing file in the filesystem "
7470+ "being appended to. It cannot be "\
7471+ "modified.", pseudo_ent->pathname);
7472+ ERROR_EXIT(" Ignoring.\n");
7473 continue;
7474 }
7475 buf = &dir_ent->inode->buf;
7476@@ -3442,17 +3530,20 @@
7477 }
7478
7479 if(dir_ent) {
7480- if(dir_ent->inode->root_entry)
7481- ERROR("Pseudo file \"%s\" is a pre-existing"
7482- " file in the filesystem being appended"
7483- " to. Ignoring.\n",
7484+ if(dir_ent->inode->root_entry) {
7485+ ERROR_START("Pseudo file \"%s\" is a "
7486+ "pre-existing file in the filesystem "
7487+ "being appended to.",
7488 pseudo_ent->pathname);
7489- else
7490- ERROR("Pseudo file \"%s\" exists in source "
7491- "filesystem \"%s\".\nIgnoring, "
7492- "exclude it (-e/-ef) to override.\n",
7493+ ERROR_EXIT(" Ignoring.\n");
7494+ } else {
7495+ ERROR_START("Pseudo file \"%s\" exists in "
7496+ "source filesystem \"%s\".",
7497 pseudo_ent->pathname,
7498 pathname(dir_ent));
7499+ ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to "
7500+ "override.\n");
7501+ }
7502 continue;
7503 }
7504
7505@@ -3473,9 +3564,9 @@
7506 struct dir_info *sub_dir = scan1_opendir("", subpath,
7507 dir->depth + 1);
7508 if(sub_dir == NULL) {
7509- ERROR("Could not create pseudo directory \"%s\""
7510- ", skipping...\n",
7511- pseudo_ent->pathname);
7512+ ERROR_START("Could not create pseudo directory "
7513+ "\"%s\"", pseudo_ent->pathname);
7514+ ERROR_EXIT(", skipping...\n");
7515 free(subpath);
7516 pseudo_ino --;
7517 continue;
7518@@ -3485,25 +3576,10 @@
7519 add_dir_entry(dir_ent, sub_dir,
7520 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
7521 } else if(pseudo_ent->dev->type == 'f') {
7522-#ifdef USE_TMP_FILE
7523- struct stat buf2;
7524- int res = stat(pseudo_ent->dev->filename, &buf2);
7525- if(res == -1) {
7526- ERROR("Stat on pseudo file \"%s\" failed, "
7527- "skipping...\n", pseudo_ent->pathname);
7528- pseudo_ino --;
7529- continue;
7530- }
7531- buf.st_size = buf2.st_size;
7532- add_dir_entry2(pseudo_ent->name, NULL,
7533- pseudo_ent->dev->filename, NULL,
7534- lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
7535-#else
7536 add_dir_entry2(pseudo_ent->name, NULL,
7537 pseudo_ent->pathname, NULL,
7538 lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
7539 pseudo_ent->dev->pseudo_id), dir);
7540-#endif
7541 } else {
7542 add_dir_entry2(pseudo_ent->name, NULL,
7543 pseudo_ent->pathname, NULL,
7544@@ -3517,35 +3593,113 @@
7545 * dir_scan3 routines...
7546 * This processes the move action
7547 */
7548-void dir_scan3(struct dir_info *root, struct dir_info *dir)
7549+void dir_scan3(struct dir_info *dir)
7550 {
7551 struct dir_ent *dir_ent = NULL;
7552
7553 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
7554
7555- eval_move_actions(root, dir_ent);
7556+ eval_move_actions(root_dir, dir_ent);
7557
7558 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
7559- dir_scan3(root, dir_ent->dir);
7560+ dir_scan3(dir_ent->dir);
7561 }
7562 }
7563
7564
7565 /*
7566 * dir_scan4 routines...
7567+ * This processes the prune action. This action is designed to do fine
7568+ * grained tuning of the in-core directory structure after the exclude,
7569+ * move and pseudo actions have been performed. This allows complex
7570+ * tests to be performed which are impossible at exclude time (i.e.
7571+ * tests which rely on the in-core directory structure)
7572+ */
7573+void free_dir(struct dir_info *dir)
7574+{
7575+ struct dir_ent *dir_ent = dir->list;
7576+
7577+ while(dir_ent) {
7578+ struct dir_ent *tmp = dir_ent;
7579+
7580+ if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
7581+ free_dir(dir_ent->dir);
7582+
7583+ dir_ent = dir_ent->next;
7584+ free_dir_entry(tmp);
7585+ }
7586+
7587+ free(dir->pathname);
7588+ free(dir->subpath);
7589+ free(dir);
7590+}
7591+
7592+
7593+void dir_scan4(struct dir_info *dir)
7594+{
7595+ struct dir_ent *dir_ent = dir->list, *prev = NULL;
7596+
7597+ while(dir_ent) {
7598+ if(dir_ent->inode->root_entry) {
7599+ prev = dir_ent;
7600+ dir_ent = dir_ent->next;
7601+ continue;
7602+ }
7603+
7604+ if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
7605+ dir_scan4(dir_ent->dir);
7606+
7607+ if(eval_prune_actions(root_dir, dir_ent)) {
7608+ struct dir_ent *tmp = dir_ent;
7609+
7610+ if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
7611+ free_dir(dir_ent->dir);
7612+ dir->directory_count --;
7613+ }
7614+
7615+ dir->count --;
7616+
7617+ /* remove dir_ent from list */
7618+ dir_ent = dir_ent->next;
7619+ if(prev)
7620+ prev->next = dir_ent;
7621+ else
7622+ dir->list = dir_ent;
7623+
7624+ /* free it */
7625+ free_dir_entry(tmp);
7626+
7627+ add_excluded(dir);
7628+ continue;
7629+ }
7630+
7631+ prev = dir_ent;
7632+ dir_ent = dir_ent->next;
7633+ }
7634+}
7635+
7636+
7637+/*
7638+ * dir_scan5 routines...
7639 * This processes the empty action. This action has to be processed after
7640 * all other actions because the previous exclude and move actions and the
7641 * pseudo actions affect whether a directory is empty
7642 */
7643-void dir_scan4(struct dir_info *dir)
7644+void dir_scan5(struct dir_info *dir)
7645 {
7646 struct dir_ent *dir_ent = dir->list, *prev = NULL;
7647
7648 while(dir_ent) {
7649+ if(dir_ent->inode->root_entry) {
7650+ prev = dir_ent;
7651+ dir_ent = dir_ent->next;
7652+ continue;
7653+ }
7654+
7655 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
7656- dir_scan4(dir_ent->dir);
7657+ dir_scan5(dir_ent->dir);
7658
7659- if(eval_empty_actions(dir_ent)) {
7660+ if(eval_empty_actions(root_dir, dir_ent)) {
7661 struct dir_ent *tmp = dir_ent;
7662
7663 /*
7664@@ -3581,7 +3735,7 @@
7665
7666
7667 /*
7668- * dir_scan5 routines...
7669+ * dir_scan6 routines...
7670 * This sorts every directory and computes the inode numbers
7671 */
7672
7673@@ -3599,7 +3753,7 @@
7674 struct dir_ent *cur, *l1, *l2, *next;
7675 int len1, len2, stride = 1;
7676
7677- if(dir->count < 2)
7678+ if(dir->list == NULL || dir->count < 2)
7679 return;
7680
7681 /*
7682@@ -3674,7 +3828,7 @@
7683 }
7684
7685
7686-void dir_scan5(struct dir_info *dir)
7687+void dir_scan6(struct dir_info *dir)
7688 {
7689 struct dir_ent *dir_ent;
7690 unsigned int byte_count = 0;
7691@@ -3691,7 +3845,7 @@
7692 alloc_inode_no(dir_ent->inode, 0);
7693
7694 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
7695- dir_scan5(dir_ent->dir);
7696+ dir_scan6(dir_ent->dir);
7697 }
7698
7699 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
7700@@ -3703,7 +3857,7 @@
7701 * dir_scan6 routines...
7702 * This generates the filesystem metadata and writes it out to the destination
7703 */
7704-void scan6_init_dir(struct directory *dir)
7705+void scan7_init_dir(struct directory *dir)
7706 {
7707 dir->buff = malloc(SQUASHFS_METADATA_SIZE);
7708 if(dir->buff == NULL)
7709@@ -3718,7 +3872,7 @@
7710 }
7711
7712
7713-struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
7714+struct dir_ent *scan7_readdir(struct directory *dir, struct dir_info *dir_info,
7715 struct dir_ent *dir_ent)
7716 {
7717 if (dir_ent == NULL)
7718@@ -3734,7 +3888,7 @@
7719 }
7720
7721
7722-void scan6_freedir(struct directory *dir)
7723+void scan7_freedir(struct directory *dir)
7724 {
7725 if(dir->index)
7726 free(dir->index);
7727@@ -3742,16 +3896,16 @@
7728 }
7729
7730
7731-void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
7732+void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info)
7733 {
7734 int squashfs_type;
7735 int duplicate_file;
7736 struct directory dir;
7737 struct dir_ent *dir_ent = NULL;
7738
7739- scan6_init_dir(&dir);
7740+ scan7_init_dir(&dir);
7741
7742- while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
7743+ while((dir_ent = scan7_readdir(&dir, dir_info, dir_ent)) != NULL) {
7744 struct stat *buf = &dir_ent->inode->buf;
7745
7746 update_info(dir_ent);
7747@@ -3772,7 +3926,7 @@
7748
7749 case S_IFDIR:
7750 squashfs_type = SQUASHFS_DIR_TYPE;
7751- dir_scan6(inode, dir_ent->dir);
7752+ dir_scan7(inode, dir_ent->dir);
7753 break;
7754
7755 case S_IFLNK:
7756@@ -3883,7 +4037,7 @@
7757 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
7758 *inode);
7759
7760- scan6_freedir(&dir);
7761+ scan7_freedir(&dir);
7762 }
7763
7764
7765@@ -3928,8 +4082,9 @@
7766 if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
7767 strncmp(path, "../", 3) == 0) {
7768 if(lstat(path, &buf) == -1) {
7769- ERROR("Cannot stat exclude dir/file %s because %s, "
7770- "ignoring\n", path, strerror(errno));
7771+ ERROR_START("Cannot stat exclude dir/file %s because "
7772+ "%s", path, strerror(errno));
7773+ ERROR_EXIT(", ignoring\n");
7774 return TRUE;
7775 }
7776 ADD_ENTRY(buf);
7777@@ -3941,10 +4096,11 @@
7778 if(res == -1)
7779 BAD_ERROR("asprintf failed in old_add_exclude\n");
7780 if(lstat(filename, &buf) == -1) {
7781- if(!(errno == ENOENT || errno == ENOTDIR))
7782- ERROR("Cannot stat exclude dir/file %s because "
7783- "%s, ignoring\n", filename,
7784- strerror(errno));
7785+ if(!(errno == ENOENT || errno == ENOTDIR)) {
7786+ ERROR_START("Cannot stat exclude dir/file %s "
7787+ "because %s", filename, strerror(errno));
7788+ ERROR_EXIT(", ignoring\n");
7789+ }
7790 free(filename);
7791 continue;
7792 }
7793@@ -3971,39 +4127,50 @@
7794 }
7795
7796
7797-void initialise_threads(int readb_mbytes, int writeb_mbytes,
7798- int fragmentb_mbytes)
7799+void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq,
7800+ int freelst, char *destination_file)
7801 {
7802 int i;
7803 sigset_t sigmask, old_mask;
7804- int reader_buffer_size;
7805- int fragment_buffer_size;
7806+ int total_mem = readq;
7807+ int reader_size;
7808+ int fragment_size;
7809+ int fwriter_size;
7810 /*
7811- * writer_buffer_size is global because it is needed in
7812+ * bwriter_size is global because it is needed in
7813 * write_file_blocks_dup()
7814 */
7815
7816 /*
7817+ * Never allow the total size of the queues to be larger than
7818+ * physical memory
7819+ *
7820+ * When adding together the possibly user supplied values, make
7821+ * sure they've not been deliberately contrived to overflow an int
7822+ */
7823+ if(add_overflow(total_mem, fragq))
7824+ BAD_ERROR("Queue sizes rediculously too large\n");
7825+ total_mem += fragq;
7826+ if(add_overflow(total_mem, bwriteq))
7827+ BAD_ERROR("Queue sizes rediculously too large\n");
7828+ total_mem += bwriteq;
7829+ if(add_overflow(total_mem, fwriteq))
7830+ BAD_ERROR("Queue sizes rediculously too large\n");
7831+ total_mem += fwriteq;
7832+
7833+ check_usable_phys_mem(total_mem);
7834+
7835+ /*
7836 * convert from queue size in Mbytes to queue size in
7837 * blocks.
7838 *
7839- * In doing so, check that the user supplied values do not
7840- * overflow a signed int
7841+ * This isn't going to overflow an int unless there exists
7842+ * systems with more than 8 Petabytes of RAM!
7843 */
7844- if(shift_overflow(readb_mbytes, 20 - block_log))
7845- BAD_ERROR("Read queue is too large\n");
7846- else
7847- reader_buffer_size = readb_mbytes << (20 - block_log);
7848-
7849- if(shift_overflow(fragmentb_mbytes, 20 - block_log))
7850- BAD_ERROR("Fragment queue is too large\n");
7851- else
7852- fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
7853-
7854- if(shift_overflow(writeb_mbytes, 20 - block_log))
7855- BAD_ERROR("Write queue is too large\n");
7856- else
7857- writer_buffer_size = writeb_mbytes << (20 - block_log);
7858+ reader_size = readq << (20 - block_log);
7859+ fragment_size = fragq << (20 - block_log);
7860+ bwriter_size = bwriteq << (20 - block_log);
7861+ fwriter_size = fwriteq << (20 - block_log);
7862
7863 /*
7864 * setup signal handlers for the main thread, these cleanup
7865@@ -4020,10 +4187,11 @@
7866 signal(SIGINT, sighandler);
7867 signal(SIGUSR1, sighandler);
7868
7869- /* block SIGQUIT this is handled by the info thread */
7870+ /* block SIGQUIT and SIGHUP, these are handled by the info thread */
7871 sigemptyset(&sigmask);
7872 sigaddset(&sigmask, SIGQUIT);
7873- if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
7874+ sigaddset(&sigmask, SIGHUP);
7875+ if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
7876 BAD_ERROR("Failed to set signal mask in intialise_threads\n");
7877
7878 /*
7879@@ -4050,8 +4218,9 @@
7880 #endif
7881
7882 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
7883- ERROR("Failed to get number of available processors. "
7884- "Defaulting to 1\n");
7885+ ERROR_START("Failed to get number of available "
7886+ "processors.");
7887+ ERROR_EXIT(" Defaulting to 1\n");
7888 processors = 1;
7889 }
7890 #else
7891@@ -4059,44 +4228,48 @@
7892 #endif
7893 }
7894
7895- if(multiply_overflow(processors, 2) ||
7896- add_overflow(processors * 2, 2) ||
7897- multiply_overflow(processors * 2 + 2,
7898- sizeof(pthread_t)))
7899+ if(multiply_overflow(processors, 3) ||
7900+ multiply_overflow(processors * 3, sizeof(pthread_t)))
7901 BAD_ERROR("Processors too large\n");
7902
7903- thread = malloc((2 + processors * 2) * sizeof(pthread_t));
7904- if(thread == NULL)
7905+ deflator_thread = malloc(processors * 3 * sizeof(pthread_t));
7906+ if(deflator_thread == NULL)
7907 MEM_ERROR();
7908
7909- deflator_thread = &thread[2];
7910 frag_deflator_thread = &deflator_thread[processors];
7911+ frag_thread = &frag_deflator_thread[processors];
7912
7913 to_reader = queue_init(1);
7914- from_reader = queue_init(reader_buffer_size);
7915- to_writer = queue_init(writer_buffer_size);
7916+ to_deflate = queue_init(reader_size);
7917+ to_process_frag = queue_init(reader_size);
7918+ to_writer = queue_init(bwriter_size + fwriter_size);
7919 from_writer = queue_init(1);
7920- from_deflate = queue_init(reader_buffer_size);
7921- to_frag = queue_init(fragment_buffer_size);
7922- reader_buffer = cache_init(block_size, reader_buffer_size);
7923- writer_buffer = cache_init(block_size, writer_buffer_size);
7924- fragment_buffer = cache_init(block_size, fragment_buffer_size);
7925- pthread_create(&thread[0], NULL, reader, NULL);
7926- pthread_create(&thread[1], NULL, writer, NULL);
7927+ to_frag = queue_init(fragment_size);
7928+ locked_fragment = queue_init(fragment_size);
7929+ to_main = seq_queue_init();
7930+ reader_buffer = cache_init(block_size, reader_size, 0, 0);
7931+ bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst);
7932+ fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst);
7933+ fragment_buffer = cache_init(block_size, fragment_size, 1, 0);
7934+ reserve_cache = cache_init(block_size, processors + 1, 1, 0);
7935+ pthread_create(&reader_thread, NULL, reader, NULL);
7936+ pthread_create(&writer_thread, NULL, writer, NULL);
7937 init_progress_bar();
7938 init_info();
7939- pthread_mutex_init(&fragment_mutex, NULL);
7940- pthread_cond_init(&fragment_waiting, NULL);
7941
7942 for(i = 0; i < processors; i++) {
7943- if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
7944- 0)
7945+ if(pthread_create(&deflator_thread[i], NULL, deflator, NULL))
7946 BAD_ERROR("Failed to create thread\n");
7947 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
7948 NULL) != 0)
7949 BAD_ERROR("Failed to create thread\n");
7950+ if(pthread_create(&frag_thread[i], NULL, frag_thrd,
7951+ (void *) destination_file) != 0)
7952+ BAD_ERROR("Failed to create thread\n");
7953 }
7954
7955+ main_thread = pthread_self();
7956+
7957 printf("Parallel mksquashfs: Using %d processor%s\n", processors,
7958 processors == 1 ? "" : "s");
7959
7960@@ -4120,12 +4293,21 @@
7961 inode_lookup_table = it;
7962
7963 for(i = 0; i < INODE_HASH_SIZE; i ++) {
7964- struct inode_info *inode = inode_info[i];
7965+ struct inode_info *inode;
7966
7967 for(inode = inode_info[i]; inode; inode = inode->next) {
7968
7969 inode_number = get_inode_no(inode);
7970
7971+ /* The empty action will produce orphaned inode
7972+ * entries in the inode_info[] table. These
7973+ * entries because they are orphaned will not be
7974+ * allocated an inode number in dir_scan5(), so
7975+ * skip any entries with the default dummy inode
7976+ * number of 0 */
7977+ if(inode_number == 0)
7978+ continue;
7979+
7980 SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
7981 &inode_lookup_table[inode_number - 1], 1);
7982
7983@@ -4146,11 +4328,14 @@
7984 target ++;
7985
7986 start = target;
7987- while(*target != '/' && *target!= '\0')
7988+ while(*target != '/' && *target != '\0')
7989 target ++;
7990
7991 *targname = strndup(start, target - start);
7992
7993+ while(*target == '/')
7994+ target ++;
7995+
7996 return target;
7997 }
7998
7999@@ -4550,91 +4735,23 @@
8000 MEM_ERROR();
8001
8002 res = read_bytes(recoverfd, metadata, bytes);
8003- if(res == -1)
8004- BAD_ERROR("Failed to read recovery file, because %s\n",
8005- strerror(errno));
8006- if(res < bytes)
8007- BAD_ERROR("Recovery file appears to be truncated\n");
8008-
8009- write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
8010-
8011- write_destination(fd, sBlk.inode_table_start, bytes, metadata);
8012-
8013- close(recoverfd);
8014- close(fd);
8015-
8016- printf("Successfully wrote recovery file \"%s\". Exiting\n",
8017- recovery_file);
8018-
8019- exit(0);
8020-}
8021-
8022-
8023-int parse_number(char *start, int *res, int size)
8024-{
8025- char *end;
8026- long number = strtol(start, &end, 10);
8027-
8028- /*
8029- * check for strtol underflow or overflow in conversion.
8030- * Note: strtol can validly return LONG_MIN and LONG_MAX
8031- * if the user entered these values, but, additional code
8032- * to distinguish this scenario is unnecessary, because for
8033- * our purposes LONG_MIN and LONG_MAX are too large anyway
8034- */
8035- if(number == LONG_MIN || number == LONG_MAX)
8036- return 0;
8037-
8038- /* reject negative numbers as invalid */
8039- if(number < 0)
8040- return 0;
8041-
8042- /* check if long result will overflow signed int */
8043- if(number > INT_MAX)
8044- return 0;
8045-
8046- if(size) {
8047- /*
8048- * Check for multiplier and trailing junk.
8049- * But first check that a number exists before the
8050- * multiplier
8051- */
8052- if(end == start)
8053- return 0;
8054-
8055- switch(end[0]) {
8056- case 'm':
8057- case 'M':
8058- if(multiply_overflow((int) number, 1048576))
8059- return 0;
8060- number *= 1048576;
8061+ if(res == -1)
8062+ BAD_ERROR("Failed to read recovery file, because %s\n",
8063+ strerror(errno));
8064+ if(res < bytes)
8065+ BAD_ERROR("Recovery file appears to be truncated\n");
8066
8067- if(end[1] != '\0')
8068- /* trailing junk after number */
8069- return 0;
8070+ write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
8071
8072- break;
8073- case 'k':
8074- case 'K':
8075- if(multiply_overflow((int) number, 1024))
8076- return 0;
8077- number *= 1024;
8078+ write_destination(fd, sBlk.inode_table_start, bytes, metadata);
8079
8080- if(end[1] != '\0')
8081- /* trailing junk after number */
8082- return 0;
8083- case '\0':
8084- break;
8085- default:
8086- /* trailing junk after number */
8087- return 0;
8088- }
8089- } else if(end[0] != '\0')
8090- /* trailing junk after number */
8091- return 0;
8092+ close(recoverfd);
8093+ close(fd);
8094
8095- *res = number;
8096- return 1;
8097+ printf("Successfully wrote recovery file \"%s\". Exiting\n",
8098+ recovery_file);
8099+
8100+ exit(0);
8101 }
8102
8103
8104@@ -4674,8 +4791,6 @@
8105
8106 close(fd);
8107
8108- delete_pseudo_files();
8109-
8110 if(recovery_file)
8111 unlink(recovery_file);
8112
8113@@ -4750,15 +4865,233 @@
8114 }
8115
8116
8117+int parse_numberll(char *start, long long *res, int size)
8118+{
8119+ char *end;
8120+ long long number;
8121+
8122+ errno = 0; /* To distinguish success/failure after call */
8123+
8124+ number = strtoll(start, &end, 10);
8125+
8126+ /*
8127+ * check for strtoll underflow or overflow in conversion, and other
8128+ * errors.
8129+ */
8130+ if((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) ||
8131+ (errno != 0 && number == 0))
8132+ return 0;
8133+
8134+ /* reject negative numbers as invalid */
8135+ if(number < 0)
8136+ return 0;
8137+
8138+ if(size) {
8139+ /*
8140+ * Check for multiplier and trailing junk.
8141+ * But first check that a number exists before the
8142+ * multiplier
8143+ */
8144+ if(end == start)
8145+ return 0;
8146+
8147+ switch(end[0]) {
8148+ case 'g':
8149+ case 'G':
8150+ if(multiply_overflowll(number, 1073741824))
8151+ return 0;
8152+ number *= 1073741824;
8153+
8154+ if(end[1] != '\0')
8155+ /* trailing junk after multiplier, but
8156+ * allow it to be "bytes" */
8157+ if(strcmp(end + 1, "bytes"))
8158+ return 0;
8159+
8160+ break;
8161+ case 'm':
8162+ case 'M':
8163+ if(multiply_overflowll(number, 1048576))
8164+ return 0;
8165+ number *= 1048576;
8166+
8167+ if(end[1] != '\0')
8168+ /* trailing junk after multiplier, but
8169+ * allow it to be "bytes" */
8170+ if(strcmp(end + 1, "bytes"))
8171+ return 0;
8172+
8173+ break;
8174+ case 'k':
8175+ case 'K':
8176+ if(multiply_overflowll(number, 1024))
8177+ return 0;
8178+ number *= 1024;
8179+
8180+ if(end[1] != '\0')
8181+ /* trailing junk after multiplier, but
8182+ * allow it to be "bytes" */
8183+ if(strcmp(end + 1, "bytes"))
8184+ return 0;
8185+
8186+ break;
8187+ case '\0':
8188+ break;
8189+ default:
8190+ /* trailing junk after number */
8191+ return 0;
8192+ }
8193+ } else if(end[0] != '\0')
8194+ /* trailing junk after number */
8195+ return 0;
8196+
8197+ *res = number;
8198+ return 1;
8199+}
8200+
8201+
8202+int parse_number(char *start, int *res, int size)
8203+{
8204+ long long number;
8205+
8206+ if(!parse_numberll(start, &number, size))
8207+ return 0;
8208+
8209+ /* check if long result will overflow signed int */
8210+ if(number > INT_MAX)
8211+ return 0;
8212+
8213+ *res = (int) number;
8214+ return 1;
8215+}
8216+
8217+
8218 int parse_num(char *arg, int *res)
8219 {
8220 return parse_number(arg, res, 0);
8221 }
8222
8223
8224+int get_physical_memory()
8225+{
8226+ /*
8227+ * Long longs are used here because with PAE, a 32-bit
8228+ * machine can have more than 4GB of physical memory
8229+ *
8230+ * sysconf(_SC_PHYS_PAGES) relies on /proc being mounted.
8231+ * If it isn't fail.
8232+ */
8233+ long long num_pages = sysconf(_SC_PHYS_PAGES);
8234+ long long page_size = sysconf(_SC_PAGESIZE);
8235+ int phys_mem = num_pages * page_size >> 20;
8236+
8237+ if(num_pages == -1 || page_size == -1)
8238+ return 0;
8239+
8240+ if(phys_mem < SQUASHFS_LOWMEM)
8241+ BAD_ERROR("Mksquashfs requires more physical memory than is "
8242+ "available!\n");
8243+
8244+ return phys_mem;
8245+}
8246+
8247+
8248+void check_usable_phys_mem(int total_mem)
8249+{
8250+ /*
8251+ * We want to allow users to use as much of their physical
8252+ * memory as they wish. However, for practical reasons there are
8253+ * limits which need to be imposed, to protect users from themselves
8254+ * and to prevent people from using Mksquashfs as a DOS attack by using
8255+ * all physical memory. Mksquashfs uses memory to cache data from disk
8256+ * to optimise performance. It is pointless to ask it to use more
8257+ * than 75% of physical memory, as this causes thrashing and it is thus
8258+ * self-defeating.
8259+ */
8260+ int mem = get_physical_memory();
8261+
8262+ mem = (mem >> 1) + (mem >> 2); /* 75% */
8263+
8264+ if(total_mem > mem && mem) {
8265+ ERROR("Total memory requested is more than 75%% of physical "
8266+ "memory.\n");
8267+ ERROR("Mksquashfs uses memory to cache data from disk to "
8268+ "optimise performance.\n");
8269+ ERROR("It is pointless to ask it to use more than this amount "
8270+ "of memory, as this\n");
8271+ ERROR("causes thrashing and it is thus self-defeating.\n");
8272+ BAD_ERROR("Requested memory size too large\n");
8273+ }
8274+
8275+ if(sizeof(void *) == 4 && total_mem > 2048) {
8276+ /*
8277+ * If we're running on a kernel with PAE or on a 64-bit kernel,
8278+ * then the 75% physical memory limit can still easily exceed
8279+ * the addressable memory by this process.
8280+ *
8281+ * Due to the typical kernel/user-space split (1GB/3GB, or
8282+ * 2GB/2GB), we have to conservatively assume the 32-bit
8283+ * processes can only address 2-3GB. So refuse if the user
8284+ * tries to allocate more than 2GB.
8285+ */
8286+ ERROR("Total memory requested may exceed maximum "
8287+ "addressable memory by this process\n");
8288+ BAD_ERROR("Requested memory size too large\n");
8289+ }
8290+}
8291+
8292+
8293+int get_default_phys_mem()
8294+{
8295+ /*
8296+ * get_physical_memory() relies on /proc being mounted.
8297+ * If it fails, issue a warning, and use
8298+ * SQUASHFS_LOWMEM / SQUASHFS_TAKE as default,
8299+ * and allow a larger value to be set with -mem.
8300+ */
8301+ int mem = get_physical_memory();
8302+
8303+ if(mem == 0) {
8304+ mem = SQUASHFS_LOWMEM / SQUASHFS_TAKE;
8305+
8306+ ERROR("Warning: Cannot get size of physical memory, probably "
8307+ "because /proc is missing.\n");
8308+ ERROR("Warning: Defaulting to minimal use of %d Mbytes, use "
8309+ "-mem to set a better value,\n", mem);
8310+ ERROR("Warning: or fix /proc.\n");
8311+ } else
8312+ mem /= SQUASHFS_TAKE;
8313+
8314+ if(sizeof(void *) == 4 && mem > 640) {
8315+ /*
8316+ * If we're running on a kernel with PAE or on a 64-bit kernel,
8317+ * the default memory usage can exceed the addressable
8318+ * memory by this process.
8319+ * Due to the typical kernel/user-space split (1GB/3GB, or
8320+ * 2GB/2GB), we have to conservatively assume the 32-bit
8321+ * processes can only address 2-3GB. So limit the default
8322+ * usage to 640M, which gives room for other data.
8323+ */
8324+ mem = 640;
8325+ }
8326+
8327+ return mem;
8328+}
8329+
8330+
8331+void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
8332+ int *fwriteq)
8333+{
8334+ *readq = mem / SQUASHFS_READQ_MEM;
8335+ *bwriteq = mem / SQUASHFS_BWRITEQ_MEM;
8336+ *fwriteq = mem / SQUASHFS_FWRITEQ_MEM;
8337+ *fragq = mem - *readq - *bwriteq - *fwriteq;
8338+}
8339+
8340+
8341 #define VERSION() \
8342- printf("mksquashfs version 4.2-git (2013/04/07)\n");\
8343- printf("copyright (C) 2013 Phillip Lougher "\
8344+ printf("mksquashfs version 4.3-git (2014/09/12)\n");\
8345+ printf("copyright (C) 2014 Phillip Lougher "\
8346 "<phillip@squashfs.org.uk>\n\n"); \
8347 printf("This program is free software; you can redistribute it and/or"\
8348 "\n");\
8349@@ -4781,29 +5114,79 @@
8350 char *b, *root_name = NULL;
8351 int keep_as_directory = FALSE;
8352 squashfs_inode inode;
8353- int readb_mbytes = READER_BUFFER_DEFAULT,
8354- writeb_mbytes = WRITER_BUFFER_DEFAULT,
8355- fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
8356+ int readq;
8357+ int fragq;
8358+ int bwriteq;
8359+ int fwriteq;
8360+ int total_mem = get_default_phys_mem();
8361+ int progress = TRUE;
8362 int force_progress = FALSE;
8363 struct file_buffer **fragment = NULL;
8364
8365- block_log = slog(block_size);
8366 if(argc > 1 && strcmp(argv[1], "-version") == 0) {
8367 VERSION();
8368 exit(0);
8369 }
8370+
8371+ block_log = slog(block_size);
8372+ calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq);
8373+
8374 for(i = 1; i < argc && argv[i][0] != '-'; i++);
8375 if(i < 3)
8376 goto printOptions;
8377 source_path = argv + 1;
8378 source = i - 2;
8379+
8380 /*
8381- * lookup default compressor. Note the Makefile ensures the default
8382- * compressor has been built, and so we don't need to to check
8383- * for failure here
8384+ * Scan the command line for -comp xxx option, this is to ensure
8385+ * any -X compressor specific options are passed to the
8386+ * correct compressor
8387 */
8388- comp = lookup_compressor(COMP_DEFAULT);
8389 for(; i < argc; i++) {
8390+ struct compressor *prev_comp = comp;
8391+
8392+ if(strcmp(argv[i], "-comp") == 0) {
8393+ if(++i == argc) {
8394+ ERROR("%s: -comp missing compression type\n",
8395+ argv[0]);
8396+ exit(1);
8397+ }
8398+ comp = lookup_compressor(argv[i]);
8399+ if(!comp->supported) {
8400+ ERROR("%s: Compressor \"%s\" is not supported!"
8401+ "\n", argv[0], argv[i]);
8402+ ERROR("%s: Compressors available:\n", argv[0]);
8403+ display_compressors("", COMP_DEFAULT);
8404+ exit(1);
8405+ }
8406+ if(prev_comp != NULL && prev_comp != comp) {
8407+ ERROR("%s: -comp multiple conflicting -comp"
8408+ " options specified on command line"
8409+ ", previously %s, now %s\n", argv[0],
8410+ prev_comp->name, comp->name);
8411+ exit(1);
8412+ }
8413+ compressor_opt_parsed = 1;
8414+
8415+ } else if(strcmp(argv[i], "-e") == 0)
8416+ break;
8417+ else if(strcmp(argv[i], "-root-becomes") == 0 ||
8418+ strcmp(argv[i], "-ef") == 0 ||
8419+ strcmp(argv[i], "-pf") == 0 ||
8420+ strcmp(argv[i], "-vaf") == 0 ||
8421+ strcmp(argv[i], "-comp") == 0)
8422+ i++;
8423+ }
8424+
8425+ /*
8426+ * if no -comp option specified lookup default compressor. Note the
8427+ * Makefile ensures the default compressor has been built, and so we
8428+ * don't need to to check for failure here
8429+ */
8430+ if(comp == NULL)
8431+ comp = lookup_compressor(COMP_DEFAULT);
8432+
8433+ for(i = source + 2; i < argc; i++) {
8434 if(strcmp(argv[i], "-action") == 0 ||
8435 strcmp(argv[i], "-a") ==0) {
8436 if(++i == argc) {
8437@@ -4811,54 +5194,114 @@
8438 argv[0], argv[i - 1]);
8439 exit(1);
8440 }
8441- res = parse_action(argv[i]);
8442+ res = parse_action(argv[i], ACTION_LOG_NONE);
8443+ if(res == 0)
8444+ exit(1);
8445+
8446+ } else if(strcmp(argv[i], "-verbose-action") == 0 ||
8447+ strcmp(argv[i], "-va") ==0) {
8448+ if(++i == argc) {
8449+ ERROR("%s: %s missing action\n",
8450+ argv[0], argv[i - 1]);
8451+ exit(1);
8452+ }
8453+ res = parse_action(argv[i], ACTION_LOG_VERBOSE);
8454 if(res == 0)
8455 exit(1);
8456
8457- } else if(strcmp(argv[i], "-af") == 0) {
8458+ } else if(strcmp(argv[i], "-true-action") == 0 ||
8459+ strcmp(argv[i], "-ta") ==0) {
8460 if(++i == argc) {
8461- ERROR("%s: -af missing filename\n", argv[0]);
8462+ ERROR("%s: %s missing action\n",
8463+ argv[0], argv[i - 1]);
8464 exit(1);
8465 }
8466- if(read_action_file(argv[i]) == FALSE)
8467+ res = parse_action(argv[i], ACTION_LOG_TRUE);
8468+ if(res == 0)
8469 exit(1);
8470
8471- } else if(strcmp(argv[i], "-comp") == 0) {
8472- if(compressor_opts_parsed) {
8473- ERROR("%s: -comp must appear before -X options"
8474- "\n", argv[0]);
8475+ } else if(strcmp(argv[i], "-false-action") == 0 ||
8476+ strcmp(argv[i], "-fa") ==0) {
8477+ if(++i == argc) {
8478+ ERROR("%s: %s missing action\n",
8479+ argv[0], argv[i - 1]);
8480 exit(1);
8481 }
8482+ res = parse_action(argv[i], ACTION_LOG_FALSE);
8483+ if(res == 0)
8484+ exit(1);
8485+
8486+ } else if(strcmp(argv[i], "-action-file") == 0 ||
8487+ strcmp(argv[i], "-af") ==0) {
8488 if(++i == argc) {
8489- ERROR("%s: -comp missing compression type\n",
8490- argv[0]);
8491+ ERROR("%s: %s missing filename\n", argv[0],
8492+ argv[i - 1]);
8493 exit(1);
8494 }
8495- comp = lookup_compressor(argv[i]);
8496- if(!comp->supported) {
8497- ERROR("%s: Compressor \"%s\" is not supported!"
8498- "\n", argv[0], argv[i]);
8499- ERROR("%s: Compressors available:\n", argv[0]);
8500- display_compressors("", COMP_DEFAULT);
8501+ if(read_action_file(argv[i], ACTION_LOG_NONE) == FALSE)
8502+ exit(1);
8503+
8504+ } else if(strcmp(argv[i], "-verbose-action-file") == 0 ||
8505+ strcmp(argv[i], "-vaf") ==0) {
8506+ if(++i == argc) {
8507+ ERROR("%s: %s missing filename\n", argv[0],
8508+ argv[i - 1]);
8509+ exit(1);
8510+ }
8511+ if(read_action_file(argv[i], ACTION_LOG_VERBOSE) == FALSE)
8512+ exit(1);
8513+
8514+ } else if(strcmp(argv[i], "-true-action-file") == 0 ||
8515+ strcmp(argv[i], "-taf") ==0) {
8516+ if(++i == argc) {
8517+ ERROR("%s: %s missing filename\n", argv[0],
8518+ argv[i - 1]);
8519+ exit(1);
8520+ }
8521+ if(read_action_file(argv[i], ACTION_LOG_TRUE) == FALSE)
8522+ exit(1);
8523+
8524+ } else if(strcmp(argv[i], "-false-action-file") == 0 ||
8525+ strcmp(argv[i], "-faf") ==0) {
8526+ if(++i == argc) {
8527+ ERROR("%s: %s missing filename\n", argv[0],
8528+ argv[i - 1]);
8529 exit(1);
8530 }
8531+ if(read_action_file(argv[i], ACTION_LOG_FALSE) == FALSE)
8532+ exit(1);
8533+
8534+ } else if(strcmp(argv[i], "-comp") == 0)
8535+ /* parsed previously */
8536+ i++;
8537+
8538+ else if(strncmp(argv[i], "-X", 2) == 0) {
8539+ int args;
8540
8541- } else if(strncmp(argv[i], "-X", 2) == 0) {
8542- int args = compressor_options(comp, argv + i, argc - i);
8543+ if(strcmp(argv[i] + 2, "help") == 0)
8544+ goto print_compressor_options;
8545+
8546+ args = compressor_options(comp, argv + i, argc - i);
8547 if(args < 0) {
8548 if(args == -1) {
8549 ERROR("%s: Unrecognised compressor"
8550 " option %s\n", argv[0],
8551 argv[i]);
8552- ERROR("%s: Did you forget to specify"
8553- " -comp, or specify it after"
8554- " the compressor specific"
8555- " option?\n", argv[0]);
8556- }
8557+ if(!compressor_opt_parsed)
8558+ ERROR("%s: Did you forget to"
8559+ " specify -comp?\n",
8560+ argv[0]);
8561+print_compressor_options:
8562+ ERROR("%s: selected compressor \"%s\""
8563+ ". Options supported: %s\n",
8564+ argv[0], comp->name,
8565+ comp->usage ? "" : "none");
8566+ if(comp->usage)
8567+ comp->usage();
8568+ }
8569 exit(1);
8570 }
8571 i += args;
8572- compressor_opts_parsed = 1;
8573
8574 } else if(strcmp(argv[i], "-pf") == 0) {
8575 if(++i == argc) {
8576@@ -4910,42 +5353,68 @@
8577 exit(1);
8578 }
8579 } else if(strcmp(argv[i], "-read-queue") == 0) {
8580- if((++i == argc) ||
8581- !parse_num(argv[i], &readb_mbytes)) {
8582+ if((++i == argc) || !parse_num(argv[i], &readq)) {
8583 ERROR("%s: -read-queue missing or invalid "
8584 "queue size\n", argv[0]);
8585 exit(1);
8586 }
8587- if(readb_mbytes < 1) {
8588+ if(readq < 1) {
8589 ERROR("%s: -read-queue should be 1 megabyte or "
8590 "larger\n", argv[0]);
8591 exit(1);
8592 }
8593 } else if(strcmp(argv[i], "-write-queue") == 0) {
8594- if((++i == argc) ||
8595- !parse_num(argv[i], &writeb_mbytes)) {
8596+ if((++i == argc) || !parse_num(argv[i], &bwriteq)) {
8597 ERROR("%s: -write-queue missing or invalid "
8598 "queue size\n", argv[0]);
8599 exit(1);
8600 }
8601- if(writeb_mbytes < 1) {
8602- ERROR("%s: -write-queue should be 1 megabyte "
8603+ if(bwriteq < 2) {
8604+ ERROR("%s: -write-queue should be 2 megabytes "
8605 "or larger\n", argv[0]);
8606 exit(1);
8607 }
8608+ fwriteq = bwriteq >> 1;
8609+ bwriteq -= fwriteq;
8610 } else if(strcmp(argv[i], "-fragment-queue") == 0) {
8611- if((++i == argc) ||
8612- !parse_num(argv[i],
8613- &fragmentb_mbytes)) {
8614+ if((++i == argc) || !parse_num(argv[i], &fragq)) {
8615 ERROR("%s: -fragment-queue missing or invalid "
8616 "queue size\n", argv[0]);
8617 exit(1);
8618 }
8619- if(fragmentb_mbytes < 1) {
8620+ if(fragq < 1) {
8621 ERROR("%s: -fragment-queue should be 1 "
8622 "megabyte or larger\n", argv[0]);
8623 exit(1);
8624 }
8625+ } else if(strcmp(argv[i], "-mem") == 0) {
8626+ long long number;
8627+
8628+ if((++i == argc) ||
8629+ !parse_numberll(argv[i], &number, 1)) {
8630+ ERROR("%s: -mem missing or invalid mem size\n",
8631+ argv[0]);
8632+ exit(1);
8633+ }
8634+
8635+ /*
8636+ * convert from bytes to Mbytes, ensuring the value
8637+ * does not overflow a signed int
8638+ */
8639+ if(number >= (1LL << 51)) {
8640+ ERROR("%s: -mem invalid mem size\n", argv[0]);
8641+ exit(1);
8642+ }
8643+
8644+ total_mem = number / 1048576;
8645+ if(total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) {
8646+ ERROR("%s: -mem should be %d Mbytes or "
8647+ "larger\n", argv[0],
8648+ SQUASHFS_LOWMEM / SQUASHFS_TAKE);
8649+ exit(1);
8650+ }
8651+ calculate_queue_sizes(total_mem, &readq, &fragq,
8652+ &bwriteq, &fwriteq);
8653 } else if(strcmp(argv[i], "-b") == 0) {
8654 if(++i == argc) {
8655 ERROR("%s: -b missing block size\n", argv[0]);
8656@@ -5067,6 +5536,9 @@
8657 else if(strcmp(argv[i], "-keep-as-directory") == 0)
8658 keep_as_directory = TRUE;
8659
8660+ else if(strcmp(argv[i], "-exit-on-error") == 0)
8661+ exit_on_error = TRUE;
8662+
8663 else if(strcmp(argv[i], "-root-becomes") == 0) {
8664 if(++i == argc) {
8665 ERROR("%s: -root-becomes: missing name\n",
8666@@ -5086,8 +5558,10 @@
8667 ERROR("\t\t\tCompressors available:\n");
8668 display_compressors("\t\t\t", COMP_DEFAULT);
8669 ERROR("-b <block_size>\t\tset data block to "
8670- "<block_size>. Default %d bytes\n",
8671- SQUASHFS_FILE_SIZE);
8672+ "<block_size>. Default 128 Kbytes\n");
8673+ ERROR("\t\t\tOptionally a suffix of K or M can be"
8674+ " given to specify\n\t\t\tKbytes or Mbytes"
8675+ " respectively\n");
8676 ERROR("-no-exports\t\tdon't make the filesystem "
8677 "exportable via NFS\n");
8678 ERROR("-no-sparse\t\tdon't detect sparse files\n");
8679@@ -5145,6 +5619,8 @@
8680 ERROR("\nMksquashfs runtime options:\n");
8681 ERROR("-version\t\tprint version, licence and "
8682 "copyright message\n");
8683+ ERROR("-exit-on-error\t\ttreat normally ignored errors "
8684+ "as fatal\n");
8685 ERROR("-recover <name>\t\trecover filesystem data "
8686 "using recovery file <name>\n");
8687 ERROR("-no-recovery\t\tdon't generate a recovery "
8688@@ -5157,15 +5633,11 @@
8689 ERROR("-processors <number>\tUse <number> processors."
8690 " By default will use number of\n");
8691 ERROR("\t\t\tprocessors available\n");
8692- ERROR("-read-queue <size>\tSet input queue to <size> "
8693- "Mbytes. Default %d Mbytes\n",
8694- READER_BUFFER_DEFAULT);
8695- ERROR("-write-queue <size>\tSet output queue to <size> "
8696- "Mbytes. Default %d Mbytes\n",
8697- WRITER_BUFFER_DEFAULT);
8698- ERROR("-fragment-queue <size>\tSet fragment queue to "
8699- "<size> Mbytes. Default %d Mbytes\n",
8700- FRAGMENT_BUFFER_DEFAULT);
8701+ ERROR("-mem <size>\t\tUse <size> physical memory. "
8702+ "Currently set to %dM\n", total_mem);
8703+ ERROR("\t\t\tOptionally a suffix of K, M or G can be"
8704+ " given to specify\n\t\t\tKbytes, Mbytes or"
8705+ " Gbytes respectively\n");
8706 ERROR("\nMiscellaneous options:\n");
8707 ERROR("-root-owned\t\talternative name for -all-root"
8708 "\n");
8709@@ -5177,6 +5649,8 @@
8710 "-noF\n");
8711 ERROR("-noXattrCompression\talternative name for "
8712 "-noX\n");
8713+ ERROR("\n-Xhelp\t\t\tprint compressor options for"
8714+ " selected compressor\n");
8715 ERROR("\nCompressors available and compressor specific "
8716 "options:\n");
8717 display_compressor_usage(COMP_DEFAULT);
8718@@ -5201,6 +5675,11 @@
8719 progress = force_progress;
8720
8721 #ifdef SQUASHFS_TRACE
8722+ /*
8723+ * Disable progress bar if full debug tracing is enabled.
8724+ * The progress bar in this case just gets in the way of the
8725+ * debug trace output
8726+ */
8727 progress = FALSE;
8728 #endif
8729
8730@@ -5269,6 +5748,7 @@
8731 strcmp(argv[i], "-sort") == 0 ||
8732 strcmp(argv[i], "-pf") == 0 ||
8733 strcmp(argv[i], "-af") == 0 ||
8734+ strcmp(argv[i], "-vaf") == 0 ||
8735 strcmp(argv[i], "-comp") == 0)
8736 i++;
8737
8738@@ -5298,6 +5778,7 @@
8739 strcmp(argv[i], "-ef") == 0 ||
8740 strcmp(argv[i], "-pf") == 0 ||
8741 strcmp(argv[i], "-af") == 0 ||
8742+ strcmp(argv[i], "-vaf") == 0 ||
8743 strcmp(argv[i], "-comp") == 0)
8744 i++;
8745
8746@@ -5324,7 +5805,8 @@
8747 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
8748 }
8749
8750- initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
8751+ initialise_threads(readq, fragq, bwriteq, fwriteq, delete,
8752+ destination_file);
8753
8754 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
8755 if(res)
8756@@ -5366,7 +5848,6 @@
8757 SQUASHFS_INODE_BLK(sBlk.root_inode),
8758 root_inode_offset =
8759 SQUASHFS_INODE_OFFSET(sBlk.root_inode);
8760- sigset_t sigmask, old_mask;
8761
8762 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
8763 &data_cache, &directory_table,
8764@@ -5385,7 +5866,7 @@
8765 "device or file use -noappend\n");
8766 EXIT_MKSQUASHFS();
8767 }
8768- if((fragments = sBlk.fragments)) {
8769+ if((append_fragments = fragments = sBlk.fragments)) {
8770 fragment_table = realloc((char *) fragment_table,
8771 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
8772 * sizeof(struct squashfs_fragment_entry));
8773@@ -5437,14 +5918,7 @@
8774 sid_count = id_count;
8775 write_recovery_data(&sBlk);
8776 save_xattrs();
8777- restore_thread = init_restore_thread(pthread_self());
8778- sigemptyset(&sigmask);
8779- sigaddset(&sigmask, SIGINT);
8780- sigaddset(&sigmask, SIGTERM);
8781- sigaddset(&sigmask, SIGUSR1);
8782- if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
8783- BAD_ERROR("Failed to set signal mask\n");
8784- write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
8785+ appending = TRUE;
8786
8787 /*
8788 * set the filesystem state up to be able to append to the
8789@@ -5493,33 +5967,22 @@
8790
8791 inode_count = file_count + dir_count + sym_count + dev_count +
8792 fifo_count + sock_count;
8793-
8794- /*
8795- * The default use freelist before growing cache policy behaves
8796- * poorly with appending - with many deplicates the caches
8797- * do not grow due to the fact that large queues of outstanding
8798- * fragments/writer blocks do not occur, leading to small caches
8799- * and un-uncessary performance loss to frequent cache
8800- * replacement in the small caches. Therefore with appending
8801- * change the policy to grow the caches before reusing blocks
8802- * from the freelist
8803- */
8804- first_freelist = FALSE;
8805 }
8806
8807 if(path)
8808 paths = add_subdir(paths, path);
8809
8810 dump_actions();
8811+ dump_pseudos();
8812
8813 if(delete && !keep_as_directory && source == 1 &&
8814 S_ISDIR(source_buf.st_mode))
8815- dir_scan(&inode, source_path[0], scan1_readdir);
8816+ dir_scan(&inode, source_path[0], scan1_readdir, progress);
8817 else if(!keep_as_directory && source == 1 &&
8818 S_ISDIR(source_buf.st_mode))
8819- dir_scan(&inode, source_path[0], scan1_single_readdir);
8820+ dir_scan(&inode, source_path[0], scan1_single_readdir, progress);
8821 else
8822- dir_scan(&inode, "", scan1_encomp_readdir);
8823+ dir_scan(&inode, "", scan1_encomp_readdir, progress);
8824 sBlk.root_inode = inode;
8825 sBlk.inodes = inode_count;
8826 sBlk.s_magic = SQUASHFS_MAGIC;
8827@@ -5532,7 +5995,6 @@
8828 no_xattrs, comp_opts);
8829 sBlk.mkfs_time = time(NULL);
8830
8831- disable_progress_bar();
8832 disable_info();
8833
8834 while((fragment = get_frag_action(fragment)))
8835@@ -5551,6 +6013,7 @@
8836 if(queue_get(from_writer) != 0)
8837 EXIT_MKSQUASHFS();
8838
8839+ set_progressbar_state(FALSE);
8840 write_filesystem_tables(&sBlk, nopad);
8841
8842 return 0;
8843diff -Nru squashfs-tools-4.2+20130409/mksquashfs.h squashfs-tools-4.3+20140919/mksquashfs.h
8844--- squashfs-tools-4.2+20130409/mksquashfs.h 2013-05-09 10:39:11.000000000 +0200
8845+++ squashfs-tools-4.3+20140919/mksquashfs.h 2015-07-20 21:03:05.000000000 +0200
8846@@ -4,8 +4,8 @@
8847 * Squashfs
8848 *
8849 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
8850- * 2012
8851- * Phillip Lougher <phillip@lougher.demon.co.uK>
8852+ * 2012, 2013, 2014
8853+ * Phillip Lougher <phillip@squashfs.org.uk>
8854 *
8855 * This program is free software; you can redistribute it and/or
8856 * modify it under the terms of the GNU General Public License
8857@@ -25,22 +25,6 @@
8858 *
8859 */
8860
8861-#if __BYTE_ORDER == __BIG_ENDIAN
8862-#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
8863-#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
8864-#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
8865-
8866-#define SWAP_LE16(s, d) swap_le16(s, d)
8867-#define SWAP_LE32(s, d) swap_le32(s, d)
8868-#define SWAP_LE64(s, d) swap_le64(s, d)
8869-#else
8870-#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
8871-#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
8872-#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
8873-#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
8874- memcpy(d, s, n * sizeof(long long))
8875-#endif
8876-
8877 struct dir_info {
8878 char *pathname;
8879 char *subpath;
8880@@ -79,6 +63,47 @@
8881 char always_use_fragments;
8882 char noD;
8883 char noF;
8884+ char symlink[0];
8885+};
8886+
8887+/* in memory file info */
8888+struct file_info {
8889+ long long file_size;
8890+ long long bytes;
8891+ long long start;
8892+ unsigned int *block_list;
8893+ struct file_info *next;
8894+ struct fragment *fragment;
8895+ unsigned short checksum;
8896+ unsigned short fragment_checksum;
8897+ char have_frag_checksum;
8898+ char have_checksum;
8899+};
8900+
8901+/* fragment block data structures */
8902+struct fragment {
8903+ unsigned int index;
8904+ int offset;
8905+ int size;
8906+};
8907+
8908+/* in memory uid tables */
8909+#define ID_ENTRIES 256
8910+#define ID_HASH(id) (id & (ID_ENTRIES - 1))
8911+#define ISA_UID 1
8912+#define ISA_GID 2
8913+
8914+struct id {
8915+ unsigned int id;
8916+ int index;
8917+ char flags;
8918+ struct id *next;
8919+};
8920+
8921+/* fragment to file mapping used when appending */
8922+struct append_file {
8923+ struct file_info *file;
8924+ struct append_file *next;
8925 };
8926
8927 #define PSEUDO_FILE_OTHER 1
8928@@ -88,7 +113,42 @@
8929 #define IS_PSEUDO_PROCESS(a) ((a)->pseudo_file & PSEUDO_FILE_PROCESS)
8930 #define IS_PSEUDO_OTHER(a) ((a)->pseudo_file & PSEUDO_FILE_OTHER)
8931
8932+/*
8933+ * Amount of physical memory to use by default, and the default queue
8934+ * ratios
8935+ */
8936+#define SQUASHFS_TAKE 4
8937+#define SQUASHFS_READQ_MEM 4
8938+#define SQUASHFS_BWRITEQ_MEM 4
8939+#define SQUASHFS_FWRITEQ_MEM 4
8940+
8941+/*
8942+ * Lowest amount of physical memory considered viable for Mksquashfs
8943+ * to run in Mbytes
8944+ */
8945+#define SQUASHFS_LOWMEM 64
8946+
8947 /* offset of data in compressed metadata blocks (allowing room for
8948 * compressed size */
8949 #define BLOCK_OFFSET 2
8950+
8951+extern struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
8952+struct cache *bwriter_buffer, *fwriter_buffer;
8953+extern struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
8954+ *to_frag, *locked_fragment, *to_process_frag;
8955+extern struct append_file **file_mapping;
8956+extern struct seq_queue *to_main;
8957+extern pthread_mutex_t fragment_mutex, dup_mutex;
8958+extern struct squashfs_fragment_entry *fragment_table;
8959+extern struct compressor *comp;
8960+extern int block_size;
8961+extern struct file_info *dupl[];
8962+extern int read_fs_bytes(int, long long, int, void *);
8963+extern void add_file(long long, long long, long long, unsigned int *, int,
8964+ unsigned int, int, int);
8965+extern struct id *create_id(unsigned int);
8966+extern unsigned int get_uid(unsigned int);
8967+extern unsigned int get_guid(unsigned int);
8968+extern int read_bytes(int, void *, int);
8969+extern unsigned short get_checksum_mem(char *, int);
8970 #endif
8971diff -Nru squashfs-tools-4.2+20130409/par_mksquashfs/README squashfs-tools-4.3+20140919/par_mksquashfs/README
8972--- squashfs-tools-4.2+20130409/par_mksquashfs/README 2013-05-09 10:39:11.000000000 +0200
8973+++ squashfs-tools-4.3+20140919/par_mksquashfs/README 1970-01-01 01:00:00.000000000 +0100
8974@@ -1,2 +0,0 @@
8975-par_mksquashfs is now the standard mksquashfs, and so this directory is now empty.
8976-
8977diff -Nru squashfs-tools-4.2+20130409/process_fragments.c squashfs-tools-4.3+20140919/process_fragments.c
8978--- squashfs-tools-4.2+20130409/process_fragments.c 1970-01-01 01:00:00.000000000 +0100
8979+++ squashfs-tools-4.3+20140919/process_fragments.c 2015-07-20 21:03:05.000000000 +0200
8980@@ -0,0 +1,370 @@
8981+/*
8982+ * Create a squashfs filesystem. This is a highly compressed read only
8983+ * filesystem.
8984+ *
8985+ * Copyright (c) 2014
8986+ * Phillip Lougher <phillip@squashfs.org.uk>
8987+ *
8988+ * This program is free software; you can redistribute it and/or
8989+ * modify it under the terms of the GNU General Public License
8990+ * as published by the Free Software Foundation; either version 2,
8991+ * or (at your option) any later version.
8992+ *
8993+ * This program is distributed in the hope that it will be useful,
8994+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
8995+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8996+ * GNU General Public License for more details.
8997+ *
8998+ * You should have received a copy of the GNU General Public License
8999+ * along with this program; if not, write to the Free Software
9000+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
9001+ *
9002+ * process_fragments.c
9003+ */
9004+
9005+#include <pthread.h>
9006+#include <sys/ioctl.h>
9007+#include <unistd.h>
9008+#include <signal.h>
9009+#include <sys/time.h>
9010+#include <string.h>
9011+#include <stdio.h>
9012+#include <math.h>
9013+#include <stdarg.h>
9014+#include <errno.h>
9015+#include <stdlib.h>
9016+#include <dirent.h>
9017+#include <sys/types.h>
9018+#include <sys/stat.h>
9019+#include <fcntl.h>
9020+
9021+#include "caches-queues-lists.h"
9022+#include "squashfs_fs.h"
9023+#include "mksquashfs.h"
9024+#include "error.h"
9025+#include "progressbar.h"
9026+#include "info.h"
9027+#include "compressor.h"
9028+#include "process_fragments.h"
9029+
9030+#define FALSE 0
9031+#define TRUE 1
9032+
9033+extern struct queue *to_process_frag;
9034+extern struct seq_queue *to_main;
9035+extern int sparse_files;
9036+
9037+/*
9038+ * Compute 16 bit BSD checksum over the data, and check for sparseness
9039+ */
9040+static int checksum_sparse(struct file_buffer *file_buffer)
9041+{
9042+ unsigned char *b = (unsigned char *) file_buffer->data;
9043+ unsigned short chksum = 0;
9044+ int bytes = file_buffer->size, sparse = TRUE, value;
9045+
9046+ while(bytes --) {
9047+ chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
9048+ value = *b++;
9049+ if(value) {
9050+ sparse = FALSE;
9051+ chksum += value;
9052+ }
9053+ }
9054+
9055+ file_buffer->checksum = chksum;
9056+ return sparse;
9057+}
9058+
9059+
9060+static int read_filesystem(int fd, long long byte, int bytes, void *buff)
9061+{
9062+ off_t off = byte;
9063+
9064+ TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n",
9065+ byte, bytes);
9066+
9067+ if(lseek(fd, off, SEEK_SET) == -1) {
9068+ ERROR("read_filesystem: Lseek on destination failed because %s, "
9069+ "offset=0x%llx\n", strerror(errno), off);
9070+ return 0;
9071+ } else if(read_bytes(fd, buff, bytes) < bytes) {
9072+ ERROR("Read on destination failed\n");
9073+ return 0;
9074+ }
9075+
9076+ return 1;
9077+}
9078+
9079+
9080+static struct file_buffer *get_fragment(struct fragment *fragment,
9081+ char *data_buffer, int fd)
9082+{
9083+ struct squashfs_fragment_entry *disk_fragment;
9084+ struct file_buffer *buffer, *compressed_buffer;
9085+ long long start_block;
9086+ int res, size, index = fragment->index;
9087+ char locked;
9088+
9089+ /*
9090+ * Lookup fragment block in cache.
9091+ * If the fragment block doesn't exist, then get the compressed version
9092+ * from the writer cache or off disk, and decompress it.
9093+ *
9094+ * This routine has two things which complicate the code:
9095+ *
9096+ * 1. Multiple threads can simultaneously lookup/create the
9097+ * same buffer. This means a buffer needs to be "locked"
9098+ * when it is being filled in, to prevent other threads from
9099+ * using it when it is not ready. This is because we now do
9100+ * fragment duplicate checking in parallel.
9101+ * 2. We have two caches which need to be checked for the
9102+ * presence of fragment blocks: the normal fragment cache
9103+ * and a "reserve" cache. The reserve cache is used to
9104+ * prevent an unnecessary pipeline stall when the fragment cache
9105+ * is full of fragments waiting to be compressed.
9106+ */
9107+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
9108+ pthread_mutex_lock(&dup_mutex);
9109+
9110+again:
9111+ buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
9112+ if(buffer) {
9113+ pthread_mutex_unlock(&dup_mutex);
9114+ if(locked)
9115+ /* got a buffer being filled in. Wait for it */
9116+ cache_wait_unlock(buffer);
9117+ goto finished;
9118+ }
9119+
9120+ /* not in fragment cache, is it in the reserve cache? */
9121+ buffer = cache_lookup_nowait(reserve_cache, index, &locked);
9122+ if(buffer) {
9123+ pthread_mutex_unlock(&dup_mutex);
9124+ if(locked)
9125+ /* got a buffer being filled in. Wait for it */
9126+ cache_wait_unlock(buffer);
9127+ goto finished;
9128+ }
9129+
9130+ /* in neither cache, try to get it from the fragment cache */
9131+ buffer = cache_get_nowait(fragment_buffer, index);
9132+ if(!buffer) {
9133+ /*
9134+ * no room, get it from the reserve cache, this is
9135+ * dimensioned so it will always have space (no more than
9136+ * processors + 1 can have an outstanding reserve buffer)
9137+ */
9138+ buffer = cache_get_nowait(reserve_cache, index);
9139+ if(!buffer) {
9140+ /* failsafe */
9141+ ERROR("no space in reserve cache\n");
9142+ goto again;
9143+ }
9144+ }
9145+
9146+ pthread_mutex_unlock(&dup_mutex);
9147+
9148+ compressed_buffer = cache_lookup(fwriter_buffer, index);
9149+
9150+ pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
9151+ pthread_mutex_lock(&fragment_mutex);
9152+ disk_fragment = &fragment_table[index];
9153+ size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
9154+ start_block = disk_fragment->start_block;
9155+ pthread_cleanup_pop(1);
9156+
9157+ if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
9158+ int error;
9159+ char *data;
9160+
9161+ if(compressed_buffer)
9162+ data = compressed_buffer->data;
9163+ else {
9164+ res = read_filesystem(fd, start_block, size, data_buffer);
9165+ if(res == 0) {
9166+ ERROR("Failed to read fragment from output"
9167+ " filesystem\n");
9168+ BAD_ERROR("Output filesystem corrupted?\n");
9169+ }
9170+ data = data_buffer;
9171+ }
9172+
9173+ res = compressor_uncompress(comp, buffer->data, data, size,
9174+ block_size, &error);
9175+ if(res == -1)
9176+ BAD_ERROR("%s uncompress failed with error code %d\n",
9177+ comp->name, error);
9178+ } else if(compressed_buffer)
9179+ memcpy(buffer->data, compressed_buffer->data, size);
9180+ else {
9181+ res = read_filesystem(fd, start_block, size, buffer->data);
9182+ if(res == 0) {
9183+ ERROR("Failed to read fragment from output "
9184+ "filesystem\n");
9185+ BAD_ERROR("Output filesystem corrupted?\n");
9186+ }
9187+ }
9188+
9189+ cache_unlock(buffer);
9190+ cache_block_put(compressed_buffer);
9191+
9192+finished:
9193+ pthread_cleanup_pop(0);
9194+
9195+ return buffer;
9196+}
9197+
9198+
9199+struct file_buffer *get_fragment_cksum(struct file_info *file,
9200+ char *data_buffer, int fd, unsigned short *checksum)
9201+{
9202+ struct file_buffer *frag_buffer;
9203+ struct append_file *append;
9204+ int index = file->fragment->index;
9205+
9206+ frag_buffer = get_fragment(file->fragment, data_buffer, fd);
9207+
9208+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
9209+
9210+ for(append = file_mapping[index]; append; append = append->next) {
9211+ int offset = append->file->fragment->offset;
9212+ int size = append->file->fragment->size;
9213+ char *data = frag_buffer->data + offset;
9214+ unsigned short cksum = get_checksum_mem(data, size);
9215+
9216+ if(file == append->file)
9217+ *checksum = cksum;
9218+
9219+ pthread_mutex_lock(&dup_mutex);
9220+ append->file->fragment_checksum = cksum;
9221+ append->file->have_frag_checksum = TRUE;
9222+ pthread_mutex_unlock(&dup_mutex);
9223+ }
9224+
9225+ pthread_cleanup_pop(0);
9226+
9227+ return frag_buffer;
9228+}
9229+
9230+
9231+void *frag_thrd(void *destination_file)
9232+{
9233+ sigset_t sigmask, old_mask;
9234+ char *data_buffer;
9235+ int fd;
9236+
9237+ sigemptyset(&sigmask);
9238+ sigaddset(&sigmask, SIGINT);
9239+ sigaddset(&sigmask, SIGTERM);
9240+ sigaddset(&sigmask, SIGUSR1);
9241+ pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
9242+
9243+ fd = open(destination_file, O_RDONLY);
9244+ if(fd == -1)
9245+ BAD_ERROR("frag_thrd: can't open destination for reading\n");
9246+
9247+ data_buffer = malloc(SQUASHFS_FILE_MAX_SIZE);
9248+ if(data_buffer == NULL)
9249+ MEM_ERROR();
9250+
9251+ pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
9252+
9253+ while(1) {
9254+ struct file_buffer *file_buffer = queue_get(to_process_frag);
9255+ struct file_buffer *buffer;
9256+ int sparse = checksum_sparse(file_buffer);
9257+ struct file_info *dupl_ptr;
9258+ long long file_size;
9259+ unsigned short checksum;
9260+ char flag;
9261+ int res;
9262+
9263+ if(sparse_files && sparse) {
9264+ file_buffer->c_byte = 0;
9265+ file_buffer->fragment = FALSE;
9266+ } else
9267+ file_buffer->c_byte = file_buffer->size;
9268+
9269+ /*
9270+ * Specutively pull into the fragment cache any fragment blocks
9271+ * which contain fragments which *this* fragment may be
9272+ * be a duplicate.
9273+ *
9274+ * By ensuring the fragment block is in cache ahead of time
9275+ * should eliminate the parallelisation stall when the
9276+ * main thread needs to read the fragment block to do a
9277+ * duplicate check on it.
9278+ *
9279+ * If this is a fragment belonging to a larger file
9280+ * (with additional blocks) then ignore it. Here we're
9281+ * interested in the "low hanging fruit" of files which
9282+ * consist of only a fragment
9283+ */
9284+ if(file_buffer->file_size != file_buffer->size) {
9285+ seq_queue_put(to_main, file_buffer);
9286+ continue;
9287+ }
9288+
9289+ file_size = file_buffer->file_size;
9290+
9291+ pthread_mutex_lock(&dup_mutex);
9292+ dupl_ptr = dupl[DUP_HASH(file_size)];
9293+ pthread_mutex_unlock(&dup_mutex);
9294+
9295+ file_buffer->dupl_start = dupl_ptr;
9296+ file_buffer->duplicate = FALSE;
9297+
9298+ for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
9299+ if(file_size != dupl_ptr->file_size ||
9300+ file_size != dupl_ptr->fragment->size)
9301+ continue;
9302+
9303+ pthread_mutex_lock(&dup_mutex);
9304+ flag = dupl_ptr->have_frag_checksum;
9305+ checksum = dupl_ptr->fragment_checksum;
9306+ pthread_mutex_unlock(&dup_mutex);
9307+
9308+ /*
9309+ * If we have the checksum and it matches then
9310+ * read in the fragment block.
9311+ *
9312+ * If we *don't* have the checksum, then we are
9313+ * appending, and the fragment block is on the
9314+ * "old" filesystem. Read it in and checksum
9315+ * the entire fragment buffer
9316+ */
9317+ if(!flag) {
9318+ buffer = get_fragment_cksum(dupl_ptr,
9319+ data_buffer, fd, &checksum);
9320+ if(checksum != file_buffer->checksum) {
9321+ cache_block_put(buffer);
9322+ continue;
9323+ }
9324+ } else if(checksum == file_buffer->checksum)
9325+ buffer = get_fragment(dupl_ptr->fragment,
9326+ data_buffer, fd);
9327+ else
9328+ continue;
9329+
9330+ res = memcmp(file_buffer->data, buffer->data +
9331+ dupl_ptr->fragment->offset, file_size);
9332+ cache_block_put(buffer);
9333+ if(res == 0) {
9334+ struct file_buffer *dup = malloc(sizeof(*dup));
9335+ if(dup == NULL)
9336+ MEM_ERROR();
9337+ memcpy(dup, file_buffer, sizeof(*dup));
9338+ cache_block_put(file_buffer);
9339+ dup->dupl_start = dupl_ptr;
9340+ dup->duplicate = TRUE;
9341+ file_buffer = dup;
9342+ break;
9343+ }
9344+ }
9345+
9346+ seq_queue_put(to_main, file_buffer);
9347+ }
9348+
9349+ pthread_cleanup_pop(0);
9350+}
9351diff -Nru squashfs-tools-4.2+20130409/process_fragments.h squashfs-tools-4.3+20140919/process_fragments.h
9352--- squashfs-tools-4.2+20130409/process_fragments.h 1970-01-01 01:00:00.000000000 +0100
9353+++ squashfs-tools-4.3+20140919/process_fragments.h 2015-07-20 21:03:05.000000000 +0200
9354@@ -0,0 +1,30 @@
9355+#ifndef PROCESS_FRAGMENTS_H
9356+#define PROCESS_FRAGMENTS_H
9357+/*
9358+ * Create a squashfs filesystem. This is a highly compressed read only
9359+ * filesystem.
9360+ *
9361+ * Copyright (c) 2014
9362+ * Phillip Lougher <phillip@squashfs.org.uk>
9363+ *
9364+ * This program is free software; you can redistribute it and/or
9365+ * modify it under the terms of the GNU General Public License
9366+ * as published by the Free Software Foundation; either version 2,
9367+ * or (at your option) any later version.
9368+ *
9369+ * This program is distributed in the hope that it will be useful,
9370+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9371+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9372+ * GNU General Public License for more details.
9373+ *
9374+ * You should have received a copy of the GNU General Public License
9375+ * along with this program; if not, write to the Free Software
9376+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
9377+ *
9378+ * process_fragments.h
9379+ */
9380+
9381+#define DUP_HASH(a) (a & 0xffff)
9382+
9383+extern void *frag_thrd(void *);
9384+#endif
9385diff -Nru squashfs-tools-4.2+20130409/progressbar.c squashfs-tools-4.3+20140919/progressbar.c
9386--- squashfs-tools-4.2+20130409/progressbar.c 2013-05-09 10:39:11.000000000 +0200
9387+++ squashfs-tools-4.3+20140919/progressbar.c 2015-07-20 21:03:05.000000000 +0200
9388@@ -2,7 +2,7 @@
9389 * Create a squashfs filesystem. This is a highly compressed read only
9390 * filesystem.
9391 *
9392- * Copyright (c) 2012, 2013
9393+ * Copyright (c) 2012, 2013, 2014
9394 * Phillip Lougher <phillip@squashfs.org.uk>
9395 *
9396 * This program is free software; you can redistribute it and/or
9397@@ -35,7 +35,15 @@
9398
9399 #include "error.h"
9400
9401-int progress_enabled = 0;
9402+#define FALSE 0
9403+#define TRUE 1
9404+
9405+/* flag whether progressbar display is enabled or not */
9406+int display_progress_bar = FALSE;
9407+
9408+/* flag whether the progress bar is temporarily disbled */
9409+int temp_disabled = FALSE;
9410+
9411 int rotate = 0;
9412 int cur_uncompressed = 0, estimated_uncompressed = 0;
9413 int columns;
9414@@ -50,7 +58,7 @@
9415
9416 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
9417 if(isatty(STDOUT_FILENO))
9418- printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
9419+ ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
9420 "columns\n");
9421 columns = 80;
9422 } else
9423@@ -132,21 +140,39 @@
9424
9425 void enable_progress_bar()
9426 {
9427+ pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
9428 pthread_mutex_lock(&progress_mutex);
9429- progress_enabled = 1;
9430- pthread_mutex_unlock(&progress_mutex);
9431+ if(display_progress_bar)
9432+ progress_bar(cur_uncompressed, estimated_uncompressed, columns);
9433+ temp_disabled = FALSE;
9434+ pthread_cleanup_pop(1);
9435 }
9436
9437
9438 void disable_progress_bar()
9439 {
9440+ pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
9441 pthread_mutex_lock(&progress_mutex);
9442- if(progress_enabled) {
9443- progress_bar(cur_uncompressed, estimated_uncompressed, columns);
9444+ if(display_progress_bar)
9445 printf("\n");
9446+ temp_disabled = TRUE;
9447+ pthread_cleanup_pop(1);
9448+}
9449+
9450+
9451+void set_progressbar_state(int state)
9452+{
9453+ pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
9454+ pthread_mutex_lock(&progress_mutex);
9455+ if(display_progress_bar != state) {
9456+ if(display_progress_bar && !temp_disabled) {
9457+ progress_bar(cur_uncompressed, estimated_uncompressed,
9458+ columns);
9459+ printf("\n");
9460+ }
9461+ display_progress_bar = state;
9462 }
9463- progress_enabled = 0;
9464- pthread_mutex_unlock(&progress_mutex);
9465+ pthread_cleanup_pop(1);
9466 }
9467
9468
9469@@ -158,7 +184,7 @@
9470
9471 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
9472 if(isatty(STDOUT_FILENO))
9473- printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
9474+ ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
9475 "columns\n");
9476 columns = 80;
9477 } else
9478@@ -181,12 +207,11 @@
9479 if(res == -1 && errno != EINTR)
9480 BAD_ERROR("nanosleep failed in progress thread\n");
9481
9482- if(progress_enabled) {
9483- pthread_mutex_lock(&progress_mutex);
9484+ pthread_mutex_lock(&progress_mutex);
9485+ if(display_progress_bar && !temp_disabled)
9486 progress_bar(cur_uncompressed, estimated_uncompressed,
9487 columns);
9488- pthread_mutex_unlock(&progress_mutex);
9489- }
9490+ pthread_mutex_unlock(&progress_mutex);
9491 }
9492 }
9493
9494@@ -201,16 +226,17 @@
9495 {
9496 va_list ap;
9497
9498+ pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
9499 pthread_mutex_lock(&progress_mutex);
9500
9501- if(progress_enabled)
9502+ if(display_progress_bar && !temp_disabled)
9503 fprintf(stderr, "\n");
9504
9505 va_start(ap, fmt);
9506 vfprintf(stderr, fmt, ap);
9507 va_end(ap);
9508
9509- pthread_mutex_unlock(&progress_mutex);
9510+ pthread_cleanup_pop(1);
9511 }
9512
9513
9514@@ -218,15 +244,16 @@
9515 {
9516 va_list ap;
9517
9518+ pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
9519 pthread_mutex_lock(&progress_mutex);
9520
9521- if(progress_enabled)
9522+ if(display_progress_bar && !temp_disabled)
9523 printf("\n");
9524
9525 va_start(ap, fmt);
9526 vprintf(fmt, ap);
9527 va_end(ap);
9528
9529- pthread_mutex_unlock(&progress_mutex);
9530+ pthread_cleanup_pop(1);
9531 }
9532
9533diff -Nru squashfs-tools-4.2+20130409/progressbar.h squashfs-tools-4.3+20140919/progressbar.h
9534--- squashfs-tools-4.2+20130409/progressbar.h 2013-05-09 10:39:11.000000000 +0200
9535+++ squashfs-tools-4.3+20140919/progressbar.h 2015-07-20 21:03:05.000000000 +0200
9536@@ -1,8 +1,10 @@
9537+#ifndef PROGRESSBAR_H
9538+#define PROGRESSBAR_H
9539 /*
9540 * Create a squashfs filesystem. This is a highly compressed read only
9541 * filesystem.
9542 *
9543- * Copyright (c) 2012, 2013
9544+ * Copyright (c) 2012, 2013, 2014
9545 * Phillip Lougher <phillip@squashfs.org.uk>
9546 *
9547 * This program is free software; you can redistribute it and/or
9548@@ -28,3 +30,5 @@
9549 extern void enable_progress_bar();
9550 extern void disable_progress_bar();
9551 extern void init_progress_bar();
9552+extern void set_progressbar_state(int);
9553+#endif
9554diff -Nru squashfs-tools-4.2+20130409/pseudo.c squashfs-tools-4.3+20140919/pseudo.c
9555--- squashfs-tools-4.2+20130409/pseudo.c 2013-05-09 10:39:11.000000000 +0200
9556+++ squashfs-tools-4.3+20140919/pseudo.c 2015-07-20 21:03:05.000000000 +0200
9557@@ -2,7 +2,7 @@
9558 * Create a squashfs filesystem. This is a highly compressed read only
9559 * filesystem.
9560 *
9561- * Copyright (c) 2009, 2010, 2012
9562+ * Copyright (c) 2009, 2010, 2012, 2014
9563 * Phillip Lougher <phillip@squashfs.org.uk>
9564 *
9565 * This program is free software; you can redistribute it and/or
9566@@ -36,6 +36,7 @@
9567
9568 #include "pseudo.h"
9569 #include "error.h"
9570+#include "progressbar.h"
9571
9572 #define TRUE 1
9573 #define FALSE 0
9574@@ -46,32 +47,6 @@
9575 struct pseudo *pseudo = NULL;
9576 int pseudo_count = 0;
9577
9578-static void dump_pseudo(struct pseudo *pseudo, char *string)
9579-{
9580- int i, res;
9581- char *path;
9582-
9583- for(i = 0; i < pseudo->names; i++) {
9584- struct pseudo_entry *entry = &pseudo->name[i];
9585- if(string) {
9586- res = asprintf(&path, "%s/%s", string, entry->name);
9587- if(res == -1)
9588- BAD_ERROR("asprintf failed in dump_pseudo\n");
9589- } else
9590- path = entry->name;
9591- if(entry->pseudo == NULL)
9592- ERROR("%s %c %o %d %d %d %d\n", path, entry->dev->type,
9593- entry->dev->mode, entry->dev->uid,
9594- entry->dev->gid, entry->dev->major,
9595- entry->dev->minor);
9596- else
9597- dump_pseudo(entry->pseudo, path);
9598- if(string)
9599- free(path);
9600- }
9601-}
9602-
9603-
9604 static char *get_component(char *target, char **targname)
9605 {
9606 char *start;
9607@@ -80,11 +55,14 @@
9608 target ++;
9609
9610 start = target;
9611- while(*target != '/' && *target!= '\0')
9612+ while(*target != '/' && *target != '\0')
9613 target ++;
9614
9615 *targname = strndup(start, target - start);
9616
9617+ while(*target == '/')
9618+ target ++;
9619+
9620 return target;
9621 }
9622
9623@@ -154,16 +132,23 @@
9624 pseudo->name[i].pseudo =
9625 add_pseudo(NULL, pseudo_dev,
9626 target, alltarget);
9627- else
9628- ERROR("%s already exists as a non "
9629- "directory. Ignoring %s!\n",
9630- targname, alltarget);
9631+ else {
9632+ ERROR_START("%s already exists as a "
9633+ "non directory.",
9634+ pseudo->name[i].name);
9635+ ERROR_EXIT(". Ignoring %s!\n",
9636+ alltarget);
9637+ }
9638 } else if(memcmp(pseudo_dev, pseudo->name[i].dev,
9639- sizeof(struct pseudo_dev)) != 0)
9640- ERROR("%s already exists as a different pseudo "
9641- "definition. Ignoring!\n", alltarget);
9642- else ERROR("%s already exists as an identical "
9643- "pseudo definition!\n", alltarget);
9644+ sizeof(struct pseudo_dev)) != 0) {
9645+ ERROR_START("%s already exists as a different "
9646+ "pseudo definition.", alltarget);
9647+ ERROR_EXIT(" Ignoring!\n");
9648+ } else {
9649+ ERROR_START("%s already exists as an identical "
9650+ "pseudo definition!", alltarget);
9651+ ERROR_EXIT(" Ignoring!\n");
9652+ }
9653 } else {
9654 if(target[0] == '\0') {
9655 /*
9656@@ -176,10 +161,13 @@
9657 pseudo->name[i].pathname =
9658 strdup(alltarget);
9659 pseudo->name[i].dev = pseudo_dev;
9660- } else
9661- ERROR("%s already exists as a different"
9662- " pseudo definition. Ignoring"
9663- " %s!\n", targname, alltarget);
9664+ } else {
9665+ ERROR_START("%s already exists as a "
9666+ "different pseudo definition.",
9667+ pseudo->name[i].name);
9668+ ERROR_EXIT(" Ignoring %s!\n",
9669+ alltarget);
9670+ }
9671 } else
9672 /* recurse adding child components */
9673 add_pseudo(pseudo->name[i].pseudo, pseudo_dev,
9674@@ -227,75 +215,40 @@
9675 }
9676
9677
9678-int exec_file(char *command, struct pseudo_dev *dev)
9679+int pseudo_exec_file(struct pseudo_dev *dev, int *child)
9680 {
9681- int child, res;
9682- static pid_t pid = -1;
9683- int pipefd[2];
9684-#ifdef USE_TMP_FILE
9685- char *filename;
9686- int status;
9687- static int number = 0;
9688-#endif
9689-
9690- if(pid == -1)
9691- pid = getpid();
9692+ int res, pipefd[2];
9693
9694-#ifdef USE_TMP_FILE
9695- res = asprintf(&filename, "/tmp/squashfs_pseudo_%d_%d", pid, number ++);
9696- if(res == -1) {
9697- ERROR("asprint failed in exec_file()\n");
9698- return -1;
9699- }
9700- pipefd[1] = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
9701- if(pipefd[1] == -1) {
9702- ERROR("Executing dynamic pseudo file, open failed\n");
9703- free(filename);
9704- return -1;
9705- }
9706-#else
9707 res = pipe(pipefd);
9708 if(res == -1) {
9709 ERROR("Executing dynamic pseudo file, pipe failed\n");
9710- return -1;
9711+ return 0;
9712 }
9713-#endif
9714
9715- child = fork();
9716- if(child == -1) {
9717+ *child = fork();
9718+ if(*child == -1) {
9719 ERROR("Executing dynamic pseudo file, fork failed\n");
9720 goto failed;
9721 }
9722
9723- if(child == 0) {
9724+ if(*child == 0) {
9725+ close(pipefd[0]);
9726 close(STDOUT_FILENO);
9727 res = dup(pipefd[1]);
9728 if(res == -1)
9729 exit(EXIT_FAILURE);
9730
9731- execl("/bin/sh", "sh", "-c", command, (char *) NULL);
9732+ execl("/bin/sh", "sh", "-c", dev->command, (char *) NULL);
9733 exit(EXIT_FAILURE);
9734 }
9735
9736-#ifdef USE_TMP_FILE
9737- res = waitpid(child, &status, 0);
9738 close(pipefd[1]);
9739- if(res != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) {
9740- dev->filename = filename;
9741- return 0;
9742- }
9743+ return pipefd[0];
9744+
9745 failed:
9746- unlink(filename);
9747- free(filename);
9748- return -1;
9749-#else
9750+ close(pipefd[0]);
9751 close(pipefd[1]);
9752- dev->fd = pipefd[0];
9753- dev->child = child;
9754 return 0;
9755-failed:
9756- return -1;
9757-#endif
9758 }
9759
9760
9761@@ -311,17 +264,6 @@
9762 }
9763
9764
9765-void delete_pseudo_files()
9766-{
9767-#ifdef USE_TMP_FILE
9768- int i;
9769-
9770- for(i = 0; i < pseudo_count; i++)
9771- unlink(pseudo_file[i]->filename);
9772-#endif
9773-}
9774-
9775-
9776 struct pseudo_dev *get_pseudo_file(int pseudo_id)
9777 {
9778 return pseudo_file[pseudo_id];
9779@@ -513,20 +455,8 @@
9780 dev->gid = gid;
9781 dev->major = major;
9782 dev->minor = minor;
9783-
9784 if(type == 'f') {
9785- int res;
9786-
9787- printf("Executing dynamic pseudo file\n");
9788- printf("\t\"%s\"\n", orig_def);
9789- res = exec_file(def, dev);
9790- if(res == -1) {
9791- ERROR("Failed to execute dynamic pseudo file definition"
9792- " \"%s\"\n", orig_def);
9793- free(filename);
9794- free(dev);
9795- return FALSE;
9796- }
9797+ dev->command = strdup(def);
9798 add_pseudo_file(dev);
9799 }
9800
9801@@ -557,3 +487,41 @@
9802 {
9803 return pseudo;
9804 }
9805+
9806+
9807+#ifdef SQUASHFS_TRACE
9808+static void dump_pseudo(struct pseudo *pseudo, char *string)
9809+{
9810+ int i, res;
9811+ char *path;
9812+
9813+ for(i = 0; i < pseudo->names; i++) {
9814+ struct pseudo_entry *entry = &pseudo->name[i];
9815+ if(string) {
9816+ res = asprintf(&path, "%s/%s", string, entry->name);
9817+ if(res == -1)
9818+ BAD_ERROR("asprintf failed in dump_pseudo\n");
9819+ } else
9820+ path = entry->name;
9821+ if(entry->dev)
9822+ ERROR("%s %c 0%o %d %d %d %d\n", path, entry->dev->type,
9823+ entry->dev->mode & ~S_IFMT, entry->dev->uid,
9824+ entry->dev->gid, entry->dev->major,
9825+ entry->dev->minor);
9826+ if(entry->pseudo)
9827+ dump_pseudo(entry->pseudo, path);
9828+ if(string)
9829+ free(path);
9830+ }
9831+}
9832+
9833+
9834+void dump_pseudos()
9835+{
9836+ dump_pseudo(pseudo, NULL);
9837+}
9838+#else
9839+void dump_pseudos()
9840+{
9841+}
9842+#endif
9843diff -Nru squashfs-tools-4.2+20130409/pseudo.h squashfs-tools-4.3+20140919/pseudo.h
9844--- squashfs-tools-4.2+20130409/pseudo.h 2013-05-09 10:39:11.000000000 +0200
9845+++ squashfs-tools-4.3+20140919/pseudo.h 2015-07-20 21:03:05.000000000 +0200
9846@@ -1,8 +1,10 @@
9847+#ifndef PSEUDO_H
9848+#define PSEUDO_H
9849 /*
9850 * Create a squashfs filesystem. This is a highly compressed read only
9851 * filesystem.
9852 *
9853- * Copyright (c) 2009, 2010
9854+ * Copyright (c) 2009, 2010, 2014
9855 * Phillip Lougher <phillip@squashfs.org.uk>
9856 *
9857 * This program is free software; you can redistribute it and/or
9858@@ -29,11 +31,7 @@
9859 unsigned int major;
9860 unsigned int minor;
9861 int pseudo_id;
9862- int fd;
9863- int child;
9864-#ifdef USE_TMP_FILE
9865- char *filename;
9866-#endif
9867+ char *command;
9868 };
9869
9870 struct pseudo_entry {
9871@@ -54,5 +52,7 @@
9872 extern struct pseudo *pseudo_subdir(char *, struct pseudo *);
9873 extern struct pseudo_entry *pseudo_readdir(struct pseudo *);
9874 extern struct pseudo_dev *get_pseudo_file(int);
9875-extern void delete_pseudo_files();
9876+extern int pseudo_exec_file(struct pseudo_dev *, int *);
9877 extern struct pseudo *get_pseudo();
9878+extern void dump_pseudos();
9879+#endif
9880diff -Nru squashfs-tools-4.2+20130409/read_fs.c squashfs-tools-4.3+20140919/read_fs.c
9881--- squashfs-tools-4.2+20130409/read_fs.c 2013-05-09 10:39:11.000000000 +0200
9882+++ squashfs-tools-4.3+20140919/read_fs.c 2015-07-20 21:03:05.000000000 +0200
9883@@ -3,7 +3,7 @@
9884 * filesystem.
9885 *
9886 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
9887- * 2012, 2013
9888+ * 2012, 2013, 2014
9889 * Phillip Lougher <phillip@squashfs.org.uk>
9890 *
9891 * This program is free software; you can redistribute it and/or
9892@@ -33,6 +33,7 @@
9893 #include <string.h>
9894 #include <sys/mman.h>
9895 #include <limits.h>
9896+#include <dirent.h>
9897
9898 #ifndef linux
9899 #define __BYTE_ORDER BYTE_ORDER
9900@@ -46,19 +47,10 @@
9901
9902 #include "squashfs_fs.h"
9903 #include "squashfs_swap.h"
9904-#include "read_fs.h"
9905 #include "compressor.h"
9906 #include "xattr.h"
9907 #include "error.h"
9908-
9909-extern int read_fs_bytes(int, long long, int, void *);
9910-extern int add_file(long long, long long, long long, unsigned int *, int,
9911- unsigned int, int, int);
9912-extern void *create_id(unsigned int);
9913-extern unsigned int get_uid(unsigned int);
9914-extern unsigned int get_guid(unsigned int);
9915-
9916-static struct compressor *comp;
9917+#include "mksquashfs.h"
9918
9919 int read_block(int fd, long long start, long long *next, int expected,
9920 void *block)
9921@@ -207,7 +199,7 @@
9922 */
9923 *root_inode_size = bytes - (*root_inode_block + root_inode_offset);
9924 bytes = *root_inode_block + root_inode_offset;
9925- SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, *inode_table + bytes);
9926+ SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir);
9927
9928 if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
9929 directory_start_block = dir_inode->dir.start_block;
9930@@ -215,8 +207,8 @@
9931 if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
9932 /* corrupted filesystem */
9933 goto corrupted;
9934- SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir,
9935- *inode_table + bytes);
9936+ SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes,
9937+ &dir_inode->ldir);
9938 directory_start_block = dir_inode->ldir.start_block;
9939 } else
9940 /* bad type, corrupted filesystem */
9941@@ -225,12 +217,17 @@
9942 get_uid(id_table[dir_inode->base.uid]);
9943 get_guid(id_table[dir_inode->base.guid]);
9944
9945+ /* allocate fragment to file mapping table */
9946+ file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
9947+ if(file_mapping == NULL)
9948+ MEM_ERROR();
9949+
9950 for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
9951 if(NO_INODE_BYTES(squashfs_base_inode_header))
9952 /* corrupted filesystem */
9953 goto corrupted;
9954
9955- SQUASHFS_SWAP_BASE_INODE_HEADER(&base, cur_ptr);
9956+ SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
9957
9958 TRACE("scan_inode_table: processing inode @ byte position "
9959 "0x%x, type 0x%x\n",
9960@@ -251,7 +248,7 @@
9961 /* corrupted filesystem */
9962 goto corrupted;
9963
9964- SQUASHFS_SWAP_REG_INODE_HEADER(&inode, cur_ptr);
9965+ SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
9966
9967 frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
9968 0 : inode.file_size % sBlk->block_size;
9969@@ -273,7 +270,7 @@
9970 MEM_ERROR();
9971
9972 cur_ptr += sizeof(inode);
9973- SQUASHFS_SWAP_INTS(block_list, cur_ptr, blocks);
9974+ SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
9975
9976 *uncompressed_file += inode.file_size;
9977 (*file_count) ++;
9978@@ -283,6 +280,12 @@
9979 SQUASHFS_COMPRESSED_SIZE_BLOCK
9980 (block_list[i]);
9981
9982+ if(inode.fragment != SQUASHFS_INVALID_FRAG &&
9983+ inode.fragment >= sBlk->fragments) {
9984+ free(block_list);
9985+ goto corrupted;
9986+ }
9987+
9988 add_file(start, inode.file_size, file_bytes,
9989 block_list, blocks, inode.fragment,
9990 inode.offset, frag_bytes);
9991@@ -300,7 +303,7 @@
9992 /* corrupted filesystem */
9993 goto corrupted;
9994
9995- SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, cur_ptr);
9996+ SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
9997
9998 frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
9999 0 : inode.file_size % sBlk->block_size;
10000@@ -323,7 +326,7 @@
10001 MEM_ERROR();
10002
10003 cur_ptr += sizeof(inode);
10004- SQUASHFS_SWAP_INTS(block_list, cur_ptr, blocks);
10005+ SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
10006
10007 *uncompressed_file += inode.file_size;
10008 (*file_count) ++;
10009@@ -333,6 +336,12 @@
10010 SQUASHFS_COMPRESSED_SIZE_BLOCK
10011 (block_list[i]);
10012
10013+ if(inode.fragment != SQUASHFS_INVALID_FRAG &&
10014+ inode.fragment >= sBlk->fragments) {
10015+ free(block_list);
10016+ goto corrupted;
10017+ }
10018+
10019 add_file(start, inode.file_size, file_bytes,
10020 block_list, blocks, inode.fragment,
10021 inode.offset, frag_bytes);
10022@@ -348,7 +357,7 @@
10023 /* corrupted filesystem */
10024 goto corrupted;
10025
10026- SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inode, cur_ptr);
10027+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
10028
10029 (*sym_count) ++;
10030
10031@@ -374,7 +383,7 @@
10032 /* corrupted filesystem */
10033 goto corrupted;
10034
10035- SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, cur_ptr);
10036+ SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
10037
10038 if(dir_inode.start_block < directory_start_block)
10039 *uncompressed_directory += dir_inode.file_size;
10040@@ -391,7 +400,7 @@
10041 /* corrupted filesystem */
10042 goto corrupted;
10043
10044- SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, cur_ptr);
10045+ SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
10046
10047 if(dir_inode.start_block < directory_start_block)
10048 *uncompressed_directory += dir_inode.file_size;
10049@@ -406,7 +415,7 @@
10050 /* corrupted filesystem */
10051 goto corrupted;
10052
10053- SQUASHFS_SWAP_DIR_INDEX(&index, cur_ptr);
10054+ SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
10055
10056 if(NO_BYTES(index.size + 1))
10057 /* corrupted filesystem */
10058@@ -531,7 +540,7 @@
10059 /* Check the compression type */
10060 comp = lookup_compressor_id(sBlk->compression);
10061 if(!comp->supported) {
10062- ERROR("Filesystem on %s uses %s compression, this is"
10063+ ERROR("Filesystem on %s uses %s compression, this is "
10064 "unsupported by this version\n", source, comp->name);
10065 ERROR("Compressors available:\n");
10066 display_compressors("", "");
10067@@ -548,6 +557,10 @@
10068 * is still called to set the default options (the defaults may have
10069 * been changed by the user specifying options on the command
10070 * line which need to be over-ridden).
10071+ *
10072+ * Compressor_extract_options is also used to ensure that
10073+ * we know how decompress a filesystem compressed with these
10074+ * compression options.
10075 */
10076 if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
10077 bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
10078@@ -579,7 +592,7 @@
10079 SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
10080 printf("\tFragments are %spresent in the filesystem\n",
10081 SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
10082- printf("\tAlways_use_fragments option is %sspecified\n",
10083+ printf("\tAlways-use-fragments option is %sspecified\n",
10084 SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
10085 printf("\tDuplicates are %sremoved\n",
10086 SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
10087@@ -651,7 +664,7 @@
10088
10089 bytes = offset;
10090 while(bytes < size) {
10091- SQUASHFS_SWAP_DIR_HEADER(&dirh, directory_table + bytes);
10092+ SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
10093
10094 dir_count = dirh.count + 1;
10095 TRACE("squashfs_readdir: Read directory header @ byte position "
10096@@ -659,7 +672,7 @@
10097 bytes += sizeof(dirh);
10098
10099 while(dir_count--) {
10100- SQUASHFS_SWAP_DIR_ENTRY(dire, directory_table + bytes);
10101+ SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
10102 bytes += sizeof(*dire);
10103
10104 memcpy(dire->name, directory_table + bytes,
10105diff -Nru squashfs-tools-4.2+20130409/read_fs.h squashfs-tools-4.3+20140919/read_fs.h
10106--- squashfs-tools-4.2+20130409/read_fs.h 2013-05-09 10:39:11.000000000 +0200
10107+++ squashfs-tools-4.3+20140919/read_fs.h 2015-07-20 21:03:05.000000000 +0200
10108@@ -3,7 +3,7 @@
10109 /*
10110 * Squashfs
10111 *
10112- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
10113+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
10114 * Phillip Lougher <phillip@squashfs.org.uk>
10115 *
10116 * This program is free software; you can redistribute it and/or
10117@@ -23,20 +23,12 @@
10118 * read_fs.h
10119 *
10120 */
10121-
10122-#if __BYTE_ORDER == __BIG_ENDIAN
10123-#define SQUASHFS_SWAP_SHORTS(d, s, n) swap_le16_num(s, d, n)
10124-#define SQUASHFS_SWAP_INTS(d, s, n) swap_le32_num(s, d, n)
10125-#define SQUASHFS_SWAP_LONG_LONGS(d, s, n) swap_le64_num(s, d, n)
10126-
10127-#define SWAP_LE16(d, s) swap_le16(s, d)
10128-#define SWAP_LE32(d, s) swap_le32(s, d)
10129-#define SWAP_LE64(d, s) swap_le64(s, d)
10130-#else
10131-#define SQUASHFS_MEMCPY(d, s, n) memcpy(d, s, n)
10132-#define SQUASHFS_SWAP_SHORTS(d, s, n) memcpy(d, s, n * sizeof(short))
10133-#define SQUASHFS_SWAP_INTS(d, s, n) memcpy(d, s, n * sizeof(int))
10134-#define SQUASHFS_SWAP_LONG_LONGS(d, s, n) \
10135- memcpy(d, s, n * sizeof(long long))
10136-#endif
10137+extern struct compressor *read_super(int, struct squashfs_super_block *,
10138+ char *);
10139+extern long long read_filesystem(char *, int, struct squashfs_super_block *,
10140+char **, char **, char **, char **, unsigned int *, unsigned int *,
10141+unsigned int *, unsigned int *, unsigned int *, int *, int *, int *, int *,
10142+int *, int *, long long *, unsigned int *, unsigned int *, unsigned int *,
10143+unsigned int *, void (push_directory_entry)(char *, squashfs_inode, int, int),
10144+struct squashfs_fragment_entry **, squashfs_inode **);
10145 #endif
10146diff -Nru squashfs-tools-4.2+20130409/read_xattrs.c squashfs-tools-4.3+20140919/read_xattrs.c
10147--- squashfs-tools-4.2+20130409/read_xattrs.c 2013-05-09 10:39:11.000000000 +0200
10148+++ squashfs-tools-4.3+20140919/read_xattrs.c 2015-07-20 21:03:05.000000000 +0200
10149@@ -41,7 +41,6 @@
10150
10151 #include "squashfs_fs.h"
10152 #include "squashfs_swap.h"
10153-#include "read_fs.h"
10154 #include "xattr.h"
10155 #include "error.h"
10156
10157@@ -338,7 +337,7 @@
10158 MEM_ERROR();
10159 }
10160
10161- SQUASHFS_SWAP_XATTR_ENTRY(&entry, xptr);
10162+ SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
10163 xptr += sizeof(entry);
10164
10165 res = read_xattr_entry(&xattr_list[j], &entry, xptr);
10166@@ -361,15 +360,15 @@
10167 void *ool_xptr;
10168
10169 xptr += sizeof(val);
10170- SQUASHFS_SWAP_LONG_LONGS(&xattr, xptr, 1);
10171+ SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
10172 xptr += sizeof(xattr);
10173 start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
10174 offset = SQUASHFS_XATTR_OFFSET(xattr);
10175 ool_xptr = xattrs + get_xattr_block(start) + offset;
10176- SQUASHFS_SWAP_XATTR_VAL(&val, ool_xptr);
10177+ SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
10178 xattr_list[j].value = ool_xptr + sizeof(val);
10179 } else {
10180- SQUASHFS_SWAP_XATTR_VAL(&val, xptr);
10181+ SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
10182 xattr_list[j].value = xptr + sizeof(val);
10183 xptr += sizeof(val) + val.vsize;
10184 }
10185diff -Nru squashfs-tools-4.2+20130409/restore.c squashfs-tools-4.3+20140919/restore.c
10186--- squashfs-tools-4.2+20130409/restore.c 2013-05-09 10:39:11.000000000 +0200
10187+++ squashfs-tools-4.3+20140919/restore.c 2015-07-20 21:03:05.000000000 +0200
10188@@ -2,7 +2,7 @@
10189 * Create a squashfs filesystem. This is a highly compressed read only
10190 * filesystem.
10191 *
10192- * Copyright (c) 2013
10193+ * Copyright (c) 2013, 2014
10194 * Phillip Lougher <phillip@squashfs.org.uk>
10195 *
10196 * This program is free software; you can redistribute it and/or
10197@@ -36,22 +36,30 @@
10198 #include <sys/types.h>
10199 #include <sys/stat.h>
10200
10201+#include "caches-queues-lists.h"
10202 #include "squashfs_fs.h"
10203 #include "mksquashfs.h"
10204 #include "error.h"
10205 #include "progressbar.h"
10206 #include "info.h"
10207
10208-pthread_t restore_thread, main_thread;
10209-int interrupted = 0;
10210+#define FALSE 0
10211+#define TRUE 1
10212
10213+extern pthread_t reader_thread, writer_thread, main_thread;
10214+extern pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
10215+extern struct queue *to_deflate, *to_writer, *to_frag, *to_process_frag;
10216+extern struct seq_queue *to_main;
10217 extern void restorefs();
10218+extern int processors;
10219
10220+static int interrupted = 0;
10221+static pthread_t restore_thread;
10222
10223 void *restore_thrd(void *arg)
10224 {
10225 sigset_t sigmask, old_mask;
10226- int sig;
10227+ int i, sig;
10228
10229 sigemptyset(&sigmask);
10230 sigaddset(&sigmask, SIGINT);
10231@@ -62,31 +70,86 @@
10232 while(1) {
10233 sigwait(&sigmask, &sig);
10234
10235- if(sig == SIGINT || sig == SIGTERM) {
10236- interrupted ++;
10237-
10238- if(interrupted == 1) {
10239- ERROR("Interrupting will restore original "
10240- "filesystem!\n");
10241- ERROR("Interrupt again to quit\n");
10242- }
10243+ if((sig == SIGINT || sig == SIGTERM) && !interrupted) {
10244+ ERROR("Interrupting will restore original "
10245+ "filesystem!\n");
10246+ ERROR("Interrupt again to quit\n");
10247+ interrupted = TRUE;
10248+ continue;
10249 }
10250
10251- if(interrupted == 2 || sig == SIGUSR1) {
10252- disable_progress_bar();
10253- disable_info();
10254- pthread_cancel(main_thread);
10255- pthread_join(main_thread, NULL);
10256+ /* kill main thread/worker threads and restore */
10257+ set_progressbar_state(FALSE);
10258+ disable_info();
10259+
10260+ /* first kill the reader thread */
10261+ pthread_cancel(reader_thread);
10262+ pthread_join(reader_thread, NULL);
10263+
10264+ /*
10265+ * then flush the reader to deflator thread(s) output queue.
10266+ * The deflator thread(s) will idle
10267+ */
10268+ queue_flush(to_deflate);
10269+
10270+ /* now kill the deflator thread(s) */
10271+ for(i = 0; i < processors; i++)
10272+ pthread_cancel(deflator_thread[i]);
10273+ for(i = 0; i < processors; i++)
10274+ pthread_join(deflator_thread[i], NULL);
10275+
10276+ /*
10277+ * then flush the reader to process fragment thread(s) output
10278+ * queue. The process fragment thread(s) will idle
10279+ */
10280+ queue_flush(to_process_frag);
10281+
10282+ /* now kill the process fragment thread(s) */
10283+ for(i = 0; i < processors; i++)
10284+ pthread_cancel(frag_thread[i]);
10285+ for(i = 0; i < processors; i++)
10286+ pthread_join(frag_thread[i], NULL);
10287+
10288+ /*
10289+ * then flush the reader/deflator/process fragment to main
10290+ * thread output queue. The main thread will idle
10291+ */
10292+ seq_queue_flush(to_main);
10293+
10294+ /* now kill the main thread */
10295+ pthread_cancel(main_thread);
10296+ pthread_join(main_thread, NULL);
10297+
10298+ /* then flush the main thread to fragment deflator thread(s)
10299+ * queue. The fragment deflator thread(s) will idle
10300+ */
10301+ queue_flush(to_frag);
10302+
10303+ /* now kill the fragment deflator thread(s) */
10304+ for(i = 0; i < processors; i++)
10305+ pthread_cancel(frag_deflator_thread[i]);
10306+ for(i = 0; i < processors; i++)
10307+ pthread_join(frag_deflator_thread[i], NULL);
10308+
10309+ /*
10310+ * then flush the main thread/fragment deflator thread(s)
10311+ * to writer thread queue. The writer thread will idle
10312+ */
10313+ queue_flush(to_writer);
10314+
10315+ /* now kill the writer thread */
10316+ pthread_cancel(writer_thread);
10317+ pthread_join(writer_thread, NULL);
10318
10319- restorefs();
10320- }
10321+ TRACE("All threads cancelled\n");
10322+
10323+ restorefs();
10324 }
10325 }
10326
10327
10328-pthread_t *init_restore_thread(pthread_t thread)
10329+pthread_t *init_restore_thread()
10330 {
10331- main_thread = thread;
10332 pthread_create(&restore_thread, NULL, restore_thrd, NULL);
10333 return &restore_thread;
10334 }
10335diff -Nru squashfs-tools-4.2+20130409/restore.h squashfs-tools-4.3+20140919/restore.h
10336--- squashfs-tools-4.2+20130409/restore.h 1970-01-01 01:00:00.000000000 +0100
10337+++ squashfs-tools-4.3+20140919/restore.h 2015-07-20 21:03:05.000000000 +0200
10338@@ -0,0 +1,28 @@
10339+#ifndef RESTORE_H
10340+#define RESTORE_H
10341+/*
10342+ * Create a squashfs filesystem. This is a highly compressed read only
10343+ * filesystem.
10344+ *
10345+ * Copyright (c) 2013, 2014
10346+ * Phillip Lougher <phillip@squashfs.org.uk>
10347+ *
10348+ * This program is free software; you can redistribute it and/or
10349+ * modify it under the terms of the GNU General Public License
10350+ * as published by the Free Software Foundation; either version 2,
10351+ * or (at your option) any later version.
10352+ *
10353+ * This program is distributed in the hope that it will be useful,
10354+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10355+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10356+ * GNU General Public License for more details.
10357+ *
10358+ * You should have received a copy of the GNU General Public License
10359+ * along with this program; if not, write to the Free Software
10360+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10361+ *
10362+ * restore.h
10363+ */
10364+
10365+extern pthread_t *init_restore_thread();
10366+#endif
10367diff -Nru squashfs-tools-4.2+20130409/sort.c squashfs-tools-4.3+20140919/sort.c
10368--- squashfs-tools-4.2+20130409/sort.c 2013-05-09 10:39:11.000000000 +0200
10369+++ squashfs-tools-4.3+20140919/sort.c 2015-07-20 21:03:05.000000000 +0200
10370@@ -3,7 +3,7 @@
10371 * filesystem.
10372 *
10373 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
10374- * 2013
10375+ * 2013, 2014
10376 * Phillip Lougher <phillip@squashfs.org.uk>
10377 *
10378 * This program is free software; you can redistribute it and/or
10379@@ -42,6 +42,7 @@
10380 #include "mksquashfs.h"
10381 #include "sort.h"
10382 #include "error.h"
10383+#include "progressbar.h"
10384
10385 int mkisofs_style = -1;
10386
10387@@ -170,9 +171,10 @@
10388 }
10389
10390 error:
10391- ERROR("Cannot stat sortlist entry \"%s\"\n", path);
10392+ ERROR_START("Cannot stat sortlist entry \"%s\"\n", path);
10393 ERROR("This is probably because you're using the wrong file\n");
10394- ERROR("path relative to the source directories\n");
10395+ ERROR("path relative to the source directories.");
10396+ ERROR_EXIT(" Ignoring");
10397 /*
10398 * Historical note
10399 * Failure to stat a sortlist entry is deliberately ignored, even
10400diff -Nru squashfs-tools-4.2+20130409/sort.h squashfs-tools-4.3+20140919/sort.h
10401--- squashfs-tools-4.2+20130409/sort.h 2013-05-09 10:39:11.000000000 +0200
10402+++ squashfs-tools-4.3+20140919/sort.h 2015-07-20 21:03:05.000000000 +0200
10403@@ -4,7 +4,7 @@
10404 /*
10405 * Squashfs
10406 *
10407- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
10408+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
10409 * Phillip Lougher <phillip@squashfs.org.uk>
10410 *
10411 * This program is free software; you can redistribute it and/or
10412@@ -28,4 +28,10 @@
10413 struct dir_ent *dir;
10414 struct priority_entry *next;
10415 };
10416+
10417+extern int read_sort_file(char *, int, char *[]);
10418+extern void sort_files_and_write(struct dir_info *);
10419+extern void generate_file_priorities(struct dir_info *, int priority,
10420+ struct stat *);
10421+extern struct priority_entry *priority_list[65536];
10422 #endif
10423diff -Nru squashfs-tools-4.2+20130409/squashfs_compat.h squashfs-tools-4.3+20140919/squashfs_compat.h
10424--- squashfs-tools-4.2+20130409/squashfs_compat.h 2013-05-09 10:39:11.000000000 +0200
10425+++ squashfs-tools-4.3+20140919/squashfs_compat.h 2015-07-20 21:03:05.000000000 +0200
10426@@ -3,7 +3,7 @@
10427 /*
10428 * Squashfs
10429 *
10430- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
10431+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014
10432 * Phillip Lougher <phillip@squashfs.org.uk>
10433 *
10434 * This program is free software; you can redistribute it and/or
10435@@ -50,7 +50,7 @@
10436 unsigned int flags:8;
10437 unsigned int no_uids:8;
10438 unsigned int no_guids:8;
10439- unsigned int mkfs_time /* time of filesystem creation */;
10440+ int mkfs_time /* time of filesystem creation */;
10441 squashfs_inode root_inode;
10442 unsigned int block_size;
10443 unsigned int fragments;
10444@@ -71,38 +71,55 @@
10445 unsigned char name[0];
10446 } __attribute__ ((packed));
10447
10448-#define SQUASHFS_BASE_INODE_HEADER_3 \
10449- unsigned int inode_type:4; \
10450- unsigned int mode:12; \
10451- unsigned int uid:8; \
10452- unsigned int guid:8; \
10453- unsigned int mtime; \
10454- unsigned int inode_number;
10455-
10456 struct squashfs_base_inode_header_3 {
10457- SQUASHFS_BASE_INODE_HEADER_3;
10458+ unsigned int inode_type:4;
10459+ unsigned int mode:12;
10460+ unsigned int uid:8;
10461+ unsigned int guid:8;
10462+ int mtime;
10463+ unsigned int inode_number;
10464 } __attribute__ ((packed));
10465
10466 struct squashfs_ipc_inode_header_3 {
10467- SQUASHFS_BASE_INODE_HEADER_3;
10468+ unsigned int inode_type:4;
10469+ unsigned int mode:12;
10470+ unsigned int uid:8;
10471+ unsigned int guid:8;
10472+ int mtime;
10473+ unsigned int inode_number;
10474 unsigned int nlink;
10475 } __attribute__ ((packed));
10476
10477 struct squashfs_dev_inode_header_3 {
10478- SQUASHFS_BASE_INODE_HEADER_3;
10479+ unsigned int inode_type:4;
10480+ unsigned int mode:12;
10481+ unsigned int uid:8;
10482+ unsigned int guid:8;
10483+ int mtime;
10484+ unsigned int inode_number;
10485 unsigned int nlink;
10486 unsigned short rdev;
10487 } __attribute__ ((packed));
10488
10489 struct squashfs_symlink_inode_header_3 {
10490- SQUASHFS_BASE_INODE_HEADER_3;
10491+ unsigned int inode_type:4;
10492+ unsigned int mode:12;
10493+ unsigned int uid:8;
10494+ unsigned int guid:8;
10495+ int mtime;
10496+ unsigned int inode_number;
10497 unsigned int nlink;
10498 unsigned short symlink_size;
10499 char symlink[0];
10500 } __attribute__ ((packed));
10501
10502 struct squashfs_reg_inode_header_3 {
10503- SQUASHFS_BASE_INODE_HEADER_3;
10504+ unsigned int inode_type:4;
10505+ unsigned int mode:12;
10506+ unsigned int uid:8;
10507+ unsigned int guid:8;
10508+ int mtime;
10509+ unsigned int inode_number;
10510 squashfs_block start_block;
10511 unsigned int fragment;
10512 unsigned int offset;
10513@@ -111,7 +128,12 @@
10514 } __attribute__ ((packed));
10515
10516 struct squashfs_lreg_inode_header_3 {
10517- SQUASHFS_BASE_INODE_HEADER_3;
10518+ unsigned int inode_type:4;
10519+ unsigned int mode:12;
10520+ unsigned int uid:8;
10521+ unsigned int guid:8;
10522+ int mtime;
10523+ unsigned int inode_number;
10524 unsigned int nlink;
10525 squashfs_block start_block;
10526 unsigned int fragment;
10527@@ -121,7 +143,12 @@
10528 } __attribute__ ((packed));
10529
10530 struct squashfs_dir_inode_header_3 {
10531- SQUASHFS_BASE_INODE_HEADER_3;
10532+ unsigned int inode_type:4;
10533+ unsigned int mode:12;
10534+ unsigned int uid:8;
10535+ unsigned int guid:8;
10536+ int mtime;
10537+ unsigned int inode_number;
10538 unsigned int nlink;
10539 unsigned int file_size:19;
10540 unsigned int offset:13;
10541@@ -130,7 +157,12 @@
10542 } __attribute__ ((packed));
10543
10544 struct squashfs_ldir_inode_header_3 {
10545- SQUASHFS_BASE_INODE_HEADER_3;
10546+ unsigned int inode_type:4;
10547+ unsigned int mode:12;
10548+ unsigned int uid:8;
10549+ unsigned int guid:8;
10550+ int mtime;
10551+ unsigned int inode_number;
10552 unsigned int nlink;
10553 unsigned int file_size:27;
10554 unsigned int offset:13;
10555@@ -449,7 +481,7 @@
10556 unsigned int mode:12; /* protection */
10557 unsigned int uid:4; /* index into uid table */
10558 unsigned int guid:4; /* index into guid table */
10559- unsigned int mtime;
10560+ int mtime;
10561 unsigned int start_block;
10562 unsigned int file_size:32;
10563 unsigned short block_list[0];
10564@@ -462,7 +494,7 @@
10565 unsigned int guid:4; /* index into guid table */
10566 unsigned int file_size:19;
10567 unsigned int offset:13;
10568- unsigned int mtime;
10569+ int mtime;
10570 unsigned int start_block:24;
10571 } __attribute__ ((packed));
10572
10573@@ -582,7 +614,7 @@
10574 unsigned int mode:12; /* protection */
10575 unsigned int uid:8; /* index into uid table */
10576 unsigned int guid:8; /* index into guid table */
10577- unsigned int mtime;
10578+ int mtime;
10579 unsigned int start_block;
10580 unsigned int fragment;
10581 unsigned int offset;
10582@@ -597,7 +629,7 @@
10583 unsigned int guid:8; /* index into guid table */
10584 unsigned int file_size:19;
10585 unsigned int offset:13;
10586- unsigned int mtime;
10587+ int mtime;
10588 unsigned int start_block:24;
10589 } __attribute__ ((packed));
10590
10591@@ -608,7 +640,7 @@
10592 unsigned int guid:8; /* index into guid table */
10593 unsigned int file_size:27;
10594 unsigned int offset:13;
10595- unsigned int mtime;
10596+ int mtime;
10597 unsigned int start_block:24;
10598 unsigned int i_count:16;
10599 struct squashfs_dir_index_2 index[0];
10600diff -Nru squashfs-tools-4.2+20130409/squashfs_fs.h squashfs-tools-4.3+20140919/squashfs_fs.h
10601--- squashfs-tools-4.2+20130409/squashfs_fs.h 2013-05-09 10:39:11.000000000 +0200
10602+++ squashfs-tools-4.3+20140919/squashfs_fs.h 2015-07-20 21:03:05.000000000 +0200
10603@@ -4,7 +4,7 @@
10604 * Squashfs
10605 *
10606 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
10607- * 2013
10608+ * 2013, 2014
10609 * Phillip Lougher <phillip@squashfs.org.uk>
10610 *
10611 * This program is free software; you can redistribute it and/or
10612@@ -276,11 +276,12 @@
10613 #define LZMA_COMPRESSION 2
10614 #define LZO_COMPRESSION 3
10615 #define XZ_COMPRESSION 4
10616+#define LZ4_COMPRESSION 5
10617
10618 struct squashfs_super_block {
10619 unsigned int s_magic;
10620 unsigned int inodes;
10621- unsigned int mkfs_time /* time of filesystem creation */;
10622+ int mkfs_time /* time of filesystem creation */;
10623 unsigned int block_size;
10624 unsigned int fragments;
10625 unsigned short compression;
10626@@ -311,7 +312,7 @@
10627 unsigned short mode;
10628 unsigned short uid;
10629 unsigned short guid;
10630- unsigned int mtime;
10631+ int mtime;
10632 unsigned int inode_number;
10633 };
10634
10635@@ -320,7 +321,7 @@
10636 unsigned short mode;
10637 unsigned short uid;
10638 unsigned short guid;
10639- unsigned int mtime;
10640+ int mtime;
10641 unsigned int inode_number;
10642 unsigned int nlink;
10643 };
10644@@ -330,7 +331,7 @@
10645 unsigned short mode;
10646 unsigned short uid;
10647 unsigned short guid;
10648- unsigned int mtime;
10649+ int mtime;
10650 unsigned int inode_number;
10651 unsigned int nlink;
10652 unsigned int xattr;
10653@@ -341,7 +342,7 @@
10654 unsigned short mode;
10655 unsigned short uid;
10656 unsigned short guid;
10657- unsigned int mtime;
10658+ int mtime;
10659 unsigned int inode_number;
10660 unsigned int nlink;
10661 unsigned int rdev;
10662@@ -352,7 +353,7 @@
10663 unsigned short mode;
10664 unsigned short uid;
10665 unsigned short guid;
10666- unsigned int mtime;
10667+ int mtime;
10668 unsigned int inode_number;
10669 unsigned int nlink;
10670 unsigned int rdev;
10671@@ -364,7 +365,7 @@
10672 unsigned short mode;
10673 unsigned short uid;
10674 unsigned short guid;
10675- unsigned int mtime;
10676+ int mtime;
10677 unsigned int inode_number;
10678 unsigned int nlink;
10679 unsigned int symlink_size;
10680@@ -376,7 +377,7 @@
10681 unsigned short mode;
10682 unsigned short uid;
10683 unsigned short guid;
10684- unsigned int mtime;
10685+ int mtime;
10686 unsigned int inode_number;
10687 unsigned int start_block;
10688 unsigned int fragment;
10689@@ -390,7 +391,7 @@
10690 unsigned short mode;
10691 unsigned short uid;
10692 unsigned short guid;
10693- unsigned int mtime;
10694+ int mtime;
10695 unsigned int inode_number;
10696 squashfs_block start_block;
10697 long long file_size;
10698@@ -407,7 +408,7 @@
10699 unsigned short mode;
10700 unsigned short uid;
10701 unsigned short guid;
10702- unsigned int mtime;
10703+ int mtime;
10704 unsigned int inode_number;
10705 unsigned int start_block;
10706 unsigned int nlink;
10707@@ -421,7 +422,7 @@
10708 unsigned short mode;
10709 unsigned short uid;
10710 unsigned short guid;
10711- unsigned int mtime;
10712+ int mtime;
10713 unsigned int inode_number;
10714 unsigned int nlink;
10715 unsigned int file_size;
10716diff -Nru squashfs-tools-4.2+20130409/squashfs_swap.h squashfs-tools-4.3+20140919/squashfs_swap.h
10717--- squashfs-tools-4.2+20130409/squashfs_swap.h 2013-05-09 10:39:11.000000000 +0200
10718+++ squashfs-tools-4.3+20140919/squashfs_swap.h 2015-07-20 21:03:05.000000000 +0200
10719@@ -3,7 +3,7 @@
10720 /*
10721 * Squashfs
10722 *
10723- * Copyright (c) 2008, 2009, 2010
10724+ * Copyright (c) 2008, 2009, 2010, 2013, 2014
10725 * Phillip Lougher <phillip@squashfs.org.uk>
10726 *
10727 * This program is free software; you can redistribute it and/or
10728@@ -45,7 +45,7 @@
10729 #define _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_FUNC) {\
10730 SWAP_FUNC(32, s, d, s_magic, struct squashfs_super_block);\
10731 SWAP_FUNC(32, s, d, inodes, struct squashfs_super_block);\
10732- SWAP_FUNC(32, s, d, mkfs_time, struct squashfs_super_block);\
10733+ SWAP_FUNC##S(32, s, d, mkfs_time, struct squashfs_super_block);\
10734 SWAP_FUNC(32, s, d, block_size, struct squashfs_super_block);\
10735 SWAP_FUNC(32, s, d, fragments, struct squashfs_super_block);\
10736 SWAP_FUNC(16, s, d, compression, struct squashfs_super_block);\
10737@@ -75,7 +75,7 @@
10738 SWAP_FUNC(16, s, d, mode, struct squashfs_base_inode_header);\
10739 SWAP_FUNC(16, s, d, uid, struct squashfs_base_inode_header);\
10740 SWAP_FUNC(16, s, d, guid, struct squashfs_base_inode_header);\
10741- SWAP_FUNC(32, s, d, mtime, struct squashfs_base_inode_header);\
10742+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_base_inode_header);\
10743 SWAP_FUNC(32, s, d, inode_number, struct squashfs_base_inode_header);\
10744 }
10745
10746@@ -84,7 +84,7 @@
10747 SWAP_FUNC(16, s, d, mode, struct squashfs_ipc_inode_header);\
10748 SWAP_FUNC(16, s, d, uid, struct squashfs_ipc_inode_header);\
10749 SWAP_FUNC(16, s, d, guid, struct squashfs_ipc_inode_header);\
10750- SWAP_FUNC(32, s, d, mtime, struct squashfs_ipc_inode_header);\
10751+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ipc_inode_header);\
10752 SWAP_FUNC(32, s, d, inode_number, struct squashfs_ipc_inode_header);\
10753 SWAP_FUNC(32, s, d, nlink, struct squashfs_ipc_inode_header);\
10754 }
10755@@ -94,7 +94,7 @@
10756 SWAP_FUNC(16, s, d, mode, struct squashfs_lipc_inode_header);\
10757 SWAP_FUNC(16, s, d, uid, struct squashfs_lipc_inode_header);\
10758 SWAP_FUNC(16, s, d, guid, struct squashfs_lipc_inode_header);\
10759- SWAP_FUNC(32, s, d, mtime, struct squashfs_lipc_inode_header);\
10760+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lipc_inode_header);\
10761 SWAP_FUNC(32, s, d, inode_number, struct squashfs_lipc_inode_header);\
10762 SWAP_FUNC(32, s, d, nlink, struct squashfs_lipc_inode_header);\
10763 SWAP_FUNC(32, s, d, xattr, struct squashfs_lipc_inode_header);\
10764@@ -105,7 +105,7 @@
10765 SWAP_FUNC(16, s, d, mode, struct squashfs_dev_inode_header);\
10766 SWAP_FUNC(16, s, d, uid, struct squashfs_dev_inode_header);\
10767 SWAP_FUNC(16, s, d, guid, struct squashfs_dev_inode_header);\
10768- SWAP_FUNC(32, s, d, mtime, struct squashfs_dev_inode_header);\
10769+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dev_inode_header);\
10770 SWAP_FUNC(32, s, d, inode_number, struct squashfs_dev_inode_header);\
10771 SWAP_FUNC(32, s, d, nlink, struct squashfs_dev_inode_header);\
10772 SWAP_FUNC(32, s, d, rdev, struct squashfs_dev_inode_header);\
10773@@ -116,7 +116,7 @@
10774 SWAP_FUNC(16, s, d, mode, struct squashfs_ldev_inode_header);\
10775 SWAP_FUNC(16, s, d, uid, struct squashfs_ldev_inode_header);\
10776 SWAP_FUNC(16, s, d, guid, struct squashfs_ldev_inode_header);\
10777- SWAP_FUNC(32, s, d, mtime, struct squashfs_ldev_inode_header);\
10778+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldev_inode_header);\
10779 SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldev_inode_header);\
10780 SWAP_FUNC(32, s, d, nlink, struct squashfs_ldev_inode_header);\
10781 SWAP_FUNC(32, s, d, rdev, struct squashfs_ldev_inode_header);\
10782@@ -128,7 +128,7 @@
10783 SWAP_FUNC(16, s, d, mode, struct squashfs_symlink_inode_header);\
10784 SWAP_FUNC(16, s, d, uid, struct squashfs_symlink_inode_header);\
10785 SWAP_FUNC(16, s, d, guid, struct squashfs_symlink_inode_header);\
10786- SWAP_FUNC(32, s, d, mtime, struct squashfs_symlink_inode_header);\
10787+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_symlink_inode_header);\
10788 SWAP_FUNC(32, s, d, inode_number, struct squashfs_symlink_inode_header);\
10789 SWAP_FUNC(32, s, d, nlink, struct squashfs_symlink_inode_header);\
10790 SWAP_FUNC(32, s, d, symlink_size, struct squashfs_symlink_inode_header);\
10791@@ -139,7 +139,7 @@
10792 SWAP_FUNC(16, s, d, mode, struct squashfs_reg_inode_header);\
10793 SWAP_FUNC(16, s, d, uid, struct squashfs_reg_inode_header);\
10794 SWAP_FUNC(16, s, d, guid, struct squashfs_reg_inode_header);\
10795- SWAP_FUNC(32, s, d, mtime, struct squashfs_reg_inode_header);\
10796+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_reg_inode_header);\
10797 SWAP_FUNC(32, s, d, inode_number, struct squashfs_reg_inode_header);\
10798 SWAP_FUNC(32, s, d, start_block, struct squashfs_reg_inode_header);\
10799 SWAP_FUNC(32, s, d, fragment, struct squashfs_reg_inode_header);\
10800@@ -152,7 +152,7 @@
10801 SWAP_FUNC(16, s, d, mode, struct squashfs_lreg_inode_header);\
10802 SWAP_FUNC(16, s, d, uid, struct squashfs_lreg_inode_header);\
10803 SWAP_FUNC(16, s, d, guid, struct squashfs_lreg_inode_header);\
10804- SWAP_FUNC(32, s, d, mtime, struct squashfs_lreg_inode_header);\
10805+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lreg_inode_header);\
10806 SWAP_FUNC(32, s, d, inode_number, struct squashfs_lreg_inode_header);\
10807 SWAP_FUNC(64, s, d, start_block, struct squashfs_lreg_inode_header);\
10808 SWAP_FUNC(64, s, d, file_size, struct squashfs_lreg_inode_header);\
10809@@ -168,7 +168,7 @@
10810 SWAP_FUNC(16, s, d, mode, struct squashfs_dir_inode_header);\
10811 SWAP_FUNC(16, s, d, uid, struct squashfs_dir_inode_header);\
10812 SWAP_FUNC(16, s, d, guid, struct squashfs_dir_inode_header);\
10813- SWAP_FUNC(32, s, d, mtime, struct squashfs_dir_inode_header);\
10814+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dir_inode_header);\
10815 SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_inode_header);\
10816 SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_inode_header);\
10817 SWAP_FUNC(32, s, d, nlink, struct squashfs_dir_inode_header);\
10818@@ -182,7 +182,7 @@
10819 SWAP_FUNC(16, s, d, mode, struct squashfs_ldir_inode_header);\
10820 SWAP_FUNC(16, s, d, uid, struct squashfs_ldir_inode_header);\
10821 SWAP_FUNC(16, s, d, guid, struct squashfs_ldir_inode_header);\
10822- SWAP_FUNC(32, s, d, mtime, struct squashfs_ldir_inode_header);\
10823+ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldir_inode_header);\
10824 SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldir_inode_header);\
10825 SWAP_FUNC(32, s, d, nlink, struct squashfs_ldir_inode_header);\
10826 SWAP_FUNC(32, s, d, file_size, struct squashfs_ldir_inode_header);\
10827@@ -281,6 +281,14 @@
10828 #define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10829 #define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10830
10831+#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
10832+#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
10833+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
10834+
10835+#define SWAP_LE16(s, d) swap_le16(s, d)
10836+#define SWAP_LE32(s, d) swap_le32(s, d)
10837+#define SWAP_LE64(s, d) swap_le64(s, d)
10838+
10839 /* big endian architecture swap in-place macros */
10840 #define SQUASHFS_INSWAP_SUPER_BLOCK(s) \
10841 _SQUASHFS_SWAP_SUPER_BLOCK(s, s, INSWAP_LE)
10842@@ -323,8 +331,9 @@
10843 #define INSWAP_LE(bits, s, d, field, type) \
10844 (s)->field = inswap_le##bits((s)->field)
10845 #define INSWAP_LES(bits, s, d, field, type) \
10846- (s)->field = (short) inswap_le##bits((unsigned short) \
10847- (s)->field)
10848+ (s)->field = INSWAP_LES##bits((s)->field)
10849+#define INSWAP_LES16(num) (short) inswap_le16((unsigned short) (num))
10850+#define INSWAP_LES32(num) (int) inswap_le32((unsigned int) (num))
10851 #define SQUASHFS_INSWAP_INODE_T(s) s = inswap_le64(s)
10852 #define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) inswap_le64_num(s, n)
10853 #define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) inswap_le64_num(s, n)
10854@@ -335,49 +344,55 @@
10855 #else
10856 /* little endian architecture, just copy */
10857 #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
10858- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10859+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_super_block))
10860 #define SQUASHFS_SWAP_DIR_INDEX(s, d) \
10861- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10862+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_index))
10863 #define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
10864- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10865+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_base_inode_header))
10866 #define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
10867- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10868+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ipc_inode_header))
10869 #define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
10870- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10871+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lipc_inode_header))
10872 #define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
10873- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10874+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dev_inode_header))
10875 #define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
10876- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10877+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldev_inode_header))
10878 #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
10879- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10880+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_symlink_inode_header))
10881 #define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
10882- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10883+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_reg_inode_header))
10884 #define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
10885- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10886+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lreg_inode_header))
10887 #define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
10888- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10889+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_inode_header))
10890 #define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
10891- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10892+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldir_inode_header))
10893 #define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
10894- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10895+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_entry))
10896 #define SQUASHFS_SWAP_DIR_HEADER(s, d) \
10897- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10898+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_header))
10899 #define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
10900- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10901+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_fragment_entry))
10902 #define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
10903- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10904+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_entry))
10905 #define SQUASHFS_SWAP_XATTR_VAL(s, d) \
10906- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10907+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_val))
10908 #define SQUASHFS_SWAP_XATTR_ID(s, d) \
10909- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10910+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_id))
10911 #define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
10912- SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
10913+ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_table))
10914 #define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
10915 #define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
10916 SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10917 #define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10918 #define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10919
10920+#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
10921+#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
10922+#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
10923+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
10924+ memcpy(d, s, n * sizeof(long long))
10925+
10926 /* little endian architecture, data already in place so do nothing */
10927 #define SQUASHFS_INSWAP_SUPER_BLOCK(s)
10928 #define SQUASHFS_INSWAP_DIR_INDEX(s)
10929diff -Nru squashfs-tools-4.2+20130409/unsquash-4.c squashfs-tools-4.3+20140919/unsquash-4.c
10930--- squashfs-tools-4.2+20130409/unsquash-4.c 2013-05-09 10:39:11.000000000 +0200
10931+++ squashfs-tools-4.3+20140919/unsquash-4.c 2015-07-20 21:03:05.000000000 +0200
10932@@ -24,7 +24,6 @@
10933
10934 #include "unsquashfs.h"
10935 #include "squashfs_swap.h"
10936-#include "read_fs.h"
10937
10938 static struct squashfs_fragment_entry *fragment_table;
10939 static unsigned int *id_table;
10940@@ -109,7 +108,7 @@
10941 EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
10942 start);
10943
10944- SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, block_ptr);
10945+ SQUASHFS_SWAP_BASE_INODE_HEADER(block_ptr, &header.base);
10946
10947 i.uid = (uid_t) id_table[header.base.uid];
10948 i.gid = (uid_t) id_table[header.base.guid];
10949@@ -122,7 +121,7 @@
10950 case SQUASHFS_DIR_TYPE: {
10951 struct squashfs_dir_inode_header *inode = &header.dir;
10952
10953- SQUASHFS_SWAP_DIR_INODE_HEADER(inode, block_ptr);
10954+ SQUASHFS_SWAP_DIR_INODE_HEADER(block_ptr, inode);
10955
10956 i.data = inode->file_size;
10957 i.offset = inode->offset;
10958@@ -133,7 +132,7 @@
10959 case SQUASHFS_LDIR_TYPE: {
10960 struct squashfs_ldir_inode_header *inode = &header.ldir;
10961
10962- SQUASHFS_SWAP_LDIR_INODE_HEADER(inode, block_ptr);
10963+ SQUASHFS_SWAP_LDIR_INODE_HEADER(block_ptr, inode);
10964
10965 i.data = inode->file_size;
10966 i.offset = inode->offset;
10967@@ -144,7 +143,7 @@
10968 case SQUASHFS_FILE_TYPE: {
10969 struct squashfs_reg_inode_header *inode = &header.reg;
10970
10971- SQUASHFS_SWAP_REG_INODE_HEADER(inode, block_ptr);
10972+ SQUASHFS_SWAP_REG_INODE_HEADER(block_ptr, inode);
10973
10974 i.data = inode->file_size;
10975 i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
10976@@ -164,7 +163,7 @@
10977 case SQUASHFS_LREG_TYPE: {
10978 struct squashfs_lreg_inode_header *inode = &header.lreg;
10979
10980- SQUASHFS_SWAP_LREG_INODE_HEADER(inode, block_ptr);
10981+ SQUASHFS_SWAP_LREG_INODE_HEADER(block_ptr, inode);
10982
10983 i.data = inode->file_size;
10984 i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
10985@@ -185,7 +184,7 @@
10986 case SQUASHFS_LSYMLINK_TYPE: {
10987 struct squashfs_symlink_inode_header *inode = &header.symlink;
10988
10989- SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inode, block_ptr);
10990+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(block_ptr, inode);
10991
10992 i.symlink = malloc(inode->symlink_size + 1);
10993 if(i.symlink == NULL)
10994@@ -198,9 +197,9 @@
10995 i.data = inode->symlink_size;
10996
10997 if(header.base.inode_type == SQUASHFS_LSYMLINK_TYPE)
10998- SQUASHFS_SWAP_INTS(&i.xattr, block_ptr +
10999+ SQUASHFS_SWAP_INTS(block_ptr +
11000 sizeof(struct squashfs_symlink_inode_header) +
11001- inode->symlink_size, 1);
11002+ inode->symlink_size, &i.xattr, 1);
11003 else
11004 i.xattr = SQUASHFS_INVALID_XATTR;
11005 break;
11006@@ -209,7 +208,7 @@
11007 case SQUASHFS_CHRDEV_TYPE: {
11008 struct squashfs_dev_inode_header *inode = &header.dev;
11009
11010- SQUASHFS_SWAP_DEV_INODE_HEADER(inode, block_ptr);
11011+ SQUASHFS_SWAP_DEV_INODE_HEADER(block_ptr, inode);
11012
11013 i.data = inode->rdev;
11014 i.xattr = SQUASHFS_INVALID_XATTR;
11015@@ -219,7 +218,7 @@
11016 case SQUASHFS_LCHRDEV_TYPE: {
11017 struct squashfs_ldev_inode_header *inode = &header.ldev;
11018
11019- SQUASHFS_SWAP_LDEV_INODE_HEADER(inode, block_ptr);
11020+ SQUASHFS_SWAP_LDEV_INODE_HEADER(block_ptr, inode);
11021
11022 i.data = inode->rdev;
11023 i.xattr = inode->xattr;
11024@@ -234,7 +233,7 @@
11025 case SQUASHFS_LSOCKET_TYPE: {
11026 struct squashfs_lipc_inode_header *inode = &header.lipc;
11027
11028- SQUASHFS_SWAP_LIPC_INODE_HEADER(inode, block_ptr);
11029+ SQUASHFS_SWAP_LIPC_INODE_HEADER(block_ptr, inode);
11030
11031 i.data = 0;
11032 i.xattr = inode->xattr;
11033@@ -299,7 +298,7 @@
11034 size = (*i)->data + bytes - 3;
11035
11036 while(bytes < size) {
11037- SQUASHFS_SWAP_DIR_HEADER(&dirh, directory_table + bytes);
11038+ SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
11039
11040 dir_count = dirh.count + 1;
11041 TRACE("squashfs_opendir: Read directory header @ byte position "
11042@@ -311,7 +310,7 @@
11043 goto corrupted;
11044
11045 while(dir_count--) {
11046- SQUASHFS_SWAP_DIR_ENTRY(dire, directory_table + bytes);
11047+ SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
11048
11049 bytes += sizeof(*dire);
11050
11051diff -Nru squashfs-tools-4.2+20130409/unsquashfs.c squashfs-tools-4.3+20140919/unsquashfs.c
11052--- squashfs-tools-4.2+20130409/unsquashfs.c 2013-05-09 10:39:11.000000000 +0200
11053+++ squashfs-tools-4.3+20140919/unsquashfs.c 2015-07-20 21:03:05.000000000 +0200
11054@@ -3,7 +3,7 @@
11055 * filesystem.
11056 *
11057 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
11058- * 2012, 2013
11059+ * 2012, 2013, 2014
11060 * Phillip Lougher <phillip@squashfs.org.uk>
11061 *
11062 * This program is free software; you can redistribute it and/or
11063@@ -26,9 +26,9 @@
11064 #include "unsquashfs.h"
11065 #include "squashfs_swap.h"
11066 #include "squashfs_compat.h"
11067-#include "read_fs.h"
11068 #include "compressor.h"
11069 #include "xattr.h"
11070+#include "unsquashfs_info.h"
11071 #include "stdarg.h"
11072
11073 #include <sys/sysinfo.h>
11074@@ -39,8 +39,8 @@
11075 #include <ctype.h>
11076
11077 struct cache *fragment_cache, *data_cache;
11078-struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
11079-pthread_t *thread, *deflator_thread;
11080+struct queue *to_reader, *to_inflate, *to_writer, *from_writer;
11081+pthread_t *thread, *inflator_thread;
11082 pthread_mutex_t fragment_mutex;
11083
11084 /* user options that control parallelisation */
11085@@ -69,7 +69,6 @@
11086 int columns;
11087 int rotate = 0;
11088 pthread_mutex_t screen_mutex;
11089-pthread_cond_t progress_wait;
11090 int progress = TRUE, progress_enabled = FALSE;
11091 unsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
11092 unsigned int cur_blocks = 0;
11093@@ -121,7 +120,6 @@
11094 };
11095
11096 void progress_bar(long long current, long long max, int columns);
11097-void update_progress_bar();
11098
11099 #define MAX_LINE 16384
11100
11101@@ -226,6 +224,21 @@
11102 }
11103
11104
11105+void dump_queue(struct queue *queue)
11106+{
11107+ pthread_mutex_lock(&queue->mutex);
11108+
11109+ printf("Max size %d, size %d%s\n", queue->size - 1,
11110+ queue->readp <= queue->writep ? queue->writep - queue->readp :
11111+ queue->size - queue->readp + queue->writep,
11112+ queue->readp == queue->writep ? " (EMPTY)" :
11113+ ((queue->writep + 1) % queue->size) == queue->readp ?
11114+ " (FULL)" : "");
11115+
11116+ pthread_mutex_unlock(&queue->mutex);
11117+}
11118+
11119+
11120 /* Called with the cache mutex held */
11121 void insert_hash_table(struct cache *cache, struct cache_entry *entry)
11122 {
11123@@ -272,7 +285,7 @@
11124 /* Called with the cache mutex held */
11125 void remove_free_list(struct cache *cache, struct cache_entry *entry)
11126 {
11127- if(entry->free_prev == NULL && entry->free_next == NULL)
11128+ if(entry->free_prev == NULL || entry->free_next == NULL)
11129 /* not in free list */
11130 return;
11131 else if(entry->free_prev == entry && entry->free_next == entry) {
11132@@ -300,6 +313,7 @@
11133 cache->max_buffers = max_buffers;
11134 cache->buffer_size = buffer_size;
11135 cache->count = 0;
11136+ cache->used = 0;
11137 cache->free_list = NULL;
11138 memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
11139 cache->wait_free = FALSE;
11140@@ -316,7 +330,7 @@
11141 {
11142 /*
11143 * Get a block out of the cache. If the block isn't in the cache
11144- * it is added and queued to the reader() and deflate() threads for
11145+ * it is added and queued to the reader() and inflate() threads for
11146 * reading off disk and decompression. The cache grows until max_blocks
11147 * is reached, once this occurs existing discarded blocks on the free
11148 * list are reused
11149@@ -332,11 +346,14 @@
11150
11151 if(entry) {
11152 /*
11153- * found the block in the cache, increment used count and
11154- * if necessary remove from free list so it won't disappear
11155+ * found the block in the cache. If the block is currently unused
11156+ * remove it from the free list and increment cache used count.
11157 */
11158+ if(entry->used == 0) {
11159+ cache->used ++;
11160+ remove_free_list(cache, entry);
11161+ }
11162 entry->used ++;
11163- remove_free_list(cache, entry);
11164 pthread_mutex_unlock(&cache->mutex);
11165 } else {
11166 /*
11167@@ -369,7 +386,11 @@
11168 }
11169
11170 /*
11171- * initialise block and insert into the hash table
11172+ * Initialise block and insert into the hash table.
11173+ * Increment used which tracks how many buffers in the
11174+ * cache are actively in use (the other blocks, count - used,
11175+ * are in the cache and available for lookup, but can also be
11176+ * re-used).
11177 */
11178 entry->block = block;
11179 entry->size = size;
11180@@ -377,6 +398,7 @@
11181 entry->error = FALSE;
11182 entry->pending = TRUE;
11183 insert_hash_table(cache, entry);
11184+ cache->used ++;
11185
11186 /*
11187 * queue to read thread to read and ultimately (via the
11188@@ -446,6 +468,7 @@
11189 entry->used --;
11190 if(entry->used == 0) {
11191 insert_free_list(entry->cache, entry);
11192+ entry->cache->used --;
11193
11194 /*
11195 * if the wait_free flag is set, one or more threads may be
11196@@ -461,6 +484,18 @@
11197 }
11198
11199
11200+void dump_cache(struct cache *cache)
11201+{
11202+ pthread_mutex_lock(&cache->mutex);
11203+
11204+ printf("Max buffers %d, Current size %d, Used %d, %s\n",
11205+ cache->max_buffers, cache->count, cache->used,
11206+ cache->free_list ? "Free buffers" : "No free buffers");
11207+
11208+ pthread_mutex_unlock(&cache->mutex);
11209+}
11210+
11211+
11212 char *modestr(char *str, int mode)
11213 {
11214 int i;
11215@@ -1223,11 +1258,14 @@
11216 target ++;
11217
11218 start = target;
11219- while(*target != '/' && *target!= '\0')
11220+ while(*target != '/' && *target != '\0')
11221 target ++;
11222
11223 *targname = strndup(start, target - start);
11224
11225+ while(*target == '/')
11226+ target ++;
11227+
11228 return target;
11229 }
11230
11231@@ -1554,26 +1592,27 @@
11232 if(res == -1)
11233 EXIT_UNSQUASH("asprintf failed in dir_scan\n");
11234
11235- if(type == SQUASHFS_DIR_TYPE)
11236+ if(type == SQUASHFS_DIR_TYPE) {
11237 dir_scan(pathname, start_block, offset, new);
11238- else if(new == NULL) {
11239+ free(pathname);
11240+ } else if(new == NULL) {
11241+ update_info(pathname);
11242+
11243 i = s_ops.read_inode(start_block, offset);
11244
11245 if(lsonly || info)
11246 print_filename(pathname, i);
11247
11248- if(!lsonly) {
11249+ if(!lsonly)
11250 create_inode(pathname, i);
11251- update_progress_bar();
11252- }
11253
11254 if(i->type == SQUASHFS_SYMLINK_TYPE ||
11255 i->type == SQUASHFS_LSYMLINK_TYPE)
11256 free(i->symlink);
11257- }
11258+ } else
11259+ free(pathname);
11260
11261 free_subdir(new);
11262- free(pathname);
11263 }
11264
11265 if(!lsonly)
11266@@ -1609,7 +1648,7 @@
11267 printf("Compression %s\n", comp->name);
11268
11269 if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
11270- char buffer[SQUASHFS_METADATA_SIZE];
11271+ char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
11272 int bytes;
11273
11274 bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
11275@@ -1637,7 +1676,7 @@
11276 printf("Fragments are %scompressed\n",
11277 SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
11278 "un" : "");
11279- printf("Always_use_fragments option is %sspecified\n",
11280+ printf("Always-use-fragments option is %sspecified\n",
11281 SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
11282 "not ");
11283 }
11284@@ -1698,6 +1737,42 @@
11285 }
11286
11287
11288+int check_compression(struct compressor *comp)
11289+{
11290+ int res, bytes = 0;
11291+ char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
11292+
11293+ if(!comp->supported) {
11294+ ERROR("Filesystem uses %s compression, this is "
11295+ "unsupported by this version\n", comp->name);
11296+ ERROR("Decompressors available:\n");
11297+ display_compressors("", "");
11298+ return 0;
11299+ }
11300+
11301+ /*
11302+ * Read compression options from disk if present, and pass to
11303+ * the compressor to ensure we know how to decompress a filesystem
11304+ * compressed with these compression options.
11305+ *
11306+ * Note, even if there is no compression options we still call the
11307+ * compressor because some compression options may be mandatory
11308+ * for some compressors.
11309+ */
11310+ if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
11311+ bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
11312+ if(bytes == 0) {
11313+ ERROR("Failed to read compressor options\n");
11314+ return 0;
11315+ }
11316+ }
11317+
11318+ res = compressor_check_options(comp, sBlk.s.block_size, buffer, bytes);
11319+
11320+ return res != -1;
11321+}
11322+
11323+
11324 int read_super(char *source)
11325 {
11326 squashfs_super_block_3 sBlk_3;
11327@@ -1897,10 +1972,10 @@
11328
11329 if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
11330 /*
11331- * queue successfully read block to the deflate
11332+ * queue successfully read block to the inflate
11333 * thread(s) for further processing
11334 */
11335- queue_put(to_deflate, entry);
11336+ queue_put(to_inflate, entry);
11337 else
11338 /*
11339 * block has either been successfully read and is
11340@@ -2019,12 +2094,12 @@
11341 /*
11342 * decompress thread. This decompresses buffers queued by the read thread
11343 */
11344-void *deflator(void *arg)
11345+void *inflator(void *arg)
11346 {
11347 char tmp[block_size];
11348
11349 while(1) {
11350- struct cache_entry *entry = queue_get(to_deflate);
11351+ struct cache_entry *entry = queue_get(to_inflate);
11352 int error, res;
11353
11354 res = compressor_uncompress(comp, tmp, entry->data,
11355@@ -2049,8 +2124,7 @@
11356
11357 void *progress_thread(void *arg)
11358 {
11359- struct timeval timeval;
11360- struct timespec timespec;
11361+ struct timespec requested_time, remaining;
11362 struct itimerval itimerval;
11363 struct winsize winsize;
11364
11365@@ -2070,22 +2144,22 @@
11366 itimerval.it_interval.tv_usec = 250000;
11367 setitimer(ITIMER_REAL, &itimerval, NULL);
11368
11369- pthread_cond_init(&progress_wait, NULL);
11370+ requested_time.tv_sec = 0;
11371+ requested_time.tv_nsec = 250000000;
11372
11373- pthread_mutex_lock(&screen_mutex);
11374 while(1) {
11375- gettimeofday(&timeval, NULL);
11376- timespec.tv_sec = timeval.tv_sec;
11377- if(timeval.tv_usec + 250000 > 999999)
11378- timespec.tv_sec++;
11379- timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
11380- 1000;
11381- pthread_cond_timedwait(&progress_wait, &screen_mutex,
11382- ×pec);
11383- if(progress_enabled)
11384+ int res = nanosleep(&requested_time, &remaining);
11385+
11386+ if(res == -1 && errno != EINTR)
11387+ EXIT_UNSQUASH("nanosleep failed in progress thread\n");
11388+
11389+ if(progress_enabled) {
11390+ pthread_mutex_lock(&screen_mutex);
11391 progress_bar(sym_count + dev_count +
11392 fifo_count + cur_blocks, total_inodes -
11393 total_files + total_blocks, columns);
11394+ pthread_mutex_unlock(&screen_mutex);
11395+ }
11396 }
11397 }
11398
11399@@ -2096,11 +2170,23 @@
11400 int i, max_files, res;
11401 sigset_t sigmask, old_mask;
11402
11403+ /* block SIGQUIT and SIGHUP, these are handled by the info thread */
11404 sigemptyset(&sigmask);
11405- sigaddset(&sigmask, SIGINT);
11406 sigaddset(&sigmask, SIGQUIT);
11407- if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
11408- EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
11409+ sigaddset(&sigmask, SIGHUP);
11410+ if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
11411+ EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
11412+ "\n");
11413+
11414+ /*
11415+ * temporarily block these signals so the created sub-threads will
11416+ * ignore them, ensuring the main thread handles them
11417+ */
11418+ sigemptyset(&sigmask);
11419+ sigaddset(&sigmask, SIGINT);
11420+ sigaddset(&sigmask, SIGTERM);
11421+ if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
11422+ EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
11423 "\n");
11424
11425 if(processors == -1) {
11426@@ -2132,14 +2218,14 @@
11427 thread = malloc((3 + processors) * sizeof(pthread_t));
11428 if(thread == NULL)
11429 EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
11430- deflator_thread = &thread[3];
11431+ inflator_thread = &thread[3];
11432
11433 /*
11434- * dimensioning the to_reader and to_deflate queues. The size of
11435+ * dimensioning the to_reader and to_inflate queues. The size of
11436 * these queues is directly related to the amount of block
11437 * read-ahead possible. To_reader queues block read requests to
11438- * the reader thread and to_deflate queues block decompression
11439- * requests to the deflate thread(s) (once the block has been read by
11440+ * the reader thread and to_inflate queues block decompression
11441+ * requests to the inflate thread(s) (once the block has been read by
11442 * the reader thread). The amount of read-ahead is determined by
11443 * the combined size of the data_block and fragment caches which
11444 * determine the total number of blocks which can be "in flight"
11445@@ -2162,7 +2248,7 @@
11446 *
11447 * dimensioning the to_writer queue. The size of this queue is
11448 * directly related to the amount of block read-ahead possible.
11449- * However, unlike the to_reader and to_deflate queues, this is
11450+ * However, unlike the to_reader and to_inflate queues, this is
11451 * complicated by the fact the to_writer queue not only contains
11452 * entries for fragments and data_blocks but it also contains
11453 * file entries, one per open file in the read-ahead.
11454@@ -2196,7 +2282,7 @@
11455 open_init(max_files);
11456
11457 /*
11458- * allocate to_reader, to_deflate and to_writer queues. Set based on
11459+ * allocate to_reader, to_inflate and to_writer queues. Set based on
11460 * open file limit and cache size, unless open file limit is unlimited,
11461 * in which case set purely based on cache limits
11462 *
11463@@ -2209,7 +2295,7 @@
11464 EXIT_UNSQUASH("Data queue size is too large\n");
11465
11466 to_reader = queue_init(max_files + data_buffer_size);
11467- to_deflate = queue_init(max_files + data_buffer_size);
11468+ to_inflate = queue_init(max_files + data_buffer_size);
11469 to_writer = queue_init(max_files * 2 + data_buffer_size);
11470 } else {
11471 int all_buffers_size;
11472@@ -2225,7 +2311,7 @@
11473 " too large\n");
11474
11475 to_reader = queue_init(all_buffers_size);
11476- to_deflate = queue_init(all_buffers_size);
11477+ to_inflate = queue_init(all_buffers_size);
11478 to_writer = queue_init(all_buffers_size * 2);
11479 }
11480
11481@@ -2236,10 +2322,11 @@
11482 pthread_create(&thread[0], NULL, reader, NULL);
11483 pthread_create(&thread[1], NULL, writer, NULL);
11484 pthread_create(&thread[2], NULL, progress_thread, NULL);
11485+ init_info();
11486 pthread_mutex_init(&fragment_mutex, NULL);
11487
11488 for(i = 0; i < processors; i++) {
11489- if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
11490+ if(pthread_create(&inflator_thread[i], NULL, inflator, NULL) !=
11491 0)
11492 EXIT_UNSQUASH("Failed to create thread\n");
11493 }
11494@@ -2247,8 +2334,8 @@
11495 printf("Parallel unsquashfs: Using %d processor%s\n", processors,
11496 processors == 1 ? "" : "s");
11497
11498- if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
11499- EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
11500+ if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1)
11501+ EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
11502 "\n");
11503 }
11504
11505@@ -2256,7 +2343,7 @@
11506 void enable_progress_bar()
11507 {
11508 pthread_mutex_lock(&screen_mutex);
11509- progress_enabled = TRUE;
11510+ progress_enabled = progress;
11511 pthread_mutex_unlock(&screen_mutex);
11512 }
11513
11514@@ -2264,19 +2351,16 @@
11515 void disable_progress_bar()
11516 {
11517 pthread_mutex_lock(&screen_mutex);
11518+ if(progress_enabled) {
11519+ progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
11520+ total_inodes - total_files + total_blocks, columns);
11521+ printf("\n");
11522+ }
11523 progress_enabled = FALSE;
11524 pthread_mutex_unlock(&screen_mutex);
11525 }
11526
11527
11528-void update_progress_bar()
11529-{
11530- pthread_mutex_lock(&screen_mutex);
11531- pthread_cond_signal(&progress_wait);
11532- pthread_mutex_unlock(&screen_mutex);
11533-}
11534-
11535-
11536 void progressbar_error(char *fmt, ...)
11537 {
11538 va_list ap;
11539@@ -2393,8 +2477,8 @@
11540
11541
11542 #define VERSION() \
11543- printf("unsquashfs version 4.2-git (2013/03/13)\n");\
11544- printf("copyright (C) 2013 Phillip Lougher "\
11545+ printf("unsquashfs version 4.3 (2014/05/12)\n");\
11546+ printf("copyright (C) 2014 Phillip Lougher "\
11547 "<phillip@squashfs.org.uk>\n\n");\
11548 printf("This program is free software; you can redistribute it and/or"\
11549 "\n");\
11550@@ -2535,6 +2619,11 @@
11551 progress = FALSE;
11552
11553 #ifdef SQUASHFS_TRACE
11554+ /*
11555+ * Disable progress bar if full debug tracing is enabled.
11556+ * The progress bar in this case just gets in the way of the
11557+ * debug trace output
11558+ */
11559 progress = FALSE;
11560 #endif
11561
11562@@ -2608,13 +2697,8 @@
11563 exit(0);
11564 }
11565
11566- if(!comp->supported) {
11567- ERROR("Filesystem uses %s compression, this is "
11568- "unsupported by this version\n", comp->name);
11569- ERROR("Decompressors available:\n");
11570- display_compressors("", "");
11571+ if(!check_compression(comp))
11572 exit(1);
11573- }
11574
11575 block_size = sBlk.s.block_size;
11576 block_log = sBlk.s.block_log;
11577@@ -2707,8 +2791,7 @@
11578 printf("%d inodes (%d blocks) to write\n\n", total_inodes,
11579 total_inodes - total_files + total_blocks);
11580
11581- if(progress)
11582- enable_progress_bar();
11583+ enable_progress_bar();
11584
11585 dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
11586 SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
11587@@ -2716,11 +2799,7 @@
11588 queue_put(to_writer, NULL);
11589 queue_get(from_writer);
11590
11591- if(progress) {
11592- disable_progress_bar();
11593- progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
11594- total_inodes - total_files + total_blocks, columns);
11595- }
11596+ disable_progress_bar();
11597
11598 if(!lsonly) {
11599 printf("\n");
11600diff -Nru squashfs-tools-4.2+20130409/unsquashfs.h squashfs-tools-4.3+20140919/unsquashfs.h
11601--- squashfs-tools-4.2+20130409/unsquashfs.h 2013-05-09 10:39:11.000000000 +0200
11602+++ squashfs-tools-4.3+20140919/unsquashfs.h 2015-07-20 21:03:05.000000000 +0200
11603@@ -1,8 +1,10 @@
11604+#ifndef UNSQUASHFS_H
11605+#define UNSQUASHFS_H
11606 /*
11607 * Unsquash a squashfs filesystem. This is a highly compressed read only
11608 * filesystem.
11609 *
11610- * Copyright (c) 2009, 2010, 2013
11611+ * Copyright (c) 2009, 2010, 2013, 2014
11612 * Phillip Lougher <phillip@squashfs.org.uk>
11613 *
11614 * This program is free software; you can redistribute it and/or
11615@@ -121,6 +123,7 @@
11616 struct cache {
11617 int max_buffers;
11618 int count;
11619+ int used;
11620 int buffer_size;
11621 int wait_free;
11622 int wait_pending;
11623@@ -232,11 +235,17 @@
11624 extern int inode_number;
11625 extern int lookup_type[];
11626 extern int fd;
11627+extern struct queue *to_reader, *to_inflate, *to_writer;
11628+extern struct cache *fragment_cache, *data_cache;
11629
11630 /* unsquashfs.c */
11631 extern int lookup_entry(struct hash_table_entry **, long long);
11632 extern int read_fs_bytes(int fd, long long, int, void *);
11633 extern int read_block(int, long long, long long *, int, void *);
11634+extern void enable_progress_bar();
11635+extern void disable_progress_bar();
11636+extern void dump_queue(struct queue *);
11637+extern void dump_cache(struct cache *);
11638
11639 /* unsquash-1.c */
11640 extern void read_block_list_1(unsigned int *, char *, int);
11641@@ -266,3 +275,4 @@
11642 extern struct dir *squashfs_opendir_4(unsigned int, unsigned int,
11643 struct inode **);
11644 extern int read_uids_guids_4();
11645+#endif
11646diff -Nru squashfs-tools-4.2+20130409/unsquashfs_info.c squashfs-tools-4.3+20140919/unsquashfs_info.c
11647--- squashfs-tools-4.2+20130409/unsquashfs_info.c 1970-01-01 01:00:00.000000000 +0100
11648+++ squashfs-tools-4.3+20140919/unsquashfs_info.c 2015-07-20 21:03:05.000000000 +0200
11649@@ -0,0 +1,145 @@
11650+/*
11651+ * Create a squashfs filesystem. This is a highly compressed read only
11652+ * filesystem.
11653+ *
11654+ * Copyright (c) 2013
11655+ * Phillip Lougher <phillip@squashfs.org.uk>
11656+ *
11657+ * This program is free software; you can redistribute it and/or
11658+ * modify it under the terms of the GNU General Public License
11659+ * as published by the Free Software Foundation; either version 2,
11660+ * or (at your option) any later version.
11661+ *
11662+ * This program is distributed in the hope that it will be useful,
11663+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11664+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11665+ * GNU General Public License for more details.
11666+ *
11667+ * You should have received a copy of the GNU General Public License
11668+ * along with this program; if not, write to the Free Software
11669+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11670+ *
11671+ * unsquashfs_info.c
11672+ */
11673+
11674+#include <pthread.h>
11675+#include <sys/ioctl.h>
11676+#include <unistd.h>
11677+#include <signal.h>
11678+#include <sys/time.h>
11679+#include <stdio.h>
11680+#include <math.h>
11681+#include <stdarg.h>
11682+#include <errno.h>
11683+#include <stdlib.h>
11684+#include <dirent.h>
11685+#include <sys/types.h>
11686+#include <sys/stat.h>
11687+#include <string.h>
11688+
11689+#include "squashfs_fs.h"
11690+#include "unsquashfs.h"
11691+#include "error.h"
11692+
11693+static int silent = 0;
11694+char *pathname = NULL;
11695+
11696+pthread_t info_thread;
11697+
11698+
11699+void disable_info()
11700+{
11701+ if(pathname)
11702+ free(pathname);
11703+
11704+ pathname = NULL;
11705+}
11706+
11707+
11708+void update_info(char *name)
11709+{
11710+ if(pathname)
11711+ free(pathname);
11712+
11713+ pathname = name;
11714+}
11715+
11716+
11717+void dump_state()
11718+{
11719+ disable_progress_bar();
11720+
11721+ printf("Queue and cache status dump\n");
11722+ printf("===========================\n");
11723+
11724+ printf("file buffer read queue (main thread -> reader thread)\n");
11725+ dump_queue(to_reader);
11726+
11727+ printf("file buffer decompress queue (reader thread -> inflate"
11728+ " thread(s))\n");
11729+ dump_queue(to_inflate);
11730+
11731+ printf("file buffer write queue (main thread -> writer thread)\n");
11732+ dump_queue(to_writer);
11733+
11734+ printf("\nbuffer cache (uncompressed blocks and compressed blocks "
11735+ "'in flight')\n");
11736+ dump_cache(data_cache);
11737+
11738+ printf("fragment buffer cache (uncompressed frags and compressed"
11739+ " frags 'in flight')\n");
11740+ dump_cache(fragment_cache);
11741+
11742+ enable_progress_bar();
11743+}
11744+
11745+
11746+void *info_thrd(void *arg)
11747+{
11748+ sigset_t sigmask;
11749+ struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
11750+ int sig, waiting = 0;
11751+
11752+ sigemptyset(&sigmask);
11753+ sigaddset(&sigmask, SIGQUIT);
11754+ sigaddset(&sigmask, SIGHUP);
11755+
11756+ while(1) {
11757+ if(waiting)
11758+ sig = sigtimedwait(&sigmask, NULL, ×pec);
11759+ else
11760+ sig = sigwaitinfo(&sigmask, NULL);
11761+
11762+ if(sig == -1) {
11763+ switch(errno) {
11764+ case EAGAIN:
11765+ /* interval timed out */
11766+ waiting = 0;
11767+ /* FALLTHROUGH */
11768+ case EINTR:
11769+ /* if waiting, the wait will be longer, but
11770+ that's OK */
11771+ continue;
11772+ default:
11773+ BAD_ERROR("sigtimedwait/sigwaitinfo failed "
11774+ "because %s\n", strerror(errno));
11775+ }
11776+ }
11777+
11778+ if(sig == SIGQUIT && !waiting) {
11779+ if(pathname)
11780+ INFO("%s\n", pathname);
11781+
11782+ /* set one second interval period, if ^\ received
11783+ within then, dump queue and cache status */
11784+ waiting = 1;
11785+ } else
11786+ dump_state();
11787+ }
11788+}
11789+
11790+
11791+void init_info()
11792+{
11793+ pthread_create(&info_thread, NULL, info_thrd, NULL);
11794+}
11795diff -Nru squashfs-tools-4.2+20130409/unsquashfs_info.h squashfs-tools-4.3+20140919/unsquashfs_info.h
11796--- squashfs-tools-4.2+20130409/unsquashfs_info.h 1970-01-01 01:00:00.000000000 +0100
11797+++ squashfs-tools-4.3+20140919/unsquashfs_info.h 2015-07-20 21:03:05.000000000 +0200
11798@@ -0,0 +1,30 @@
11799+#ifndef UNSQUASHFS_INFO_H
11800+#define UNSQUASHFS_INFO_H
11801+/*
11802+ * Create a squashfs filesystem. This is a highly compressed read only
11803+ * filesystem.
11804+ *
11805+ * Copyright (c) 2013, 2014
11806+ * Phillip Lougher <phillip@squashfs.org.uk>
11807+ *
11808+ * This program is free software; you can redistribute it and/or
11809+ * modify it under the terms of the GNU General Public License
11810+ * as published by the Free Software Foundation; either version 2,
11811+ * or (at your option) any later version.
11812+ *
11813+ * This program is distributed in the hope that it will be useful,
11814+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11815+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11816+ * GNU General Public License for more details.
11817+ *
11818+ * You should have received a copy of the GNU General Public License
11819+ * along with this program; if not, write to the Free Software
11820+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11821+ *
11822+ * unsquashfs_info.h
11823+ */
11824+
11825+extern void disable_info();
11826+extern void update_info(char *);
11827+extern void init_info();
11828+#endif
11829diff -Nru squashfs-tools-4.2+20130409/xattr.c squashfs-tools-4.3+20140919/xattr.c
11830--- squashfs-tools-4.2+20130409/xattr.c 2013-05-09 10:39:11.000000000 +0200
11831+++ squashfs-tools-4.3+20140919/xattr.c 2015-07-20 21:03:05.000000000 +0200
11832@@ -2,7 +2,7 @@
11833 * Create a squashfs filesystem. This is a highly compressed read only
11834 * filesystem.
11835 *
11836- * Copyright (c) 2008, 2009, 2010, 2012
11837+ * Copyright (c) 2008, 2009, 2010, 2012, 2014
11838 * Phillip Lougher <phillip@squashfs.org.uk>
11839 *
11840 * This program is free software; you can redistribute it and/or
11841@@ -41,6 +41,7 @@
11842 #include "mksquashfs.h"
11843 #include "xattr.h"
11844 #include "error.h"
11845+#include "progressbar.h"
11846
11847 /* compressed xattr table */
11848 static char *xattr_table = NULL;
11849@@ -65,7 +66,7 @@
11850 static int sxattr_ids = 0;
11851
11852 /* xattr hash table for value duplicate detection */
11853-static struct xattr_list *dupl[65536];
11854+static struct xattr_list *dupl_value[65536];
11855
11856 /* xattr hash table for id duplicate detection */
11857 static struct dupl_id *dupl_id[65536];
11858@@ -120,10 +121,12 @@
11859 while(1) {
11860 size = llistxattr(filename, NULL, 0);
11861 if(size <= 0) {
11862- if(size < 0 && errno != ENOTSUP)
11863- ERROR("llistxattr for %s failed in read_attrs,"
11864- " because %s\n", filename,
11865+ if(size < 0 && errno != ENOTSUP) {
11866+ ERROR_START("llistxattr for %s failed in "
11867+ "read_attrs, because %s", filename,
11868 strerror(errno));
11869+ ERROR_EXIT(". Ignoring");
11870+ }
11871 return 0;
11872 }
11873
11874@@ -138,9 +141,10 @@
11875 /* xattr list grew? Try again */
11876 continue;
11877 else {
11878- ERROR("llistxattr for %s failed in read_attrs,"
11879- " because %s\n", filename,
11880+ ERROR_START("llistxattr for %s failed in "
11881+ "read_attrs, because %s", filename,
11882 strerror(errno));
11883+ ERROR_EXIT(". Ignoring");
11884 return 0;
11885 }
11886 }
11887@@ -169,9 +173,10 @@
11888 vsize = lgetxattr(filename, xattr_list[i].full_name,
11889 NULL, 0);
11890 if(vsize < 0) {
11891- ERROR("lgetxattr failed for %s in read_attrs,"
11892- " because %s\n", filename,
11893+ ERROR_START("lgetxattr failed for %s in "
11894+ "read_attrs, because %s", filename,
11895 strerror(errno));
11896+ ERROR_EXIT(". Ignoring");
11897 free(xattr_list[i].full_name);
11898 goto failed;
11899 }
11900@@ -188,9 +193,10 @@
11901 /* xattr grew? Try again */
11902 continue;
11903 else {
11904- ERROR("lgetxattr failed for %s in "
11905- "read_attrs, because %s\n",
11906+ ERROR_START("lgetxattr failed for %s "
11907+ "in read_attrs, because %s",
11908 filename, strerror(errno));
11909+ ERROR_EXIT(". Ignoring");
11910 free(xattr_list[i].full_name);
11911 goto failed;
11912 }
11913@@ -342,7 +348,7 @@
11914
11915 /* Check if this is a duplicate of an existing value */
11916 xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0);
11917- for(entry = dupl[xattr->vchecksum]; entry; entry = entry->vnext) {
11918+ for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) {
11919 if(entry->vsize != xattr->vsize)
11920 continue;
11921
11922@@ -355,8 +361,8 @@
11923 * No duplicate exists, add to hash table, and mark as
11924 * requiring writing
11925 */
11926- xattr->vnext = dupl[xattr->vchecksum];
11927- dupl[xattr->vchecksum] = xattr;
11928+ xattr->vnext = dupl_value[xattr->vchecksum];
11929+ dupl_value[xattr->vchecksum] = xattr;
11930 xattr->ool_value = SQUASHFS_INVALID_BLK;
11931 } else {
11932 /*
11933diff -Nru squashfs-tools-4.2+20130409/xattr.h squashfs-tools-4.3+20140919/xattr.h
11934--- squashfs-tools-4.2+20130409/xattr.h 2013-05-09 10:39:11.000000000 +0200
11935+++ squashfs-tools-4.3+20140919/xattr.h 2015-07-20 21:03:05.000000000 +0200
11936@@ -1,8 +1,10 @@
11937+#ifndef XATTR_H
11938+#define XATTR_H
11939 /*
11940 * Create a squashfs filesystem. This is a highly compressed read only
11941 * filesystem.
11942 *
11943- * Copyright (c) 2010, 2012, 2013
11944+ * Copyright (c) 2010, 2012, 2013, 2014
11945 * Phillip Lougher <phillip@squashfs.org.uk>
11946 *
11947 * This program is free software; you can redistribute it and/or
11948@@ -124,7 +126,7 @@
11949 }
11950
11951
11952-static inline struct xattr_list *get_xattr(int i, unsigned int *count, int)
11953+static inline struct xattr_list *get_xattr(int i, unsigned int *count, int j)
11954 {
11955 return NULL;
11956 }
11957@@ -145,4 +147,4 @@
11958 #define XOPT_STR " (unsupported)"
11959 #define XATTR_DEF 1
11960 #endif
11961-
11962+#endif
11963diff -Nru squashfs-tools-4.2+20130409/xz_wrapper.c squashfs-tools-4.3+20140919/xz_wrapper.c
11964--- squashfs-tools-4.2+20130409/xz_wrapper.c 2013-05-09 10:39:11.000000000 +0200
11965+++ squashfs-tools-4.3+20140919/xz_wrapper.c 2015-07-20 21:03:05.000000000 +0200
11966@@ -41,8 +41,6 @@
11967 { NULL, LZMA_VLI_UNKNOWN, 0 }
11968 };
11969
11970-static struct comp_opts comp_opts;
11971-
11972 static int filter_count = 1;
11973 static int dictionary_size = 0;
11974 static float dictionary_percent = 0;
11975@@ -56,10 +54,11 @@
11976 * -Xbcj
11977 * -Xdict-size
11978 *
11979- * This function returns 1 on successful parsing of an option
11980- * -1 if the option was unrecognised, or
11981- * -2 if the option was recognised, but otherwise bad in
11982- * some way (e.g. invalid parameter)
11983+ * This function returns:
11984+ * >=0 (number of additional args parsed) on success
11985+ * -1 if the option was unrecognised, or
11986+ * -2 if the option was recognised, but otherwise bad in
11987+ * some way (e.g. invalid parameter)
11988 *
11989 * Note: this function sets internal compressor state, but does not
11990 * pass back the results of the parsing other than success/failure.
11991@@ -226,6 +225,7 @@
11992 */
11993 static void *xz_dump_options(int block_size, int *size)
11994 {
11995+ static struct comp_opts comp_opts;
11996 int flags = 0, i;
11997
11998 /*
11999@@ -329,7 +329,7 @@
12000 int i, n;
12001
12002 /* check passed comp opts struct is of the correct length */
12003- if(size != sizeof(comp_opts))
12004+ if(size != sizeof(struct comp_opts))
12005 goto failed;
12006
12007 SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
12008@@ -494,8 +494,12 @@
12009 lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
12010 src, &src_pos, size, dest, &dest_pos, outsize);
12011
12012- *error = res;
12013- return res == LZMA_OK && size == (int) src_pos ? (int) dest_pos : -1;
12014+ if(res == LZMA_OK && size == (int) src_pos)
12015+ return (int) dest_pos;
12016+ else {
12017+ *error = res;
12018+ return -1;
12019+ }
12020 }