Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff -Nru squashfs-tools-4.2+20130409/action.c squashfs-tools-4.3+20140919/action.c
- --- squashfs-tools-4.2+20130409/action.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/action.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2011, 2012, 2013
- + * Copyright (c) 2011, 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -53,12 +53,15 @@
- static struct action *exclude_spec = NULL;
- static struct action *empty_spec = NULL;
- static struct action *move_spec = NULL;
- +static struct action *prune_spec = NULL;
- static struct action *other_spec = NULL;
- static int fragment_count = 0;
- static int exclude_count = 0;
- static int empty_count = 0;
- static int move_count = 0;
- +static int prune_count = 0;
- static int other_count = 0;
- +static struct action_entry *parsing_action;
- static struct file_buffer *def_fragment = NULL;
- @@ -198,12 +201,34 @@
- /*
- * Expression parser
- */
- +static void free_parse_tree(struct expr *expr)
- +{
- + if(expr->type == ATOM_TYPE) {
- + int i;
- +
- + for(i = 0; i < expr->atom.test->args; i++)
- + free(expr->atom.argv[i]);
- +
- + free(expr->atom.argv);
- + } else if (expr->type == UNARY_TYPE)
- + free_parse_tree(expr->unary_op.expr);
- + else {
- + free_parse_tree(expr->expr_op.lhs);
- + free_parse_tree(expr->expr_op.rhs);
- + }
- +
- + free(expr);
- +}
- +
- +
- static struct expr *create_expr(struct expr *lhs, int op, struct expr *rhs)
- {
- struct expr *expr;
- - if (rhs == NULL)
- + if (rhs == NULL) {
- + free_parse_tree(lhs);
- return NULL;
- + }
- expr = malloc(sizeof(*expr));
- if (expr == NULL)
- @@ -239,8 +264,8 @@
- static struct expr *parse_test(char *name)
- {
- - char *string;
- - int token;
- + char *string, **argv = NULL;
- + int token, args = 0;
- int i;
- struct test_entry *test;
- struct expr *expr;
- @@ -249,12 +274,20 @@
- if (strcmp(name, test_table[i].name) == 0)
- break;
- - if (test_table[i].args == -1) {
- + test = &test_table[i];
- +
- + if (test->args == -1) {
- SYNTAX_ERROR("Non-existent test \"%s\"\n", name);
- return NULL;
- }
- - test = &test_table[i];
- + if(parsing_action->type == EXCLUDE_ACTION && !test->exclude_ok) {
- + fprintf(stderr, "Failed to parse action \"%s\"\n", source);
- + fprintf(stderr, "Test \"%s\" cannot be used in exclude "
- + "actions\n", name);
- + fprintf(stderr, "Use prune action instead ...\n");
- + return NULL;
- + }
- expr = malloc(sizeof(*expr));
- if (expr == NULL)
- @@ -262,55 +295,68 @@
- expr->type = ATOM_TYPE;
- - expr->atom.argv = malloc(test->args * sizeof(char *));
- - if (expr->atom.argv == NULL)
- - MEM_ERROR();
- -
- expr->atom.test = test;
- expr->atom.data = NULL;
- /*
- - * If the test has no arguments, allow it to be typed
- - * without brackets
- + * If the test has no arguments, then go straight to checking if there's
- + * enough arguments
- */
- - if (test->args == 0) {
- - token = peek_token(&string);
- + token = peek_token(&string);
- - if (token != TOK_OPEN_BRACKET)
- + if (token != TOK_OPEN_BRACKET)
- goto skip_args;
- - }
- -
- - token = get_token(&string);
- - if (token != TOK_OPEN_BRACKET) {
- - SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n",
- - TOK_TO_STR(token, string));
- - goto failed;
- - }
- + get_token(&string);
- - for (i = 0; i < test->args; i++) {
- - token = get_token(&string);
- + /*
- + * speculatively read all the arguments, and then see if the
- + * number of arguments read is the number expected, this handles
- + * tests with a variable number of arguments
- + */
- + token = get_token(&string);
- + if (token == TOK_CLOSE_BRACKET)
- + goto skip_args;
- + while(1) {
- if (token != TOK_STRING) {
- SYNTAX_ERROR("Unexpected token \"%s\", expected "
- "argument\n", TOK_TO_STR(token, string));
- goto failed;
- }
- - expr->atom.argv[i] = strdup(string);
- + argv = realloc(argv, (args + 1) * sizeof(char *));
- + if (argv == NULL)
- + MEM_ERROR();
- +
- + argv[args ++ ] = strdup(string);
- +
- + token = get_token(&string);
- - if (i + 1 < test->args) {
- - token = get_token(&string);
- + if (token == TOK_CLOSE_BRACKET)
- + break;
- - if (token != TOK_COMMA) {
- - SYNTAX_ERROR("Unexpected token \"%s\", "
- - "expected \",\"\n",
- - TOK_TO_STR(token, string));
- + if (token != TOK_COMMA) {
- + SYNTAX_ERROR("Unexpected token \"%s\", expected "
- + "\",\" or \")\"\n", TOK_TO_STR(token, string));
- goto failed;
- - }
- }
- + token = get_token(&string);
- + }
- +
- +skip_args:
- + /*
- + * expected number of arguments?
- + */
- + if(test->args != -2 && args != test->args) {
- + SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
- + "got %d\n", test->args, args);
- + goto failed;
- }
- + expr->atom.args = args;
- + expr->atom.argv = argv;
- +
- if (test->parse_args) {
- int res = test->parse_args(test, &expr->atom);
- @@ -318,19 +364,10 @@
- goto failed;
- }
- - token = get_token(&string);
- -
- - if (token != TOK_CLOSE_BRACKET) {
- - SYNTAX_ERROR("Unexpected token \"%s\", expected \")\"\n",
- - TOK_TO_STR(token, string));
- - goto failed;
- - }
- -
- -skip_args:
- return expr;
- failed:
- - free(expr->atom.argv);
- + free(argv);
- free(expr);
- return NULL;
- }
- @@ -367,6 +404,7 @@
- if (op == TOK_EOF) {
- if (subexp) {
- + free_parse_tree(expr);
- SYNTAX_ERROR("Expected \"&&\", \"||\" or "
- "\")\", got EOF\n");
- return NULL;
- @@ -376,6 +414,7 @@
- if (op == TOK_CLOSE_BRACKET) {
- if (!subexp) {
- + free_parse_tree(expr);
- SYNTAX_ERROR("Unexpected \")\", expected "
- "\"&&\", \"!!\" or EOF\n");
- return NULL;
- @@ -384,6 +423,7 @@
- }
- if (op != TOK_AND && op != TOK_OR) {
- + free_parse_tree(expr);
- SYNTAX_ERROR("Unexpected token \"%s\", expected "
- "\"&&\" or \"||\"\n", TOK_TO_STR(op, string));
- return NULL;
- @@ -399,7 +439,7 @@
- /*
- * Action parser
- */
- -int parse_action(char *s)
- +int parse_action(char *s, int verbose)
- {
- char *string, **argv = NULL;
- int i, token, args = 0;
- @@ -501,6 +541,7 @@
- goto failed;
- }
- + parsing_action = action;
- expr = parse_expr(0);
- if (expr == NULL)
- @@ -526,6 +567,10 @@
- spec_count = move_count ++;
- spec_list = &move_spec;
- break;
- + case PRUNE_ACTION:
- + spec_count = prune_count ++;
- + spec_list = &prune_spec;
- + break;
- default:
- spec_count = other_count ++;
- spec_list = &other_spec;
- @@ -542,6 +587,7 @@
- (*spec_list)[spec_count].argv = argv;
- (*spec_list)[spec_count].expr = expr;
- (*spec_list)[spec_count].data = data;
- + (*spec_list)[spec_count].verbose = verbose;
- return 1;
- @@ -551,68 +597,133 @@
- }
- -static void dump_parse_tree(struct expr *expr)
- -{
- - if(expr->type == ATOM_TYPE) {
- - int i;
- +/*
- + * Evaluate expressions
- + */
- - printf("%s(", expr->atom.test->name);
- - for(i = 0; i < expr->atom.test->args; i++) {
- - printf("%s", expr->atom.argv[i]);
- - if (i + 1 < expr->atom.test->args)
- - printf(",");
- - }
- - printf(")");
- - } else if (expr->type == UNARY_TYPE) {
- - printf("%s", token_table[expr->unary_op.op].string);
- - dump_parse_tree(expr->unary_op.expr);
- - } else {
- - printf("(");
- - dump_parse_tree(expr->expr_op.lhs);
- - printf("%s", token_table[expr->expr_op.op].string);
- - dump_parse_tree(expr->expr_op.rhs);
- - printf(")");
- +#define ALLOC_SZ 128
- +
- +#define LOG_ENABLE 0
- +#define LOG_DISABLE 1
- +#define LOG_PRINT 2
- +#define LOG_ENABLED 3
- +
- +char *_expr_log(char *string, int cmnd)
- +{
- + static char *expr_msg = NULL;
- + static int cur_size = 0, alloc_size = 0;
- + int size;
- +
- + switch(cmnd) {
- + case LOG_ENABLE:
- + expr_msg = malloc(ALLOC_SZ);
- + alloc_size = ALLOC_SZ;
- + cur_size = 0;
- + return expr_msg;
- + case LOG_DISABLE:
- + free(expr_msg);
- + alloc_size = cur_size = 0;
- + return expr_msg = NULL;
- + case LOG_ENABLED:
- + return expr_msg;
- + default:
- + if(expr_msg == NULL)
- + return NULL;
- + break;
- + }
- +
- + /* if string is empty append '\0' */
- + size = strlen(string) ? : 1;
- +
- + if(alloc_size - cur_size < size) {
- + /* buffer too small, expand */
- + alloc_size = (cur_size + size + ALLOC_SZ - 1) & ~(ALLOC_SZ - 1);
- +
- + expr_msg = realloc(expr_msg, alloc_size);
- + if(expr_msg == NULL)
- + MEM_ERROR();
- }
- +
- + memcpy(expr_msg + cur_size, string, size);
- + cur_size += size;
- +
- + return expr_msg;
- }
- -void dump_action_list(struct action *spec_list, int spec_count)
- +char *expr_log_cmnd(int cmnd)
- +{
- + return _expr_log(NULL, cmnd);
- +}
- +
- +
- +char *expr_log(char *string)
- +{
- + return _expr_log(string, LOG_PRINT);
- +}
- +
- +
- +void expr_log_atom(struct atom *atom)
- {
- int i;
- - for (i = 0; i < spec_count; i++) {
- - printf("%s", spec_list[i].action->name);
- - if (spec_list[i].action->args) {
- - int n;
- + if(atom->test->handle_logging)
- + return;
- - printf("(");
- - for (n = 0; n < spec_list[i].action->args; n++) {
- - printf("%s", spec_list[i].argv[n]);
- - if (n + 1 < spec_list[i].action->args)
- - printf(",");
- - }
- - printf(")");
- + expr_log(atom->test->name);
- +
- + if(atom->args) {
- + expr_log("(");
- + for(i = 0; i < atom->args; i++) {
- + expr_log(atom->argv[i]);
- + if (i + 1 < atom->args)
- + expr_log(",");
- }
- - printf("=");
- - dump_parse_tree(spec_list[i].expr);
- - printf("\n");
- + expr_log(")");
- }
- }
- -void dump_actions()
- +void expr_log_match(int match)
- {
- - dump_action_list(exclude_spec, exclude_count);
- - dump_action_list(fragment_spec, fragment_count);
- - dump_action_list(other_spec, other_count);
- - dump_action_list(move_spec, move_count);
- - dump_action_list(empty_spec, empty_count);
- + if(match)
- + expr_log("=True");
- + else
- + expr_log("=False");
- +}
- +
- +
- +static int eval_expr_log(struct expr *expr, struct action_data *action_data)
- +{
- + int match;
- +
- + switch (expr->type) {
- + case ATOM_TYPE:
- + expr_log_atom(&expr->atom);
- + match = expr->atom.test->fn(&expr->atom, action_data);
- + expr_log_match(match);
- + break;
- + case UNARY_TYPE:
- + expr_log("!");
- + match = !eval_expr_log(expr->unary_op.expr, action_data);
- + break;
- + default:
- + expr_log("(");
- + match = eval_expr_log(expr->expr_op.lhs, action_data);
- +
- + if ((expr->expr_op.op == TOK_AND && match) ||
- + (expr->expr_op.op == TOK_OR && !match)) {
- + expr_log(token_table[expr->expr_op.op].string);
- + match = eval_expr_log(expr->expr_op.rhs, action_data);
- + }
- + expr_log(")");
- + break;
- + }
- +
- + return match;
- }
- -/*
- - * Evaluate expressions
- - */
- static int eval_expr(struct expr *expr, struct action_data *action_data)
- {
- int match;
- @@ -637,6 +748,49 @@
- }
- +static int eval_expr_top(struct action *action, struct action_data *action_data)
- +{
- + if(action->verbose) {
- + int match, n;
- +
- + expr_log_cmnd(LOG_ENABLE);
- +
- + if(action_data->subpath)
- + expr_log(action_data->subpath);
- +
- + expr_log("=");
- + expr_log(action->action->name);
- +
- + if(action->args) {
- + expr_log("(");
- + for (n = 0; n < action->args; n++) {
- + expr_log(action->argv[n]);
- + if(n + 1 < action->args)
- + expr_log(",");
- + }
- + expr_log(")");
- + }
- +
- + expr_log("@");
- +
- + match = eval_expr_log(action->expr, action_data);
- +
- + /*
- + * Print the evaluated expression log, if the
- + * result matches the logging specified
- + */
- + if((match && (action->verbose & ACTION_LOG_TRUE)) || (!match
- + && (action->verbose & ACTION_LOG_FALSE)))
- + progressbar_info("%s\n", expr_log(""));
- +
- + expr_log_cmnd(LOG_DISABLE);
- +
- + return match;
- + } else
- + return eval_expr(action->expr, action_data);
- +}
- +
- +
- /*
- * Read action file, passing each line to parse_action() for
- * parsing.
- @@ -648,9 +802,65 @@
- *
- * Blank lines and comment lines indicated by # are supported.
- */
- -int read_action_file(char *filename)
- +int parse_action_true(char *s)
- +{
- + return parse_action(s, ACTION_LOG_TRUE);
- +}
- +
- +
- +int parse_action_false(char *s)
- +{
- + return parse_action(s, ACTION_LOG_FALSE);
- +}
- +
- +
- +int parse_action_verbose(char *s)
- +{
- + return parse_action(s, ACTION_LOG_VERBOSE);
- +}
- +
- +
- +int parse_action_nonverbose(char *s)
- +{
- + return parse_action(s, ACTION_LOG_NONE);
- +}
- +
- +
- +int read_action_file(char *filename, int verbose)
- +{
- + switch(verbose) {
- + case ACTION_LOG_TRUE:
- + return read_file(filename, "action", parse_action_true);
- + case ACTION_LOG_FALSE:
- + return read_file(filename, "action", parse_action_false);
- + case ACTION_LOG_VERBOSE:
- + return read_file(filename, "action", parse_action_verbose);
- + default:
- + return read_file(filename, "action", parse_action_nonverbose);
- + }
- +}
- +
- +
- +/*
- + * helper to evaluate whether action/test acts on this file type
- + */
- +static int file_type_match(int st_mode, int type)
- {
- - return read_file(filename, "action", parse_action);
- + switch(type) {
- + case ACTION_DIR:
- + return S_ISDIR(st_mode);
- + case ACTION_REG:
- + return S_ISREG(st_mode);
- + case ACTION_ALL:
- + return S_ISREG(st_mode) || S_ISDIR(st_mode) ||
- + S_ISCHR(st_mode) || S_ISBLK(st_mode) ||
- + S_ISFIFO(st_mode) || S_ISSOCK(st_mode);
- + case ACTION_LNK:
- + return S_ISLNK(st_mode);
- + case ACTION_ALL_LNK:
- + default:
- + return 1;
- + }
- }
- @@ -663,53 +873,65 @@
- }
- -void eval_actions(struct dir_ent *dir_ent)
- +void eval_actions(struct dir_info *root, struct dir_ent *dir_ent)
- {
- int i, match;
- struct action_data action_data;
- - int file_type = dir_ent->inode->buf.st_mode & S_IFMT;
- + int st_mode = dir_ent->inode->buf.st_mode;
- action_data.name = dir_ent->name;
- - action_data.pathname = pathname(dir_ent);
- - action_data.subpath = subpathname(dir_ent);
- + action_data.pathname = strdup(pathname(dir_ent));
- + action_data.subpath = strdup(subpathname(dir_ent));
- action_data.buf = &dir_ent->inode->buf;
- action_data.depth = dir_ent->our_dir->depth;
- + action_data.dir_ent = dir_ent;
- + action_data.root = root;
- for (i = 0; i < other_count; i++) {
- struct action *action = &other_spec[i];
- - if ((action->action->file_types & file_type) == 0)
- + if (!file_type_match(st_mode, action->action->file_types))
- /* action does not operate on this file type */
- continue;
- - match = eval_expr(action->expr, &action_data);
- + match = eval_expr_top(action, &action_data);
- if (match)
- action->action->run_action(action, dir_ent);
- }
- +
- + free(action_data.pathname);
- + free(action_data.subpath);
- }
- /*
- * Fragment specific action code
- */
- -void *eval_frag_actions(struct dir_ent *dir_ent)
- +void *eval_frag_actions(struct dir_info *root, struct dir_ent *dir_ent)
- {
- int i, match;
- struct action_data action_data;
- action_data.name = dir_ent->name;
- - action_data.pathname = pathname(dir_ent);
- - action_data.subpath = subpathname(dir_ent);
- + action_data.pathname = strdup(pathname(dir_ent));
- + action_data.subpath = strdup(subpathname(dir_ent));
- action_data.buf = &dir_ent->inode->buf;
- action_data.depth = dir_ent->our_dir->depth;
- + action_data.dir_ent = dir_ent;
- + action_data.root = root;
- for (i = 0; i < fragment_count; i++) {
- - match = eval_expr(fragment_spec[i].expr, &action_data);
- - if (match)
- + match = eval_expr_top(&fragment_spec[i], &action_data);
- + if (match) {
- + free(action_data.pathname);
- + free(action_data.subpath);
- return &fragment_spec[i].data;
- + }
- }
- + free(action_data.pathname);
- + free(action_data.subpath);
- return &def_fragment;
- }
- @@ -747,7 +969,7 @@
- int eval_exclude_actions(char *name, char *pathname, char *subpath,
- - struct stat *buf, int depth)
- + struct stat *buf, int depth, struct dir_ent *dir_ent)
- {
- int i, match = 0;
- struct action_data action_data;
- @@ -757,9 +979,10 @@
- action_data.subpath = subpath;
- action_data.buf = buf;
- action_data.depth = depth;
- + action_data.dir_ent = dir_ent;
- for (i = 0; i < exclude_count && !match; i++)
- - match = eval_expr(exclude_spec[i].expr, &action_data);
- + match = eval_expr_top(&exclude_spec[i], &action_data);
- return match;
- }
- @@ -823,8 +1046,8 @@
- long long uid = strtoll(arg, &b, 10);
- if (*b == '\0') {
- - if (uid < 0 || uid >= (1LL < 32)) {
- - SYNTAX_ERROR("action: uid out of range\n");
- + if (uid < 0 || uid >= (1LL << 32)) {
- + SYNTAX_ERROR("Uid out of range\n");
- return -1;
- }
- } else {
- @@ -833,7 +1056,7 @@
- if (passwd)
- uid = passwd->pw_uid;
- else {
- - SYNTAX_ERROR("action: invalid uid or unknown user\n");
- + SYNTAX_ERROR("Invalid uid or unknown user\n");
- return -1;
- }
- }
- @@ -847,8 +1070,8 @@
- long long gid = strtoll(arg, &b, 10);
- if (*b == '\0') {
- - if (gid < 0 || gid >= (1LL < 32)) {
- - SYNTAX_ERROR("action: gid out of range\n");
- + if (gid < 0 || gid >= (1LL << 32)) {
- + SYNTAX_ERROR("Gid out of range\n");
- return -1;
- }
- } else {
- @@ -857,7 +1080,7 @@
- if (group)
- gid = group->gr_gid;
- else {
- - SYNTAX_ERROR("action: invalid gid or unknown user\n");
- + SYNTAX_ERROR("Invalid gid or unknown group\n");
- return -1;
- }
- }
- @@ -964,29 +1187,37 @@
- /*
- * Mode specific action code
- */
- -static int parse_octal_mode_args(unsigned int mode, int bytes, int args,
- - char **argv, void **data)
- +static int parse_octal_mode_args(int args, char **argv,
- + void **data)
- {
- + int n, bytes;
- + unsigned int mode;
- struct mode_data *mode_data;
- + /* octal mode number? */
- + n = sscanf(argv[0], "%o%n", &mode, &bytes);
- + if (n == 0)
- + return -1; /* not an octal number arg */
- +
- +
- /* check there's no trailing junk */
- if (argv[0][bytes] != '\0') {
- SYNTAX_ERROR("Unexpected trailing bytes after octal "
- "mode number\n");
- - return 0;
- + return 0; /* bad octal number arg */
- }
- /* check there's only one argument */
- if (args > 1) {
- SYNTAX_ERROR("Octal mode number is first argument, "
- "expected one argument, got %d\n", args);
- - return 0;
- + return 0; /* bad octal number arg */
- }
- /* check mode is within range */
- if (mode > 07777) {
- SYNTAX_ERROR("Octal mode %o is out of range\n", mode);
- - return 0;
- + return 0; /* bad octal number arg */
- }
- mode_data = malloc(sizeof(struct mode_data));
- @@ -1003,19 +1234,17 @@
- /*
- - * Parse symbolic mode of format [ugoa]+[+-=]PERMS
- + * Parse symbolic mode of format [ugoa]*[[+-=]PERMS]+
- * PERMS = [rwxXst]+ or [ugo]
- */
- -static struct mode_data *parse_sym_mode_arg(char *arg)
- +static int parse_sym_mode_arg(char *arg, struct mode_data **head,
- + struct mode_data **cur)
- {
- - struct mode_data *mode_data = malloc(sizeof(*mode_data));
- - int mode = 0;
- + struct mode_data *mode_data;
- + int mode;
- int mask = 0;
- int op;
- - char X = 0;
- -
- - if (mode_data == NULL)
- - MEM_ERROR();
- + char X;
- if (arg[0] != 'u' && arg[0] != 'g' && arg[0] != 'o' && arg[0] != 'a') {
- /* no ownership specifiers, default to a */
- @@ -1045,130 +1274,138 @@
- }
- parse_operation:
- - switch(*arg) {
- - case '+':
- - op = ACTION_MODE_ADD;
- - break;
- - case '-':
- - op = ACTION_MODE_REM;
- - break;
- - case '=':
- - op = ACTION_MODE_SET;
- - break;
- - default:
- - SYNTAX_ERROR("Action mode: Expected one of '+', '-' or '=', "
- - "got '%c'\n", *arg);
- + /* trap a symbolic mode with just an ownership specification */
- + if(*arg == '\0') {
- + SYNTAX_ERROR("Expected one of '+', '-' or '=', got EOF\n");
- goto failed;
- }
- - arg ++;
- + while(*arg != '\0') {
- + mode = 0;
- + X = 0;
- - /* Parse PERMS */
- - if (*arg == 'u' || *arg == 'g' || *arg == 'o') {
- - /* PERMS = [ugo] */
- - mode = - *arg;
- - if (*++arg != '\0') {
- - SYNTAX_ERROR("Action mode: permission 'u', 'g' or 'o' "
- - "has trailing characters\n");
- + switch(*arg) {
- + case '+':
- + op = ACTION_MODE_ADD;
- + break;
- + case '-':
- + op = ACTION_MODE_REM;
- + break;
- + case '=':
- + op = ACTION_MODE_SET;
- + break;
- + default:
- + SYNTAX_ERROR("Expected one of '+', '-' or '=', got "
- + "'%c'\n", *arg);
- goto failed;
- }
- - } else {
- - /* PERMS = [rwxXst]+ */
- - while(*arg != '\0') {
- - switch(*arg) {
- - case 'r':
- - mode |= 0444;
- - break;
- - case 'w':
- - mode |= 0222;
- - break;
- - case 'x':
- - mode |= 0111;
- - break;
- - case 's':
- - mode |= 06000;
- - break;
- - case 't':
- - mode |= 01000;
- - break;
- - case 'X':
- - X = 1;
- - break;
- - default:
- - SYNTAX_ERROR("Action mode: unrecognised "
- - "permission '%c'\n", *arg);
- - goto failed;
- - }
- -
- +
- + arg ++;
- +
- + /* Parse PERMS */
- + if (*arg == 'u' || *arg == 'g' || *arg == 'o') {
- + /* PERMS = [ugo] */
- + mode = - *arg;
- arg ++;
- + } else {
- + /* PERMS = [rwxXst]* */
- + while(1) {
- + switch(*arg) {
- + case 'r':
- + mode |= 0444;
- + break;
- + case 'w':
- + mode |= 0222;
- + break;
- + case 'x':
- + mode |= 0111;
- + break;
- + case 's':
- + mode |= 06000;
- + break;
- + case 't':
- + mode |= 01000;
- + break;
- + case 'X':
- + X = 1;
- + break;
- + case '+':
- + case '-':
- + case '=':
- + case '\0':
- + mode &= mask;
- + goto perms_parsed;
- + default:
- + SYNTAX_ERROR("Unrecognised permission "
- + "'%c'\n", *arg);
- + goto failed;
- + }
- +
- + arg ++;
- + }
- }
- - mode &= mask;
- - }
- +
- +perms_parsed:
- + mode_data = malloc(sizeof(*mode_data));
- + if (mode_data == NULL)
- + MEM_ERROR();
- - mode_data->operation = op;
- - mode_data->mode = mode;
- - mode_data->mask = mask;
- - mode_data->X = X;
- - mode_data->next = NULL;
- + mode_data->operation = op;
- + mode_data->mode = mode;
- + mode_data->mask = mask;
- + mode_data->X = X;
- + mode_data->next = NULL;
- +
- + if (*cur) {
- + (*cur)->next = mode_data;
- + *cur = mode_data;
- + } else
- + *head = *cur = mode_data;
- + }
- - return mode_data;
- + return 1;
- failed:
- - free(mode_data);
- - return NULL;
- + return 0;
- }
- static int parse_sym_mode_args(struct action_entry *action, int args,
- char **argv, void **data)
- {
- - int i;
- + int i, res = 1;
- struct mode_data *head = NULL, *cur = NULL;
- - for (i = 0; i < args; i++) {
- - struct mode_data *entry = parse_sym_mode_arg(argv[i]);
- -
- - if (entry == NULL)
- - return 0;
- -
- - if (cur) {
- - cur->next = entry;
- - cur = entry;
- - } else
- - head = cur = entry;
- - }
- + for (i = 0; i < args && res; i++)
- + res = parse_sym_mode_arg(argv[i], &head, &cur);
- *data = head;
- - return 1;
- + return res;
- }
- static int parse_mode_args(struct action_entry *action, int args,
- char **argv, void **data)
- {
- - int n, bytes;
- - unsigned int mode;
- + int res;
- if (args == 0) {
- SYNTAX_ERROR("Mode action expects one or more arguments\n");
- return 0;
- }
- - /* octal mode number? */
- - n = sscanf(argv[0], "%o%n", &mode, &bytes);
- -
- - if(n >= 1)
- - return parse_octal_mode_args(mode, bytes, args, argv, data);
- - else
- + res = parse_octal_mode_args(args, argv, data);
- + if(res >= 0)
- + /* Got an octal mode argument */
- + return res;
- + else /* not an octal mode argument */
- return parse_sym_mode_args(action, args, argv, data);
- }
- -static void mode_action(struct action *action, struct dir_ent *dir_ent)
- +static int mode_execute(struct mode_data *mode_data, int st_mode)
- {
- - struct stat *buf = &dir_ent->inode->buf;
- - struct mode_data *mode_data = action->data;
- int mode = 0;
- for (;mode_data; mode_data = mode_data->next) {
- @@ -1176,20 +1413,20 @@
- /* 'u', 'g' or 'o' */
- switch(-mode_data->mode) {
- case 'u':
- - mode = (buf->st_mode >> 6) & 07;
- + mode = (st_mode >> 6) & 07;
- break;
- case 'g':
- - mode = (buf->st_mode >> 3) & 07;
- + mode = (st_mode >> 3) & 07;
- break;
- case 'o':
- - mode = buf->st_mode & 07;
- + mode = st_mode & 07;
- break;
- }
- mode = ((mode << 6) | (mode << 3) | mode) &
- mode_data->mask;
- } else if (mode_data->X &&
- - ((buf->st_mode & S_IFMT) == S_IFDIR ||
- - (buf->st_mode & 0111)))
- + ((st_mode & S_IFMT) == S_IFDIR ||
- + (st_mode & 0111)))
- /* X permission, only takes effect if inode is a
- * directory or x is set for some owner */
- mode = mode_data->mode | (0111 & mode_data->mask);
- @@ -1198,18 +1435,27 @@
- switch(mode_data->operation) {
- case ACTION_MODE_OCT:
- - buf->st_mode = (buf->st_mode & ~S_IFMT) | mode;
- + st_mode = (st_mode & S_IFMT) | mode;
- break;
- case ACTION_MODE_SET:
- - buf->st_mode = (buf->st_mode & ~mode_data->mask) | mode;
- + st_mode = (st_mode & ~mode_data->mask) | mode;
- break;
- case ACTION_MODE_ADD:
- - buf->st_mode |= mode;
- + st_mode |= mode;
- break;
- case ACTION_MODE_REM:
- - buf->st_mode &= ~mode;
- + st_mode &= ~mode;
- }
- }
- +
- + return st_mode;
- +}
- +
- +
- +static void mode_action(struct action *action, struct dir_ent *dir_ent)
- +{
- + dir_ent->inode->buf.st_mode = mode_execute(action->data,
- + dir_ent->inode->buf.st_mode);
- }
- @@ -1257,7 +1503,7 @@
- }
- -int eval_empty_actions(struct dir_ent *dir_ent)
- +int eval_empty_actions(struct dir_info *root, struct dir_ent *dir_ent)
- {
- int i, match = 0;
- struct action_data action_data;
- @@ -1271,10 +1517,12 @@
- return 0;
- action_data.name = dir_ent->name;
- - action_data.pathname = pathname(dir_ent);
- - action_data.subpath = subpathname(dir_ent);
- + action_data.pathname = strdup(pathname(dir_ent));
- + action_data.subpath = strdup(subpathname(dir_ent));
- action_data.buf = &dir_ent->inode->buf;
- action_data.depth = dir_ent->our_dir->depth;
- + action_data.dir_ent = dir_ent;
- + action_data.root = root;
- for (i = 0; i < empty_count && !match; i++) {
- data = empty_spec[i].data;
- @@ -1297,9 +1545,12 @@
- (data->val == EMPTY_SOURCE && dir->excluded))
- continue;
- - match = eval_expr(empty_spec[i].expr, &action_data);
- + match = eval_expr_top(&empty_spec[i], &action_data);
- }
- + free(action_data.pathname);
- + free(action_data.subpath);
- +
- return match;
- }
- @@ -1510,10 +1761,12 @@
- struct move_ent *move = NULL;
- action_data.name = dir_ent->name;
- - action_data.pathname = pathname(dir_ent);
- - action_data.subpath = subpathname(dir_ent);
- + action_data.pathname = strdup(pathname(dir_ent));
- + action_data.subpath = strdup(subpathname(dir_ent));
- action_data.buf = &dir_ent->inode->buf;
- action_data.depth = dir_ent->our_dir->depth;
- + action_data.dir_ent = dir_ent;
- + action_data.root = root;
- /*
- * Evaluate each move action against the current file. For any
- @@ -1526,7 +1779,7 @@
- */
- for (i = 0; i < move_count; i++) {
- struct action *action = &move_spec[i];
- - int match = eval_expr(action->expr, &action_data);
- + int match = eval_expr_top(action, &action_data);
- if(match) {
- if(move == NULL) {
- @@ -1553,7 +1806,7 @@
- */
- if(move->ops == 0) {
- free(move);
- - return;
- + goto finish;
- }
- dest = (move->ops & ACTION_MOVE_MOVE) ?
- @@ -1568,7 +1821,7 @@
- action_data.subpath, conf_path);
- free(conf_path);
- free(move);
- - return;
- + goto finish;
- }
- /*
- @@ -1582,11 +1835,15 @@
- action_data.subpath, conf_path);
- free(conf_path);
- free(move);
- - return;
- + goto finish;
- }
- move->next = move_list;
- move_list = move;
- }
- +
- +finish:
- + free(action_data.pathname);
- + free(action_data.subpath);
- }
- @@ -1714,6 +1971,46 @@
- /*
- + * Prune specific action code
- + */
- +int prune_actions()
- +{
- + return prune_count;
- +}
- +
- +
- +int eval_prune_actions(struct dir_info *root, struct dir_ent *dir_ent)
- +{
- + int i, match = 0;
- + struct action_data action_data;
- +
- + action_data.name = dir_ent->name;
- + action_data.pathname = strdup(pathname(dir_ent));
- + action_data.subpath = strdup(subpathname(dir_ent));
- + action_data.buf = &dir_ent->inode->buf;
- + action_data.depth = dir_ent->our_dir->depth;
- + action_data.dir_ent = dir_ent;
- + action_data.root = root;
- +
- + for (i = 0; i < prune_count && !match; i++)
- + match = eval_expr_top(&prune_spec[i], &action_data);
- +
- + free(action_data.pathname);
- + free(action_data.subpath);
- +
- + return match;
- +}
- +
- +
- +/*
- + * Noop specific action code
- + */
- +static void noop_action(struct action *action, struct dir_ent *dir_ent)
- +{
- +}
- +
- +
- +/*
- * General test evaluation code
- */
- @@ -1768,13 +2065,13 @@
- switch (end[0]) {
- case 'g':
- case 'G':
- - *size *= 1024;
- + number *= 1024;
- case 'm':
- case 'M':
- - *size *= 1024;
- + number *= 1024;
- case 'k':
- case 'K':
- - *size *= 1024;
- + number *= 1024;
- if (end[1] != '\0') {
- *error = "Trailing junk after size specifier";
- @@ -1873,7 +2170,7 @@
- static int NAME##_fn(struct atom *atom, struct action_data *action_data) \
- { \
- /* test operates on MATCH file types only */ \
- - if (!(action_data->buf->st_mode & MATCH)) \
- + if (!file_type_match(action_data->buf->st_mode, MATCH)) \
- return 0; \
- \
- CODE \
- @@ -1992,6 +2289,12 @@
- FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
- }
- +/*
- + * Inode attribute test operations using generic
- + * TEST_VAR_FN(test name, file scope, attribute name) macro.
- + * This is for tests that do not need to be specially handled in any way.
- + * They just take a variable and compare it against a number.
- + */
- TEST_VAR_FN(filesize, ACTION_REG, action_data->buf->st_size)
- TEST_VAR_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
- @@ -2008,9 +2311,7 @@
- TEST_VAR_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
- -TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
- -
- -TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
- +TEST_VAR_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
- TEST_VAR_FN(depth, ACTION_ALL_LNK, action_data->depth)
- @@ -2036,6 +2337,98 @@
- TEST_VAR_RANGE_FN(depth, ACTION_ALL_LNK, action_data->depth)
- +TEST_VAR_RANGE_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
- +
- +/*
- + * uid specific test code
- + */
- +TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
- +
- +static int parse_uid_arg(struct test_entry *test, struct atom *atom)
- +{
- + struct test_number_arg *number;
- + long long size;
- + int range;
- + char *error;
- +
- + if(parse_number(atom->argv[0], &size, &range, &error)) {
- + /* managed to fully parse argument as a number */
- + if(size < 0 || size > (((long long) 1 << 32) - 1)) {
- + TEST_SYNTAX_ERROR(test, 1, "Numeric uid out of "
- + "range\n");
- + return 0;
- + }
- + } else {
- + /* couldn't parse (fully) as a number, is it a user name? */
- + struct passwd *uid = getpwnam(atom->argv[0]);
- + if(uid) {
- + size = uid->pw_uid;
- + range = NUM_EQ;
- + } else {
- + TEST_SYNTAX_ERROR(test, 1, "Invalid uid or unknown "
- + "user\n");
- + return 0;
- + }
- + }
- +
- + number = malloc(sizeof(*number));
- + if(number == NULL)
- + MEM_ERROR();
- +
- + number->range = range;
- + number->size= size;
- +
- + atom->data = number;
- +
- + return 1;
- +}
- +
- +
- +/*
- + * gid specific test code
- + */
- +TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
- +
- +static int parse_gid_arg(struct test_entry *test, struct atom *atom)
- +{
- + struct test_number_arg *number;
- + long long size;
- + int range;
- + char *error;
- +
- + if(parse_number(atom->argv[0], &size, &range, &error)) {
- + /* managed to fully parse argument as a number */
- + if(size < 0 || size > (((long long) 1 << 32) - 1)) {
- + TEST_SYNTAX_ERROR(test, 1, "Numeric gid out of "
- + "range\n");
- + return 0;
- + }
- + } else {
- + /* couldn't parse (fully) as a number, is it a group name? */
- + struct group *gid = getgrnam(atom->argv[0]);
- + if(gid) {
- + size = gid->gr_gid;
- + range = NUM_EQ;
- + } else {
- + TEST_SYNTAX_ERROR(test, 1, "Invalid gid or unknown "
- + "group\n");
- + return 0;
- + }
- + }
- +
- + number = malloc(sizeof(*number));
- + if(number == NULL)
- + MEM_ERROR();
- +
- + number->range = range;
- + number->size= size;
- +
- + atom->data = number;
- +
- + return 1;
- +}
- +
- +
- /*
- * Type test specific code
- */
- @@ -2116,6 +2509,7 @@
- char str[1024]; /* overflow safe */
- regerror(res, preg, str, 1024);
- + free(preg);
- TEST_SYNTAX_ERROR(test, 0, "invalid regex \"%s\" because "
- "\"%s\"\n", atom->argv[0], str);
- return 0;
- @@ -2265,37 +2659,583 @@
- }
- +/*
- + * Symbolic link specific test code
- + */
- +
- +/*
- + * Walk the supplied pathname and return the directory entry corresponding
- + * to the pathname. If any symlinks are encountered whilst walking the
- + * pathname, then recursively walk these, to obtain the fully
- + * dereferenced canonicalised directory entry.
- + *
- + * If follow_path fails to walk a pathname either because a component
- + * doesn't exist, it is a non directory component when a directory
- + * component is expected, a symlink with an absolute path is encountered,
- + * or a symlink is encountered which cannot be recursively walked due to
- + * the above failures, then return NULL.
- + */
- +static struct dir_ent *follow_path(struct dir_info *dir, char *pathname)
- +{
- + char *comp, *path = pathname;
- + struct dir_ent *dir_ent = NULL;
- +
- + /* We cannot follow absolute paths */
- + if(pathname[0] == '/')
- + return NULL;
- +
- + for(comp = get_comp(&path); comp; free(comp), comp = get_comp(&path)) {
- + if(strcmp(comp, ".") == 0)
- + continue;
- +
- + if(strcmp(comp, "..") == 0) {
- + /* Move to parent if we're not in the root directory */
- + if(dir->depth > 1) {
- + dir = dir->dir_ent->our_dir;
- + dir_ent = NULL; /* lazily eval at loop exit */
- + continue;
- + } else
- + /* Failed to walk pathname */
- + return NULL;
- + }
- +
- + /* Lookup comp in current directory */
- + dir_ent = lookup_comp(comp, dir);
- + if(dir_ent == NULL)
- + /* Doesn't exist, failed to walk pathname */
- + return NULL;
- +
- + if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFLNK) {
- + /* Symbolic link, try to walk it */
- + dir_ent = follow_path(dir, dir_ent->inode->symlink);
- + if(dir_ent == NULL)
- + /* Failed to follow symlink */
- + return NULL;
- + }
- +
- + if((dir_ent->inode->buf.st_mode & S_IFMT) != S_IFDIR)
- + /* Cannot walk further */
- + break;
- +
- + dir = dir_ent->dir;
- + }
- +
- + /* We will have exited the loop either because we've processed
- + * all the components, which means we've successfully walked the
- + * pathname, or because we've hit a non-directory, in which case
- + * it's success if this is the leaf component */
- + if(comp) {
- + free(comp);
- + comp = get_comp(&path);
- + free(comp);
- + if(comp != NULL)
- + /* Not a leaf component */
- + return NULL;
- + } else {
- + /* Fully walked pathname, dir_ent contains correct value unless
- + * we've walked to the parent ("..") in which case we need
- + * to resolve it here */
- + if(!dir_ent)
- + dir_ent = dir->dir_ent;
- + }
- +
- + return dir_ent;
- +}
- +
- +
- +static int exists_fn(struct atom *atom, struct action_data *action_data)
- +{
- + /*
- + * Test if a symlink exists within the output filesystem, that is,
- + * the symlink has a relative path, and the relative path refers
- + * to an entry within the output filesystem.
- + *
- + * This test function evaluates the path for symlinks - that is it
- + * follows any symlinks in the path (and any symlinks that it contains
- + * etc.), to discover the fully dereferenced canonicalised relative
- + * path.
- + *
- + * If any symlinks within the path do not exist or are absolute
- + * then the symlink is considered to not exist, as it cannot be
- + * fully dereferenced.
- + *
- + * exists operates on symlinks only, other files by definition
- + * exist
- + */
- + if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
- + return 1;
- +
- + /* dereference the symlink, and return TRUE if it exists */
- + return follow_path(action_data->dir_ent->our_dir,
- + action_data->dir_ent->inode->symlink) ? 1 : 0;
- +}
- +
- +
- +static int absolute_fn(struct atom *atom, struct action_data *action_data)
- +{
- + /*
- + * Test if a symlink has an absolute path, which by definition
- + * means the symbolic link may be broken (even if the absolute path
- + * does point into the filesystem being squashed, because the resultant
- + * filesystem can be mounted/unsquashed anywhere, it is unlikely the
- + * absolute path will still point to the right place). If you know that
- + * an absolute symlink will point to the right place then you don't need
- + * to use this function, and/or these symlinks can be excluded by
- + * use of other test operators.
- + *
- + * absolute operates on symlinks only, other files by definition
- + * don't have problems
- + */
- + if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
- + return 0;
- +
- + return action_data->dir_ent->inode->symlink[0] == '/';
- +}
- +
- +
- +static int parse_expr_argX(struct test_entry *test, struct atom *atom,
- + int argno)
- +{
- + /* Call parse_expr to parse argument, which should be an expression */
- +
- + /* save the current parser state */
- + char *save_cur_ptr = cur_ptr;
- + char *save_source = source;
- +
- + cur_ptr = source = atom->argv[argno];
- + atom->data = parse_expr(0);
- +
- + cur_ptr = save_cur_ptr;
- + source = save_source;
- +
- + if(atom->data == NULL) {
- + /* parse_expr(0) will have reported the exact syntax error,
- + * but, because we recursively evaluated the expression, it
- + * will have been reported without the context of the stat
- + * test(). So here additionally report our failure to parse
- + * the expression in the stat() test to give context */
- + TEST_SYNTAX_ERROR(test, 0, "Failed to parse expression\n");
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- +
- +static int parse_expr_arg0(struct test_entry *test, struct atom *atom)
- +{
- + return parse_expr_argX(test, atom, 0);
- +}
- +
- +
- +static int parse_expr_arg1(struct test_entry *test, struct atom *atom)
- +{
- + return parse_expr_argX(test, atom, 1);
- +}
- +
- +
- +static int stat_fn(struct atom *atom, struct action_data *action_data)
- +{
- + struct stat buf;
- + struct action_data eval_action;
- + int match, res;
- +
- + /* evaluate the expression using the context of the inode
- + * pointed to by the symlink. This allows the inode attributes
- + * of the file pointed to by the symlink to be evaluated, rather
- + * than the symlink itself.
- + *
- + * Note, stat() deliberately does not evaluate the pathname, name or
- + * depth of the symlink, these are left with the symlink values.
- + * This allows stat() to be used on any symlink, rather than
- + * just symlinks which are contained (if the symlink is *not*
- + * contained then pathname, name and depth are meaningless as they
- + * are relative to the filesystem being squashed). */
- +
- + /* if this isn't a symlink then stat will just return the current
- + * information, i.e. stat(expr) == expr. This is harmless and
- + * is better than returning TRUE or FALSE in a non symlink case */
- + res = stat(action_data->pathname, &buf);
- + if(res == -1) {
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + expr_log_match(0);
- + expr_log(")");
- + }
- + return 0;
- + }
- +
- + /* fill in the inode values of the file pointed to by the
- + * symlink, but, leave everything else the same */
- + memcpy(&eval_action, action_data, sizeof(struct action_data));
- + eval_action.buf = &buf;
- +
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + match = eval_expr_log(atom->data, &eval_action);
- + expr_log(")");
- + } else
- + match = eval_expr(atom->data, &eval_action);
- +
- + return match;
- +}
- +
- +
- +static int readlink_fn(struct atom *atom, struct action_data *action_data)
- +{
- + int match = 0;
- + struct dir_ent *dir_ent;
- + struct action_data eval_action;
- +
- + /* Dereference the symlink and evaluate the expression in the
- + * context of the file pointed to by the symlink.
- + * All attributes are updated to refer to the file that is pointed to.
- + * Thus the inode attributes, pathname, name and depth all refer to
- + * the dereferenced file, and not the symlink.
- + *
- + * If the symlink cannot be dereferenced because it doesn't exist in
- + * the output filesystem, or due to some other failure to
- + * walk the pathname (see follow_path above), then FALSE is returned.
- + *
- + * If you wish to evaluate the inode attributes of symlinks which
- + * exist in the source filestem (but not in the output filesystem then
- + * use stat instead (see above).
- + *
- + * readlink operates on symlinks only */
- + if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
- + goto finish;
- +
- + /* dereference the symlink, and get the directory entry it points to */
- + dir_ent = follow_path(action_data->dir_ent->our_dir,
- + action_data->dir_ent->inode->symlink);
- + if(dir_ent == NULL)
- + goto finish;
- +
- + eval_action.name = dir_ent->name;
- + eval_action.pathname = strdup(pathname(dir_ent));
- + eval_action.subpath = strdup(subpathname(dir_ent));
- + eval_action.buf = &dir_ent->inode->buf;
- + eval_action.depth = dir_ent->our_dir->depth;
- + eval_action.dir_ent = dir_ent;
- + eval_action.root = action_data->root;
- +
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + match = eval_expr_log(atom->data, &eval_action);
- + expr_log(")");
- + } else
- + match = eval_expr(atom->data, &eval_action);
- +
- + free(eval_action.pathname);
- + free(eval_action.subpath);
- +
- + return match;
- +
- +finish:
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + expr_log_match(0);
- + expr_log(")");
- + }
- +
- + return 0;
- +}
- +
- +
- +static int eval_fn(struct atom *atom, struct action_data *action_data)
- +{
- + int match;
- + char *path = atom->argv[0];
- + struct dir_ent *dir_ent = action_data->dir_ent;
- + struct stat *buf = action_data->buf;
- + struct action_data eval_action;
- +
- + /* Follow path (arg1) and evaluate the expression (arg2)
- + * in the context of the file discovered. All attributes are updated
- + * to refer to the file that is pointed to.
- + *
- + * This test operation allows you to add additional context to the
- + * evaluation of the file being scanned, such as "if current file is
- + * XXX and the parent is YYY, then ..." Often times you need or
- + * want to test a combination of file status
- + *
- + * If the file referenced by the path does not exist in
- + * the output filesystem, or some other failure is experienced in
- + * walking the path (see follow_path above), then FALSE is returned.
- + *
- + * If you wish to evaluate the inode attributes of files which
- + * exist in the source filestem (but not in the output filesystem then
- + * use stat instead (see above). */
- +
- + /* try to follow path, and get the directory entry it points to */
- + if(path[0] == '/') {
- + /* absolute, walk from root - first skip the leading / */
- + while(path[0] == '/')
- + path ++;
- + if(path[0] == '\0')
- + dir_ent = action_data->root->dir_ent;
- + else
- + dir_ent = follow_path(action_data->root, path);
- + } else {
- + /* relative, if first component is ".." walk from parent,
- + * otherwise walk from dir_ent.
- + * Note: this has to be handled here because follow_path
- + * will quite correctly refuse to execute ".." on anything
- + * which isn't a directory */
- + if(strncmp(path, "..", 2) == 0 && (path[2] == '\0' ||
- + path[2] == '/')) {
- + /* walk from parent */
- + path += 2;
- + while(path[0] == '/')
- + path ++;
- + if(path[0] == '\0')
- + dir_ent = dir_ent->our_dir->dir_ent;
- + else
- + dir_ent = follow_path(dir_ent->our_dir, path);
- + } else if(!file_type_match(buf->st_mode, ACTION_DIR))
- + dir_ent = NULL;
- + else
- + dir_ent = follow_path(dir_ent->dir, path);
- + }
- +
- + if(dir_ent == NULL) {
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + expr_log(atom->argv[0]);
- + expr_log(",");
- + expr_log_match(0);
- + expr_log(")");
- + }
- +
- + return 0;
- + }
- +
- + eval_action.name = dir_ent->name;
- + eval_action.pathname = strdup(pathname(dir_ent));
- + eval_action.subpath = strdup(subpathname(dir_ent));
- + eval_action.buf = &dir_ent->inode->buf;
- + eval_action.depth = dir_ent->our_dir->depth;
- + eval_action.dir_ent = dir_ent;
- + eval_action.root = action_data->root;
- +
- + if(expr_log_cmnd(LOG_ENABLED)) {
- + expr_log(atom->test->name);
- + expr_log("(");
- + expr_log(eval_action.subpath);
- + expr_log(",");
- + match = eval_expr_log(atom->data, &eval_action);
- + expr_log(")");
- + } else
- + match = eval_expr(atom->data, &eval_action);
- +
- + free(eval_action.pathname);
- + free(eval_action.subpath);
- +
- + return match;
- +}
- +
- +
- +/*
- + * Perm specific test code
- + */
- +static int parse_perm_args(struct test_entry *test, struct atom *atom)
- +{
- + int res = 1, mode, op, i;
- + char *arg;
- + struct mode_data *head = NULL, *cur = NULL;
- + struct perm_data *perm_data;
- +
- + if(atom->args == 0) {
- + TEST_SYNTAX_ERROR(test, 0, "One or more arguments expected\n");
- + return 0;
- + }
- +
- + switch(atom->argv[0][0]) {
- + case '-':
- + op = PERM_ALL;
- + arg = atom->argv[0] + 1;
- + break;
- + case '/':
- + op = PERM_ANY;
- + arg = atom->argv[0] + 1;
- + break;
- + default:
- + op = PERM_EXACT;
- + arg = atom->argv[0];
- + break;
- + }
- +
- + /* try to parse as an octal number */
- + res = parse_octal_mode_args(atom->args, atom->argv, (void **) &head);
- + if(res == -1) {
- + /* parse as sym mode argument */
- + for(i = 0; i < atom->args && res; i++, arg = atom->argv[i])
- + res = parse_sym_mode_arg(arg, &head, &cur);
- + }
- +
- + if (res == 0)
- + goto finish;
- +
- + /*
- + * Evaluate the symbolic mode against a permission of 0000 octal
- + */
- + mode = mode_execute(head, 0);
- +
- + perm_data = malloc(sizeof(struct perm_data));
- + if (perm_data == NULL)
- + MEM_ERROR();
- +
- + perm_data->op = op;
- + perm_data->mode = mode;
- +
- + atom->data = perm_data;
- +
- +finish:
- + while(head) {
- + struct mode_data *tmp = head;
- + head = head->next;
- + free(tmp);
- + }
- +
- + return res;
- +}
- +
- +
- +static int perm_fn(struct atom *atom, struct action_data *action_data)
- +{
- + struct perm_data *perm_data = atom->data;
- + struct stat *buf = action_data->buf;
- +
- + switch(perm_data->op) {
- + case PERM_EXACT:
- + return (buf->st_mode & ~S_IFMT) == perm_data->mode;
- + case PERM_ALL:
- + return (buf->st_mode & perm_data->mode) == perm_data->mode;
- + case PERM_ANY:
- + default:
- + /*
- + * if no permission bits are set in perm_data->mode match
- + * on any file, this is to be consistent with find, which
- + * does this to be consistent with the behaviour of
- + * -perm -000
- + */
- + return perm_data->mode == 0 || (buf->st_mode & perm_data->mode);
- + }
- +}
- +
- +
- +#ifdef SQUASHFS_TRACE
- +static void dump_parse_tree(struct expr *expr)
- +{
- + int i;
- +
- + if(expr->type == ATOM_TYPE) {
- + printf("%s", expr->atom.test->name);
- + if(expr->atom.args) {
- + printf("(");
- + for(i = 0; i < expr->atom.args; i++) {
- + printf("%s", expr->atom.argv[i]);
- + if (i + 1 < expr->atom.args)
- + printf(",");
- + }
- + printf(")");
- + }
- + } else if (expr->type == UNARY_TYPE) {
- + printf("%s", token_table[expr->unary_op.op].string);
- + dump_parse_tree(expr->unary_op.expr);
- + } else {
- + printf("(");
- + dump_parse_tree(expr->expr_op.lhs);
- + printf("%s", token_table[expr->expr_op.op].string);
- + dump_parse_tree(expr->expr_op.rhs);
- + printf(")");
- + }
- +}
- +
- +
- +void dump_action_list(struct action *spec_list, int spec_count)
- +{
- + int i;
- +
- + for (i = 0; i < spec_count; i++) {
- + printf("%s", spec_list[i].action->name);
- + if (spec_list[i].args) {
- + int n;
- +
- + printf("(");
- + for (n = 0; n < spec_list[i].args; n++) {
- + printf("%s", spec_list[i].argv[n]);
- + if (n + 1 < spec_list[i].args)
- + printf(",");
- + }
- + printf(")");
- + }
- + printf("=");
- + dump_parse_tree(spec_list[i].expr);
- + printf("\n");
- + }
- +}
- +
- +
- +void dump_actions()
- +{
- + dump_action_list(exclude_spec, exclude_count);
- + dump_action_list(fragment_spec, fragment_count);
- + dump_action_list(other_spec, other_count);
- + dump_action_list(move_spec, move_count);
- + dump_action_list(empty_spec, empty_count);
- +}
- +#else
- +void dump_actions()
- +{
- +}
- +#endif
- +
- +
- static struct test_entry test_table[] = {
- - { "name", 1, name_fn},
- - { "pathname", 1, pathname_fn, check_pathname},
- - { "subpathname", 1, subpathname_fn, check_pathname},
- - { "filesize", 1, filesize_fn, parse_number_arg},
- - { "dirsize", 1, dirsize_fn, parse_number_arg},
- - { "size", 1, size_fn, parse_number_arg},
- - { "inode", 1, inode_fn, parse_number_arg},
- - { "nlink", 1, nlink_fn, parse_number_arg},
- - { "fileblocks", 1, fileblocks_fn, parse_number_arg},
- - { "dirblocks", 1, dirblocks_fn, parse_number_arg},
- - { "blocks", 1, blocks_fn, parse_number_arg},
- - { "gid", 1, gid_fn, parse_number_arg},
- - { "uid", 1, uid_fn, parse_number_arg},
- - { "depth", 1, depth_fn, parse_number_arg},
- - { "filesize_range", 2, filesize_range_fn, parse_range_args},
- - { "dirsize_range", 2, dirsize_range_fn, parse_range_args},
- - { "size_range", 2, size_range_fn, parse_range_args},
- - { "inode_range", 2, inode_range_fn, parse_range_args},
- - { "nlink_range", 2, nlink_range_fn, parse_range_args},
- - { "fileblocks_range", 2, fileblocks_range_fn, parse_range_args},
- - { "dirblocks_range", 2, dirblocks_range_fn, parse_range_args},
- - { "blocks_range", 2, blocks_range_fn, parse_range_args},
- - { "gid_range", 2, gid_range_fn, parse_range_args},
- - { "uid_range", 2, uid_range_fn, parse_range_args},
- - { "depth_range", 2, depth_range_fn, parse_range_args},
- - { "type", 1, type_fn, parse_type_arg},
- - { "true", 0, true_fn, NULL},
- - { "false", 0, false_fn, NULL},
- - { "file", 1, file_fn, parse_file_arg},
- - { "exec", 1, exec_fn, NULL},
- + { "name", 1, name_fn, NULL, 1},
- + { "pathname", 1, pathname_fn, check_pathname, 1, 0},
- + { "subpathname", 1, subpathname_fn, check_pathname, 1, 0},
- + { "filesize", 1, filesize_fn, parse_number_arg, 1, 0},
- + { "dirsize", 1, dirsize_fn, parse_number_arg, 1, 0},
- + { "size", 1, size_fn, parse_number_arg, 1, 0},
- + { "inode", 1, inode_fn, parse_number_arg, 1, 0},
- + { "nlink", 1, nlink_fn, parse_number_arg, 1, 0},
- + { "fileblocks", 1, fileblocks_fn, parse_number_arg, 1, 0},
- + { "dirblocks", 1, dirblocks_fn, parse_number_arg, 1, 0},
- + { "blocks", 1, blocks_fn, parse_number_arg, 1, 0},
- + { "gid", 1, gid_fn, parse_gid_arg, 1, 0},
- + { "uid", 1, uid_fn, parse_uid_arg, 1, 0},
- + { "depth", 1, depth_fn, parse_number_arg, 1, 0},
- + { "dircount", 1, dircount_fn, parse_number_arg, 0, 0},
- + { "filesize_range", 2, filesize_range_fn, parse_range_args, 1, 0},
- + { "dirsize_range", 2, dirsize_range_fn, parse_range_args, 1, 0},
- + { "size_range", 2, size_range_fn, parse_range_args, 1, 0},
- + { "inode_range", 2, inode_range_fn, parse_range_args, 1, 0},
- + { "nlink_range", 2, nlink_range_fn, parse_range_args, 1, 0},
- + { "fileblocks_range", 2, fileblocks_range_fn, parse_range_args, 1, 0},
- + { "dirblocks_range", 2, dirblocks_range_fn, parse_range_args, 1, 0},
- + { "blocks_range", 2, blocks_range_fn, parse_range_args, 1, 0},
- + { "gid_range", 2, gid_range_fn, parse_range_args, 1, 0},
- + { "uid_range", 2, uid_range_fn, parse_range_args, 1, 0},
- + { "depth_range", 2, depth_range_fn, parse_range_args, 1, 0},
- + { "dircount_range", 2, dircount_range_fn, parse_range_args, 0, 0},
- + { "type", 1, type_fn, parse_type_arg, 1, 0},
- + { "true", 0, true_fn, NULL, 1, 0},
- + { "false", 0, false_fn, NULL, 1, 0},
- + { "file", 1, file_fn, parse_file_arg, 1, 0},
- + { "exec", 1, exec_fn, NULL, 1, 0},
- + { "exists", 0, exists_fn, NULL, 0, 0},
- + { "absolute", 0, absolute_fn, NULL, 0, 0},
- + { "stat", 1, stat_fn, parse_expr_arg0, 1, 1},
- + { "readlink", 1, readlink_fn, parse_expr_arg0, 0, 1},
- + { "eval", 2, eval_fn, parse_expr_arg1, 0, 1},
- + { "perm", -2, perm_fn, parse_perm_args, 1, 0},
- { "", -1 }
- };
- @@ -2318,6 +3258,9 @@
- { "guid", GUID_ACTION, 2, ACTION_ALL_LNK, parse_guid_args, guid_action},
- { "mode", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
- { "empty", EMPTY_ACTION, -2, ACTION_DIR, parse_empty_args, NULL},
- - { "move", MOVE_ACTION, -2, ACTION_ALL_LNK, NULL, NULL},
- + { "move", MOVE_ACTION, 1, ACTION_ALL_LNK, NULL, NULL},
- + { "prune", PRUNE_ACTION, 0, ACTION_ALL_LNK, NULL, NULL},
- + { "chmod", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
- + { "noop", NOOP_ACTION, 0, ACTION_ALL, NULL, noop_action },
- { "", 0, -1, 0, NULL, NULL}
- };
- diff -Nru squashfs-tools-4.2+20130409/action.h squashfs-tools-4.3+20140919/action.h
- --- squashfs-tools-4.2+20130409/action.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/action.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef ACTION_H
- +#define ACTION_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2011, 2012, 2013
- + * Copyright (c) 2011, 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -72,6 +74,7 @@
- fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
- fprintf(stderr, "Syntax error: "S, ##ARGS); \
- fprintf(stderr, "Got here \"%s\"\n", src); \
- + free(src); \
- }
- #define TEST_SYNTAX_ERROR(TEST, ARG, S, ARGS...) { \
- @@ -81,6 +84,7 @@
- fprintf(stderr, "Syntax error in \"%s()\", arg %d: "S, TEST->name, \
- ARG, ##ARGS); \
- fprintf(stderr, "Got here \"%s\"\n", src); \
- + free(src); \
- }
- struct expr;
- @@ -94,6 +98,7 @@
- struct atom {
- struct test_entry *test;
- + int args;
- char **argv;
- void *data;
- };
- @@ -139,6 +144,8 @@
- int args;
- int (*fn)(struct atom *, struct action_data *);
- int (*parse_args)(struct test_entry *, struct atom *);
- + int exclude_ok;
- + int handle_logging;
- };
- @@ -168,15 +175,28 @@
- #define MODE_ACTION 11
- #define EMPTY_ACTION 12
- #define MOVE_ACTION 13
- +#define PRUNE_ACTION 14
- +#define NOOP_ACTION 15
- /*
- * Define what file types each action operates over
- */
- -#define ACTION_DIR S_IFDIR
- -#define ACTION_REG S_IFREG
- -#define ACTION_ALL_LNK (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | \
- - S_IFIFO | S_IFLNK)
- -#define ACTION_ALL (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | S_IFIFO)
- +#define ACTION_DIR 1
- +#define ACTION_REG 2
- +#define ACTION_ALL_LNK 3
- +#define ACTION_ALL 4
- +#define ACTION_LNK 5
- +
- +
- +/*
- + * Action logging requested, specified by the various
- + * -action, -true-action, -false-action and -verbose-action
- + * options
- + */
- +#define ACTION_LOG_NONE 0
- +#define ACTION_LOG_TRUE 1
- +#define ACTION_LOG_FALSE 2
- +#define ACTION_LOG_VERBOSE ACTION_LOG_TRUE | ACTION_LOG_FALSE
- struct action_entry {
- char *name;
- @@ -194,6 +214,8 @@
- char *pathname;
- char *subpath;
- struct stat *buf;
- + struct dir_ent *dir_ent;
- + struct dir_info *root;
- };
- @@ -204,6 +226,7 @@
- char **argv;
- struct expr *expr;
- void *data;
- + int verbose;
- };
- @@ -269,20 +292,37 @@
- /*
- + * Perm test function specific definitions
- + */
- +#define PERM_ALL 1
- +#define PERM_ANY 2
- +#define PERM_EXACT 3
- +
- +struct perm_data {
- + int op;
- + int mode;
- +};
- +
- +
- +/*
- * External function definitions
- */
- -extern int parse_action(char *);
- +extern int parse_action(char *, int verbose);
- extern void dump_actions();
- -extern void *eval_frag_actions(struct dir_ent *);
- +extern void *eval_frag_actions(struct dir_info *, struct dir_ent *);
- extern void *get_frag_action(void *);
- -extern int eval_exclude_actions(char *, char *, char *, struct stat *, int);
- -extern void eval_actions(struct dir_ent *);
- -extern int eval_empty_actions(struct dir_ent *dir_ent);
- +extern int eval_exclude_actions(char *, char *, char *, struct stat *, int,
- + struct dir_ent *);
- +extern void eval_actions(struct dir_info *, struct dir_ent *);
- +extern int eval_empty_actions(struct dir_info *, struct dir_ent *dir_ent);
- extern void eval_move_actions(struct dir_info *, struct dir_ent *);
- +extern int eval_prune_actions(struct dir_info *, struct dir_ent *);
- extern void do_move_actions();
- extern int read_bytes(int, void *, int);
- extern int actions();
- extern int move_actions();
- extern int empty_actions();
- -extern int read_action_file(char *);
- +extern int read_action_file(char *, int);
- extern int exclude_actions();
- +extern int prune_actions();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/caches-queues-lists.c squashfs-tools-4.3+20140919/caches-queues-lists.c
- --- squashfs-tools-4.2+20130409/caches-queues-lists.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/caches-queues-lists.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -25,12 +25,11 @@
- #include <pthread.h>
- #include <stdlib.h>
- #include <string.h>
- +#include <stdio.h>
- #include "error.h"
- #include "caches-queues-lists.h"
- -int first_freelist = 1;
- -
- extern int add_overflow(int, int);
- extern int multiply_overflow(int, int);
- @@ -98,37 +97,182 @@
- }
- -#define CALCULATE_HASH(start) (start & 0xffff) \
- +int queue_empty(struct queue *queue)
- +{
- + int empty;
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- -/* Called with the cache mutex held */
- -void insert_hash_table(struct cache *cache, struct file_buffer *entry)
- + empty = queue->readp == queue->writep;
- +
- + pthread_cleanup_pop(1);
- +
- + return empty;
- +}
- +
- +
- +void queue_flush(struct queue *queue)
- +{
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + queue->readp = queue->writep;
- +
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +void dump_queue(struct queue *queue)
- {
- - int hash = CALCULATE_HASH(entry->index);
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + printf("\tMax size %d, size %d%s\n", queue->size - 1,
- + queue->readp <= queue->writep ? queue->writep - queue->readp :
- + queue->size - queue->readp + queue->writep,
- + queue->readp == queue->writep ? " (EMPTY)" :
- + ((queue->writep + 1) % queue->size) == queue->readp ?
- + " (FULL)" : "");
- - entry->hash_next = cache->hash_table[hash];
- - cache->hash_table[hash] = entry;
- - entry->hash_prev = NULL;
- - if(entry->hash_next)
- - entry->hash_next->hash_prev = entry;
- + pthread_cleanup_pop(1);
- }
- +/* define seq queue hash tables */
- +#define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N)
- +
- +/* Called with the seq queue mutex held */
- +INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq)
- +
- /* Called with the cache mutex held */
- -void remove_hash_table(struct cache *cache, struct file_buffer *entry)
- +REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq);
- +
- +static unsigned int sequence = 0;
- +
- +
- +struct seq_queue *seq_queue_init()
- +{
- + struct seq_queue *queue = malloc(sizeof(struct seq_queue));
- + if(queue == NULL)
- + MEM_ERROR();
- +
- + memset(queue, 0, sizeof(struct seq_queue));
- +
- + pthread_mutex_init(&queue->mutex, NULL);
- + pthread_cond_init(&queue->wait, NULL);
- +
- + return queue;
- +}
- +
- +
- +void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry)
- {
- - if(entry->hash_prev)
- - entry->hash_prev->hash_next = entry->hash_next;
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + insert_seq_hash_table(queue, entry);
- +
- + if(entry->fragment)
- + queue->fragment_count ++;
- else
- - cache->hash_table[CALCULATE_HASH(entry->index)] =
- - entry->hash_next;
- - if(entry->hash_next)
- - entry->hash_next->hash_prev = entry->hash_prev;
- + queue->block_count ++;
- +
- + if(entry->sequence == sequence)
- + pthread_cond_signal(&queue->wait);
- - entry->hash_prev = entry->hash_next = NULL;
- + pthread_cleanup_pop(1);
- }
- +struct file_buffer *seq_queue_get(struct seq_queue *queue)
- +{
- + /*
- + * Look-up buffer matching sequence in the queue, if found return
- + * it, otherwise wait until it arrives
- + */
- + int hash = CALCULATE_SEQ_HASH(sequence);
- + struct file_buffer *entry;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + while(1) {
- + for(entry = queue->hash_table[hash]; entry;
- + entry = entry->seq_next)
- + if(entry->sequence == sequence)
- + break;
- +
- + if(entry) {
- + /*
- + * found the buffer in the queue, decrement the
- + * appropriate count, and remove from hash list
- + */
- + if(entry->fragment)
- + queue->fragment_count --;
- + else
- + queue->block_count --;
- +
- + remove_seq_hash_table(queue, entry);
- +
- + sequence ++;
- +
- + break;
- + }
- +
- + /* entry not found, wait for it to arrive */
- + pthread_cond_wait(&queue->wait, &queue->mutex);
- + }
- +
- + pthread_cleanup_pop(1);
- +
- + return entry;
- +}
- +
- +
- +void seq_queue_flush(struct seq_queue *queue)
- +{
- + int i;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + for(i = 0; i < HASH_SIZE; i++)
- + queue->hash_table[i] = NULL;
- +
- + queue->fragment_count = queue->block_count = 0;
- +
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +void dump_seq_queue(struct seq_queue *queue, int fragment_queue)
- +{
- + int size;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
- + pthread_mutex_lock(&queue->mutex);
- +
- + size = fragment_queue ? queue->fragment_count : queue->block_count;
- +
- + printf("\tMax size unlimited, size %d%s\n", size,
- + size == 0 ? " (EMPTY)" : "");
- +
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +/* define cache hash tables */
- +#define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N))
- +
- +/* Called with the cache mutex held */
- +INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash)
- +
- +/* Called with the cache mutex held */
- +REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash);
- +
- +/* define cache free list */
- +
- /* Called with the cache mutex held */
- INSERT_LIST(free, struct file_buffer)
- @@ -136,7 +280,8 @@
- REMOVE_LIST(free, struct file_buffer)
- -struct cache *cache_init(int buffer_size, int max_buffers)
- +struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup,
- + int first_freelist)
- {
- struct cache *cache = malloc(sizeof(struct cache));
- @@ -146,10 +291,38 @@
- cache->max_buffers = max_buffers;
- cache->buffer_size = buffer_size;
- cache->count = 0;
- + cache->used = 0;
- cache->free_list = NULL;
- +
- + /*
- + * The cache will grow up to max_buffers in size in response to
- + * an increase in readhead/number of buffers in flight. But
- + * once the outstanding buffers gets returned, we can either elect
- + * to shrink the cache, or to put the freed blocks onto a free list.
- + *
- + * For the caches where we want to do lookup (fragment/writer),
- + * a don't shrink policy is best, for the reader cache it
- + * makes no sense to keep buffers around longer than necessary as
- + * we don't do any lookup on those blocks.
- + */
- + cache->noshrink_lookup = noshrink_lookup;
- +
- + /*
- + * The default use freelist before growing cache policy behaves
- + * poorly with appending - with many duplicates the caches
- + * do not grow due to the fact that large queues of outstanding
- + * fragments/writer blocks do not occur, leading to small caches
- + * and un-uncessary performance loss to frequent cache
- + * replacement in the small caches. Therefore with appending
- + * change the policy to grow the caches before reusing blocks
- + * from the freelist
- + */
- + cache->first_freelist = first_freelist;
- +
- memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
- pthread_mutex_init(&cache->mutex, NULL);
- pthread_cond_init(&cache->wait_for_free, NULL);
- + pthread_cond_init(&cache->wait_for_unlock, NULL);
- return cache;
- }
- @@ -159,7 +332,7 @@
- {
- /* Lookup block in the cache, if found return with usage count
- * incremented, if not found return NULL */
- - int hash = CALCULATE_HASH(index);
- + int hash = CALCULATE_CACHE_HASH(index);
- struct file_buffer *entry;
- pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- @@ -173,8 +346,11 @@
- /* found the block in the cache, increment used count and
- * if necessary remove from free list so it won't disappear
- */
- + if(entry->used == 0) {
- + remove_free_list(&cache->free_list, entry);
- + cache->used ++;
- + }
- entry->used ++;
- - remove_free_list(&cache->free_list, entry);
- }
- pthread_cleanup_pop(1);
- @@ -183,50 +359,76 @@
- }
- -struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
- +static struct file_buffer *cache_freelist(struct cache *cache)
- {
- - /* Get a free block out of the cache indexed on index. */
- - struct file_buffer *entry;
- + struct file_buffer *entry = cache->free_list;
- +
- + remove_free_list(&cache->free_list, entry);
- +
- + /* a block on the free_list is hashed */
- + remove_cache_hash_table(cache, entry);
- + cache->used ++;
- + return entry;
- +}
- +
- +
- +static struct file_buffer *cache_alloc(struct cache *cache)
- +{
- + struct file_buffer *entry = malloc(sizeof(struct file_buffer) +
- + cache->buffer_size);
- + if(entry == NULL)
- + MEM_ERROR();
- +
- + entry->cache = cache;
- + entry->free_prev = entry->free_next = NULL;
- + cache->count ++;
- + return entry;
- +}
- +
- +
- +static struct file_buffer *_cache_get(struct cache *cache, long long index,
- + int hash)
- +{
- + /* Get a free block out of the cache indexed on index. */
- + struct file_buffer *entry = NULL;
- +
- pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- pthread_mutex_lock(&cache->mutex);
- while(1) {
- - /* first try to get a block from the free list */
- - if(first_freelist && cache->free_list) {
- - /* a block on the free_list is a "keep" block */
- - entry = cache->free_list;
- - remove_free_list(&cache->free_list, entry);
- - remove_hash_table(cache, entry);
- - break;
- - } else if(cache->count < cache->max_buffers) {
- - /* next try to allocate new block */
- - entry = malloc(sizeof(struct file_buffer) +
- - cache->buffer_size);
- - if(entry == NULL)
- - MEM_ERROR();
- - entry->cache = cache;
- - entry->free_prev = entry->free_next = NULL;
- - cache->count ++;
- - break;
- - } else if(!first_freelist && cache->free_list) {
- - /* a block on the free_list is a "keep" block */
- - entry = cache->free_list;
- - remove_free_list(&cache->free_list, entry);
- - remove_hash_table(cache, entry);
- + if(cache->noshrink_lookup) {
- + /* first try to get a block from the free list */
- + if(cache->first_freelist && cache->free_list)
- + entry = cache_freelist(cache);
- + else if(cache->count < cache->max_buffers) {
- + entry = cache_alloc(cache);
- + cache->used ++;
- + } else if(!cache->first_freelist && cache->free_list)
- + entry = cache_freelist(cache);
- + } else { /* shrinking non-lookup cache */
- + if(cache->count < cache->max_buffers) {
- + entry = cache_alloc(cache);
- + if(cache->count > cache->max_count)
- + cache->max_count = cache->count;
- + }
- + }
- +
- + if(entry)
- break;
- - } else
- - /* wait for a block */
- - pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
- +
- + /* wait for a block */
- + pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
- }
- - /* initialise block and if a keep block insert into the hash table */
- + /* initialise block and if hash is set insert into the hash table */
- entry->used = 1;
- + entry->locked = FALSE;
- + entry->wait_on_unlock = FALSE;
- entry->error = FALSE;
- - entry->keep = keep;
- - if(keep) {
- + if(hash) {
- entry->index = index;
- - insert_hash_table(cache, entry);
- + insert_cache_hash_table(cache, entry);
- }
- pthread_cleanup_pop(1);
- @@ -235,17 +437,28 @@
- }
- -void cache_rehash(struct file_buffer *entry, long long index)
- +struct file_buffer *cache_get(struct cache *cache, long long index)
- +{
- + return _cache_get(cache, index, 1);
- +}
- +
- +
- +struct file_buffer *cache_get_nohash(struct cache *cache)
- +{
- + return _cache_get(cache, 0, 0);
- +}
- +
- +
- +void cache_hash(struct file_buffer *entry, long long index)
- {
- struct cache *cache = entry->cache;
- pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- pthread_mutex_lock(&cache->mutex);
- - if(entry->keep)
- - remove_hash_table(cache, entry);
- - entry->keep = TRUE;
- +
- entry->index = index;
- - insert_hash_table(cache, entry);
- + insert_cache_hash_table(cache, entry);
- +
- pthread_cleanup_pop(1);
- }
- @@ -254,10 +467,16 @@
- {
- struct cache *cache;
- - /* finished with this cache entry, once the usage count reaches zero it
- - * can be reused and if a keep block put onto the free list. As keep
- - * blocks remain accessible via the hash table they can be found
- - * getting a new lease of life before they are reused. */
- + /*
- + * Finished with this cache entry, once the usage count reaches zero it
- + * can be reused.
- + *
- + * If noshrink_lookup is set, put the block onto the free list.
- + * As blocks remain accessible via the hash table they can be found
- + * getting a new lease of life before they are reused.
- + *
- + * if noshrink_lookup is not set then shrink the cache.
- + */
- if(entry == NULL)
- return;
- @@ -269,9 +488,10 @@
- entry->used --;
- if(entry->used == 0) {
- - if(entry->keep)
- + if(cache->noshrink_lookup) {
- insert_free_list(&cache->free_list, entry);
- - else {
- + cache->used --;
- + } else {
- free(entry);
- cache->count --;
- }
- @@ -281,4 +501,144 @@
- }
- pthread_cleanup_pop(1);
- +}
- +
- +
- +void dump_cache(struct cache *cache)
- +{
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- + pthread_mutex_lock(&cache->mutex);
- +
- + if(cache->noshrink_lookup)
- + printf("\tMax buffers %d, Current size %d, Used %d, %s\n",
- + cache->max_buffers, cache->count, cache->used,
- + cache->free_list ? "Free buffers" : "No free buffers");
- + else
- + printf("\tMax buffers %d, Current size %d, Maximum historical "
- + "size %d\n", cache->max_buffers, cache->count,
- + cache->max_count);
- +
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +struct file_buffer *cache_get_nowait(struct cache *cache, long long index)
- +{
- + struct file_buffer *entry = NULL;
- + /*
- + * block doesn't exist, create it, but return it with the
- + * locked flag set, so nothing tries to use it while it doesn't
- + * contain data.
- + *
- + * If there's no space in the cache then return NULL.
- + */
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- + pthread_mutex_lock(&cache->mutex);
- +
- + /* first try to get a block from the free list */
- + if(cache->first_freelist && cache->free_list)
- + entry = cache_freelist(cache);
- + else if(cache->count < cache->max_buffers) {
- + entry = cache_alloc(cache);
- + cache->used ++;
- + } else if(!cache->first_freelist && cache->free_list)
- + entry = cache_freelist(cache);
- +
- + if(entry) {
- + /* initialise block and insert into the hash table */
- + entry->used = 1;
- + entry->locked = TRUE;
- + entry->wait_on_unlock = FALSE;
- + entry->error = FALSE;
- + entry->index = index;
- + insert_cache_hash_table(cache, entry);
- + }
- +
- + pthread_cleanup_pop(1);
- +
- + return entry;
- +}
- +
- +
- +struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index,
- + char *locked)
- +{
- + /*
- + * Lookup block in the cache, if found return it with the locked flag
- + * indicating whether it is currently locked. In both cases increment
- + * the used count.
- + *
- + * If it doesn't exist in the cache return NULL;
- + */
- + int hash = CALCULATE_CACHE_HASH(index);
- + struct file_buffer *entry;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- + pthread_mutex_lock(&cache->mutex);
- +
- + /* first check if the entry already exists */
- + for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
- + if(entry->index == index)
- + break;
- +
- + if(entry) {
- + if(entry->used == 0) {
- + remove_free_list(&cache->free_list, entry);
- + cache->used ++;
- + }
- + entry->used ++;
- + *locked = entry->locked;
- + }
- +
- + pthread_cleanup_pop(1);
- +
- + return entry;
- +}
- +
- +
- +void cache_wait_unlock(struct file_buffer *buffer)
- +{
- + struct cache *cache = buffer->cache;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- + pthread_mutex_lock(&cache->mutex);
- +
- + while(buffer->locked) {
- + /*
- + * another thread is filling this in, wait until it
- + * becomes unlocked. Used has been incremented to ensure it
- + * doesn't get reused. By definition a block can't be
- + * locked and unused, and so we don't need to worry
- + * about it being on the freelist now, but, it may
- + * become unused when unlocked unless used is
- + * incremented
- + */
- + buffer->wait_on_unlock = TRUE;
- + pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex);
- + }
- +
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +void cache_unlock(struct file_buffer *entry)
- +{
- + struct cache *cache = entry->cache;
- +
- + /*
- + * Unlock this locked cache entry. If anything is waiting for this
- + * to become unlocked, wake it up.
- + */
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
- + pthread_mutex_lock(&cache->mutex);
- +
- + entry->locked = FALSE;
- +
- + if(entry->wait_on_unlock) {
- + entry->wait_on_unlock = FALSE;
- + pthread_cond_broadcast(&cache->wait_for_unlock);
- + }
- +
- + pthread_cleanup_pop(1);
- }
- diff -Nru squashfs-tools-4.2+20130409/caches-queues-lists.h squashfs-tools-4.3+20140919/caches-queues-lists.h
- --- squashfs-tools-4.2+20130409/caches-queues-lists.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/caches-queues-lists.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef CACHES_QUEUES_LISTS_H
- +#define CACHES_QUEUES_LISTS_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -22,24 +24,104 @@
- * caches-queues-lists.h
- */
- +#define INSERT_LIST(NAME, TYPE) \
- +void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
- + if(*list) { \
- + entry->NAME##_next = *list; \
- + entry->NAME##_prev = (*list)->NAME##_prev; \
- + (*list)->NAME##_prev->NAME##_next = entry; \
- + (*list)->NAME##_prev = entry; \
- + } else { \
- + *list = entry; \
- + entry->NAME##_prev = entry->NAME##_next = entry; \
- + } \
- +}
- +
- +
- +#define REMOVE_LIST(NAME, TYPE) \
- +void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
- + if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
- + /* only this entry in the list */ \
- + *list = NULL; \
- + } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
- + /* more than one entry in the list */ \
- + entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
- + entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
- + if(*list == entry) \
- + *list = entry->NAME##_next; \
- + } \
- + entry->NAME##_prev = entry->NAME##_next = NULL; \
- +}
- +
- +
- +#define INSERT_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
- +void insert_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
- +{ \
- + int hash = HASH_FUNCTION(entry->FIELD); \
- +\
- + entry->LINK##_next = container->hash_table[hash]; \
- + container->hash_table[hash] = entry; \
- + entry->LINK##_prev = NULL; \
- + if(entry->LINK##_next) \
- + entry->LINK##_next->LINK##_prev = entry; \
- +}
- +
- +
- +#define REMOVE_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
- +void remove_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
- +{ \
- + if(entry->LINK##_prev) \
- + entry->LINK##_prev->LINK##_next = entry->LINK##_next; \
- + else \
- + container->hash_table[HASH_FUNCTION(entry->FIELD)] = \
- + entry->LINK##_next; \
- + if(entry->LINK##_next) \
- + entry->LINK##_next->LINK##_prev = entry->LINK##_prev; \
- +\
- + entry->LINK##_prev = entry->LINK##_next = NULL; \
- +}
- +
- +#define HASH_SIZE 65536
- +#define CALCULATE_HASH(n) ((n) & 0xffff)
- +
- +
- /* struct describing a cache entry passed between threads */
- struct file_buffer {
- - struct cache *cache;
- - struct file_buffer *hash_next;
- - struct file_buffer *hash_prev;
- - struct file_buffer *free_next;
- - struct file_buffer *free_prev;
- - struct file_buffer *next;
- + union {
- + long long index;
- + long long sequence;
- + };
- long long file_size;
- - long long index;
- - long long block;
- - long long sequence;
- + union {
- + long long block;
- + unsigned short checksum;
- + };
- + struct cache *cache;
- + union {
- + struct file_info *dupl_start;
- + struct file_buffer *hash_next;
- + };
- + union {
- + int duplicate;
- + struct file_buffer *hash_prev;
- + };
- + union {
- + struct {
- + struct file_buffer *free_next;
- + struct file_buffer *free_prev;
- + };
- + struct {
- + struct file_buffer *seq_next;
- + struct file_buffer *seq_prev;
- + };
- + };
- int size;
- int c_byte;
- - char keep;
- char used;
- char fragment;
- char error;
- + char locked;
- + char wait_on_unlock;
- char noD;
- char data[0];
- };
- @@ -57,59 +139,62 @@
- };
- +/*
- + * struct describing seq_queues used to pass data between the read
- + * thread and the deflate and main threads
- + */
- +struct seq_queue {
- + int fragment_count;
- + int block_count;
- + struct file_buffer *hash_table[HASH_SIZE];
- + pthread_mutex_t mutex;
- + pthread_cond_t wait;
- +};
- +
- +
- /* Cache status struct. Caches are used to keep
- track of memory buffers passed between different threads */
- struct cache {
- int max_buffers;
- int count;
- int buffer_size;
- + int noshrink_lookup;
- + int first_freelist;
- + union {
- + int used;
- + int max_count;
- + };
- pthread_mutex_t mutex;
- pthread_cond_t wait_for_free;
- + pthread_cond_t wait_for_unlock;
- struct file_buffer *free_list;
- - struct file_buffer *hash_table[65536];
- + struct file_buffer *hash_table[HASH_SIZE];
- };
- -#define INSERT_LIST(NAME, TYPE) \
- -void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
- - if(*list) { \
- - entry->NAME##_next = *list; \
- - entry->NAME##_prev = (*list)->NAME##_prev; \
- - (*list)->NAME##_prev->NAME##_next = entry; \
- - (*list)->NAME##_prev = entry; \
- - } else { \
- - *list = entry; \
- - entry->NAME##_prev = entry->NAME##_next = entry; \
- - } \
- -}
- -
- -
- -#define REMOVE_LIST(NAME, TYPE) \
- -void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
- - if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
- - /* only this entry in the list */ \
- - *list = NULL; \
- - } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
- - /* more than one entry in the list */ \
- - entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
- - entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
- - if(*list == entry) \
- - *list = entry->NAME##_next; \
- - } \
- - entry->NAME##_prev = entry->NAME##_next = NULL; \
- -}
- -
- extern struct queue *queue_init(int);
- extern void queue_put(struct queue *, void *);
- extern void *queue_get(struct queue *);
- -extern struct cache *cache_init(int, int);
- +extern int queue_empty(struct queue *);
- +extern void queue_flush(struct queue *);
- +extern void dump_queue(struct queue *);
- +extern struct seq_queue *seq_queue_init();
- +extern void seq_queue_put(struct seq_queue *, struct file_buffer *);
- +extern void dump_seq_queue(struct seq_queue *, int);
- +extern struct file_buffer *seq_queue_get(struct seq_queue *);
- +extern void seq_queue_flush(struct seq_queue *);
- +extern struct cache *cache_init(int, int, int, int);
- extern struct file_buffer *cache_lookup(struct cache *, long long);
- -extern struct file_buffer *cache_get(struct cache *, long long, int);
- -extern void cache_rehash(struct file_buffer *, long long);
- +extern struct file_buffer *cache_get(struct cache *, long long);
- +extern struct file_buffer *cache_get_nohash(struct cache *);
- +extern void cache_hash(struct file_buffer *, long long);
- extern void cache_block_put(struct file_buffer *);
- -
- -//extern void insert_free_list(struct file_buffer **, struct file_buffer *);
- -//extern void remove_free_list(struct file_buffer **, struct file_buffer *);
- +extern void dump_cache(struct cache *);
- +extern struct file_buffer *cache_get_nowait(struct cache *, long long);
- +extern struct file_buffer *cache_lookup_nowait(struct cache *, long long,
- + char *);
- +extern void cache_wait_unlock(struct file_buffer *);
- +extern void cache_unlock(struct file_buffer *);
- extern int first_freelist;
- -
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/compressor.c squashfs-tools-4.3+20140919/compressor.c
- --- squashfs-tools-4.2+20130409/compressor.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/compressor.c 2015-07-20 21:03:05.000000000 +0200
- @@ -49,6 +49,14 @@
- extern struct compressor lzo_comp_ops;
- #endif
- +#ifndef LZ4_SUPPORT
- +static struct compressor lz4_comp_ops = {
- + LZ4_COMPRESSION, "lz4"
- +};
- +#else
- +extern struct compressor lz4_comp_ops;
- +#endif
- +
- #ifndef XZ_SUPPORT
- static struct compressor xz_comp_ops = {
- XZ_COMPRESSION, "xz"
- @@ -67,6 +75,7 @@
- &gzip_comp_ops,
- &lzma_comp_ops,
- &lzo_comp_ops,
- + &lz4_comp_ops,
- &xz_comp_ops,
- &unknown_comp_ops
- };
- diff -Nru squashfs-tools-4.2+20130409/compressor.h squashfs-tools-4.3+20140919/compressor.h
- --- squashfs-tools-4.2+20130409/compressor.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/compressor.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,6 +1,8 @@
- +#ifndef COMPRESSOR_H
- +#define COMPRESSOR_H
- /*
- *
- - * Copyright (c) 2009, 2010, 2011, 2012, 2013
- + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -31,6 +33,7 @@
- int (*options_post)(int);
- void *(*dump_options)(int, int *);
- int (*extract_options)(int, void *, int);
- + int (*check_options)(int, void *, int);
- void (*display_options)(void *, int);
- void (*usage)();
- };
- @@ -64,9 +67,8 @@
- /*
- - * For the following functions, please see xz_wrapper.c for
- - * commented examples of how they are used (xz is currently
- - * the only compressor that uses compression options).
- + * For the following functions please see the lzo, lz4 or xz
- + * compressors for commented examples of how they are used.
- */
- static inline int compressor_options(struct compressor *comp, char *argv[],
- int argc)
- @@ -104,9 +106,19 @@
- }
- +static inline int compressor_check_options(struct compressor *comp,
- + int block_size, void *buffer, int size)
- +{
- + if(comp->check_options == NULL)
- + return 0;
- + return comp->check_options(block_size, buffer, size);
- +}
- +
- +
- static inline void compressor_display_options(struct compressor *comp,
- void *buffer, int size)
- {
- if(comp->display_options != NULL)
- comp->display_options(buffer, size);
- }
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/debian/changelog squashfs-tools-4.3+20140919/debian/changelog
- --- squashfs-tools-4.2+20130409/debian/changelog 2013-09-18 10:22:27.000000000 +0200
- +++ squashfs-tools-4.3+20140919/debian/changelog 2015-07-20 22:44:05.000000000 +0200
- @@ -1,3 +1,11 @@
- +squashfs-tools (1:4.3+20140919-0) unstable; urgency=low
- +
- + * Merging upstream version 4.3+20140919.
- + * Fix for CVE 2015-4645/4646
- + * Updates man pages
- +
- + -- Romeo Papa <romeopapa@caramail.com> Mon, 20 Jul 2015 21:28:12 +0200
- +
- squashfs-tools (1:4.2+20130409-2) unstable; urgency=low
- * New maintainer (closes: #723600).
- diff -Nru squashfs-tools-4.2+20130409/debian/manpages/mksquashfs.1 squashfs-tools-4.3+20140919/debian/manpages/mksquashfs.1
- --- squashfs-tools-4.2+20130409/debian/manpages/mksquashfs.1 2013-05-09 22:22:49.000000000 +0200
- +++ squashfs-tools-4.3+20140919/debian/manpages/mksquashfs.1 2015-07-20 22:44:05.000000000 +0200
- @@ -1,4 +1,4 @@
- -.TH MKSQUASHFS 1 "2012\-06\-30" "4.2" "create and append squashfs filesystems"
- +.TH MKSQUASHFS 1 "2014\-05\-13" "4.3" "create and append squashfs filesystems"
- .SH NAME
- mksquashfs \- tool to create and append to squashfs filesystems
- @@ -15,9 +15,9 @@
- .SS Filesystem build options
- .IP "\-comp \fICOMPRESSION\fR" 4
- -select \fICOMPRESSION\fR compression. Compressors available: gzip (default), lzo, xz.
- +select \fICOMPRESSION\fR compression. Compressors available: gzip (default), lzma (no kernel support), lzo, lz4 and xz.
- .IP "\-b \fIBLOCK_SIZE\fR"
- -set data block to \fIBLOCK_SIZE\fR. Default 131072 bytes.
- +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.
- .IP "\-no\-exports" 4
- don't make the filesystem exportable via NFS.
- .IP "\-no\-sparse" 4
- @@ -74,6 +74,8 @@
- .SS Mksquashfs runtime options:
- .IP "\-version" 4
- print version, licence and copyright message.
- +.IP "\-exit\-on\-error" 4
- +treat normally ignored errors as fatal.
- .IP "\-recover \fINAME\fR" 4
- recover filesystem data using recovery file \fINAME\fR.
- .IP "\-no\-recovery" 4
- @@ -82,14 +84,18 @@
- print files written to filesystem.
- .IP "\-no\-progress" 4
- don't display the progress bar.
- +.IP "\-progress" 4
- +display progress bar when using the \-info option.
- .IP "\-processors \fINUMBER\fR" 4
- Use \fINUMBER\fR processors. By default will use number of processors available.
- +.IP "\-mem \fISIZE\fR" 4
- +Use \fISIZE\fR physical memory. Optionally K or M can be used as a suffix for kilobytes or megabytes, respectively. Default 25% of memory.
- .IP "\-read\-queue \fISIZE\fR" 4
- -Set input queue to \fISIZE\fR Mbytes. Default 64 Mbytes.
- +Deprecated. Use \-mem instead.
- .IP "\-write\-queue \fISIZE\fR" 4
- -Set output queue to \fISIZE\fR Mbytes. Default 512 Mbytes.
- +Deprecated. Use \-mem instead.
- .IP "\-fragment\-queue \fISIZE\fR" 4
- -Set fragment queue to \fISIZE\fR Mbytes. Default 64 Mbytes.
- +Deprecated. Use \-mem instead.
- .SS Miscellaneous options
- .IP "\-root\-owned" 4
- @@ -102,11 +108,27 @@
- alternative name for \-noF.
- .IP "\-noXattrCompression" 4
- alternative name for \-noX.
- +.IP "\-Xhelp" 4
- +print compressor options for selected compressor
- .SS Compressors available and compressor specific options
- -.IP "gzip (no options) (default)"
- -.IP "lzo (no options)"
- -.IP "xz"
- +.IP "gzip (default)"
- +.IP "\-Xcompression-level \fIcompression\-level\fR" 4
- +\fIcompression\-level\fR should be 1 .. 9 (default 9)
- +.IP "\-Xwindow\-size \fIwindow\-size\fR" 4
- +\fIwindow\-size\fR should be 8 .. 15 (default 15)
- +.IP "\-Xstrategy strategy1,strategy2,...,strategyN" 4
- +Compress using strategy1,strategy2,...,strategyN in turn and choose the best compression. Available strategies: default, filtered, huffman_only, run_length_encoded and fixed
- +.IP "lzmz (no options) (no kernel support)" 4
- +.IP "lzo" 4
- +.IP "\-Xalgorithm \fIalgorithm\fR" 4
- +Where \fIalgorithm\fR is one of: lzo1x_1, lzo1x_1_11, lzo1x_1_12, lzo1x_1_15 or lzo1x_999. (default lzo1x_999)
- +.IP "\-Xcompression\-level \fIcompression\-level\fR" 4
- +\fIcompression\-level\fR should be 1 .. 9 (default 8)
- +.IP "lz4" 4
- +.IP "\-Xhc"
- +Compress using LZ4 High Compression
- +.IP "xz" 4
- .IP "\-Xbcj filter1,filter2,...,filterN" 4
- 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.
- .IP "\-Xdict\-size \fIDICT_SIZE\fR" 4
- @@ -119,6 +141,6 @@
- More information about mksquashfs and the squashfs filesystem can be found at <\fIhttp://squashfs.sourceforge.net/\fR>.
- .SH AUTHOR
- -squashfs was written by Phillip Lougher <\fIphillip@squashfs.org.uk\fR>.
- +squashfs was written by Phillip Lougher <\fIplougher@users.sourceforge.net\fR>.
- .PP
- -This manual page was written by Daniel Baumann <\fImail@daniel\-baumann.ch\fR>.
- +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.
- diff -Nru squashfs-tools-4.2+20130409/debian/manpages/unsquashfs.1 squashfs-tools-4.3+20140919/debian/manpages/unsquashfs.1
- --- squashfs-tools-4.2+20130409/debian/manpages/unsquashfs.1 2013-05-09 22:22:49.000000000 +0200
- +++ squashfs-tools-4.3+20140919/debian/manpages/unsquashfs.1 2015-07-20 22:44:05.000000000 +0200
- @@ -1,4 +1,4 @@
- -.TH UNSQUASHFS 1 "2012\-06\-30" "4.2" "uncompress squashfs filesystems"
- +.TH UNSQUASHFS 1 "2014\-05\-13" "4.3" "uncompress squashfs filesystems"
- .SH NAME
- mksquashfs \- tool to uncompress squashfs filesystems
- @@ -22,6 +22,8 @@
- don't extract xattrs in file system.
- .IP "\-x, \-xattrs" 4
- extract xattrs in file system (default).
- +.IP "\-u, \-user\-xattrs" 4
- +only extract user xattrs in file system. Enables extracting xattrs.
- .IP "\-p \fINUMBER\fR, \-processors \fINUMBER\fR" 4
- use \fINUMBER\fR processors. By default will use number of processors available.
- .IP "\-i, \-info" 4
- @@ -38,7 +40,7 @@
- display filesystem superblock information.
- .IP "\-e \fIEXTRACT_FILE\fR, \-ef \fIEXTRACT_FILE\fR" 4
- list of directories or files to extract. One per line.
- -.IP "\-da \fISIZE\fR, \-data-queue \fISIZE\fR" 4
- +.IP "\-da \fISIZE\fR, \-data\-queue \fISIZE\fR" 4
- Set data queue to \fISIZE\fR Mbytes. Default 256 Mbytes.
- .IP "\-fr \fISIZE\fR, \-frag\-queue \fISIZE\fR" 4
- Set fragment queue to \fISIZE\fR Mbytes. Default 256 Mbytes.
- @@ -47,7 +49,9 @@
- .SS Decompressors available
- .IP "gzip" 4
- +.IP "lzma" 4
- .IP "lzo" 4
- +.IP "lz4" 4
- .IP "xz" 4
- .SH SEE ALSO
- @@ -57,6 +61,6 @@
- More information about unsquashfs and the squashfs filesystem can be found at <\fIhttp://squashfs.sourceforge.net/\fR>.
- .SH AUTHOR
- -squashfs was written by Phillip Lougher <\fIphillip@squashfs.org.uk\fR>.
- +squashfs was written by Phillip Lougher <\fIplougher@users.sourceforge.net\fR>.
- .PP
- -This manual page was written by Daniel Baumann <\fImail@daniel\-baumann.ch\fR>.
- +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.
- diff -Nru squashfs-tools-4.2+20130409/debian/patches/0001-kfreebsd.patch squashfs-tools-4.3+20140919/debian/patches/0001-kfreebsd.patch
- --- squashfs-tools-4.2+20130409/debian/patches/0001-kfreebsd.patch 2013-05-09 22:25:25.000000000 +0200
- +++ squashfs-tools-4.3+20140919/debian/patches/0001-kfreebsd.patch 1970-01-01 01:00:00.000000000 +0100
- @@ -1,103 +0,0 @@
- -Author: Cyril Brulebois <kibi@debian.org>
- -Description: Fixes FTBFS on kfreebsd (Closes: #557174).
- -
- -Index: squashfs-tools/mksquashfs.c
- -===================================================================
- ---- squashfs-tools.orig/mksquashfs.c 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/mksquashfs.c 2013-05-09 20:25:19.000000000 +0000
- -@@ -51,7 +51,7 @@
- - #include <limits.h>
- - #include <ctype.h>
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- -@@ -4038,7 +4038,7 @@
- - BAD_ERROR("Failed to set signal mask in intialise_threads\n");
- -
- - if(processors == -1) {
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - int mib[2];
- - size_t len = sizeof(processors);
- -
- -Index: squashfs-tools/read_fs.c
- -===================================================================
- ---- squashfs-tools.orig/read_fs.c 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/read_fs.c 2013-05-09 20:25:19.000000000 +0000
- -@@ -34,7 +34,7 @@
- - #include <sys/mman.h>
- - #include <limits.h>
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- -Index: squashfs-tools/read_xattrs.c
- -===================================================================
- ---- squashfs-tools.orig/read_xattrs.c 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/read_xattrs.c 2013-05-09 20:25:19.000000000 +0000
- -@@ -31,7 +31,7 @@
- - #include <stdio.h>
- - #include <string.h>
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- -Index: squashfs-tools/swap.c
- -===================================================================
- ---- squashfs-tools.orig/swap.c 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/swap.c 2013-05-09 20:25:19.000000000 +0000
- -@@ -19,7 +19,7 @@
- - * swap.c
- - */
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- -Index: squashfs-tools/unsquashfs.c
- -===================================================================
- ---- squashfs-tools.orig/unsquashfs.c 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/unsquashfs.c 2013-05-09 20:25:19.000000000 +0000
- -@@ -2104,7 +2104,7 @@
- - "\n");
- -
- - if(processors == -1) {
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - int mib[2];
- - size_t len = sizeof(processors);
- -
- -Index: squashfs-tools/unsquashfs.h
- -===================================================================
- ---- squashfs-tools.orig/unsquashfs.h 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/unsquashfs.h 2013-05-09 20:25:19.000000000 +0000
- -@@ -45,7 +45,7 @@
- - #include <sys/ioctl.h>
- - #include <sys/time.h>
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- -Index: squashfs-tools/xz_wrapper.h
- -===================================================================
- ---- squashfs-tools.orig/xz_wrapper.h 2013-05-09 20:25:19.000000000 +0000
- -+++ squashfs-tools/xz_wrapper.h 2013-05-09 20:25:19.000000000 +0000
- -@@ -24,7 +24,7 @@
- - *
- - */
- -
- --#ifndef linux
- -+#if !defined(linux) && !defined(__GLIBC__)
- - #define __BYTE_ORDER BYTE_ORDER
- - #define __BIG_ENDIAN BIG_ENDIAN
- - #define __LITTLE_ENDIAN LITTLE_ENDIAN
- diff -Nru squashfs-tools-4.2+20130409/debian/patches/cve-2015-4646 squashfs-tools-4.3+20140919/debian/patches/cve-2015-4646
- --- squashfs-tools-4.2+20130409/debian/patches/cve-2015-4646 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/debian/patches/cve-2015-4646 2015-07-20 22:29:13.000000000 +0200
- @@ -0,0 +1,47 @@
- +Description: CVE-2015-4645 integer overflow in read_fragment_table_4
- + Integer overflow issue was reported in squashfs-tools.
- + Following code in unsquash-4.c overflows the bytes variable, so that the allocation of fragments_bytes[] has an erroneous size.
- +
- + int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
- + ...
- + fragment_table = malloc(bytes)
- + .
- + squashfs-tools (1:4.3+20140919-0) unstable; urgency=low
- + .
- + * Fixes https://security-tracker.debian.org/tracker/CVE-2015-4645
- + * Fixes https://security-tracker.debian.org/tracker/CVE-2015-4646
- +
- +Author: Romeo Papa <romeopapa@caramail.com>
- +Origin: upstream, https://github.com/gcanalesb/sasquatch/commit/6777e08cc38bc780d27c69c1d8c272867b74524f
- +Bug: https://github.com/devttys0/sasquatch/pull/5
- +Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2015-4646
- +Bug-Fedora: http://people.canonical.com/~ubuntu-security/cve/2015/CVE-2015-4646.html
- +Last-Update: 2015-06-17
- +
- +--- squashfs-tools-4.3+20140919.orig/unsquash-4.c
- ++++ squashfs-tools-4.3+20140919/unsquash-4.c
- +@@ -31,9 +31,9 @@ static unsigned int *id_table;
- + int read_fragment_table_4(long long *directory_table_end)
- + {
- + int res, i;
- +- int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
- +- int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments);
- +- long long fragment_table_index[indexes];
- ++ size_t bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments);
- ++ size_t indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments);
- ++ long long *fragment_table_index;
- +
- + TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
- + "from 0x%llx\n", sBlk.s.fragments, indexes,
- +@@ -44,6 +44,11 @@ int read_fragment_table_4(long long *dir
- + return TRUE;
- + }
- +
- ++ fragment_table_index = malloc(indexes*sizeof(long long));
- ++ if(fragment_table_index == NULL)
- ++ EXIT_UNSQUASH("read_fragment_table: failed to allocate "
- ++ "fragment table index\n");
- ++
- + fragment_table = malloc(bytes);
- + if(fragment_table == NULL)
- + EXIT_UNSQUASH("read_fragment_table: failed to allocate "
- diff -Nru squashfs-tools-4.2+20130409/debian/patches/series squashfs-tools-4.3+20140919/debian/patches/series
- --- squashfs-tools-4.2+20130409/debian/patches/series 2013-05-09 22:22:49.000000000 +0200
- +++ squashfs-tools-4.3+20140919/debian/patches/series 2015-07-20 22:30:50.000000000 +0200
- @@ -1 +1 @@
- -0001-kfreebsd.patch
- +cve-2015-4646
- diff -Nru squashfs-tools-4.2+20130409/error.h squashfs-tools-4.3+20140919/error.h
- --- squashfs-tools-4.2+20130409/error.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/error.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef ERROR_H
- +#define ERROR_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2012, 2013
- + * Copyright (c) 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -22,6 +24,8 @@
- * error.h
- */
- +extern int exit_on_error;
- +
- extern void prep_exit();
- extern void progressbar_error(char *fmt, ...);
- extern void progressbar_info(char *fmt, ...);
- @@ -46,6 +50,23 @@
- progressbar_error(s, ## args); \
- } while(0)
- +#define ERROR_START(s, args...) \
- + do { \
- + disable_progress_bar(); \
- + fprintf(stderr, s, ## args); \
- + } while(0)
- +
- +#define ERROR_EXIT(s, args...) \
- + do {\
- + if (exit_on_error) { \
- + fprintf(stderr, "\n"); \
- + EXIT_MKSQUASHFS(); \
- + } else { \
- + fprintf(stderr, s, ## args); \
- + enable_progress_bar(); \
- + } \
- + } while(0)
- +
- #define EXIT_MKSQUASHFS() \
- do {\
- prep_exit();\
- @@ -66,3 +87,4 @@
- __func__); \
- EXIT_MKSQUASHFS();\
- } while(0)
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/gzip_wrapper.c squashfs-tools-4.3+20140919/gzip_wrapper.c
- --- squashfs-tools-4.2+20130409/gzip_wrapper.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/gzip_wrapper.c 2015-07-20 21:03:05.000000000 +0200
- @@ -1,5 +1,5 @@
- /*
- - * Copyright (c) 2009, 2010, 2013
- + * Copyright (c) 2009, 2010, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -17,34 +17,376 @@
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * gzip_wrapper.c
- + *
- + * Support for ZLIB compression http://www.zlib.net
- */
- +#include <stdio.h>
- +#include <string.h>
- #include <stdlib.h>
- #include <zlib.h>
- #include "squashfs_fs.h"
- +#include "gzip_wrapper.h"
- #include "compressor.h"
- -static int gzip_init(void **strm, int block_size, int flags)
- +static struct strategy strategy[] = {
- + { "default", Z_DEFAULT_STRATEGY, 0 },
- + { "filtered", Z_FILTERED, 0 },
- + { "huffman_only", Z_HUFFMAN_ONLY, 0 },
- + { "run_length_encoded", Z_RLE, 0 },
- + { "fixed", Z_FIXED, 0 },
- + { NULL, 0, 0 }
- +};
- +
- +static int strategy_count = 0;
- +
- +/* default compression level */
- +static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
- +
- +/* default window size */
- +static int window_size = GZIP_DEFAULT_WINDOW_SIZE;
- +
- +/*
- + * This function is called by the options parsing code in mksquashfs.c
- + * to parse any -X compressor option.
- + *
- + * This function returns:
- + * >=0 (number of additional args parsed) on success
- + * -1 if the option was unrecognised, or
- + * -2 if the option was recognised, but otherwise bad in
- + * some way (e.g. invalid parameter)
- + *
- + * Note: this function sets internal compressor state, but does not
- + * pass back the results of the parsing other than success/failure.
- + * The gzip_dump_options() function is called later to get the options in
- + * a format suitable for writing to the filesystem.
- + */
- +static int gzip_options(char *argv[], int argc)
- {
- - int res;
- - z_stream *stream;
- + if(strcmp(argv[0], "-Xcompression-level") == 0) {
- + if(argc < 2) {
- + fprintf(stderr, "gzip: -Xcompression-level missing "
- + "compression level\n");
- + fprintf(stderr, "gzip: -Xcompression-level it "
- + "should be 1 >= n <= 9\n");
- + goto failed;
- + }
- +
- + compression_level = atoi(argv[1]);
- + if(compression_level < 1 || compression_level > 9) {
- + fprintf(stderr, "gzip: -Xcompression-level invalid, it "
- + "should be 1 >= n <= 9\n");
- + goto failed;
- + }
- +
- + return 1;
- + } else if(strcmp(argv[0], "-Xwindow-size") == 0) {
- + if(argc < 2) {
- + fprintf(stderr, "gzip: -Xwindow-size missing window "
- + " size\n");
- + fprintf(stderr, "gzip: -Xwindow-size <window-size>\n");
- + goto failed;
- + }
- +
- + window_size = atoi(argv[1]);
- + if(window_size < 8 || window_size > 15) {
- + fprintf(stderr, "gzip: -Xwindow-size invalid, it "
- + "should be 8 >= n <= 15\n");
- + goto failed;
- + }
- +
- + return 1;
- + } else if(strcmp(argv[0], "-Xstrategy") == 0) {
- + char *name;
- + int i;
- +
- + if(argc < 2) {
- + fprintf(stderr, "gzip: -Xstrategy missing "
- + "strategies\n");
- + goto failed;
- + }
- +
- + name = argv[1];
- + while(name[0] != '\0') {
- + for(i = 0; strategy[i].name; i++) {
- + int n = strlen(strategy[i].name);
- + if((strncmp(name, strategy[i].name, n) == 0) &&
- + (name[n] == '\0' ||
- + name[n] == ',')) {
- + if(strategy[i].selected == 0) {
- + strategy[i].selected = 1;
- + strategy_count++;
- + }
- + name += name[n] == ',' ? n + 1 : n;
- + break;
- + }
- + }
- + if(strategy[i].name == NULL) {
- + fprintf(stderr, "gzip: -Xstrategy unrecognised "
- + "strategy\n");
- + goto failed;
- + }
- + }
- +
- + return 1;
- + }
- +
- + return -1;
- +
- +failed:
- + return -2;
- +}
- +
- +
- +/*
- + * This function is called after all options have been parsed.
- + * It is used to do post-processing on the compressor options using
- + * values that were not expected to be known at option parse time.
- + *
- + * This function returns 0 on successful post processing, or
- + * -1 on error
- + */
- +static int gzip_options_post(int block_size)
- +{
- + if(strategy_count == 1 && strategy[0].selected) {
- + strategy_count = 0;
- + strategy[0].selected = 0;
- + }
- +
- + return 0;
- +}
- +
- +
- +/*
- + * This function is called by mksquashfs to dump the parsed
- + * compressor options in a format suitable for writing to the
- + * compressor options field in the filesystem (stored immediately
- + * after the superblock).
- + *
- + * This function returns a pointer to the compression options structure
- + * to be stored (and the size), or NULL if there are no compression
- + * options
- + *
- + */
- +static void *gzip_dump_options(int block_size, int *size)
- +{
- + static struct gzip_comp_opts comp_opts;
- + int i, strategies = 0;
- +
- + /*
- + * If default compression options of:
- + * compression-level: 8 and
- + * window-size: 15 and
- + * strategy_count == 0 then
- + * don't store a compression options structure (this is compatible
- + * with the legacy implementation of GZIP for Squashfs)
- + */
- + if(compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL &&
- + window_size == GZIP_DEFAULT_WINDOW_SIZE &&
- + strategy_count == 0)
- + return NULL;
- +
- + for(i = 0; strategy[i].name; i++)
- + strategies |= strategy[i].selected << i;
- +
- + comp_opts.compression_level = compression_level;
- + comp_opts.window_size = window_size;
- + comp_opts.strategy = strategies;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
- +
- + *size = sizeof(comp_opts);
- + return &comp_opts;
- +}
- +
- +
- +/*
- + * This function is a helper specifically for the append mode of
- + * mksquashfs. Its purpose is to set the internal compressor state
- + * to the stored compressor options in the passed compressor options
- + * structure.
- + *
- + * In effect this function sets up the compressor options
- + * to the same state they were when the filesystem was originally
- + * generated, this is to ensure on appending, the compressor uses
- + * the same compression options that were used to generate the
- + * original filesystem.
- + *
- + * Note, even if there are no compressor options, this function is still
- + * called with an empty compressor structure (size == 0), to explicitly
- + * set the default options, this is to ensure any user supplied
- + * -X options on the appending mksquashfs command line are over-ridden
- + *
- + * This function returns 0 on sucessful extraction of options, and
- + * -1 on error
- + */
- +static int gzip_extract_options(int block_size, void *buffer, int size)
- +{
- + struct gzip_comp_opts *comp_opts = buffer;
- + int i;
- +
- + if(size == 0) {
- + /* Set default values */
- + compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
- + window_size = GZIP_DEFAULT_WINDOW_SIZE;
- + strategy_count = 0;
- + return 0;
- + }
- +
- + /* we expect a comp_opts structure of sufficient size to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* Check comp_opts structure for correctness */
- + if(comp_opts->compression_level < 1 ||
- + comp_opts->compression_level > 9) {
- + fprintf(stderr, "gzip: bad compression level in "
- + "compression options structure\n");
- + goto failed;
- + }
- + compression_level = comp_opts->compression_level;
- - stream = *strm = malloc(sizeof(z_stream));
- - if(stream == NULL)
- + if(comp_opts->window_size < 8 ||
- + comp_opts->window_size > 15) {
- + fprintf(stderr, "gzip: bad window size in "
- + "compression options structure\n");
- goto failed;
- + }
- + window_size = comp_opts->window_size;
- +
- + strategy_count = 0;
- + for(i = 0; strategy[i].name; i++) {
- + if((comp_opts->strategy >> i) & 1) {
- + strategy[i].selected = 1;
- + strategy_count ++;
- + } else
- + strategy[i].selected = 0;
- + }
- +
- + return 0;
- +
- +failed:
- + fprintf(stderr, "gzip: error reading stored compressor options from "
- + "filesystem!\n");
- +
- + return -1;
- +}
- +
- +
- +void gzip_display_options(void *buffer, int size)
- +{
- + struct gzip_comp_opts *comp_opts = buffer;
- + int i, printed;
- +
- + /* we expect a comp_opts structure of sufficient size to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* Check comp_opts structure for correctness */
- + if(comp_opts->compression_level < 1 ||
- + comp_opts->compression_level > 9) {
- + fprintf(stderr, "gzip: bad compression level in "
- + "compression options structure\n");
- + goto failed;
- + }
- + printf("\tcompression-level %d\n", comp_opts->compression_level);
- +
- + if(comp_opts->window_size < 8 ||
- + comp_opts->window_size > 15) {
- + fprintf(stderr, "gzip: bad window size in "
- + "compression options structure\n");
- + goto failed;
- + }
- + printf("\twindow-size %d\n", comp_opts->window_size);
- +
- + for(i = 0, printed = 0; strategy[i].name; i++) {
- + if((comp_opts->strategy >> i) & 1) {
- + if(printed)
- + printf(", ");
- + else
- + printf("\tStrategies selected: ");
- + printf("%s", strategy[i].name);
- + printed = 1;
- + }
- + }
- +
- + if(!printed)
- + printf("\tStrategies selected: default\n");
- + else
- + printf("\n");
- +
- + return;
- +
- +failed:
- + fprintf(stderr, "gzip: error reading stored compressor options from "
- + "filesystem!\n");
- +}
- - stream->zalloc = Z_NULL;
- - stream->zfree = Z_NULL;
- - stream->opaque = 0;
- - res = deflateInit(stream, 9);
- +/*
- + * This function is called by mksquashfs to initialise the
- + * compressor, before compress() is called.
- + *
- + * This function returns 0 on success, and
- + * -1 on error
- + */
- +static int gzip_init(void **strm, int block_size, int datablock)
- +{
- + int i, j, res;
- + struct gzip_stream *stream;
- +
- + if(!datablock || !strategy_count) {
- + stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy));
- + if(stream == NULL)
- + goto failed;
- +
- + stream->strategies = 1;
- + stream->strategy[0].strategy = Z_DEFAULT_STRATEGY;
- + } else {
- + stream = malloc(sizeof(*stream) +
- + sizeof(struct gzip_strategy) * strategy_count);
- + if(stream == NULL)
- + goto failed;
- +
- + memset(stream->strategy, 0, sizeof(struct gzip_strategy) *
- + strategy_count);
- +
- + stream->strategies = strategy_count;
- +
- + for(i = 0, j = 0; strategy[i].name; i++) {
- + if(!strategy[i].selected)
- + continue;
- +
- + stream->strategy[j].strategy = strategy[i].strategy;
- + if(j) {
- + stream->strategy[j].buffer = malloc(block_size);
- + if(stream->strategy[j].buffer == NULL)
- + goto failed2;
- + }
- + j++;
- + }
- + }
- +
- + stream->stream.zalloc = Z_NULL;
- + stream->stream.zfree = Z_NULL;
- + stream->stream.opaque = 0;
- +
- + res = deflateInit2(&stream->stream, compression_level, Z_DEFLATED,
- + window_size, 8, stream->strategy[0].strategy);
- if(res != Z_OK)
- goto failed2;
- + *strm = stream;
- return 0;
- failed2:
- + for(i = 1; i < stream->strategies; i++)
- + free(stream->strategy[i].buffer);
- free(stream);
- failed:
- return -1;
- @@ -54,29 +396,51 @@
- static int gzip_compress(void *strm, void *d, void *s, int size, int block_size,
- int *error)
- {
- - int res;
- - z_stream *stream = strm;
- -
- - res = deflateReset(stream);
- - if(res != Z_OK)
- - goto failed;
- -
- - stream->next_in = s;
- - stream->avail_in = size;
- - stream->next_out = d;
- - stream->avail_out = block_size;
- + int i, res;
- + struct gzip_stream *stream = strm;
- + struct gzip_strategy *selected = NULL;
- +
- + stream->strategy[0].buffer = d;
- +
- + for(i = 0; i < stream->strategies; i++) {
- + struct gzip_strategy *strategy = &stream->strategy[i];
- +
- + res = deflateReset(&stream->stream);
- + if(res != Z_OK)
- + goto failed;
- +
- + stream->stream.next_in = s;
- + stream->stream.avail_in = size;
- + stream->stream.next_out = strategy->buffer;
- + stream->stream.avail_out = block_size;
- +
- + if(stream->strategies > 1) {
- + res = deflateParams(&stream->stream,
- + compression_level, strategy->strategy);
- + if(res != Z_OK)
- + goto failed;
- + }
- +
- + res = deflate(&stream->stream, Z_FINISH);
- + strategy->length = stream->stream.total_out;
- + if(res == Z_STREAM_END) {
- + if(!selected || selected->length > strategy->length)
- + selected = strategy;
- + } else if(res != Z_OK)
- + goto failed;
- + }
- - res = deflate(stream, Z_FINISH);
- - if(res == Z_STREAM_END)
- - /*
- - * Success, return the compressed size.
- - */
- - return (int) stream->total_out;
- - if(res == Z_OK)
- + if(!selected)
- /*
- * Output buffer overflow. Return out of buffer space
- */
- return 0;
- +
- + if(selected->buffer != d)
- + memcpy(d, selected->buffer, selected->length);
- +
- + return (int) selected->length;
- +
- failed:
- /*
- * All other errors return failure, with the compressor
- @@ -94,8 +458,29 @@
- res = uncompress(d, &bytes, s, size);
- - *error = res;
- - return res == Z_OK ? (int) bytes : -1;
- + if(res == Z_OK)
- + return (int) bytes;
- + else {
- + *error = res;
- + return -1;
- + }
- +}
- +
- +
- +void gzip_usage()
- +{
- + fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
- + fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
- + "%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL);
- + fprintf(stderr, "\t -Xwindow-size <window-size>\n");
- + fprintf(stderr, "\t\t<window-size> should be 8 .. 15 (default "
- + "%d)\n", GZIP_DEFAULT_WINDOW_SIZE);
- + fprintf(stderr, "\t -Xstrategy strategy1,strategy2,...,strategyN\n");
- + fprintf(stderr, "\t\tCompress using strategy1,strategy2,...,strategyN"
- + " in turn\n");
- + fprintf(stderr, "\t\tand choose the best compression.\n");
- + fprintf(stderr, "\t\tAvailable strategies: default, filtered, "
- + "huffman_only,\n\t\trun_length_encoded and fixed\n");
- }
- @@ -103,10 +488,13 @@
- .init = gzip_init,
- .compress = gzip_compress,
- .uncompress = gzip_uncompress,
- - .options = NULL,
- - .usage = NULL,
- + .options = gzip_options,
- + .options_post = gzip_options_post,
- + .dump_options = gzip_dump_options,
- + .extract_options = gzip_extract_options,
- + .display_options = gzip_display_options,
- + .usage = gzip_usage,
- .id = ZLIB_COMPRESSION,
- .name = "gzip",
- .supported = 1
- };
- -
- diff -Nru squashfs-tools-4.2+20130409/gzip_wrapper.h squashfs-tools-4.3+20140919/gzip_wrapper.h
- --- squashfs-tools-4.2+20130409/gzip_wrapper.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/gzip_wrapper.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,75 @@
- +#ifndef GZIP_WRAPPER_H
- +#define GZIP_WRAPPER_H
- +/*
- + * Squashfs
- + *
- + * Copyright (c) 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * gzip_wrapper.h
- + *
- + */
- +
- +#ifndef linux
- +#define __BYTE_ORDER BYTE_ORDER
- +#define __BIG_ENDIAN BIG_ENDIAN
- +#define __LITTLE_ENDIAN LITTLE_ENDIAN
- +#else
- +#include <endian.h>
- +#endif
- +
- +#if __BYTE_ORDER == __BIG_ENDIAN
- +extern unsigned int inswap_le16(unsigned short);
- +extern unsigned int inswap_le32(unsigned int);
- +
- +#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
- + (s)->compression_level = inswap_le32((s)->compression_level); \
- + (s)->window_size = inswap_le16((s)->window_size); \
- + (s)->strategy = inswap_le16((s)->strategy); \
- +}
- +#else
- +#define SQUASHFS_INSWAP_COMP_OPTS(s)
- +#endif
- +
- +/* Default compression */
- +#define GZIP_DEFAULT_COMPRESSION_LEVEL 9
- +#define GZIP_DEFAULT_WINDOW_SIZE 15
- +
- +struct gzip_comp_opts {
- + int compression_level;
- + short window_size;
- + short strategy;
- +};
- +
- +struct strategy {
- + char *name;
- + int strategy;
- + int selected;
- +};
- +
- +struct gzip_strategy {
- + int strategy;
- + int length;
- + void *buffer;
- +};
- +
- +struct gzip_stream {
- + z_stream stream;
- + int strategies;
- + struct gzip_strategy strategy[0];
- +};
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/info.c squashfs-tools-4.3+20140919/info.c
- --- squashfs-tools-4.2+20130409/info.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/info.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -35,55 +35,142 @@
- #include <dirent.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- +#include <string.h>
- #include "squashfs_fs.h"
- #include "mksquashfs.h"
- #include "error.h"
- +#include "progressbar.h"
- +#include "caches-queues-lists.h"
- static int silent = 0;
- -static struct dir_ent *dir_ent = NULL;
- +static struct dir_ent *ent = NULL;
- pthread_t info_thread;
- void disable_info()
- {
- - dir_ent = NULL;
- + ent = NULL;
- }
- -void update_info(struct dir_ent *ent)
- +void update_info(struct dir_ent *dir_ent)
- {
- - dir_ent = ent;
- + ent = dir_ent;
- +}
- +
- +
- +void print_filename()
- +{
- + struct dir_ent *dir_ent = ent;
- +
- + if(dir_ent == NULL)
- + return;
- +
- + if(dir_ent->our_dir->subpath[0] != '\0')
- + INFO("%s/%s\n", dir_ent->our_dir->subpath, dir_ent->name);
- + else
- + INFO("/%s\n", dir_ent->name);
- +}
- +
- +
- +void dump_state()
- +{
- + disable_progress_bar();
- +
- + printf("Queue and Cache status dump\n");
- + printf("===========================\n");
- +
- + printf("file buffer queue (reader thread -> deflate thread(s))\n");
- + dump_queue(to_deflate);
- +
- + printf("uncompressed fragment queue (reader thread -> fragment"
- + " thread(s))\n");
- + dump_queue(to_process_frag);
- +
- + printf("processed fragment queue (fragment thread(s) -> main"
- + " thread)\n");
- + dump_seq_queue(to_main, 1);
- +
- + printf("compressed block queue (deflate thread(s) -> main thread)\n");
- + dump_seq_queue(to_main, 0);
- +
- + printf("uncompressed packed fragment queue (main thread -> fragment"
- + " deflate thread(s))\n");
- + dump_queue(to_frag);
- +
- +
- + printf("locked frag queue (compressed frags waiting while multi-block"
- + " file is written)\n");
- + dump_queue(locked_fragment);
- +
- + printf("compressed block queue (main & fragment deflate threads(s) ->"
- + " writer thread)\n");
- + dump_queue(to_writer);
- +
- + printf("read cache (uncompressed blocks read by reader thread)\n");
- + dump_cache(reader_buffer);
- +
- + printf("block write cache (compressed blocks waiting for the writer"
- + " thread)\n");
- + dump_cache(bwriter_buffer);
- + printf("fragment write cache (compressed fragments waiting for the"
- + " writer thread)\n");
- + dump_cache(fwriter_buffer);
- +
- + printf("fragment cache (frags waiting to be compressed by fragment"
- + " deflate thread(s))\n");
- + dump_cache(fragment_buffer);
- +
- + printf("fragment reserve cache (avoids pipeline stall if frag cache"
- + " full in dup check)\n");
- + dump_cache(reserve_cache);
- +
- + enable_progress_bar();
- }
- void *info_thrd(void *arg)
- {
- sigset_t sigmask;
- - int sig, res;
- - char *subpath;
- + struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
- + int sig, waiting = 0;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGQUIT);
- + sigaddset(&sigmask, SIGHUP);
- while(1) {
- - sigwait(&sigmask, &sig);
- -
- - if(dir_ent == NULL)
- - continue;
- -
- - if(dir_ent->our_dir->subpath[0] != '\0')
- - res = asprintf(&subpath, "%s/%s",
- - dir_ent->our_dir->subpath, dir_ent->name);
- + if(waiting)
- + sig = sigtimedwait(&sigmask, NULL, ×pec);
- else
- - res = asprintf(&subpath, "/%s", dir_ent->name);
- -
- - if(res < 0)
- - printf("asprintf failed in info_thrd\n");
- + sig = sigwaitinfo(&sigmask, NULL);
- - INFO("%s\n", subpath);
- - free(subpath);
- + if(sig == -1) {
- + switch(errno) {
- + case EAGAIN:
- + /* interval timed out */
- + waiting = 0;
- + /* FALLTHROUGH */
- + case EINTR:
- + /* if waiting, the wait will be longer, but
- + that's OK */
- + continue;
- + default:
- + BAD_ERROR("sigtimedwait/sigwaitinfo failed "
- + "because %s\n", strerror(errno));
- + }
- + }
- +
- + if(sig == SIGQUIT && !waiting) {
- + print_filename();
- +
- + /* set one second interval period, if ^\ received
- + within then, dump queue and cache status */
- + waiting = 1;
- + } else
- + dump_state();
- }
- }
- diff -Nru squashfs-tools-4.2+20130409/info.h squashfs-tools-4.3+20140919/info.h
- --- squashfs-tools-4.2+20130409/info.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/info.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef INFO_H
- +#define INFO_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -23,5 +25,6 @@
- */
- extern void disable_info();
- -extern void update_info();
- +extern void update_info(struct dir_ent *);
- extern void init_info();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/lz4_wrapper.c squashfs-tools-4.3+20140919/lz4_wrapper.c
- --- squashfs-tools-4.2+20130409/lz4_wrapper.c 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/lz4_wrapper.c 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,283 @@
- +/*
- + * Copyright (c) 2013
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * lz4_wrapper.c
- + *
- + * Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html
- + */
- +
- +#include <stdio.h>
- +#include <string.h>
- +#include <stdlib.h>
- +#include <lz4.h>
- +#include <lz4hc.h>
- +
- +#include "squashfs_fs.h"
- +#include "lz4_wrapper.h"
- +#include "compressor.h"
- +
- +static int hc = 0;
- +
- +/*
- + * This function is called by the options parsing code in mksquashfs.c
- + * to parse any -X compressor option.
- + *
- + * This function returns:
- + * >=0 (number of additional args parsed) on success
- + * -1 if the option was unrecognised, or
- + * -2 if the option was recognised, but otherwise bad in
- + * some way (e.g. invalid parameter)
- + *
- + * Note: this function sets internal compressor state, but does not
- + * pass back the results of the parsing other than success/failure.
- + * The lz4_dump_options() function is called later to get the options in
- + * a format suitable for writing to the filesystem.
- + */
- +static int lz4_options(char *argv[], int argc)
- +{
- + if(strcmp(argv[0], "-Xhc") == 0) {
- + hc = 1;
- + return 0;
- + }
- +
- + return -1;
- +}
- +
- +
- +/*
- + * This function is called by mksquashfs to dump the parsed
- + * compressor options in a format suitable for writing to the
- + * compressor options field in the filesystem (stored immediately
- + * after the superblock).
- + *
- + * This function returns a pointer to the compression options structure
- + * to be stored (and the size), or NULL if there are no compression
- + * options
- + *
- + * Currently LZ4 always returns a comp_opts structure, with
- + * the version indicating LZ4_LEGACY stream fomat. This is to
- + * easily accomodate changes in the kernel code to different
- + * stream formats
- + */
- +static void *lz4_dump_options(int block_size, int *size)
- +{
- + static struct lz4_comp_opts comp_opts;
- +
- + comp_opts.version = LZ4_LEGACY;
- + comp_opts.flags = hc ? LZ4_HC : 0;
- + SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
- +
- + *size = sizeof(comp_opts);
- + return &comp_opts;
- +}
- +
- +
- +/*
- + * This function is a helper specifically for the append mode of
- + * mksquashfs. Its purpose is to set the internal compressor state
- + * to the stored compressor options in the passed compressor options
- + * structure.
- + *
- + * In effect this function sets up the compressor options
- + * to the same state they were when the filesystem was originally
- + * generated, this is to ensure on appending, the compressor uses
- + * the same compression options that were used to generate the
- + * original filesystem.
- + *
- + * Note, even if there are no compressor options, this function is still
- + * called with an empty compressor structure (size == 0), to explicitly
- + * set the default options, this is to ensure any user supplied
- + * -X options on the appending mksquashfs command line are over-ridden
- + *
- + * This function returns 0 on sucessful extraction of options, and
- + * -1 on error
- + */
- +static int lz4_extract_options(int block_size, void *buffer, int size)
- +{
- + struct lz4_comp_opts *comp_opts = buffer;
- +
- + /* we expect a comp_opts structure to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* we expect the stream format to be LZ4_LEGACY */
- + if(comp_opts->version != LZ4_LEGACY) {
- + fprintf(stderr, "lz4: unknown LZ4 version\n");
- + goto failed;
- + }
- +
- + /*
- + * Check compression flags, currently only LZ4_HC ("high compression")
- + * can be set.
- + */
- + if(comp_opts->flags == LZ4_HC)
- + hc = 1;
- + else if(comp_opts->flags != 0) {
- + fprintf(stderr, "lz4: unknown LZ4 flags\n");
- + goto failed;
- + }
- +
- + return 0;
- +
- +failed:
- + fprintf(stderr, "lz4: error reading stored compressor options from "
- + "filesystem!\n");
- +
- + return -1;
- +}
- +
- +
- +/*
- + * This function is a helper specifically for unsquashfs.
- + * Its purpose is to check that the compression options are
- + * understood by this version of LZ4.
- + *
- + * This is important for LZ4 because the format understood by the
- + * Linux kernel may change from the already obsolete legacy format
- + * currently supported.
- + *
- + * If this does happen, then this version of LZ4 will not be able to decode
- + * the newer format. So we need to check for this.
- + *
- + * This function returns 0 on sucessful checking of options, and
- + * -1 on error
- + */
- +static int lz4_check_options(int block_size, void *buffer, int size)
- +{
- + struct lz4_comp_opts *comp_opts = buffer;
- +
- + /* we expect a comp_opts structure to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* we expect the stream format to be LZ4_LEGACY */
- + if(comp_opts->version != LZ4_LEGACY) {
- + fprintf(stderr, "lz4: unknown LZ4 version\n");
- + goto failed;
- + }
- +
- + return 0;
- +
- +failed:
- + fprintf(stderr, "lz4: error reading stored compressor options from "
- + "filesystem!\n");
- + return -1;
- +}
- +
- +
- +void lz4_display_options(void *buffer, int size)
- +{
- + struct lz4_comp_opts *comp_opts = buffer;
- +
- + /* check passed comp opts struct is of the correct length */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* we expect the stream format to be LZ4_LEGACY */
- + if(comp_opts->version != LZ4_LEGACY) {
- + fprintf(stderr, "lz4: unknown LZ4 version\n");
- + goto failed;
- + }
- +
- + /*
- + * Check compression flags, currently only LZ4_HC ("high compression")
- + * can be set.
- + */
- + if(comp_opts->flags & ~LZ4_FLAGS_MASK) {
- + fprintf(stderr, "lz4: unknown LZ4 flags\n");
- + goto failed;
- + }
- +
- + if(comp_opts->flags & LZ4_HC)
- + printf("\tHigh Compression option specified (-Xhc)\n");
- +
- + return;
- +
- +failed:
- + fprintf(stderr, "lz4: error reading stored compressor options from "
- + "filesystem!\n");
- +}
- +
- +
- +static int lz4_compress(void *strm, void *dest, void *src, int size,
- + int block_size, int *error)
- +{
- + int res;
- +
- + if(hc)
- + res = LZ4_compressHC_limitedOutput(src, dest, size, block_size);
- + else
- + res = LZ4_compress_limitedOutput(src, dest, size, block_size);
- +
- + if(res == 0) {
- + /*
- + * Output buffer overflow. Return out of buffer space
- + */
- + return 0;
- + } else if(res < 0) {
- + /*
- + * All other errors return failure, with the compressor
- + * specific error code in *error
- + */
- + *error = res;
- + return -1;
- + }
- +
- + return res;
- +}
- +
- +
- +static int lz4_uncompress(void *dest, void *src, int size, int outsize,
- + int *error)
- +{
- + int res = LZ4_decompress_safe(src, dest, size, outsize);
- + if(res < 0) {
- + *error = res;
- + return -1;
- + }
- +
- + return res;
- +}
- +
- +
- +void lz4_usage()
- +{
- + fprintf(stderr, "\t -Xhc\n");
- + fprintf(stderr, "\t\tCompress using LZ4 High Compression\n");
- +}
- +
- +
- +struct compressor lz4_comp_ops = {
- + .compress = lz4_compress,
- + .uncompress = lz4_uncompress,
- + .options = lz4_options,
- + .dump_options = lz4_dump_options,
- + .extract_options = lz4_extract_options,
- + .check_options = lz4_check_options,
- + .display_options = lz4_display_options,
- + .usage = lz4_usage,
- + .id = LZ4_COMPRESSION,
- + .name = "lz4",
- + .supported = 1
- +};
- diff -Nru squashfs-tools-4.2+20130409/lz4_wrapper.h squashfs-tools-4.3+20140919/lz4_wrapper.h
- --- squashfs-tools-4.2+20130409/lz4_wrapper.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/lz4_wrapper.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,61 @@
- +#ifndef LZ4_WRAPPER_H
- +#define LZ4_WRAPPER_H
- +/*
- + * Squashfs
- + *
- + * Copyright (c) 2013
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * lz4_wrapper.h
- + *
- + */
- +
- +#ifndef linux
- +#define __BYTE_ORDER BYTE_ORDER
- +#define __BIG_ENDIAN BIG_ENDIAN
- +#define __LITTLE_ENDIAN LITTLE_ENDIAN
- +#else
- +#include <endian.h>
- +#endif
- +
- +#if __BYTE_ORDER == __BIG_ENDIAN
- +extern unsigned int inswap_le32(unsigned int);
- +
- +#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
- + (s)->version = inswap_le32((s)->version); \
- + (s)->flags = inswap_le32((s)->flags); \
- +}
- +#else
- +#define SQUASHFS_INSWAP_COMP_OPTS(s)
- +#endif
- +
- +/*
- + * Define the various stream formats recognised.
- + * Currently omly legacy stream format is supported by the
- + * kernel
- + */
- +#define LZ4_LEGACY 1
- +#define LZ4_FLAGS_MASK 1
- +
- +/* Define the compression flags recognised. */
- +#define LZ4_HC 1
- +
- +struct lz4_comp_opts {
- + int version;
- + int flags;
- +};
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/lzma_wrapper.c squashfs-tools-4.3+20140919/lzma_wrapper.c
- --- squashfs-tools-4.2+20130409/lzma_wrapper.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/lzma_wrapper.c 2015-07-20 21:03:05.000000000 +0200
- @@ -99,8 +99,12 @@
- res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src,
- LZMA_PROPS_SIZE);
- - *error = res;
- - return res == SZ_OK ? outlen : -1;
- + if(res == SZ_OK)
- + return outlen;
- + else {
- + *error = res;
- + return -1;
- + }
- }
- diff -Nru squashfs-tools-4.2+20130409/lzo_wrapper.c squashfs-tools-4.3+20140919/lzo_wrapper.c
- --- squashfs-tools-4.2+20130409/lzo_wrapper.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/lzo_wrapper.c 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,5 @@
- /*
- - * Copyright (c) 2010 LG Electronics
- - * Chan Jeong <chan.jeong@lge.com>
- - *
- - * All modifications Copyright (c) 2010, 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -20,44 +17,319 @@
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * lzo_wrapper.c
- + *
- + * Support for LZO compression http://www.oberhumer.com/opensource/lzo
- */
- -#include <stdlib.h>
- +#include <stdio.h>
- #include <string.h>
- -
- +#include <stdlib.h>
- #include <lzo/lzoconf.h>
- #include <lzo/lzo1x.h>
- #include "squashfs_fs.h"
- +#include "lzo_wrapper.h"
- #include "compressor.h"
- -/* worst-case expansion calculation during compression,
- - see LZO FAQ for more information */
- -#define LZO_OUTPUT_BUFFER_SIZE(size) (size + (size/16) + 64 + 3)
- -
- -struct lzo_stream {
- - lzo_voidp wrkmem;
- - lzo_bytep out;
- +static struct lzo_algorithm lzo[] = {
- + { "lzo1x_1", LZO1X_1_MEM_COMPRESS, lzo1x_1_compress },
- + { "lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS, lzo1x_1_11_compress },
- + { "lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS, lzo1x_1_12_compress },
- + { "lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS, lzo1x_1_15_compress },
- + { "lzo1x_999", LZO1X_999_MEM_COMPRESS, lzo1x_999_wrapper },
- + { NULL, 0, NULL }
- };
- +/* default LZO compression algorithm and compression level */
- +static int algorithm = SQUASHFS_LZO1X_999;
- +static int compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
- +
- +/* user specified compression level */
- +static int user_comp_level = -1;
- +
- +
- +/*
- + * This function is called by the options parsing code in mksquashfs.c
- + * to parse any -X compressor option.
- + *
- + * This function returns:
- + * >=0 (number of additional args parsed) on success
- + * -1 if the option was unrecognised, or
- + * -2 if the option was recognised, but otherwise bad in
- + * some way (e.g. invalid parameter)
- + *
- + * Note: this function sets internal compressor state, but does not
- + * pass back the results of the parsing other than success/failure.
- + * The lzo_dump_options() function is called later to get the options in
- + * a format suitable for writing to the filesystem.
- + */
- +static int lzo_options(char *argv[], int argc)
- +{
- + int i;
- +
- + if(strcmp(argv[0], "-Xalgorithm") == 0) {
- + if(argc < 2) {
- + fprintf(stderr, "lzo: -Xalgorithm missing algorithm\n");
- + fprintf(stderr, "lzo: -Xalgorithm <algorithm>\n");
- + goto failed2;
- + }
- +
- + for(i = 0; lzo[i].name; i++) {
- + if(strcmp(argv[1], lzo[i].name) == 0) {
- + algorithm = i;
- + return 1;
- + }
- + }
- +
- + fprintf(stderr, "lzo: -Xalgorithm unrecognised algorithm\n");
- + goto failed2;
- + } else if(strcmp(argv[0], "-Xcompression-level") == 0) {
- + if(argc < 2) {
- + fprintf(stderr, "lzo: -Xcompression-level missing "
- + "compression level\n");
- + fprintf(stderr, "lzo: -Xcompression-level it "
- + "should be 1 >= n <= 9\n");
- + goto failed;
- + }
- +
- + user_comp_level = atoi(argv[1]);
- + if(user_comp_level < 1 || user_comp_level > 9) {
- + fprintf(stderr, "lzo: -Xcompression-level invalid, it "
- + "should be 1 >= n <= 9\n");
- + goto failed;
- + }
- +
- + return 1;
- + }
- +
- + return -1;
- -static int squashfs_lzo_init(void **strm, int block_size, int flags)
- +failed:
- + return -2;
- +
- +failed2:
- + fprintf(stderr, "lzo: compression algorithm should be one of:\n");
- + for(i = 0; lzo[i].name; i++)
- + fprintf(stderr, "\t%s\n", lzo[i].name);
- + return -2;
- +}
- +
- +
- +/*
- + * This function is called after all options have been parsed.
- + * It is used to do post-processing on the compressor options using
- + * values that were not expected to be known at option parse time.
- + *
- + * In this case the LZO algorithm may not be known until after the
- + * compression level has been set (-Xalgorithm used after -Xcompression-level)
- + *
- + * This function returns 0 on successful post processing, or
- + * -1 on error
- + */
- +static int lzo_options_post(int block_size)
- +{
- + /*
- + * Use of compression level only makes sense for
- + * LZO1X_999 algorithm
- + */
- + if(user_comp_level != -1) {
- + if(algorithm != SQUASHFS_LZO1X_999) {
- + fprintf(stderr, "lzo: -Xcompression-level not "
- + "supported by selected %s algorithm\n",
- + lzo[algorithm].name);
- + fprintf(stderr, "lzo: -Xcompression-level is only "
- + "applicable for the lzo1x_999 algorithm\n");
- + goto failed;
- + }
- + compression_level = user_comp_level;
- + }
- +
- + return 0;
- +
- +failed:
- + return -1;
- +}
- +
- +
- +/*
- + * This function is called by mksquashfs to dump the parsed
- + * compressor options in a format suitable for writing to the
- + * compressor options field in the filesystem (stored immediately
- + * after the superblock).
- + *
- + * This function returns a pointer to the compression options structure
- + * to be stored (and the size), or NULL if there are no compression
- + * options
- + *
- + */
- +static void *lzo_dump_options(int block_size, int *size)
- +{
- + static struct lzo_comp_opts comp_opts;
- +
- + /*
- + * If default compression options of SQUASHFS_LZO1X_999 and
- + * compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then
- + * don't store a compression options structure (this is compatible
- + * with the legacy implementation of LZO for Squashfs)
- + */
- + if(algorithm == SQUASHFS_LZO1X_999 &&
- + compression_level == SQUASHFS_LZO1X_999_COMP_DEFAULT)
- + return NULL;
- +
- + comp_opts.algorithm = algorithm;
- + comp_opts.compression_level = algorithm == SQUASHFS_LZO1X_999 ?
- + compression_level : 0;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
- +
- + *size = sizeof(comp_opts);
- + return &comp_opts;
- +}
- +
- +
- +/*
- + * This function is a helper specifically for the append mode of
- + * mksquashfs. Its purpose is to set the internal compressor state
- + * to the stored compressor options in the passed compressor options
- + * structure.
- + *
- + * In effect this function sets up the compressor options
- + * to the same state they were when the filesystem was originally
- + * generated, this is to ensure on appending, the compressor uses
- + * the same compression options that were used to generate the
- + * original filesystem.
- + *
- + * Note, even if there are no compressor options, this function is still
- + * called with an empty compressor structure (size == 0), to explicitly
- + * set the default options, this is to ensure any user supplied
- + * -X options on the appending mksquashfs command line are over-ridden
- + *
- + * This function returns 0 on sucessful extraction of options, and
- + * -1 on error
- + */
- +static int lzo_extract_options(int block_size, void *buffer, int size)
- +{
- + struct lzo_comp_opts *comp_opts = buffer;
- +
- + if(size == 0) {
- + /* Set default values */
- + algorithm = SQUASHFS_LZO1X_999;
- + compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
- + return 0;
- + }
- +
- + /* we expect a comp_opts structure of sufficient size to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* Check comp_opts structure for correctness */
- + switch(comp_opts->algorithm) {
- + case SQUASHFS_LZO1X_1:
- + case SQUASHFS_LZO1X_1_11:
- + case SQUASHFS_LZO1X_1_12:
- + case SQUASHFS_LZO1X_1_15:
- + if(comp_opts->compression_level != 0) {
- + fprintf(stderr, "lzo: bad compression level in "
- + "compression options structure\n");
- + goto failed;
- + }
- + break;
- + case SQUASHFS_LZO1X_999:
- + if(comp_opts->compression_level < 1 ||
- + comp_opts->compression_level > 9) {
- + fprintf(stderr, "lzo: bad compression level in "
- + "compression options structure\n");
- + goto failed;
- + }
- + compression_level = comp_opts->compression_level;
- + break;
- + default:
- + fprintf(stderr, "lzo: bad algorithm in compression options "
- + "structure\n");
- + goto failed;
- + }
- +
- + algorithm = comp_opts->algorithm;
- +
- + return 0;
- +
- +failed:
- + fprintf(stderr, "lzo: error reading stored compressor options from "
- + "filesystem!\n");
- +
- + return -1;
- +}
- +
- +
- +void lzo_display_options(void *buffer, int size)
- +{
- + struct lzo_comp_opts *comp_opts = buffer;
- +
- + /* we expect a comp_opts structure of sufficient size to be present */
- + if(size < sizeof(*comp_opts))
- + goto failed;
- +
- + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- +
- + /* Check comp_opts structure for correctness */
- + switch(comp_opts->algorithm) {
- + case SQUASHFS_LZO1X_1:
- + case SQUASHFS_LZO1X_1_11:
- + case SQUASHFS_LZO1X_1_12:
- + case SQUASHFS_LZO1X_1_15:
- + printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
- + break;
- + case SQUASHFS_LZO1X_999:
- + if(comp_opts->compression_level < 1 ||
- + comp_opts->compression_level > 9) {
- + fprintf(stderr, "lzo: bad compression level in "
- + "compression options structure\n");
- + goto failed;
- + }
- + printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
- + printf("\tcompression level %d\n",
- + comp_opts->compression_level);
- + break;
- + default:
- + fprintf(stderr, "lzo: bad algorithm in compression options "
- + "structure\n");
- + goto failed;
- + }
- +
- + return;
- +
- +failed:
- + fprintf(stderr, "lzo: error reading stored compressor options from "
- + "filesystem!\n");
- +}
- +
- +
- +/*
- + * This function is called by mksquashfs to initialise the
- + * compressor, before compress() is called.
- + *
- + * This function returns 0 on success, and
- + * -1 on error
- + */
- +static int squashfs_lzo_init(void **strm, int block_size, int datablock)
- {
- struct lzo_stream *stream;
- - if((stream = *strm = malloc(sizeof(struct lzo_stream))) == NULL)
- + stream = *strm = malloc(sizeof(struct lzo_stream));
- + if(stream == NULL)
- goto failed;
- - /* work memory for compression */
- - if((stream->wrkmem = malloc(LZO1X_999_MEM_COMPRESS)) == NULL)
- +
- + stream->workspace = malloc(lzo[algorithm].size);
- + if(stream->workspace == NULL)
- goto failed2;
- - /* temporal output buffer */
- - if((stream->out = malloc(LZO_OUTPUT_BUFFER_SIZE(block_size))) == NULL)
- - goto failed3;
- - return 0;
- + stream->buffer = malloc(LZO_MAX_EXPANSION(block_size));
- + if(stream->buffer != NULL)
- + return 0;
- -failed3:
- - free(stream->wrkmem);
- + free(stream->workspace);
- failed2:
- free(stream);
- failed:
- @@ -65,47 +337,89 @@
- }
- -static int lzo_compress(void *strm, void *d, void *s, int size, int block_size,
- - int *error)
- +static int lzo_compress(void *strm, void *dest, void *src, int size,
- + int block_size, int *error)
- {
- int res;
- - lzo_uint outlen;
- + lzo_uint compsize, orig_size = size;
- struct lzo_stream *stream = strm;
- - res = lzo1x_999_compress(s, size, stream->out, &outlen, stream->wrkmem);
- + res = lzo[algorithm].compress(src, size, stream->buffer, &compsize,
- + stream->workspace);
- if(res != LZO_E_OK)
- - goto failed;
- - if(outlen >= size)
- - /*
- - * Output buffer overflow. Return out of buffer space
- - */
- - return 0;
- + goto failed;
- - /*
- - * Success, return the compressed size.
- + /* Successful compression, however, we need to check that
- + * the compressed size is not larger than the available
- + * buffer space. Normally in other compressor APIs they take
- + * a destination buffer size, and overflows return an error.
- + * With LZO it lacks a destination size and so we must output
- + * to a temporary buffer large enough to accomodate any
- + * result, and explictly check here for overflow
- */
- - memcpy(d, stream->out, outlen);
- - return outlen;
- + if(compsize > block_size)
- + return 0;
- +
- + res = lzo1x_optimize(stream->buffer, compsize, src, &orig_size, NULL);
- +
- + if (res != LZO_E_OK || orig_size != size)
- + goto failed;
- +
- + memcpy(dest, stream->buffer, compsize);
- + return compsize;
- failed:
- - /*
- - * All other errors return failure, with the compressor
- - * specific error code in *error
- - */
- + /* fail, compressor specific error code returned in error */
- *error = res;
- return -1;
- }
- -static int lzo_uncompress(void *d, void *s, int size, int outsize, int *error)
- +static int lzo_uncompress(void *dest, void *src, int size, int outsize,
- + int *error)
- {
- int res;
- - lzo_uint bytes = outsize;
- + lzo_uint outlen = outsize;
- - res = lzo1x_decompress_safe(s, size, d, &bytes, NULL);
- + res = lzo1x_decompress_safe(src, size, dest, &outlen, NULL);
- + if(res != LZO_E_OK) {
- + *error = res;
- + return -1;
- + }
- - *error = res;
- - return res == LZO_E_OK ? bytes : -1;
- + return outlen;
- +}
- +
- +
- +void lzo_usage()
- +{
- + int i;
- +
- + fprintf(stderr, "\t -Xalgorithm <algorithm>\n");
- + fprintf(stderr, "\t\tWhere <algorithm> is one of:\n");
- +
- + for(i = 0; lzo[i].name; i++)
- + fprintf(stderr, "\t\t\t%s%s\n", lzo[i].name,
- + i == SQUASHFS_LZO1X_999 ? " (default)" : "");
- +
- + fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
- + fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
- + "%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT);
- + fprintf(stderr, "\t\tOnly applies to lzo1x_999 algorithm\n");
- +}
- +
- +
- +/*
- + * Helper function for lzo1x_999 compression algorithm.
- + * All other lzo1x_xxx compressors do not take a compression level,
- + * so we need to wrap lzo1x_999 to pass the compression level which
- + * is applicable to it
- + */
- +int lzo1x_999_wrapper(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst,
- + lzo_uintp compsize, lzo_voidp workspace)
- +{
- + return lzo1x_999_compress_level(src, src_len, dst, compsize,
- + workspace, NULL, 0, 0, compression_level);
- }
- @@ -113,10 +427,13 @@
- .init = squashfs_lzo_init,
- .compress = lzo_compress,
- .uncompress = lzo_uncompress,
- - .options = NULL,
- - .usage = NULL,
- + .options = lzo_options,
- + .options_post = lzo_options_post,
- + .dump_options = lzo_dump_options,
- + .extract_options = lzo_extract_options,
- + .display_options = lzo_display_options,
- + .usage = lzo_usage,
- .id = LZO_COMPRESSION,
- .name = "lzo",
- .supported = 1
- };
- -
- diff -Nru squashfs-tools-4.2+20130409/lzo_wrapper.h squashfs-tools-4.3+20140919/lzo_wrapper.h
- --- squashfs-tools-4.2+20130409/lzo_wrapper.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/lzo_wrapper.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,78 @@
- +#ifndef LZO_WRAPPER_H
- +#define LZO_WRAPPER_H
- +/*
- + * Squashfs
- + *
- + * Copyright (c) 2013
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * lzo_wrapper.h
- + *
- + */
- +
- +#ifndef linux
- +#define __BYTE_ORDER BYTE_ORDER
- +#define __BIG_ENDIAN BIG_ENDIAN
- +#define __LITTLE_ENDIAN LITTLE_ENDIAN
- +#else
- +#include <endian.h>
- +#endif
- +
- +#if __BYTE_ORDER == __BIG_ENDIAN
- +extern unsigned int inswap_le32(unsigned int);
- +
- +#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
- + (s)->algorithm = inswap_le32((s)->algorithm); \
- + (s)->compression_level = inswap_le32((s)->compression_level); \
- +}
- +#else
- +#define SQUASHFS_INSWAP_COMP_OPTS(s)
- +#endif
- +
- +/* Define the compression flags recognised. */
- +#define SQUASHFS_LZO1X_1 0
- +#define SQUASHFS_LZO1X_1_11 1
- +#define SQUASHFS_LZO1X_1_12 2
- +#define SQUASHFS_LZO1X_1_15 3
- +#define SQUASHFS_LZO1X_999 4
- +
- +/* Default compression level used by SQUASHFS_LZO1X_999 */
- +#define SQUASHFS_LZO1X_999_COMP_DEFAULT 8
- +
- +struct lzo_comp_opts {
- + int algorithm;
- + int compression_level;
- +};
- +
- +struct lzo_algorithm {
- + char *name;
- + int size;
- + int (*compress) (const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
- + lzo_voidp);
- +};
- +
- +struct lzo_stream {
- + void *workspace;
- + void *buffer;
- +};
- +
- +#define LZO_MAX_EXPANSION(size) (size + (size / 16) + 64 + 3)
- +
- +int lzo1x_999_wrapper(const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
- + lzo_voidp);
- +
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/Makefile squashfs-tools-4.3+20140919/Makefile
- --- squashfs-tools-4.2+20130409/Makefile 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/Makefile 2015-07-20 21:03:05.000000000 +0200
- @@ -40,6 +40,20 @@
- #LZO_SUPPORT = 1
- #LZO_DIR = /usr/local
- +
- +########### Building LZ4 support #############
- +#
- +# Yann Collet's LZ4 tools are supported
- +# LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html
- +# LZ4 source repository: http://code.google.com/p/lz4
- +#
- +# To build configure the tools using cmake to build shared libraries,
- +# install and uncomment
- +# the LZ4_SUPPORT line below.
- +#
- +#LZ4_SUPPORT = 1
- +
- +
- ########### Building LZMA support #############
- #
- # LZMA1 compression.
- @@ -96,12 +110,12 @@
- INCLUDEDIR = -I.
- INSTALL_DIR = /usr/local/bin
- -MKSQUASHFS_OBJS = mksquashfs.o read_fs.o sort.o swap.o pseudo.o compressor.o \
- - action.o progressbar.o read_file.o info.o restore.o \
- +MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
- + sort.o progressbar.o read_file.o info.o restore.o process_fragments.o \
- caches-queues-lists.o
- UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
- - unsquash-4.o swap.o compressor.o
- + unsquash-4.o swap.o compressor.o unsquashfs_info.o
- CFLAGS ?= -O2
- CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
- @@ -155,6 +169,14 @@
- COMPRESSORS += lzo
- endif
- +ifeq ($(LZ4_SUPPORT),1)
- +CFLAGS += -DLZ4_SUPPORT
- +MKSQUASHFS_OBJS += lz4_wrapper.o
- +UNSQUASHFS_OBJS += lz4_wrapper.o
- +LIBS += -llz4
- +COMPRESSORS += lz4
- +endif
- +
- ifeq ($(XATTR_SUPPORT),1)
- ifeq ($(XATTR_DEFAULT),1)
- CFLAGS += -DXATTR_SUPPORT -DXATTR_DEFAULT
- @@ -187,14 +209,16 @@
- # At least one compressor must have been selected
- #
- ifndef COMPRESSORS
- -$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ or LZO!")
- +$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ, LZO or \
- + LZ4!")
- endif
- #
- # COMP_DEFAULT must be a selected compressor
- #
- ifeq (, $(findstring $(COMP_DEFAULT), $(COMPRESSORS)))
- -$(error "COMP_DEFAULT isn't selected to be built!")
- +$(error "COMP_DEFAULT is set to ${COMP_DEFAULT}, which isn't selected to be \
- + built!")
- endif
- .PHONY: all
- @@ -203,45 +227,53 @@
- mksquashfs: $(MKSQUASHFS_OBJS)
- $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(MKSQUASHFS_OBJS) $(LIBS) -o $@
- -mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h sort.h squashfs_swap.h \
- - xattr.h pseudo.h compressor.h action.h progressbar.h
- +mksquashfs.o: Makefile mksquashfs.c squashfs_fs.h squashfs_swap.h mksquashfs.h \
- + sort.h pseudo.h compressor.h xattr.h action.h error.h progressbar.h \
- + info.h caches-queues-lists.h read_fs.h restore.h process_fragments.h
- -read_fs.o: read_fs.c squashfs_fs.h read_fs.h squashfs_swap.h compressor.h \
- - xattr.h
- +read_fs.o: read_fs.c squashfs_fs.h squashfs_swap.h compressor.h xattr.h \
- + error.h mksquashfs.h
- -sort.o: sort.c squashfs_fs.h sort.h mksquashfs.h
- +sort.o: sort.c squashfs_fs.h mksquashfs.h sort.h error.h progressbar.h
- swap.o: swap.c
- -pseudo.o: pseudo.c pseudo.h
- +pseudo.o: pseudo.c pseudo.h error.h progressbar.h
- -compressor.o: compressor.c compressor.h squashfs_fs.h
- +compressor.o: Makefile compressor.c compressor.h squashfs_fs.h
- -xattr.o: xattr.c xattr.h squashfs_fs.h squashfs_swap.h mksquashfs.h
- +xattr.o: xattr.c squashfs_fs.h squashfs_swap.h mksquashfs.h xattr.h error.h \
- + progressbar.h
- -read_xattrs.o: read_xattrs.c xattr.h squashfs_fs.h squashfs_swap.h read_fs.h
- +read_xattrs.o: read_xattrs.c squashfs_fs.h squashfs_swap.h xattr.h error.h
- -action.o: action.h squashfs_fs.h mksquashfs.h
- +action.o: action.c squashfs_fs.h mksquashfs.h action.h error.h
- -progressbar.o: progressbar.c
- +progressbar.o: progressbar.c error.h
- -read_file.o: read_file.c
- +read_file.o: read_file.c error.h
- -info.o: info.c
- +info.o: info.c squashfs_fs.h mksquashfs.h error.h progressbar.h \
- + caches-queues-lists.h
- -restore.o: restore.c
- +restore.o: restore.c caches-queues-lists.h squashfs_fs.h mksquashfs.h error.h \
- + progressbar.h info.h
- -caches-queues-lists.o: caches-queues-lists.c
- +process_fragments.o: process_fragments.c process_fragments.h
- -gzip_wrapper.o: gzip_wrapper.c compressor.h squashfs_fs.h
- +caches-queues-lists.o: caches-queues-lists.c error.h caches-queues-lists.h
- +
- +gzip_wrapper.o: gzip_wrapper.c squashfs_fs.h gzip_wrapper.h compressor.h
- lzma_wrapper.o: lzma_wrapper.c compressor.h squashfs_fs.h
- lzma_xz_wrapper.o: lzma_xz_wrapper.c compressor.h squashfs_fs.h
- -lzo_wrapper.o: lzo_wrapper.c compressor.h squashfs_fs.h
- +lzo_wrapper.o: lzo_wrapper.c squashfs_fs.h lzo_wrapper.h compressor.h
- +
- +lz4_wrapper.o: lz4_wrapper.c squashfs_fs.h lz4_wrapper.h compressor.h
- -xz_wrapper.o: xz_wrapper.c compressor.h squashfs_fs.h
- +xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
- unsquashfs: $(UNSQUASHFS_OBJS)
- $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
- @@ -260,6 +292,7 @@
- unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h
- +unsquashfs_info.o: unsquashfs.h squashfs_fs.h
- .PHONY: clean
- clean:
- diff -Nru squashfs-tools-4.2+20130409/mksquashfs.c squashfs-tools-4.3+20140919/mksquashfs.c
- --- squashfs-tools-4.2+20130409/mksquashfs.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/mksquashfs.c 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- * filesystem.
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- - * 2012, 2013
- + * 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -73,6 +73,9 @@
- #include "progressbar.h"
- #include "info.h"
- #include "caches-queues-lists.h"
- +#include "read_fs.h"
- +#include "restore.h"
- +#include "process_fragments.h"
- int delete = FALSE;
- int fd;
- @@ -80,17 +83,23 @@
- /* filesystem flags for building */
- int comp_opts = FALSE;
- -int no_xattrs = XATTR_DEF, noX = 0;
- -int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
- -int noI = 0, noD = 0;
- +int no_xattrs = XATTR_DEF;
- +int noX = FALSE;
- +int duplicate_checking = TRUE;
- +int noF = FALSE;
- +int no_fragments = FALSE;
- +int always_use_fragments = FALSE;
- +int noI = FALSE;
- +int noD = FALSE;
- int silent = TRUE;
- -long long global_uid = -1, global_gid = -1;
- int exportable = TRUE;
- -int progress = TRUE;
- int sparse_files = TRUE;
- int old_exclude = TRUE;
- int use_regex = FALSE;
- int nopad = FALSE;
- +int exit_on_error = FALSE;
- +
- +long long global_uid = -1, global_gid = -1;
- /* superblock attributes */
- int block_size = SQUASHFS_FILE_SIZE, block_log;
- @@ -186,21 +195,15 @@
- struct pathname *stickypath = NULL;
- int excluded(char *name, struct pathnames *paths, struct pathnames **new);
- -/* fragment block data structures */
- int fragments = 0;
- -struct fragment {
- - unsigned int index;
- - int offset;
- - int size;
- -};
- -
- #define FRAG_SIZE 32768
- -#define FRAG_INDEX (1LL << 32)
- struct squashfs_fragment_entry *fragment_table = NULL;
- int fragments_outstanding = 0;
- +int fragments_locked = FALSE;
- +
- /* current inode number for directories and non directories */
- unsigned int inode_no = 1;
- unsigned int root_inode_number = 0;
- @@ -217,21 +220,9 @@
- };
- struct old_root_entry_info *old_root_entry;
- -/* in memory file info */
- -struct file_info {
- - long long file_size;
- - long long bytes;
- - unsigned short checksum;
- - unsigned short fragment_checksum;
- - long long start;
- - unsigned int *block_list;
- - struct file_info *next;
- - struct fragment *fragment;
- - char checksum_flag;
- -};
- -
- /* restore orignal filesystem state if appending to existing filesystem is
- * cancelled */
- +int appending = FALSE;
- char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
- long long sbytes, stotal_bytes;
- @@ -245,10 +236,10 @@
- int threads;
- /* flag whether destination file is a block device */
- -int block_device = 0;
- +int block_device = FALSE;
- /* flag indicating whether files are sorted using sort list(s) */
- -int sorted = 0;
- +int sorted = FALSE;
- /* save destination file name for deleting on error */
- char *destination_file = NULL;
- @@ -257,93 +248,67 @@
- char *recovery_file = NULL;
- int recover = TRUE;
- -/* in memory uid tables */
- -#define ID_ENTRIES 256
- -#define ID_HASH(id) (id & (ID_ENTRIES - 1))
- -#define ISA_UID 1
- -#define ISA_GID 2
- -struct id {
- - unsigned int id;
- - int index;
- - char flags;
- - struct id *next;
- -};
- struct id *id_hash_table[ID_ENTRIES];
- struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
- unsigned int uid_count = 0, guid_count = 0;
- unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
- -struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
- -struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate,
- - *to_frag;
- -pthread_t *thread, *deflator_thread, *frag_deflator_thread;
- +struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
- +struct cache *bwriter_buffer, *fwriter_buffer;
- +struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
- + *to_frag, *locked_fragment, *to_process_frag;
- +struct seq_queue *to_main;
- +pthread_t reader_thread, writer_thread, main_thread;
- +pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
- pthread_t *restore_thread = NULL;
- -pthread_mutex_t fragment_mutex;
- -pthread_cond_t fragment_waiting;
- -pthread_mutex_t pos_mutex;
- +pthread_mutex_t fragment_mutex = PTHREAD_MUTEX_INITIALIZER;
- +pthread_mutex_t pos_mutex = PTHREAD_MUTEX_INITIALIZER;
- +pthread_mutex_t dup_mutex = PTHREAD_MUTEX_INITIALIZER;
- /* user options that control parallelisation */
- int processors = -1;
- -/* default size of output buffer in Mbytes */
- -#define WRITER_BUFFER_DEFAULT 512
- -/* default size of input buffer in Mbytes */
- -#define READER_BUFFER_DEFAULT 64
- -/* default size of fragment buffer in Mbytes */
- -#define FRAGMENT_BUFFER_DEFAULT 64
- -int writer_buffer_size;
- +int bwriter_size;
- /* compression operations */
- -static struct compressor *comp;
- -int compressor_opts_parsed = 0;
- +struct compressor *comp = NULL;
- +int compressor_opt_parsed = FALSE;
- void *stream = NULL;
- /* xattr stats */
- unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
- -char *read_from_disk(long long start, unsigned int avail_bytes);
- +/* fragment to file mapping used when appending */
- +int append_fragments = 0;
- +struct append_file **file_mapping;
- +
- +/* root of the in-core directory structure */
- +struct dir_info *root_dir;
- +
- +static char *read_from_disk(long long start, unsigned int avail_bytes);
- void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
- int type);
- -extern struct compressor *read_super(int fd, struct squashfs_super_block *sBlk,
- - char *source);
- -extern long long read_filesystem(char *root_name, int fd,
- - struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache,
- - char **cdirectory_table, char **directory_data_cache,
- - unsigned int *last_directory_block, unsigned int *inode_dir_offset,
- - unsigned int *inode_dir_file_size, unsigned int *root_inode_size,
- - unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
- - int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
- - long long *uncompressed_file, unsigned int *uncompressed_inode,
- - unsigned int *uncompressed_directory,
- - unsigned int *inode_dir_inode_number,
- - unsigned int *inode_dir_parent_inode,
- - void (push_directory_entry)(char *, squashfs_inode, int, int),
- - struct squashfs_fragment_entry **fragment_table,
- - squashfs_inode **inode_lookup_table);
- -extern int read_sort_file(char *filename, int source, char *source_path[]);
- -extern void sort_files_and_write(struct dir_info *dir);
- struct file_info *duplicate(long long file_size, long long bytes,
- unsigned int **block_list, long long *start, struct fragment **fragment,
- struct file_buffer *file_buffer, int blocks, unsigned short checksum,
- - unsigned short fragment_checksum, int checksum_flag);
- + int checksum_flag);
- struct dir_info *dir_scan1(char *, char *, struct pathnames *,
- struct dir_ent *(_readdir)(struct dir_info *), int);
- void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
- -void dir_scan3(struct dir_info *root, struct dir_info *dir);
- +void dir_scan3(struct dir_info *dir);
- void dir_scan4(struct dir_info *dir);
- void dir_scan5(struct dir_info *dir);
- -void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info);
- +void dir_scan6(struct dir_info *dir);
- +void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info);
- struct file_info *add_non_dup(long long file_size, long long bytes,
- unsigned int *block_list, long long start, struct fragment *fragment,
- unsigned short checksum, unsigned short fragment_checksum,
- - int checksum_flag);
- -extern void generate_file_priorities(struct dir_info *dir, int priority,
- - struct stat *buf);
- -extern struct priority_entry *priority_list[65536];
- + int checksum_flag, int checksum_frag_flag);
- long long generic_write_table(int, void *, int, void *, int);
- void restorefs();
- struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
- -extern pthread_t *init_restore_thread(pthread_t);
- void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
- +unsigned short get_checksum_mem(char *buff, int bytes);
- +void check_usable_phys_mem(int total_mem);
- void prep_exit()
- @@ -360,12 +325,14 @@
- exit(1);
- } else {
- /* signal the restore thread to restore */
- - kill(getpid(), SIGUSR1);
- + pthread_kill(*restore_thread, SIGUSR1);
- pthread_exit(NULL);
- }
- - }
- - if(delete && destination_file && !block_device)
- - unlink(destination_file);
- + } else if(delete) {
- + if(destination_file && !block_device)
- + unlink(destination_file);
- + } else if(recovery_file)
- + unlink(recovery_file);
- }
- @@ -387,22 +354,20 @@
- }
- +int multiply_overflowll(long long a, int multiplier)
- +{
- + return (LLONG_MAX / multiplier) < a;
- +}
- +
- +
- #define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
- + (((char *)A) - data_cache)))
- void restorefs()
- {
- - int i;
- -
- ERROR("Exiting - restoring original filesystem!\n\n");
- - for(i = 0; i < 2 + processors * 2; i++)
- - pthread_cancel(thread[i]);
- - for(i = 0; i < 2 + processors * 2; i++)
- - pthread_join(thread[i], NULL);
- -
- - TRACE("All threads in signal handler\n");
- bytes = sbytes;
- memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
- memcpy(directory_data_cache, sdirectory_data_cache,
- @@ -555,15 +520,11 @@
- ERROR("read_fs_bytes: Lseek on destination failed because %s, "
- "offset=0x%llx\n", strerror(errno), off);
- res = 0;
- - goto mutex_unlock;
- - }
- -
- - if(read_bytes(fd, buff, bytes) < bytes) {
- + } else if(read_bytes(fd, buff, bytes) < bytes) {
- ERROR("Read on destination failed\n");
- res = 0;
- }
- -mutex_unlock:
- pthread_cleanup_pop(1);
- return res;
- }
- @@ -1076,56 +1037,28 @@
- }
- else if(type == SQUASHFS_SYMLINK_TYPE) {
- struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
- - int byte;
- - char buff[65536]; /* overflow safe */
- + int byte = strlen(dir_ent->inode->symlink);
- size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
- - byte = readlink(filename, buff, 65536);
- - if(byte == -1) {
- - ERROR("Failed to read symlink %s, creating empty "
- - "symlink\n", filename);
- - byte = 0;
- - }
- -
- - if(byte == 65536) {
- - ERROR("Symlink %s is greater than 65536 bytes! "
- - "Creating empty symlink\n", filename);
- - byte = 0;
- - }
- -
- inode = get_inode(sizeof(*symlink) + byte);
- symlink->nlink = nlink;
- symlink->symlink_size = byte;
- SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
- - strncpy(inode + off, buff, byte);
- + strncpy(inode + off, dir_ent->inode->symlink, byte);
- TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
- nlink);
- }
- else if(type == SQUASHFS_LSYMLINK_TYPE) {
- struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
- - int byte;
- - char buff[65536]; /* overflow safe */
- + int byte = strlen(dir_ent->inode->symlink);
- size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
- - byte = readlink(filename, buff, 65536);
- - if(byte == -1) {
- - ERROR("Failed to read symlink %s, creating empty "
- - "symlink\n", filename);
- - byte = 0;
- - }
- -
- - if(byte == 65536) {
- - ERROR("Symlink %s is greater than 65536 bytes! "
- - "Creating empty symlink\n", filename);
- - byte = 0;
- - }
- -
- inode = get_inode(sizeof(*symlink) + byte +
- sizeof(unsigned int));
- symlink->nlink = nlink;
- symlink->symlink_size = byte;
- SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
- - strncpy(inode + off, buff, byte);
- + strncpy(inode + off, dir_ent->inode->symlink, byte);
- SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
- TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
- nlink);
- @@ -1363,28 +1296,82 @@
- }
- -struct file_buffer *get_fragment(struct fragment *fragment)
- +static struct file_buffer *get_fragment(struct fragment *fragment)
- {
- struct squashfs_fragment_entry *disk_fragment;
- - int res, size;
- - long long start_block;
- struct file_buffer *buffer, *compressed_buffer;
- + long long start_block;
- + int res, size, index = fragment->index;
- + char locked;
- +
- + /*
- + * Lookup fragment block in cache.
- + * If the fragment block doesn't exist, then get the compressed version
- + * from the writer cache or off disk, and decompress it.
- + *
- + * This routine has two things which complicate the code:
- + *
- + * 1. Multiple threads can simultaneously lookup/create the
- + * same buffer. This means a buffer needs to be "locked"
- + * when it is being filled in, to prevent other threads from
- + * using it when it is not ready. This is because we now do
- + * fragment duplicate checking in parallel.
- + * 2. We have two caches which need to be checked for the
- + * presence of fragment blocks: the normal fragment cache
- + * and a "reserve" cache. The reserve cache is used to
- + * prevent an unnecessary pipeline stall when the fragment cache
- + * is full of fragments waiting to be compressed.
- + */
- if(fragment->index == SQUASHFS_INVALID_FRAG)
- return NULL;
- - buffer = cache_lookup(fragment_buffer, fragment->index);
- - if(buffer)
- - return buffer;
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- + pthread_mutex_lock(&dup_mutex);
- - compressed_buffer = cache_lookup(writer_buffer, fragment->index +
- - FRAG_INDEX);
- +again:
- + buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
- + if(buffer) {
- + pthread_mutex_unlock(&dup_mutex);
- + if(locked)
- + /* got a buffer being filled in. Wait for it */
- + cache_wait_unlock(buffer);
- + goto finished;
- + }
- +
- + /* not in fragment cache, is it in the reserve cache? */
- + buffer = cache_lookup_nowait(reserve_cache, index, &locked);
- + if(buffer) {
- + pthread_mutex_unlock(&dup_mutex);
- + if(locked)
- + /* got a buffer being filled in. Wait for it */
- + cache_wait_unlock(buffer);
- + goto finished;
- + }
- +
- + /* in neither cache, try to get it from the fragment cache */
- + buffer = cache_get_nowait(fragment_buffer, index);
- + if(!buffer) {
- + /*
- + * no room, get it from the reserve cache, this is
- + * dimensioned so it will always have space (no more than
- + * processors + 1 can have an outstanding reserve buffer)
- + */
- + buffer = cache_get_nowait(reserve_cache, index);
- + if(!buffer) {
- + /* failsafe */
- + ERROR("no space in reserve cache\n");
- + goto again;
- + }
- + }
- +
- + pthread_mutex_unlock(&dup_mutex);
- - buffer = cache_get(fragment_buffer, fragment->index, 1);
- + compressed_buffer = cache_lookup(fwriter_buffer, index);
- pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- pthread_mutex_lock(&fragment_mutex);
- - disk_fragment = &fragment_table[fragment->index];
- + disk_fragment = &fragment_table[index];
- size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
- start_block = disk_fragment->start_block;
- pthread_cleanup_pop(1);
- @@ -1395,8 +1382,14 @@
- if(compressed_buffer)
- data = compressed_buffer->data;
- - else
- + else {
- data = read_from_disk(start_block, size);
- + if(data == NULL) {
- + ERROR("Failed to read fragment from output"
- + " filesystem\n");
- + BAD_ERROR("Output filesystem corrupted?\n");
- + }
- + }
- res = compressor_uncompress(comp, buffer->data, data, size,
- block_size, &error);
- @@ -1414,58 +1407,95 @@
- }
- }
- + cache_unlock(buffer);
- cache_block_put(compressed_buffer);
- +finished:
- + pthread_cleanup_pop(0);
- +
- return buffer;
- }
- -struct frag_locked {
- - struct file_buffer *buffer;
- - int c_byte;
- - int fragment;
- - struct frag_locked *fragment_prev;
- - struct frag_locked *fragment_next;
- -};
- +unsigned short get_fragment_checksum(struct file_info *file)
- +{
- + struct file_buffer *frag_buffer;
- + struct append_file *append;
- + int res, index = file->fragment->index;
- + unsigned short checksum;
- -int fragments_locked = FALSE;
- -struct frag_locked *frag_locked_list = NULL;
- + if(index == SQUASHFS_INVALID_FRAG)
- + return 0;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- + pthread_mutex_lock(&dup_mutex);
- + res = file->have_frag_checksum;
- + checksum = file->fragment_checksum;
- + pthread_cleanup_pop(1);
- +
- + if(res)
- + return checksum;
- +
- + frag_buffer = get_fragment(file->fragment);
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- +
- + for(append = file_mapping[index]; append; append = append->next) {
- + int offset = append->file->fragment->offset;
- + int size = append->file->fragment->size;
- + unsigned short cksum =
- + get_checksum_mem(frag_buffer->data + offset, size);
- -INSERT_LIST(fragment, struct frag_locked)
- -REMOVE_LIST(fragment, struct frag_locked)
- + if(file == append->file)
- + checksum = cksum;
- -int lock_fragments()
- + pthread_mutex_lock(&dup_mutex);
- + append->file->fragment_checksum = cksum;
- + append->file->have_frag_checksum = TRUE;
- + pthread_mutex_unlock(&dup_mutex);
- + }
- +
- + cache_block_put(frag_buffer);
- + pthread_cleanup_pop(0);
- +
- + return checksum;
- +}
- +
- +
- +void lock_fragments()
- {
- - int count;
- pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- pthread_mutex_lock(&fragment_mutex);
- fragments_locked = TRUE;
- - count = fragments_outstanding;
- pthread_cleanup_pop(1);
- - return count;
- }
- void unlock_fragments()
- {
- - struct frag_locked *entry;
- - int compressed_size;
- + int frg, size;
- + struct file_buffer *write_buffer;
- pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- pthread_mutex_lock(&fragment_mutex);
- - while(frag_locked_list) {
- - entry = frag_locked_list;
- - remove_fragment_list(&frag_locked_list, entry);
- - compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->c_byte);
- - fragment_table[entry->fragment].size = entry->c_byte;
- - fragment_table[entry->fragment].start_block = bytes;
- - entry->buffer->block = bytes;
- - bytes += compressed_size;
- +
- + /*
- + * Note queue_empty() is inherently racy with respect to concurrent
- + * queue get and pushes. We avoid this because we're holding the
- + * fragment_mutex which ensures no other threads can be using the
- + * queue at this time.
- + */
- + while(!queue_empty(locked_fragment)) {
- + write_buffer = queue_get(locked_fragment);
- + frg = write_buffer->block;
- + size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size);
- + fragment_table[frg].start_block = bytes;
- + write_buffer->block = bytes;
- + bytes += size;
- fragments_outstanding --;
- - queue_put(to_writer, entry->buffer);
- + queue_put(to_writer, write_buffer);
- TRACE("fragment_locked writing fragment %d, compressed size %d"
- - "\n", entry->fragment, compressed_size);
- - free(entry);
- + "\n", frg, size);
- }
- fragments_locked = FALSE;
- pthread_cleanup_pop(1);
- @@ -1475,14 +1505,10 @@
- void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
- int fragment)
- {
- - struct frag_locked *entry = malloc(sizeof(struct frag_locked));
- - if(entry == NULL)
- - MEM_ERROR();
- - entry->buffer = write_buffer;
- - entry->c_byte = c_byte;
- - entry->fragment = fragment;
- - entry->fragment_prev = entry->fragment_next = NULL;
- - insert_fragment_list(&frag_locked_list, entry);
- + fragment_table[fragment].size = c_byte;
- + write_buffer->block = fragment;
- +
- + queue_put(locked_fragment, write_buffer);
- }
- @@ -1502,7 +1528,7 @@
- struct file_buffer *allocate_fragment()
- {
- - struct file_buffer *fragment = cache_get(fragment_buffer, fragments, 1);
- + struct file_buffer *fragment = cache_get(fragment_buffer, fragments);
- pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- pthread_mutex_lock(&fragment_mutex);
- @@ -1543,7 +1569,7 @@
- if(file_buffer == NULL || file_buffer->size == 0)
- return &empty_fragment;
- - fragment = eval_frag_actions(dir_ent);
- + fragment = eval_frag_actions(root_dir, dir_ent);
- if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
- write_fragment(*fragment);
- @@ -1645,15 +1671,13 @@
- char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
- -char *read_from_disk(long long start, unsigned int avail_bytes)
- +static char *read_from_disk(long long start, unsigned int avail_bytes)
- {
- int res;
- res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
- - if(res == 0) {
- - ERROR("Failed to read data from output filesystem\n");
- - BAD_ERROR("Output filesystem corrupted?\n");
- - }
- + if(res == 0)
- + return NULL;
- return read_from_file_buffer;
- }
- @@ -1665,10 +1689,8 @@
- int res;
- res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
- - if(res == 0) {
- - ERROR("Failed to read data from output filesystem\n");
- - BAD_ERROR("Output filesystem corrupted?\n");
- - }
- + if(res == 0)
- + return NULL;
- return read_from_file_buffer2;
- }
- @@ -1702,14 +1724,22 @@
- bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
- if(bytes == 0) /* sparse block */
- continue;
- - write_buffer = cache_lookup(writer_buffer, start);
- + write_buffer = cache_lookup(bwriter_buffer, start);
- if(write_buffer) {
- chksum = get_checksum(write_buffer->data, bytes,
- chksum);
- cache_block_put(write_buffer);
- - } else
- - chksum = get_checksum(read_from_disk(start, bytes),
- - bytes, chksum);
- + } else {
- + void *data = read_from_disk(start, bytes);
- + if(data == NULL) {
- + ERROR("Failed to checksum data from output"
- + " filesystem\n");
- + BAD_ERROR("Output filesystem corrupted?\n");
- + }
- +
- + chksum = get_checksum(data, bytes, chksum);
- + }
- +
- l -= bytes;
- start += bytes;
- }
- @@ -1741,6 +1771,8 @@
- struct fragment *frg;
- unsigned int *block_list = block_listp;
- struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
- + struct append_file *append_file;
- + struct file_info *file;
- if(!duplicate_checking || file_size == 0)
- return;
- @@ -1767,44 +1799,29 @@
- frg->offset = offset;
- frg->size = bytes;
- - add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE);
- -}
- -
- + file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0,
- + FALSE, FALSE);
- -int pre_duplicate(long long file_size)
- -{
- - struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
- + if(fragment == SQUASHFS_INVALID_FRAG)
- + return;
- - for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
- - if(dupl_ptr->file_size == file_size)
- - return TRUE;
- + append_file = malloc(sizeof(struct append_file));
- + if(append_file == NULL)
- + MEM_ERROR();
- - return FALSE;
- + append_file->file = file;
- + append_file->next = file_mapping[fragment];
- + file_mapping[fragment] = append_file;
- }
- -int pre_duplicate_frag(long long file_size, unsigned short checksum)
- +int pre_duplicate(long long file_size)
- {
- struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
- for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
- - if(file_size == dupl_ptr->file_size && file_size ==
- - dupl_ptr->fragment->size) {
- - if(dupl_ptr->checksum_flag == FALSE) {
- - struct file_buffer *frag_buffer =
- - get_fragment(dupl_ptr->fragment);
- - dupl_ptr->checksum =
- - get_checksum_disk(dupl_ptr->start,
- - dupl_ptr->bytes, dupl_ptr->block_list);
- - dupl_ptr->fragment_checksum =
- - get_checksum_mem(frag_buffer->data +
- - dupl_ptr->fragment->offset, file_size);
- - cache_block_put(frag_buffer);
- - dupl_ptr->checksum_flag = TRUE;
- - }
- - if(dupl_ptr->fragment_checksum == checksum)
- - return TRUE;
- - }
- + if(dupl_ptr->file_size == file_size)
- + return TRUE;
- return FALSE;
- }
- @@ -1813,7 +1830,7 @@
- struct file_info *add_non_dup(long long file_size, long long bytes,
- unsigned int *block_list, long long start, struct fragment *fragment,
- unsigned short checksum, unsigned short fragment_checksum,
- - int checksum_flag)
- + int checksum_flag, int checksum_frag_flag)
- {
- struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
- @@ -1827,22 +1844,74 @@
- dupl_ptr->fragment = fragment;
- dupl_ptr->checksum = checksum;
- dupl_ptr->fragment_checksum = fragment_checksum;
- - dupl_ptr->checksum_flag = checksum_flag;
- + dupl_ptr->have_frag_checksum = checksum_frag_flag;
- + dupl_ptr->have_checksum = checksum_flag;
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- + pthread_mutex_lock(&dup_mutex);
- dupl_ptr->next = dupl[DUP_HASH(file_size)];
- dupl[DUP_HASH(file_size)] = dupl_ptr;
- dup_files ++;
- + pthread_cleanup_pop(1);
- return dupl_ptr;
- }
- +struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put)
- +{
- + struct file_info *dupl_ptr;
- + struct file_buffer *buffer;
- + struct file_info *dupl_start = file_buffer->dupl_start;
- + long long file_size = file_buffer->file_size;
- + unsigned short checksum = file_buffer->checksum;
- + int res;
- +
- + if(file_buffer->duplicate) {
- + TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
- + "checksum 0x%x\n", dupl_start->fragment->index,
- + file_size, dupl_start->fragment->offset, checksum);
- + *dont_put = TRUE;
- + return dupl_start->fragment;
- + } else {
- + *dont_put = FALSE;
- + dupl_ptr = dupl[DUP_HASH(file_size)];
- + }
- +
- + for(; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) {
- + if(file_size == dupl_ptr->file_size && file_size ==
- + dupl_ptr->fragment->size) {
- + if(get_fragment_checksum(dupl_ptr) == checksum) {
- + buffer = get_fragment(dupl_ptr->fragment);
- + res = memcmp(file_buffer->data, buffer->data +
- + dupl_ptr->fragment->offset, file_size);
- + cache_block_put(buffer);
- + if(res == 0)
- + break;
- + }
- + }
- + }
- +
- + if(!dupl_ptr || dupl_ptr == dupl_start)
- + return NULL;
- +
- + TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
- + "checksum 0x%x\n", dupl_ptr->fragment->index, file_size,
- + dupl_ptr->fragment->offset, checksum);
- +
- + return dupl_ptr->fragment;
- +}
- +
- +
- struct file_info *duplicate(long long file_size, long long bytes,
- unsigned int **block_list, long long *start, struct fragment **fragment,
- struct file_buffer *file_buffer, int blocks, unsigned short checksum,
- - unsigned short fragment_checksum, int checksum_flag)
- + int checksum_flag)
- {
- struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
- int frag_bytes = file_buffer ? file_buffer->size : 0;
- + unsigned short fragment_checksum = file_buffer ?
- + file_buffer->checksum : 0;
- for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
- if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
- @@ -1857,27 +1926,19 @@
- if(checksum_flag == FALSE) {
- checksum = get_checksum_disk(*start, bytes,
- *block_list);
- - fragment_checksum =
- - get_checksum_mem_buffer(file_buffer);
- checksum_flag = TRUE;
- }
- - if(dupl_ptr->checksum_flag == FALSE) {
- - struct file_buffer *frag_buffer =
- - get_fragment(dupl_ptr->fragment);
- + if(!dupl_ptr->have_checksum) {
- dupl_ptr->checksum =
- get_checksum_disk(dupl_ptr->start,
- dupl_ptr->bytes, dupl_ptr->block_list);
- - dupl_ptr->fragment_checksum =
- - get_checksum_mem(frag_buffer->data +
- - dupl_ptr->fragment->offset, frag_bytes);
- - cache_block_put(frag_buffer);
- - dupl_ptr->checksum_flag = TRUE;
- + dupl_ptr->have_checksum = TRUE;
- }
- if(checksum != dupl_ptr->checksum ||
- fragment_checksum !=
- - dupl_ptr->fragment_checksum)
- + get_fragment_checksum(dupl_ptr))
- continue;
- target_start = *start;
- @@ -1891,22 +1952,36 @@
- if(size == 0)
- continue;
- - target_buffer = cache_lookup(writer_buffer,
- + target_buffer = cache_lookup(bwriter_buffer,
- target_start);
- if(target_buffer)
- target_data = target_buffer->data;
- - else
- + else {
- target_data =
- read_from_disk(target_start,
- size);
- + if(target_data == NULL) {
- + ERROR("Failed to read data from"
- + " output filesystem\n");
- + BAD_ERROR("Output filesystem"
- + " corrupted?\n");
- + }
- + }
- - dup_buffer = cache_lookup(writer_buffer,
- + dup_buffer = cache_lookup(bwriter_buffer,
- dup_start);
- if(dup_buffer)
- dup_data = dup_buffer->data;
- - else
- + else {
- dup_data = read_from_disk2(dup_start,
- size);
- + if(dup_data == NULL) {
- + ERROR("Failed to read data from"
- + " output filesystem\n");
- + BAD_ERROR("Output filesystem"
- + " corrupted?\n");
- + }
- + }
- res = memcmp(target_data, dup_data, size);
- cache_block_put(target_buffer);
- @@ -1948,13 +2023,13 @@
- return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
- - checksum, fragment_checksum, checksum_flag);
- + checksum, fragment_checksum, checksum_flag, TRUE);
- }
- inline int is_fragment(struct inode_info *inode)
- {
- - int file_size = inode->buf.st_size;
- + off_t file_size = inode->buf.st_size;
- /*
- * If this block is to be compressed differently to the
- @@ -1963,33 +2038,57 @@
- if(inode->noF != noF)
- return FALSE;
- - return !inode->no_fragments && (file_size < block_size ||
- + return !inode->no_fragments && file_size && (file_size < block_size ||
- (inode->always_use_fragments && file_size & (block_size - 1)));
- }
- +void put_file_buffer(struct file_buffer *file_buffer)
- +{
- + /*
- + * Decide where to send the file buffer:
- + * - compressible non-fragment blocks go to the deflate threads,
- + * - fragments go to the process fragment threads,
- + * - all others go directly to the main thread
- + */
- + if(file_buffer->error) {
- + file_buffer->fragment = 0;
- + seq_queue_put(to_main, file_buffer);
- + } else if (file_buffer->file_size == 0)
- + seq_queue_put(to_main, file_buffer);
- + else if(file_buffer->fragment)
- + queue_put(to_process_frag, file_buffer);
- + else
- + queue_put(to_deflate, file_buffer);
- +}
- +
- +
- static int seq = 0;
- void reader_read_process(struct dir_ent *dir_ent)
- {
- + long long bytes = 0;
- struct inode_info *inode = dir_ent->inode;
- struct file_buffer *prev_buffer = NULL, *file_buffer;
- - int status, res, byte, count = 0;
- - int file = get_pseudo_file(inode->pseudo_id)->fd;
- - int child = get_pseudo_file(inode->pseudo_id)->child;
- - long long bytes = 0;
- + int status, byte, res, child;
- + int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child);
- +
- + if(!file) {
- + file_buffer = cache_get_nohash(reader_buffer);
- + file_buffer->sequence = seq ++;
- + goto read_err;
- + }
- while(1) {
- - file_buffer = cache_get(reader_buffer, 0, 0);
- + file_buffer = cache_get_nohash(reader_buffer);
- file_buffer->sequence = seq ++;
- file_buffer->noD = inode->noD;
- byte = read_bytes(file, file_buffer->data, block_size);
- if(byte == -1)
- - goto read_err;
- + goto read_err2;
- file_buffer->size = byte;
- file_buffer->file_size = -1;
- - file_buffer->block = count ++;
- file_buffer->error = FALSE;
- file_buffer->fragment = FALSE;
- bytes += byte;
- @@ -2007,7 +2106,7 @@
- progress_bar_size(1);
- if(prev_buffer)
- - queue_put(from_reader, prev_buffer);
- + put_file_buffer(prev_buffer);
- prev_buffer = file_buffer;
- }
- @@ -2018,6 +2117,8 @@
- inode->buf.st_size = bytes;
- res = waitpid(child, &status, 0);
- + close(file);
- +
- if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
- goto read_err;
- @@ -2029,10 +2130,12 @@
- }
- prev_buffer->file_size = bytes;
- prev_buffer->fragment = is_fragment(inode);
- - queue_put(from_reader, prev_buffer);
- + put_file_buffer(prev_buffer);
- return;
- +read_err2:
- + close(file);
- read_err:
- if(prev_buffer) {
- cache_block_put(file_buffer);
- @@ -2040,7 +2143,7 @@
- file_buffer = prev_buffer;
- }
- file_buffer->error = TRUE;
- - queue_put(from_deflate, file_buffer);
- + put_file_buffer(file_buffer);
- }
- @@ -2048,7 +2151,7 @@
- {
- struct stat *buf = &dir_ent->inode->buf, buf2;
- struct file_buffer *file_buffer;
- - int blocks, byte, count, expected, file, res;
- + int blocks, file, res;
- long long bytes, read_size;
- struct inode_info *inode = dir_ent->inode;
- @@ -2058,28 +2161,22 @@
- inode->read = TRUE;
- again:
- bytes = 0;
- - count = 0;
- - file_buffer = NULL;
- read_size = buf->st_size;
- blocks = (read_size + block_size - 1) >> block_log;
- file = open(pathname_reader(dir_ent), O_RDONLY);
- if(file == -1) {
- - file_buffer = cache_get(reader_buffer, 0, 0);
- + file_buffer = cache_get_nohash(reader_buffer);
- file_buffer->sequence = seq ++;
- goto read_err2;
- }
- do {
- - expected = read_size - ((long long) count * block_size) >
- - block_size ? block_size :
- - read_size - ((long long) count * block_size);
- -
- - if(file_buffer)
- - queue_put(from_reader, file_buffer);
- - file_buffer = cache_get(reader_buffer, 0, 0);
- + file_buffer = cache_get_nohash(reader_buffer);
- + file_buffer->file_size = read_size;
- file_buffer->sequence = seq ++;
- file_buffer->noD = inode->noD;
- + file_buffer->error = FALSE;
- /*
- * Always try to read block_size bytes from the file rather
- @@ -2090,29 +2187,28 @@
- * case where the file is an exact multiple of the block_size
- * is dealt with later.
- */
- - byte = file_buffer->size = read_bytes(file, file_buffer->data,
- + file_buffer->size = read_bytes(file, file_buffer->data,
- block_size);
- -
- - file_buffer->file_size = read_size;
- -
- - if(byte == -1)
- + if(file_buffer->size == -1)
- goto read_err;
- - if(byte != expected)
- - goto restat;
- + bytes += file_buffer->size;
- - file_buffer->block = count;
- - file_buffer->error = FALSE;
- - file_buffer->fragment = FALSE;
- + if(blocks > 1) {
- + /* non-tail block should be exactly block_size */
- + if(file_buffer->size < block_size)
- + goto restat;
- - bytes += byte;
- - count ++;
- - } while(count < blocks);
- + file_buffer->fragment = FALSE;
- + put_file_buffer(file_buffer);
- + }
- + } while(-- blocks > 0);
- + /* Overall size including tail should match */
- if(read_size != bytes)
- goto restat;
- - if(expected == block_size) {
- + if(read_size && read_size % block_size == 0) {
- /*
- * Special case where we've not tried to read past the end of
- * the file. We expect to get EOF, i.e. the file isn't larger
- @@ -2130,7 +2226,7 @@
- }
- file_buffer->fragment = is_fragment(inode);
- - queue_put(from_reader, file_buffer);
- + put_file_buffer(file_buffer);
- close(file);
- @@ -2139,7 +2235,7 @@
- restat:
- res = fstat(file, &buf2);
- if(res == -1) {
- - ERROR("Cannot stat dir/file %s because %s, ignoring\n",
- + ERROR("Cannot stat dir/file %s because %s\n",
- pathname_reader(dir_ent), strerror(errno));
- goto read_err;
- }
- @@ -2148,14 +2244,14 @@
- close(file);
- memcpy(buf, &buf2, sizeof(struct stat));
- file_buffer->error = 2;
- - queue_put(from_deflate, file_buffer);
- + put_file_buffer(file_buffer);
- goto again;
- }
- read_err:
- close(file);
- read_err2:
- file_buffer->error = TRUE;
- - queue_put(from_deflate, file_buffer);
- + put_file_buffer(file_buffer);
- }
- @@ -2261,6 +2357,7 @@
- void *deflator(void *arg)
- {
- + struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer);
- void *stream = NULL;
- int res;
- @@ -2269,20 +2366,12 @@
- BAD_ERROR("deflator:: compressor_init failed\n");
- while(1) {
- - struct file_buffer *file_buffer = queue_get(from_reader);
- - struct file_buffer *write_buffer;
- + struct file_buffer *file_buffer = queue_get(to_deflate);
- - if(file_buffer->file_size == 0) {
- + if(sparse_files && all_zero(file_buffer)) {
- file_buffer->c_byte = 0;
- - queue_put(from_deflate, file_buffer);
- - } else if(sparse_files && all_zero(file_buffer)) {
- - file_buffer->c_byte = 0;
- - queue_put(from_deflate, file_buffer);
- - } else if(file_buffer->fragment) {
- - file_buffer->c_byte = file_buffer->size;
- - queue_put(from_deflate, file_buffer);
- + seq_queue_put(to_main, file_buffer);
- } else {
- - write_buffer = cache_get(writer_buffer, 0, 0);
- write_buffer->c_byte = mangle2(stream,
- write_buffer->data, file_buffer->data,
- file_buffer->size, block_size,
- @@ -2295,7 +2384,8 @@
- write_buffer->fragment = FALSE;
- write_buffer->error = FALSE;
- cache_block_put(file_buffer);
- - queue_put(from_deflate, write_buffer);
- + seq_queue_put(to_main, write_buffer);
- + write_buffer = cache_get_nohash(bwriter_buffer);
- }
- }
- }
- @@ -2310,18 +2400,18 @@
- if(res)
- BAD_ERROR("frag_deflator:: compressor_init failed\n");
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- +
- while(1) {
- int c_byte, compressed_size;
- struct file_buffer *file_buffer = queue_get(to_frag);
- struct file_buffer *write_buffer =
- - cache_get(writer_buffer, file_buffer->block +
- - FRAG_INDEX, 1);
- + cache_get(fwriter_buffer, file_buffer->block);
- c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
- file_buffer->size, block_size, noF, 1);
- compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
- write_buffer->size = compressed_size;
- - pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- pthread_mutex_lock(&fragment_mutex);
- if(fragments_locked == FALSE) {
- fragment_table[file_buffer->block].size = c_byte;
- @@ -2330,137 +2420,73 @@
- bytes += compressed_size;
- fragments_outstanding --;
- queue_put(to_writer, write_buffer);
- + pthread_mutex_unlock(&fragment_mutex);
- TRACE("Writing fragment %lld, uncompressed size %d, "
- "compressed size %d\n", file_buffer->block,
- file_buffer->size, compressed_size);
- - } else
- + } else {
- add_pending_fragment(write_buffer, c_byte,
- file_buffer->block);
- - pthread_cleanup_pop(1);
- + pthread_mutex_unlock(&fragment_mutex);
- + }
- cache_block_put(file_buffer);
- }
- -}
- -
- -#define HASH_ENTRIES 256
- -#define BLOCK_HASH(a) (a % HASH_ENTRIES)
- -struct file_buffer *block_hash[HASH_ENTRIES];
- -
- -void push_buffer(struct file_buffer *file_buffer)
- -{
- - int hash = BLOCK_HASH(file_buffer->sequence);
- -
- - file_buffer->next = block_hash[hash];
- - block_hash[hash] = file_buffer;
- + pthread_cleanup_pop(0);
- }
- -struct file_buffer *get_file_buffer(struct queue *queue)
- +struct file_buffer *get_file_buffer()
- {
- - static unsigned int sequence = 0;
- - int hash = BLOCK_HASH(sequence);
- - struct file_buffer *file_buffer = block_hash[hash], *prev = NULL;
- -
- - for(;file_buffer; prev = file_buffer, file_buffer = file_buffer->next)
- - if(file_buffer->sequence == sequence)
- - break;
- -
- - if(file_buffer) {
- - if(prev)
- - prev->next = file_buffer->next;
- - else
- - block_hash[hash] = file_buffer->next;
- - } else {
- - while(1) {
- - file_buffer = queue_get(queue);
- - if(file_buffer->sequence == sequence)
- - break;
- - push_buffer(file_buffer);
- - }
- - }
- -
- - sequence ++;
- + struct file_buffer *file_buffer = seq_queue_get(to_main);
- return file_buffer;
- }
- void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
- - int *duplicate_file)
- + struct file_buffer *file_buffer, int *duplicate_file)
- {
- file_count ++;
- *duplicate_file = FALSE;
- + cache_block_put(file_buffer);
- create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
- NULL, &empty_fragment, NULL, 0);
- }
- -void write_file_frag_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
- - int size, int *duplicate_file, struct file_buffer *file_buffer,
- - unsigned short checksum)
- -{
- - struct file_info *dupl_ptr;
- - struct fragment *fragment;
- - unsigned int *block_listp = NULL;
- - long long start = 0;
- -
- - dupl_ptr = duplicate(size, 0, &block_listp, &start, &fragment,
- - file_buffer, 0, 0, checksum, TRUE);
- -
- - if(dupl_ptr) {
- - *duplicate_file = FALSE;
- - fragment = get_and_fill_fragment(file_buffer, dir_ent);
- - dupl_ptr->fragment = fragment;
- - } else
- - *duplicate_file = TRUE;
- -
- - cache_block_put(file_buffer);
- -
- - total_bytes += size;
- - file_count ++;
- -
- - inc_progress_bar();
- -
- - create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
- - 0, NULL, fragment, NULL, 0);
- -}
- -
- -
- -void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, int size,
- +void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent,
- struct file_buffer *file_buffer, int *duplicate_file)
- {
- + int size = file_buffer->file_size;
- struct fragment *fragment;
- - unsigned short checksum;
- -
- - checksum = get_checksum_mem_buffer(file_buffer);
- + unsigned short checksum = file_buffer->checksum;
- + char dont_put;
- - if(pre_duplicate_frag(size, checksum)) {
- - write_file_frag_dup(inode, dir_ent, size, duplicate_file,
- - file_buffer, checksum);
- - return;
- + fragment = frag_duplicate(file_buffer, &dont_put);
- + *duplicate_file = !fragment;
- + if(!fragment) {
- + fragment = get_and_fill_fragment(file_buffer, dir_ent);
- + if(duplicate_checking)
- + add_non_dup(size, 0, NULL, 0, fragment, 0, checksum,
- + TRUE, TRUE);
- }
- -
- - fragment = get_and_fill_fragment(file_buffer, dir_ent);
- -
- - cache_block_put(file_buffer);
- - if(duplicate_checking)
- - add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE);
- + if(dont_put)
- + free(file_buffer);
- + else
- + cache_block_put(file_buffer);
- total_bytes += size;
- file_count ++;
- - *duplicate_file = FALSE;
- -
- inc_progress_bar();
- create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
- 0, NULL, fragment, NULL, 0);
- - if(duplicate_checking == FALSE)
- + if(!duplicate_checking)
- free_fragment(fragment);
- -
- - return;
- }
- @@ -2482,7 +2508,7 @@
- start = bytes;
- while (1) {
- read_size = read_buffer->file_size;
- - if(read_buffer->fragment && read_buffer->c_byte)
- + if(read_buffer->fragment)
- fragment_buffer = read_buffer;
- else {
- block_list = realloc(block_list, (block + 1) *
- @@ -2493,7 +2519,7 @@
- if(read_buffer->c_byte) {
- read_buffer->block = bytes;
- bytes += read_buffer->size;
- - cache_rehash(read_buffer, read_buffer->block);
- + cache_hash(read_buffer, read_buffer->block);
- file_bytes += read_buffer->size;
- queue_put(to_writer, read_buffer);
- } else {
- @@ -2506,18 +2532,19 @@
- if(read_size != -1)
- break;
- - read_buffer = get_file_buffer(from_deflate);
- + read_buffer = get_file_buffer();
- if(read_buffer->error)
- goto read_err;
- }
- unlock_fragments();
- fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
- - cache_block_put(fragment_buffer);
- if(duplicate_checking)
- add_non_dup(read_size, file_bytes, block_list, start, fragment,
- - 0, 0, FALSE);
- + 0, fragment_buffer ? fragment_buffer->checksum : 0,
- + FALSE, TRUE);
- + cache_block_put(fragment_buffer);
- file_count ++;
- total_bytes += read_size;
- @@ -2553,42 +2580,57 @@
- }
- -int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
- - long long read_size, struct file_buffer *read_buffer,
- - int *duplicate_file)
- +int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
- + struct file_buffer *read_buffer, int *duplicate_file)
- {
- - long long file_bytes, start;
- + int block, thresh;
- + long long read_size = read_buffer->file_size;
- + long long file_bytes, dup_start, start;
- struct fragment *fragment;
- - unsigned int *block_list;
- - int block, status;
- + struct file_info *dupl_ptr;
- int blocks = (read_size + block_size - 1) >> block_log;
- - long long sparse = 0;
- + unsigned int *block_list, *block_listp;
- + struct file_buffer **buffer_list;
- + int status;
- + long long sparse = 0;
- struct file_buffer *fragment_buffer = NULL;
- - *duplicate_file = FALSE;
- -
- block_list = malloc(blocks * sizeof(unsigned int));
- if(block_list == NULL)
- MEM_ERROR();
- + block_listp = block_list;
- +
- + buffer_list = malloc(blocks * sizeof(struct file_buffer *));
- + if(buffer_list == NULL)
- + MEM_ERROR();
- lock_fragments();
- file_bytes = 0;
- - start = bytes;
- + start = dup_start = bytes;
- + thresh = blocks > bwriter_size ? blocks - bwriter_size : 0;
- +
- for(block = 0; block < blocks;) {
- - if(read_buffer->fragment && read_buffer->c_byte) {
- + if(read_buffer->fragment) {
- block_list[block] = 0;
- + buffer_list[block] = NULL;
- fragment_buffer = read_buffer;
- blocks = read_size >> block_log;
- } else {
- block_list[block] = read_buffer->c_byte;
- +
- if(read_buffer->c_byte) {
- read_buffer->block = bytes;
- bytes += read_buffer->size;
- - cache_rehash(read_buffer, read_buffer->block);
- file_bytes += read_buffer->size;
- - queue_put(to_writer, read_buffer);
- + cache_hash(read_buffer, read_buffer->block);
- + if(block < thresh) {
- + buffer_list[block] = NULL;
- + queue_put(to_writer, read_buffer);
- + } else
- + buffer_list[block] = read_buffer;
- } else {
- + buffer_list[block] = NULL;
- sparse += read_buffer->size;
- cache_block_put(read_buffer);
- }
- @@ -2596,19 +2638,43 @@
- inc_progress_bar();
- if(++block < blocks) {
- - read_buffer = get_file_buffer(from_deflate);
- + read_buffer = get_file_buffer();
- if(read_buffer->error)
- goto read_err;
- }
- }
- + dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
- + &fragment, fragment_buffer, blocks, 0, FALSE);
- +
- + if(dupl_ptr) {
- + *duplicate_file = FALSE;
- + for(block = thresh; block < blocks; block ++)
- + if(buffer_list[block])
- + queue_put(to_writer, buffer_list[block]);
- + fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
- + dupl_ptr->fragment = fragment;
- + } else {
- + *duplicate_file = TRUE;
- + for(block = thresh; block < blocks; block ++)
- + cache_block_put(buffer_list[block]);
- + bytes = start;
- + if(thresh && !block_device) {
- + int res;
- +
- + queue_put(to_writer, NULL);
- + if(queue_get(from_writer) != 0)
- + EXIT_MKSQUASHFS();
- + res = ftruncate(fd, bytes);
- + if(res != 0)
- + BAD_ERROR("Failed to truncate dest file because"
- + " %s\n", strerror(errno));
- + }
- + }
- +
- unlock_fragments();
- - fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
- cache_block_put(fragment_buffer);
- -
- - if(duplicate_checking)
- - add_non_dup(read_size, file_bytes, block_list, start, fragment,
- - 0, 0, FALSE);
- + free(buffer_list);
- file_count ++;
- total_bytes += read_size;
- @@ -2623,13 +2689,11 @@
- if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
- sparse = 0;
- - create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
- - blocks, block_list, fragment, NULL, sparse);
- + create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
- + dup_start, blocks, block_listp, fragment, NULL, sparse);
- - if(duplicate_checking == FALSE) {
- + if(*duplicate_file == TRUE)
- free(block_list);
- - free_fragment(fragment);
- - }
- return 0;
- @@ -2637,7 +2701,7 @@
- dec_progress_bar(block);
- status = read_buffer->error;
- bytes = start;
- - if(!block_device) {
- + if(thresh && !block_device) {
- int res;
- queue_put(to_writer, NULL);
- @@ -2649,64 +2713,54 @@
- strerror(errno));
- }
- unlock_fragments();
- + for(blocks = thresh; blocks < block; blocks ++)
- + cache_block_put(buffer_list[blocks]);
- + free(buffer_list);
- free(block_list);
- cache_block_put(read_buffer);
- return status;
- }
- -int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
- - long long read_size, struct file_buffer *read_buffer,
- - int *duplicate_file)
- +int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
- + struct file_buffer *read_buffer, int *dup)
- {
- - int block, thresh;
- - long long file_bytes, dup_start, start;
- + long long read_size = read_buffer->file_size;
- + long long file_bytes, start;
- struct fragment *fragment;
- - struct file_info *dupl_ptr;
- + unsigned int *block_list;
- + int block, status;
- int blocks = (read_size + block_size - 1) >> block_log;
- - unsigned int *block_list, *block_listp;
- - struct file_buffer **buffer_list;
- - int status, num_locked_fragments;
- long long sparse = 0;
- struct file_buffer *fragment_buffer = NULL;
- + if(pre_duplicate(read_size))
- + return write_file_blocks_dup(inode, dir_ent, read_buffer, dup);
- +
- + *dup = FALSE;
- +
- block_list = malloc(blocks * sizeof(unsigned int));
- if(block_list == NULL)
- MEM_ERROR();
- - block_listp = block_list;
- - buffer_list = malloc(blocks * sizeof(struct file_buffer *));
- - if(buffer_list == NULL)
- - MEM_ERROR();
- -
- - num_locked_fragments = lock_fragments();
- + lock_fragments();
- file_bytes = 0;
- - start = dup_start = bytes;
- - thresh = blocks > (writer_buffer_size - num_locked_fragments) ?
- - blocks - (writer_buffer_size - num_locked_fragments): 0;
- -
- + start = bytes;
- for(block = 0; block < blocks;) {
- - if(read_buffer->fragment && read_buffer->c_byte) {
- + if(read_buffer->fragment) {
- block_list[block] = 0;
- - buffer_list[block] = NULL;
- fragment_buffer = read_buffer;
- blocks = read_size >> block_log;
- } else {
- block_list[block] = read_buffer->c_byte;
- -
- if(read_buffer->c_byte) {
- read_buffer->block = bytes;
- bytes += read_buffer->size;
- + cache_hash(read_buffer, read_buffer->block);
- file_bytes += read_buffer->size;
- - cache_rehash(read_buffer, read_buffer->block);
- - if(block < thresh) {
- - buffer_list[block] = NULL;
- - queue_put(to_writer, read_buffer);
- - } else
- - buffer_list[block] = read_buffer;
- + queue_put(to_writer, read_buffer);
- } else {
- - buffer_list[block] = NULL;
- sparse += read_buffer->size;
- cache_block_put(read_buffer);
- }
- @@ -2714,43 +2768,20 @@
- inc_progress_bar();
- if(++block < blocks) {
- - read_buffer = get_file_buffer(from_deflate);
- + read_buffer = get_file_buffer();
- if(read_buffer->error)
- goto read_err;
- }
- }
- - dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
- - &fragment, fragment_buffer, blocks, 0, 0, FALSE);
- -
- - if(dupl_ptr) {
- - *duplicate_file = FALSE;
- - for(block = thresh; block < blocks; block ++)
- - if(buffer_list[block])
- - queue_put(to_writer, buffer_list[block]);
- - fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
- - dupl_ptr->fragment = fragment;
- - } else {
- - *duplicate_file = TRUE;
- - for(block = thresh; block < blocks; block ++)
- - cache_block_put(buffer_list[block]);
- - bytes = start;
- - if(thresh && !block_device) {
- - int res;
- -
- - queue_put(to_writer, NULL);
- - if(queue_get(from_writer) != 0)
- - EXIT_MKSQUASHFS();
- - res = ftruncate(fd, bytes);
- - if(res != 0)
- - BAD_ERROR("Failed to truncate dest file because"
- - " %s\n", strerror(errno));
- - }
- - }
- -
- unlock_fragments();
- + fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
- +
- + if(duplicate_checking)
- + add_non_dup(read_size, file_bytes, block_list, start, fragment,
- + 0, fragment_buffer ? fragment_buffer->checksum : 0,
- + FALSE, TRUE);
- cache_block_put(fragment_buffer);
- - free(buffer_list);
- file_count ++;
- total_bytes += read_size;
- @@ -2765,11 +2796,13 @@
- if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
- sparse = 0;
- - create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
- - dup_start, blocks, block_listp, fragment, NULL, sparse);
- + create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
- + blocks, block_list, fragment, NULL, sparse);
- - if(*duplicate_file == TRUE)
- + if(duplicate_checking == FALSE) {
- free(block_list);
- + free_fragment(fragment);
- + }
- return 0;
- @@ -2777,7 +2810,7 @@
- dec_progress_bar(block);
- status = read_buffer->error;
- bytes = start;
- - if(thresh && !block_device) {
- + if(!block_device) {
- int res;
- queue_put(to_writer, NULL);
- @@ -2789,58 +2822,40 @@
- strerror(errno));
- }
- unlock_fragments();
- - for(blocks = thresh; blocks < block; blocks ++)
- - cache_block_put(buffer_list[blocks]);
- - free(buffer_list);
- free(block_list);
- cache_block_put(read_buffer);
- return status;
- }
- -void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
- - int *duplicate_file)
- +void write_file(squashfs_inode *inode, struct dir_ent *dir, int *dup)
- {
- int status;
- struct file_buffer *read_buffer;
- - long long read_size;
- again:
- - read_buffer = get_file_buffer(from_deflate);
- -
- + read_buffer = get_file_buffer();
- status = read_buffer->error;
- - if(status) {
- - cache_block_put(read_buffer);
- - goto file_err;
- - }
- -
- - read_size = read_buffer->file_size;
- - if(read_size == -1)
- - status = write_file_process(inode, dir_ent, read_buffer,
- - duplicate_file);
- - else if(read_size == 0) {
- - write_file_empty(inode, dir_ent, duplicate_file);
- + if(status)
- cache_block_put(read_buffer);
- - } else if(read_buffer->fragment && read_buffer->c_byte)
- - write_file_frag(inode, dir_ent, read_size, read_buffer,
- - duplicate_file);
- - else if(pre_duplicate(read_size))
- - status = write_file_blocks_dup(inode, dir_ent, read_size,
- - read_buffer, duplicate_file);
- + else if(read_buffer->file_size == -1)
- + status = write_file_process(inode, dir, read_buffer, dup);
- + else if(read_buffer->file_size == 0)
- + write_file_empty(inode, dir, read_buffer, dup);
- + else if(read_buffer->fragment && read_buffer->c_byte)
- + write_file_frag(inode, dir, read_buffer, dup);
- else
- - status = write_file_blocks(inode, dir_ent, read_size,
- - read_buffer, duplicate_file);
- + status = write_file_blocks(inode, dir, read_buffer, dup);
- -file_err:
- if(status == 2) {
- ERROR("File %s changed size while reading filesystem, "
- - "attempting to re-read\n", pathname(dir_ent));
- + "attempting to re-read\n", pathname(dir));
- goto again;
- } else if(status == 1) {
- - ERROR("Failed to read file %s, creating empty file\n",
- - pathname(dir_ent));
- - write_file_empty(inode, dir_ent, duplicate_file);
- + ERROR_START("Failed to read file %s", pathname(dir));
- + ERROR_EXIT(", creating empty file\n");
- + write_file_empty(inode, dir, NULL, dup);
- }
- }
- @@ -2921,7 +2936,8 @@
- }
- -struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
- +struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id,
- + char *symlink, int bytes)
- {
- int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
- struct inode_info *inode;
- @@ -2941,10 +2957,12 @@
- }
- }
- - inode = malloc(sizeof(struct inode_info));
- + inode = malloc(sizeof(struct inode_info) + bytes);
- if(inode == NULL)
- MEM_ERROR();
- + if(bytes)
- + memcpy(&inode->symlink, symlink, bytes);
- memcpy(&inode->buf, buf, sizeof(struct stat));
- inode->read = FALSE;
- inode->root_entry = FALSE;
- @@ -2965,9 +2983,6 @@
- inode->noD = noD;
- inode->noF = noF;
- - if((buf->st_mode & S_IFMT) == S_IFREG)
- - progress_bar_size((buf->st_size + block_size - 1) >> block_log);
- -
- inode->next = inode_info[ino_hash];
- inode_info[ino_hash] = inode;
- @@ -2975,6 +2990,12 @@
- }
- +struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
- +{
- + return lookup_inode3(buf, pseudo, id, NULL, 0);
- +}
- +
- +
- inline struct inode_info *lookup_inode(struct stat *buf)
- {
- return lookup_inode2(buf, 0, 0);
- @@ -2983,8 +3004,12 @@
- inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
- {
- - if (inode->inode_number == 0)
- + if (inode->inode_number == 0) {
- inode->inode_number = use_this ? : inode_no ++;
- + if((inode->buf.st_mode & S_IFMT) == S_IFREG)
- + progress_bar_size((inode->buf.st_size + block_size - 1)
- + >> block_log);
- + }
- }
- @@ -2999,6 +3024,7 @@
- dir_ent->source_name = source_name;
- dir_ent->nonstandard_pathname = nonstandard_pathname;
- dir_ent->our_dir = dir;
- + dir_ent->inode = NULL;
- dir_ent->next = NULL;
- return dir_ent;
- @@ -3041,6 +3067,15 @@
- if(dir_ent->source_name)
- free(dir_ent->source_name);
- + if(dir_ent->nonstandard_pathname)
- + free(dir_ent->nonstandard_pathname);
- +
- + /* if this entry has been associated with an inode, then we need
- + * to update the inode nlink count. Orphaned inodes are harmless, and
- + * is easier to leave them than go to the bother of deleting them */
- + if(dir_ent->inode && !dir_ent->inode->root_entry)
- + dir_ent->inode->nlink --;
- +
- free(dir_ent);
- }
- @@ -3051,42 +3086,18 @@
- }
- -
- void dir_scan(squashfs_inode *inode, char *pathname,
- - struct dir_ent *(_readdir)(struct dir_info *))
- + struct dir_ent *(_readdir)(struct dir_info *), int progress)
- {
- struct stat buf;
- - struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1);
- struct dir_ent *dir_ent;
- - if(dir_info == NULL)
- + root_dir = dir_scan1(pathname, "", paths, _readdir, 1);
- + if(root_dir == NULL)
- return;
- - /*
- - * Process most actions and any pseudo files
- - */
- - if(actions() || get_pseudo())
- - dir_scan2(dir_info, get_pseudo());
- -
- - /*
- - * Process move actions
- - */
- - if(move_actions()) {
- - dir_scan3(dir_info, dir_info);
- - do_move_actions();
- - }
- -
- - /*
- - * Process empty actions
- - */
- - if(empty_actions())
- - dir_scan4(dir_info);
- -
- - /*
- - * Sort directories and compute the inode numbers
- - */
- - dir_scan5(dir_info);
- -
- + /* Create root directory dir_ent and associated inode, and connect
- + * it to the root directory dir_info structure */
- dir_ent = create_dir_entry("", NULL, pathname,
- scan1_opendir("", "", 0));
- @@ -3111,21 +3122,69 @@
- dir_ent->inode = lookup_inode(&buf);
- }
- + dir_ent->dir = root_dir;
- + root_dir->dir_ent = dir_ent;
- +
- + /*
- + * Process most actions and any pseudo files
- + */
- + if(actions() || get_pseudo())
- + dir_scan2(root_dir, get_pseudo());
- +
- + /*
- + * Process move actions
- + */
- + if(move_actions()) {
- + dir_scan3(root_dir);
- + do_move_actions();
- + }
- +
- + /*
- + * Process prune actions
- + */
- + if(prune_actions())
- + dir_scan4(root_dir);
- +
- + /*
- + * Process empty actions
- + */
- + if(empty_actions())
- + dir_scan5(root_dir);
- +
- + /*
- + * Sort directories and compute the inode numbers
- + */
- + dir_scan6(root_dir);
- +
- alloc_inode_no(dir_ent->inode, root_inode_number);
- - dir_ent->dir = dir_info;
- - dir_info->dir_ent = dir_ent;
- - eval_actions(dir_ent);
- + eval_actions(root_dir, dir_ent);
- if(sorted)
- - generate_file_priorities(dir_info, 0,
- - &dir_info->dir_ent->inode->buf);
- - queue_put(to_reader, dir_info);
- + generate_file_priorities(root_dir, 0,
- + &root_dir->dir_ent->inode->buf);
- +
- + if(appending) {
- + sigset_t sigmask;
- +
- + restore_thread = init_restore_thread();
- + sigemptyset(&sigmask);
- + sigaddset(&sigmask, SIGINT);
- + sigaddset(&sigmask, SIGTERM);
- + sigaddset(&sigmask, SIGUSR1);
- + if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
- + BAD_ERROR("Failed to set signal mask\n");
- + write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
- + }
- +
- + queue_put(to_reader, root_dir);
- +
- + set_progressbar_state(progress);
- +
- if(sorted)
- - sort_files_and_write(dir_info);
- - if(progress)
- - enable_progress_bar();
- - dir_scan6(inode, dir_info);
- + sort_files_and_write(root_dir);
- +
- + dir_scan7(inode, root_dir);
- dir_ent->inode->inode = *inode;
- dir_ent->inode->type = SQUASHFS_DIR_TYPE;
- }
- @@ -3187,8 +3246,9 @@
- int pass = 1, res;
- if(dir_name == NULL) {
- - ERROR("Bad source directory %s - skipping ...\n",
- + ERROR_START("Bad source directory %s",
- source_path[index]);
- + ERROR_EXIT(" - skipping ...\n");
- index ++;
- continue;
- }
- @@ -3213,7 +3273,7 @@
- ERROR("%s\n", dir_name);
- }
- return create_dir_entry(dir_name, basename,
- - source_path[index ++], dir);
- + strdup(source_path[index ++]), dir);
- }
- return NULL;
- }
- @@ -3289,7 +3349,8 @@
- struct dir_ent *dir_ent;
- if(dir == NULL) {
- - ERROR("Could not open %s, skipping...\n", filename);
- + ERROR_START("Could not open %s", filename);
- + ERROR_EXIT(", skipping...\n");
- return NULL;
- }
- @@ -3307,8 +3368,9 @@
- }
- if(lstat(filename, &buf) == -1) {
- - ERROR("Cannot stat dir/file %s because %s, ignoring\n",
- + ERROR_START("Cannot stat dir/file %s because %s",
- filename, strerror(errno));
- + ERROR_EXIT(", ignoring\n");
- free_dir_entry(dir_ent);
- continue;
- }
- @@ -3320,8 +3382,9 @@
- (buf.st_mode & S_IFMT) != S_IFBLK &&
- (buf.st_mode & S_IFMT) != S_IFIFO &&
- (buf.st_mode & S_IFMT) != S_IFSOCK) {
- - ERROR("File %s has unrecognised filetype %d, ignoring"
- - "\n", filename, buf.st_mode & S_IFMT);
- + ERROR_START("File %s has unrecognised filetype %d",
- + filename, buf.st_mode & S_IFMT);
- + ERROR_EXIT(", ignoring\n");
- free_dir_entry(dir_ent);
- continue;
- }
- @@ -3337,30 +3400,53 @@
- subpath = subpathname(dir_ent);
- if(eval_exclude_actions(dir_name, filename, subpath,
- - &buf, depth)) {
- + &buf, depth, dir_ent)) {
- add_excluded(dir);
- free_dir_entry(dir_ent);
- continue;
- }
- }
- - if((buf.st_mode & S_IFMT) == S_IFDIR) {
- + switch(buf.st_mode & S_IFMT) {
- + case S_IFDIR:
- if(subpath == NULL)
- subpath = subpathname(dir_ent);
- sub_dir = dir_scan1(filename, subpath, new,
- scan1_readdir, depth + 1);
- - if(sub_dir == NULL) {
- + if(sub_dir) {
- + dir->directory_count ++;
- + add_dir_entry(dir_ent, sub_dir,
- + lookup_inode(&buf));
- + } else
- free_dir_entry(dir_ent);
- - free(new);
- - continue;
- + break;
- + case S_IFLNK: {
- + int byte;
- + static char buff[65536]; /* overflow safe */
- +
- + byte = readlink(filename, buff, 65536);
- + if(byte == -1) {
- + ERROR_START("Failed to read symlink %s",
- + filename);
- + ERROR_EXIT(", ignoring\n");
- + } else if(byte == 65536) {
- + ERROR_START("Symlink %s is greater than 65536 "
- + "bytes!", filename);
- + ERROR_EXIT(", ignoring\n");
- + } else {
- + /* readlink doesn't 0 terminate the returned
- + * path */
- + buff[byte] = '\0';
- + add_dir_entry(dir_ent, NULL, lookup_inode3(&buf,
- + 0, 0, buff, byte + 1));
- }
- + break;
- + }
- + default:
- + add_dir_entry(dir_ent, NULL, lookup_inode(&buf));
- + }
- - dir->directory_count ++;
- - } else
- - sub_dir = NULL;
- -
- - add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
- free(new);
- }
- @@ -3410,7 +3496,7 @@
- struct stat *buf = &inode_info->buf;
- char *name = dir_ent->name;
- - eval_actions(dir_ent);
- + eval_actions(root_dir, dir_ent);
- if((buf->st_mode & S_IFMT) == S_IFDIR)
- dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
- @@ -3421,16 +3507,18 @@
- if(pseudo_ent->dev->type == 'm') {
- struct stat *buf;
- if(dir_ent == NULL) {
- - ERROR("Pseudo modify file \"%s\" does not exist "
- - "in source filesystem. Ignoring.\n",
- + ERROR_START("Pseudo modify file \"%s\" does "
- + "not exist in source filesystem.",
- pseudo_ent->pathname);
- + ERROR_EXIT(" Ignoring.\n");
- continue;
- }
- if(dir_ent->inode->root_entry) {
- - ERROR("Pseudo modify file \"%s\" is a pre-existing"
- - " file in the filesystem being appended"
- - " to. It cannot be modified. "
- - "Ignoring.\n", pseudo_ent->pathname);
- + ERROR_START("Pseudo modify file \"%s\" is a "
- + "pre-existing file in the filesystem "
- + "being appended to. It cannot be "\
- + "modified.", pseudo_ent->pathname);
- + ERROR_EXIT(" Ignoring.\n");
- continue;
- }
- buf = &dir_ent->inode->buf;
- @@ -3442,17 +3530,20 @@
- }
- if(dir_ent) {
- - if(dir_ent->inode->root_entry)
- - ERROR("Pseudo file \"%s\" is a pre-existing"
- - " file in the filesystem being appended"
- - " to. Ignoring.\n",
- + if(dir_ent->inode->root_entry) {
- + ERROR_START("Pseudo file \"%s\" is a "
- + "pre-existing file in the filesystem "
- + "being appended to.",
- pseudo_ent->pathname);
- - else
- - ERROR("Pseudo file \"%s\" exists in source "
- - "filesystem \"%s\".\nIgnoring, "
- - "exclude it (-e/-ef) to override.\n",
- + ERROR_EXIT(" Ignoring.\n");
- + } else {
- + ERROR_START("Pseudo file \"%s\" exists in "
- + "source filesystem \"%s\".",
- pseudo_ent->pathname,
- pathname(dir_ent));
- + ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to "
- + "override.\n");
- + }
- continue;
- }
- @@ -3473,9 +3564,9 @@
- struct dir_info *sub_dir = scan1_opendir("", subpath,
- dir->depth + 1);
- if(sub_dir == NULL) {
- - ERROR("Could not create pseudo directory \"%s\""
- - ", skipping...\n",
- - pseudo_ent->pathname);
- + ERROR_START("Could not create pseudo directory "
- + "\"%s\"", pseudo_ent->pathname);
- + ERROR_EXIT(", skipping...\n");
- free(subpath);
- pseudo_ino --;
- continue;
- @@ -3485,25 +3576,10 @@
- add_dir_entry(dir_ent, sub_dir,
- lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
- } else if(pseudo_ent->dev->type == 'f') {
- -#ifdef USE_TMP_FILE
- - struct stat buf2;
- - int res = stat(pseudo_ent->dev->filename, &buf2);
- - if(res == -1) {
- - ERROR("Stat on pseudo file \"%s\" failed, "
- - "skipping...\n", pseudo_ent->pathname);
- - pseudo_ino --;
- - continue;
- - }
- - buf.st_size = buf2.st_size;
- - add_dir_entry2(pseudo_ent->name, NULL,
- - pseudo_ent->dev->filename, NULL,
- - lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
- -#else
- add_dir_entry2(pseudo_ent->name, NULL,
- pseudo_ent->pathname, NULL,
- lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
- pseudo_ent->dev->pseudo_id), dir);
- -#endif
- } else {
- add_dir_entry2(pseudo_ent->name, NULL,
- pseudo_ent->pathname, NULL,
- @@ -3517,35 +3593,113 @@
- * dir_scan3 routines...
- * This processes the move action
- */
- -void dir_scan3(struct dir_info *root, struct dir_info *dir)
- +void dir_scan3(struct dir_info *dir)
- {
- struct dir_ent *dir_ent = NULL;
- while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
- - eval_move_actions(root, dir_ent);
- + eval_move_actions(root_dir, dir_ent);
- if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
- - dir_scan3(root, dir_ent->dir);
- + dir_scan3(dir_ent->dir);
- }
- }
- /*
- * dir_scan4 routines...
- + * This processes the prune action. This action is designed to do fine
- + * grained tuning of the in-core directory structure after the exclude,
- + * move and pseudo actions have been performed. This allows complex
- + * tests to be performed which are impossible at exclude time (i.e.
- + * tests which rely on the in-core directory structure)
- + */
- +void free_dir(struct dir_info *dir)
- +{
- + struct dir_ent *dir_ent = dir->list;
- +
- + while(dir_ent) {
- + struct dir_ent *tmp = dir_ent;
- +
- + if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
- + free_dir(dir_ent->dir);
- +
- + dir_ent = dir_ent->next;
- + free_dir_entry(tmp);
- + }
- +
- + free(dir->pathname);
- + free(dir->subpath);
- + free(dir);
- +}
- +
- +
- +void dir_scan4(struct dir_info *dir)
- +{
- + struct dir_ent *dir_ent = dir->list, *prev = NULL;
- +
- + while(dir_ent) {
- + if(dir_ent->inode->root_entry) {
- + prev = dir_ent;
- + dir_ent = dir_ent->next;
- + continue;
- + }
- +
- + if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
- + dir_scan4(dir_ent->dir);
- +
- + if(eval_prune_actions(root_dir, dir_ent)) {
- + struct dir_ent *tmp = dir_ent;
- +
- + if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
- + free_dir(dir_ent->dir);
- + dir->directory_count --;
- + }
- +
- + dir->count --;
- +
- + /* remove dir_ent from list */
- + dir_ent = dir_ent->next;
- + if(prev)
- + prev->next = dir_ent;
- + else
- + dir->list = dir_ent;
- +
- + /* free it */
- + free_dir_entry(tmp);
- +
- + add_excluded(dir);
- + continue;
- + }
- +
- + prev = dir_ent;
- + dir_ent = dir_ent->next;
- + }
- +}
- +
- +
- +/*
- + * dir_scan5 routines...
- * This processes the empty action. This action has to be processed after
- * all other actions because the previous exclude and move actions and the
- * pseudo actions affect whether a directory is empty
- */
- -void dir_scan4(struct dir_info *dir)
- +void dir_scan5(struct dir_info *dir)
- {
- struct dir_ent *dir_ent = dir->list, *prev = NULL;
- while(dir_ent) {
- + if(dir_ent->inode->root_entry) {
- + prev = dir_ent;
- + dir_ent = dir_ent->next;
- + continue;
- + }
- +
- if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
- - dir_scan4(dir_ent->dir);
- + dir_scan5(dir_ent->dir);
- - if(eval_empty_actions(dir_ent)) {
- + if(eval_empty_actions(root_dir, dir_ent)) {
- struct dir_ent *tmp = dir_ent;
- /*
- @@ -3581,7 +3735,7 @@
- /*
- - * dir_scan5 routines...
- + * dir_scan6 routines...
- * This sorts every directory and computes the inode numbers
- */
- @@ -3599,7 +3753,7 @@
- struct dir_ent *cur, *l1, *l2, *next;
- int len1, len2, stride = 1;
- - if(dir->count < 2)
- + if(dir->list == NULL || dir->count < 2)
- return;
- /*
- @@ -3674,7 +3828,7 @@
- }
- -void dir_scan5(struct dir_info *dir)
- +void dir_scan6(struct dir_info *dir)
- {
- struct dir_ent *dir_ent;
- unsigned int byte_count = 0;
- @@ -3691,7 +3845,7 @@
- alloc_inode_no(dir_ent->inode, 0);
- if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
- - dir_scan5(dir_ent->dir);
- + dir_scan6(dir_ent->dir);
- }
- if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
- @@ -3703,7 +3857,7 @@
- * dir_scan6 routines...
- * This generates the filesystem metadata and writes it out to the destination
- */
- -void scan6_init_dir(struct directory *dir)
- +void scan7_init_dir(struct directory *dir)
- {
- dir->buff = malloc(SQUASHFS_METADATA_SIZE);
- if(dir->buff == NULL)
- @@ -3718,7 +3872,7 @@
- }
- -struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info,
- +struct dir_ent *scan7_readdir(struct directory *dir, struct dir_info *dir_info,
- struct dir_ent *dir_ent)
- {
- if (dir_ent == NULL)
- @@ -3734,7 +3888,7 @@
- }
- -void scan6_freedir(struct directory *dir)
- +void scan7_freedir(struct directory *dir)
- {
- if(dir->index)
- free(dir->index);
- @@ -3742,16 +3896,16 @@
- }
- -void dir_scan6(squashfs_inode *inode, struct dir_info *dir_info)
- +void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info)
- {
- int squashfs_type;
- int duplicate_file;
- struct directory dir;
- struct dir_ent *dir_ent = NULL;
- - scan6_init_dir(&dir);
- + scan7_init_dir(&dir);
- - while((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) {
- + while((dir_ent = scan7_readdir(&dir, dir_info, dir_ent)) != NULL) {
- struct stat *buf = &dir_ent->inode->buf;
- update_info(dir_ent);
- @@ -3772,7 +3926,7 @@
- case S_IFDIR:
- squashfs_type = SQUASHFS_DIR_TYPE;
- - dir_scan6(inode, dir_ent->dir);
- + dir_scan7(inode, dir_ent->dir);
- break;
- case S_IFLNK:
- @@ -3883,7 +4037,7 @@
- INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
- *inode);
- - scan6_freedir(&dir);
- + scan7_freedir(&dir);
- }
- @@ -3928,8 +4082,9 @@
- if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
- strncmp(path, "../", 3) == 0) {
- if(lstat(path, &buf) == -1) {
- - ERROR("Cannot stat exclude dir/file %s because %s, "
- - "ignoring\n", path, strerror(errno));
- + ERROR_START("Cannot stat exclude dir/file %s because "
- + "%s", path, strerror(errno));
- + ERROR_EXIT(", ignoring\n");
- return TRUE;
- }
- ADD_ENTRY(buf);
- @@ -3941,10 +4096,11 @@
- if(res == -1)
- BAD_ERROR("asprintf failed in old_add_exclude\n");
- if(lstat(filename, &buf) == -1) {
- - if(!(errno == ENOENT || errno == ENOTDIR))
- - ERROR("Cannot stat exclude dir/file %s because "
- - "%s, ignoring\n", filename,
- - strerror(errno));
- + if(!(errno == ENOENT || errno == ENOTDIR)) {
- + ERROR_START("Cannot stat exclude dir/file %s "
- + "because %s", filename, strerror(errno));
- + ERROR_EXIT(", ignoring\n");
- + }
- free(filename);
- continue;
- }
- @@ -3971,39 +4127,50 @@
- }
- -void initialise_threads(int readb_mbytes, int writeb_mbytes,
- - int fragmentb_mbytes)
- +void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq,
- + int freelst, char *destination_file)
- {
- int i;
- sigset_t sigmask, old_mask;
- - int reader_buffer_size;
- - int fragment_buffer_size;
- + int total_mem = readq;
- + int reader_size;
- + int fragment_size;
- + int fwriter_size;
- /*
- - * writer_buffer_size is global because it is needed in
- + * bwriter_size is global because it is needed in
- * write_file_blocks_dup()
- */
- /*
- + * Never allow the total size of the queues to be larger than
- + * physical memory
- + *
- + * When adding together the possibly user supplied values, make
- + * sure they've not been deliberately contrived to overflow an int
- + */
- + if(add_overflow(total_mem, fragq))
- + BAD_ERROR("Queue sizes rediculously too large\n");
- + total_mem += fragq;
- + if(add_overflow(total_mem, bwriteq))
- + BAD_ERROR("Queue sizes rediculously too large\n");
- + total_mem += bwriteq;
- + if(add_overflow(total_mem, fwriteq))
- + BAD_ERROR("Queue sizes rediculously too large\n");
- + total_mem += fwriteq;
- +
- + check_usable_phys_mem(total_mem);
- +
- + /*
- * convert from queue size in Mbytes to queue size in
- * blocks.
- *
- - * In doing so, check that the user supplied values do not
- - * overflow a signed int
- + * This isn't going to overflow an int unless there exists
- + * systems with more than 8 Petabytes of RAM!
- */
- - if(shift_overflow(readb_mbytes, 20 - block_log))
- - BAD_ERROR("Read queue is too large\n");
- - else
- - reader_buffer_size = readb_mbytes << (20 - block_log);
- -
- - if(shift_overflow(fragmentb_mbytes, 20 - block_log))
- - BAD_ERROR("Fragment queue is too large\n");
- - else
- - fragment_buffer_size = fragmentb_mbytes << (20 - block_log);
- -
- - if(shift_overflow(writeb_mbytes, 20 - block_log))
- - BAD_ERROR("Write queue is too large\n");
- - else
- - writer_buffer_size = writeb_mbytes << (20 - block_log);
- + reader_size = readq << (20 - block_log);
- + fragment_size = fragq << (20 - block_log);
- + bwriter_size = bwriteq << (20 - block_log);
- + fwriter_size = fwriteq << (20 - block_log);
- /*
- * setup signal handlers for the main thread, these cleanup
- @@ -4020,10 +4187,11 @@
- signal(SIGINT, sighandler);
- signal(SIGUSR1, sighandler);
- - /* block SIGQUIT this is handled by the info thread */
- + /* block SIGQUIT and SIGHUP, these are handled by the info thread */
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGQUIT);
- - if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
- + sigaddset(&sigmask, SIGHUP);
- + if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
- BAD_ERROR("Failed to set signal mask in intialise_threads\n");
- /*
- @@ -4050,8 +4218,9 @@
- #endif
- if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
- - ERROR("Failed to get number of available processors. "
- - "Defaulting to 1\n");
- + ERROR_START("Failed to get number of available "
- + "processors.");
- + ERROR_EXIT(" Defaulting to 1\n");
- processors = 1;
- }
- #else
- @@ -4059,44 +4228,48 @@
- #endif
- }
- - if(multiply_overflow(processors, 2) ||
- - add_overflow(processors * 2, 2) ||
- - multiply_overflow(processors * 2 + 2,
- - sizeof(pthread_t)))
- + if(multiply_overflow(processors, 3) ||
- + multiply_overflow(processors * 3, sizeof(pthread_t)))
- BAD_ERROR("Processors too large\n");
- - thread = malloc((2 + processors * 2) * sizeof(pthread_t));
- - if(thread == NULL)
- + deflator_thread = malloc(processors * 3 * sizeof(pthread_t));
- + if(deflator_thread == NULL)
- MEM_ERROR();
- - deflator_thread = &thread[2];
- frag_deflator_thread = &deflator_thread[processors];
- + frag_thread = &frag_deflator_thread[processors];
- to_reader = queue_init(1);
- - from_reader = queue_init(reader_buffer_size);
- - to_writer = queue_init(writer_buffer_size);
- + to_deflate = queue_init(reader_size);
- + to_process_frag = queue_init(reader_size);
- + to_writer = queue_init(bwriter_size + fwriter_size);
- from_writer = queue_init(1);
- - from_deflate = queue_init(reader_buffer_size);
- - to_frag = queue_init(fragment_buffer_size);
- - reader_buffer = cache_init(block_size, reader_buffer_size);
- - writer_buffer = cache_init(block_size, writer_buffer_size);
- - fragment_buffer = cache_init(block_size, fragment_buffer_size);
- - pthread_create(&thread[0], NULL, reader, NULL);
- - pthread_create(&thread[1], NULL, writer, NULL);
- + to_frag = queue_init(fragment_size);
- + locked_fragment = queue_init(fragment_size);
- + to_main = seq_queue_init();
- + reader_buffer = cache_init(block_size, reader_size, 0, 0);
- + bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst);
- + fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst);
- + fragment_buffer = cache_init(block_size, fragment_size, 1, 0);
- + reserve_cache = cache_init(block_size, processors + 1, 1, 0);
- + pthread_create(&reader_thread, NULL, reader, NULL);
- + pthread_create(&writer_thread, NULL, writer, NULL);
- init_progress_bar();
- init_info();
- - pthread_mutex_init(&fragment_mutex, NULL);
- - pthread_cond_init(&fragment_waiting, NULL);
- for(i = 0; i < processors; i++) {
- - if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
- - 0)
- + if(pthread_create(&deflator_thread[i], NULL, deflator, NULL))
- BAD_ERROR("Failed to create thread\n");
- if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
- NULL) != 0)
- BAD_ERROR("Failed to create thread\n");
- + if(pthread_create(&frag_thread[i], NULL, frag_thrd,
- + (void *) destination_file) != 0)
- + BAD_ERROR("Failed to create thread\n");
- }
- + main_thread = pthread_self();
- +
- printf("Parallel mksquashfs: Using %d processor%s\n", processors,
- processors == 1 ? "" : "s");
- @@ -4120,12 +4293,21 @@
- inode_lookup_table = it;
- for(i = 0; i < INODE_HASH_SIZE; i ++) {
- - struct inode_info *inode = inode_info[i];
- + struct inode_info *inode;
- for(inode = inode_info[i]; inode; inode = inode->next) {
- inode_number = get_inode_no(inode);
- + /* The empty action will produce orphaned inode
- + * entries in the inode_info[] table. These
- + * entries because they are orphaned will not be
- + * allocated an inode number in dir_scan5(), so
- + * skip any entries with the default dummy inode
- + * number of 0 */
- + if(inode_number == 0)
- + continue;
- +
- SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
- &inode_lookup_table[inode_number - 1], 1);
- @@ -4146,11 +4328,14 @@
- target ++;
- start = target;
- - while(*target != '/' && *target!= '\0')
- + while(*target != '/' && *target != '\0')
- target ++;
- *targname = strndup(start, target - start);
- + while(*target == '/')
- + target ++;
- +
- return target;
- }
- @@ -4550,91 +4735,23 @@
- MEM_ERROR();
- res = read_bytes(recoverfd, metadata, bytes);
- - if(res == -1)
- - BAD_ERROR("Failed to read recovery file, because %s\n",
- - strerror(errno));
- - if(res < bytes)
- - BAD_ERROR("Recovery file appears to be truncated\n");
- -
- - write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
- -
- - write_destination(fd, sBlk.inode_table_start, bytes, metadata);
- -
- - close(recoverfd);
- - close(fd);
- -
- - printf("Successfully wrote recovery file \"%s\". Exiting\n",
- - recovery_file);
- -
- - exit(0);
- -}
- -
- -
- -int parse_number(char *start, int *res, int size)
- -{
- - char *end;
- - long number = strtol(start, &end, 10);
- -
- - /*
- - * check for strtol underflow or overflow in conversion.
- - * Note: strtol can validly return LONG_MIN and LONG_MAX
- - * if the user entered these values, but, additional code
- - * to distinguish this scenario is unnecessary, because for
- - * our purposes LONG_MIN and LONG_MAX are too large anyway
- - */
- - if(number == LONG_MIN || number == LONG_MAX)
- - return 0;
- -
- - /* reject negative numbers as invalid */
- - if(number < 0)
- - return 0;
- -
- - /* check if long result will overflow signed int */
- - if(number > INT_MAX)
- - return 0;
- -
- - if(size) {
- - /*
- - * Check for multiplier and trailing junk.
- - * But first check that a number exists before the
- - * multiplier
- - */
- - if(end == start)
- - return 0;
- -
- - switch(end[0]) {
- - case 'm':
- - case 'M':
- - if(multiply_overflow((int) number, 1048576))
- - return 0;
- - number *= 1048576;
- + if(res == -1)
- + BAD_ERROR("Failed to read recovery file, because %s\n",
- + strerror(errno));
- + if(res < bytes)
- + BAD_ERROR("Recovery file appears to be truncated\n");
- - if(end[1] != '\0')
- - /* trailing junk after number */
- - return 0;
- + write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
- - break;
- - case 'k':
- - case 'K':
- - if(multiply_overflow((int) number, 1024))
- - return 0;
- - number *= 1024;
- + write_destination(fd, sBlk.inode_table_start, bytes, metadata);
- - if(end[1] != '\0')
- - /* trailing junk after number */
- - return 0;
- - case '\0':
- - break;
- - default:
- - /* trailing junk after number */
- - return 0;
- - }
- - } else if(end[0] != '\0')
- - /* trailing junk after number */
- - return 0;
- + close(recoverfd);
- + close(fd);
- - *res = number;
- - return 1;
- + printf("Successfully wrote recovery file \"%s\". Exiting\n",
- + recovery_file);
- +
- + exit(0);
- }
- @@ -4674,8 +4791,6 @@
- close(fd);
- - delete_pseudo_files();
- -
- if(recovery_file)
- unlink(recovery_file);
- @@ -4750,15 +4865,233 @@
- }
- +int parse_numberll(char *start, long long *res, int size)
- +{
- + char *end;
- + long long number;
- +
- + errno = 0; /* To distinguish success/failure after call */
- +
- + number = strtoll(start, &end, 10);
- +
- + /*
- + * check for strtoll underflow or overflow in conversion, and other
- + * errors.
- + */
- + if((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) ||
- + (errno != 0 && number == 0))
- + return 0;
- +
- + /* reject negative numbers as invalid */
- + if(number < 0)
- + return 0;
- +
- + if(size) {
- + /*
- + * Check for multiplier and trailing junk.
- + * But first check that a number exists before the
- + * multiplier
- + */
- + if(end == start)
- + return 0;
- +
- + switch(end[0]) {
- + case 'g':
- + case 'G':
- + if(multiply_overflowll(number, 1073741824))
- + return 0;
- + number *= 1073741824;
- +
- + if(end[1] != '\0')
- + /* trailing junk after multiplier, but
- + * allow it to be "bytes" */
- + if(strcmp(end + 1, "bytes"))
- + return 0;
- +
- + break;
- + case 'm':
- + case 'M':
- + if(multiply_overflowll(number, 1048576))
- + return 0;
- + number *= 1048576;
- +
- + if(end[1] != '\0')
- + /* trailing junk after multiplier, but
- + * allow it to be "bytes" */
- + if(strcmp(end + 1, "bytes"))
- + return 0;
- +
- + break;
- + case 'k':
- + case 'K':
- + if(multiply_overflowll(number, 1024))
- + return 0;
- + number *= 1024;
- +
- + if(end[1] != '\0')
- + /* trailing junk after multiplier, but
- + * allow it to be "bytes" */
- + if(strcmp(end + 1, "bytes"))
- + return 0;
- +
- + break;
- + case '\0':
- + break;
- + default:
- + /* trailing junk after number */
- + return 0;
- + }
- + } else if(end[0] != '\0')
- + /* trailing junk after number */
- + return 0;
- +
- + *res = number;
- + return 1;
- +}
- +
- +
- +int parse_number(char *start, int *res, int size)
- +{
- + long long number;
- +
- + if(!parse_numberll(start, &number, size))
- + return 0;
- +
- + /* check if long result will overflow signed int */
- + if(number > INT_MAX)
- + return 0;
- +
- + *res = (int) number;
- + return 1;
- +}
- +
- +
- int parse_num(char *arg, int *res)
- {
- return parse_number(arg, res, 0);
- }
- +int get_physical_memory()
- +{
- + /*
- + * Long longs are used here because with PAE, a 32-bit
- + * machine can have more than 4GB of physical memory
- + *
- + * sysconf(_SC_PHYS_PAGES) relies on /proc being mounted.
- + * If it isn't fail.
- + */
- + long long num_pages = sysconf(_SC_PHYS_PAGES);
- + long long page_size = sysconf(_SC_PAGESIZE);
- + int phys_mem = num_pages * page_size >> 20;
- +
- + if(num_pages == -1 || page_size == -1)
- + return 0;
- +
- + if(phys_mem < SQUASHFS_LOWMEM)
- + BAD_ERROR("Mksquashfs requires more physical memory than is "
- + "available!\n");
- +
- + return phys_mem;
- +}
- +
- +
- +void check_usable_phys_mem(int total_mem)
- +{
- + /*
- + * We want to allow users to use as much of their physical
- + * memory as they wish. However, for practical reasons there are
- + * limits which need to be imposed, to protect users from themselves
- + * and to prevent people from using Mksquashfs as a DOS attack by using
- + * all physical memory. Mksquashfs uses memory to cache data from disk
- + * to optimise performance. It is pointless to ask it to use more
- + * than 75% of physical memory, as this causes thrashing and it is thus
- + * self-defeating.
- + */
- + int mem = get_physical_memory();
- +
- + mem = (mem >> 1) + (mem >> 2); /* 75% */
- +
- + if(total_mem > mem && mem) {
- + ERROR("Total memory requested is more than 75%% of physical "
- + "memory.\n");
- + ERROR("Mksquashfs uses memory to cache data from disk to "
- + "optimise performance.\n");
- + ERROR("It is pointless to ask it to use more than this amount "
- + "of memory, as this\n");
- + ERROR("causes thrashing and it is thus self-defeating.\n");
- + BAD_ERROR("Requested memory size too large\n");
- + }
- +
- + if(sizeof(void *) == 4 && total_mem > 2048) {
- + /*
- + * If we're running on a kernel with PAE or on a 64-bit kernel,
- + * then the 75% physical memory limit can still easily exceed
- + * the addressable memory by this process.
- + *
- + * Due to the typical kernel/user-space split (1GB/3GB, or
- + * 2GB/2GB), we have to conservatively assume the 32-bit
- + * processes can only address 2-3GB. So refuse if the user
- + * tries to allocate more than 2GB.
- + */
- + ERROR("Total memory requested may exceed maximum "
- + "addressable memory by this process\n");
- + BAD_ERROR("Requested memory size too large\n");
- + }
- +}
- +
- +
- +int get_default_phys_mem()
- +{
- + /*
- + * get_physical_memory() relies on /proc being mounted.
- + * If it fails, issue a warning, and use
- + * SQUASHFS_LOWMEM / SQUASHFS_TAKE as default,
- + * and allow a larger value to be set with -mem.
- + */
- + int mem = get_physical_memory();
- +
- + if(mem == 0) {
- + mem = SQUASHFS_LOWMEM / SQUASHFS_TAKE;
- +
- + ERROR("Warning: Cannot get size of physical memory, probably "
- + "because /proc is missing.\n");
- + ERROR("Warning: Defaulting to minimal use of %d Mbytes, use "
- + "-mem to set a better value,\n", mem);
- + ERROR("Warning: or fix /proc.\n");
- + } else
- + mem /= SQUASHFS_TAKE;
- +
- + if(sizeof(void *) == 4 && mem > 640) {
- + /*
- + * If we're running on a kernel with PAE or on a 64-bit kernel,
- + * the default memory usage can exceed the addressable
- + * memory by this process.
- + * Due to the typical kernel/user-space split (1GB/3GB, or
- + * 2GB/2GB), we have to conservatively assume the 32-bit
- + * processes can only address 2-3GB. So limit the default
- + * usage to 640M, which gives room for other data.
- + */
- + mem = 640;
- + }
- +
- + return mem;
- +}
- +
- +
- +void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
- + int *fwriteq)
- +{
- + *readq = mem / SQUASHFS_READQ_MEM;
- + *bwriteq = mem / SQUASHFS_BWRITEQ_MEM;
- + *fwriteq = mem / SQUASHFS_FWRITEQ_MEM;
- + *fragq = mem - *readq - *bwriteq - *fwriteq;
- +}
- +
- +
- #define VERSION() \
- - printf("mksquashfs version 4.2-git (2013/04/07)\n");\
- - printf("copyright (C) 2013 Phillip Lougher "\
- + printf("mksquashfs version 4.3-git (2014/09/12)\n");\
- + printf("copyright (C) 2014 Phillip Lougher "\
- "<phillip@squashfs.org.uk>\n\n"); \
- printf("This program is free software; you can redistribute it and/or"\
- "\n");\
- @@ -4781,29 +5114,79 @@
- char *b, *root_name = NULL;
- int keep_as_directory = FALSE;
- squashfs_inode inode;
- - int readb_mbytes = READER_BUFFER_DEFAULT,
- - writeb_mbytes = WRITER_BUFFER_DEFAULT,
- - fragmentb_mbytes = FRAGMENT_BUFFER_DEFAULT;
- + int readq;
- + int fragq;
- + int bwriteq;
- + int fwriteq;
- + int total_mem = get_default_phys_mem();
- + int progress = TRUE;
- int force_progress = FALSE;
- struct file_buffer **fragment = NULL;
- - block_log = slog(block_size);
- if(argc > 1 && strcmp(argv[1], "-version") == 0) {
- VERSION();
- exit(0);
- }
- +
- + block_log = slog(block_size);
- + calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq);
- +
- for(i = 1; i < argc && argv[i][0] != '-'; i++);
- if(i < 3)
- goto printOptions;
- source_path = argv + 1;
- source = i - 2;
- +
- /*
- - * lookup default compressor. Note the Makefile ensures the default
- - * compressor has been built, and so we don't need to to check
- - * for failure here
- + * Scan the command line for -comp xxx option, this is to ensure
- + * any -X compressor specific options are passed to the
- + * correct compressor
- */
- - comp = lookup_compressor(COMP_DEFAULT);
- for(; i < argc; i++) {
- + struct compressor *prev_comp = comp;
- +
- + if(strcmp(argv[i], "-comp") == 0) {
- + if(++i == argc) {
- + ERROR("%s: -comp missing compression type\n",
- + argv[0]);
- + exit(1);
- + }
- + comp = lookup_compressor(argv[i]);
- + if(!comp->supported) {
- + ERROR("%s: Compressor \"%s\" is not supported!"
- + "\n", argv[0], argv[i]);
- + ERROR("%s: Compressors available:\n", argv[0]);
- + display_compressors("", COMP_DEFAULT);
- + exit(1);
- + }
- + if(prev_comp != NULL && prev_comp != comp) {
- + ERROR("%s: -comp multiple conflicting -comp"
- + " options specified on command line"
- + ", previously %s, now %s\n", argv[0],
- + prev_comp->name, comp->name);
- + exit(1);
- + }
- + compressor_opt_parsed = 1;
- +
- + } else if(strcmp(argv[i], "-e") == 0)
- + break;
- + else if(strcmp(argv[i], "-root-becomes") == 0 ||
- + strcmp(argv[i], "-ef") == 0 ||
- + strcmp(argv[i], "-pf") == 0 ||
- + strcmp(argv[i], "-vaf") == 0 ||
- + strcmp(argv[i], "-comp") == 0)
- + i++;
- + }
- +
- + /*
- + * if no -comp option specified lookup default compressor. Note the
- + * Makefile ensures the default compressor has been built, and so we
- + * don't need to to check for failure here
- + */
- + if(comp == NULL)
- + comp = lookup_compressor(COMP_DEFAULT);
- +
- + for(i = source + 2; i < argc; i++) {
- if(strcmp(argv[i], "-action") == 0 ||
- strcmp(argv[i], "-a") ==0) {
- if(++i == argc) {
- @@ -4811,54 +5194,114 @@
- argv[0], argv[i - 1]);
- exit(1);
- }
- - res = parse_action(argv[i]);
- + res = parse_action(argv[i], ACTION_LOG_NONE);
- + if(res == 0)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-verbose-action") == 0 ||
- + strcmp(argv[i], "-va") ==0) {
- + if(++i == argc) {
- + ERROR("%s: %s missing action\n",
- + argv[0], argv[i - 1]);
- + exit(1);
- + }
- + res = parse_action(argv[i], ACTION_LOG_VERBOSE);
- if(res == 0)
- exit(1);
- - } else if(strcmp(argv[i], "-af") == 0) {
- + } else if(strcmp(argv[i], "-true-action") == 0 ||
- + strcmp(argv[i], "-ta") ==0) {
- if(++i == argc) {
- - ERROR("%s: -af missing filename\n", argv[0]);
- + ERROR("%s: %s missing action\n",
- + argv[0], argv[i - 1]);
- exit(1);
- }
- - if(read_action_file(argv[i]) == FALSE)
- + res = parse_action(argv[i], ACTION_LOG_TRUE);
- + if(res == 0)
- exit(1);
- - } else if(strcmp(argv[i], "-comp") == 0) {
- - if(compressor_opts_parsed) {
- - ERROR("%s: -comp must appear before -X options"
- - "\n", argv[0]);
- + } else if(strcmp(argv[i], "-false-action") == 0 ||
- + strcmp(argv[i], "-fa") ==0) {
- + if(++i == argc) {
- + ERROR("%s: %s missing action\n",
- + argv[0], argv[i - 1]);
- exit(1);
- }
- + res = parse_action(argv[i], ACTION_LOG_FALSE);
- + if(res == 0)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-action-file") == 0 ||
- + strcmp(argv[i], "-af") ==0) {
- if(++i == argc) {
- - ERROR("%s: -comp missing compression type\n",
- - argv[0]);
- + ERROR("%s: %s missing filename\n", argv[0],
- + argv[i - 1]);
- exit(1);
- }
- - comp = lookup_compressor(argv[i]);
- - if(!comp->supported) {
- - ERROR("%s: Compressor \"%s\" is not supported!"
- - "\n", argv[0], argv[i]);
- - ERROR("%s: Compressors available:\n", argv[0]);
- - display_compressors("", COMP_DEFAULT);
- + if(read_action_file(argv[i], ACTION_LOG_NONE) == FALSE)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-verbose-action-file") == 0 ||
- + strcmp(argv[i], "-vaf") ==0) {
- + if(++i == argc) {
- + ERROR("%s: %s missing filename\n", argv[0],
- + argv[i - 1]);
- + exit(1);
- + }
- + if(read_action_file(argv[i], ACTION_LOG_VERBOSE) == FALSE)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-true-action-file") == 0 ||
- + strcmp(argv[i], "-taf") ==0) {
- + if(++i == argc) {
- + ERROR("%s: %s missing filename\n", argv[0],
- + argv[i - 1]);
- + exit(1);
- + }
- + if(read_action_file(argv[i], ACTION_LOG_TRUE) == FALSE)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-false-action-file") == 0 ||
- + strcmp(argv[i], "-faf") ==0) {
- + if(++i == argc) {
- + ERROR("%s: %s missing filename\n", argv[0],
- + argv[i - 1]);
- exit(1);
- }
- + if(read_action_file(argv[i], ACTION_LOG_FALSE) == FALSE)
- + exit(1);
- +
- + } else if(strcmp(argv[i], "-comp") == 0)
- + /* parsed previously */
- + i++;
- +
- + else if(strncmp(argv[i], "-X", 2) == 0) {
- + int args;
- - } else if(strncmp(argv[i], "-X", 2) == 0) {
- - int args = compressor_options(comp, argv + i, argc - i);
- + if(strcmp(argv[i] + 2, "help") == 0)
- + goto print_compressor_options;
- +
- + args = compressor_options(comp, argv + i, argc - i);
- if(args < 0) {
- if(args == -1) {
- ERROR("%s: Unrecognised compressor"
- " option %s\n", argv[0],
- argv[i]);
- - ERROR("%s: Did you forget to specify"
- - " -comp, or specify it after"
- - " the compressor specific"
- - " option?\n", argv[0]);
- - }
- + if(!compressor_opt_parsed)
- + ERROR("%s: Did you forget to"
- + " specify -comp?\n",
- + argv[0]);
- +print_compressor_options:
- + ERROR("%s: selected compressor \"%s\""
- + ". Options supported: %s\n",
- + argv[0], comp->name,
- + comp->usage ? "" : "none");
- + if(comp->usage)
- + comp->usage();
- + }
- exit(1);
- }
- i += args;
- - compressor_opts_parsed = 1;
- } else if(strcmp(argv[i], "-pf") == 0) {
- if(++i == argc) {
- @@ -4910,42 +5353,68 @@
- exit(1);
- }
- } else if(strcmp(argv[i], "-read-queue") == 0) {
- - if((++i == argc) ||
- - !parse_num(argv[i], &readb_mbytes)) {
- + if((++i == argc) || !parse_num(argv[i], &readq)) {
- ERROR("%s: -read-queue missing or invalid "
- "queue size\n", argv[0]);
- exit(1);
- }
- - if(readb_mbytes < 1) {
- + if(readq < 1) {
- ERROR("%s: -read-queue should be 1 megabyte or "
- "larger\n", argv[0]);
- exit(1);
- }
- } else if(strcmp(argv[i], "-write-queue") == 0) {
- - if((++i == argc) ||
- - !parse_num(argv[i], &writeb_mbytes)) {
- + if((++i == argc) || !parse_num(argv[i], &bwriteq)) {
- ERROR("%s: -write-queue missing or invalid "
- "queue size\n", argv[0]);
- exit(1);
- }
- - if(writeb_mbytes < 1) {
- - ERROR("%s: -write-queue should be 1 megabyte "
- + if(bwriteq < 2) {
- + ERROR("%s: -write-queue should be 2 megabytes "
- "or larger\n", argv[0]);
- exit(1);
- }
- + fwriteq = bwriteq >> 1;
- + bwriteq -= fwriteq;
- } else if(strcmp(argv[i], "-fragment-queue") == 0) {
- - if((++i == argc) ||
- - !parse_num(argv[i],
- - &fragmentb_mbytes)) {
- + if((++i == argc) || !parse_num(argv[i], &fragq)) {
- ERROR("%s: -fragment-queue missing or invalid "
- "queue size\n", argv[0]);
- exit(1);
- }
- - if(fragmentb_mbytes < 1) {
- + if(fragq < 1) {
- ERROR("%s: -fragment-queue should be 1 "
- "megabyte or larger\n", argv[0]);
- exit(1);
- }
- + } else if(strcmp(argv[i], "-mem") == 0) {
- + long long number;
- +
- + if((++i == argc) ||
- + !parse_numberll(argv[i], &number, 1)) {
- + ERROR("%s: -mem missing or invalid mem size\n",
- + argv[0]);
- + exit(1);
- + }
- +
- + /*
- + * convert from bytes to Mbytes, ensuring the value
- + * does not overflow a signed int
- + */
- + if(number >= (1LL << 51)) {
- + ERROR("%s: -mem invalid mem size\n", argv[0]);
- + exit(1);
- + }
- +
- + total_mem = number / 1048576;
- + if(total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) {
- + ERROR("%s: -mem should be %d Mbytes or "
- + "larger\n", argv[0],
- + SQUASHFS_LOWMEM / SQUASHFS_TAKE);
- + exit(1);
- + }
- + calculate_queue_sizes(total_mem, &readq, &fragq,
- + &bwriteq, &fwriteq);
- } else if(strcmp(argv[i], "-b") == 0) {
- if(++i == argc) {
- ERROR("%s: -b missing block size\n", argv[0]);
- @@ -5067,6 +5536,9 @@
- else if(strcmp(argv[i], "-keep-as-directory") == 0)
- keep_as_directory = TRUE;
- + else if(strcmp(argv[i], "-exit-on-error") == 0)
- + exit_on_error = TRUE;
- +
- else if(strcmp(argv[i], "-root-becomes") == 0) {
- if(++i == argc) {
- ERROR("%s: -root-becomes: missing name\n",
- @@ -5086,8 +5558,10 @@
- ERROR("\t\t\tCompressors available:\n");
- display_compressors("\t\t\t", COMP_DEFAULT);
- ERROR("-b <block_size>\t\tset data block to "
- - "<block_size>. Default %d bytes\n",
- - SQUASHFS_FILE_SIZE);
- + "<block_size>. Default 128 Kbytes\n");
- + ERROR("\t\t\tOptionally a suffix of K or M can be"
- + " given to specify\n\t\t\tKbytes or Mbytes"
- + " respectively\n");
- ERROR("-no-exports\t\tdon't make the filesystem "
- "exportable via NFS\n");
- ERROR("-no-sparse\t\tdon't detect sparse files\n");
- @@ -5145,6 +5619,8 @@
- ERROR("\nMksquashfs runtime options:\n");
- ERROR("-version\t\tprint version, licence and "
- "copyright message\n");
- + ERROR("-exit-on-error\t\ttreat normally ignored errors "
- + "as fatal\n");
- ERROR("-recover <name>\t\trecover filesystem data "
- "using recovery file <name>\n");
- ERROR("-no-recovery\t\tdon't generate a recovery "
- @@ -5157,15 +5633,11 @@
- ERROR("-processors <number>\tUse <number> processors."
- " By default will use number of\n");
- ERROR("\t\t\tprocessors available\n");
- - ERROR("-read-queue <size>\tSet input queue to <size> "
- - "Mbytes. Default %d Mbytes\n",
- - READER_BUFFER_DEFAULT);
- - ERROR("-write-queue <size>\tSet output queue to <size> "
- - "Mbytes. Default %d Mbytes\n",
- - WRITER_BUFFER_DEFAULT);
- - ERROR("-fragment-queue <size>\tSet fragment queue to "
- - "<size> Mbytes. Default %d Mbytes\n",
- - FRAGMENT_BUFFER_DEFAULT);
- + ERROR("-mem <size>\t\tUse <size> physical memory. "
- + "Currently set to %dM\n", total_mem);
- + ERROR("\t\t\tOptionally a suffix of K, M or G can be"
- + " given to specify\n\t\t\tKbytes, Mbytes or"
- + " Gbytes respectively\n");
- ERROR("\nMiscellaneous options:\n");
- ERROR("-root-owned\t\talternative name for -all-root"
- "\n");
- @@ -5177,6 +5649,8 @@
- "-noF\n");
- ERROR("-noXattrCompression\talternative name for "
- "-noX\n");
- + ERROR("\n-Xhelp\t\t\tprint compressor options for"
- + " selected compressor\n");
- ERROR("\nCompressors available and compressor specific "
- "options:\n");
- display_compressor_usage(COMP_DEFAULT);
- @@ -5201,6 +5675,11 @@
- progress = force_progress;
- #ifdef SQUASHFS_TRACE
- + /*
- + * Disable progress bar if full debug tracing is enabled.
- + * The progress bar in this case just gets in the way of the
- + * debug trace output
- + */
- progress = FALSE;
- #endif
- @@ -5269,6 +5748,7 @@
- strcmp(argv[i], "-sort") == 0 ||
- strcmp(argv[i], "-pf") == 0 ||
- strcmp(argv[i], "-af") == 0 ||
- + strcmp(argv[i], "-vaf") == 0 ||
- strcmp(argv[i], "-comp") == 0)
- i++;
- @@ -5298,6 +5778,7 @@
- strcmp(argv[i], "-ef") == 0 ||
- strcmp(argv[i], "-pf") == 0 ||
- strcmp(argv[i], "-af") == 0 ||
- + strcmp(argv[i], "-vaf") == 0 ||
- strcmp(argv[i], "-comp") == 0)
- i++;
- @@ -5324,7 +5805,8 @@
- comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
- }
- - initialise_threads(readb_mbytes, writeb_mbytes, fragmentb_mbytes);
- + initialise_threads(readq, fragq, bwriteq, fwriteq, delete,
- + destination_file);
- res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
- if(res)
- @@ -5366,7 +5848,6 @@
- SQUASHFS_INODE_BLK(sBlk.root_inode),
- root_inode_offset =
- SQUASHFS_INODE_OFFSET(sBlk.root_inode);
- - sigset_t sigmask, old_mask;
- if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
- &data_cache, &directory_table,
- @@ -5385,7 +5866,7 @@
- "device or file use -noappend\n");
- EXIT_MKSQUASHFS();
- }
- - if((fragments = sBlk.fragments)) {
- + if((append_fragments = fragments = sBlk.fragments)) {
- fragment_table = realloc((char *) fragment_table,
- ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
- * sizeof(struct squashfs_fragment_entry));
- @@ -5437,14 +5918,7 @@
- sid_count = id_count;
- write_recovery_data(&sBlk);
- save_xattrs();
- - restore_thread = init_restore_thread(pthread_self());
- - sigemptyset(&sigmask);
- - sigaddset(&sigmask, SIGINT);
- - sigaddset(&sigmask, SIGTERM);
- - sigaddset(&sigmask, SIGUSR1);
- - if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
- - BAD_ERROR("Failed to set signal mask\n");
- - write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
- + appending = TRUE;
- /*
- * set the filesystem state up to be able to append to the
- @@ -5493,33 +5967,22 @@
- inode_count = file_count + dir_count + sym_count + dev_count +
- fifo_count + sock_count;
- -
- - /*
- - * The default use freelist before growing cache policy behaves
- - * poorly with appending - with many deplicates the caches
- - * do not grow due to the fact that large queues of outstanding
- - * fragments/writer blocks do not occur, leading to small caches
- - * and un-uncessary performance loss to frequent cache
- - * replacement in the small caches. Therefore with appending
- - * change the policy to grow the caches before reusing blocks
- - * from the freelist
- - */
- - first_freelist = FALSE;
- }
- if(path)
- paths = add_subdir(paths, path);
- dump_actions();
- + dump_pseudos();
- if(delete && !keep_as_directory && source == 1 &&
- S_ISDIR(source_buf.st_mode))
- - dir_scan(&inode, source_path[0], scan1_readdir);
- + dir_scan(&inode, source_path[0], scan1_readdir, progress);
- else if(!keep_as_directory && source == 1 &&
- S_ISDIR(source_buf.st_mode))
- - dir_scan(&inode, source_path[0], scan1_single_readdir);
- + dir_scan(&inode, source_path[0], scan1_single_readdir, progress);
- else
- - dir_scan(&inode, "", scan1_encomp_readdir);
- + dir_scan(&inode, "", scan1_encomp_readdir, progress);
- sBlk.root_inode = inode;
- sBlk.inodes = inode_count;
- sBlk.s_magic = SQUASHFS_MAGIC;
- @@ -5532,7 +5995,6 @@
- no_xattrs, comp_opts);
- sBlk.mkfs_time = time(NULL);
- - disable_progress_bar();
- disable_info();
- while((fragment = get_frag_action(fragment)))
- @@ -5551,6 +6013,7 @@
- if(queue_get(from_writer) != 0)
- EXIT_MKSQUASHFS();
- + set_progressbar_state(FALSE);
- write_filesystem_tables(&sBlk, nopad);
- return 0;
- diff -Nru squashfs-tools-4.2+20130409/mksquashfs.h squashfs-tools-4.3+20140919/mksquashfs.h
- --- squashfs-tools-4.2+20130409/mksquashfs.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/mksquashfs.h 2015-07-20 21:03:05.000000000 +0200
- @@ -4,8 +4,8 @@
- * Squashfs
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- - * 2012
- - * Phillip Lougher <phillip@lougher.demon.co.uK>
- + * 2012, 2013, 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- @@ -25,22 +25,6 @@
- *
- */
- -#if __BYTE_ORDER == __BIG_ENDIAN
- -#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
- -#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
- -#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
- -
- -#define SWAP_LE16(s, d) swap_le16(s, d)
- -#define SWAP_LE32(s, d) swap_le32(s, d)
- -#define SWAP_LE64(s, d) swap_le64(s, d)
- -#else
- -#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
- -#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
- -#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
- -#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
- - memcpy(d, s, n * sizeof(long long))
- -#endif
- -
- struct dir_info {
- char *pathname;
- char *subpath;
- @@ -79,6 +63,47 @@
- char always_use_fragments;
- char noD;
- char noF;
- + char symlink[0];
- +};
- +
- +/* in memory file info */
- +struct file_info {
- + long long file_size;
- + long long bytes;
- + long long start;
- + unsigned int *block_list;
- + struct file_info *next;
- + struct fragment *fragment;
- + unsigned short checksum;
- + unsigned short fragment_checksum;
- + char have_frag_checksum;
- + char have_checksum;
- +};
- +
- +/* fragment block data structures */
- +struct fragment {
- + unsigned int index;
- + int offset;
- + int size;
- +};
- +
- +/* in memory uid tables */
- +#define ID_ENTRIES 256
- +#define ID_HASH(id) (id & (ID_ENTRIES - 1))
- +#define ISA_UID 1
- +#define ISA_GID 2
- +
- +struct id {
- + unsigned int id;
- + int index;
- + char flags;
- + struct id *next;
- +};
- +
- +/* fragment to file mapping used when appending */
- +struct append_file {
- + struct file_info *file;
- + struct append_file *next;
- };
- #define PSEUDO_FILE_OTHER 1
- @@ -88,7 +113,42 @@
- #define IS_PSEUDO_PROCESS(a) ((a)->pseudo_file & PSEUDO_FILE_PROCESS)
- #define IS_PSEUDO_OTHER(a) ((a)->pseudo_file & PSEUDO_FILE_OTHER)
- +/*
- + * Amount of physical memory to use by default, and the default queue
- + * ratios
- + */
- +#define SQUASHFS_TAKE 4
- +#define SQUASHFS_READQ_MEM 4
- +#define SQUASHFS_BWRITEQ_MEM 4
- +#define SQUASHFS_FWRITEQ_MEM 4
- +
- +/*
- + * Lowest amount of physical memory considered viable for Mksquashfs
- + * to run in Mbytes
- + */
- +#define SQUASHFS_LOWMEM 64
- +
- /* offset of data in compressed metadata blocks (allowing room for
- * compressed size */
- #define BLOCK_OFFSET 2
- +
- +extern struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
- +struct cache *bwriter_buffer, *fwriter_buffer;
- +extern struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
- + *to_frag, *locked_fragment, *to_process_frag;
- +extern struct append_file **file_mapping;
- +extern struct seq_queue *to_main;
- +extern pthread_mutex_t fragment_mutex, dup_mutex;
- +extern struct squashfs_fragment_entry *fragment_table;
- +extern struct compressor *comp;
- +extern int block_size;
- +extern struct file_info *dupl[];
- +extern int read_fs_bytes(int, long long, int, void *);
- +extern void add_file(long long, long long, long long, unsigned int *, int,
- + unsigned int, int, int);
- +extern struct id *create_id(unsigned int);
- +extern unsigned int get_uid(unsigned int);
- +extern unsigned int get_guid(unsigned int);
- +extern int read_bytes(int, void *, int);
- +extern unsigned short get_checksum_mem(char *, int);
- #endif
- diff -Nru squashfs-tools-4.2+20130409/par_mksquashfs/README squashfs-tools-4.3+20140919/par_mksquashfs/README
- --- squashfs-tools-4.2+20130409/par_mksquashfs/README 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/par_mksquashfs/README 1970-01-01 01:00:00.000000000 +0100
- @@ -1,2 +0,0 @@
- -par_mksquashfs is now the standard mksquashfs, and so this directory is now empty.
- -
- diff -Nru squashfs-tools-4.2+20130409/process_fragments.c squashfs-tools-4.3+20140919/process_fragments.c
- --- squashfs-tools-4.2+20130409/process_fragments.c 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/process_fragments.c 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,370 @@
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only
- + * filesystem.
- + *
- + * Copyright (c) 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * process_fragments.c
- + */
- +
- +#include <pthread.h>
- +#include <sys/ioctl.h>
- +#include <unistd.h>
- +#include <signal.h>
- +#include <sys/time.h>
- +#include <string.h>
- +#include <stdio.h>
- +#include <math.h>
- +#include <stdarg.h>
- +#include <errno.h>
- +#include <stdlib.h>
- +#include <dirent.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <fcntl.h>
- +
- +#include "caches-queues-lists.h"
- +#include "squashfs_fs.h"
- +#include "mksquashfs.h"
- +#include "error.h"
- +#include "progressbar.h"
- +#include "info.h"
- +#include "compressor.h"
- +#include "process_fragments.h"
- +
- +#define FALSE 0
- +#define TRUE 1
- +
- +extern struct queue *to_process_frag;
- +extern struct seq_queue *to_main;
- +extern int sparse_files;
- +
- +/*
- + * Compute 16 bit BSD checksum over the data, and check for sparseness
- + */
- +static int checksum_sparse(struct file_buffer *file_buffer)
- +{
- + unsigned char *b = (unsigned char *) file_buffer->data;
- + unsigned short chksum = 0;
- + int bytes = file_buffer->size, sparse = TRUE, value;
- +
- + while(bytes --) {
- + chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
- + value = *b++;
- + if(value) {
- + sparse = FALSE;
- + chksum += value;
- + }
- + }
- +
- + file_buffer->checksum = chksum;
- + return sparse;
- +}
- +
- +
- +static int read_filesystem(int fd, long long byte, int bytes, void *buff)
- +{
- + off_t off = byte;
- +
- + TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n",
- + byte, bytes);
- +
- + if(lseek(fd, off, SEEK_SET) == -1) {
- + ERROR("read_filesystem: Lseek on destination failed because %s, "
- + "offset=0x%llx\n", strerror(errno), off);
- + return 0;
- + } else if(read_bytes(fd, buff, bytes) < bytes) {
- + ERROR("Read on destination failed\n");
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- +
- +static struct file_buffer *get_fragment(struct fragment *fragment,
- + char *data_buffer, int fd)
- +{
- + struct squashfs_fragment_entry *disk_fragment;
- + struct file_buffer *buffer, *compressed_buffer;
- + long long start_block;
- + int res, size, index = fragment->index;
- + char locked;
- +
- + /*
- + * Lookup fragment block in cache.
- + * If the fragment block doesn't exist, then get the compressed version
- + * from the writer cache or off disk, and decompress it.
- + *
- + * This routine has two things which complicate the code:
- + *
- + * 1. Multiple threads can simultaneously lookup/create the
- + * same buffer. This means a buffer needs to be "locked"
- + * when it is being filled in, to prevent other threads from
- + * using it when it is not ready. This is because we now do
- + * fragment duplicate checking in parallel.
- + * 2. We have two caches which need to be checked for the
- + * presence of fragment blocks: the normal fragment cache
- + * and a "reserve" cache. The reserve cache is used to
- + * prevent an unnecessary pipeline stall when the fragment cache
- + * is full of fragments waiting to be compressed.
- + */
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- + pthread_mutex_lock(&dup_mutex);
- +
- +again:
- + buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
- + if(buffer) {
- + pthread_mutex_unlock(&dup_mutex);
- + if(locked)
- + /* got a buffer being filled in. Wait for it */
- + cache_wait_unlock(buffer);
- + goto finished;
- + }
- +
- + /* not in fragment cache, is it in the reserve cache? */
- + buffer = cache_lookup_nowait(reserve_cache, index, &locked);
- + if(buffer) {
- + pthread_mutex_unlock(&dup_mutex);
- + if(locked)
- + /* got a buffer being filled in. Wait for it */
- + cache_wait_unlock(buffer);
- + goto finished;
- + }
- +
- + /* in neither cache, try to get it from the fragment cache */
- + buffer = cache_get_nowait(fragment_buffer, index);
- + if(!buffer) {
- + /*
- + * no room, get it from the reserve cache, this is
- + * dimensioned so it will always have space (no more than
- + * processors + 1 can have an outstanding reserve buffer)
- + */
- + buffer = cache_get_nowait(reserve_cache, index);
- + if(!buffer) {
- + /* failsafe */
- + ERROR("no space in reserve cache\n");
- + goto again;
- + }
- + }
- +
- + pthread_mutex_unlock(&dup_mutex);
- +
- + compressed_buffer = cache_lookup(fwriter_buffer, index);
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
- + pthread_mutex_lock(&fragment_mutex);
- + disk_fragment = &fragment_table[index];
- + size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
- + start_block = disk_fragment->start_block;
- + pthread_cleanup_pop(1);
- +
- + if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
- + int error;
- + char *data;
- +
- + if(compressed_buffer)
- + data = compressed_buffer->data;
- + else {
- + res = read_filesystem(fd, start_block, size, data_buffer);
- + if(res == 0) {
- + ERROR("Failed to read fragment from output"
- + " filesystem\n");
- + BAD_ERROR("Output filesystem corrupted?\n");
- + }
- + data = data_buffer;
- + }
- +
- + res = compressor_uncompress(comp, buffer->data, data, size,
- + block_size, &error);
- + if(res == -1)
- + BAD_ERROR("%s uncompress failed with error code %d\n",
- + comp->name, error);
- + } else if(compressed_buffer)
- + memcpy(buffer->data, compressed_buffer->data, size);
- + else {
- + res = read_filesystem(fd, start_block, size, buffer->data);
- + if(res == 0) {
- + ERROR("Failed to read fragment from output "
- + "filesystem\n");
- + BAD_ERROR("Output filesystem corrupted?\n");
- + }
- + }
- +
- + cache_unlock(buffer);
- + cache_block_put(compressed_buffer);
- +
- +finished:
- + pthread_cleanup_pop(0);
- +
- + return buffer;
- +}
- +
- +
- +struct file_buffer *get_fragment_cksum(struct file_info *file,
- + char *data_buffer, int fd, unsigned short *checksum)
- +{
- + struct file_buffer *frag_buffer;
- + struct append_file *append;
- + int index = file->fragment->index;
- +
- + frag_buffer = get_fragment(file->fragment, data_buffer, fd);
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- +
- + for(append = file_mapping[index]; append; append = append->next) {
- + int offset = append->file->fragment->offset;
- + int size = append->file->fragment->size;
- + char *data = frag_buffer->data + offset;
- + unsigned short cksum = get_checksum_mem(data, size);
- +
- + if(file == append->file)
- + *checksum = cksum;
- +
- + pthread_mutex_lock(&dup_mutex);
- + append->file->fragment_checksum = cksum;
- + append->file->have_frag_checksum = TRUE;
- + pthread_mutex_unlock(&dup_mutex);
- + }
- +
- + pthread_cleanup_pop(0);
- +
- + return frag_buffer;
- +}
- +
- +
- +void *frag_thrd(void *destination_file)
- +{
- + sigset_t sigmask, old_mask;
- + char *data_buffer;
- + int fd;
- +
- + sigemptyset(&sigmask);
- + sigaddset(&sigmask, SIGINT);
- + sigaddset(&sigmask, SIGTERM);
- + sigaddset(&sigmask, SIGUSR1);
- + pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
- +
- + fd = open(destination_file, O_RDONLY);
- + if(fd == -1)
- + BAD_ERROR("frag_thrd: can't open destination for reading\n");
- +
- + data_buffer = malloc(SQUASHFS_FILE_MAX_SIZE);
- + if(data_buffer == NULL)
- + MEM_ERROR();
- +
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
- +
- + while(1) {
- + struct file_buffer *file_buffer = queue_get(to_process_frag);
- + struct file_buffer *buffer;
- + int sparse = checksum_sparse(file_buffer);
- + struct file_info *dupl_ptr;
- + long long file_size;
- + unsigned short checksum;
- + char flag;
- + int res;
- +
- + if(sparse_files && sparse) {
- + file_buffer->c_byte = 0;
- + file_buffer->fragment = FALSE;
- + } else
- + file_buffer->c_byte = file_buffer->size;
- +
- + /*
- + * Specutively pull into the fragment cache any fragment blocks
- + * which contain fragments which *this* fragment may be
- + * be a duplicate.
- + *
- + * By ensuring the fragment block is in cache ahead of time
- + * should eliminate the parallelisation stall when the
- + * main thread needs to read the fragment block to do a
- + * duplicate check on it.
- + *
- + * If this is a fragment belonging to a larger file
- + * (with additional blocks) then ignore it. Here we're
- + * interested in the "low hanging fruit" of files which
- + * consist of only a fragment
- + */
- + if(file_buffer->file_size != file_buffer->size) {
- + seq_queue_put(to_main, file_buffer);
- + continue;
- + }
- +
- + file_size = file_buffer->file_size;
- +
- + pthread_mutex_lock(&dup_mutex);
- + dupl_ptr = dupl[DUP_HASH(file_size)];
- + pthread_mutex_unlock(&dup_mutex);
- +
- + file_buffer->dupl_start = dupl_ptr;
- + file_buffer->duplicate = FALSE;
- +
- + for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
- + if(file_size != dupl_ptr->file_size ||
- + file_size != dupl_ptr->fragment->size)
- + continue;
- +
- + pthread_mutex_lock(&dup_mutex);
- + flag = dupl_ptr->have_frag_checksum;
- + checksum = dupl_ptr->fragment_checksum;
- + pthread_mutex_unlock(&dup_mutex);
- +
- + /*
- + * If we have the checksum and it matches then
- + * read in the fragment block.
- + *
- + * If we *don't* have the checksum, then we are
- + * appending, and the fragment block is on the
- + * "old" filesystem. Read it in and checksum
- + * the entire fragment buffer
- + */
- + if(!flag) {
- + buffer = get_fragment_cksum(dupl_ptr,
- + data_buffer, fd, &checksum);
- + if(checksum != file_buffer->checksum) {
- + cache_block_put(buffer);
- + continue;
- + }
- + } else if(checksum == file_buffer->checksum)
- + buffer = get_fragment(dupl_ptr->fragment,
- + data_buffer, fd);
- + else
- + continue;
- +
- + res = memcmp(file_buffer->data, buffer->data +
- + dupl_ptr->fragment->offset, file_size);
- + cache_block_put(buffer);
- + if(res == 0) {
- + struct file_buffer *dup = malloc(sizeof(*dup));
- + if(dup == NULL)
- + MEM_ERROR();
- + memcpy(dup, file_buffer, sizeof(*dup));
- + cache_block_put(file_buffer);
- + dup->dupl_start = dupl_ptr;
- + dup->duplicate = TRUE;
- + file_buffer = dup;
- + break;
- + }
- + }
- +
- + seq_queue_put(to_main, file_buffer);
- + }
- +
- + pthread_cleanup_pop(0);
- +}
- diff -Nru squashfs-tools-4.2+20130409/process_fragments.h squashfs-tools-4.3+20140919/process_fragments.h
- --- squashfs-tools-4.2+20130409/process_fragments.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/process_fragments.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,30 @@
- +#ifndef PROCESS_FRAGMENTS_H
- +#define PROCESS_FRAGMENTS_H
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only
- + * filesystem.
- + *
- + * Copyright (c) 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * process_fragments.h
- + */
- +
- +#define DUP_HASH(a) (a & 0xffff)
- +
- +extern void *frag_thrd(void *);
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/progressbar.c squashfs-tools-4.3+20140919/progressbar.c
- --- squashfs-tools-4.2+20130409/progressbar.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/progressbar.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2012, 2013
- + * Copyright (c) 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -35,7 +35,15 @@
- #include "error.h"
- -int progress_enabled = 0;
- +#define FALSE 0
- +#define TRUE 1
- +
- +/* flag whether progressbar display is enabled or not */
- +int display_progress_bar = FALSE;
- +
- +/* flag whether the progress bar is temporarily disbled */
- +int temp_disabled = FALSE;
- +
- int rotate = 0;
- int cur_uncompressed = 0, estimated_uncompressed = 0;
- int columns;
- @@ -50,7 +58,7 @@
- if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
- if(isatty(STDOUT_FILENO))
- - printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
- + ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
- "columns\n");
- columns = 80;
- } else
- @@ -132,21 +140,39 @@
- void enable_progress_bar()
- {
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
- pthread_mutex_lock(&progress_mutex);
- - progress_enabled = 1;
- - pthread_mutex_unlock(&progress_mutex);
- + if(display_progress_bar)
- + progress_bar(cur_uncompressed, estimated_uncompressed, columns);
- + temp_disabled = FALSE;
- + pthread_cleanup_pop(1);
- }
- void disable_progress_bar()
- {
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
- pthread_mutex_lock(&progress_mutex);
- - if(progress_enabled) {
- - progress_bar(cur_uncompressed, estimated_uncompressed, columns);
- + if(display_progress_bar)
- printf("\n");
- + temp_disabled = TRUE;
- + pthread_cleanup_pop(1);
- +}
- +
- +
- +void set_progressbar_state(int state)
- +{
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
- + pthread_mutex_lock(&progress_mutex);
- + if(display_progress_bar != state) {
- + if(display_progress_bar && !temp_disabled) {
- + progress_bar(cur_uncompressed, estimated_uncompressed,
- + columns);
- + printf("\n");
- + }
- + display_progress_bar = state;
- }
- - progress_enabled = 0;
- - pthread_mutex_unlock(&progress_mutex);
- + pthread_cleanup_pop(1);
- }
- @@ -158,7 +184,7 @@
- if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
- if(isatty(STDOUT_FILENO))
- - printf("TIOCGWINSZ ioctl failed, defaulting to 80 "
- + ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
- "columns\n");
- columns = 80;
- } else
- @@ -181,12 +207,11 @@
- if(res == -1 && errno != EINTR)
- BAD_ERROR("nanosleep failed in progress thread\n");
- - if(progress_enabled) {
- - pthread_mutex_lock(&progress_mutex);
- + pthread_mutex_lock(&progress_mutex);
- + if(display_progress_bar && !temp_disabled)
- progress_bar(cur_uncompressed, estimated_uncompressed,
- columns);
- - pthread_mutex_unlock(&progress_mutex);
- - }
- + pthread_mutex_unlock(&progress_mutex);
- }
- }
- @@ -201,16 +226,17 @@
- {
- va_list ap;
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
- pthread_mutex_lock(&progress_mutex);
- - if(progress_enabled)
- + if(display_progress_bar && !temp_disabled)
- fprintf(stderr, "\n");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- - pthread_mutex_unlock(&progress_mutex);
- + pthread_cleanup_pop(1);
- }
- @@ -218,15 +244,16 @@
- {
- va_list ap;
- + pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
- pthread_mutex_lock(&progress_mutex);
- - if(progress_enabled)
- + if(display_progress_bar && !temp_disabled)
- printf("\n");
- va_start(ap, fmt);
- vprintf(fmt, ap);
- va_end(ap);
- - pthread_mutex_unlock(&progress_mutex);
- + pthread_cleanup_pop(1);
- }
- diff -Nru squashfs-tools-4.2+20130409/progressbar.h squashfs-tools-4.3+20140919/progressbar.h
- --- squashfs-tools-4.2+20130409/progressbar.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/progressbar.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef PROGRESSBAR_H
- +#define PROGRESSBAR_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2012, 2013
- + * Copyright (c) 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -28,3 +30,5 @@
- extern void enable_progress_bar();
- extern void disable_progress_bar();
- extern void init_progress_bar();
- +extern void set_progressbar_state(int);
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/pseudo.c squashfs-tools-4.3+20140919/pseudo.c
- --- squashfs-tools-4.2+20130409/pseudo.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/pseudo.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2009, 2010, 2012
- + * Copyright (c) 2009, 2010, 2012, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -36,6 +36,7 @@
- #include "pseudo.h"
- #include "error.h"
- +#include "progressbar.h"
- #define TRUE 1
- #define FALSE 0
- @@ -46,32 +47,6 @@
- struct pseudo *pseudo = NULL;
- int pseudo_count = 0;
- -static void dump_pseudo(struct pseudo *pseudo, char *string)
- -{
- - int i, res;
- - char *path;
- -
- - for(i = 0; i < pseudo->names; i++) {
- - struct pseudo_entry *entry = &pseudo->name[i];
- - if(string) {
- - res = asprintf(&path, "%s/%s", string, entry->name);
- - if(res == -1)
- - BAD_ERROR("asprintf failed in dump_pseudo\n");
- - } else
- - path = entry->name;
- - if(entry->pseudo == NULL)
- - ERROR("%s %c %o %d %d %d %d\n", path, entry->dev->type,
- - entry->dev->mode, entry->dev->uid,
- - entry->dev->gid, entry->dev->major,
- - entry->dev->minor);
- - else
- - dump_pseudo(entry->pseudo, path);
- - if(string)
- - free(path);
- - }
- -}
- -
- -
- static char *get_component(char *target, char **targname)
- {
- char *start;
- @@ -80,11 +55,14 @@
- target ++;
- start = target;
- - while(*target != '/' && *target!= '\0')
- + while(*target != '/' && *target != '\0')
- target ++;
- *targname = strndup(start, target - start);
- + while(*target == '/')
- + target ++;
- +
- return target;
- }
- @@ -154,16 +132,23 @@
- pseudo->name[i].pseudo =
- add_pseudo(NULL, pseudo_dev,
- target, alltarget);
- - else
- - ERROR("%s already exists as a non "
- - "directory. Ignoring %s!\n",
- - targname, alltarget);
- + else {
- + ERROR_START("%s already exists as a "
- + "non directory.",
- + pseudo->name[i].name);
- + ERROR_EXIT(". Ignoring %s!\n",
- + alltarget);
- + }
- } else if(memcmp(pseudo_dev, pseudo->name[i].dev,
- - sizeof(struct pseudo_dev)) != 0)
- - ERROR("%s already exists as a different pseudo "
- - "definition. Ignoring!\n", alltarget);
- - else ERROR("%s already exists as an identical "
- - "pseudo definition!\n", alltarget);
- + sizeof(struct pseudo_dev)) != 0) {
- + ERROR_START("%s already exists as a different "
- + "pseudo definition.", alltarget);
- + ERROR_EXIT(" Ignoring!\n");
- + } else {
- + ERROR_START("%s already exists as an identical "
- + "pseudo definition!", alltarget);
- + ERROR_EXIT(" Ignoring!\n");
- + }
- } else {
- if(target[0] == '\0') {
- /*
- @@ -176,10 +161,13 @@
- pseudo->name[i].pathname =
- strdup(alltarget);
- pseudo->name[i].dev = pseudo_dev;
- - } else
- - ERROR("%s already exists as a different"
- - " pseudo definition. Ignoring"
- - " %s!\n", targname, alltarget);
- + } else {
- + ERROR_START("%s already exists as a "
- + "different pseudo definition.",
- + pseudo->name[i].name);
- + ERROR_EXIT(" Ignoring %s!\n",
- + alltarget);
- + }
- } else
- /* recurse adding child components */
- add_pseudo(pseudo->name[i].pseudo, pseudo_dev,
- @@ -227,75 +215,40 @@
- }
- -int exec_file(char *command, struct pseudo_dev *dev)
- +int pseudo_exec_file(struct pseudo_dev *dev, int *child)
- {
- - int child, res;
- - static pid_t pid = -1;
- - int pipefd[2];
- -#ifdef USE_TMP_FILE
- - char *filename;
- - int status;
- - static int number = 0;
- -#endif
- -
- - if(pid == -1)
- - pid = getpid();
- + int res, pipefd[2];
- -#ifdef USE_TMP_FILE
- - res = asprintf(&filename, "/tmp/squashfs_pseudo_%d_%d", pid, number ++);
- - if(res == -1) {
- - ERROR("asprint failed in exec_file()\n");
- - return -1;
- - }
- - pipefd[1] = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
- - if(pipefd[1] == -1) {
- - ERROR("Executing dynamic pseudo file, open failed\n");
- - free(filename);
- - return -1;
- - }
- -#else
- res = pipe(pipefd);
- if(res == -1) {
- ERROR("Executing dynamic pseudo file, pipe failed\n");
- - return -1;
- + return 0;
- }
- -#endif
- - child = fork();
- - if(child == -1) {
- + *child = fork();
- + if(*child == -1) {
- ERROR("Executing dynamic pseudo file, fork failed\n");
- goto failed;
- }
- - if(child == 0) {
- + if(*child == 0) {
- + close(pipefd[0]);
- close(STDOUT_FILENO);
- res = dup(pipefd[1]);
- if(res == -1)
- exit(EXIT_FAILURE);
- - execl("/bin/sh", "sh", "-c", command, (char *) NULL);
- + execl("/bin/sh", "sh", "-c", dev->command, (char *) NULL);
- exit(EXIT_FAILURE);
- }
- -#ifdef USE_TMP_FILE
- - res = waitpid(child, &status, 0);
- close(pipefd[1]);
- - if(res != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- - dev->filename = filename;
- - return 0;
- - }
- + return pipefd[0];
- +
- failed:
- - unlink(filename);
- - free(filename);
- - return -1;
- -#else
- + close(pipefd[0]);
- close(pipefd[1]);
- - dev->fd = pipefd[0];
- - dev->child = child;
- return 0;
- -failed:
- - return -1;
- -#endif
- }
- @@ -311,17 +264,6 @@
- }
- -void delete_pseudo_files()
- -{
- -#ifdef USE_TMP_FILE
- - int i;
- -
- - for(i = 0; i < pseudo_count; i++)
- - unlink(pseudo_file[i]->filename);
- -#endif
- -}
- -
- -
- struct pseudo_dev *get_pseudo_file(int pseudo_id)
- {
- return pseudo_file[pseudo_id];
- @@ -513,20 +455,8 @@
- dev->gid = gid;
- dev->major = major;
- dev->minor = minor;
- -
- if(type == 'f') {
- - int res;
- -
- - printf("Executing dynamic pseudo file\n");
- - printf("\t\"%s\"\n", orig_def);
- - res = exec_file(def, dev);
- - if(res == -1) {
- - ERROR("Failed to execute dynamic pseudo file definition"
- - " \"%s\"\n", orig_def);
- - free(filename);
- - free(dev);
- - return FALSE;
- - }
- + dev->command = strdup(def);
- add_pseudo_file(dev);
- }
- @@ -557,3 +487,41 @@
- {
- return pseudo;
- }
- +
- +
- +#ifdef SQUASHFS_TRACE
- +static void dump_pseudo(struct pseudo *pseudo, char *string)
- +{
- + int i, res;
- + char *path;
- +
- + for(i = 0; i < pseudo->names; i++) {
- + struct pseudo_entry *entry = &pseudo->name[i];
- + if(string) {
- + res = asprintf(&path, "%s/%s", string, entry->name);
- + if(res == -1)
- + BAD_ERROR("asprintf failed in dump_pseudo\n");
- + } else
- + path = entry->name;
- + if(entry->dev)
- + ERROR("%s %c 0%o %d %d %d %d\n", path, entry->dev->type,
- + entry->dev->mode & ~S_IFMT, entry->dev->uid,
- + entry->dev->gid, entry->dev->major,
- + entry->dev->minor);
- + if(entry->pseudo)
- + dump_pseudo(entry->pseudo, path);
- + if(string)
- + free(path);
- + }
- +}
- +
- +
- +void dump_pseudos()
- +{
- + dump_pseudo(pseudo, NULL);
- +}
- +#else
- +void dump_pseudos()
- +{
- +}
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/pseudo.h squashfs-tools-4.3+20140919/pseudo.h
- --- squashfs-tools-4.2+20130409/pseudo.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/pseudo.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef PSEUDO_H
- +#define PSEUDO_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2009, 2010
- + * Copyright (c) 2009, 2010, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -29,11 +31,7 @@
- unsigned int major;
- unsigned int minor;
- int pseudo_id;
- - int fd;
- - int child;
- -#ifdef USE_TMP_FILE
- - char *filename;
- -#endif
- + char *command;
- };
- struct pseudo_entry {
- @@ -54,5 +52,7 @@
- extern struct pseudo *pseudo_subdir(char *, struct pseudo *);
- extern struct pseudo_entry *pseudo_readdir(struct pseudo *);
- extern struct pseudo_dev *get_pseudo_file(int);
- -extern void delete_pseudo_files();
- +extern int pseudo_exec_file(struct pseudo_dev *, int *);
- extern struct pseudo *get_pseudo();
- +extern void dump_pseudos();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/read_fs.c squashfs-tools-4.3+20140919/read_fs.c
- --- squashfs-tools-4.2+20130409/read_fs.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/read_fs.c 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- * filesystem.
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- - * 2012, 2013
- + * 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -33,6 +33,7 @@
- #include <string.h>
- #include <sys/mman.h>
- #include <limits.h>
- +#include <dirent.h>
- #ifndef linux
- #define __BYTE_ORDER BYTE_ORDER
- @@ -46,19 +47,10 @@
- #include "squashfs_fs.h"
- #include "squashfs_swap.h"
- -#include "read_fs.h"
- #include "compressor.h"
- #include "xattr.h"
- #include "error.h"
- -
- -extern int read_fs_bytes(int, long long, int, void *);
- -extern int add_file(long long, long long, long long, unsigned int *, int,
- - unsigned int, int, int);
- -extern void *create_id(unsigned int);
- -extern unsigned int get_uid(unsigned int);
- -extern unsigned int get_guid(unsigned int);
- -
- -static struct compressor *comp;
- +#include "mksquashfs.h"
- int read_block(int fd, long long start, long long *next, int expected,
- void *block)
- @@ -207,7 +199,7 @@
- */
- *root_inode_size = bytes - (*root_inode_block + root_inode_offset);
- bytes = *root_inode_block + root_inode_offset;
- - SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, *inode_table + bytes);
- + SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir);
- if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
- directory_start_block = dir_inode->dir.start_block;
- @@ -215,8 +207,8 @@
- if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir,
- - *inode_table + bytes);
- + SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes,
- + &dir_inode->ldir);
- directory_start_block = dir_inode->ldir.start_block;
- } else
- /* bad type, corrupted filesystem */
- @@ -225,12 +217,17 @@
- get_uid(id_table[dir_inode->base.uid]);
- get_guid(id_table[dir_inode->base.guid]);
- + /* allocate fragment to file mapping table */
- + file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
- + if(file_mapping == NULL)
- + MEM_ERROR();
- +
- for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
- if(NO_INODE_BYTES(squashfs_base_inode_header))
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_BASE_INODE_HEADER(&base, cur_ptr);
- + SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
- TRACE("scan_inode_table: processing inode @ byte position "
- "0x%x, type 0x%x\n",
- @@ -251,7 +248,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_REG_INODE_HEADER(&inode, cur_ptr);
- + SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
- frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
- 0 : inode.file_size % sBlk->block_size;
- @@ -273,7 +270,7 @@
- MEM_ERROR();
- cur_ptr += sizeof(inode);
- - SQUASHFS_SWAP_INTS(block_list, cur_ptr, blocks);
- + SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
- *uncompressed_file += inode.file_size;
- (*file_count) ++;
- @@ -283,6 +280,12 @@
- SQUASHFS_COMPRESSED_SIZE_BLOCK
- (block_list[i]);
- + if(inode.fragment != SQUASHFS_INVALID_FRAG &&
- + inode.fragment >= sBlk->fragments) {
- + free(block_list);
- + goto corrupted;
- + }
- +
- add_file(start, inode.file_size, file_bytes,
- block_list, blocks, inode.fragment,
- inode.offset, frag_bytes);
- @@ -300,7 +303,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, cur_ptr);
- + SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
- frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
- 0 : inode.file_size % sBlk->block_size;
- @@ -323,7 +326,7 @@
- MEM_ERROR();
- cur_ptr += sizeof(inode);
- - SQUASHFS_SWAP_INTS(block_list, cur_ptr, blocks);
- + SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
- *uncompressed_file += inode.file_size;
- (*file_count) ++;
- @@ -333,6 +336,12 @@
- SQUASHFS_COMPRESSED_SIZE_BLOCK
- (block_list[i]);
- + if(inode.fragment != SQUASHFS_INVALID_FRAG &&
- + inode.fragment >= sBlk->fragments) {
- + free(block_list);
- + goto corrupted;
- + }
- +
- add_file(start, inode.file_size, file_bytes,
- block_list, blocks, inode.fragment,
- inode.offset, frag_bytes);
- @@ -348,7 +357,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inode, cur_ptr);
- + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
- (*sym_count) ++;
- @@ -374,7 +383,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, cur_ptr);
- + SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
- if(dir_inode.start_block < directory_start_block)
- *uncompressed_directory += dir_inode.file_size;
- @@ -391,7 +400,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, cur_ptr);
- + SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
- if(dir_inode.start_block < directory_start_block)
- *uncompressed_directory += dir_inode.file_size;
- @@ -406,7 +415,7 @@
- /* corrupted filesystem */
- goto corrupted;
- - SQUASHFS_SWAP_DIR_INDEX(&index, cur_ptr);
- + SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
- if(NO_BYTES(index.size + 1))
- /* corrupted filesystem */
- @@ -531,7 +540,7 @@
- /* Check the compression type */
- comp = lookup_compressor_id(sBlk->compression);
- if(!comp->supported) {
- - ERROR("Filesystem on %s uses %s compression, this is"
- + ERROR("Filesystem on %s uses %s compression, this is "
- "unsupported by this version\n", source, comp->name);
- ERROR("Compressors available:\n");
- display_compressors("", "");
- @@ -548,6 +557,10 @@
- * is still called to set the default options (the defaults may have
- * been changed by the user specifying options on the command
- * line which need to be over-ridden).
- + *
- + * Compressor_extract_options is also used to ensure that
- + * we know how decompress a filesystem compressed with these
- + * compression options.
- */
- if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
- bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
- @@ -579,7 +592,7 @@
- SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
- printf("\tFragments are %spresent in the filesystem\n",
- SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
- - printf("\tAlways_use_fragments option is %sspecified\n",
- + printf("\tAlways-use-fragments option is %sspecified\n",
- SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
- printf("\tDuplicates are %sremoved\n",
- SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
- @@ -651,7 +664,7 @@
- bytes = offset;
- while(bytes < size) {
- - SQUASHFS_SWAP_DIR_HEADER(&dirh, directory_table + bytes);
- + SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
- dir_count = dirh.count + 1;
- TRACE("squashfs_readdir: Read directory header @ byte position "
- @@ -659,7 +672,7 @@
- bytes += sizeof(dirh);
- while(dir_count--) {
- - SQUASHFS_SWAP_DIR_ENTRY(dire, directory_table + bytes);
- + SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
- bytes += sizeof(*dire);
- memcpy(dire->name, directory_table + bytes,
- diff -Nru squashfs-tools-4.2+20130409/read_fs.h squashfs-tools-4.3+20140919/read_fs.h
- --- squashfs-tools-4.2+20130409/read_fs.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/read_fs.h 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- /*
- * Squashfs
- *
- - * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -23,20 +23,12 @@
- * read_fs.h
- *
- */
- -
- -#if __BYTE_ORDER == __BIG_ENDIAN
- -#define SQUASHFS_SWAP_SHORTS(d, s, n) swap_le16_num(s, d, n)
- -#define SQUASHFS_SWAP_INTS(d, s, n) swap_le32_num(s, d, n)
- -#define SQUASHFS_SWAP_LONG_LONGS(d, s, n) swap_le64_num(s, d, n)
- -
- -#define SWAP_LE16(d, s) swap_le16(s, d)
- -#define SWAP_LE32(d, s) swap_le32(s, d)
- -#define SWAP_LE64(d, s) swap_le64(s, d)
- -#else
- -#define SQUASHFS_MEMCPY(d, s, n) memcpy(d, s, n)
- -#define SQUASHFS_SWAP_SHORTS(d, s, n) memcpy(d, s, n * sizeof(short))
- -#define SQUASHFS_SWAP_INTS(d, s, n) memcpy(d, s, n * sizeof(int))
- -#define SQUASHFS_SWAP_LONG_LONGS(d, s, n) \
- - memcpy(d, s, n * sizeof(long long))
- -#endif
- +extern struct compressor *read_super(int, struct squashfs_super_block *,
- + char *);
- +extern long long read_filesystem(char *, int, struct squashfs_super_block *,
- +char **, char **, char **, char **, unsigned int *, unsigned int *,
- +unsigned int *, unsigned int *, unsigned int *, int *, int *, int *, int *,
- +int *, int *, long long *, unsigned int *, unsigned int *, unsigned int *,
- +unsigned int *, void (push_directory_entry)(char *, squashfs_inode, int, int),
- +struct squashfs_fragment_entry **, squashfs_inode **);
- #endif
- diff -Nru squashfs-tools-4.2+20130409/read_xattrs.c squashfs-tools-4.3+20140919/read_xattrs.c
- --- squashfs-tools-4.2+20130409/read_xattrs.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/read_xattrs.c 2015-07-20 21:03:05.000000000 +0200
- @@ -41,7 +41,6 @@
- #include "squashfs_fs.h"
- #include "squashfs_swap.h"
- -#include "read_fs.h"
- #include "xattr.h"
- #include "error.h"
- @@ -338,7 +337,7 @@
- MEM_ERROR();
- }
- - SQUASHFS_SWAP_XATTR_ENTRY(&entry, xptr);
- + SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
- xptr += sizeof(entry);
- res = read_xattr_entry(&xattr_list[j], &entry, xptr);
- @@ -361,15 +360,15 @@
- void *ool_xptr;
- xptr += sizeof(val);
- - SQUASHFS_SWAP_LONG_LONGS(&xattr, xptr, 1);
- + SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
- xptr += sizeof(xattr);
- start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
- offset = SQUASHFS_XATTR_OFFSET(xattr);
- ool_xptr = xattrs + get_xattr_block(start) + offset;
- - SQUASHFS_SWAP_XATTR_VAL(&val, ool_xptr);
- + SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
- xattr_list[j].value = ool_xptr + sizeof(val);
- } else {
- - SQUASHFS_SWAP_XATTR_VAL(&val, xptr);
- + SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
- xattr_list[j].value = xptr + sizeof(val);
- xptr += sizeof(val) + val.vsize;
- }
- diff -Nru squashfs-tools-4.2+20130409/restore.c squashfs-tools-4.3+20140919/restore.c
- --- squashfs-tools-4.2+20130409/restore.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/restore.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2013
- + * Copyright (c) 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -36,22 +36,30 @@
- #include <sys/types.h>
- #include <sys/stat.h>
- +#include "caches-queues-lists.h"
- #include "squashfs_fs.h"
- #include "mksquashfs.h"
- #include "error.h"
- #include "progressbar.h"
- #include "info.h"
- -pthread_t restore_thread, main_thread;
- -int interrupted = 0;
- +#define FALSE 0
- +#define TRUE 1
- +extern pthread_t reader_thread, writer_thread, main_thread;
- +extern pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
- +extern struct queue *to_deflate, *to_writer, *to_frag, *to_process_frag;
- +extern struct seq_queue *to_main;
- extern void restorefs();
- +extern int processors;
- +static int interrupted = 0;
- +static pthread_t restore_thread;
- void *restore_thrd(void *arg)
- {
- sigset_t sigmask, old_mask;
- - int sig;
- + int i, sig;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGINT);
- @@ -62,31 +70,86 @@
- while(1) {
- sigwait(&sigmask, &sig);
- - if(sig == SIGINT || sig == SIGTERM) {
- - interrupted ++;
- -
- - if(interrupted == 1) {
- - ERROR("Interrupting will restore original "
- - "filesystem!\n");
- - ERROR("Interrupt again to quit\n");
- - }
- + if((sig == SIGINT || sig == SIGTERM) && !interrupted) {
- + ERROR("Interrupting will restore original "
- + "filesystem!\n");
- + ERROR("Interrupt again to quit\n");
- + interrupted = TRUE;
- + continue;
- }
- - if(interrupted == 2 || sig == SIGUSR1) {
- - disable_progress_bar();
- - disable_info();
- - pthread_cancel(main_thread);
- - pthread_join(main_thread, NULL);
- + /* kill main thread/worker threads and restore */
- + set_progressbar_state(FALSE);
- + disable_info();
- +
- + /* first kill the reader thread */
- + pthread_cancel(reader_thread);
- + pthread_join(reader_thread, NULL);
- +
- + /*
- + * then flush the reader to deflator thread(s) output queue.
- + * The deflator thread(s) will idle
- + */
- + queue_flush(to_deflate);
- +
- + /* now kill the deflator thread(s) */
- + for(i = 0; i < processors; i++)
- + pthread_cancel(deflator_thread[i]);
- + for(i = 0; i < processors; i++)
- + pthread_join(deflator_thread[i], NULL);
- +
- + /*
- + * then flush the reader to process fragment thread(s) output
- + * queue. The process fragment thread(s) will idle
- + */
- + queue_flush(to_process_frag);
- +
- + /* now kill the process fragment thread(s) */
- + for(i = 0; i < processors; i++)
- + pthread_cancel(frag_thread[i]);
- + for(i = 0; i < processors; i++)
- + pthread_join(frag_thread[i], NULL);
- +
- + /*
- + * then flush the reader/deflator/process fragment to main
- + * thread output queue. The main thread will idle
- + */
- + seq_queue_flush(to_main);
- +
- + /* now kill the main thread */
- + pthread_cancel(main_thread);
- + pthread_join(main_thread, NULL);
- +
- + /* then flush the main thread to fragment deflator thread(s)
- + * queue. The fragment deflator thread(s) will idle
- + */
- + queue_flush(to_frag);
- +
- + /* now kill the fragment deflator thread(s) */
- + for(i = 0; i < processors; i++)
- + pthread_cancel(frag_deflator_thread[i]);
- + for(i = 0; i < processors; i++)
- + pthread_join(frag_deflator_thread[i], NULL);
- +
- + /*
- + * then flush the main thread/fragment deflator thread(s)
- + * to writer thread queue. The writer thread will idle
- + */
- + queue_flush(to_writer);
- +
- + /* now kill the writer thread */
- + pthread_cancel(writer_thread);
- + pthread_join(writer_thread, NULL);
- - restorefs();
- - }
- + TRACE("All threads cancelled\n");
- +
- + restorefs();
- }
- }
- -pthread_t *init_restore_thread(pthread_t thread)
- +pthread_t *init_restore_thread()
- {
- - main_thread = thread;
- pthread_create(&restore_thread, NULL, restore_thrd, NULL);
- return &restore_thread;
- }
- diff -Nru squashfs-tools-4.2+20130409/restore.h squashfs-tools-4.3+20140919/restore.h
- --- squashfs-tools-4.2+20130409/restore.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/restore.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,28 @@
- +#ifndef RESTORE_H
- +#define RESTORE_H
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only
- + * filesystem.
- + *
- + * Copyright (c) 2013, 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * restore.h
- + */
- +
- +extern pthread_t *init_restore_thread();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/sort.c squashfs-tools-4.3+20140919/sort.c
- --- squashfs-tools-4.2+20130409/sort.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/sort.c 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- * filesystem.
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
- - * 2013
- + * 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -42,6 +42,7 @@
- #include "mksquashfs.h"
- #include "sort.h"
- #include "error.h"
- +#include "progressbar.h"
- int mkisofs_style = -1;
- @@ -170,9 +171,10 @@
- }
- error:
- - ERROR("Cannot stat sortlist entry \"%s\"\n", path);
- + ERROR_START("Cannot stat sortlist entry \"%s\"\n", path);
- ERROR("This is probably because you're using the wrong file\n");
- - ERROR("path relative to the source directories\n");
- + ERROR("path relative to the source directories.");
- + ERROR_EXIT(" Ignoring");
- /*
- * Historical note
- * Failure to stat a sortlist entry is deliberately ignored, even
- diff -Nru squashfs-tools-4.2+20130409/sort.h squashfs-tools-4.3+20140919/sort.h
- --- squashfs-tools-4.2+20130409/sort.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/sort.h 2015-07-20 21:03:05.000000000 +0200
- @@ -4,7 +4,7 @@
- /*
- * Squashfs
- *
- - * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -28,4 +28,10 @@
- struct dir_ent *dir;
- struct priority_entry *next;
- };
- +
- +extern int read_sort_file(char *, int, char *[]);
- +extern void sort_files_and_write(struct dir_info *);
- +extern void generate_file_priorities(struct dir_info *, int priority,
- + struct stat *);
- +extern struct priority_entry *priority_list[65536];
- #endif
- diff -Nru squashfs-tools-4.2+20130409/squashfs_compat.h squashfs-tools-4.3+20140919/squashfs_compat.h
- --- squashfs-tools-4.2+20130409/squashfs_compat.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/squashfs_compat.h 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- /*
- * Squashfs
- *
- - * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -50,7 +50,7 @@
- unsigned int flags:8;
- unsigned int no_uids:8;
- unsigned int no_guids:8;
- - unsigned int mkfs_time /* time of filesystem creation */;
- + int mkfs_time /* time of filesystem creation */;
- squashfs_inode root_inode;
- unsigned int block_size;
- unsigned int fragments;
- @@ -71,38 +71,55 @@
- unsigned char name[0];
- } __attribute__ ((packed));
- -#define SQUASHFS_BASE_INODE_HEADER_3 \
- - unsigned int inode_type:4; \
- - unsigned int mode:12; \
- - unsigned int uid:8; \
- - unsigned int guid:8; \
- - unsigned int mtime; \
- - unsigned int inode_number;
- -
- struct squashfs_base_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- } __attribute__ ((packed));
- struct squashfs_ipc_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- } __attribute__ ((packed));
- struct squashfs_dev_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- unsigned short rdev;
- } __attribute__ ((packed));
- struct squashfs_symlink_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- unsigned short symlink_size;
- char symlink[0];
- } __attribute__ ((packed));
- struct squashfs_reg_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- squashfs_block start_block;
- unsigned int fragment;
- unsigned int offset;
- @@ -111,7 +128,12 @@
- } __attribute__ ((packed));
- struct squashfs_lreg_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- squashfs_block start_block;
- unsigned int fragment;
- @@ -121,7 +143,12 @@
- } __attribute__ ((packed));
- struct squashfs_dir_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- unsigned int file_size:19;
- unsigned int offset:13;
- @@ -130,7 +157,12 @@
- } __attribute__ ((packed));
- struct squashfs_ldir_inode_header_3 {
- - SQUASHFS_BASE_INODE_HEADER_3;
- + unsigned int inode_type:4;
- + unsigned int mode:12;
- + unsigned int uid:8;
- + unsigned int guid:8;
- + int mtime;
- + unsigned int inode_number;
- unsigned int nlink;
- unsigned int file_size:27;
- unsigned int offset:13;
- @@ -449,7 +481,7 @@
- unsigned int mode:12; /* protection */
- unsigned int uid:4; /* index into uid table */
- unsigned int guid:4; /* index into guid table */
- - unsigned int mtime;
- + int mtime;
- unsigned int start_block;
- unsigned int file_size:32;
- unsigned short block_list[0];
- @@ -462,7 +494,7 @@
- unsigned int guid:4; /* index into guid table */
- unsigned int file_size:19;
- unsigned int offset:13;
- - unsigned int mtime;
- + int mtime;
- unsigned int start_block:24;
- } __attribute__ ((packed));
- @@ -582,7 +614,7 @@
- unsigned int mode:12; /* protection */
- unsigned int uid:8; /* index into uid table */
- unsigned int guid:8; /* index into guid table */
- - unsigned int mtime;
- + int mtime;
- unsigned int start_block;
- unsigned int fragment;
- unsigned int offset;
- @@ -597,7 +629,7 @@
- unsigned int guid:8; /* index into guid table */
- unsigned int file_size:19;
- unsigned int offset:13;
- - unsigned int mtime;
- + int mtime;
- unsigned int start_block:24;
- } __attribute__ ((packed));
- @@ -608,7 +640,7 @@
- unsigned int guid:8; /* index into guid table */
- unsigned int file_size:27;
- unsigned int offset:13;
- - unsigned int mtime;
- + int mtime;
- unsigned int start_block:24;
- unsigned int i_count:16;
- struct squashfs_dir_index_2 index[0];
- diff -Nru squashfs-tools-4.2+20130409/squashfs_fs.h squashfs-tools-4.3+20140919/squashfs_fs.h
- --- squashfs-tools-4.2+20130409/squashfs_fs.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/squashfs_fs.h 2015-07-20 21:03:05.000000000 +0200
- @@ -4,7 +4,7 @@
- * Squashfs
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
- - * 2013
- + * 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -276,11 +276,12 @@
- #define LZMA_COMPRESSION 2
- #define LZO_COMPRESSION 3
- #define XZ_COMPRESSION 4
- +#define LZ4_COMPRESSION 5
- struct squashfs_super_block {
- unsigned int s_magic;
- unsigned int inodes;
- - unsigned int mkfs_time /* time of filesystem creation */;
- + int mkfs_time /* time of filesystem creation */;
- unsigned int block_size;
- unsigned int fragments;
- unsigned short compression;
- @@ -311,7 +312,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- };
- @@ -320,7 +321,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- };
- @@ -330,7 +331,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- unsigned int xattr;
- @@ -341,7 +342,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- unsigned int rdev;
- @@ -352,7 +353,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- unsigned int rdev;
- @@ -364,7 +365,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- unsigned int symlink_size;
- @@ -376,7 +377,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int start_block;
- unsigned int fragment;
- @@ -390,7 +391,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- squashfs_block start_block;
- long long file_size;
- @@ -407,7 +408,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int start_block;
- unsigned int nlink;
- @@ -421,7 +422,7 @@
- unsigned short mode;
- unsigned short uid;
- unsigned short guid;
- - unsigned int mtime;
- + int mtime;
- unsigned int inode_number;
- unsigned int nlink;
- unsigned int file_size;
- diff -Nru squashfs-tools-4.2+20130409/squashfs_swap.h squashfs-tools-4.3+20140919/squashfs_swap.h
- --- squashfs-tools-4.2+20130409/squashfs_swap.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/squashfs_swap.h 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- /*
- * Squashfs
- *
- - * Copyright (c) 2008, 2009, 2010
- + * Copyright (c) 2008, 2009, 2010, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -45,7 +45,7 @@
- #define _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_FUNC) {\
- SWAP_FUNC(32, s, d, s_magic, struct squashfs_super_block);\
- SWAP_FUNC(32, s, d, inodes, struct squashfs_super_block);\
- - SWAP_FUNC(32, s, d, mkfs_time, struct squashfs_super_block);\
- + SWAP_FUNC##S(32, s, d, mkfs_time, struct squashfs_super_block);\
- SWAP_FUNC(32, s, d, block_size, struct squashfs_super_block);\
- SWAP_FUNC(32, s, d, fragments, struct squashfs_super_block);\
- SWAP_FUNC(16, s, d, compression, struct squashfs_super_block);\
- @@ -75,7 +75,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_base_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_base_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_base_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_base_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_base_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_base_inode_header);\
- }
- @@ -84,7 +84,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_ipc_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_ipc_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_ipc_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_ipc_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ipc_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_ipc_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_ipc_inode_header);\
- }
- @@ -94,7 +94,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_lipc_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_lipc_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_lipc_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_lipc_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lipc_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_lipc_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_lipc_inode_header);\
- SWAP_FUNC(32, s, d, xattr, struct squashfs_lipc_inode_header);\
- @@ -105,7 +105,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_dev_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_dev_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_dev_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_dev_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dev_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_dev_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_dev_inode_header);\
- SWAP_FUNC(32, s, d, rdev, struct squashfs_dev_inode_header);\
- @@ -116,7 +116,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_ldev_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_ldev_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_ldev_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_ldev_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldev_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldev_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_ldev_inode_header);\
- SWAP_FUNC(32, s, d, rdev, struct squashfs_ldev_inode_header);\
- @@ -128,7 +128,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_symlink_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_symlink_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_symlink_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_symlink_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_symlink_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_symlink_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_symlink_inode_header);\
- SWAP_FUNC(32, s, d, symlink_size, struct squashfs_symlink_inode_header);\
- @@ -139,7 +139,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_reg_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_reg_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_reg_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_reg_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_reg_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_reg_inode_header);\
- SWAP_FUNC(32, s, d, start_block, struct squashfs_reg_inode_header);\
- SWAP_FUNC(32, s, d, fragment, struct squashfs_reg_inode_header);\
- @@ -152,7 +152,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_lreg_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_lreg_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_lreg_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_lreg_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lreg_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_lreg_inode_header);\
- SWAP_FUNC(64, s, d, start_block, struct squashfs_lreg_inode_header);\
- SWAP_FUNC(64, s, d, file_size, struct squashfs_lreg_inode_header);\
- @@ -168,7 +168,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_dir_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_dir_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_dir_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_dir_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dir_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_inode_header);\
- SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_dir_inode_header);\
- @@ -182,7 +182,7 @@
- SWAP_FUNC(16, s, d, mode, struct squashfs_ldir_inode_header);\
- SWAP_FUNC(16, s, d, uid, struct squashfs_ldir_inode_header);\
- SWAP_FUNC(16, s, d, guid, struct squashfs_ldir_inode_header);\
- - SWAP_FUNC(32, s, d, mtime, struct squashfs_ldir_inode_header);\
- + SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldir_inode_header);\
- SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldir_inode_header);\
- SWAP_FUNC(32, s, d, nlink, struct squashfs_ldir_inode_header);\
- SWAP_FUNC(32, s, d, file_size, struct squashfs_ldir_inode_header);\
- @@ -281,6 +281,14 @@
- #define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
- #define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
- +#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
- +#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
- +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
- +
- +#define SWAP_LE16(s, d) swap_le16(s, d)
- +#define SWAP_LE32(s, d) swap_le32(s, d)
- +#define SWAP_LE64(s, d) swap_le64(s, d)
- +
- /* big endian architecture swap in-place macros */
- #define SQUASHFS_INSWAP_SUPER_BLOCK(s) \
- _SQUASHFS_SWAP_SUPER_BLOCK(s, s, INSWAP_LE)
- @@ -323,8 +331,9 @@
- #define INSWAP_LE(bits, s, d, field, type) \
- (s)->field = inswap_le##bits((s)->field)
- #define INSWAP_LES(bits, s, d, field, type) \
- - (s)->field = (short) inswap_le##bits((unsigned short) \
- - (s)->field)
- + (s)->field = INSWAP_LES##bits((s)->field)
- +#define INSWAP_LES16(num) (short) inswap_le16((unsigned short) (num))
- +#define INSWAP_LES32(num) (int) inswap_le32((unsigned int) (num))
- #define SQUASHFS_INSWAP_INODE_T(s) s = inswap_le64(s)
- #define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) inswap_le64_num(s, n)
- #define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) inswap_le64_num(s, n)
- @@ -335,49 +344,55 @@
- #else
- /* little endian architecture, just copy */
- #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_super_block))
- #define SQUASHFS_SWAP_DIR_INDEX(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_index))
- #define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_base_inode_header))
- #define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ipc_inode_header))
- #define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lipc_inode_header))
- #define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dev_inode_header))
- #define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldev_inode_header))
- #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_symlink_inode_header))
- #define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_reg_inode_header))
- #define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lreg_inode_header))
- #define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_inode_header))
- #define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldir_inode_header))
- #define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_entry))
- #define SQUASHFS_SWAP_DIR_HEADER(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_header))
- #define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_fragment_entry))
- #define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_entry))
- #define SQUASHFS_SWAP_XATTR_VAL(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_val))
- #define SQUASHFS_SWAP_XATTR_ID(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_id))
- #define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
- - SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
- + SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_table))
- #define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
- #define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
- SQUASHFS_SWAP_LONG_LONGS(s, d, n)
- #define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
- #define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
- +#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
- +#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
- +#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
- +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
- + memcpy(d, s, n * sizeof(long long))
- +
- /* little endian architecture, data already in place so do nothing */
- #define SQUASHFS_INSWAP_SUPER_BLOCK(s)
- #define SQUASHFS_INSWAP_DIR_INDEX(s)
- diff -Nru squashfs-tools-4.2+20130409/unsquash-4.c squashfs-tools-4.3+20140919/unsquash-4.c
- --- squashfs-tools-4.2+20130409/unsquash-4.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/unsquash-4.c 2015-07-20 21:03:05.000000000 +0200
- @@ -24,7 +24,6 @@
- #include "unsquashfs.h"
- #include "squashfs_swap.h"
- -#include "read_fs.h"
- static struct squashfs_fragment_entry *fragment_table;
- static unsigned int *id_table;
- @@ -109,7 +108,7 @@
- EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
- start);
- - SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, block_ptr);
- + SQUASHFS_SWAP_BASE_INODE_HEADER(block_ptr, &header.base);
- i.uid = (uid_t) id_table[header.base.uid];
- i.gid = (uid_t) id_table[header.base.guid];
- @@ -122,7 +121,7 @@
- case SQUASHFS_DIR_TYPE: {
- struct squashfs_dir_inode_header *inode = &header.dir;
- - SQUASHFS_SWAP_DIR_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_DIR_INODE_HEADER(block_ptr, inode);
- i.data = inode->file_size;
- i.offset = inode->offset;
- @@ -133,7 +132,7 @@
- case SQUASHFS_LDIR_TYPE: {
- struct squashfs_ldir_inode_header *inode = &header.ldir;
- - SQUASHFS_SWAP_LDIR_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_LDIR_INODE_HEADER(block_ptr, inode);
- i.data = inode->file_size;
- i.offset = inode->offset;
- @@ -144,7 +143,7 @@
- case SQUASHFS_FILE_TYPE: {
- struct squashfs_reg_inode_header *inode = &header.reg;
- - SQUASHFS_SWAP_REG_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_REG_INODE_HEADER(block_ptr, inode);
- i.data = inode->file_size;
- i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
- @@ -164,7 +163,7 @@
- case SQUASHFS_LREG_TYPE: {
- struct squashfs_lreg_inode_header *inode = &header.lreg;
- - SQUASHFS_SWAP_LREG_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_LREG_INODE_HEADER(block_ptr, inode);
- i.data = inode->file_size;
- i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
- @@ -185,7 +184,7 @@
- case SQUASHFS_LSYMLINK_TYPE: {
- struct squashfs_symlink_inode_header *inode = &header.symlink;
- - SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(block_ptr, inode);
- i.symlink = malloc(inode->symlink_size + 1);
- if(i.symlink == NULL)
- @@ -198,9 +197,9 @@
- i.data = inode->symlink_size;
- if(header.base.inode_type == SQUASHFS_LSYMLINK_TYPE)
- - SQUASHFS_SWAP_INTS(&i.xattr, block_ptr +
- + SQUASHFS_SWAP_INTS(block_ptr +
- sizeof(struct squashfs_symlink_inode_header) +
- - inode->symlink_size, 1);
- + inode->symlink_size, &i.xattr, 1);
- else
- i.xattr = SQUASHFS_INVALID_XATTR;
- break;
- @@ -209,7 +208,7 @@
- case SQUASHFS_CHRDEV_TYPE: {
- struct squashfs_dev_inode_header *inode = &header.dev;
- - SQUASHFS_SWAP_DEV_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_DEV_INODE_HEADER(block_ptr, inode);
- i.data = inode->rdev;
- i.xattr = SQUASHFS_INVALID_XATTR;
- @@ -219,7 +218,7 @@
- case SQUASHFS_LCHRDEV_TYPE: {
- struct squashfs_ldev_inode_header *inode = &header.ldev;
- - SQUASHFS_SWAP_LDEV_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_LDEV_INODE_HEADER(block_ptr, inode);
- i.data = inode->rdev;
- i.xattr = inode->xattr;
- @@ -234,7 +233,7 @@
- case SQUASHFS_LSOCKET_TYPE: {
- struct squashfs_lipc_inode_header *inode = &header.lipc;
- - SQUASHFS_SWAP_LIPC_INODE_HEADER(inode, block_ptr);
- + SQUASHFS_SWAP_LIPC_INODE_HEADER(block_ptr, inode);
- i.data = 0;
- i.xattr = inode->xattr;
- @@ -299,7 +298,7 @@
- size = (*i)->data + bytes - 3;
- while(bytes < size) {
- - SQUASHFS_SWAP_DIR_HEADER(&dirh, directory_table + bytes);
- + SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
- dir_count = dirh.count + 1;
- TRACE("squashfs_opendir: Read directory header @ byte position "
- @@ -311,7 +310,7 @@
- goto corrupted;
- while(dir_count--) {
- - SQUASHFS_SWAP_DIR_ENTRY(dire, directory_table + bytes);
- + SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
- bytes += sizeof(*dire);
- diff -Nru squashfs-tools-4.2+20130409/unsquashfs.c squashfs-tools-4.3+20140919/unsquashfs.c
- --- squashfs-tools-4.2+20130409/unsquashfs.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/unsquashfs.c 2015-07-20 21:03:05.000000000 +0200
- @@ -3,7 +3,7 @@
- * filesystem.
- *
- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- - * 2012, 2013
- + * 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -26,9 +26,9 @@
- #include "unsquashfs.h"
- #include "squashfs_swap.h"
- #include "squashfs_compat.h"
- -#include "read_fs.h"
- #include "compressor.h"
- #include "xattr.h"
- +#include "unsquashfs_info.h"
- #include "stdarg.h"
- #include <sys/sysinfo.h>
- @@ -39,8 +39,8 @@
- #include <ctype.h>
- struct cache *fragment_cache, *data_cache;
- -struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
- -pthread_t *thread, *deflator_thread;
- +struct queue *to_reader, *to_inflate, *to_writer, *from_writer;
- +pthread_t *thread, *inflator_thread;
- pthread_mutex_t fragment_mutex;
- /* user options that control parallelisation */
- @@ -69,7 +69,6 @@
- int columns;
- int rotate = 0;
- pthread_mutex_t screen_mutex;
- -pthread_cond_t progress_wait;
- int progress = TRUE, progress_enabled = FALSE;
- unsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
- unsigned int cur_blocks = 0;
- @@ -121,7 +120,6 @@
- };
- void progress_bar(long long current, long long max, int columns);
- -void update_progress_bar();
- #define MAX_LINE 16384
- @@ -226,6 +224,21 @@
- }
- +void dump_queue(struct queue *queue)
- +{
- + pthread_mutex_lock(&queue->mutex);
- +
- + printf("Max size %d, size %d%s\n", queue->size - 1,
- + queue->readp <= queue->writep ? queue->writep - queue->readp :
- + queue->size - queue->readp + queue->writep,
- + queue->readp == queue->writep ? " (EMPTY)" :
- + ((queue->writep + 1) % queue->size) == queue->readp ?
- + " (FULL)" : "");
- +
- + pthread_mutex_unlock(&queue->mutex);
- +}
- +
- +
- /* Called with the cache mutex held */
- void insert_hash_table(struct cache *cache, struct cache_entry *entry)
- {
- @@ -272,7 +285,7 @@
- /* Called with the cache mutex held */
- void remove_free_list(struct cache *cache, struct cache_entry *entry)
- {
- - if(entry->free_prev == NULL && entry->free_next == NULL)
- + if(entry->free_prev == NULL || entry->free_next == NULL)
- /* not in free list */
- return;
- else if(entry->free_prev == entry && entry->free_next == entry) {
- @@ -300,6 +313,7 @@
- cache->max_buffers = max_buffers;
- cache->buffer_size = buffer_size;
- cache->count = 0;
- + cache->used = 0;
- cache->free_list = NULL;
- memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
- cache->wait_free = FALSE;
- @@ -316,7 +330,7 @@
- {
- /*
- * Get a block out of the cache. If the block isn't in the cache
- - * it is added and queued to the reader() and deflate() threads for
- + * it is added and queued to the reader() and inflate() threads for
- * reading off disk and decompression. The cache grows until max_blocks
- * is reached, once this occurs existing discarded blocks on the free
- * list are reused
- @@ -332,11 +346,14 @@
- if(entry) {
- /*
- - * found the block in the cache, increment used count and
- - * if necessary remove from free list so it won't disappear
- + * found the block in the cache. If the block is currently unused
- + * remove it from the free list and increment cache used count.
- */
- + if(entry->used == 0) {
- + cache->used ++;
- + remove_free_list(cache, entry);
- + }
- entry->used ++;
- - remove_free_list(cache, entry);
- pthread_mutex_unlock(&cache->mutex);
- } else {
- /*
- @@ -369,7 +386,11 @@
- }
- /*
- - * initialise block and insert into the hash table
- + * Initialise block and insert into the hash table.
- + * Increment used which tracks how many buffers in the
- + * cache are actively in use (the other blocks, count - used,
- + * are in the cache and available for lookup, but can also be
- + * re-used).
- */
- entry->block = block;
- entry->size = size;
- @@ -377,6 +398,7 @@
- entry->error = FALSE;
- entry->pending = TRUE;
- insert_hash_table(cache, entry);
- + cache->used ++;
- /*
- * queue to read thread to read and ultimately (via the
- @@ -446,6 +468,7 @@
- entry->used --;
- if(entry->used == 0) {
- insert_free_list(entry->cache, entry);
- + entry->cache->used --;
- /*
- * if the wait_free flag is set, one or more threads may be
- @@ -461,6 +484,18 @@
- }
- +void dump_cache(struct cache *cache)
- +{
- + pthread_mutex_lock(&cache->mutex);
- +
- + printf("Max buffers %d, Current size %d, Used %d, %s\n",
- + cache->max_buffers, cache->count, cache->used,
- + cache->free_list ? "Free buffers" : "No free buffers");
- +
- + pthread_mutex_unlock(&cache->mutex);
- +}
- +
- +
- char *modestr(char *str, int mode)
- {
- int i;
- @@ -1223,11 +1258,14 @@
- target ++;
- start = target;
- - while(*target != '/' && *target!= '\0')
- + while(*target != '/' && *target != '\0')
- target ++;
- *targname = strndup(start, target - start);
- + while(*target == '/')
- + target ++;
- +
- return target;
- }
- @@ -1554,26 +1592,27 @@
- if(res == -1)
- EXIT_UNSQUASH("asprintf failed in dir_scan\n");
- - if(type == SQUASHFS_DIR_TYPE)
- + if(type == SQUASHFS_DIR_TYPE) {
- dir_scan(pathname, start_block, offset, new);
- - else if(new == NULL) {
- + free(pathname);
- + } else if(new == NULL) {
- + update_info(pathname);
- +
- i = s_ops.read_inode(start_block, offset);
- if(lsonly || info)
- print_filename(pathname, i);
- - if(!lsonly) {
- + if(!lsonly)
- create_inode(pathname, i);
- - update_progress_bar();
- - }
- if(i->type == SQUASHFS_SYMLINK_TYPE ||
- i->type == SQUASHFS_LSYMLINK_TYPE)
- free(i->symlink);
- - }
- + } else
- + free(pathname);
- free_subdir(new);
- - free(pathname);
- }
- if(!lsonly)
- @@ -1609,7 +1648,7 @@
- printf("Compression %s\n", comp->name);
- if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
- - char buffer[SQUASHFS_METADATA_SIZE];
- + char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
- int bytes;
- bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
- @@ -1637,7 +1676,7 @@
- printf("Fragments are %scompressed\n",
- SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
- "un" : "");
- - printf("Always_use_fragments option is %sspecified\n",
- + printf("Always-use-fragments option is %sspecified\n",
- SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
- "not ");
- }
- @@ -1698,6 +1737,42 @@
- }
- +int check_compression(struct compressor *comp)
- +{
- + int res, bytes = 0;
- + char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
- +
- + if(!comp->supported) {
- + ERROR("Filesystem uses %s compression, this is "
- + "unsupported by this version\n", comp->name);
- + ERROR("Decompressors available:\n");
- + display_compressors("", "");
- + return 0;
- + }
- +
- + /*
- + * Read compression options from disk if present, and pass to
- + * the compressor to ensure we know how to decompress a filesystem
- + * compressed with these compression options.
- + *
- + * Note, even if there is no compression options we still call the
- + * compressor because some compression options may be mandatory
- + * for some compressors.
- + */
- + if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
- + bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
- + if(bytes == 0) {
- + ERROR("Failed to read compressor options\n");
- + return 0;
- + }
- + }
- +
- + res = compressor_check_options(comp, sBlk.s.block_size, buffer, bytes);
- +
- + return res != -1;
- +}
- +
- +
- int read_super(char *source)
- {
- squashfs_super_block_3 sBlk_3;
- @@ -1897,10 +1972,10 @@
- if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
- /*
- - * queue successfully read block to the deflate
- + * queue successfully read block to the inflate
- * thread(s) for further processing
- */
- - queue_put(to_deflate, entry);
- + queue_put(to_inflate, entry);
- else
- /*
- * block has either been successfully read and is
- @@ -2019,12 +2094,12 @@
- /*
- * decompress thread. This decompresses buffers queued by the read thread
- */
- -void *deflator(void *arg)
- +void *inflator(void *arg)
- {
- char tmp[block_size];
- while(1) {
- - struct cache_entry *entry = queue_get(to_deflate);
- + struct cache_entry *entry = queue_get(to_inflate);
- int error, res;
- res = compressor_uncompress(comp, tmp, entry->data,
- @@ -2049,8 +2124,7 @@
- void *progress_thread(void *arg)
- {
- - struct timeval timeval;
- - struct timespec timespec;
- + struct timespec requested_time, remaining;
- struct itimerval itimerval;
- struct winsize winsize;
- @@ -2070,22 +2144,22 @@
- itimerval.it_interval.tv_usec = 250000;
- setitimer(ITIMER_REAL, &itimerval, NULL);
- - pthread_cond_init(&progress_wait, NULL);
- + requested_time.tv_sec = 0;
- + requested_time.tv_nsec = 250000000;
- - pthread_mutex_lock(&screen_mutex);
- while(1) {
- - gettimeofday(&timeval, NULL);
- - timespec.tv_sec = timeval.tv_sec;
- - if(timeval.tv_usec + 250000 > 999999)
- - timespec.tv_sec++;
- - timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
- - 1000;
- - pthread_cond_timedwait(&progress_wait, &screen_mutex,
- - ×pec);
- - if(progress_enabled)
- + int res = nanosleep(&requested_time, &remaining);
- +
- + if(res == -1 && errno != EINTR)
- + EXIT_UNSQUASH("nanosleep failed in progress thread\n");
- +
- + if(progress_enabled) {
- + pthread_mutex_lock(&screen_mutex);
- progress_bar(sym_count + dev_count +
- fifo_count + cur_blocks, total_inodes -
- total_files + total_blocks, columns);
- + pthread_mutex_unlock(&screen_mutex);
- + }
- }
- }
- @@ -2096,11 +2170,23 @@
- int i, max_files, res;
- sigset_t sigmask, old_mask;
- + /* block SIGQUIT and SIGHUP, these are handled by the info thread */
- sigemptyset(&sigmask);
- - sigaddset(&sigmask, SIGINT);
- sigaddset(&sigmask, SIGQUIT);
- - if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
- - EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
- + sigaddset(&sigmask, SIGHUP);
- + if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
- + EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
- + "\n");
- +
- + /*
- + * temporarily block these signals so the created sub-threads will
- + * ignore them, ensuring the main thread handles them
- + */
- + sigemptyset(&sigmask);
- + sigaddset(&sigmask, SIGINT);
- + sigaddset(&sigmask, SIGTERM);
- + if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
- + EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
- "\n");
- if(processors == -1) {
- @@ -2132,14 +2218,14 @@
- thread = malloc((3 + processors) * sizeof(pthread_t));
- if(thread == NULL)
- EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
- - deflator_thread = &thread[3];
- + inflator_thread = &thread[3];
- /*
- - * dimensioning the to_reader and to_deflate queues. The size of
- + * dimensioning the to_reader and to_inflate queues. The size of
- * these queues is directly related to the amount of block
- * read-ahead possible. To_reader queues block read requests to
- - * the reader thread and to_deflate queues block decompression
- - * requests to the deflate thread(s) (once the block has been read by
- + * the reader thread and to_inflate queues block decompression
- + * requests to the inflate thread(s) (once the block has been read by
- * the reader thread). The amount of read-ahead is determined by
- * the combined size of the data_block and fragment caches which
- * determine the total number of blocks which can be "in flight"
- @@ -2162,7 +2248,7 @@
- *
- * dimensioning the to_writer queue. The size of this queue is
- * directly related to the amount of block read-ahead possible.
- - * However, unlike the to_reader and to_deflate queues, this is
- + * However, unlike the to_reader and to_inflate queues, this is
- * complicated by the fact the to_writer queue not only contains
- * entries for fragments and data_blocks but it also contains
- * file entries, one per open file in the read-ahead.
- @@ -2196,7 +2282,7 @@
- open_init(max_files);
- /*
- - * allocate to_reader, to_deflate and to_writer queues. Set based on
- + * allocate to_reader, to_inflate and to_writer queues. Set based on
- * open file limit and cache size, unless open file limit is unlimited,
- * in which case set purely based on cache limits
- *
- @@ -2209,7 +2295,7 @@
- EXIT_UNSQUASH("Data queue size is too large\n");
- to_reader = queue_init(max_files + data_buffer_size);
- - to_deflate = queue_init(max_files + data_buffer_size);
- + to_inflate = queue_init(max_files + data_buffer_size);
- to_writer = queue_init(max_files * 2 + data_buffer_size);
- } else {
- int all_buffers_size;
- @@ -2225,7 +2311,7 @@
- " too large\n");
- to_reader = queue_init(all_buffers_size);
- - to_deflate = queue_init(all_buffers_size);
- + to_inflate = queue_init(all_buffers_size);
- to_writer = queue_init(all_buffers_size * 2);
- }
- @@ -2236,10 +2322,11 @@
- pthread_create(&thread[0], NULL, reader, NULL);
- pthread_create(&thread[1], NULL, writer, NULL);
- pthread_create(&thread[2], NULL, progress_thread, NULL);
- + init_info();
- pthread_mutex_init(&fragment_mutex, NULL);
- for(i = 0; i < processors; i++) {
- - if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
- + if(pthread_create(&inflator_thread[i], NULL, inflator, NULL) !=
- 0)
- EXIT_UNSQUASH("Failed to create thread\n");
- }
- @@ -2247,8 +2334,8 @@
- printf("Parallel unsquashfs: Using %d processor%s\n", processors,
- processors == 1 ? "" : "s");
- - if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
- - EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
- + if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1)
- + EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
- "\n");
- }
- @@ -2256,7 +2343,7 @@
- void enable_progress_bar()
- {
- pthread_mutex_lock(&screen_mutex);
- - progress_enabled = TRUE;
- + progress_enabled = progress;
- pthread_mutex_unlock(&screen_mutex);
- }
- @@ -2264,19 +2351,16 @@
- void disable_progress_bar()
- {
- pthread_mutex_lock(&screen_mutex);
- + if(progress_enabled) {
- + progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
- + total_inodes - total_files + total_blocks, columns);
- + printf("\n");
- + }
- progress_enabled = FALSE;
- pthread_mutex_unlock(&screen_mutex);
- }
- -void update_progress_bar()
- -{
- - pthread_mutex_lock(&screen_mutex);
- - pthread_cond_signal(&progress_wait);
- - pthread_mutex_unlock(&screen_mutex);
- -}
- -
- -
- void progressbar_error(char *fmt, ...)
- {
- va_list ap;
- @@ -2393,8 +2477,8 @@
- #define VERSION() \
- - printf("unsquashfs version 4.2-git (2013/03/13)\n");\
- - printf("copyright (C) 2013 Phillip Lougher "\
- + printf("unsquashfs version 4.3 (2014/05/12)\n");\
- + printf("copyright (C) 2014 Phillip Lougher "\
- "<phillip@squashfs.org.uk>\n\n");\
- printf("This program is free software; you can redistribute it and/or"\
- "\n");\
- @@ -2535,6 +2619,11 @@
- progress = FALSE;
- #ifdef SQUASHFS_TRACE
- + /*
- + * Disable progress bar if full debug tracing is enabled.
- + * The progress bar in this case just gets in the way of the
- + * debug trace output
- + */
- progress = FALSE;
- #endif
- @@ -2608,13 +2697,8 @@
- exit(0);
- }
- - if(!comp->supported) {
- - ERROR("Filesystem uses %s compression, this is "
- - "unsupported by this version\n", comp->name);
- - ERROR("Decompressors available:\n");
- - display_compressors("", "");
- + if(!check_compression(comp))
- exit(1);
- - }
- block_size = sBlk.s.block_size;
- block_log = sBlk.s.block_log;
- @@ -2707,8 +2791,7 @@
- printf("%d inodes (%d blocks) to write\n\n", total_inodes,
- total_inodes - total_files + total_blocks);
- - if(progress)
- - enable_progress_bar();
- + enable_progress_bar();
- dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
- SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
- @@ -2716,11 +2799,7 @@
- queue_put(to_writer, NULL);
- queue_get(from_writer);
- - if(progress) {
- - disable_progress_bar();
- - progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
- - total_inodes - total_files + total_blocks, columns);
- - }
- + disable_progress_bar();
- if(!lsonly) {
- printf("\n");
- diff -Nru squashfs-tools-4.2+20130409/unsquashfs.h squashfs-tools-4.3+20140919/unsquashfs.h
- --- squashfs-tools-4.2+20130409/unsquashfs.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/unsquashfs.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef UNSQUASHFS_H
- +#define UNSQUASHFS_H
- /*
- * Unsquash a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2009, 2010, 2013
- + * Copyright (c) 2009, 2010, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -121,6 +123,7 @@
- struct cache {
- int max_buffers;
- int count;
- + int used;
- int buffer_size;
- int wait_free;
- int wait_pending;
- @@ -232,11 +235,17 @@
- extern int inode_number;
- extern int lookup_type[];
- extern int fd;
- +extern struct queue *to_reader, *to_inflate, *to_writer;
- +extern struct cache *fragment_cache, *data_cache;
- /* unsquashfs.c */
- extern int lookup_entry(struct hash_table_entry **, long long);
- extern int read_fs_bytes(int fd, long long, int, void *);
- extern int read_block(int, long long, long long *, int, void *);
- +extern void enable_progress_bar();
- +extern void disable_progress_bar();
- +extern void dump_queue(struct queue *);
- +extern void dump_cache(struct cache *);
- /* unsquash-1.c */
- extern void read_block_list_1(unsigned int *, char *, int);
- @@ -266,3 +275,4 @@
- extern struct dir *squashfs_opendir_4(unsigned int, unsigned int,
- struct inode **);
- extern int read_uids_guids_4();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/unsquashfs_info.c squashfs-tools-4.3+20140919/unsquashfs_info.c
- --- squashfs-tools-4.2+20130409/unsquashfs_info.c 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/unsquashfs_info.c 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,145 @@
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only
- + * filesystem.
- + *
- + * Copyright (c) 2013
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * unsquashfs_info.c
- + */
- +
- +#include <pthread.h>
- +#include <sys/ioctl.h>
- +#include <unistd.h>
- +#include <signal.h>
- +#include <sys/time.h>
- +#include <stdio.h>
- +#include <math.h>
- +#include <stdarg.h>
- +#include <errno.h>
- +#include <stdlib.h>
- +#include <dirent.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <string.h>
- +
- +#include "squashfs_fs.h"
- +#include "unsquashfs.h"
- +#include "error.h"
- +
- +static int silent = 0;
- +char *pathname = NULL;
- +
- +pthread_t info_thread;
- +
- +
- +void disable_info()
- +{
- + if(pathname)
- + free(pathname);
- +
- + pathname = NULL;
- +}
- +
- +
- +void update_info(char *name)
- +{
- + if(pathname)
- + free(pathname);
- +
- + pathname = name;
- +}
- +
- +
- +void dump_state()
- +{
- + disable_progress_bar();
- +
- + printf("Queue and cache status dump\n");
- + printf("===========================\n");
- +
- + printf("file buffer read queue (main thread -> reader thread)\n");
- + dump_queue(to_reader);
- +
- + printf("file buffer decompress queue (reader thread -> inflate"
- + " thread(s))\n");
- + dump_queue(to_inflate);
- +
- + printf("file buffer write queue (main thread -> writer thread)\n");
- + dump_queue(to_writer);
- +
- + printf("\nbuffer cache (uncompressed blocks and compressed blocks "
- + "'in flight')\n");
- + dump_cache(data_cache);
- +
- + printf("fragment buffer cache (uncompressed frags and compressed"
- + " frags 'in flight')\n");
- + dump_cache(fragment_cache);
- +
- + enable_progress_bar();
- +}
- +
- +
- +void *info_thrd(void *arg)
- +{
- + sigset_t sigmask;
- + struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
- + int sig, waiting = 0;
- +
- + sigemptyset(&sigmask);
- + sigaddset(&sigmask, SIGQUIT);
- + sigaddset(&sigmask, SIGHUP);
- +
- + while(1) {
- + if(waiting)
- + sig = sigtimedwait(&sigmask, NULL, ×pec);
- + else
- + sig = sigwaitinfo(&sigmask, NULL);
- +
- + if(sig == -1) {
- + switch(errno) {
- + case EAGAIN:
- + /* interval timed out */
- + waiting = 0;
- + /* FALLTHROUGH */
- + case EINTR:
- + /* if waiting, the wait will be longer, but
- + that's OK */
- + continue;
- + default:
- + BAD_ERROR("sigtimedwait/sigwaitinfo failed "
- + "because %s\n", strerror(errno));
- + }
- + }
- +
- + if(sig == SIGQUIT && !waiting) {
- + if(pathname)
- + INFO("%s\n", pathname);
- +
- + /* set one second interval period, if ^\ received
- + within then, dump queue and cache status */
- + waiting = 1;
- + } else
- + dump_state();
- + }
- +}
- +
- +
- +void init_info()
- +{
- + pthread_create(&info_thread, NULL, info_thrd, NULL);
- +}
- diff -Nru squashfs-tools-4.2+20130409/unsquashfs_info.h squashfs-tools-4.3+20140919/unsquashfs_info.h
- --- squashfs-tools-4.2+20130409/unsquashfs_info.h 1970-01-01 01:00:00.000000000 +0100
- +++ squashfs-tools-4.3+20140919/unsquashfs_info.h 2015-07-20 21:03:05.000000000 +0200
- @@ -0,0 +1,30 @@
- +#ifndef UNSQUASHFS_INFO_H
- +#define UNSQUASHFS_INFO_H
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only
- + * filesystem.
- + *
- + * Copyright (c) 2013, 2014
- + * Phillip Lougher <phillip@squashfs.org.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * unsquashfs_info.h
- + */
- +
- +extern void disable_info();
- +extern void update_info(char *);
- +extern void init_info();
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/xattr.c squashfs-tools-4.3+20140919/xattr.c
- --- squashfs-tools-4.2+20130409/xattr.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/xattr.c 2015-07-20 21:03:05.000000000 +0200
- @@ -2,7 +2,7 @@
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2008, 2009, 2010, 2012
- + * Copyright (c) 2008, 2009, 2010, 2012, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -41,6 +41,7 @@
- #include "mksquashfs.h"
- #include "xattr.h"
- #include "error.h"
- +#include "progressbar.h"
- /* compressed xattr table */
- static char *xattr_table = NULL;
- @@ -65,7 +66,7 @@
- static int sxattr_ids = 0;
- /* xattr hash table for value duplicate detection */
- -static struct xattr_list *dupl[65536];
- +static struct xattr_list *dupl_value[65536];
- /* xattr hash table for id duplicate detection */
- static struct dupl_id *dupl_id[65536];
- @@ -120,10 +121,12 @@
- while(1) {
- size = llistxattr(filename, NULL, 0);
- if(size <= 0) {
- - if(size < 0 && errno != ENOTSUP)
- - ERROR("llistxattr for %s failed in read_attrs,"
- - " because %s\n", filename,
- + if(size < 0 && errno != ENOTSUP) {
- + ERROR_START("llistxattr for %s failed in "
- + "read_attrs, because %s", filename,
- strerror(errno));
- + ERROR_EXIT(". Ignoring");
- + }
- return 0;
- }
- @@ -138,9 +141,10 @@
- /* xattr list grew? Try again */
- continue;
- else {
- - ERROR("llistxattr for %s failed in read_attrs,"
- - " because %s\n", filename,
- + ERROR_START("llistxattr for %s failed in "
- + "read_attrs, because %s", filename,
- strerror(errno));
- + ERROR_EXIT(". Ignoring");
- return 0;
- }
- }
- @@ -169,9 +173,10 @@
- vsize = lgetxattr(filename, xattr_list[i].full_name,
- NULL, 0);
- if(vsize < 0) {
- - ERROR("lgetxattr failed for %s in read_attrs,"
- - " because %s\n", filename,
- + ERROR_START("lgetxattr failed for %s in "
- + "read_attrs, because %s", filename,
- strerror(errno));
- + ERROR_EXIT(". Ignoring");
- free(xattr_list[i].full_name);
- goto failed;
- }
- @@ -188,9 +193,10 @@
- /* xattr grew? Try again */
- continue;
- else {
- - ERROR("lgetxattr failed for %s in "
- - "read_attrs, because %s\n",
- + ERROR_START("lgetxattr failed for %s "
- + "in read_attrs, because %s",
- filename, strerror(errno));
- + ERROR_EXIT(". Ignoring");
- free(xattr_list[i].full_name);
- goto failed;
- }
- @@ -342,7 +348,7 @@
- /* Check if this is a duplicate of an existing value */
- xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0);
- - for(entry = dupl[xattr->vchecksum]; entry; entry = entry->vnext) {
- + for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) {
- if(entry->vsize != xattr->vsize)
- continue;
- @@ -355,8 +361,8 @@
- * No duplicate exists, add to hash table, and mark as
- * requiring writing
- */
- - xattr->vnext = dupl[xattr->vchecksum];
- - dupl[xattr->vchecksum] = xattr;
- + xattr->vnext = dupl_value[xattr->vchecksum];
- + dupl_value[xattr->vchecksum] = xattr;
- xattr->ool_value = SQUASHFS_INVALID_BLK;
- } else {
- /*
- diff -Nru squashfs-tools-4.2+20130409/xattr.h squashfs-tools-4.3+20140919/xattr.h
- --- squashfs-tools-4.2+20130409/xattr.h 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/xattr.h 2015-07-20 21:03:05.000000000 +0200
- @@ -1,8 +1,10 @@
- +#ifndef XATTR_H
- +#define XATTR_H
- /*
- * Create a squashfs filesystem. This is a highly compressed read only
- * filesystem.
- *
- - * Copyright (c) 2010, 2012, 2013
- + * Copyright (c) 2010, 2012, 2013, 2014
- * Phillip Lougher <phillip@squashfs.org.uk>
- *
- * This program is free software; you can redistribute it and/or
- @@ -124,7 +126,7 @@
- }
- -static inline struct xattr_list *get_xattr(int i, unsigned int *count, int)
- +static inline struct xattr_list *get_xattr(int i, unsigned int *count, int j)
- {
- return NULL;
- }
- @@ -145,4 +147,4 @@
- #define XOPT_STR " (unsupported)"
- #define XATTR_DEF 1
- #endif
- -
- +#endif
- diff -Nru squashfs-tools-4.2+20130409/xz_wrapper.c squashfs-tools-4.3+20140919/xz_wrapper.c
- --- squashfs-tools-4.2+20130409/xz_wrapper.c 2013-05-09 10:39:11.000000000 +0200
- +++ squashfs-tools-4.3+20140919/xz_wrapper.c 2015-07-20 21:03:05.000000000 +0200
- @@ -41,8 +41,6 @@
- { NULL, LZMA_VLI_UNKNOWN, 0 }
- };
- -static struct comp_opts comp_opts;
- -
- static int filter_count = 1;
- static int dictionary_size = 0;
- static float dictionary_percent = 0;
- @@ -56,10 +54,11 @@
- * -Xbcj
- * -Xdict-size
- *
- - * This function returns 1 on successful parsing of an option
- - * -1 if the option was unrecognised, or
- - * -2 if the option was recognised, but otherwise bad in
- - * some way (e.g. invalid parameter)
- + * This function returns:
- + * >=0 (number of additional args parsed) on success
- + * -1 if the option was unrecognised, or
- + * -2 if the option was recognised, but otherwise bad in
- + * some way (e.g. invalid parameter)
- *
- * Note: this function sets internal compressor state, but does not
- * pass back the results of the parsing other than success/failure.
- @@ -226,6 +225,7 @@
- */
- static void *xz_dump_options(int block_size, int *size)
- {
- + static struct comp_opts comp_opts;
- int flags = 0, i;
- /*
- @@ -329,7 +329,7 @@
- int i, n;
- /* check passed comp opts struct is of the correct length */
- - if(size != sizeof(comp_opts))
- + if(size != sizeof(struct comp_opts))
- goto failed;
- SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
- @@ -494,8 +494,12 @@
- lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
- src, &src_pos, size, dest, &dest_pos, outsize);
- - *error = res;
- - return res == LZMA_OK && size == (int) src_pos ? (int) dest_pos : -1;
- + if(res == LZMA_OK && size == (int) src_pos)
- + return (int) dest_pos;
- + else {
- + *error = res;
- + return -1;
- + }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement