diff options
Diffstat (limited to 'mkfs')
| -rw-r--r-- | mkfs/Makemodule.am | 1 | ||||
| -rw-r--r-- | mkfs/dirscan.c | 228 | ||||
| -rw-r--r-- | mkfs/mkfs.h | 15 | 
3 files changed, 244 insertions, 0 deletions
| diff --git a/mkfs/Makemodule.am b/mkfs/Makemodule.am index 1955852..f1e0d0d 100644 --- a/mkfs/Makemodule.am +++ b/mkfs/Makemodule.am @@ -1,4 +1,5 @@  gensquashfs_SOURCES = mkfs/mkfs.c mkfs/mkfs.h mkfs/options.c +gensquashfs_SOURCES += mkfs/dirscan.c  gensquashfs_LDADD = libsqfshelper.a libsquashfs.la libfstree.a libutil.la  gensquashfs_LDADD += $(LIBSELINUX_LIBS)  gensquashfs_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/mkfs/dirscan.c b/mkfs/dirscan.c new file mode 100644 index 0000000..5cb955a --- /dev/null +++ b/mkfs/dirscan.c @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * fstree_from_dir.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +static char *get_file_path(tree_node_t *n, const char *name) +{ +	char *ptr, *new; +	int ret; + +	if (n->parent == NULL) { +		ptr = strdup(name); +		if (ptr == NULL) +			goto fail; +		return ptr; +	} + +	ptr = fstree_get_path(n); +	if (ptr == NULL) +		goto fail; + +	ret = canonicalize_name(ptr); +	assert(ret == 0); + +	new = realloc(ptr, strlen(ptr) + strlen(name) + 2); +	if (new == NULL) +		goto fail; + +	ptr = new; +	strcat(ptr, "/"); +	strcat(ptr, name); +	return ptr; +fail: +	perror("getting absolute file path"); +	free(ptr); +	return NULL; +} + +#ifdef HAVE_SYS_XATTR_H +static int populate_xattr(fstree_t *fs, tree_node_t *node) +{ +	char *key, *value = NULL, *buffer = NULL; +	ssize_t buflen, vallen, keylen; + +	buflen = listxattr(node->name, NULL, 0); + +	if (buflen < 0) { +		perror("listxattr"); +		return -1; +	} + +	if (buflen == 0) +		return 0; + +	buffer = malloc(buflen); +	if (buffer == NULL) { +		perror("xattr name buffer"); +		return -1; +	} + +	buflen = listxattr(node->name, buffer, buflen); +	if (buflen == -1) { +		perror("listxattr"); +		goto fail; +	} + +	key = buffer; +	while (buflen > 0) { +		vallen = getxattr(node->name, key, NULL, 0); +		if (vallen == -1) +			goto fail; + +		if (vallen > 0) { +			value = alloc_string(vallen); +			if (value == NULL) { +				perror("xattr value buffer"); +				goto fail; +			} + +			vallen = getxattr(node->name, key, value, vallen); +			if (vallen == -1) { +				perror("getxattr"); +				goto fail; +			} + +			value[vallen] = 0; +			if (fstree_add_xattr(fs, node, key, value)) +				goto fail; + +			free(value); +			value = NULL; +		} + +		keylen = strlen(key) + 1; +		buflen -= keylen; +		key += keylen; +	} + +	free(buffer); +	return 0; +fail: +	free(value); +	free(buffer); +	return -1; +} +#endif + +static int populate_dir(fstree_t *fs, tree_node_t *root, dev_t devstart, +			unsigned int flags) +{ +	char *extra = NULL; +	struct dirent *ent; +	struct stat sb; +	tree_node_t *n; +	DIR *dir; + +	dir = opendir("."); +	if (dir == NULL) { +		perror("opendir"); +		return -1; +	} + +	for (;;) { +		errno = 0; +		ent = readdir(dir); + +		if (ent == NULL) { +			if (errno) { +				perror("readdir"); +				goto fail; +			} +			break; +		} + +		if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, ".")) +			continue; + +		if (fstatat(AT_FDCWD, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) { +			perror(ent->d_name); +			goto fail; +		} + +		if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) +			continue; + +		if (S_ISLNK(sb.st_mode)) { +			extra = alloc_string(sb.st_size); +			if (extra == NULL) +				goto fail_rdlink; + +			if (readlink(ent->d_name, extra, sb.st_size) < 0) +				goto fail_rdlink; + +			extra[sb.st_size] = '\0'; +		} else if (S_ISREG(sb.st_mode)) { +			extra = get_file_path(root, ent->d_name); +			if (extra == NULL) +				goto fail; +		} + +		if (!(flags & DIR_SCAN_KEEP_TIME)) +			sb.st_mtim = fs->defaults.st_mtim; + +		n = fstree_mknode(root, ent->d_name, strlen(ent->d_name), +				  extra, &sb); +		if (n == NULL) { +			perror("creating tree node"); +			goto fail; +		} + +#ifdef HAVE_SYS_XATTR_H +		if (flags & DIR_SCAN_READ_XATTR) { +			if (populate_xattr(fs, n)) +				goto fail; +		} +#endif + +		free(extra); +		extra = NULL; +	} + +	closedir(dir); + +	for (n = root->data.dir.children; n != NULL; n = n->next) { +		if (S_ISDIR(n->mode)) { +			if (pushd(n->name)) +				return -1; + +			if (populate_dir(fs, n, devstart, flags)) +				return -1; + +			if (popd()) +				return -1; +		} +	} + +	return 0; +fail_rdlink: +	perror("readlink"); +fail: +	closedir(dir); +	free(extra); +	return -1; +} + +int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags) +{ +	struct stat sb; +	int ret; + +	if (stat(path, &sb)) { +		perror(path); +		return -1; +	} + +	if (pushd(path)) +		return -1; + +	ret = populate_dir(fs, fs->root, sb.st_dev, flags); + +	if (popd()) +		ret = -1; + +	return ret; +} diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index 0e374dc..bce98d8 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -19,12 +19,17 @@  #include "fstree.h"  #include "util.h" +#ifdef HAVE_SYS_XATTR_H +#include <sys/xattr.h> +#endif +  #include <getopt.h>  #include <assert.h>  #include <unistd.h>  #include <stdlib.h>  #include <string.h>  #include <limits.h> +#include <dirent.h>  #include <stdio.h>  #include <fcntl.h>  #include <errno.h> @@ -48,6 +53,16 @@ typedef struct {  	char *comp_extra;  } options_t; +enum { +	DIR_SCAN_KEEP_TIME = 0x01, + +	DIR_SCAN_ONE_FILESYSTEM = 0x02, + +	DIR_SCAN_READ_XATTR = 0x04, +}; +  void process_command_line(options_t *opt, int argc, char **argv); +int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags); +  #endif /* MKFS_H */ | 
