diff options
Diffstat (limited to 'lib/exclude.c')
-rw-r--r-- | lib/exclude.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/lib/exclude.c b/lib/exclude.c new file mode 100644 index 0000000..47b467d --- /dev/null +++ b/lib/exclude.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * erofs-utils/lib/exclude.c + * + * Created by Li Guifu <bluce.lee@aliyun.com> + */ +#include <string.h> +#include <stdlib.h> +#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 unsigned int rpathlen; /* root directory prefix length */ + +void erofs_exclude_set_root(const char *rootdir) +{ + rpathlen = strlen(rootdir); +} + +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 += rpathlen; + while (*s == '/') + 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; +} + |