diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-23 13:16:21 +0100 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-23 13:55:38 +0100 | 
| commit | f92e31c94f953a68309dab7df75f5f9cc67caa7a (patch) | |
| tree | e3c25f232b44a99d40db49521d1974ddbb67df2c /lib | |
| parent | 9db873364de85e6b5f972dbd2bada80591ef8af4 (diff) | |
Add simple sqfs_tree_node_t hardlink detection to libcommon
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/common/Makemodule.am | 2 | ||||
| -rw-r--r-- | lib/common/hardlink.c | 104 | 
2 files changed, 105 insertions, 1 deletions
| diff --git a/lib/common/Makemodule.am b/lib/common/Makemodule.am index 696a169..635c342 100644 --- a/lib/common/Makemodule.am +++ b/lib/common/Makemodule.am @@ -1,5 +1,5 @@  libcommon_a_SOURCES = lib/common/serialize_fstree.c lib/common/statistics.c -libcommon_a_SOURCES += lib/common/inode_stat.c +libcommon_a_SOURCES += lib/common/inode_stat.c lib/common/hardlink.c  libcommon_a_SOURCES += lib/common/print_version.c lib/common/data_reader_dump.c  libcommon_a_SOURCES += lib/common/compress.c lib/common/comp_opt.c  libcommon_a_SOURCES += lib/common/data_writer.c include/common.h diff --git a/lib/common/hardlink.c b/lib/common/hardlink.c new file mode 100644 index 0000000..c1fca8a --- /dev/null +++ b/lib/common/hardlink.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * hardlink.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "common.h" + +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> + +static size_t count_nodes(const sqfs_tree_node_t *n) +{ +	size_t count = n->children == NULL ? 1 : 0; + +	for (n = n->children; n != NULL; n = n->next) +		count += count_nodes(n); + +	return count; +} + +static size_t map_nodes(const sqfs_tree_node_t **list, +			const sqfs_tree_node_t *n, +			size_t idx) +{ +	if (n->children == NULL) +		list[idx++] = n; + +	for (n = n->children; n != NULL; n = n->next) +		idx = map_nodes(list, n, idx); + +	return idx; +} + +int sqfs_tree_find_hard_links(const sqfs_tree_node_t *root, +			      sqfs_hard_link_t **out) +{ +	sqfs_hard_link_t *hardlinks = NULL, *lnk = NULL; +	const sqfs_tree_node_t **list = NULL; +	size_t i, j, count; +	const char *name; +	bool is_dup; + +	count = count_nodes(root); +	list = malloc(sizeof(list[0]) * count); +	if (list == NULL) +		goto fail; + +	map_nodes(list, root, 0); + +	for (i = 0; i < count; ++i) { +		name = (const char *)list[i]->name; +		if (!is_filename_sane(name, false)) +			continue; + +		is_dup = false; + +		for (j = 0; j < i; ++j) { +			if (list[j]->inode->base.inode_number == +			    list[i]->inode->base.inode_number) { +				name = (const char *)list[j]->name; +				if (!is_filename_sane(name, false)) +					continue; + +				is_dup = true; +				break; +			} +		} + +		if (is_dup) { +			lnk = calloc(1, sizeof(*lnk)); +			if (lnk == NULL) +				goto fail; + +			lnk->inode_number = list[j]->inode->base.inode_number; +			lnk->target = sqfs_tree_node_get_path(list[j]); +			if (lnk->target == NULL) +				goto fail; + +			if (canonicalize_name(lnk->target) == 0) { +				lnk->next = hardlinks; +				hardlinks = lnk; +			} else { +				free(lnk->target); +				free(lnk); +			} +		} +	} + +	*out = hardlinks; +	return 0; +fail: +	perror("detecting hard links in file system tree"); +	free(lnk); +	while (hardlinks != NULL) { +		lnk = hardlinks; +		hardlinks = hardlinks->next; +		free(lnk->target); +		free(lnk); +	} +	free(list); +	return -1; +} | 
