diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-05-24 16:56:53 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-05-30 17:49:40 +0200 |
commit | 8aa0366b85ce621ec54637ab4f9d37ad1e636e8f (patch) | |
tree | e92f60bbb761211363005386f16d254d46a19120 /bin/sqfs2tar/write_tree.c | |
parent | 59631ccfde23d175e97bda016923bf9cbabbd92a (diff) |
Cleanup: try to split sqfs2tar.c in a reasonable way
This comit breaks sqfs2tar into multiple files:
- options.c contains the command line argument processing
- write_tree.c contains the code for generating the actual tar archive
- sqfs2tar.c contains what is left
- A header is added for glueing it all together.
No actual code is changed.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'bin/sqfs2tar/write_tree.c')
-rw-r--r-- | bin/sqfs2tar/write_tree.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/bin/sqfs2tar/write_tree.c b/bin/sqfs2tar/write_tree.c new file mode 100644 index 0000000..545adc1 --- /dev/null +++ b/bin/sqfs2tar/write_tree.c @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * write_tree.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "sqfs2tar.h" + +static unsigned int record_counter; + +static int get_xattrs(const char *name, const sqfs_inode_generic_t *inode, + tar_xattr_t **out) +{ + tar_xattr_t *list = NULL, *ent; + sqfs_xattr_value_t *value; + sqfs_xattr_entry_t *key; + sqfs_xattr_id_t desc; + sqfs_u32 index; + size_t i; + int ret; + + if (xr == NULL) + return 0; + + sqfs_inode_get_xattr_index(inode, &index); + + if (index == 0xFFFFFFFF) + return 0; + + ret = sqfs_xattr_reader_get_desc(xr, index, &desc); + if (ret) { + sqfs_perror(name, "resolving xattr index", ret); + return -1; + } + + ret = sqfs_xattr_reader_seek_kv(xr, &desc); + if (ret) { + sqfs_perror(name, "locating xattr key-value pairs", ret); + return -1; + } + + for (i = 0; i < desc.count; ++i) { + ret = sqfs_xattr_reader_read_key(xr, &key); + if (ret) { + sqfs_perror(name, "reading xattr key", ret); + goto fail; + } + + ret = sqfs_xattr_reader_read_value(xr, key, &value); + if (ret) { + sqfs_perror(name, "reading xattr value", ret); + free(key); + goto fail; + } + + ent = calloc(1, sizeof(*ent) + strlen((const char *)key->key) + + value->size + 2); + if (ent == NULL) { + perror("creating xattr entry"); + free(key); + free(value); + goto fail; + } + + ent->key = ent->data; + strcpy(ent->key, (const char *)key->key); + + ent->value = (sqfs_u8 *)ent->key + strlen(ent->key) + 1; + memcpy(ent->value, value->value, value->size + 1); + + ent->value_len = value->size; + ent->next = list; + list = ent; + + free(key); + free(value); + } + + *out = list; + return 0; +fail: + while (list != NULL) { + ent = list; + list = list->next; + free(ent); + } + return -1; +} + +int write_tree_dfs(const sqfs_tree_node_t *n) +{ + tar_xattr_t *xattr = NULL, *xit; + sqfs_hard_link_t *lnk = NULL; + char *name, *target; + struct stat sb; + size_t len; + int ret; + + inode_stat(n, &sb); + + if (n->parent == NULL) { + if (root_becomes == NULL) + goto skip_hdr; + + len = strlen(root_becomes); + name = malloc(len + 2); + if (name == NULL) { + perror("creating root directory"); + return -1; + } + + memcpy(name, root_becomes, len); + name[len] = '/'; + name[len + 1] = '\0'; + } else { + if (!is_filename_sane((const char *)n->name, false)) { + fprintf(stderr, "Found a file named '%s', skipping.\n", + n->name); + if (dont_skip) { + fputs("Not allowed to skip files, aborting!\n", + stderr); + return -1; + } + return 0; + } + + name = sqfs_tree_node_get_path(n); + if (name == NULL) { + perror("resolving tree node path"); + return -1; + } + + if (canonicalize_name(name)) + goto out_skip; + + for (lnk = links; lnk != NULL; lnk = lnk->next) { + if (lnk->inode_number == n->inode->base.inode_number) { + if (strcmp(name, lnk->target) == 0) + lnk = NULL; + break; + } + } + + name = assemble_tar_path(name, S_ISDIR(sb.st_mode)); + if (name == NULL) + return -1; + } + + if (lnk != NULL) { + ret = write_hard_link(out_file, &sb, name, lnk->target, + record_counter++); + free(name); + return ret; + } + + if (!no_xattr) { + if (get_xattrs(name, n->inode, &xattr)) { + free(name); + return -1; + } + } + + target = S_ISLNK(sb.st_mode) ? (char *)n->inode->extra : NULL; + ret = write_tar_header(out_file, &sb, name, target, xattr, + record_counter++); + + while (xattr != NULL) { + xit = xattr; + xattr = xattr->next; + free(xit); + } + + if (ret > 0) + goto out_skip; + + if (ret < 0) { + free(name); + return -1; + } + + if (S_ISREG(sb.st_mode)) { + if (sqfs_data_reader_dump(name, data, n->inode, out_file, + super.block_size, false)) { + free(name); + return -1; + } + + if (padd_file(out_file, sb.st_size)) { + free(name); + return -1; + } + } + + free(name); +skip_hdr: + 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; +} |