diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/fstree/Makemodule.am | 6 | ||||
| -rw-r--r-- | lib/fstree/fstree_from_dir.c | 493 | ||||
| -rw-r--r-- | lib/fstree/fstree_from_file.c | 591 | ||||
| -rw-r--r-- | lib/fstree/sort_by_file.c | 368 | 
4 files changed, 2 insertions, 1456 deletions
| diff --git a/lib/fstree/Makemodule.am b/lib/fstree/Makemodule.am index 4388bde..09cd9ac 100644 --- a/lib/fstree/Makemodule.am +++ b/lib/fstree/Makemodule.am @@ -1,9 +1,7 @@ -libfstree_a_SOURCES = lib/fstree/fstree.c lib/fstree/fstree_from_file.c -libfstree_a_SOURCES += lib/fstree/hardlink.c +libfstree_a_SOURCES = include/fstree.h lib/fstree/fstree.c  libfstree_a_SOURCES += lib/fstree/post_process.c lib/fstree/get_path.c -libfstree_a_SOURCES += lib/fstree/mknode.c lib/fstree/fstree_from_dir.c +libfstree_a_SOURCES += lib/fstree/mknode.c lib/fstree/hardlink.c  libfstree_a_SOURCES += lib/fstree/add_by_path.c lib/fstree/get_by_path.c -libfstree_a_SOURCES += include/fstree.h lib/fstree/sort_by_file.c  libfstree_a_CFLAGS = $(AM_CFLAGS)  libfstree_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/lib/fstree/fstree_from_dir.c b/lib/fstree/fstree_from_dir.c deleted file mode 100644 index 01f331d..0000000 --- a/lib/fstree/fstree_from_dir.c +++ /dev/null @@ -1,493 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * fstree_from_dir.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" -#include "fstree.h" - -#include <dirent.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#if defined(_WIN32) || defined(__WINDOWS__) -#define UNIX_EPOCH_ON_W32 11644473600UL -#define W32_TICS_PER_SEC 10000000UL - -static sqfs_u32 w32time_to_sqfs_time(const FILETIME *ft) -{ -	sqfs_u64 w32ts; - -	w32ts = ft->dwHighDateTime; -	w32ts <<= 32UL; -	w32ts |= ft->dwLowDateTime; - -	w32ts /= W32_TICS_PER_SEC; - -	if (w32ts <= UNIX_EPOCH_ON_W32) -		return 0; - -	w32ts -= UNIX_EPOCH_ON_W32; - -	return (w32ts < 0x0FFFFFFFFUL) ? w32ts : 0xFFFFFFFF; -} - -static int add_node(fstree_t *fs, tree_node_t *root, -		    scan_node_callback cb, void *user, -		    unsigned int flags, -		    const LPWIN32_FIND_DATAW entry) -{ -	tree_node_t *n; -	DWORD length; - -	if (entry->cFileName[0] == '.') { -		if (entry->cFileName[1] == '\0') -			return 0; - -		if (entry->cFileName[1] == '.' && entry->cFileName[2] == '\0') -			return 0; -	} - -	length = WideCharToMultiByte(CP_UTF8, 0, entry->cFileName, -				     -1, NULL, 0, NULL, NULL); -	if (length <= 0) { -		w32_perror("converting path to UTF-8"); -		return -1; -	} - -	n = calloc(1, sizeof(*n) + length + 1); -	if (n == NULL) { -		fprintf(stderr, "creating tree node: out-of-memory\n"); -		return -1; -	} - -	n->name = (char *)n->payload; -	WideCharToMultiByte(CP_UTF8, 0, entry->cFileName, -1, -			    n->name, length + 1, NULL, NULL); - -	if (entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { -		if (flags & DIR_SCAN_NO_DIR) { -			free(n); -			return 0; -		} - -		n->mode = S_IFDIR | 0755; -	} else { -		if (flags & DIR_SCAN_NO_FILE) { -			free(n); -			return 0; -		} - -		n->mode = S_IFREG | 0644; -	} - -	if (cb != NULL) { -		int ret = cb(user, fs, n); - -		if (ret != 0) { -			free(n); -			return ret < 0 ? ret : 0; -		} -	} - -	if (flags & DIR_SCAN_KEEP_TIME) { -		n->mod_time = w32time_to_sqfs_time(&(entry->ftLastWriteTime)); -	} else { -		n->mod_time = fs->defaults.st_mtime; -	} - -	fstree_insert_sorted(root, n); -	return 0; -} - -static int scan_dir(fstree_t *fs, tree_node_t *root, -		    const char *path, const WCHAR *wpath, -		    scan_node_callback cb, void *user, -		    unsigned int flags) -{ -	WIN32_FIND_DATAW entry; -	HANDLE dirhnd; - -	dirhnd = FindFirstFileW(wpath, &entry); - -	if (dirhnd == INVALID_HANDLE_VALUE) -		goto fail_perror; - -	do { -		if (add_node(fs, root, cb, user, flags, &entry)) -			goto fail; -	} while (FindNextFileW(dirhnd, &entry)); - -	if (GetLastError() != ERROR_NO_MORE_FILES) -		goto fail_perror; - -	FindClose(dirhnd); -	return 0; -fail_perror: -	w32_perror(path); -fail: -	if (dirhnd != INVALID_HANDLE_VALUE) -		FindClose(dirhnd); -	return -1; -} - -int fstree_from_dir(fstree_t *fs, tree_node_t *root, -		    const char *path, scan_node_callback cb, -		    void *user, unsigned int flags) -{ -	WCHAR *wpath = NULL, *new = NULL; -	size_t len, newlen; -	tree_node_t *n; - -	/* path -> to_wchar(path) + L"\*" */ -	wpath = path_to_windows(path); -	if (wpath == NULL) { -		fprintf(stderr, "%s: allocation failure.\n", path); -		return -1; -	} - -	for (len = 0; wpath[len] != '\0'; ++len) -		; - -	newlen = len + 1; - -	if (len > 0 && wpath[len - 1] != '\\') -		newlen += 1; - -	new = realloc(wpath, sizeof(wpath[0]) * (newlen + 1)); -	if (new == NULL) { -		fprintf(stderr, "%s: allocation failure.\n", path); -		goto fail; -	} - -	wpath = new; - -	if (len > 0 && wpath[len - 1] != '\\') -		wpath[len++] = '\\'; - -	wpath[len++] = '*'; -	wpath[len++] = '\0'; - -	/* scan directory contents */ -	if (scan_dir(fs, root, path, wpath, cb, user, flags)) -		goto fail; - -	free(wpath); -	wpath = NULL; - -	/* recursion step */ -	if (flags & DIR_SCAN_NO_RECURSION) -		return 0; - -	for (n = root->data.dir.children; n != NULL; n = n->next) { -		if (!S_ISDIR(n->mode)) -			continue; - -		if (fstree_from_subdir(fs, n, path, n->name, cb, user, flags)) -			return -1; -	} - -	return 0; -fail: -	free(wpath); -	return -1; -} - -int fstree_from_subdir(fstree_t *fs, tree_node_t *root, -		       const char *path, const char *subdir, -		       scan_node_callback cb, void *user, -		       unsigned int flags) -{ -	size_t len, plen, slen; -	WCHAR *wpath = NULL; -	char *temp = NULL; -	tree_node_t *n; - -	plen = strlen(path); -	slen = subdir == NULL ? 0 : strlen(subdir); - -	if (slen == 0) -		return fstree_from_dir(fs, root, path, cb, user, flags); - -	len = plen + 1 + slen + 2; - -	temp = calloc(1, len + 1); -	if (temp == NULL) { -		fprintf(stderr, "%s/%s: allocation failure.\n", path, subdir); -		return -1; -	} - -	memcpy(temp, path, plen); -	temp[plen] = '/'; -	memcpy(temp + plen + 1, subdir, slen); -	temp[plen + 1 + slen    ] = '/'; -	temp[plen + 1 + slen + 1] = '*'; -	temp[plen + 1 + slen + 2] = '\0'; - -	wpath = path_to_windows(temp); -	if (wpath == NULL) { -		fprintf(stderr, "%s: allocation failure.\n", temp); -		goto fail; -	} - -	if (scan_dir(fs, root, temp, wpath, cb, user, flags)) -		goto fail; - -	free(wpath); -	wpath = NULL; - -	if (flags & DIR_SCAN_NO_RECURSION) { -		free(temp); -		return 0; -	} - -	temp[plen + 1 + slen] = '\0'; - -	for (n = root->data.dir.children; n != NULL; n = n->next) { -		if (!S_ISDIR(n->mode)) -			continue; - -		if (fstree_from_subdir(fs, n, temp, n->name, cb, user, flags)) -			goto fail; -	} - -	free(temp); -	return 0; -fail: -	free(temp); -	free(wpath); -	return -1; - -} -#else -static void discard_node(tree_node_t *root, tree_node_t *n) -{ -	tree_node_t *it; - -	if (n == root->data.dir.children) { -		root->data.dir.children = n->next; -	} else { -		it = root->data.dir.children; - -		while (it != NULL && it->next != n) -			it = it->next; - -		if (it != NULL) -			it->next = n->next; -	} - -	free(n); -} - -static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, -			dev_t devstart, scan_node_callback cb, -			void *user, unsigned int flags) -{ -	char *extra = NULL; -	struct dirent *ent; -	int ret, childfd; -	struct stat sb; -	tree_node_t *n; -	DIR *dir; - -	dir = fdopendir(dir_fd); -	if (dir == NULL) { -		perror("fdopendir"); -		close(dir_fd); -		return -1; -	} - -	/* XXX: fdopendir can dup and close dir_fd internally -	   and still be compliant with the spec. */ -	dir_fd = dirfd(dir); - -	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(dir_fd, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) { -			perror(ent->d_name); -			goto fail; -		} - -		switch (sb.st_mode & S_IFMT) { -		case S_IFSOCK: -			if (flags & DIR_SCAN_NO_SOCK) -				continue; -			break; -		case S_IFLNK: -			if (flags & DIR_SCAN_NO_SLINK) -				continue; -			break; -		case S_IFREG: -			if (flags & DIR_SCAN_NO_FILE) -				continue; -			break; -		case S_IFBLK: -			if (flags & DIR_SCAN_NO_BLK) -				continue; -			break; -		case S_IFCHR: -			if (flags & DIR_SCAN_NO_CHR) -				continue; -			break; -		case S_IFIFO: -			if (flags & DIR_SCAN_NO_FIFO) -				continue; -			break; -		default: -			break; -		} - -		if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) -			continue; - -		if (S_ISLNK(sb.st_mode)) { -			size_t size; - -			if ((sizeof(sb.st_size) > sizeof(size_t)) && -			    sb.st_size > SIZE_MAX) { -				errno = EOVERFLOW; -				goto fail_rdlink; -			} - -			if (SZ_ADD_OV((size_t)sb.st_size, 1, &size)) { -				errno = EOVERFLOW; -				goto fail_rdlink; -			} - -			extra = calloc(1, size); -			if (extra == NULL) -				goto fail_rdlink; - -			if (readlinkat(dir_fd, ent->d_name, -				       extra, (size_t)sb.st_size) < 0) { -				goto fail_rdlink; -			} - -			extra[sb.st_size] = '\0'; -		} - -		if (!(flags & DIR_SCAN_KEEP_TIME)) -			sb.st_mtime = fs->defaults.st_mtime; - -		if (S_ISDIR(sb.st_mode) && (flags & DIR_SCAN_NO_DIR)) { -			n = fstree_get_node_by_path(fs, root, ent->d_name, -						    false, false); -			if (n == NULL) -				continue; - -			ret = 0; -		} else { -			n = fstree_mknode(root, ent->d_name, -					  strlen(ent->d_name), extra, &sb); -			if (n == NULL) { -				perror("creating tree node"); -				goto fail; -			} - -			ret = (cb == NULL) ? 0 : cb(user, fs, n); -		} - -		free(extra); -		extra = NULL; - -		if (ret < 0) -			goto fail; - -		if (ret > 0) { -			discard_node(root, n); -			continue; -		} - -		if (S_ISDIR(n->mode) && !(flags & DIR_SCAN_NO_RECURSION)) { -			childfd = openat(dir_fd, n->name, O_DIRECTORY | -					 O_RDONLY | O_CLOEXEC); -			if (childfd < 0) { -				perror(n->name); -				goto fail; -			} - -			if (populate_dir(childfd, fs, n, devstart, -					 cb, user, flags)) { -				goto fail; -			} -		} -	} - -	closedir(dir); -	return 0; -fail_rdlink: -	perror("readlink"); -fail: -	closedir(dir); -	free(extra); -	return -1; -} - -int fstree_from_subdir(fstree_t *fs, tree_node_t *root, -		       const char *path, const char *subdir, -		       scan_node_callback cb, void *user, -		       unsigned int flags) -{ -	struct stat sb; -	int fd, subfd; - -	if (!S_ISDIR(root->mode)) { -		fprintf(stderr, -			"scanning %s/%s into %s: target is not a directory\n", -			path, subdir == NULL ? "" : subdir, root->name); -		return -1; -	} - -	fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); -	if (fd < 0) { -		perror(path); -		return -1; -	} - -	if (subdir != NULL) { -		subfd = openat(fd, subdir, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - -		if (subfd < 0) { -			fprintf(stderr, "%s/%s: %s\n", path, subdir, -				strerror(errno)); -			close(fd); -			return -1; -		} - -		close(fd); -		fd = subfd; -	} - -	if (fstat(fd, &sb)) { -		fprintf(stderr, "%s/%s: %s\n", path, -			subdir == NULL ? "" : subdir, -			strerror(errno)); -		close(fd); -		return -1; -	} - -	return populate_dir(fd, fs, root, sb.st_dev, cb, user, flags); -} - -int fstree_from_dir(fstree_t *fs, tree_node_t *root, -		    const char *path, scan_node_callback cb, -		    void *user, unsigned int flags) -{ -	return fstree_from_subdir(fs, root, path, NULL, cb, user, flags); -} -#endif diff --git a/lib/fstree/fstree_from_file.c b/lib/fstree/fstree_from_file.c deleted file mode 100644 index 411c64f..0000000 --- a/lib/fstree/fstree_from_file.c +++ /dev/null @@ -1,591 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * fstree_from_file.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" - -#include "util/util.h" -#include "io/file.h" -#include "fstree.h" -#include "compat.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <errno.h> -#include <ctype.h> - -struct glob_context { -	const char *filename; -	size_t line_num; - -	struct stat *basic; -	unsigned int glob_flags; - -	char *name_pattern; -}; - -enum { -	GLOB_MODE_FROM_SRC = 0x01, -	GLOB_UID_FROM_SRC = 0x02, -	GLOB_GID_FROM_SRC = 0x04, -	GLOB_FLAG_PATH = 0x08, -}; - -static const struct { -	const char *name; -	unsigned int clear_flag; -	unsigned int set_flag; -} glob_scan_flags[] = { -	{ "-type b", DIR_SCAN_NO_BLK, 0 }, -	{ "-type c", DIR_SCAN_NO_CHR, 0 }, -	{ "-type d", DIR_SCAN_NO_DIR, 0 }, -	{ "-type p", DIR_SCAN_NO_FIFO, 0 }, -	{ "-type f", DIR_SCAN_NO_FILE, 0 }, -	{ "-type l", DIR_SCAN_NO_SLINK, 0 }, -	{ "-type s", DIR_SCAN_NO_SOCK, 0 }, -	{ "-xdev", 0, DIR_SCAN_ONE_FILESYSTEM }, -	{ "-mount", 0, DIR_SCAN_ONE_FILESYSTEM }, -	{ "-keeptime", 0, DIR_SCAN_KEEP_TIME }, -	{ "-nonrecursive", 0, DIR_SCAN_NO_RECURSION }, -}; - -static int add_generic(fstree_t *fs, const char *filename, size_t line_num, -		       const char *path, struct stat *sb, -		       const char *basepath, unsigned int glob_flags, -		       const char *extra) -{ -	(void)basepath; -	(void)glob_flags; - -	if (fstree_add_generic(fs, path, sb, extra) == NULL) { -		fprintf(stderr, "%s: " PRI_SZ ": %s: %s\n", -			filename, line_num, path, strerror(errno)); -		return -1; -	} - -	return 0; -} - -static int add_device(fstree_t *fs, const char *filename, size_t line_num, -		      const char *path, struct stat *sb, const char *basepath, -		      unsigned int glob_flags, const char *extra) -{ -	unsigned int maj, min; -	char c; - -	if (sscanf(extra, "%c %u %u", &c, &maj, &min) != 3) { -		fprintf(stderr, "%s: " PRI_SZ ": " -			"expected '<c|b> major minor'\n", -			filename, line_num); -		return -1; -	} - -	if (c == 'c' || c == 'C') { -		sb->st_mode |= S_IFCHR; -	} else if (c == 'b' || c == 'B') { -		sb->st_mode |= S_IFBLK; -	} else { -		fprintf(stderr, "%s: " PRI_SZ ": unknown device type '%c'\n", -			filename, line_num, c); -		return -1; -	} - -	sb->st_rdev = makedev(maj, min); -	return add_generic(fs, filename, line_num, path, sb, basepath, -			   glob_flags, NULL); -} - -static int add_file(fstree_t *fs, const char *filename, size_t line_num, -		    const char *path, struct stat *basic, const char *basepath, -		    unsigned int glob_flags, const char *extra) -{ -	if (extra == NULL || *extra == '\0') -		extra = path; - -	return add_generic(fs, filename, line_num, path, basic, -			   basepath, glob_flags, extra); -} - -static int add_hard_link(fstree_t *fs, const char *filename, size_t line_num, -			 const char *path, struct stat *basic, -			 const char *basepath, unsigned int glob_flags, -			 const char *extra) -{ -	(void)basepath; -	(void)glob_flags; -	(void)basic; - -	if (fstree_add_hard_link(fs, path, extra) == NULL) { -		fprintf(stderr, "%s: " PRI_SZ ": %s\n", -			filename, line_num, strerror(errno)); -		return -1; -	} -	return 0; -} - -static int glob_node_callback(void *user, fstree_t *fs, tree_node_t *node) -{ -	struct glob_context *ctx = user; -	char *path; -	int ret; -	(void)fs; - -	if (!(ctx->glob_flags & GLOB_MODE_FROM_SRC)) { -		node->mode &= ~(07777); -		node->mode |= ctx->basic->st_mode & 07777; -	} - -	if (!(ctx->glob_flags & GLOB_UID_FROM_SRC)) -		node->uid = ctx->basic->st_uid; - -	if (!(ctx->glob_flags & GLOB_GID_FROM_SRC)) -		node->gid = ctx->basic->st_gid; - -	if (ctx->name_pattern != NULL) { -		if (ctx->glob_flags & GLOB_FLAG_PATH) { -			path = fstree_get_path(node); -			if (path == NULL) { -				fprintf(stderr, "%s: " PRI_SZ ": %s\n", -					ctx->filename, ctx->line_num, -					strerror(errno)); -				return -1; -			} - -			ret = canonicalize_name(path); -			assert(ret == 0); - -			ret = fnmatch(ctx->name_pattern, path, FNM_PATHNAME); -			free(path); -		} else { -			ret = fnmatch(ctx->name_pattern, node->name, 0); -		} - -		if (ret != 0) -			return 1; -	} - -	return 0; -} - -static size_t name_string_length(const char *str) -{ -	size_t len = 0; -	int start; - -	if (*str == '"' || *str == '\'') { -		start = *str; -		++len; - -		while (str[len] != '\0' && str[len] != start) -			++len; - -		if (str[len] == start) -			++len; -	} else { -		while (str[len] != '\0' && !isspace(str[len])) -			++len; -	} - -	return len; -} - -static void quote_remove(char *str) -{ -	char *dst = str; -	int start = *(str++); - -	if (start != '\'' && start != '"') -		return; - -	while (*str != start && *str != '\0') -		*(dst++) = *(str++); - -	*(dst++) = '\0'; -} - -static int glob_files(fstree_t *fs, const char *filename, size_t line_num, -		      const char *path, struct stat *basic, -		      const char *basepath, unsigned int glob_flags, -		      const char *extra) -{ -	unsigned int scan_flags = 0, all_flags; -	struct glob_context ctx; -	bool first_clear_flag; -	size_t i, count, len; -	tree_node_t *root; -	int ret; - -	memset(&ctx, 0, sizeof(ctx)); -	ctx.filename = filename; -	ctx.line_num = line_num; -	ctx.basic = basic; -	ctx.glob_flags = glob_flags; - -	/* fetch the actual target node */ -	root = fstree_get_node_by_path(fs, fs->root, path, true, false); -	if (root == NULL) { -		fprintf(stderr, "%s: " PRI_SZ ": %s: %s\n", -			filename, line_num, path, strerror(errno)); -		return -1; -	} - -	/* process options */ -	first_clear_flag = true; - -	all_flags = DIR_SCAN_NO_BLK | DIR_SCAN_NO_CHR | DIR_SCAN_NO_DIR | -		DIR_SCAN_NO_FIFO | DIR_SCAN_NO_FILE | DIR_SCAN_NO_SLINK | -		DIR_SCAN_NO_SOCK; - -	while (extra != NULL && *extra != '\0') { -		count = sizeof(glob_scan_flags) / sizeof(glob_scan_flags[0]); - -		for (i = 0; i < count; ++i) { -			len = strlen(glob_scan_flags[i].name); -			if (strncmp(extra, glob_scan_flags[i].name, len) != 0) -				continue; - -			if (isspace(extra[len])) { -				extra += len; -				while (isspace(*extra)) -					++extra; -				break; -			} -		} - -		if (i < count) { -			if (glob_scan_flags[i].clear_flag != 0 && -			    first_clear_flag) { -				scan_flags |= all_flags; -				first_clear_flag = false; -			} - -			scan_flags &= ~(glob_scan_flags[i].clear_flag); -			scan_flags |= glob_scan_flags[i].set_flag; -			continue; -		} - -		if (strncmp(extra, "-name", 5) == 0 && isspace(extra[5])) { -			for (extra += 5; isspace(*extra); ++extra) -				; - -			len = name_string_length(extra); - -			free(ctx.name_pattern); -			ctx.name_pattern = strndup(extra, len); -			extra += len; - -			while (isspace(*extra)) -				++extra; - -			quote_remove(ctx.name_pattern); -			continue; -		} - -		if (strncmp(extra, "-path", 5) == 0 && isspace(extra[5])) { -			for (extra += 5; isspace(*extra); ++extra) -				; - -			len = name_string_length(extra); - -			free(ctx.name_pattern); -			ctx.name_pattern = strndup(extra, len); -			extra += len; - -			while (isspace(*extra)) -				++extra; - -			quote_remove(ctx.name_pattern); -			ctx.glob_flags |= GLOB_FLAG_PATH; -			continue; -		} - -		if (extra[0] == '-') { -			if (extra[1] == '-' && isspace(extra[2])) { -				extra += 2; -				while (isspace(*extra)) -					++extra; -				break; -			} - -			fprintf(stderr, "%s: " PRI_SZ ": unknown option.\n", -				filename, line_num); -			free(ctx.name_pattern); -			return -1; -		} else { -			break; -		} -	} - -	if (extra != NULL && *extra == '\0') -		extra = NULL; - -	/* do the scan */ -	if (basepath == NULL) { -		if (extra == NULL) { -			ret = fstree_from_dir(fs, root, ".", glob_node_callback, -					      &ctx, scan_flags); -		} else { -			ret = fstree_from_dir(fs, root, extra, -					      glob_node_callback, -					      &ctx, scan_flags); -		} -	} else { -		ret = fstree_from_subdir(fs, root, basepath, extra, -					 glob_node_callback, &ctx, -					 scan_flags); -	} - -	free(ctx.name_pattern); -	return ret; -} - -static const struct callback_t { -	const char *keyword; -	unsigned int mode; -	bool need_extra; -	bool is_glob; -	bool allow_root; -	int (*callback)(fstree_t *fs, const char *filename, size_t line_num, -			const char *path, struct stat *sb, -			const char *basepath, unsigned int glob_flags, -			const char *extra); -} file_list_hooks[] = { -	{ "dir", S_IFDIR, false, false, true, add_generic }, -	{ "slink", S_IFLNK, true, false, false, add_generic }, -	{ "link", 0, true, false, false, add_hard_link }, -	{ "nod", 0, true, false, false, add_device }, -	{ "pipe", S_IFIFO, false, false, false, add_generic }, -	{ "sock", S_IFSOCK, false, false, false, add_generic }, -	{ "file", S_IFREG, false, false, false, add_file }, -	{ "glob", 0, false, true, true, glob_files }, -}; - -#define NUM_HOOKS (sizeof(file_list_hooks) / sizeof(file_list_hooks[0])) - -static char *skip_space(char *str) -{ -	if (!isspace(*str)) -		return NULL; -	while (isspace(*str)) -		++str; -	return str; -} - -static char *read_u32(char *str, sqfs_u32 *out, sqfs_u32 base) -{ -	*out = 0; - -	if (!isdigit(*str)) -		return NULL; - -	while (isdigit(*str)) { -		sqfs_u32 x = *(str++) - '0'; - -		if (x >= base || (*out) > (0xFFFFFFFF - x) / base) -			return NULL; - -		(*out) = (*out) * base + x; -	} - -	return str; -} - -static char *read_str(char *str, char **out) -{ -	*out = str; - -	if (*str == '"') { -		char *ptr = str++; - -		while (*str != '\0' && *str != '"') { -			if (str[0] == '\\' && -			    (str[1] == '"' || str[1] == '\\')) { -				*(ptr++) = str[1]; -				str += 2; -			} else { -				*(ptr++) = *(str++); -			} -		} - -		if (str[0] != '"' || !isspace(str[1])) -			return NULL; - -		*ptr = '\0'; -		++str; -	} else { -		while (*str != '\0' && !isspace(*str)) -			++str; - -		if (!isspace(*str)) -			return NULL; - -		*(str++) = '\0'; -	} - -	while (isspace(*str)) -		++str; - -	return str; -} - -static int handle_line(fstree_t *fs, const char *filename, -		       size_t line_num, char *line, -		       const char *basepath) -{ -	const char *extra = NULL, *msg = NULL; -	const struct callback_t *cb = NULL; -	unsigned int glob_flags = 0; -	sqfs_u32 uid, gid, mode; -	struct stat sb; -	char *path; - -	for (size_t i = 0; i < NUM_HOOKS; ++i) { -		size_t len = strlen(file_list_hooks[i].keyword); -		if (strncmp(file_list_hooks[i].keyword, line, len) != 0) -			continue; - -		if (isspace(line[len])) { -			cb = file_list_hooks + i; -			line = skip_space(line + len); -			break; -		} -	} - -	if (cb == NULL) -		goto fail_kw; - -	if ((line = read_str(line, &path)) == NULL) -		goto fail_ent; - -	if (canonicalize_name(path)) -		goto fail_ent; - -	if (*path == '\0' && !cb->allow_root) -		goto fail_root; - -	if (cb->is_glob && *line == '*') { -		++line; -		mode = 0; -		glob_flags |= GLOB_MODE_FROM_SRC; -	} else { -		if ((line = read_u32(line, &mode, 8)) == NULL || mode > 07777) -			goto fail_mode; -	} - -	if ((line = skip_space(line)) == NULL) -		goto fail_ent; - -	if (cb->is_glob && *line == '*') { -		++line; -		uid = 0; -		glob_flags |= GLOB_UID_FROM_SRC; -	} else { -		if ((line = read_u32(line, &uid, 10)) == NULL) -			goto fail_uid_gid; -	} - -	if ((line = skip_space(line)) == NULL) -		goto fail_ent; - -	if (cb->is_glob && *line == '*') { -		++line; -		gid = 0; -		glob_flags |= GLOB_GID_FROM_SRC; -	} else { -		if ((line = read_u32(line, &gid, 10)) == NULL) -			goto fail_uid_gid; -	} - -	if ((line = skip_space(line)) != NULL && *line != '\0') -		extra = line; - -	if (cb->need_extra && extra == NULL) -		goto fail_no_extra; - -	/* forward to callback */ -	memset(&sb, 0, sizeof(sb)); -	sb.st_mtime = fs->defaults.st_mtime; -	sb.st_mode = mode | cb->mode; -	sb.st_uid = uid; -	sb.st_gid = gid; - -	return cb->callback(fs, filename, line_num, path, -			    &sb, basepath, glob_flags, extra); -fail_root: -	fprintf(stderr, "%s: " PRI_SZ ": cannot use / as argument for %s.\n", -		filename, line_num, cb->keyword); -	return -1; -fail_no_extra: -	fprintf(stderr, "%s: " PRI_SZ ": missing argument for %s.\n", -		filename, line_num, cb->keyword); -	return -1; -fail_uid_gid: -	msg = "uid & gid must be decimal numbers < 2^32"; -	goto out_desc; -fail_mode: -	msg = "mode must be an octal number <= 07777"; -	goto out_desc; -fail_kw: -	msg = "unknown entry type"; -	goto out_desc; -fail_ent: -	msg = "error in entry description"; -	goto out_desc; -out_desc: -	fprintf(stderr, "%s: " PRI_SZ ": %s.\n", filename, line_num, msg); -	fputs("expected: <type> <path> <mode> <uid> <gid> [<extra>]\n", -	      stderr); -	return -1; -} - -int fstree_from_file_stream(fstree_t *fs, istream_t *fp, const char *basepath) -{ -	const char *filename; -	size_t line_num = 1; -	char *line; -	int ret; - -	filename = istream_get_filename(fp); - -	for (;;) { -		ret = istream_get_line(fp, &line, &line_num, -				       ISTREAM_LINE_LTRIM | ISTREAM_LINE_SKIP_EMPTY); -		if (ret < 0) -			return -1; -		if (ret > 0) -			break; - -		if (line[0] != '#') { -			if (handle_line(fs, filename, line_num, -					line, basepath)) { -				goto fail_line; -			} -		} - -		free(line); -		++line_num; -	} - -	return 0; -fail_line: -	free(line); -	return -1; -} - -int fstree_from_file(fstree_t *fs, const char *filename, const char *basepath) -{ -	istream_t *fp; -	int ret; - -	fp = istream_open_file(filename); -	if (fp == NULL) -		return -1; - -	ret = fstree_from_file_stream(fs, fp, basepath); - -	sqfs_destroy(fp); -	return ret; -} diff --git a/lib/fstree/sort_by_file.c b/lib/fstree/sort_by_file.c deleted file mode 100644 index ed4a58c..0000000 --- a/lib/fstree/sort_by_file.c +++ /dev/null @@ -1,368 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * sort_by_file.c - * - * Copyright (C) 2021 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" - -#include "util/util.h" -#include "fstree.h" -#include "compat.h" - -#include "sqfs/block.h" - -#include <string.h> -#include <stdlib.h> -#include <ctype.h> - -static int decode_priority(const char *filename, size_t line_no, -			   char *line, sqfs_s64 *priority) -{ -	bool negative = false; -	size_t i = 0; - -	if (line[0] == '-') { -		negative = true; -		i = 1; -	} - -	if (!isdigit(line[i])) -		goto fail_number; - -	*priority = 0; - -	for (; isdigit(line[i]); ++i) { -		sqfs_s64 x = line[i] - '0'; - -		if ((*priority) >= ((0x7FFFFFFFFFFFFFFFL - x) / 10L)) -			goto fail_ov; - -		(*priority) = (*priority) * 10 + x; -	} - -	if (!isspace(line[i])) -		goto fail_filename; - -	while (isspace(line[i])) -		++i; - -	if (line[i] == '\0') -		goto fail_filename; - -	if (negative) -		(*priority) = -(*priority); - -	memmove(line, line + i, strlen(line + i) + 1); -	return 0; -fail_number: -	fprintf(stderr, "%s: " PRI_SZ ": Line must start with " -		"numeric sort priority.\n", -		filename, line_no); -	return -1; -fail_ov: -	fprintf(stderr, "%s: " PRI_SZ ": Numeric overflow in sort priority.\n", -		filename, line_no); -	return -1; -fail_filename: -	fprintf(stderr, "%s: " PRI_SZ ": Expacted `<space> <filename>` " -		"after sort priority.\n", -		filename, line_no); -	return -1; -} - -static int decode_filename(const char *filename, size_t line_no, char *buffer) -{ -	char *src, *dst; - -	if (buffer[0] == '"') { -		src = buffer + 1; -		dst = buffer; - -		for (;;) { -			if (src[0] == '\0') -				goto fail_match; - -			if (src[0] == '"') { -				++src; -				break; -			} - -			if (src[0] == '\\') { -				switch (src[1]) { -				case '\\': -					*(dst++) = '\\'; -					src += 2; -					break; -				case '"': -					*(dst++) = '"'; -					src += 2; -					break; -				default: -					goto fail_escape; -				} -			} else { -				*(dst++) = *(src++); -			} -		} - -		if (*src != '\0') -			return -1; -	} - -	if (canonicalize_name(buffer)) -		goto fail_canon; -	return 0; -fail_canon: -	fprintf(stderr, "%s: " PRI_SZ ": Malformed filename.\n", -		filename, line_no); -	return -1; -fail_escape: -	fprintf(stderr, "%s: " PRI_SZ ": Unknown escape sequence `\\%c` " -		"in filename.\n", filename, line_no, src[1]); -	return -1; -fail_match: -	fprintf(stderr, "%s: " PRI_SZ ": Unmatched '\"' in filename.\n", -		filename, line_no); -	return -1; -} - -static int decode_flags(const char *filename, size_t line_no, bool *do_glob, -			bool *path_glob, int *flags, char *line) -{ -	char *start = line; - -	*do_glob = false; -	*path_glob = false; -	*flags = 0; - -	if (*(line++) != '[') -		return 0; - -	for (;;) { -		while (isspace(*line)) -			++line; - -		if (*line == ']') { -			++line; -			break; -		} - -		if (strncmp(line, "glob_no_path", 12) == 0) { -			line += 12; -			*do_glob = true; -			*path_glob = false; -		} else if (strncmp(line, "glob", 4) == 0) { -			line += 4; -			*do_glob = true; -			*path_glob = true; -		} else if (strncmp(line, "dont_fragment", 13) == 0) { -			line += 13; -			(*flags) |= SQFS_BLK_DONT_FRAGMENT; -		} else if (strncmp(line, "align", 5) == 0) { -			line += 5; -			(*flags) |= SQFS_BLK_ALIGN; -		} else if (strncmp(line, "dont_compress", 13) == 0) { -			line += 13; -			(*flags) |= SQFS_BLK_DONT_COMPRESS; -		} else if (strncmp(line, "dont_deduplicate", 16) == 0) { -			line += 16; -			(*flags) |= SQFS_BLK_DONT_DEDUPLICATE; -		} else if (strncmp(line, "nosparse", 8) == 0) { -			line += 8; -			(*flags) |= SQFS_BLK_IGNORE_SPARSE; -		} else { -			goto fail_flag; -		} - -		while (isspace(*line)) -			++line; - -		if (*line == ']') { -			++line; -			break; -		} - -		if (*(line++) != ',') -			goto fail_sep; -	} - -	if (!isspace(*line)) -		goto fail_fname; - -	while (isspace(*line)) -		++line; - -	memmove(start, line, strlen(line) + 1); -	return 0; -fail_fname: -	fprintf(stderr, "%s: " PRI_SZ ": Expected `<space> <filename>` " -		"after flag list.\n", filename, line_no); -	return -1; -fail_sep: -	fprintf(stderr, "%s: " PRI_SZ ": Unexpected '%c' after flag.\n", -		filename, line_no, *line); -	return -1; -fail_flag: -	fprintf(stderr, "%s: " PRI_SZ ": Unknown flag `%.3s...`.\n", -		filename, line_no, line); -	return -1; -} - -static void sort_file_list(fstree_t *fs) -{ -	file_info_t *out = NULL, *out_last = NULL; - -	while (fs->files != NULL) { -		sqfs_s64 lowest = fs->files->priority; -		file_info_t *it, *prev; - -		for (it = fs->files; it != NULL; it = it->next) { -			if (it->priority < lowest) -				lowest = it->priority; -		} - -		it = fs->files; -		prev = NULL; - -		while (it != NULL) { -			if (it->priority != lowest) { -				prev = it; -				it = it->next; -				continue; -			} - -			if (prev == NULL) { -				fs->files = it->next; -			} else { -				prev->next = it->next; -			} - -			if (out == NULL) { -				out = it; -			} else { -				out_last->next = it; -			} - -			out_last = it; -			it = it->next; -			out_last->next = NULL; -		} -	} - -	fs->files = out; -} - -int fstree_sort_files(fstree_t *fs, istream_t *sortfile) -{ -	const char *filename; -	size_t line_num = 1; -	file_info_t *it; - -	for (it = fs->files; it != NULL; it = it->next) { -		it->priority = 0; -		it->flags = 0; -		it->already_matched = false; -	} - -	filename = istream_get_filename(sortfile); - -	for (;;) { -		bool do_glob, path_glob, have_match; -		char *line = NULL; -		sqfs_s64 priority; -		int ret, flags; - -		ret = istream_get_line(sortfile, &line, &line_num, -				       ISTREAM_LINE_LTRIM | -				       ISTREAM_LINE_RTRIM | -				       ISTREAM_LINE_SKIP_EMPTY); -		if (ret != 0) { -			free(line); -			if (ret < 0) -				return -1; -			break; -		} - -		if (line[0] == '#') { -			free(line); -			continue; -		} - -		if (decode_priority(filename, line_num, line, &priority)) { -			free(line); -			return -1; -		} - -		if (decode_flags(filename, line_num, &do_glob, &path_glob, -				 &flags, line)) { -			free(line); -			return -1; -		} - -		if (decode_filename(filename, line_num, line)) { -			free(line); -			return -1; -		} - -		have_match = false; - -		for (it = fs->files; it != NULL; it = it->next) { -			tree_node_t *node; -			char *path; - -			if (it->already_matched) -				continue; - -			node = container_of(it, tree_node_t, data.file); -			path = fstree_get_path(node); -			if (path == NULL) { -				fprintf(stderr, "%s: " PRI_SZ ": out-of-memory\n", -					filename, line_num); -				free(line); -				return -1; -			} - -			if (canonicalize_name(path)) { -				fprintf(stderr, -					"%s: " PRI_SZ ": [BUG] error " -					"reconstructing node path\n", -					filename, line_num); -				free(line); -				free(path); -				return -1; -			} - -			if (do_glob) { -				ret = fnmatch(line, path, -					      path_glob ? FNM_PATHNAME : 0); - -			} else { -				ret = strcmp(path, line); -			} - -			free(path); - -			if (ret == 0) { -				have_match = true; -				it->flags = flags; -				it->priority = priority; -				it->already_matched = true; - -				if (!do_glob) -					break; -			} -		} - -		if (!have_match) { -			fprintf(stderr, "WARNING: %s: " PRI_SZ ": no match " -				"for '%s'.\n", -				filename, line_num, line); -		} - -		free(line); -	} - -	sort_file_list(fs); -	return 0; -} | 
