xref: /aosp_15_r20/external/erofs-utils/lib/exclude.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
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 = &regex_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 = &regex_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, &regex_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