aboutsummaryrefslogtreecommitdiff
path: root/lib/fstree/fstree_from_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fstree/fstree_from_file.c')
-rw-r--r--lib/fstree/fstree_from_file.c591
1 files changed, 0 insertions, 591 deletions
diff --git a/lib/fstree/fstree_from_file.c b/lib/fstree/fstree_from_file.c
deleted file mode 100644
index 411c64f..0000000
--- a/lib/fstree/fstree_from_file.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * fstree_from_file.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include "util/util.h"
-#include "io/file.h"
-#include "fstree.h"
-#include "compat.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <ctype.h>
-
-struct glob_context {
- const char *filename;
- size_t line_num;
-
- struct stat *basic;
- unsigned int glob_flags;
-
- char *name_pattern;
-};
-
-enum {
- GLOB_MODE_FROM_SRC = 0x01,
- GLOB_UID_FROM_SRC = 0x02,
- GLOB_GID_FROM_SRC = 0x04,
- GLOB_FLAG_PATH = 0x08,
-};
-
-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 int add_generic(fstree_t *fs, const char *filename, size_t line_num,
- const char *path, struct stat *sb,
- const char *basepath, unsigned int glob_flags,
- const char *extra)
-{
- (void)basepath;
- (void)glob_flags;
-
- if (fstree_add_generic(fs, path, sb, extra) == NULL) {
- fprintf(stderr, "%s: " PRI_SZ ": %s: %s\n",
- filename, line_num, path, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static int add_device(fstree_t *fs, const char *filename, size_t line_num,
- const char *path, struct stat *sb, const char *basepath,
- unsigned int glob_flags, const char *extra)
-{
- unsigned int maj, min;
- char c;
-
- if (sscanf(extra, "%c %u %u", &c, &maj, &min) != 3) {
- fprintf(stderr, "%s: " PRI_SZ ": "
- "expected '<c|b> major minor'\n",
- filename, line_num);
- return -1;
- }
-
- if (c == 'c' || c == 'C') {
- sb->st_mode |= S_IFCHR;
- } else if (c == 'b' || c == 'B') {
- sb->st_mode |= S_IFBLK;
- } else {
- fprintf(stderr, "%s: " PRI_SZ ": unknown device type '%c'\n",
- filename, line_num, c);
- return -1;
- }
-
- sb->st_rdev = makedev(maj, min);
- return add_generic(fs, filename, line_num, path, sb, basepath,
- glob_flags, NULL);
-}
-
-static int add_file(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)
-{
- if (extra == NULL || *extra == '\0')
- extra = path;
-
- return add_generic(fs, filename, line_num, path, basic,
- basepath, glob_flags, extra);
-}
-
-static int add_hard_link(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)
-{
- (void)basepath;
- (void)glob_flags;
- (void)basic;
-
- if (fstree_add_hard_link(fs, path, extra) == NULL) {
- fprintf(stderr, "%s: " PRI_SZ ": %s\n",
- filename, line_num, strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static int glob_node_callback(void *user, fstree_t *fs, tree_node_t *node)
-{
- struct glob_context *ctx = user;
- char *path;
- int ret;
- (void)fs;
-
- if (!(ctx->glob_flags & GLOB_MODE_FROM_SRC)) {
- node->mode &= ~(07777);
- node->mode |= ctx->basic->st_mode & 07777;
- }
-
- if (!(ctx->glob_flags & GLOB_UID_FROM_SRC))
- node->uid = ctx->basic->st_uid;
-
- if (!(ctx->glob_flags & GLOB_GID_FROM_SRC))
- node->gid = ctx->basic->st_gid;
-
- if (ctx->name_pattern != NULL) {
- if (ctx->glob_flags & GLOB_FLAG_PATH) {
- path = fstree_get_path(node);
- if (path == NULL) {
- fprintf(stderr, "%s: " PRI_SZ ": %s\n",
- ctx->filename, ctx->line_num,
- strerror(errno));
- return -1;
- }
-
- ret = canonicalize_name(path);
- assert(ret == 0);
-
- ret = fnmatch(ctx->name_pattern, path, FNM_PATHNAME);
- free(path);
- } else {
- ret = fnmatch(ctx->name_pattern, node->name, 0);
- }
-
- if (ret != 0)
- return 1;
- }
-
- return 0;
-}
-
-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';
-}
-
-static 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)
-{
- unsigned int scan_flags = 0, all_flags;
- struct glob_context ctx;
- bool first_clear_flag;
- size_t i, count, len;
- tree_node_t *root;
- int ret;
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.filename = filename;
- ctx.line_num = line_num;
- ctx.basic = basic;
- ctx.glob_flags = glob_flags;
-
- /* 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;
- }
-
- /* 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(ctx.name_pattern);
- ctx.name_pattern = strndup(extra, len);
- extra += len;
-
- while (isspace(*extra))
- ++extra;
-
- quote_remove(ctx.name_pattern);
- continue;
- }
-
- if (strncmp(extra, "-path", 5) == 0 && isspace(extra[5])) {
- for (extra += 5; isspace(*extra); ++extra)
- ;
-
- len = name_string_length(extra);
-
- free(ctx.name_pattern);
- ctx.name_pattern = strndup(extra, len);
- extra += len;
-
- while (isspace(*extra))
- ++extra;
-
- quote_remove(ctx.name_pattern);
- ctx.glob_flags |= GLOB_FLAG_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(ctx.name_pattern);
- return -1;
- } else {
- break;
- }
- }
-
- if (extra != NULL && *extra == '\0')
- extra = NULL;
-
- /* do the scan */
- if (basepath == NULL) {
- if (extra == NULL) {
- ret = fstree_from_dir(fs, root, ".", glob_node_callback,
- &ctx, scan_flags);
- } else {
- ret = fstree_from_dir(fs, root, extra,
- glob_node_callback,
- &ctx, scan_flags);
- }
- } else {
- ret = fstree_from_subdir(fs, root, basepath, extra,
- glob_node_callback, &ctx,
- scan_flags);
- }
-
- free(ctx.name_pattern);
- return ret;
-}
-
-static const struct callback_t {
- const char *keyword;
- unsigned int mode;
- bool need_extra;
- bool is_glob;
- bool allow_root;
- int (*callback)(fstree_t *fs, const char *filename, size_t line_num,
- const char *path, struct stat *sb,
- const char *basepath, unsigned int glob_flags,
- const char *extra);
-} file_list_hooks[] = {
- { "dir", S_IFDIR, false, false, true, add_generic },
- { "slink", S_IFLNK, true, false, false, add_generic },
- { "link", 0, true, false, false, add_hard_link },
- { "nod", 0, true, false, false, add_device },
- { "pipe", S_IFIFO, false, false, false, add_generic },
- { "sock", S_IFSOCK, false, false, false, add_generic },
- { "file", S_IFREG, false, false, false, add_file },
- { "glob", 0, false, true, true, glob_files },
-};
-
-#define NUM_HOOKS (sizeof(file_list_hooks) / sizeof(file_list_hooks[0]))
-
-static char *skip_space(char *str)
-{
- if (!isspace(*str))
- return NULL;
- while (isspace(*str))
- ++str;
- return str;
-}
-
-static char *read_u32(char *str, sqfs_u32 *out, sqfs_u32 base)
-{
- *out = 0;
-
- if (!isdigit(*str))
- return NULL;
-
- while (isdigit(*str)) {
- sqfs_u32 x = *(str++) - '0';
-
- if (x >= base || (*out) > (0xFFFFFFFF - x) / base)
- return NULL;
-
- (*out) = (*out) * base + x;
- }
-
- return str;
-}
-
-static char *read_str(char *str, char **out)
-{
- *out = str;
-
- if (*str == '"') {
- char *ptr = str++;
-
- while (*str != '\0' && *str != '"') {
- if (str[0] == '\\' &&
- (str[1] == '"' || str[1] == '\\')) {
- *(ptr++) = str[1];
- str += 2;
- } else {
- *(ptr++) = *(str++);
- }
- }
-
- if (str[0] != '"' || !isspace(str[1]))
- return NULL;
-
- *ptr = '\0';
- ++str;
- } else {
- while (*str != '\0' && !isspace(*str))
- ++str;
-
- if (!isspace(*str))
- return NULL;
-
- *(str++) = '\0';
- }
-
- while (isspace(*str))
- ++str;
-
- return str;
-}
-
-static int handle_line(fstree_t *fs, const char *filename,
- size_t line_num, char *line,
- const char *basepath)
-{
- const char *extra = NULL, *msg = NULL;
- const struct callback_t *cb = NULL;
- unsigned int glob_flags = 0;
- sqfs_u32 uid, gid, mode;
- struct stat sb;
- char *path;
-
- 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 (isspace(line[len])) {
- cb = file_list_hooks + i;
- line = skip_space(line + len);
- break;
- }
- }
-
- if (cb == NULL)
- goto fail_kw;
-
- if ((line = read_str(line, &path)) == NULL)
- goto fail_ent;
-
- if (canonicalize_name(path))
- goto fail_ent;
-
- if (*path == '\0' && !cb->allow_root)
- goto fail_root;
-
- if (cb->is_glob && *line == '*') {
- ++line;
- mode = 0;
- glob_flags |= GLOB_MODE_FROM_SRC;
- } else {
- if ((line = read_u32(line, &mode, 8)) == NULL || mode > 07777)
- goto fail_mode;
- }
-
- if ((line = skip_space(line)) == NULL)
- goto fail_ent;
-
- if (cb->is_glob && *line == '*') {
- ++line;
- uid = 0;
- glob_flags |= GLOB_UID_FROM_SRC;
- } else {
- if ((line = read_u32(line, &uid, 10)) == NULL)
- goto fail_uid_gid;
- }
-
- if ((line = skip_space(line)) == NULL)
- goto fail_ent;
-
- if (cb->is_glob && *line == '*') {
- ++line;
- gid = 0;
- glob_flags |= GLOB_GID_FROM_SRC;
- } else {
- if ((line = read_u32(line, &gid, 10)) == NULL)
- goto fail_uid_gid;
- }
-
- if ((line = skip_space(line)) != NULL && *line != '\0')
- extra = line;
-
- if (cb->need_extra && extra == NULL)
- goto fail_no_extra;
-
- /* forward to callback */
- 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;
-
- return cb->callback(fs, filename, line_num, path,
- &sb, basepath, glob_flags, extra);
-fail_root:
- fprintf(stderr, "%s: " PRI_SZ ": cannot use / as argument for %s.\n",
- filename, line_num, cb->keyword);
- return -1;
-fail_no_extra:
- fprintf(stderr, "%s: " PRI_SZ ": missing argument for %s.\n",
- filename, line_num, cb->keyword);
- return -1;
-fail_uid_gid:
- msg = "uid & gid must be decimal numbers < 2^32";
- goto out_desc;
-fail_mode:
- msg = "mode must be an octal number <= 07777";
- goto out_desc;
-fail_kw:
- msg = "unknown entry type";
- goto out_desc;
-fail_ent:
- msg = "error in entry description";
- goto out_desc;
-out_desc:
- fprintf(stderr, "%s: " PRI_SZ ": %s.\n", filename, line_num, msg);
- fputs("expected: <type> <path> <mode> <uid> <gid> [<extra>]\n",
- stderr);
- return -1;
-}
-
-int fstree_from_file_stream(fstree_t *fs, istream_t *fp, const char *basepath)
-{
- const char *filename;
- size_t line_num = 1;
- char *line;
- int ret;
-
- filename = istream_get_filename(fp);
-
- for (;;) {
- ret = istream_get_line(fp, &line, &line_num,
- ISTREAM_LINE_LTRIM | ISTREAM_LINE_SKIP_EMPTY);
- if (ret < 0)
- return -1;
- if (ret > 0)
- break;
-
- if (line[0] != '#') {
- if (handle_line(fs, filename, line_num,
- line, basepath)) {
- goto fail_line;
- }
- }
-
- free(line);
- ++line_num;
- }
-
- return 0;
-fail_line:
- free(line);
- return -1;
-}
-
-int fstree_from_file(fstree_t *fs, const char *filename, const char *basepath)
-{
- istream_t *fp;
- int ret;
-
- fp = istream_open_file(filename);
- if (fp == NULL)
- return -1;
-
- ret = fstree_from_file_stream(fs, fp, basepath);
-
- sqfs_destroy(fp);
- return ret;
-}