[PATCH v7] erofs-utils: introduce exclude dirs and files

Gao Xiang gaoxiang25 at huawei.com
Wed Feb 19 13:20:56 AEDT 2020


Hi Guifu,

On Tue, Feb 18, 2020 at 10:30:47PM +0800, Li Guifu wrote:
> From: Li GuiFu <bluce.lee at aliyun.com>
> 
> Add excluded file feature "--exclude-path=" and '--exclude-regex=',
> which can be used to build EROFS image without some user specific
> files or dirs. Note that you may give multiple '--exclude-path'
> or '--exclude-regex' options.
> 
> Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
> Signed-off-by: Li Guifu <bluce.lee at aliyun.com>

Applied to experimental branch with the following minor updates.

If you have more suggestions, please kindly point out. Or I will
push it out to dev branch later.

Thanks,
Gao Xiang


>From 8cdf49bc529d05e741d540b4e5018e2b4215c90a Mon Sep 17 00:00:00 2001
From: Li Guifu <bluce.lee at aliyun.com>
Date: Tue, 18 Feb 2020 22:30:47 +0800
Subject: [PATCH v8] erofs-utils: introduce exclude dirs and files

Add excluded file feature "--exclude-path=" and '--exclude-regex=',
which can be used to build EROFS image without some user specific
files or dirs.

The implementation is kept as simple as possible for now.

Note that you may give multiple '--exclude-path' and '--exclude-regex'
options.

Signed-off-by: Li Guifu <bluce.lee at aliyun.com>
Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
---
 include/erofs/exclude.h |  26 ++++++++
 lib/Makefile.am         |   2 +-
 lib/exclude.c           | 142 ++++++++++++++++++++++++++++++++++++++++
 lib/inode.c             |   5 ++
 man/mkfs.erofs.1        |   8 +++
 mkfs/main.c             |  36 ++++++++--
 6 files changed, 211 insertions(+), 8 deletions(-)
 create mode 100644 include/erofs/exclude.h
 create mode 100644 lib/exclude.c

diff --git a/include/erofs/exclude.h b/include/erofs/exclude.h
new file mode 100644
index 000000000000..6435538e35cf
--- /dev/null
+++ b/include/erofs/exclude.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/include/erofs/exclude.h
+ *
+ * Created by Li Guifu <bluce.lee at aliyun.com>
+ */
+#ifndef __EROFS_EXCLUDE_H
+#define __EROFS_EXCLUDE_H
+#include <sys/types.h>
+#include <regex.h>
+
+struct erofs_exclude_rule {
+	struct list_head list;
+
+	char *pattern;
+	regex_t reg;
+};
+
+void erofs_exclude_set_root(const char *rootdir);
+void erofs_cleanup_exclude_rules(void);
+
+int erofs_parse_exclude_path(const char *args, bool is_regex);
+struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
+						 const char *name);
+#endif
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1ff81f9eebfe..e4b51e65f053 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,7 +3,7 @@
 
 noinst_LTLIBRARIES = liberofs.la
 liberofs_la_SOURCES = config.c io.c cache.c inode.c xattr.c \
-		      compress.c compressor.c
+		      compress.c compressor.c exclude.c
 liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
 if ENABLE_LZ4
 liberofs_la_CFLAGS += ${LZ4_CFLAGS}
diff --git a/lib/exclude.c b/lib/exclude.c
new file mode 100644
index 000000000000..47b467dcbb1b
--- /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 at 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 = &regex_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 = &regex_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, &regex_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;
+}
+
diff --git a/lib/inode.c b/lib/inode.c
index bd0652b1daed..711402346d72 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -20,6 +20,7 @@
 #include "erofs/io.h"
 #include "erofs/compress.h"
 #include "erofs/xattr.h"
+#include "erofs/exclude.h"
 
 struct erofs_sb_info sbi;
 
@@ -877,6 +878,10 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 		    !strncmp(dp->d_name, "lost+found", strlen("lost+found")))
 			continue;
 
+		/* skip if it's a exclude file */
+		if (erofs_is_exclude_path(dir->i_srcpath, dp->d_name))
+			continue;
+
 		d = erofs_d_alloc(dir, dp->d_name);
 		if (IS_ERR(d)) {
 			ret = PTR_ERR(d);
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d6bf82838e0e..d47207adf379 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -52,6 +52,14 @@ Forcely generate extended inodes (64-byte inodes) to output.
 Set all files to the given UNIX timestamp. Reproducible builds requires setting
 all to a specific one.
 .TP
+.BI "\-\-exclude-path=" path
+Ignore file that matches the exact literal path.
+You may give multiple `--exclude-path' options.
+.TP
+.BI "\-\-exclude-regex=" regex
+Ignore files that match the given regular expression.
+You may give multiple `--exclude-regex` options.
+.TP
 .B \-\-help
 Display this help and exit.
 .SH AUTHOR
diff --git a/mkfs/main.c b/mkfs/main.c
index 817a6c1ab967..940d4e8b845d 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -21,6 +21,7 @@
 #include "erofs/io.h"
 #include "erofs/compress.h"
 #include "erofs/xattr.h"
+#include "erofs/exclude.h"
 
 #ifdef HAVE_LIBUUID
 #include <uuid/uuid.h>
@@ -30,6 +31,8 @@
 
 static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
+	{"exclude-path", required_argument, NULL, 2},
+	{"exclude-regex", required_argument, NULL, 3},
 	{0, 0, 0, 0},
 };
 
@@ -50,12 +53,14 @@ static void usage(void)
 {
 	fputs("usage: [options] FILE DIRECTORY\n\n"
 	      "Generate erofs image from DIRECTORY to FILE, and [options] are:\n"
-	      " -zX[,Y]   X=compressor (Y=compression level, optional)\n"
-	      " -d#       set output message level to # (maximum 9)\n"
-	      " -x#       set xattr tolerance to # (< 0, disable xattrs; default 2)\n"
-	      " -EX[,...] X=extended options\n"
-	      " -T#       set a fixed UNIX timestamp # to all files\n"
-	      " --help    display this help and exit\n"
+	      " -zX[,Y]           X=compressor (Y=compression level, optional)\n"
+	      " -d#               set output message level to # (maximum 9)\n"
+	      " -x#               set xattr tolerance to # (< 0, disable xattrs; default 2)\n"
+	      " -EX[,...]         X=extended options\n"
+	      " -T#               set a fixed UNIX timestamp # to all files\n"
+	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
+	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
+	      " --help            display this help and exit\n"
 	      "\nAvailable compressors are: ", stderr);
 	print_available_compressors(stderr, ", ");
 }
@@ -177,7 +182,22 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				return -EINVAL;
 			}
 			break;
-
+		case 2:
+			opt = erofs_parse_exclude_path(optarg, false);
+			if (opt) {
+				erofs_err("failed to parse exclude path: %s",
+					  erofs_strerror(opt));
+				return opt;
+			}
+			break;
+		case 3:
+			opt = erofs_parse_exclude_path(optarg, true);
+			if (opt) {
+				erofs_err("failed to parse exclude regex: %s",
+					  erofs_strerror(opt));
+				return opt;
+			}
+			break;
 		case 1:
 			usage();
 			exit(0);
@@ -372,6 +392,7 @@ int main(int argc, char **argv)
 	}
 
 	erofs_show_config();
+	erofs_exclude_set_root(cfg.c_src_path);
 
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
@@ -428,6 +449,7 @@ int main(int argc, char **argv)
 exit:
 	z_erofs_compress_exit();
 	dev_close();
+	erofs_cleanup_exclude_rules();
 	erofs_exit_configure();
 
 	if (err) {
-- 
2.17.1



More information about the Linux-erofs mailing list