diff options
Diffstat (limited to 'tar')
| -rw-r--r-- | tar/sqfs2tar.c | 319 | 
1 files changed, 219 insertions, 100 deletions
| diff --git a/tar/sqfs2tar.c b/tar/sqfs2tar.c index 253e437..43df40b 100644 --- a/tar/sqfs2tar.c +++ b/tar/sqfs2tar.c @@ -10,7 +10,6 @@  #include "sqfs/compress.h"  #include "data_reader.h"  #include "highlevel.h" -#include "fstree.h"  #include "util.h"  #include "tar.h" @@ -75,13 +74,11 @@ static bool dont_skip = false;  static bool keep_as_dir = false;  static bool no_xattr = false; -static const char *current_subdir = NULL; -  static char **subdirs = NULL;  static size_t num_subdirs = 0;  static size_t max_subdirs = 0; -static fstree_t fs; +static sqfs_xattr_reader_t *xr;  static data_reader_t *data;  static sqfs_file_t *file;  static sqfs_super_t super; @@ -186,138 +183,215 @@ static int terminate_archive(void)  			  buffer, sizeof(buffer));  } -static tar_xattr_t *gen_xattr_list(tree_xattr_t *xattr) +static int get_xattrs(const sqfs_inode_generic_t *inode, tar_xattr_t **out)  { -	const char *key, *value; -	tar_xattr_t *list; +	tar_xattr_t *list = NULL, *ent; +	sqfs_xattr_value_t *value; +	sqfs_xattr_entry_t *key; +	sqfs_xattr_id_t desc; +	uint32_t index;  	size_t i; -	list = alloc_array(sizeof(list[0]), xattr->num_attr); -	if (list == NULL) { -		perror("creating xattr list"); -		return NULL; +	if (xr == NULL) +		return 0; + +	switch (inode->base.type) { +	case SQFS_INODE_EXT_DIR: +		index = inode->data.dir_ext.xattr_idx; +		break; +	case SQFS_INODE_EXT_FILE: +		index = inode->data.file_ext.xattr_idx; +		break; +	case SQFS_INODE_EXT_SLINK: +		index = inode->data.slink_ext.xattr_idx; +		break; +	case SQFS_INODE_EXT_BDEV: +	case SQFS_INODE_EXT_CDEV: +		index = inode->data.dev_ext.xattr_idx; +		break; +	case SQFS_INODE_EXT_FIFO: +	case SQFS_INODE_EXT_SOCKET: +		index = inode->data.ipc_ext.xattr_idx; +		break; +	default: +		return 0;  	} -	for (i = 0; i < xattr->num_attr; ++i) { -		key = str_table_get_string(&fs.xattr_keys, -					   xattr->attr[i].key_index); -		value = str_table_get_string(&fs.xattr_values, -					     xattr->attr[i].value_index); +	if (index == 0xFFFFFFFF) +		return 0; -		list[i].key = (char *)key; -		list[i].value = (char *)value; +	if (sqfs_xattr_reader_get_desc(xr, index, &desc)) { +		fputs("Error resolving xattr index\n", stderr); +		return -1; +	} -		if (i + 1 < xattr->num_attr) { -			list[i].next = list + i + 1; -		} else { -			list[i].next = NULL; +	if (sqfs_xattr_reader_seek_kv(xr, &desc)) { +		fputs("Error locating xattr key-value pairs\n", stderr); +		return -1; +	} + +	for (i = 0; i < desc.count; ++i) { +		if (sqfs_xattr_reader_read_key(xr, &key)) { +			fputs("Error reading xattr key\n", stderr); +			return -1;  		} + +		if (sqfs_xattr_reader_read_value(xr, key, &value)) { +			fputs("Error reading xattr value\n", stderr); +			free(key); +			return -1; +		} + +		ent = calloc(1, sizeof(*ent) + strlen((const char *)key->key) + +			     value->size + 2); +		if (ent == NULL) { +			perror("creating xattr entry"); +			goto fail; +		} + +		ent->key = ent->data; +		strcpy(ent->key, (const char *)key->key); + +		ent->value = ent->key + strlen(ent->key) + 1; +		memcpy(ent->value, value->value, value->size + 1); + +		ent->next = list; +		list = ent; + +		free(key); +		free(value);  	} -	return list; +	*out = list; +	return 0; +fail: +	while (list != NULL) { +		ent = list; +		list = list->next; +		free(ent); +	} +	return -1;  } -static int write_tree_dfs(tree_node_t *n) +static int write_tree_dfs(const sqfs_tree_node_t *n)  { -	tar_xattr_t *xattr = NULL; -	size_t len, name_len; +	tar_xattr_t *xattr = NULL, *xit;  	char *name, *target;  	struct stat sb;  	int ret; -	if (n->parent == NULL && S_ISDIR(n->mode)) +	if (n->parent == NULL && S_ISDIR(n->inode->base.mode))  		goto skip_hdr; -	name = fstree_get_path(n); +	name = sqfs_tree_node_get_path(n);  	if (name == NULL) {  		perror("resolving tree node path");  		return -1;  	} -	ret = canonicalize_name(name); -	assert(ret == 0); - -	if (current_subdir != NULL && !keep_as_dir) { -		if (strcmp(name, current_subdir) == 0) { -			free(name); -			goto skip_hdr; -		} - -		len = strlen(current_subdir); -		name_len = strlen(name); - -		assert(name_len > len); -		assert(name[len] == '/'); - -		memmove(name, name + len + 1, name_len - len); -	} +	if (canonicalize_name(name)) +		goto out_skip; -	fstree_node_stat(&fs, n, &sb); +	inode_stat(n, &sb); -	if (!no_xattr && n->xattr != NULL) { -		xattr = gen_xattr_list(n->xattr); -		if (xattr == NULL) { -			free(name); +	if (!no_xattr) { +		if (get_xattrs(n->inode, &xattr))  			return -1; -		}  	} -	target = S_ISLNK(sb.st_mode) ? n->data.slink_target : NULL; +	target = S_ISLNK(sb.st_mode) ? n->inode->slink_target : NULL;  	ret = write_tar_header(STDOUT_FILENO, &sb, name, target, xattr,  			       record_counter++); -	free(xattr); -	if (ret > 0) { -		if (dont_skip) { -			fputs("Not allowed to skip files, aborting!\n", -			      stderr); -			ret = -1; -		} else { -			fprintf(stderr, "Skipping %s\n", name); -			ret = 0; -		} -		free(name); -		return ret; +	while (xattr != NULL) { +		xit = xattr; +		xattr = xattr->next; +		free(xit);  	} -	free(name); +	if (ret > 0) +		goto out_skip; +	free(name);  	if (ret < 0)  		return -1; -	if (S_ISREG(n->mode)) { -		if (data_reader_dump_file(data, n->data.file, -					  STDOUT_FILENO, false)) { +	if (S_ISREG(sb.st_mode)) { +		if (data_reader_dump(data, n->inode, STDOUT_FILENO, false))  			return -1; -		} -		if (padd_file(STDOUT_FILENO, n->data.file->size, 512)) +		if (padd_file(STDOUT_FILENO, sb.st_size, 512))  			return -1;  	}  skip_hdr: -	if (S_ISDIR(n->mode)) { -		for (n = n->data.dir->children; n != NULL; n = n->next) { -			if (write_tree_dfs(n)) -				return -1; +	for (n = n->children; n != NULL; n = n->next) { +		if (write_tree_dfs(n)) +			return -1; +	} +	return 0; +out_skip: +	if (dont_skip) { +		fputs("Not allowed to skip files, aborting!\n", stderr); +		ret = -1; +	} else { +		fprintf(stderr, "Skipping %s\n", name); +		ret = 0; +	} +	free(name); +	return ret; +} + +static sqfs_tree_node_t *tree_merge(sqfs_tree_node_t *lhs, +				    sqfs_tree_node_t *rhs) +{ +	sqfs_tree_node_t *head = NULL, **next_ptr = &head; +	sqfs_tree_node_t *it, *l, *r; +	int diff; + +	while (lhs->children != NULL && rhs->children != NULL) { +		diff = strcmp((const char *)lhs->children->name, +			      (const char *)rhs->children->name); + +		if (diff < 0) { +			it = lhs->children; +			lhs->children = lhs->children->next; +		} else if (diff > 0) { +			it = rhs->children; +			rhs->children = rhs->children->next; +		} else { +			l = lhs->children; +			lhs->children = lhs->children->next; + +			r = rhs->children; +			rhs->children = rhs->children->next; + +			it = tree_merge(l, r);  		} + +		*next_ptr = it; +		next_ptr = &it->next;  	} -	return 0; +	it = (lhs->children != NULL ? lhs->children : rhs->children); +	*next_ptr = it; + +	sqfs_dir_tree_destroy(rhs); +	lhs->children = head; +	return lhs;  }  int main(int argc, char **argv)  { -	int rdtree_flags = 0, status = EXIT_FAILURE; +	sqfs_tree_node_t *root = NULL, *subtree; +	int flags, ret, status = EXIT_FAILURE;  	sqfs_compressor_config_t cfg;  	sqfs_compressor_t *cmp; -	tree_node_t *root; +	sqfs_id_table_t *idtbl; +	sqfs_dir_reader_t *dr;  	size_t i;  	process_args(argc, argv); -	if (!no_xattr) -		rdtree_flags |= RDTREE_READ_XATTR; -  	file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY);  	if (file == NULL) {  		perror(filename); @@ -347,46 +421,91 @@ int main(int argc, char **argv)  			goto out_cmp;  	} -	if (deserialize_fstree(&fs, &super, cmp, file, rdtree_flags)) +	idtbl = sqfs_id_table_create(); + +	if (idtbl == NULL) { +		perror("creating ID table");  		goto out_cmp; +	} -	fstree_gen_file_list(&fs); +	if (sqfs_id_table_read(idtbl, file, &super, cmp)) { +		fputs("error loading ID table\n", stderr); +		goto out_id; +	}  	data = data_reader_create(file, &super, cmp);  	if (data == NULL) -		goto out; +		goto out_data; -	for (i = 0; i < num_subdirs; ++i) { -		root = fstree_node_from_path(&fs, subdirs[i]); -		if (root == NULL) { -			perror(subdirs[i]); -			goto out; -		} +	dr = sqfs_dir_reader_create(&super, cmp, file); +	if (dr == NULL) { +		perror("creating dir reader"); +		goto out_data; +	} -		if (!S_ISDIR(root->mode)) { -			fprintf(stderr, "%s is not a directory\n", subdirs[i]); -			goto out; +	if (!no_xattr && (super.flags & SQFS_FLAG_NO_XATTRS)) { +		xr = sqfs_xattr_reader_create(file, &super, cmp); +		if (xr == NULL) { +			goto out_dr;  		} -		current_subdir = subdirs[i]; - -		if (write_tree_dfs(root)) -			goto out; +		if (sqfs_xattr_reader_load_locations(xr)) { +			fputs("error loading xattr table\n", stderr); +			goto out_xr; +		}  	} -	current_subdir = NULL; -  	if (num_subdirs == 0) { -		if (write_tree_dfs(fs.root)) +		ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, NULL, +							 0, &root); +		if (ret) { +			fputs("error loading file system tree", stderr);  			goto out; +		} +	} else { +		flags = 0; + +		if (keep_as_dir || num_subdirs > 1) +			flags = SQFS_TREE_STORE_PARENTS; + +		for (i = 0; i < num_subdirs; ++i) { +			ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, +								 subdirs[i], +								 flags, +								 &subtree); +			if (ret) { +				fprintf(stderr, "error loading '%s'\n", +					subdirs[i]); +				goto out; +			} + +			if (root == NULL) { +				root = subtree; +			} else { +				root = tree_merge(root, subtree); +			} +		}  	} +	if (write_tree_dfs(root)) +		goto out; +  	if (terminate_archive())  		goto out;  	status = EXIT_SUCCESS;  out: -	fstree_cleanup(&fs); +	if (root != NULL) +		sqfs_dir_tree_destroy(root); +out_xr: +	if (xr != NULL) +		sqfs_xattr_reader_destroy(xr); +out_dr: +	sqfs_dir_reader_destroy(dr); +out_data: +	data_reader_destroy(data); +out_id: +	sqfs_id_table_destroy(idtbl);  out_cmp:  	cmp->destroy(cmp);  out_fd: | 
