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