From 76c04748d7b3fec12ed81d464a1e6121181dec99 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 21 Jan 2021 21:30:25 +0100 Subject: cleanup: fstree_from_file: split & simplify line parsing function Signed-off-by: David Oberhollenzer --- lib/fstree/fstree_from_file.c | 198 +++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 107 deletions(-) (limited to 'lib/fstree') diff --git a/lib/fstree/fstree_from_file.c b/lib/fstree/fstree_from_file.c index 678d565..5e2fd87 100644 --- a/lib/fstree/fstree_from_file.c +++ b/lib/fstree/fstree_from_file.c @@ -75,7 +75,7 @@ static int add_hard_link(fstree_t *fs, const char *filename, size_t line_num, return 0; } -static const struct { +static const struct callback_t { const char *keyword; unsigned int mode; bool need_extra; @@ -93,159 +93,143 @@ static const struct { #define NUM_HOOKS (sizeof(file_list_hooks) / sizeof(file_list_hooks[0])) -static int handle_line(fstree_t *fs, const char *filename, - size_t line_num, char *line) +static char *skip_space(char *str) { - const char *extra = NULL, *msg = NULL; - char keyword[16], *path, *ptr; - unsigned int x; - struct stat sb; - size_t i; + if (!isspace(*str)) + return NULL; + while (isspace(*str)) + ++str; + return str; +} - memset(&sb, 0, sizeof(sb)); - sb.st_mtime = fs->defaults.st_mtime; +static char *read_u32(char *str, sqfs_u32 *out, sqfs_u32 base) +{ + *out = 0; - /* isolate keyword */ - for (i = 0; isalpha(line[i]); ++i) - ; + if (!isdigit(*str)) + return NULL; - if (i >= sizeof(keyword) || i == 0 || !isspace(line[i])) - goto fail_ent; + while (isdigit(*str)) { + sqfs_u32 x = *(str++) - '0'; - memcpy(keyword, line, i); - keyword[i] = '\0'; + if (x >= base || (*out) > (0xFFFFFFFF - x) / base) + return NULL; - while (isspace(line[i])) - ++i; + (*out) = (*out) * base + x; + } + + return str; +} - /* isolate path */ - path = line + i; +static char *read_str(char *str, char **out) +{ + *out = str; - if (*path == '"') { - ptr = path; - ++i; + if (*str == '"') { + char *ptr = str++; - while (line[i] != '\0' && line[i] != '"') { - if (line[i] == '\\' && - (line[i + 1] == '"' || line[i + 1] == '\\')) { - *(ptr++) = line[i + 1]; - i += 2; + while (*str != '\0' && *str != '"') { + if (str[0] == '\\' && + (str[1] == '"' || str[1] == '\\')) { + *(ptr++) = str[1]; + str += 2; } else { - *(ptr++) = line[i++]; + *(ptr++) = *(str++); } } - if (line[i] != '"' || !isspace(line[i + 1])) - goto fail_ent; + if (str[0] != '"' || !isspace(str[1])) + return NULL; *ptr = '\0'; - ++i; + ++str; } else { - while (line[i] != '\0' && !isspace(line[i])) - ++i; + while (*str != '\0' && !isspace(*str)) + ++str; - if (!isspace(line[i])) - goto fail_ent; + if (!isspace(*str)) + return NULL; - line[i++] = '\0'; + *(str++) = '\0'; } - while (isspace(line[i])) - ++i; - - if (canonicalize_name(path) || *path == '\0') - goto fail_ent; + while (isspace(*str)) + ++str; - /* mode */ - if (!isdigit(line[i])) - goto fail_mode; + return str; +} - for (; isdigit(line[i]); ++i) { - if (line[i] > '7') - goto fail_mode; +static int handle_line(fstree_t *fs, const char *filename, + size_t line_num, char *line) +{ + const char *extra = NULL, *msg = NULL; + const struct callback_t *cb = NULL; + sqfs_u32 uid, gid, mode; + struct stat sb; + char *path; - sb.st_mode = (sb.st_mode << 3) | (line[i] - '0'); + for (size_t i = 0; i < NUM_HOOKS; ++i) { + size_t len = strlen(file_list_hooks[i].keyword); + if (strncmp(file_list_hooks[i].keyword, line, len) != 0) + continue; - if (sb.st_mode > 07777) - goto fail_mode_bits; + if (isspace(line[len])) { + cb = file_list_hooks + i; + line = skip_space(line + len); + break; + } } - if (!isspace(line[i])) - goto fail_ent; - - while (isspace(line[i])) - ++i; + if (cb == NULL) + goto fail_kw; - /* uid */ - if (!isdigit(line[i])) - goto fail_uid_gid; - - for (; isdigit(line[i]); ++i) { - x = line[i] - '0'; + if ((line = read_str(line, &path)) == NULL) + goto fail_ent; - if (sb.st_uid > (0xFFFFFFFF - x) / 10) - goto fail_ent; + if (canonicalize_name(path) || *path == '\0') + goto fail_ent; - sb.st_uid = sb.st_uid * 10 + x; - } + if ((line = read_u32(line, &mode, 8)) == NULL || mode > 07777) + goto fail_mode; - if (!isspace(line[i])) + if ((line = skip_space(line)) == NULL) goto fail_ent; - while (isspace(line[i])) - ++i; - - /* gid */ - if (!isdigit(line[i])) + if ((line = read_u32(line, &uid, 10)) == NULL) goto fail_uid_gid; - for (; isdigit(line[i]); ++i) { - x = line[i] - '0'; - - if (sb.st_gid > (0xFFFFFFFF - x) / 10) - goto fail_ent; + if ((line = skip_space(line)) == NULL) + goto fail_ent; - sb.st_gid = sb.st_gid * 10 + x; - } + if ((line = read_u32(line, &gid, 10)) == NULL) + goto fail_uid_gid; - /* extra */ - if (isspace(line[i])) { - while (isspace(line[i])) - ++i; + if ((line = skip_space(line)) != NULL && *line != '\0') + extra = line; - if (line[i] != '\0') - extra = line + i; - } + if (cb->need_extra && extra == NULL) + goto fail_no_extra; /* forward to callback */ - for (i = 0; i < NUM_HOOKS; ++i) { - if (strcmp(file_list_hooks[i].keyword, keyword) == 0) { - if (file_list_hooks[i].need_extra && extra == NULL) - goto fail_no_extra; - - sb.st_mode |= file_list_hooks[i].mode; - - return file_list_hooks[i].callback(fs, filename, - line_num, path, - &sb, extra); - } - } + memset(&sb, 0, sizeof(sb)); + sb.st_mtime = fs->defaults.st_mtime; + sb.st_mode = mode | cb->mode; + sb.st_uid = uid; + sb.st_gid = gid; - fprintf(stderr, "%s: " PRI_SZ ": unknown entry type '%s'.\n", filename, - line_num, keyword); - return -1; + return cb->callback(fs, filename, line_num, path, &sb, extra); fail_no_extra: fprintf(stderr, "%s: " PRI_SZ ": missing argument for %s.\n", - filename, line_num, keyword); + filename, line_num, cb->keyword); return -1; fail_uid_gid: - msg = "uid & gid must be decimal numbers"; + msg = "uid & gid must be decimal numbers < 2^32"; goto out_desc; fail_mode: - msg = "mode must be an octal number"; + msg = "mode must be an octal number <= 07777"; goto out_desc; -fail_mode_bits: - msg = "you can only set the permission bits in the mode"; +fail_kw: + msg = "unknown entry type"; goto out_desc; fail_ent: msg = "error in entry description"; -- cgit v1.2.3