diff options
Diffstat (limited to 'bin/gensquashfs')
| -rw-r--r-- | bin/gensquashfs/Makemodule.am | 1 | ||||
| -rw-r--r-- | bin/gensquashfs/dirscan_xattr.c | 54 | ||||
| -rw-r--r-- | bin/gensquashfs/filemap_xattr.c | 352 | ||||
| -rw-r--r-- | bin/gensquashfs/mkfs.c | 8 | ||||
| -rw-r--r-- | bin/gensquashfs/mkfs.h | 10 | ||||
| -rw-r--r-- | bin/gensquashfs/options.c | 8 | 
6 files changed, 413 insertions, 20 deletions
| diff --git a/bin/gensquashfs/Makemodule.am b/bin/gensquashfs/Makemodule.am index b0b8a79..e7fad8e 100644 --- a/bin/gensquashfs/Makemodule.am +++ b/bin/gensquashfs/Makemodule.am @@ -1,6 +1,7 @@  gensquashfs_SOURCES = bin/gensquashfs/mkfs.c bin/gensquashfs/mkfs.h  gensquashfs_SOURCES += bin/gensquashfs/options.c bin/gensquashfs/selinux.c  gensquashfs_SOURCES += bin/gensquashfs/dirscan_xattr.c +gensquashfs_SOURCES += bin/gensquashfs/filemap_xattr.c  gensquashfs_LDADD = libcommon.a libsquashfs.la libfstree.a libio.a  gensquashfs_LDADD += libutil.a libcompat.a $(LZO_LIBS) $(PTHREAD_LIBS)  gensquashfs_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/bin/gensquashfs/dirscan_xattr.c b/bin/gensquashfs/dirscan_xattr.c index 65f7f5c..7d4e552 100644 --- a/bin/gensquashfs/dirscan_xattr.c +++ b/bin/gensquashfs/dirscan_xattr.c @@ -122,10 +122,10 @@ fail:  #endif  static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, -			  sqfs_xattr_writer_t *xwr, bool scan_xattr, +			  sqfs_xattr_writer_t *xwr, bool scan_xattr, void *xattr_map,  			  tree_node_t *node)  { -	char *path; +	char *path = NULL;  	int ret;  	ret = sqfs_xattr_writer_begin(xwr, 0); @@ -143,32 +143,49 @@ static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle,  		ret = xattr_from_path(xwr, path);  		free(path); - -		if (ret) -			return -1; +		path = NULL; +		if (ret) { +			ret = -1; +			goto out; +		}  	}  #else  	(void)path_prefix;  #endif -	if (selinux_handle != NULL) { +	if (selinux_handle != NULL || xattr_map != NULL) {  		path = fstree_get_path(node); +  		if (path == NULL) {  			perror("reconstructing absolute path"); -			return -1; +			ret = -1; +			goto out; +		} +	} + +	if (xattr_map != NULL) { +		ret = xattr_apply_map_file(path, xattr_map, xwr); + +		if (ret) { +			ret = -1; +			goto out;  		} +	} +	if (selinux_handle != NULL) {  		ret = selinux_relable_node(selinux_handle, xwr, node, path); -		free(path); -		if (ret) -			return -1; +		if (ret) { +			ret = -1; +			goto out; +		}  	}  	if (sqfs_xattr_writer_end(xwr, &node->xattr_idx)) {  		sqfs_perror(node->name, "completing xattr key-value pairs",  			    ret); -		return -1; +		ret = -1; +		goto out;  	}  	if (S_ISDIR(node->mode)) { @@ -176,25 +193,28 @@ static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle,  		while (node != NULL) {  			if (xattr_xcan_dfs(path_prefix, selinux_handle, xwr, -					   scan_xattr, node)) { -				return -1; +					   scan_xattr, xattr_map, node)) { +				ret = -1; +				goto out;  			}  			node = node->next;  		}  	} -	return 0; +out: +	free(path); +	return ret;  }  int xattrs_from_dir(fstree_t *fs, const char *path, void *selinux_handle, -		    sqfs_xattr_writer_t *xwr, bool scan_xattr) +		    void *xattr_map, sqfs_xattr_writer_t *xwr, bool scan_xattr)  {  	if (xwr == NULL)  		return 0; -	if (selinux_handle == NULL && !scan_xattr) +	if (selinux_handle == NULL && !scan_xattr && xattr_map == NULL)  		return 0; -	return xattr_xcan_dfs(path, selinux_handle, xwr, scan_xattr, fs->root); +	return xattr_xcan_dfs(path, selinux_handle, xwr, scan_xattr, xattr_map, fs->root);  } diff --git a/bin/gensquashfs/filemap_xattr.c b/bin/gensquashfs/filemap_xattr.c new file mode 100644 index 0000000..f241617 --- /dev/null +++ b/bin/gensquashfs/filemap_xattr.c @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * filemap_xattr.c + * + * Copyright (C) 2022 Enno Boland <mail@eboland.de> + */ +#include "fstree.h" +#include "mkfs.h" +#include <stdio.h> + +#define NEW_FILE_START "# file: " + +struct XattrMapEntry { +	char *key; +	char *value; +	size_t value_len; +	struct XattrMapEntry *next; +}; + +struct XattrMapPattern { +	char *path; +	struct XattrMapEntry *entries; +	struct XattrMapPattern *next; +}; + +struct XattrMap { +	struct XattrMapPattern *patterns; +}; + +// Taken from attr-2.5.1/tools/setfattr.c +static int +hex_digit(char c) { +	if (c >= '0' && c <= '9') +		return c - '0'; +	else if (c >= 'A' && c <= 'F') +		return c - 'A' + 10; +	else if (c >= 'a' && c <= 'f') +		return c - 'a' + 10; +	else +		return -1; +} + +// Taken from attr-2.5.1/tools/setfattr.c +static int +base64_digit(char c) { +	if (c >= 'A' && c <= 'Z') +		return c - 'A'; +	else if (c >= 'a' && c <= 'z') +		return 26 + c - 'a'; +	else if (c >= '0' && c <= '9') +		return 52 + c - '0'; +	else if (c == '+') +		return 62; +	else if (c == '/') +		return 63; +	else if (c == '=') +		return -2; +	else +		return -1; +} + +// Taken from attr-2.5.1/tools/setfattr.c +static char * +decode(const char *value, size_t *size) { +	char *decoded = NULL; + +	if (*size == 0) +		return strdup(""); +	if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { +		const char *v = value + 2, *end = value + *size; +		char *d; + +		decoded = realloc(decoded, *size / 2); +		if (decoded == NULL) { +			return NULL; +		} +		d = decoded; +		while (v < end) { +			int d1, d0; + +			while (v < end && isspace(*v)) +				v++; +			if (v == end) +				break; +			d1 = hex_digit(*v++); +			while (v < end && isspace(*v)) +				v++; +			if (v == end) { +			bad_hex_encoding: +				fprintf(stderr, "bad input encoding\n"); +				free(decoded); +				return NULL; +			} +			d0 = hex_digit(*v++); +			if (d1 < 0 || d0 < 0) +				goto bad_hex_encoding; +			*d++ = ((d1 << 4) | d0); +		} +		*size = d - decoded; +	} else if (value[0] == '0' && (value[1] == 's' || value[1] == 'S')) { +		const char *v = value + 2, *end = value + *size; +		int d0, d1, d2, d3; +		char *d; + +		decoded = realloc(decoded, *size / 4 * 3); +		if (decoded == NULL) { +			return NULL; +		} +		d = decoded; +		for (;;) { +			while (v < end && isspace(*v)) +				v++; +			if (v == end) { +				d0 = d1 = d2 = d3 = -2; +				break; +			} +			if (v + 4 > end) { +			bad_base64_encoding: +				free(decoded); +				fprintf(stderr, "bad input encoding\n"); +				return NULL; +			} +			d0 = base64_digit(*v++); +			d1 = base64_digit(*v++); +			d2 = base64_digit(*v++); +			d3 = base64_digit(*v++); +			if (d0 < 0 || d1 < 0 || d2 < 0 || d3 < 0) +				break; + +			*d++ = (char)((d0 << 2) | (d1 >> 4)); +			*d++ = (char)((d1 << 4) | (d2 >> 2)); +			*d++ = (char)((d2 << 6) | d3); +		} +		if (d0 == -2) { +			if (d1 != -2 || d2 != -2 || d3 != -2) +				goto bad_base64_encoding; +			goto base64_end; +		} +		if (d0 == -1 || d1 < 0 || d2 == -1 || d3 == -1) +			goto bad_base64_encoding; +		*d++ = (char)((d0 << 2) | (d1 >> 4)); +		if (d2 != -2) +			*d++ = (char)((d1 << 4) | (d2 >> 2)); +		else { +			if (d1 & 0x0F || d3 != -2) +				goto bad_base64_encoding; +			goto base64_end; +		} +		if (d3 != -2) +			*d++ = (char)((d2 << 6) | d3); +		else if (d2 & 0x03) +			goto bad_base64_encoding; +	base64_end: +		while (v < end && isspace(*v)) +			v++; +		if (v + 4 <= end && *v == '=') { +			if (*++v != '=' || *++v != '=' || *++v != '=') +				goto bad_base64_encoding; +			v++; +		} +		while (v < end && isspace(*v)) +			v++; +		if (v < end) +			goto bad_base64_encoding; +		*size = d - decoded; +	} else { +		const char *v = value, *end = value + *size; +		char *d; + +		if (end > v + 1 && *v == '"' && *(end - 1) == '"') { +			v++; +			end--; +		} + +		decoded = realloc(decoded, *size); +		if (decoded == NULL) { +			return NULL; +		} +		d = decoded; + +		while (v < end) { +			if (v[0] == '\\') { +				if (v[1] == '\\' || v[1] == '"') { +					*d++ = *++v; +					v++; +				} else if (v[1] >= '0' && v[1] <= '7') { +					int c = 0; +					v++; +					c = (*v++ - '0'); +					if (*v >= '0' && *v <= '7') +						c = (c << 3) + (*v++ - '0'); +					if (*v >= '0' && *v <= '7') +						c = (c << 3) + (*v++ - '0'); +					*d++ = c; +				} else +					*d++ = *v++; +			} else +				*d++ = *v++; +		} +		*size = d - decoded; +	} +	return decoded; +} + +static int +parse_file_name(char *line, struct XattrMap *map) { +	char *p; +	struct XattrMapPattern *current_file; +	char *file_name = &line[strlen(NEW_FILE_START)]; + +	p = strchr(file_name, '\n'); +	if (p != NULL) { +		*p = '\0'; +	} +	file_name = strdup(file_name); +	if (file_name == NULL) { +		return -1; +	} +	current_file = calloc(1, sizeof(struct XattrMapPattern)); +	if (current_file == NULL) { +		free(file_name); +		return -1; +	} + +	current_file->next = map->patterns; +	map->patterns = current_file; +	canonicalize_name(file_name); +	current_file->path = file_name; + +	return 0; +} + +static int +parse_xattr(char *key_start, char *value_start, struct XattrMap *map) { +	char *p; +	size_t len; +	struct XattrMapPattern *current_pattern = map->patterns; +	struct XattrMapEntry *current_entry; + +	*value_start = '\0'; +	value_start += 1; +	p = strchr(value_start, '\n'); +	if (p != NULL) { +		*p = '\0'; +	} + +	current_entry = calloc(1, sizeof(struct XattrMapEntry)); +	if (current_entry == NULL) { +		return -1; +	} +	current_entry->next = current_pattern->entries; +	current_pattern->entries = current_entry; + +	current_entry->key = strdup(key_start); +	len = strlen(value_start); +	current_entry->value = decode(value_start, &len); +	current_entry->value_len = len; + +	return 0; +} + +void * +xattr_open_map_file(const char *path) { +	struct XattrMap *map; +	char *line = NULL; +	size_t line_size; +	char *p = NULL; +	FILE *file = fopen(path, "r"); +	if (file == NULL) { +		return NULL; +	} + +	map = calloc(1, sizeof(struct XattrMap)); +	if (map == NULL) { +		fclose(file); +		return NULL; +	} + +	while (getline(&line, &line_size, file) != -1) { +		if (strncmp(NEW_FILE_START, line, strlen(NEW_FILE_START)) == 0) { +			if (parse_file_name(line, map) < 0) { +				fclose(file); +				xattr_close_map_file(map); +				return NULL; +			} +		} else if ((p = strchr(line, '=')) && map->patterns) { +			if (parse_xattr(line, p, map) < 0) { +				fclose(file); +				xattr_close_map_file(map); +				return NULL; +			} +		} +	} + +	free(line); +	fclose(file); +	return map; +} + +void +xattr_close_map_file(void *xattr_map) { +	struct XattrMap *map = xattr_map; +	while (map->patterns != NULL) { +		struct XattrMapPattern *file = map->patterns; +		map->patterns = file->next; +		while (file->entries != NULL) { +			struct XattrMapEntry *entry = file->entries; +			file->entries = entry->next; +			free(entry->key); +			entry->key = NULL; +			free(entry->value); +			entry->value = NULL; +			free(entry); +		} +		free(file->path); +		file->path = NULL; +		free(file); +	} +	free(xattr_map); +} + +int +xattr_apply_map_file(char *path, void *map, sqfs_xattr_writer_t *xwr) { +	struct XattrMap *xattr_map = map; +	int ret = 0; +	const struct XattrMapPattern *pat; +	const struct XattrMapEntry *entry; + +	for (pat = xattr_map->patterns; pat != NULL; pat = pat->next) { +		char *patstr = pat->path; +		const char *stripped = path; + +		if (patstr[0] != '/' && stripped[0] == '/') { +			stripped++; +		} + +		if (strcmp(patstr, stripped) == 0) { +			printf("Applying xattrs for %s", path); +			for (entry = pat->entries; entry != NULL; entry = entry->next) { +				printf("  %s = \n", entry->key); +				fwrite(entry->value, entry->value_len, 1, stdout); +				puts("\n"); +				ret = sqfs_xattr_writer_add( +						xwr, entry->key, entry->value, entry->value_len); +				if (ret < 0) { +					return ret; +				} +			} +		} +	} +	return ret; +} diff --git a/bin/gensquashfs/mkfs.c b/bin/gensquashfs/mkfs.c index cb891f9..171a887 100644 --- a/bin/gensquashfs/mkfs.c +++ b/bin/gensquashfs/mkfs.c @@ -143,6 +143,7 @@ int main(int argc, char **argv)  	int status = EXIT_FAILURE;  	istream_t *sortfile = NULL;  	void *sehnd = NULL; +	void *xattrmap = NULL;  	sqfs_writer_t sqfs;  	options_t opt; @@ -156,6 +157,11 @@ int main(int argc, char **argv)  		if (sehnd == NULL)  			goto out;  	} +	if (opt.xattr_file != NULL) { +		xattrmap = xattr_open_map_file(opt.xattr_file); +		if (xattrmap == NULL) +			goto out; +	}  	if (opt.sortfile != NULL) {  		sortfile = istream_open_file(opt.sortfile); @@ -180,7 +186,7 @@ int main(int argc, char **argv)  		goto out;  	if (opt.infile == NULL) { -		if (xattrs_from_dir(&sqfs.fs, opt.packdir, sehnd, +		if (xattrs_from_dir(&sqfs.fs, opt.packdir, sehnd, xattrmap,  				    sqfs.xwr, opt.scan_xattr)) {  			goto out;  		} diff --git a/bin/gensquashfs/mkfs.h b/bin/gensquashfs/mkfs.h index 2697d3e..1254770 100644 --- a/bin/gensquashfs/mkfs.h +++ b/bin/gensquashfs/mkfs.h @@ -44,6 +44,7 @@ typedef struct {  	unsigned int dirscan_flags;  	const char *infile;  	const char *selinux; +	const char *xattr_file;  	const char *sortfile;  	bool no_tail_packing; @@ -62,7 +63,14 @@ typedef struct {  void process_command_line(options_t *opt, int argc, char **argv);  int xattrs_from_dir(fstree_t *fs, const char *path, void *selinux_handle, -		    sqfs_xattr_writer_t *xwr, bool scan_xattr); +		    void *xattr_map, sqfs_xattr_writer_t *xwr, bool scan_xattr); + +void *xattr_open_map_file(const char *path); + +int +xattr_apply_map_file(char *path, void *map, sqfs_xattr_writer_t *xwr); + +void xattr_close_map_file(void *xattr_map);  void *selinux_open_context_file(const char *filename); diff --git a/bin/gensquashfs/options.c b/bin/gensquashfs/options.c index fc2d900..b554cb2 100644 --- a/bin/gensquashfs/options.c +++ b/bin/gensquashfs/options.c @@ -35,13 +35,14 @@ static struct option long_opts[] = {  #ifdef WITH_SELINUX  	{ "selinux", required_argument, NULL, 's' },  #endif +	{ "xattr-file", required_argument, NULL, 'A' },  	{ "sort-file", required_argument, NULL, 'S' },  	{ "version", no_argument, NULL, 'V' },  	{ "help", no_argument, NULL, 'h' },  	{ NULL, 0, NULL, 0 },  }; -static const char *short_opts = "F:D:X:c:b:B:d:u:g:j:Q:S:kxoefqThV" +static const char *short_opts = "F:D:X:c:b:B:d:u:g:j:Q:S:A:kxoefqThV"  #ifdef WITH_SELINUX  "s:"  #endif @@ -107,6 +108,8 @@ static const char *help_string =  "  --selinux, -s <file>        Specify an SELinux label file to get context\n"  "                              attributes from.\n"  #endif +"  --xattr-file, -A <file>     Specify an Xattr file to get extended attributes\n" +"                              for loading xattrs\n"  "  --keep-time, -k             When using --pack-dir only, use the timestamps\n"  "                              from the input files instead of setting\n"  "                              defaults on all input paths.\n" @@ -323,6 +326,9 @@ void process_command_line(options_t *opt, int argc, char **argv)  			opt->selinux = optarg;  			break;  #endif +		case 'A': +			opt->xattr_file = optarg; +			break;  		case 'S':  			opt->sortfile = optarg;  			break; | 
