diff options
Diffstat (limited to 'bin/gensquashfs/src/glob.c')
-rw-r--r-- | bin/gensquashfs/src/glob.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/bin/gensquashfs/src/glob.c b/bin/gensquashfs/src/glob.c new file mode 100644 index 0000000..c95d06d --- /dev/null +++ b/bin/gensquashfs/src/glob.c @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * glob.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +static const struct { + const char *name; + unsigned int clear_flag; + unsigned int set_flag; +} glob_scan_flags[] = { + { "-type b", DIR_SCAN_NO_BLK, 0 }, + { "-type c", DIR_SCAN_NO_CHR, 0 }, + { "-type d", DIR_SCAN_NO_DIR, 0 }, + { "-type p", DIR_SCAN_NO_FIFO, 0 }, + { "-type f", DIR_SCAN_NO_FILE, 0 }, + { "-type l", DIR_SCAN_NO_SLINK, 0 }, + { "-type s", DIR_SCAN_NO_SOCK, 0 }, + { "-xdev", 0, DIR_SCAN_ONE_FILESYSTEM }, + { "-mount", 0, DIR_SCAN_ONE_FILESYSTEM }, + { "-keeptime", 0, DIR_SCAN_KEEP_TIME }, + { "-nonrecursive", 0, DIR_SCAN_NO_RECURSION }, +}; + +static size_t name_string_length(const char *str) +{ + size_t len = 0; + int start; + + if (*str == '"' || *str == '\'') { + start = *str; + ++len; + + while (str[len] != '\0' && str[len] != start) + ++len; + + if (str[len] == start) + ++len; + } else { + while (str[len] != '\0' && !isspace(str[len])) + ++len; + } + + return len; +} + +static void quote_remove(char *str) +{ + char *dst = str; + int start = *(str++); + + if (start != '\'' && start != '"') + return; + + while (*str != start && *str != '\0') + *(dst++) = *(str++); + + *(dst++) = '\0'; +} + +int glob_files(fstree_t *fs, const char *filename, size_t line_num, + const char *path, struct stat *basic, + const char *basepath, unsigned int glob_flags, + const char *extra) +{ + char *name_pattern = NULL, *prefix = NULL; + unsigned int scan_flags = 0, all_flags; + dir_iterator_t *dir = NULL; + bool first_clear_flag; + size_t i, count, len; + dir_tree_cfg_t cfg; + tree_node_t *root; + int ret; + + /* fetch the actual target node */ + root = fstree_get_node_by_path(fs, fs->root, path, true, false); + if (root == NULL) { + fprintf(stderr, "%s: " PRI_SZ ": %s: %s\n", + filename, line_num, path, strerror(errno)); + return -1; + } + + if (!S_ISDIR(root->mode)) { + fprintf(stderr, "%s: " PRI_SZ ": %s is not a directoy!\n", + filename, line_num, path); + return -1; + } + + prefix = fstree_get_path(root); + if (canonicalize_name(prefix) != 0) { + fprintf(stderr, "%s: " PRI_SZ ": error cannonicalizing `%s`!\n", + filename, line_num, prefix); + free(prefix); + return -1; + } + + /* process options */ + first_clear_flag = true; + + all_flags = DIR_SCAN_NO_BLK | DIR_SCAN_NO_CHR | DIR_SCAN_NO_DIR | + DIR_SCAN_NO_FIFO | DIR_SCAN_NO_FILE | DIR_SCAN_NO_SLINK | + DIR_SCAN_NO_SOCK; + + while (extra != NULL && *extra != '\0') { + count = sizeof(glob_scan_flags) / sizeof(glob_scan_flags[0]); + + for (i = 0; i < count; ++i) { + len = strlen(glob_scan_flags[i].name); + if (strncmp(extra, glob_scan_flags[i].name, len) != 0) + continue; + + if (isspace(extra[len])) { + extra += len; + while (isspace(*extra)) + ++extra; + break; + } + } + + if (i < count) { + if (glob_scan_flags[i].clear_flag != 0 && + first_clear_flag) { + scan_flags |= all_flags; + first_clear_flag = false; + } + + scan_flags &= ~(glob_scan_flags[i].clear_flag); + scan_flags |= glob_scan_flags[i].set_flag; + continue; + } + + if (strncmp(extra, "-name", 5) == 0 && isspace(extra[5])) { + for (extra += 5; isspace(*extra); ++extra) + ; + + len = name_string_length(extra); + + free(name_pattern); + name_pattern = strndup(extra, len); + extra += len; + + while (isspace(*extra)) + ++extra; + + quote_remove(name_pattern); + continue; + } + + if (strncmp(extra, "-path", 5) == 0 && isspace(extra[5])) { + for (extra += 5; isspace(*extra); ++extra) + ; + + len = name_string_length(extra); + + free(name_pattern); + name_pattern = strndup(extra, len); + extra += len; + + while (isspace(*extra)) + ++extra; + + quote_remove(name_pattern); + glob_flags |= DIR_SCAN_MATCH_FULL_PATH; + continue; + } + + if (extra[0] == '-') { + if (extra[1] == '-' && isspace(extra[2])) { + extra += 2; + while (isspace(*extra)) + ++extra; + break; + } + + fprintf(stderr, "%s: " PRI_SZ ": unknown option.\n", + filename, line_num); + free(name_pattern); + free(prefix); + return -1; + } else { + break; + } + } + + if (extra != NULL && *extra == '\0') + extra = NULL; + + /* do the scan */ + memset(&cfg, 0, sizeof(cfg)); + cfg.flags = scan_flags | glob_flags; + cfg.def_mtime = basic->st_mtime; + cfg.def_uid = basic->st_uid; + cfg.def_gid = basic->st_gid; + cfg.def_mode = basic->st_mode; + cfg.prefix = prefix; + cfg.name_pattern = name_pattern; + + if (basepath == NULL) { + dir = dir_tree_iterator_create(extra == NULL ? "." : extra, + &cfg); + } else { + size_t plen = strlen(basepath); + size_t slen = strlen(extra); + char *temp = calloc(1, plen + 1 + slen + 1); + + if (temp == NULL) { + fprintf(stderr, "%s: " PRI_SZ ": allocation failure.\n", + filename, line_num); + } else { + memcpy(temp, basepath, plen); + temp[plen] = '/'; + memcpy(temp + plen + 1, extra, slen); + temp[plen + 1 + slen] = '\0'; + + dir = dir_tree_iterator_create(temp, &cfg); + } + + free(temp); + } + + if (dir != NULL) { + ret = fstree_from_dir(fs, dir); + sqfs_drop(dir); + } else { + ret = -1; + } + + free(name_pattern); + free(prefix); + return ret; +} |