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: |