// SPDX-License-Identifier: GPL-2.0+ /* * erofs-utils/lib/exclude.c * * Created by Li Guifu */ #include #include #include "erofs/err.h" #include "erofs/list.h" #include "erofs/print.h" #include "erofs/exclude.h" #define EXCLUDE_RULE_EXACT_SIZE offsetof(struct erofs_exclude_rule, reg) #define EXCLUDE_RULE_REGEX_SIZE sizeof(struct erofs_exclude_rule) static LIST_HEAD(exclude_head); static LIST_HEAD(regex_exclude_head); static void dump_regerror(int errcode, const char *s, const regex_t *preg) { char str[512]; regerror(errcode, preg, str, sizeof(str)); erofs_err("invalid regex %s (%s)\n", s, str); } static struct erofs_exclude_rule *erofs_insert_exclude(const char *s, bool is_regex) { struct erofs_exclude_rule *r; int ret; struct list_head *h; r = malloc(is_regex ? EXCLUDE_RULE_REGEX_SIZE : EXCLUDE_RULE_EXACT_SIZE); if (!r) return ERR_PTR(-ENOMEM); r->pattern = strdup(s); if (!r->pattern) { ret = -ENOMEM; goto err_rule; } if (is_regex) { ret = regcomp(&r->reg, s, REG_EXTENDED|REG_NOSUB); if (ret) { dump_regerror(ret, s, &r->reg); goto err_rule; } h = ®ex_exclude_head; } else { h = &exclude_head; } list_add_tail(&r->list, h); erofs_info("insert exclude %s: %s\n", is_regex ? "regex" : "path", s); return r; err_rule: if (r->pattern) free(r->pattern); free(r); return ERR_PTR(ret); } void erofs_cleanup_exclude_rules(void) { struct erofs_exclude_rule *r, *n; struct list_head *h; h = &exclude_head; list_for_each_entry_safe(r, n, h, list) { list_del(&r->list); free(r->pattern); free(r); } h = ®ex_exclude_head; list_for_each_entry_safe(r, n, h, list) { list_del(&r->list); free(r->pattern); regfree(&r->reg); free(r); } } int erofs_parse_exclude_path(const char *args, bool is_regex) { struct erofs_exclude_rule *r = erofs_insert_exclude(args, is_regex); if (IS_ERR(r)) { erofs_cleanup_exclude_rules(); return PTR_ERR(r); } return 0; } struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir, const char *name) { char buf[PATH_MAX]; const char *s; struct erofs_exclude_rule *r; if (!dir) { /* no prefix */ s = name; } else { sprintf(buf, "%s/%s", dir, name); s = buf; } s = erofs_fspath(s); list_for_each_entry(r, &exclude_head, list) { if (!strcmp(r->pattern, s)) return r; } list_for_each_entry(r, ®ex_exclude_head, list) { int ret = regexec(&r->reg, s, (size_t)0, NULL, 0); if (!ret) return r; if (ret != REG_NOMATCH) dump_regerror(ret, s, &r->reg); } return NULL; }