1 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2 /*
3 * Created by Li Guifu <[email protected]>
4 */
5 #include <string.h>
6 #include <stdlib.h>
7 #include "erofs/err.h"
8 #include "erofs/list.h"
9 #include "erofs/print.h"
10 #include "erofs/exclude.h"
11
12 #define EXCLUDE_RULE_EXACT_SIZE offsetof(struct erofs_exclude_rule, reg)
13 #define EXCLUDE_RULE_REGEX_SIZE sizeof(struct erofs_exclude_rule)
14
15 static LIST_HEAD(exclude_head);
16 static LIST_HEAD(regex_exclude_head);
17
dump_regerror(int errcode,const char * s,const regex_t * preg)18 static void dump_regerror(int errcode, const char *s, const regex_t *preg)
19 {
20 char str[512];
21
22 regerror(errcode, preg, str, sizeof(str));
23 erofs_err("invalid regex %s (%s)\n", s, str);
24 }
25
erofs_insert_exclude(const char * s,bool is_regex)26 static struct erofs_exclude_rule *erofs_insert_exclude(const char *s,
27 bool is_regex)
28 {
29 struct erofs_exclude_rule *r;
30 int ret;
31 struct list_head *h;
32
33 r = malloc(is_regex ? EXCLUDE_RULE_REGEX_SIZE :
34 EXCLUDE_RULE_EXACT_SIZE);
35 if (!r)
36 return ERR_PTR(-ENOMEM);
37
38 r->pattern = strdup(s);
39 if (!r->pattern) {
40 ret = -ENOMEM;
41 goto err_rule;
42 }
43
44 if (is_regex) {
45 ret = regcomp(&r->reg, s, REG_EXTENDED|REG_NOSUB);
46 if (ret) {
47 dump_regerror(ret, s, &r->reg);
48 goto err_rule;
49 }
50 h = ®ex_exclude_head;
51 } else {
52 h = &exclude_head;
53 }
54
55 list_add_tail(&r->list, h);
56 erofs_info("insert exclude %s: %s\n",
57 is_regex ? "regex" : "path", s);
58 return r;
59
60 err_rule:
61 if (r->pattern)
62 free(r->pattern);
63 free(r);
64 return ERR_PTR(ret);
65 }
66
erofs_cleanup_exclude_rules(void)67 void erofs_cleanup_exclude_rules(void)
68 {
69 struct erofs_exclude_rule *r, *n;
70 struct list_head *h;
71
72 h = &exclude_head;
73 list_for_each_entry_safe(r, n, h, list) {
74 list_del(&r->list);
75 free(r->pattern);
76 free(r);
77 }
78
79 h = ®ex_exclude_head;
80 list_for_each_entry_safe(r, n, h, list) {
81 list_del(&r->list);
82 free(r->pattern);
83 regfree(&r->reg);
84 free(r);
85 }
86 }
87
erofs_parse_exclude_path(const char * args,bool is_regex)88 int erofs_parse_exclude_path(const char *args, bool is_regex)
89 {
90 struct erofs_exclude_rule *r = erofs_insert_exclude(args, is_regex);
91
92 if (IS_ERR(r)) {
93 erofs_cleanup_exclude_rules();
94 return PTR_ERR(r);
95 }
96 return 0;
97 }
98
erofs_is_exclude_path(const char * dir,const char * name)99 struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
100 const char *name)
101 {
102 char buf[PATH_MAX];
103 const char *s;
104 struct erofs_exclude_rule *r;
105
106 if (!dir) {
107 /* no prefix */
108 s = name;
109 } else {
110 sprintf(buf, "%s/%s", dir, name);
111 s = buf;
112 }
113
114 s = erofs_fspath(s);
115 list_for_each_entry(r, &exclude_head, list) {
116 if (!strcmp(r->pattern, s))
117 return r;
118 }
119
120 list_for_each_entry(r, ®ex_exclude_head, list) {
121 int ret = regexec(&r->reg, s, (size_t)0, NULL, 0);
122
123 if (!ret)
124 return r;
125 if (ret != REG_NOMATCH)
126 dump_regerror(ret, s, &r->reg);
127 }
128 return NULL;
129 }
130