actions: fix symbolic mode parsing in the mode() action
When I implemented symbolic modes in the mode() action (i.e.
u+r-w) I made an oversight. I didn't realise the specification
allowed multiple =-+ sequences after the ownership specification.
In otherwords if you wanted to add r (+r) and remove w (-w)
from user, I assumed you would do u+r,u-w. After revisiting
the symbolic mode specification it turns out you should be able
to do u+r-w as a short cut to the previous specification. It
also should be obvious I don't tend to use the symbolic mode but
directly use the octal specification!
So fix the parser to allow multiple =-+ sequences.
So the syntax of the symbolic mode support goes from
[ugoa]+[+-=]PERMS
PERMS = [rwxXst]+ or [ugo]
to
[ugoa]*[[+-=]PERMS]+
PERMS = [rwxXst]+ or [ugo]
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
diff --git a/squashfs-tools/action.c b/squashfs-tools/action.c
index 5275466..0808cde 100644
--- a/squashfs-tools/action.c
+++ b/squashfs-tools/action.c
@@ -1219,19 +1219,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 */
@@ -1261,102 +1259,116 @@
}
parse_operation:
- switch(*arg) {
- case '+':
- op = ACTION_MODE_ADD;
- break;
- case '-':
- op = ACTION_MODE_REM;
- break;
- case '=':
- op = ACTION_MODE_SET;
- break;
- default:
+ /* trap a symbolic mode with just an ownership specification */
+ if(*arg == '\0') {
SYNTAX_ERROR("Action mode: Expected one of '+', '-' or '=', "
- "got '%c'\n", *arg);
+ "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("Action mode: 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("Action mode: "
+ "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;
+
+ if (*cur) {
+ (*cur)->next = mode_data;
+ *cur = mode_data;
+ } else
+ *head = *cur = mode_data;
}
- mode_data->operation = op;
- mode_data->mode = mode;
- mode_data->mask = mask;
- mode_data->X = X;
- mode_data->next = NULL;
-
- 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;
}
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
index 84fa545..e81e0b4 100644
--- a/squashfs-tools/mksquashfs.c
+++ b/squashfs-tools/mksquashfs.c
@@ -5089,7 +5089,7 @@
#define VERSION() \
- printf("mksquashfs version 4.3-git (2014/08/23)\n");\
+ printf("mksquashfs version 4.3-git (2014/08/30)\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"\