diff --git a/archival/dpkg.c b/archival/dpkg.c index 6cab77f38..df894472c 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -38,6 +38,7 @@ * */ +#include #include #include #include @@ -1310,14 +1311,44 @@ void purge_package(const unsigned int package_num) set_status(status_num, "not-installed", 3); } +static archive_handle_t *deb_extract(const char *filename, const char *ar_name, + const char *tar_gz_name, char *prefix, void (*deb_action_data)(struct archive_handle_s *)) +{ + archive_handle_t *ar_archive; + archive_handle_t *tar_gz_archive; + + /* Setup the tar archive handle */ + tar_gz_archive = init_handle(); + tar_gz_archive->filter = filter_accept_reject_list; + tar_gz_archive->action_data = deb_action_data; + tar_gz_archive->buffer = prefix; + if (tar_gz_name) { + tar_gz_archive->accept = add_to_list(NULL, tar_gz_name); + } + + /* Setup an ar archive handle that refers to the gzip sub archive */ + ar_archive = init_handle(); + ar_archive->action_data_subarchive = get_header_tar_gz; + ar_archive->sub_archive = tar_gz_archive; + ar_archive->filter = filter_accept_reject_list; + ar_archive->accept = add_to_list(NULL, ar_name); + + tar_gz_archive->src_fd = ar_archive->src_fd = xopen(filename, O_RDONLY); + + unpack_ar_archive(ar_archive); + close(ar_archive->src_fd); + + return(ar_archive->sub_archive); +} + void unpack_package(deb_file_t *deb_file) { const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; const unsigned int status_num = search_status_hashtable(package_name); const unsigned int status_package_num = status_hashtable[status_num]->package; - - FILE *out_stream; char *info_prefix; + archive_handle_t *archive_handle; + FILE *out_stream; /* If existing version, remove it first */ if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { @@ -1333,8 +1364,8 @@ void unpack_package(deb_file_t *deb_file) /* Extract control.tar.gz to /var/lib/dpkg/info/.filename */ info_prefix = (char *) xmalloc(strlen(package_name) + 20 + 4 + 2); sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs | extract_unconditional), info_prefix, NULL); + deb_extract(deb_file->filename, "control.tar.gz", NULL, info_prefix, data_extract_all_prefix); /* Run the preinst prior to extracting */ if (run_package_script(package_name, "preinst") != 0) { /* when preinst returns exit code != 0 then quit installation process */ @@ -1342,12 +1373,17 @@ void unpack_package(deb_file_t *deb_file) } /* Extract data.tar.gz to the root directory */ - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs | extract_unconditional), "/", NULL); + archive_handle = deb_extract(deb_file->filename, "data.tar.gz", NULL, NULL, data_extract_all); /* Create the list file */ strcat(info_prefix, "list"); out_stream = xfopen(info_prefix, "w"); - deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), "/", NULL); + while (archive_handle->passed) { + /* blindly skip over the leading '.' */ + fputs(archive_handle->passed->data + 1, out_stream); + fputc('\n', out_stream); + archive_handle->passed = archive_handle->passed->link; + } fclose(out_stream); /* change status */ @@ -1440,8 +1476,10 @@ int dpkg_main(int argc, char **argv) deb_file = xrealloc(deb_file, sizeof(deb_file_t *) * (deb_count + 2)); deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); if (dpkg_opt & dpkg_opt_filename) { + archive_handle_t *archive_handle; deb_file[deb_count]->filename = xstrdup(argv[optind]); - deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control"); + archive_handle = deb_extract(argv[optind], "control.tar.gz", "./control", NULL, data_extract_to_buffer); + deb_file[deb_count]->control_file = archive_handle->buffer; if (deb_file[deb_count]->control_file == NULL) { error_msg_and_die("Couldnt extract control file"); } diff --git a/archival/libunarchive/Makefile.in b/archival/libunarchive/Makefile.in index e559cb40e..87c888b0b 100644 --- a/archival/libunarchive/Makefile.in +++ b/archival/libunarchive/Makefile.in @@ -26,7 +26,9 @@ LIBUNARCHIVE-y:= \ \ data_skip.o \ data_extract_all.o \ + data_extract_all_prefix.o \ data_extract_to_stdout.o \ + data_extract_to_buffer.o \ \ filter_accept_all.o \ filter_accept_list.o \ diff --git a/archival/libunarchive/data_extract_all_prefix.c b/archival/libunarchive/data_extract_all_prefix.c new file mode 100644 index 000000000..e4e93fc74 --- /dev/null +++ b/archival/libunarchive/data_extract_all_prefix.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "libbb.h" +#include "unarchive.h" + +extern void data_extract_all_prefix(archive_handle_t *archive_handle) +{ + char *name_ptr = archive_handle->file_header->name; + + name_ptr += strspn(name_ptr, "./"); + if (name_ptr[0] != '\0') { + archive_handle->file_header->name = xmalloc(strlen(archive_handle->buffer) + 2 + strlen(name_ptr)); + sprintf(archive_handle->file_header->name, "%s%s", archive_handle->buffer, name_ptr); + data_extract_all(archive_handle); + } + return; +} diff --git a/archival/libunarchive/data_extract_to_buffer.c b/archival/libunarchive/data_extract_to_buffer.c new file mode 100644 index 000000000..02ee4b362 --- /dev/null +++ b/archival/libunarchive/data_extract_to_buffer.c @@ -0,0 +1,11 @@ +#include +#include +#include "unarchive.h" +#include "libbb.h" + +extern void data_extract_to_buffer(archive_handle_t *archive_handle) +{ + archive_handle->buffer = xmalloc(archive_handle->file_header->size + 1); + + xread_all(archive_handle->src_fd, archive_handle->buffer, archive_handle->file_header->size); +} diff --git a/include/unarchive.h b/include/unarchive.h index 956c74fb8..d9cf3c05c 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -57,6 +57,9 @@ typedef struct archive_handle_s { /* Count the number of bytes processed */ off_t offset; + /* Temperary storage */ + char *buffer; + /* Misc. stuff */ unsigned char flags; @@ -70,10 +73,11 @@ extern char filter_accept_reject_list(const llist_t *accept_list, const llist_t extern void unpack_ar_archive(archive_handle_t *ar_archive); -extern void data_gunzip(archive_handle_t *archive_handle); extern void data_skip(archive_handle_t *archive_handle); extern void data_extract_all(archive_handle_t *archive_handle); +extern void data_extract_all_prefix(archive_handle_t *archive_handle); extern void data_extract_to_stdout(archive_handle_t *archive_handle); +extern void data_extract_to_buffer(archive_handle_t *archive_handle); extern void header_skip(const file_header_t *file_header); extern void header_list(const file_header_t *file_header);