/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * sqfs2tar.c * * Copyright (C) 2019 David Oberhollenzer */ #include "sqfs2tar.h" sqfs_xattr_reader_t *xr; sqfs_data_reader_t *data; sqfs_super_t super; sqfs_ostream_t *out_file = NULL; static sqfs_file_t *file; char *assemble_tar_path(char *name, bool is_dir) { size_t len, new_len; char *temp; (void)is_dir; if (root_becomes == NULL && !is_dir) return name; new_len = strlen(name); if (root_becomes != NULL) new_len += strlen(root_becomes) + 1; if (is_dir) new_len += 1; temp = realloc(name, new_len + 1); if (temp == NULL) { perror("assembling tar entry filename"); free(name); return NULL; } name = temp; if (root_becomes != NULL) { len = strlen(root_becomes); memmove(name + len + 1, name, strlen(name) + 1); memcpy(name, root_becomes, len); name[len] = '/'; } if (is_dir) { len = strlen(name); if (len == 0 || name[len - 1] != '/') { name[len++] = '/'; name[len] = '\0'; } } return name; } static int terminate_archive(void) { char buffer[1024]; memset(buffer, '\0', sizeof(buffer)); return out_file->append(out_file, buffer, sizeof(buffer)); } 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; } 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) { sqfs_tree_node_t *root = NULL, *subtree = NULL; int flags, ret, status = EXIT_FAILURE; sqfs_compressor_t *cmp = NULL; sqfs_id_table_t *idtbl = NULL; sqfs_dir_reader_t *dr = NULL; sqfs_compressor_config_t cfg; size_t i; process_args(argc, argv); ret = ostream_open_stdout(&out_file); if (ret) { sqfs_perror("stdout", "creating stream wrapper", ret); goto out; } if (compressor > 0) { xfrm_stream_t *xfrm = compressor_stream_create(compressor,NULL); sqfs_ostream_t *strm; if (xfrm == NULL) goto out; strm = ostream_xfrm_create(out_file, xfrm); sqfs_drop(out_file); sqfs_drop(xfrm); out_file = strm; if (out_file == NULL) goto out; } file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY); if (file == NULL) { perror(filename); goto out; } ret = sqfs_super_read(&super, file); if (ret) { sqfs_perror(filename, "reading super block", ret); goto out; } sqfs_compressor_config_init(&cfg, super.compression_id, super.block_size, SQFS_COMP_FLAG_UNCOMPRESS); ret = sqfs_compressor_create(&cfg, &cmp); #ifdef WITH_LZO if (super.compression_id == SQFS_COMP_LZO && ret != 0) ret = lzo_compressor_create(&cfg, &cmp); #endif if (ret != 0) { sqfs_perror(filename, "creating compressor", ret); goto out; } idtbl = sqfs_id_table_create(0); if (idtbl == NULL) { perror("creating ID table"); goto out; } ret = sqfs_id_table_read(idtbl, file, &super, cmp); if (ret) { sqfs_perror(filename, "loading ID table", ret); goto out; } data = sqfs_data_reader_create(file, super.block_size, cmp, 0); if (data == NULL) { sqfs_perror(filename, "creating data reader", SQFS_ERROR_ALLOC); goto out; } ret = sqfs_data_reader_load_fragment_table(data, &super); if (ret) { sqfs_perror(filename, "loading fragment table", ret); goto out; } dr = sqfs_dir_reader_create(&super, cmp, file, 0); if (dr == NULL) { sqfs_perror(filename, "creating dir reader", SQFS_ERROR_ALLOC); goto out; } if (!no_xattr && !(super.flags & SQFS_FLAG_NO_XATTRS)) { xr = sqfs_xattr_reader_create(0); if (xr == NULL) { sqfs_perror(filename, "creating xattr reader", SQFS_ERROR_ALLOC); goto out; } ret = sqfs_xattr_reader_load(xr, &super, file, cmp); if (ret) { sqfs_perror(filename, "loading xattr table", ret); goto out; } } if (num_subdirs == 0) { ret = sqfs_dir_reader_get_full_hierarchy(dr, idtbl, NULL, 0, &root); if (ret) { sqfs_perror(filename, "loading filesystem tree", ret); 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) { sqfs_perror(subdirs[i], "loading filesystem " "tree", ret); goto out; } if (root == NULL) { root = subtree; } else { root = tree_merge(root, subtree); } } } if (write_tree(root)) goto out; if (terminate_archive()) goto out; ret = out_file->flush(out_file); if (ret) { sqfs_perror(out_file->get_filename(out_file), NULL, ret); goto out; } status = EXIT_SUCCESS; out: sqfs_dir_tree_destroy(root); sqfs_drop(xr); sqfs_drop(dr); sqfs_drop(data); sqfs_drop(idtbl); sqfs_drop(cmp); sqfs_drop(file); sqfs_drop(out_file); for (i = 0; i < num_subdirs; ++i) free(subdirs[i]); free(subdirs); free(root_becomes); return status; }