New common unarchive code.
No binary (build failed)
—
(log yok)
| @@ -21,41 +21,100 @@ | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| + | * There is no signle standard to adhere to so ar may not portable |
| + | * between different systems |
| + | * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html |
| */ | |
| + | #include <sys/types.h> |
| #include <fcntl.h> | |
| + | #include <fnmatch.h> |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <time.h> |
| + | #include <utime.h> |
| + | #include <unistd.h> |
| #include <getopt.h> | |
| #include "unarchive.h" | |
| #include "busybox.h" | |
| + | static void header_verbose_list_ar(const file_header_t *file_header) |
| + | { |
| + | const char *mode = mode_string(file_header->mode); |
| + | char *mtime; |
| + | |
| + | mtime = ctime(&file_header->mtime); |
| + | mtime[16] = ' '; |
| + | memmove(&mtime[17], &mtime[20], 4); |
| + | mtime[21] = '\0'; |
| + | printf("%s %d/%d%7d %s %s\n", &mode[1], file_header->uid, file_header->gid, (int) file_header->size, &mtime[4], file_header->name); |
| + | } |
| + | |
| + | #if defined CONFIG_TAR | defined CONFIG_DPKG_DEB | defined CONFIG_CPIO |
| + | /* This is simpler than data_extract_all */ |
| + | static void data_extract_regular_file(archive_handle_t *archive_handle) |
| + | { |
| + | file_header_t *file_header; |
| + | int dst_fd; |
| + | |
| + | file_header = archive_handle->file_header; |
| + | dst_fd = xopen(file_header->name, O_WRONLY | O_CREAT); |
| + | copy_file_chunk_fd(archive_handle->src_fd, dst_fd, file_header->size); |
| + | close(dst_fd); |
| + | |
| + | chmod(file_header->name, file_header->mode); |
| + | chown(file_header->name, file_header->uid, file_header->gid); |
| + | |
| + | if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { |
| + | struct utimbuf t; |
| + | t.actime = t.modtime = file_header->mtime; |
| + | utime(file_header->name, &t); |
| + | } |
| + | |
| + | return; |
| + | } |
| + | #endif |
| + | |
| extern int ar_main(int argc, char **argv) | |
| { | |
| - | FILE *src_stream = NULL; |
| - | char **extract_names = NULL; |
| - | char ar_magic[8]; |
| - | int extract_function = extract_unconditional; |
| + | archive_handle_t *archive_handle; |
| int opt; | |
| - | int num_of_entries = 0; |
| - | extern off_t archive_offset; |
| - | while ((opt = getopt(argc, argv, "ovtpx")) != -1) { |
| + | #if defined CONFIG_TAR | defined CONFIG_DPKG_DEB | defined CONFIG_CPIO |
| + | archive_handle = init_handle(); |
| + | #else |
| + | char magic[8]; |
| + | |
| + | archive_handle = xcalloc(1, sizeof(archive_handle_t)); |
| + | archive_handle->filter = filter_accept_all; |
| + | archive_handle->action_data = data_skip; |
| + | archive_handle->action_header = header_skip; |
| + | archive_handle->file_header =xmalloc(sizeof(file_header_t)); |
| + | #endif |
| + | |
| + | while ((opt = getopt(argc, argv, "covtpxX")) != -1) { |
| switch (opt) { | |
| - | case 'o': |
| - | extract_function |= extract_preserve_date; |
| + | case 'p': /* print */ |
| + | archive_handle->action_data = data_extract_to_stdout; |
| break; | |
| - | case 'v': |
| - | extract_function |= extract_verbose_list; |
| + | case 't': /* list contents */ |
| + | archive_handle->action_header = header_list; |
| break; | |
| - | case 't': |
| - | extract_function |= extract_list; |
| + | case 'X': |
| + | archive_handle->action_header = header_verbose_list_ar; |
| + | case 'x': /* extract */ |
| + | #if defined CONFIG_TAR | defined CONFIG_DPKG_DEB | defined CONFIG_CPIO |
| + | archive_handle->action_data = data_extract_all; |
| + | #else |
| + | archive_handle->action_data = data_extract_regular_file; |
| + | #endif |
| break; | |
| - | case 'p': |
| - | extract_function |= extract_to_stdout; |
| + | /* Modifiers */ |
| + | case 'o': /* preserve original dates */ |
| + | archive_handle->flags |= ARCHIVE_PRESERVE_DATE; |
| break; | |
| - | case 'x': |
| - | extract_function |= extract_all_to_fs; |
| + | case 'v': /* verbose */ |
| + | archive_handle->action_header = header_verbose_list_ar; |
| break; | |
| default: | |
| show_usage(); | |
| @@ -67,24 +126,26 @@ extern int ar_main(int argc, char **argv) | |
| show_usage(); | |
| } | |
| - | src_stream = xfopen(argv[optind++], "r"); |
| + | archive_handle->src_fd = xopen(argv[optind++], O_RDONLY); |
| - | /* check ar magic */ |
| - | fread(ar_magic, 1, 8, src_stream); |
| - | archive_offset = 8; |
| - | if (strncmp(ar_magic,"!<arch>",7) != 0) { |
| - | error_msg_and_die("invalid magic"); |
| - | } |
| - | |
| - | /* Create a list of files to extract */ |
| + | /* TODO: This is the same as in tar, seperate function ? */ |
| while (optind < argc) { | |
| - | extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); |
| - | extract_names[num_of_entries] = xstrdup(argv[optind]); |
| - | num_of_entries++; |
| - | extract_names[num_of_entries] = NULL; |
| + | archive_handle->filter = filter_accept_list; |
| + | archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]); |
| optind++; | |
| } | |
| - | unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names, NULL); |
| + | #if defined CONFIG_DPKG_DEB |
| + | unpack_ar_archive(archive_handle); |
| + | #else |
| + | xread_all(archive_handle->src_fd, magic, 7); |
| + | if (strncmp(magic, "!<arch>", 7) != 0) { |
| + | error_msg_and_die("Invalid ar magic"); |
| + | } |
| + | archive_handle->offset += 7; |
| + | |
| + | while (get_header_ar(archive_handle) == EXIT_SUCCESS); |
| + | #endif |
| + | |
| return EXIT_SUCCESS; | |
| } | |
| @@ -7,10 +7,16 @@ mainmenu_option next_comment | |
| comment 'Archival Utilities' | |
| bool 'ar' CONFIG_AR | |
| + | if [ "$CONFIG_AR" = "y" ] ; then |
| + | bool ' Enable support for long filenames (not need for debs)' CONFIG_FEATURE_AR_LONG_FILENAMES |
| + | fi |
| bool 'bunzip2' CONFIG_BUNZIP2 | |
| bool 'cpio' CONFIG_CPIO | |
| bool 'dpkg' CONFIG_DPKG | |
| bool 'dpkg_deb' CONFIG_DPKG_DEB | |
| + | if [ "$CONFIG_DPKG_DEB" = "y" ] ; then |
| + | bool ' -x support only' CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY |
| + | fi |
| bool 'gunzip' CONFIG_GUNZIP | |
| bool 'gzip' CONFIG_GZIP | |
| bool 'rpm2cpio' CONFIG_RPM2CPIO | |
| @@ -31,66 +31,210 @@ | |
| #include "unarchive.h" | |
| #include "busybox.h" | |
| + | typedef struct hardlinks_s { |
| + | file_header_t *entry; |
| + | int inode; |
| + | struct hardlinks_s *next; |
| + | } hardlinks_t; |
| + | |
| extern int cpio_main(int argc, char **argv) | |
| { | |
| - | FILE *src_stream = stdin; |
| - | char **extract_names = NULL; |
| - | int extract_function = 0; |
| - | int num_of_entries = 0; |
| - | int opt = 0; |
| - | mode_t oldmask = 0; |
| + | archive_handle_t *archive_handle; |
| + | int opt; |
| + | |
| + | /* Initialise */ |
| + | archive_handle = init_handle(); |
| + | archive_handle->src_fd = fileno(stdin); |
| + | archive_handle->action_header = header_list; |
| while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { | |
| switch (opt) { | |
| - | case 'i': // extract |
| - | extract_function |= extract_all_to_fs; |
| + | case 'i': /* extract */ |
| + | archive_handle->action_data = data_extract_all; |
| break; | |
| - | case 'd': // create _leading_ directories |
| - | extract_function |= extract_create_leading_dirs; |
| - | oldmask = umask(077); /* Make make_directory act like GNU cpio */ |
| + | case 'd': /* create _leading_ directories */ |
| + | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; |
| break; | |
| - | case 'm': // preserve modification time |
| - | extract_function |= extract_preserve_date; |
| + | case 'm': /* preserve modification time */ |
| + | archive_handle->flags |= ARCHIVE_PRESERVE_DATE; |
| break; | |
| - | case 'v': // verbosly list files |
| - | extract_function |= extract_verbose_list; |
| + | case 'v': /* verbosly list files */ |
| + | archive_handle->action_header = header_verbose_list; |
| break; | |
| - | case 'u': // unconditional |
| - | extract_function |= extract_unconditional; |
| + | case 'u': /* unconditional */ |
| + | archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
| break; | |
| - | case 't': // list files |
| - | extract_function |= extract_list; |
| + | case 't': /* list files */ |
| + | archive_handle->action_header = header_list; |
| break; | |
| case 'F': | |
| - | src_stream = xfopen(optarg, "r"); |
| + | archive_handle->src_fd = xopen(optarg, O_RDONLY); |
| break; | |
| default: | |
| show_usage(); | |
| } | |
| } | |
| - | if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) { |
| - | extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ |
| + | while (optind < argc) { |
| + | archive_handle->filter = filter_accept_list; |
| + | archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]); |
| + | optind++; |
| } | |
| - | if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) { |
| - | /* The meaning of v changes on extract */ |
| - | extract_function ^= extract_verbose_list; |
| - | extract_function |= extract_list; |
| + | while (1) { |
| + | static hardlinks_t *saved_hardlinks = NULL; |
| + | static unsigned short pending_hardlinks = 0; |
| + | file_header_t *file_header = archive_handle->file_header; |
| + | char cpio_header[110]; |
| + | int namesize; |
| + | char dummy[16]; |
| + | int major, minor, nlink, inode; |
| + | char extract_flag; |
| + | |
| + | if (pending_hardlinks) { /* Deal with any pending hardlinks */ |
| + | hardlinks_t *tmp; |
| + | hardlinks_t *oldtmp; |
| + | |
| + | tmp = saved_hardlinks; |
| + | oldtmp = NULL; |
| + | |
| + | while (tmp) { |
| + | error_msg_and_die("need to fix this\n"); |
| + | if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ |
| + | file_header = tmp->entry; |
| + | if (oldtmp) { |
| + | oldtmp->next = tmp->next; /* Remove item from linked list */ |
| + | } else { |
| + | saved_hardlinks = tmp->next; |
| + | } |
| + | free(tmp); |
| + | continue; |
| + | } |
| + | oldtmp = tmp; |
| + | tmp = tmp->next; |
| + | } |
| + | pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ |
| } | |
| - | while (optind < argc) { |
| - | extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); |
| - | extract_names[num_of_entries] = xstrdup(argv[optind]); |
| - | num_of_entries++; |
| - | extract_names[num_of_entries] = NULL; |
| - | optind++; |
| + | /* There can be padding before archive header */ |
| + | archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 4); |
| + | |
| + | if (xread_all_eof(archive_handle->src_fd, cpio_header, 110) == 0) { |
| + | return(EXIT_FAILURE); |
| + | } |
| + | archive_handle->offset += 110; |
| + | |
| + | if (strncmp(&cpio_header[0], "07070", 5) != 0) { |
| + | printf("cpio header is %x-%x-%x-%x-%x\n", |
| + | cpio_header[0], |
| + | cpio_header[1], |
| + | cpio_header[2], |
| + | cpio_header[3], |
| + | cpio_header[4]); |
| + | error_msg_and_die("Unsupported cpio format"); |
| + | } |
| + | |
| + | if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) { |
| + | error_msg_and_die("Unsupported cpio format, use newc or crc"); |
| + | } |
| + | |
| + | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", |
| + | dummy, &inode, (unsigned int*)&file_header->mode, |
| + | (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid, |
| + | &nlink, &file_header->mtime, &file_header->size, |
| + | dummy, &major, &minor, &namesize, dummy); |
| + | |
| + | file_header->name = (char *) xmalloc(namesize + 1); |
| + | xread(archive_handle->src_fd, file_header->name, namesize); /* Read in filename */ |
| + | file_header->name[namesize] = '\0'; |
| + | archive_handle->offset += namesize; |
| + | |
| + | /* Update offset amount and skip padding before file contents */ |
| + | archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 4); |
| + | |
| + | if (strcmp(file_header->name, "TRAILER!!!") == 0) { |
| + | printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */ |
| + | if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ |
| + | hardlinks_t *tmp = saved_hardlinks; |
| + | hardlinks_t *oldtmp = NULL; |
| + | while (tmp) { |
| + | error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); |
| + | oldtmp = tmp; |
| + | tmp = tmp->next; |
| + | free (oldtmp->entry->name); |
| + | free (oldtmp->entry); |
| + | free (oldtmp); |
| + | } |
| + | saved_hardlinks = NULL; |
| + | pending_hardlinks = 0; |
| } | |
| + | return(EXIT_FAILURE); |
| + | } |
| + | |
| + | if (S_ISLNK(file_header->mode)) { |
| + | file_header->link_name = (char *) xmalloc(file_header->size + 1); |
| + | xread(archive_handle->src_fd, file_header->link_name, file_header->size); |
| + | file_header->link_name[file_header->size] = '\0'; |
| + | archive_handle->offset += file_header->size; |
| + | file_header->size = 0; /* Stop possible seeks in future */ |
| + | } |
| + | if (nlink > 1 && !S_ISDIR(file_header->mode)) { |
| + | if (file_header->size == 0) { /* Put file on a linked list for later */ |
| + | hardlinks_t *new = xmalloc(sizeof(hardlinks_t)); |
| + | new->next = saved_hardlinks; |
| + | new->inode = inode; |
| + | new->entry = file_header; |
| + | saved_hardlinks = new; |
| + | continue; |
| + | } else { /* Found the file with data in */ |
| + | hardlinks_t *tmp = saved_hardlinks; |
| + | pending_hardlinks = 1; |
| + | while (tmp) { |
| + | if (tmp->inode == inode) { |
| + | tmp->entry->link_name = xstrdup(file_header->name); |
| + | nlink--; |
| + | } |
| + | tmp = tmp->next; |
| + | } |
| + | if (nlink > 1) { |
| + | error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); |
| + | } |
| + | } |
| + | } |
| + | file_header->device = (major << 8) | minor; |
| + | |
| + | extract_flag = FALSE; |
| + | if (archive_handle->filter(archive_handle->accept, archive_handle->reject, file_header->name) == EXIT_SUCCESS) { |
| + | struct stat statbuf; |
| - | unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names, NULL); |
| - | if (oldmask) { |
| - | umask(oldmask); /* Restore umask if we changed it */ |
| + | extract_flag = TRUE; |
| + | |
| + | /* Check if the file already exists */ |
| + | if (lstat (file_header->name, &statbuf) == 0) { |
| + | if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) { |
| + | /* Remove file if flag set or its older than the file to be extracted */ |
| + | if (unlink(file_header->name) == -1) { |
| + | perror_msg_and_die("Couldnt remove old file"); |
| + | } |
| + | } else { |
| + | if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) { |
| + | error_msg("%s not created: newer or same age file exists", file_header->name); |
| + | } |
| + | extract_flag = FALSE; |
| + | } |
| + | } |
| + | archive_handle->action_header(file_header); |
| + | } |
| + | |
| + | archive_handle->action_header(file_header); |
| + | if (extract_flag) { |
| + | archive_handle->action_data(archive_handle); |
| + | } else { |
| + | data_skip(archive_handle); |
| + | } |
| + | archive_handle->offset += file_header->size; |
| } | |
| - | return EXIT_SUCCESS; |
| + | |
| + | return(EXIT_SUCCESS); |
| } | |
| @@ -13,119 +13,100 @@ | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| */ | |
| - | |
| + | #include <fcntl.h> |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <unistd.h> |
| #include <getopt.h> | |
| #include "unarchive.h" | |
| #include "busybox.h" | |
| extern int dpkg_deb_main(int argc, char **argv) | |
| { | |
| - | char *prefix = NULL; |
| - | char *filename = NULL; |
| - | char *output_buffer = NULL; |
| + | archive_handle_t *ar_archive; |
| + | archive_handle_t *tar_gz_archive; |
| int opt = 0; | |
| - | int arg_type = 0; |
| - | int deb_extract_funct = extract_create_leading_dirs | extract_unconditional; |
| + | #ifndef CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY |
| + | const llist_t *control_tar_gz_llist = add_to_list(NULL, "control.tar.gz"); |
| + | #endif |
| + | #ifndef CONFIG_AR |
| + | char magic[7]; |
| + | #endif |
| + | |
| + | /* a .deb file is an ar archive that contain three files, |
| + | * data.tar.gz, control.tar.gz and debian |
| + | */ |
| - | const int arg_type_prefix = 1; |
| - | const int arg_type_field = 2; |
| - | const int arg_type_filename = 4; |
| - | // const int arg_type_un_ar_gz = 8; |
| + | /* Setup the tar archive handle */ |
| + | tar_gz_archive = init_handle(); |
| - | while ((opt = getopt(argc, argv, "ceftXxI")) != -1) { |
| + | /* 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_list; |
| + | ar_archive->accept = add_to_list(NULL, "data.tar.gz"); |
| + | |
| + | #ifndef CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY |
| + | while ((opt = getopt(argc, argv, "cefXx")) != -1) { |
| + | #else |
| + | while ((opt = getopt(argc, argv, "x")) != -1) { |
| + | #endif |
| switch (opt) { | |
| + | #ifndef CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY |
| case 'c': | |
| - | deb_extract_funct |= extract_data_tar_gz; |
| - | deb_extract_funct |= extract_verbose_list; |
| + | tar_gz_archive->action_header = header_verbose_list; |
| break; | |
| case 'e': | |
| - | arg_type = arg_type_prefix; |
| - | deb_extract_funct |= extract_control_tar_gz; |
| - | deb_extract_funct |= extract_all_to_fs; |
| + | ar_archive->accept = control_tar_gz_llist; |
| + | tar_gz_archive->action_data = data_extract_all; |
| break; | |
| case 'f': | |
| - | arg_type = arg_type_field; |
| - | deb_extract_funct |= extract_control_tar_gz; |
| - | deb_extract_funct |= extract_one_to_buffer; |
| - | filename = xstrdup("./control"); |
| - | break; |
| - | case 't': /* --fsys-tarfile, i just made up this short name */ |
| - | /* Integrate the functionality needed with some code from ar.c */ |
| - | error_msg_and_die("Option disabled"); |
| - | // arg_type = arg_type_un_ar_gz; |
| + | /* Print the entire control file |
| + | * it should accept a second argument which specifies a |
| + | * specific field to print */ |
| + | ar_archive->accept = control_tar_gz_llist; |
| + | tar_gz_archive->accept = add_to_list(NULL, "./control");; |
| + | tar_gz_archive->filter = filter_accept_list; |
| + | tar_gz_archive->action_data = data_extract_to_stdout; |
| break; | |
| case 'X': | |
| - | arg_type = arg_type_prefix; |
| - | deb_extract_funct |= extract_data_tar_gz; |
| - | deb_extract_funct |= extract_all_to_fs; |
| - | deb_extract_funct |= extract_list; |
| + | tar_gz_archive->action_header = header_list; |
| + | #endif |
| case 'x': | |
| - | arg_type = arg_type_prefix; |
| - | deb_extract_funct |= extract_data_tar_gz; |
| - | deb_extract_funct |= extract_all_to_fs; |
| - | break; |
| - | case 'I': |
| - | arg_type = arg_type_filename; |
| - | deb_extract_funct |= extract_control_tar_gz; |
| - | deb_extract_funct |= extract_one_to_buffer; |
| + | tar_gz_archive->action_data = data_extract_all; |
| break; | |
| default: | |
| show_usage(); | |
| } | |
| } | |
| - | if (optind == argc) { |
| + | if (optind + 2 < argc) { |
| show_usage(); | |
| } | |
| + | tar_gz_archive->src_fd = ar_archive->src_fd = xopen(argv[optind++], O_RDONLY); |
| + | |
| /* Workout where to extract the files */ | |
| - | if (arg_type == arg_type_prefix) { |
| - | /* argument is a dir name */ |
| - | if ((optind + 1) == argc ) { |
| - | prefix = xstrdup("./DEBIAN/"); |
| - | } else { |
| - | prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2); |
| - | strcpy(prefix, argv[optind + 1]); |
| - | /* Make sure the directory has a trailing '/' */ |
| - | if (last_char_is(prefix, '/') == NULL) { |
| - | strcat(prefix, "/"); |
| - | } |
| - | } |
| - | mkdir(prefix, 0777); |
| - | } |
| + | /* 2nd argument is a dir name */ |
| + | mkdir(argv[optind], 0777); |
| + | chdir(argv[optind]); |
| - | if (arg_type == arg_type_filename) { |
| - | if ((optind + 1) != argc) { |
| - | filename = xstrdup(argv[optind + 1]); |
| - | } else { |
| - | error_msg_and_die("-I currently requires a filename to be specified"); |
| - | } |
| + | #ifdef CONFIG_AR |
| + | unpack_ar_archive(ar_archive); |
| + | #else |
| + | xread_all(ar_archive->src_fd, magic, 7); |
| + | if (strncmp(magic, "!<arch>", 7) != 0) { |
| + | error_msg_and_die("Invalid ar magic"); |
| } | |
| + | ar_archive->offset += 7; |
| - | output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename); |
| + | while (get_header_ar(ar_archive) == EXIT_SUCCESS); |
| + | #endif |
| - | if ((arg_type == arg_type_filename) && (output_buffer != NULL)) { |
| - | puts(output_buffer); |
| - | } |
| - | else if (arg_type == arg_type_field) { |
| - | char *field = NULL; |
| - | char *name; |
| - | char *value; |
| - | int field_start = 0; |
| - | |
| - | while (1) { |
| - | field_start += read_package_field(&output_buffer[field_start], &name, &value); |
| - | if (name == NULL) { |
| - | break; |
| - | } |
| - | if (strcmp(name, argv[optind + 1]) == 0) { |
| - | puts(value); |
| - | } |
| - | free(field); |
| - | } |
| - | } |
| + | /* Cleanup */ |
| + | close (ar_archive->src_fd); |
| return(EXIT_SUCCESS); | |
| } | |
| + | |
| @@ -64,7 +64,12 @@ static char *license_msg[] = { | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <getopt.h> | |
| + | #include <sys/types.h> |
| + | #include <sys/stat.h> |
| + | #include <fcntl.h> |
| + | |
| #include "busybox.h" | |
| + | #include "unarchive.h" |
| const char gunzip_to_stdout = 1; | |
| const char gunzip_force = 2; | |
| @@ -100,23 +105,20 @@ extern int gunzip_main(int argc, char **argv) | |
| } | |
| do { | |
| - | FILE *in_file, *out_file; |
| struct stat stat_buf; | |
| const char *old_path = argv[optind]; | |
| const char *delete_path = NULL; | |
| char *new_path = NULL; | |
| + | int src_fd; |
| + | int dst_fd; |
| optind++; | |
| if (old_path == NULL || strcmp(old_path, "-") == 0) { | |
| - | in_file = stdin; |
| + | src_fd = fileno(stdin); |
| flags |= gunzip_to_stdout; | |
| } else { | |
| - | in_file = wfopen(old_path, "r"); |
| - | if (in_file == NULL) { |
| - | status = EXIT_FAILURE; |
| - | break; |
| - | } |
| + | src_fd = xopen(old_path, O_RDONLY); |
| /* Get the time stamp on the input file. */ | |
| if (stat(old_path, &stat_buf) < 0) { | |
| @@ -125,16 +127,16 @@ extern int gunzip_main(int argc, char **argv) | |
| } | |
| /* Check that the input is sane. */ | |
| - | if (isatty(fileno(in_file)) && ((flags & gunzip_force) == 0)) { |
| + | if (isatty(src_fd) && ((flags & gunzip_force) == 0)) { |
| error_msg_and_die | |
| ("compressed data not read from terminal. Use -f to force it."); | |
| } | |
| /* Set output filename and number */ | |
| if (flags & gunzip_test) { | |
| - | out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */ |
| + | dst_fd = xopen("/dev/null", O_WRONLY); /* why does test use filenum 2 ? */ |
| } else if (flags & gunzip_to_stdout) { | |
| - | out_file = stdout; |
| + | dst_fd = fileno(stdout); |
| } else { | |
| char *extension; | |
| @@ -151,7 +153,7 @@ extern int gunzip_main(int argc, char **argv) | |
| } | |
| /* Open output file */ | |
| - | out_file = xfopen(new_path, "w"); |
| + | dst_fd = xopen(new_path, O_WRONLY | O_CREAT); |
| /* Set permissions on the file */ | |
| chmod(new_path, stat_buf.st_mode); | |
| @@ -161,16 +163,22 @@ extern int gunzip_main(int argc, char **argv) | |
| } | |
| /* do the decompression, and cleanup */ | |
| - | if ((unzip(in_file, out_file) != 0) && (new_path)) { |
| + | check_header_gzip(src_fd); |
| + | if (inflate(src_fd, dst_fd) != 0) { |
| + | error_msg("Error inflating"); |
| + | } |
| + | check_trailer_gzip(src_fd); |
| + | |
| + | if ((status != EXIT_SUCCESS) && (new_path)) { |
| /* Unzip failed, remove new path instead of old path */ | |
| delete_path = new_path; | |
| } | |
| - | if (out_file != stdout) { |
| - | fclose(out_file); |
| + | if (dst_fd != fileno(stdout)) { |
| + | close(dst_fd); |
| } | |
| - | if (in_file != stdin) { |
| - | fclose(in_file); |
| + | if (src_fd != fileno(stdin)) { |
| + | close(src_fd); |
| } | |
| /* delete_path will be NULL if in test mode or from stdin */ | |
| @@ -22,14 +22,41 @@ ifndef $(LIBUNARCHIVE_DIR) | |
| LIBUNARCHIVE_DIR:=$(TOPDIR)archival/libunarchive/ | |
| endif | |
| - | LIBUNARCHIVE-y:=unarchive.o seek_sub_file.o |
| - | LIBUNARCHIVE-$(CONFIG_DPKG) += deb_extract.o get_header_ar.o get_header_tar.o |
| - | LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += deb_extract.o get_header_ar.o get_header_tar.o |
| - | LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o |
| - | LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o |
| - | LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += get_header_cpio.o |
| - | LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o |
| - | LIBUNARCHIVE-$(CONFIG_UNZIP) += get_header_zip.o |
| + | LIBUNARCHIVE-y:= \ |
| + | \ |
| + | data_skip.o \ |
| + | data_extract_all.o \ |
| + | data_extract_to_stdout.o \ |
| + | \ |
| + | filter_accept_all.o \ |
| + | filter_accept_list.o \ |
| + | filter_accept_reject_list.o \ |
| + | \ |
| + | get_header_ar.o \ |
| + | get_header_tar.o \ |
| + | get_header_tar_gz.o \ |
| + | \ |
| + | header_skip.o \ |
| + | header_list.o \ |
| + | header_verbose_list.o \ |
| + | \ |
| + | add_to_list.o \ |
| + | check_header_gzip.o \ |
| + | check_trailer_gzip.o \ |
| + | copy_file_chunk_fd.o \ |
| + | data_align.o \ |
| + | init_handle.o \ |
| + | seek_sub_file.o \ |
| + | unpack_ar_archive.o \ |
| + | |
| + | LIBUNARCHIVE-$(CONFIG_DPKG) += |
| + | LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += |
| + | LIBUNARCHIVE-$(CONFIG_AR) += |
| + | LIBUNARCHIVE-$(CONFIG_CPIO) += |
| + | LIBUNARCHIVE-$(CONFIG_GUNZIP) += |
| + | LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += |
| + | LIBUNARCHIVE-$(CONFIG_TAR) += |
| + | LIBUNARCHIVE-$(CONFIG_UNZIP) += |
| libraries-y+=$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR) | |
| @@ -0,0 +1,15 @@ | |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include "unarchive.h" |
| + | #include "libbb.h" |
| + | |
| + | extern const llist_t *add_to_list(const llist_t *old_head, const char *new_item) |
| + | { |
| + | llist_t *new_head; |
| + | |
| + | new_head = xmalloc(sizeof(llist_t)); |
| + | new_head->data = new_item; |
| + | new_head->link = old_head; |
| + | |
| + | return(new_head); |
| + | } |
| @@ -0,0 +1,75 @@ | |
| + | #include <stdlib.h> |
| + | #include <unistd.h> |
| + | #include "libbb.h" |
| + | |
| + | extern void check_header_gzip(int src_fd) |
| + | { |
| + | union { |
| + | unsigned char raw[10]; |
| + | struct { |
| + | unsigned char magic[2]; |
| + | unsigned char method; |
| + | unsigned char flags; |
| + | unsigned int mtime; |
| + | unsigned char xtra_flags; |
| + | unsigned char os_flags; |
| + | } formated; |
| + | } header; |
| + | |
| + | xread_all(src_fd, header.raw, 10); |
| + | |
| + | /* Magic header for gzip files, 1F 8B = \037\213 */ |
| + | if ((header.formated.magic[0] != 0x1F) |
| + | || (header.formated.magic[1] != 0x8b)) { |
| + | error_msg_and_die("Invalid gzip magic"); |
| + | } |
| + | |
| + | /* Check the compression method */ |
| + | if (header.formated.method != 8) { |
| + | error_msg_and_die("Unknown compression method %d", |
| + | header.formated.method); |
| + | } |
| + | |
| + | if (header.formated.flags & 0x04) { |
| + | /* bit 2 set: extra field present */ |
| + | unsigned char extra_short; |
| + | |
| + | extra_short = xread_char(src_fd); |
| + | extra_short += xread_char(src_fd) << 8; |
| + | while (extra_short > 0) { |
| + | /* Ignore extra field */ |
| + | xread_char(src_fd); |
| + | extra_short--; |
| + | } |
| + | } |
| + | |
| + | /* Discard original name if any */ |
| + | if (header.formated.flags & 0x08) { |
| + | /* bit 3 set: original file name present */ |
| + | char tmp; |
| + | |
| + | do { |
| + | read(src_fd, &tmp, 1); |
| + | } while (tmp != 0); |
| + | } |
| + | |
| + | /* Discard file comment if any */ |
| + | if (header.formated.flags & 0x10) { |
| + | /* bit 4 set: file comment present */ |
| + | char tmp; |
| + | |
| + | do { |
| + | read(src_fd, &tmp, 1); |
| + | } while (tmp != 0); |
| + | } |
| + | |
| + | /* Read the header checksum */ |
| + | if (header.formated.flags & 0x02) { |
| + | char tmp; |
| + | |
| + | read(src_fd, &tmp, 1); |
| + | read(src_fd, &tmp, 1); |
| + | } |
| + | |
| + | return; |
| + | } |
| @@ -0,0 +1,62 @@ | |
| + | /* vi: set sw=4 ts=4: */ |
| + | /* |
| + | * busybox gunzip trailing header handler |
| + | * Copyright Glenn McGrath 2002 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| + | */ |
| + | |
| + | |
| + | #include <sys/types.h> |
| + | #include <sys/wait.h> |
| + | #include <signal.h> |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| + | #include "config.h" |
| + | #include "busybox.h" |
| + | #include "unarchive.h" |
| + | |
| + | extern unsigned int gunzip_crc; |
| + | extern unsigned int gunzip_bytes_out; |
| + | extern unsigned char *gunzip_in_buffer; |
| + | extern unsigned char gunzip_in_buffer_count; |
| + | |
| + | extern void check_trailer_gzip(int src_fd) |
| + | { |
| + | |
| + | unsigned int stored_crc = 0; |
| + | unsigned char count; |
| + | |
| + | /* top up the input buffer with the rest of the trailer */ |
| + | xread_all(src_fd, &gunzip_in_buffer[gunzip_in_buffer_count], 8 - gunzip_in_buffer_count); |
| + | for (count = 0; count != 4; count++) { |
| + | stored_crc |= (gunzip_in_buffer[count] << (count * 8)); |
| + | } |
| + | |
| + | /* Validate decompression - crc */ |
| + | if (stored_crc != (gunzip_crc ^ 0xffffffffL)) { |
| + | error_msg("invalid compressed data--crc error"); |
| + | } |
| + | |
| + | /* Validate decompression - size */ |
| + | if (gunzip_bytes_out != |
| + | (gunzip_in_buffer[4] | (gunzip_in_buffer[5] << 8) | |
| + | (gunzip_in_buffer[6] << 16) | (gunzip_in_buffer[7] << 24))) { |
| + | error_msg("invalid compressed data--length error"); |
| + | } |
| + | |
| + | } |
| @@ -0,0 +1,33 @@ | |
| + | #include <unistd.h> |
| + | #include <sys/types.h> |
| + | #include "libbb.h" |
| + | |
| + | /* Copy CHUNKSIZE bytes (or untill EOF if chunksize == -1) |
| + | * from SRC_FILE to DST_FILE. */ |
| + | extern int copy_file_chunk_fd(int src_fd, int dst_fd, off_t chunksize) |
| + | { |
| + | size_t nread, size; |
| + | char buffer[BUFSIZ]; |
| + | |
| + | while (chunksize != 0) { |
| + | if (chunksize > BUFSIZ) { |
| + | size = BUFSIZ; |
| + | } else { |
| + | size = chunksize; |
| + | } |
| + | nread = xread(src_fd, buffer, size); |
| + | if (nread == 0) { |
| + | return 1; |
| + | } |
| + | |
| + | if (write (dst_fd, buffer, nread) != nread) { |
| + | error_msg_and_die ("Short write"); |
| + | } |
| + | |
| + | if (chunksize != -1) { |
| + | chunksize -= nread; |
| + | } |
| + | } |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,13 @@ | |
| + | #include <errno.h> |
| + | #include <sys/types.h> |
| + | #include <unistd.h> |
| + | #include "unarchive.h" |
| + | #include "libbb.h" |
| + | |
| + | extern const unsigned short data_align(const int src_fd, const unsigned int offset, const unsigned short align_to) |
| + | { |
| + | const unsigned short skip_amount = (align_to - (offset % align_to)) % align_to; |
| + | seek_sub_file(src_fd, skip_amount); |
| + | |
| + | return(skip_amount); |
| + | } |
| @@ -0,0 +1,76 @@ | |
| + | #include <sys/types.h> |
| + | #include <errno.h> |
| + | #include <fcntl.h> |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <utime.h> |
| + | #include <unistd.h> |
| + | #include <stdlib.h> |
| + | #include "libbb.h" |
| + | #include "unarchive.h" |
| + | |
| + | extern void data_extract_all(archive_handle_t *archive_handle) |
| + | { |
| + | file_header_t *file_header = archive_handle->file_header; |
| + | int dst_fd; |
| + | int res; |
| + | |
| + | if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { |
| + | char *dir = dirname(strdup(file_header->name)); |
| + | make_directory (dir, 0777, FILEUTILS_RECUR); |
| + | free(dir); |
| + | } |
| + | |
| + | /* Create the file */ |
| + | switch(file_header->mode & S_IFMT) { |
| + | case S_IFREG: { |
| + | #ifdef CONFIG_CPIO |
| + | if (file_header->link_name) { |
| + | /* hard link */ |
| + | res = link(file_header->link_name, file_header->name); |
| + | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { |
| + | perror_msg("Couldnt create hard link"); |
| + | } |
| + | } else |
| + | #endif |
| + | { |
| + | /* Regular file */ |
| + | dst_fd = xopen(file_header->name, O_WRONLY | O_CREAT); |
| + | copy_file_chunk_fd(archive_handle->src_fd, dst_fd, file_header->size); |
| + | close(dst_fd); |
| + | } |
| + | break; |
| + | } |
| + | case S_IFDIR: |
| + | res = mkdir(file_header->name, file_header->mode); |
| + | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { |
| + | perror_msg("extract_archive: %s", file_header->name); |
| + | } |
| + | break; |
| + | case S_IFLNK: |
| + | /* Symlink */ |
| + | res = symlink(file_header->link_name, file_header->name); |
| + | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { |
| + | perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); |
| + | } |
| + | break; |
| + | case S_IFSOCK: |
| + | case S_IFBLK: |
| + | case S_IFCHR: |
| + | case S_IFIFO: |
| + | res = mknod(file_header->name, file_header->mode, file_header->device); |
| + | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { |
| + | perror_msg("Cannot create node %s", file_header->name); |
| + | } |
| + | break; |
| + | } |
| + | |
| + | chmod(file_header->name, file_header->mode); |
| + | chown(file_header->name, file_header->uid, file_header->gid); |
| + | |
| + | if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { |
| + | struct utimbuf t; |
| + | t.actime = t.modtime = file_header->mtime; |
| + | utime(file_header->name, &t); |
| + | } |
| + | } |
| @@ -0,0 +1,8 @@ | |
| + | #include <stdlib.h> |
| + | #include <stdio.h> |
| + | #include "unarchive.h" |
| + | |
| + | extern void data_extract_to_stdout(archive_handle_t *archive_handle) |
| + | { |
| + | copy_file_chunk_fd(archive_handle->src_fd, fileno(stdout), archive_handle->file_header->size); |
| + | } |
| @@ -0,0 +1,27 @@ | |
| + | /* |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| + | */ |
| + | |
| + | #include <sys/types.h> |
| + | #include <errno.h> |
| + | #include <unistd.h> |
| + | #include <stdlib.h> |
| + | #include "unarchive.h" |
| + | #include "libbb.h" |
| + | |
| + | extern void data_skip(archive_handle_t *archive_handle) |
| + | { |
| + | seek_sub_file(archive_handle->src_fd, archive_handle->file_header->size); |
| + | } |
| @@ -65,114 +65,126 @@ static char *license_msg[] = { | |
| #include <signal.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| #include "config.h" | |
| - | #include "libbb.h" |
| + | #include "busybox.h" |
| + | #include "unarchive.h" |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | int uncompress(FILE * in, FILE * out); |
| - | #endif |
| - | |
| - | static FILE *in_file, *out_file; |
| + | typedef struct huft_s { |
| + | unsigned char e; /* number of extra bits or operation */ |
| + | unsigned char b; /* number of bits in this code or subcode */ |
| + | union { |
| + | unsigned short n; /* literal, length base, or distance base */ |
| + | struct huft_s *t; /* pointer to next level of table */ |
| + | } v; |
| + | } huft_t; |
| - | /* these are freed by gz_close */ |
| - | static unsigned char *window; |
| - | static unsigned long *crc_table; |
| + | static int gunzip_src_fd; |
| + | static int gunzip_dst_fd; |
| + | unsigned int gunzip_bytes_out; /* number of output bytes */ |
| + | static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ |
| - | static unsigned long crc; /* shift register contents */ |
| + | /* This is used to sanify any unused bits from the bitbuffer |
| + | * so they arent skipped when reading trailers (trailing headers) */ |
| + | unsigned char gunzip_in_buffer_count; |
| + | unsigned char *gunzip_in_buffer; |
| - | /* Return codes from gzip */ |
| - | #define ERROR 1 |
| + | /* gunzip_window size--must be a power of two, and |
| + | * at least 32K for zip's deflate method */ |
| + | static const int gunzip_wsize = 0x8000; |
| - | /* |
| - | * window size--must be a power of two, and |
| - | * at least 32K for zip's deflate method |
| - | */ |
| - | #define WSIZE 0x8000 |
| + | static unsigned char *gunzip_window; |
| + | static unsigned int *gunzip_crc_table; |
| + | unsigned int gunzip_crc; |
| /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ | |
| #define BMAX 16 /* maximum bit length of any code (16 for explode) */ | |
| #define N_MAX 288 /* maximum number of codes in any set */ | |
| - | static long bytes_out; /* number of output bytes */ |
| - | static unsigned long outcnt; /* bytes in output buffer */ |
| - | |
| - | static unsigned hufts; /* track memory usage */ |
| - | static unsigned long bb; /* bit buffer */ |
| - | static unsigned bk; /* bits in bit buffer */ |
| - | |
| - | typedef struct huft_s { |
| - | unsigned char e; /* number of extra bits or operation */ |
| - | unsigned char b; /* number of bits in this code or subcode */ |
| - | union { |
| - | unsigned short n; /* literal, length base, or distance base */ |
| - | struct huft_s *t; /* pointer to next level of table */ |
| - | } v; |
| - | } huft_t; |
| + | static unsigned int gunzip_hufts; /* track memory usage */ |
| + | static unsigned int gunzip_bb; /* bit buffer */ |
| + | static unsigned char gunzip_bk; /* bits in bit buffer */ |
| static const unsigned short mask_bits[] = { | |
| - | 0x0000, |
| - | 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| + | 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | |
| }; | |
| - | /* static int error_number = 0; */ |
| - | /* ======================================================================== |
| - | * Signal and error handler. |
| - | */ |
| + | /* Copy lengths for literal codes 257..285 */ |
| + | static const unsigned short cplens[] = { |
| + | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, |
| + | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| + | }; |
| + | |
| + | /* note: see note #13 above about the 258 in this list. */ |
| + | /* Extra bits for literal codes 257..285 */ |
| + | static const unsigned char cplext[] = { |
| + | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, |
| + | 5, 5, 5, 0, 99, 99 |
| + | }; /* 99==invalid */ |
| + | |
| + | /* Copy offsets for distance codes 0..29 */ |
| + | static const unsigned short cpdist[] = { |
| + | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, |
| + | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 |
| + | }; |
| + | |
| + | /* Extra bits for distance codes */ |
| + | static const unsigned char cpdext[] = { |
| + | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, |
| + | 11, 11, 12, 12, 13, 13 |
| + | }; |
| + | |
| + | /* Tables for deflate from PKZIP's appnote.txt. */ |
| + | /* Order of the bit length code lengths */ |
| + | static const unsigned char border[] = { |
| + | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| + | }; |
| + | |
| + | static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) |
| + | { |
| + | while (*current < required) { |
| + | bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; |
| + | *current += 8; |
| + | } |
| + | |
| + | return(bitbuffer); |
| + | } |
| static void abort_gzip(void) | |
| { | |
| error_msg("gzip aborted\n"); | |
| - | exit(ERROR); |
| + | exit(-1); |
| } | |
| - | static void make_crc_table(void) |
| + | static void make_gunzip_crc_table(void) |
| { | |
| - | const unsigned long poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| + | const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| unsigned short i; /* counter for all possible eight bit values */ | |
| /* initial shift register value */ | |
| - | crc = 0xffffffffL; |
| - | crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); |
| + | gunzip_crc = 0xffffffffL; |
| + | gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); |
| /* Compute and print table of CRC's, five per line */ | |
| for (i = 0; i < 256; i++) { | |
| - | unsigned long table_entry; /* crc shift register */ |
| - | char k; /* byte being shifted into crc apparatus */ |
| + | unsigned int table_entry; /* crc shift register */ |
| + | unsigned char k; /* byte being shifted into crc apparatus */ |
| table_entry = i; | |
| /* The idea to initialize the register with the byte instead of | |
| * zero was stolen from Haruhiko Okumura's ar002 | |
| */ | |
| for (k = 8; k; k--) { | |
| - | table_entry = |
| - | table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> |
| - | 1; |
| - | } |
| - | crc_table[i] = table_entry; |
| + | if (table_entry & 1) { |
| + | table_entry = (table_entry >> 1) ^ poly; |
| + | } else { |
| + | table_entry >>= 1; |
| } | |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
| - | * (Used for the decompressed data only.) |
| - | */ |
| - | static void flush_window(void) |
| - | { |
| - | int n; |
| - | |
| - | if (outcnt == 0) |
| - | return; |
| - | |
| - | for (n = 0; n < outcnt; n++) { |
| - | crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); |
| } | |
| - | |
| - | if (fwrite(window, 1, outcnt, out_file) != outcnt) { |
| - | error_msg_and_die("Couldnt write"); |
| + | gunzip_crc_table[i] = table_entry; |
| } | |
| - | bytes_out += (unsigned long) outcnt; |
| - | outcnt = 0; |
| } | |
| /* | |
| @@ -183,7 +195,8 @@ static void flush_window(void) | |
| */ | |
| static int huft_free(huft_t * t) | |
| { | |
| - | huft_t *p, *q; |
| + | huft_t *p; |
| + | huft_t *q; |
| /* Go through linked list, freeing from the malloced (t[-1]) address. */ | |
| p = t; | |
| @@ -195,8 +208,6 @@ static int huft_free(huft_t * t) | |
| return 0; | |
| } | |
| - | typedef unsigned char extra_bits_t; |
| - | |
| /* Given a list of code lengths and a maximum table size, make a set of | |
| * tables to decode that set of codes. Return zero on success, one if | |
| * the given code set is incomplete (the tables are still built in this | |
| @@ -213,7 +224,7 @@ typedef unsigned char extra_bits_t; | |
| */ | |
| static int huft_build(unsigned int *b, const unsigned int n, | |
| const unsigned int s, const unsigned short *d, | |
| - | const extra_bits_t * e, huft_t ** t, int *m) |
| + | const unsigned char *e, huft_t ** t, int *m) |
| { | |
| unsigned a; /* counter for codes of length k */ | |
| unsigned c[BMAX + 1]; /* bit length count table */ | |
| @@ -251,26 +262,35 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* Find minimum and maximum length, bound *m by those */ | |
| l = *m; | |
| - | for (j = 1; j <= BMAX; j++) |
| - | if (c[j]) |
| + | for (j = 1; j <= BMAX; j++) { |
| + | if (c[j]) { |
| break; | |
| + | } |
| + | } |
| k = j; /* minimum code length */ | |
| - | if ((unsigned) l < j) |
| + | if ((unsigned) l < j) { |
| l = j; | |
| - | for (i = BMAX; i; i--) |
| - | if (c[i]) |
| + | } |
| + | for (i = BMAX; i; i--) { |
| + | if (c[i]) { |
| break; | |
| + | } |
| + | } |
| g = i; /* maximum code length */ | |
| - | if ((unsigned) l > i) |
| + | if ((unsigned) l > i) { |
| l = i; | |
| + | } |
| *m = l; | |
| /* Adjust last length count to fill out codes, if needed */ | |
| - | for (y = 1 << j; j < i; j++, y <<= 1) |
| - | if ((y -= c[j]) < 0) |
| + | for (y = 1 << j; j < i; j++, y <<= 1) { |
| + | if ((y -= c[j]) < 0) { |
| return 2; /* bad input: more codes than bits */ | |
| - | if ((y -= c[i]) < 0) |
| + | } |
| + | } |
| + | if ((y -= c[i]) < 0) { |
| return 2; | |
| + | } |
| c[i] += y; | |
| /* Generate starting offsets into the value table for each length */ | |
| @@ -285,8 +305,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| p = b; | |
| i = 0; | |
| do { | |
| - | if ((j = *p++) != 0) |
| + | if ((j = *p++) != 0) { |
| v[x[j]++] = i; | |
| + | } |
| } while (++i < n); | |
| /* Generate the Huffman codes and for each, make the table entries */ | |
| @@ -314,8 +335,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| f -= a + 1; /* deduct codes from patterns left */ | |
| xp = c + k; | |
| while (++j < z) { /* try smaller tables up to z bits */ | |
| - | if ((f <<= 1) <= *++xp) |
| + | if ((f <<= 1) <= *++xp) { |
| break; /* enough codes to use up j bits */ | |
| + | } |
| f -= *xp; /* else deduct codes from patterns */ | |
| } | |
| } | |
| @@ -324,7 +346,7 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* allocate and link in new table */ | |
| q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); | |
| - | hufts += z + 1; /* track memory usage */ |
| + | gunzip_hufts += z + 1; /* track memory usage */ |
| *t = q + 1; /* link to list for huft_free() */ | |
| *(t = &(q->v.t)) = NULL; | |
| u[h] = ++q; /* table starts after link */ | |
| @@ -342,9 +364,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* set up table entry in r */ | |
| r.b = (unsigned char) (k - w); | |
| - | if (p >= v + n) |
| + | if (p >= v + n) { |
| r.e = 99; /* out of values--invalid code */ | |
| - | else if (*p < s) { |
| + | } else if (*p < s) { |
| r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ | |
| r.v.n = (unsigned short) (*p); /* simple code is just the value */ | |
| p++; /* one compiler does not like *p++ */ | |
| @@ -355,12 +377,14 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* fill code-like entries with r */ | |
| f = 1 << (k - w); | |
| - | for (j = i >> w; j < z; j += f) |
| + | for (j = i >> w; j < z; j += f) { |
| q[j] = r; | |
| + | } |
| /* backwards increment the k-bit code i */ | |
| - | for (j = 1 << (k - 1); i & j; j >>= 1) |
| + | for (j = 1 << (k - 1); i & j; j >>= 1) { |
| i ^= j; | |
| + | } |
| i ^= j; | |
| /* backup over finished tables */ | |
| @@ -374,6 +398,25 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| return y != 0 && g != 1; | |
| } | |
| + | /* =========================================================================== |
| + | * Write the output gunzip_window gunzip_window[0..gunzip_outbuf_count-1] and update crc and gunzip_bytes_out. |
| + | * (Used for the decompressed data only.) |
| + | */ |
| + | static void flush_gunzip_window(void) |
| + | { |
| + | int n; |
| + | |
| + | for (n = 0; n < gunzip_outbuf_count; n++) { |
| + | gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); |
| + | } |
| + | |
| + | if (write(gunzip_dst_fd, gunzip_window, gunzip_outbuf_count) != gunzip_outbuf_count) { |
| + | error_msg_and_die("Couldnt write"); |
| + | } |
| + | gunzip_bytes_out += gunzip_outbuf_count; |
| + | gunzip_outbuf_count = 0; |
| + | } |
| + | |
| /* | |
| * inflate (decompress) the codes in a deflated (compressed) block. | |
| * Return an error code or zero if it all goes ok. | |
| @@ -381,32 +424,26 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| * tl, td: literal/length and distance decoder tables | |
| * bl, bd: number of bits decoded by tl[] and td[] | |
| */ | |
| - | static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) |
| + | static int inflate_codes(huft_t * tl, huft_t * td, const unsigned int bl, const unsigned int bd) |
| { | |
| - | register unsigned long e; /* table entry flag/number of extra bits */ |
| - | unsigned long n, d; /* length and index for copy */ |
| - | unsigned long w; /* current window position */ |
| + | unsigned int e; /* table entry flag/number of extra bits */ |
| + | unsigned int n, d; /* length and index for copy */ |
| + | unsigned int w; /* current gunzip_window position */ |
| huft_t *t; /* pointer to table entry */ | |
| - | unsigned ml, md; /* masks for bl and bd bits */ |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | register int input_char; |
| + | unsigned int ml, md; /* masks for bl and bd bits */ |
| + | unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b = bb; /* initialize bit buffer */ |
| - | k = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b = gunzip_bb; /* initialize bit buffer */ |
| + | k = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* inflate the coded data */ | |
| ml = mask_bits[bl]; /* precompute masks for speed */ | |
| md = mask_bits[bd]; | |
| - | for (;;) { /* do until end of block */ |
| - | while (k < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | while (1) { /* do until end of block */ |
| + | b = fill_bitbuffer(b, &k, bl); |
| if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) | |
| do { | |
| if (e == 99) { | |
| @@ -415,20 +452,16 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| if (e == 16) { /* then it's a literal */ | |
| - | window[w++] = (unsigned char) t->v.n; |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | gunzip_window[w++] = (unsigned char) t->v.n; |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| } else { /* it's an EOB or a length */ | |
| @@ -439,24 +472,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| } | |
| /* get length of block to copy */ | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| n = t->v.n + ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| /* decode distance of block to copy */ | |
| - | while (k < (unsigned) bd) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| - | |
| + | b = fill_bitbuffer(b, &k, bd); |
| if ((e = (t = td + ((unsigned) b & md))->e) > 16) | |
| do { | |
| if (e == 99) | |
| @@ -464,23 +486,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = | |
| t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| d = w - t->v.n - ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| @@ -489,60 +501,38 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| do { | |
| n -= (e = | |
| (e = | |
| - | WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); |
| - | #if !defined(NOMEMCPY) && !defined(DEBUG) |
| + | gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); |
| + | /* copy to new buffer to prevent possible overwrite */ |
| if (w - d >= e) { /* (this test assumes unsigned comparison) */ | |
| - | memcpy(window + w, window + d, e); |
| + | memcpy(gunzip_window + w, gunzip_window + d, e); |
| w += e; | |
| d += e; | |
| - | } else /* do it slow to avoid memcpy() overlap */ |
| - | #endif /* !NOMEMCPY */ |
| + | } else { |
| + | /* do it slow to avoid memcpy() overlap */ |
| + | /* !NOMEMCPY */ |
| do { | |
| - | window[w++] = window[d++]; |
| + | gunzip_window[w++] = gunzip_window[d++]; |
| } while (--e); | |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | } |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| + | |
| } while (n); | |
| } | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b; /* restore global bit buffer */ |
| - | bk = k; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b; /* restore global bit buffer */ |
| + | gunzip_bk = k; |
| /* done */ | |
| return 0; | |
| } | |
| - | static const unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ |
| - | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, |
| - | 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| - | }; |
| - | |
| - | /* note: see note #13 above about the 258 in this list. */ |
| - | static const extra_bits_t cplext[] = { /* Extra bits for literal codes 257..285 */ |
| - | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, |
| - | 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 |
| - | }; /* 99==invalid */ |
| - | static const unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ |
| - | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, |
| - | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, |
| - | 8193, 12289, 16385, 24577 |
| - | }; |
| - | static const extra_bits_t cpdext[] = { /* Extra bits for distance codes */ |
| - | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, |
| - | 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, |
| - | 12, 12, 13, 13 |
| - | }; |
| - | |
| - | /* Tables for deflate from PKZIP's appnote.txt. */ |
| - | static const extra_bits_t border[] = { /* Order of the bit length code lengths */ |
| - | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| - | }; |
| - | |
| /* | |
| * decompress an inflated block | |
| * e: last block flag | |
| @@ -552,53 +542,43 @@ static const extra_bits_t border[] = { /* Order of the bit length code lengths * | |
| static int inflate_block(int *e) | |
| { | |
| unsigned t; /* block type */ | |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | int input_char; |
| + | register unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b = bb; |
| - | k = bk; |
| + | |
| + | b = gunzip_bb; |
| + | k = gunzip_bk; |
| /* read in last block bit */ | |
| - | while (k < 1) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 1); |
| *e = (int) b & 1; | |
| b >>= 1; | |
| k -= 1; | |
| /* read in block type */ | |
| - | while (k < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 2); |
| t = (unsigned) b & 3; | |
| b >>= 2; | |
| k -= 2; | |
| /* restore the global bit buffer */ | |
| - | bb = b; |
| - | bk = k; |
| + | gunzip_bb = b; |
| + | gunzip_bk = k; |
| /* inflate that block type */ | |
| switch (t) { | |
| case 0: /* Inflate stored */ | |
| { | |
| - | unsigned long n; /* number of bytes in block */ |
| - | unsigned long w; /* current window position */ |
| - | register unsigned long b_stored; /* bit buffer */ |
| - | register unsigned long k_stored; /* number of bits in bit buffer */ |
| + | unsigned int n; /* number of bytes in block */ |
| + | unsigned int w; /* current gunzip_window position */ |
| + | unsigned int b_stored; /* bit buffer */ |
| + | unsigned int k_stored; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b_stored = bb; /* initialize bit buffer */ |
| - | k_stored = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b_stored = gunzip_bb; /* initialize bit buffer */ |
| + | k_stored = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* go to byte boundary */ | |
| n = k_stored & 7; | |
| @@ -606,21 +586,12 @@ static int inflate_block(int *e) | |
| k_stored -= n; | |
| /* get the length and its complement */ | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| n = ((unsigned) b_stored & 0xffff); | |
| b_stored >>= 16; | |
| k_stored -= 16; | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| if (n != (unsigned) ((~b_stored) & 0xffff)) { | |
| return 1; /* error in compressed data */ | |
| } | |
| @@ -629,15 +600,11 @@ static int inflate_block(int *e) | |
| /* read and output the compressed data */ | |
| while (n--) { | |
| - | while (k_stored < 8) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| - | window[w++] = (unsigned char) b_stored; |
| - | if (w == (unsigned long) WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 8); |
| + | gunzip_window[w++] = (unsigned char) b_stored; |
| + | if (w == (unsigned int) gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| b_stored >>= 8; | |
| @@ -645,9 +612,9 @@ static int inflate_block(int *e) | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b_stored; /* restore global bit buffer */ |
| - | bk = k_stored; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b_stored; /* restore global bit buffer */ |
| + | gunzip_bk = k_stored; |
| return 0; | |
| } | |
| case 1: /* Inflate fixed | |
| @@ -659,8 +626,8 @@ static int inflate_block(int *e) | |
| int i; /* temporary variable */ | |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| unsigned int l[288]; /* length list for huft_build */ | |
| /* set up literal table */ | |
| @@ -692,8 +659,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -705,53 +673,41 @@ static int inflate_block(int *e) | |
| const int dbits = 6; /* bits in base distance lookup table */ | |
| const int lbits = 9; /* bits in base literal/length lookup table */ | |
| - | int i; /* temporary variables */ |
| - | unsigned j; |
| - | unsigned l; /* last length */ |
| - | unsigned m; /* mask for bit lengths table */ |
| - | unsigned n; /* number of lengths to get */ |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| - | unsigned nb; /* number of bit length codes */ |
| - | unsigned nl; /* number of literal/length codes */ |
| - | unsigned nd; /* number of distance codes */ |
| - | |
| - | unsigned ll[286 + 30]; /* literal/length and distance code lengths */ |
| - | register unsigned long b_dynamic; /* bit buffer */ |
| - | register unsigned k_dynamic; /* number of bits in bit buffer */ |
| + | unsigned int i; /* temporary variables */ |
| + | unsigned int j; |
| + | unsigned int l; /* last length */ |
| + | unsigned int m; /* mask for bit lengths table */ |
| + | unsigned int n; /* number of lengths to get */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| + | unsigned int nb; /* number of bit length codes */ |
| + | unsigned int nl; /* number of literal/length codes */ |
| + | unsigned int nd; /* number of distance codes */ |
| + | |
| + | unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ |
| + | unsigned int b_dynamic; /* bit buffer */ |
| + | unsigned int k_dynamic; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b_dynamic = bb; |
| - | k_dynamic = bk; |
| + | b_dynamic = gunzip_bb; |
| + | k_dynamic = gunzip_bk; |
| /* read in table lengths */ | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 4) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); |
| + | nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ |
| + | |
| b_dynamic >>= 4; | |
| k_dynamic -= 4; | |
| if (nl > 286 || nd > 30) { | |
| @@ -760,13 +716,8 @@ static int inflate_block(int *e) | |
| /* read in bit-length-code lengths */ | |
| for (j = 0; j < nb; j++) { | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | ll[border[j]] = (unsigned) b_dynamic & 7; |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | ll[border[j]] = (unsigned int) b_dynamic & 7; |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| } | |
| @@ -776,7 +727,8 @@ static int inflate_block(int *e) | |
| /* build decoding table for trees--single level, 7 bit lookup */ | |
| bl = 7; | |
| - | if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { |
| + | i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); |
| + | if (i != 0) { |
| if (i == 1) { | |
| huft_free(tl); | |
| } | |
| @@ -787,46 +739,31 @@ static int inflate_block(int *e) | |
| n = nl + nd; | |
| m = mask_bits[bl]; | |
| i = l = 0; | |
| - | while ((unsigned) i < n) { |
| - | while (k_dynamic < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = (td = tl + ((unsigned) b_dynamic & m))->b; |
| + | while ((unsigned int) i < n) { |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); |
| + | j = (td = tl + ((unsigned int) b_dynamic & m))->b; |
| b_dynamic >>= j; | |
| k_dynamic -= j; | |
| j = td->v.n; | |
| if (j < 16) { /* length of code in bits (0..15) */ | |
| ll[i++] = l = j; /* save last length in l */ | |
| } else if (j == 16) { /* repeat last length 3 to 6 times */ | |
| - | while (k_dynamic < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 3); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); |
| + | j = 3 + ((unsigned int) b_dynamic & 3); |
| b_dynamic >>= 2; | |
| k_dynamic -= 2; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| ll[i++] = l; | |
| } | |
| } else if (j == 17) { /* 3 to 10 zero length codes */ | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 7); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | j = 3 + ((unsigned int) b_dynamic & 7); |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -834,16 +771,11 @@ static int inflate_block(int *e) | |
| } | |
| l = 0; | |
| } else { /* j == 18: 11 to 138 zero length codes */ | |
| - | while (k_dynamic < 7) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 11 + ((unsigned) b_dynamic & 0x7f); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); |
| + | j = 11 + ((unsigned int) b_dynamic & 0x7f); |
| b_dynamic >>= 7; | |
| k_dynamic -= 7; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -857,22 +789,24 @@ static int inflate_block(int *e) | |
| huft_free(tl); | |
| /* restore the global bit buffer */ | |
| - | bb = b_dynamic; |
| - | bk = k_dynamic; |
| + | gunzip_bb = b_dynamic; |
| + | gunzip_bk = k_dynamic; |
| /* build the decoding tables for literal/length and distance codes */ | |
| bl = lbits; | |
| + | |
| if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("Incomplete literal tree"); |
| + | error_msg_and_die("Incomplete literal tree"); |
| huft_free(tl); | |
| } | |
| return i; /* incomplete code set */ | |
| } | |
| + | |
| bd = dbits; | |
| if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("incomplete distance tree"); |
| + | error_msg_and_die("incomplete distance tree"); |
| huft_free(td); | |
| } | |
| huft_free(tl); | |
| @@ -880,8 +814,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -890,6 +825,7 @@ static int inflate_block(int *e) | |
| } | |
| default: | |
| /* bad block type */ | |
| + | error_msg("bad block type %d\n", t); |
| return 2; | |
| } | |
| } | |
| @@ -897,72 +833,24 @@ static int inflate_block(int *e) | |
| /* | |
| * decompress an inflated entry | |
| * | |
| - | * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr |
| + | * GLOBAL VARIABLES: gunzip_outbuf_count, bk, gunzip_bb, hufts, inptr |
| */ | |
| - | extern int inflate(FILE * in, FILE * out) |
| + | extern int inflate(int in, int out) |
| { | |
| + | typedef void (*sig_type) (int); |
| int e; /* last block flag */ | |
| int r; /* result code */ | |
| unsigned h = 0; /* maximum struct huft's malloc'ed */ | |
| - | /* initialize window, bit buffer */ |
| - | outcnt = 0; |
| - | bk = 0; |
| - | bb = 0; |
| - | |
| - | in_file = in; |
| - | out_file = out; |
| - | |
| /* Allocate all global buffers (for DYN_ALLOC option) */ | |
| - | window = xmalloc((size_t) (((2L * WSIZE) + 1L) * sizeof(unsigned char))); |
| - | bytes_out = 0L; |
| + | gunzip_window = xmalloc(0x8000); |
| + | gunzip_outbuf_count = 0; |
| + | gunzip_bytes_out = 0; |
| - | /* Create the crc table */ |
| - | make_crc_table(); |
| + | gunzip_src_fd = in; |
| + | gunzip_dst_fd = out; |
| - | /* decompress until the last block */ |
| - | do { |
| - | hufts = 0; |
| - | if ((r = inflate_block(&e)) != 0) { |
| - | return r; |
| - | } |
| - | if (hufts > h) { |
| - | h = hufts; |
| - | } |
| - | } while (!e); |
| - | |
| - | /* Undo too much lookahead. The next read will be byte aligned so we |
| - | * can discard unused bits in the last meaningful byte. |
| - | */ |
| - | while (bk >= 8) { |
| - | bk -= 8; |
| - | ungetc((bb << bk), in_file); |
| - | } |
| - | |
| - | /* flush out window */ |
| - | flush_window(); |
| - | free(window); |
| - | free(crc_table); |
| - | |
| - | /* return success */ |
| - | return 0; |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Unzip in to out. This routine works on gzip files only. |
| - | * |
| - | * IN assertions: the buffer inbuf contains already the beginning of |
| - | * the compressed data, from offsets inptr to insize-1 included. |
| - | * The magic header has already been checked. The output buffer is cleared. |
| - | * in, out: input and output file descriptors |
| - | */ |
| - | extern int unzip(FILE * l_in_file, FILE * l_out_file) |
| - | { |
| - | unsigned char buf[8]; /* extended local header */ |
| - | unsigned char flags; /* compression flags */ |
| - | typedef void (*sig_type) (int); |
| - | unsigned short i; |
| - | unsigned char magic[2]; |
| + | gunzip_in_buffer = malloc(8); |
| if (signal(SIGINT, SIG_IGN) != SIG_IGN) { | |
| (void) signal(SIGINT, (sig_type) abort_gzip); | |
| @@ -973,97 +861,44 @@ extern int unzip(FILE * l_in_file, FILE * l_out_file) | |
| } | |
| #endif | |
| - | magic[0] = fgetc(l_in_file); |
| - | magic[1] = fgetc(l_in_file); |
| - | |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | /* Magic header for compress files, 1F 9d = \037\235 */ |
| - | if ((magic[0] == 0x1F) && (magic[1] == 0x9d)) { |
| - | return uncompress(l_in_file, l_out_file); |
| - | } |
| - | #endif |
| - | |
| - | /* Magic header for gzip files, 1F 8B = \037\213 */ |
| - | if ((magic[0] != 0x1F) || (magic[1] != 0x8b)) { |
| - | error_msg("Invalid gzip magic"); |
| - | return EXIT_FAILURE; |
| - | } |
| - | |
| - | /* Check the compression method */ |
| - | if (fgetc(l_in_file) != 8) /* also catches EOF */ { |
| - | error_msg("Unknown compression method"); |
| - | return (-1); |
| - | } |
| - | |
| - | flags = (unsigned char) fgetc(l_in_file); |
| - | |
| - | /* Ignore time stamp(4), extra flags(1), OS type(1) */ |
| - | for (i = 0; i < 6; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| + | /* initialize gunzip_window, bit buffer */ |
| + | gunzip_bk = 0; |
| + | gunzip_bb = 0; |
| - | if (flags & 0x04) { |
| - | /* bit 2 set: extra field present */ |
| - | const unsigned short extra = |
| - | fgetc(l_in_file) + (fgetc(l_in_file) << 8); |
| - | if (feof(in_file)) return 1; |
| - | for (i = 0; i < extra; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| - | } |
| - | |
| - | /* Discard original name if any */ |
| - | if (flags & 0x08) { |
| - | /* bit 3 set: original file name present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| - | } |
| + | /* Create the crc table */ |
| + | make_gunzip_crc_table(); |
| - | /* Discard file comment if any */ |
| - | if (flags & 0x10) { |
| - | /* bit 4 set: file comment present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| + | /* decompress until the last block */ |
| + | do { |
| + | gunzip_hufts = 0; |
| + | r = inflate_block(&e); |
| + | if (r != 0) { |
| + | error_msg_and_die("inflate error %d", r); |
| + | return r; |
| } | |
| - | |
| - | /* Decompress */ |
| - | if (inflate(l_in_file, l_out_file) != 0) { |
| - | error_msg("invalid compressed data--format violated"); |
| + | if (gunzip_hufts > h) { |
| + | h = gunzip_hufts; |
| } | |
| + | } while (!e); |
| - | /* Get the crc and original length |
| - | * crc32 (see algorithm.doc) |
| - | * uncompressed input size modulo 2^32 |
| - | */ |
| - | fread(buf, 1, 8, l_in_file); |
| - | |
| - | /* Validate decompression - crc */ |
| - | if ((unsigned int) ((buf[0] | (buf[1] << 8)) | |
| - | ((buf[2] | (buf[3] << 8)) << 16)) != |
| - | (crc ^ 0xffffffffL)) { |
| - | error_msg("invalid compressed data--crc error"); |
| - | } |
| - | /* Validate decompression - size */ |
| - | if (((buf[4] | (buf[5] << 8)) | ((buf[6] | (buf[7] << 8)) << 16)) != |
| - | (unsigned long) bytes_out) { |
| - | error_msg("invalid compressed data--length error"); |
| + | /* write any buffered uncompressed data */ |
| + | flush_gunzip_window(); |
| + | free(gunzip_window); |
| + | |
| + | /* Cleanup */ |
| + | free(gunzip_crc_table); |
| + | |
| + | /* Store unused bytes in a global buffer so calling applets can access it */ |
| + | gunzip_in_buffer_count = 0; |
| + | if (gunzip_bk >= 8) { |
| + | /* Undo too much lookahead. The next read will be byte aligned |
| + | * so we can discard unused bits in the last meaningful byte. */ |
| + | gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; |
| + | gunzip_in_buffer_count++; |
| + | gunzip_bb >>= 8; |
| + | gunzip_bk -= 8; |
| } | |
| + | /* return success */ |
| return 0; | |
| } | |
| - | |
| - | /* |
| - | * This needs access to global variables window and crc_table, so its not in its own file. |
| - | */ |
| - | extern void gz_close(int gunzip_pid) |
| - | { |
| - | if (kill(gunzip_pid, SIGTERM) == -1) { |
| - | error_msg_and_die |
| - | ("*** Couldnt kill old gunzip process *** aborting"); |
| - | } |
| - | |
| - | if (waitpid(gunzip_pid, NULL, 0) == -1) { |
| - | printf("Couldnt wait ?"); |
| - | } |
| - | |
| - | free(window); |
| - | free(crc_table); |
| - | } |
| @@ -0,0 +1,10 @@ | |
| + | #include <fnmatch.h> |
| + | #include <stdlib.h> |
| + | #include "unarchive.h" |
| + | /* |
| + | * Accept names that are in the accept list |
| + | */ |
| + | extern char filter_accept_all(const llist_t *accept_list, const llist_t *reject_list, const char *key) |
| + | { |
| + | return(EXIT_SUCCESS); |
| + | } |
| @@ -0,0 +1,16 @@ | |
| + | #include <fnmatch.h> |
| + | #include <stdlib.h> |
| + | #include "unarchive.h" |
| + | /* |
| + | * Accept names that are in the accept list |
| + | */ |
| + | extern char filter_accept_list(const llist_t *accept_list, const llist_t *reject_list, const char *key) |
| + | { |
| + | while (accept_list) { |
| + | if (fnmatch(accept_list->data, key, 0) == 0) { |
| + | return(EXIT_SUCCESS); |
| + | } |
| + | accept_list = accept_list->link; |
| + | } |
| + | return(EXIT_FAILURE); |
| + | } |
| @@ -0,0 +1,34 @@ | |
| + | #include <fnmatch.h> |
| + | #include <stdlib.h> |
| + | #include "unarchive.h" |
| + | |
| + | static char check_list(const llist_t *list, const char *filename) |
| + | { |
| + | if (list) { |
| + | while (list) { |
| + | if (fnmatch(list->data, filename, 0) == 0) { |
| + | return(EXIT_SUCCESS); |
| + | } |
| + | list = list->link; |
| + | } |
| + | } |
| + | return(EXIT_FAILURE); |
| + | } |
| + | |
| + | /* |
| + | * Accept names that are in the accept list |
| + | */ |
| + | extern char filter_accept_reject_list(const llist_t *accept_list, const llist_t *reject_list, const char *key) |
| + | { |
| + | /* Fail if an accept list was specified and the key wasnt in there */ |
| + | if ((accept_list) && (check_list(accept_list, key) == EXIT_FAILURE)) { |
| + | return(EXIT_FAILURE); |
| + | } |
| + | |
| + | /* If the key is in a reject list fail */ |
| + | if (check_list(reject_list, key) == EXIT_FAILURE) { |
| + | return(EXIT_FAILURE); |
| + | } |
| + | |
| + | return(EXIT_SUCCESS); |
| + | } |
| @@ -17,12 +17,13 @@ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <unistd.h> |
| #include "unarchive.h" | |
| #include "libbb.h" | |
| - | file_header_t *get_header_ar(FILE *src_stream) |
| + | extern char get_header_ar(archive_handle_t *archive_handle) |
| { | |
| - | file_header_t *typed; |
| + | file_header_t *typed = archive_handle->file_header; |
| union { | |
| char raw[60]; | |
| struct { | |
| @@ -35,72 +36,87 @@ file_header_t *get_header_ar(FILE *src_stream) | |
| char magic[2]; | |
| } formated; | |
| } ar; | |
| + | #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES |
| static char *ar_long_names; | |
| + | static unsigned int ar_long_name_size; |
| + | #endif |
| - | if (fread(ar.raw, 1, 60, src_stream) != 60) { |
| - | return(NULL); |
| - | } |
| - | archive_offset += 60; |
| - | /* align the headers based on the header magic */ |
| - | if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { |
| - | /* some version of ar, have an extra '\n' after each data entry, |
| - | * this puts the next header out by 1 */ |
| - | if (ar.formated.magic[1] != '`') { |
| - | error_msg("Invalid magic"); |
| - | return(NULL); |
| - | } |
| - | /* read the next char out of what would be the data section, |
| - | * if its a '\n' then it is a valid header offset by 1*/ |
| - | archive_offset++; |
| - | if (fgetc(src_stream) != '\n') { |
| - | error_msg("Invalid magic"); |
| - | return(NULL); |
| + | /* dont use xread as we want to handle the error ourself */ |
| + | if (read(archive_handle->src_fd, ar.raw, 60) != 60) { |
| + | /* End Of File */ |
| + | return(EXIT_FAILURE); |
| } | |
| + | |
| + | /* Some ar entries have a trailing '\n' after the previous data entry */ |
| + | if (ar.raw[0] == '\n') { |
| /* fix up the header, we started reading 1 byte too early */ | |
| - | /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ |
| memmove(ar.raw, &ar.raw[1], 59); | |
| + | ar.raw[59] = xread_char(archive_handle->src_fd); |
| + | archive_handle->offset++; |
| } | |
| + | archive_handle->offset += 60; |
| - | typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); |
| + | /* align the headers based on the header magic */ |
| + | if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { |
| + | error_msg_and_die("Invalid ar header"); |
| + | } |
| + | |
| + | typed->mode = strtol(ar.formated.mode, NULL, 8); |
| + | typed->mtime = atoi(ar.formated.date); |
| + | typed->uid = atoi(ar.formated.uid); |
| + | typed->gid = atoi(ar.formated.gid); |
| + | typed->size = atoi(ar.formated.size); |
| - | typed->size = (size_t) atoi(ar.formated.size); |
| /* long filenames have '/' as the first character */ | |
| if (ar.formated.name[0] == '/') { | |
| + | #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES |
| if (ar.formated.name[1] == '/') { | |
| /* If the second char is a '/' then this entries data section | |
| * stores long filename for multiple entries, they are stored | |
| * in static variable long_names for use in future entries */ | |
| - | ar_long_names = (char *) xrealloc(ar_long_names, typed->size); |
| - | fread(ar_long_names, 1, typed->size, src_stream); |
| - | archive_offset += typed->size; |
| + | ar_long_name_size = typed->size; |
| + | ar_long_names = xmalloc(ar_long_name_size); |
| + | xread_all(archive_handle->src_fd, ar_long_names, ar_long_name_size); |
| + | archive_handle->offset += ar_long_name_size; |
| /* This ar entries data section only contained filenames for other records | |
| * they are stored in the static ar_long_names for future reference */ | |
| - | return (get_header_ar(src_stream)); /* Return next header */ |
| + | return (get_header_ar(archive_handle)); /* Return next header */ |
| } else if (ar.formated.name[1] == ' ') { | |
| /* This is the index of symbols in the file for compilers */ | |
| - | seek_sub_file(src_stream, typed->size); |
| - | return (get_header_ar(src_stream)); /* Return next header */ |
| + | data_skip(archive_handle); |
| + | return (get_header_ar(archive_handle)); /* Return next header */ |
| } else { | |
| /* The number after the '/' indicates the offset in the ar data section | |
| (saved in variable long_name) that conatains the real filename */ | |
| - | if (!ar_long_names) { |
| - | error_msg("Cannot resolve long file name"); |
| - | return (NULL); |
| + | const unsigned int long_offset = atoi(&ar.formated.name[1]); |
| + | if (long_offset >= ar_long_name_size) { |
| + | error_msg_and_die("Cant resolve long filename"); |
| } | |
| - | typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); |
| + | typed->name = xstrdup(ar_long_names + long_offset); |
| } | |
| + | #else |
| + | error_msg_and_die("long filenames not supported"); |
| + | #endif |
| } else { | |
| /* short filenames */ | |
| typed->name = xstrndup(ar.formated.name, 16); | |
| } | |
| - | typed->name[strcspn(typed->name, " /")]='\0'; |
| - | /* convert the rest of the now valid char header to its typed struct */ |
| - | parse_mode(ar.formated.mode, &typed->mode); |
| - | typed->mtime = atoi(ar.formated.date); |
| - | typed->uid = atoi(ar.formated.uid); |
| - | typed->gid = atoi(ar.formated.gid); |
| + | typed->name[strcspn(typed->name, " /")] = '\0'; |
| + | |
| + | if (archive_handle->filter(archive_handle->accept, archive_handle->reject, typed->name) == EXIT_SUCCESS) { |
| + | archive_handle->action_header(typed); |
| + | if (archive_handle->sub_archive) { |
| + | while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS); |
| + | } else { |
| + | archive_handle->action_data(archive_handle); |
| + | } |
| + | } else { |
| + | data_skip(archive_handle); |
| + | } |
| + | |
| + | archive_handle->offset += typed->size + 1; |
| - | return(typed); |
| + | return(EXIT_SUCCESS); |
| } | |
| @@ -20,8 +20,9 @@ | |
| #include "unarchive.h" | |
| #include "libbb.h" | |
| - | file_header_t *get_header_tar(FILE * tar_stream) |
| + | extern char get_header_tar(archive_handle_t *archive_handle) |
| { | |
| + | file_header_t *file_header = archive_handle->file_header; |
| union { | |
| unsigned char raw[512]; | |
| struct { | |
| @@ -44,20 +45,22 @@ file_header_t *get_header_tar(FILE * tar_stream) | |
| char padding[12]; /* 500-512 */ | |
| } formated; | |
| } tar; | |
| - | file_header_t *tar_entry = NULL; |
| long sum = 0; | |
| long i; | |
| - | if (archive_offset % 512 != 0) { |
| - | seek_sub_file(tar_stream, 512 - (archive_offset % 512)); |
| + | /* Align header */ |
| + | archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 512); |
| + | |
| + | if (xread_all_eof(archive_handle->src_fd, tar.raw, 512) == 0) { |
| + | /* End of file */ |
| + | return(EXIT_FAILURE); |
| } | |
| + | archive_handle->offset += 512; |
| - | if (fread(tar.raw, 1, 512, tar_stream) != 512) { |
| - | /* Unfortunatly its common for tar files to have all sorts of |
| - | * trailing garbage, fail silently */ |
| - | return (NULL); |
| + | /* If there is no filename its an empty header */ |
| + | if (tar.formated.name[0] == 0) { |
| + | return(EXIT_SUCCESS); |
| } | |
| - | archive_offset += 512; |
| /* Check header has valid magic, "ustar" is for the proper tar | |
| * 0's are for the old tar format | |
| @@ -66,100 +69,102 @@ file_header_t *get_header_tar(FILE * tar_stream) | |
| #ifdef CONFIG_FEATURE_TAR_OLD_FORMAT | |
| if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) | |
| #endif | |
| - | return (NULL); |
| - | } |
| - | |
| - | /* If there is no filename its an empty header, skip it */ |
| - | if (tar.formated.name[0] == 0) { |
| - | return (NULL); |
| + | error_msg_and_die("Invalid tar magic"); |
| } | |
| /* Do checksum on headers */ | |
| - | for (i = 0; i < 148; i++) { |
| + | for (i = 0; i < 148 ; i++) { |
| sum += tar.raw[i]; | |
| } | |
| sum += ' ' * 8; | |
| - | for (i = 156; i < 512; i++) { |
| + | for (i = 156; i < 512 ; i++) { |
| sum += tar.raw[i]; | |
| } | |
| if (sum != strtol(tar.formated.chksum, NULL, 8)) { | |
| error_msg("Invalid tar header checksum"); | |
| - | return (NULL); |
| + | return(EXIT_FAILURE); |
| } | |
| /* convert to type'ed variables */ | |
| - | tar_entry = xcalloc(1, sizeof(file_header_t)); |
| if (tar.formated.prefix[0] == 0) { | |
| - | tar_entry->name = xstrdup(tar.formated.name); |
| + | file_header->name = strdup(tar.formated.name); |
| } else { | |
| - | tar_entry->name = |
| - | concat_path_file(tar.formated.prefix, tar.formated.name); |
| + | file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name); |
| } | |
| - | |
| - | tar_entry->mode = strtol(tar.formated.mode, NULL, 8); |
| - | tar_entry->uid = strtol(tar.formated.uid, NULL, 8); |
| - | tar_entry->gid = strtol(tar.formated.gid, NULL, 8); |
| - | tar_entry->size = strtol(tar.formated.size, NULL, 8); |
| - | tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); |
| - | tar_entry->link_name = |
| - | strlen(tar.formated.linkname) ? xstrdup(tar.formated.linkname) : NULL; |
| - | tar_entry->device = |
| - | (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + |
| + | file_header->mode = strtol(tar.formated.mode, NULL, 8); |
| + | file_header->uid = strtol(tar.formated.uid, NULL, 8); |
| + | file_header->gid = strtol(tar.formated.gid, NULL, 8); |
| + | file_header->size = strtol(tar.formated.size, NULL, 8); |
| + | file_header->mtime = strtol(tar.formated.mtime, NULL, 8); |
| + | file_header->link_name = (tar.formated.linkname[0] != '\0') ? |
| + | xstrdup(tar.formated.linkname) : NULL; |
| + | file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + |
| strtol(tar.formated.devminor, NULL, 8)); | |
| #if defined CONFIG_FEATURE_TAR_OLD_FORMAT || defined CONFIG_FEATURE_GNUTAR_LONG_FILENAME | |
| + | /* Fix mode, used by the old format */ |
| switch (tar.formated.typeflag) { | |
| # ifdef CONFIG_FEATURE_TAR_OLD_FORMAT | |
| case 0: | |
| - | tar_entry->mode |= S_IFREG; |
| + | file_header->mode |= S_IFREG; |
| break; | |
| case 1: | |
| - | error_msg("internal hard link not handled\n"); |
| + | error_msg("Internal hard link not supported"); |
| break; | |
| case 2: | |
| - | tar_entry->mode |= S_IFLNK; |
| + | file_header->mode |= S_IFLNK; |
| break; | |
| case 3: | |
| - | tar_entry->mode |= S_IFCHR; |
| + | file_header->mode |= S_IFCHR; |
| break; | |
| case 4: | |
| - | tar_entry->mode |= S_IFBLK; |
| + | file_header->mode |= S_IFBLK; |
| break; | |
| case 5: | |
| - | tar_entry->mode |= S_IFDIR; |
| + | file_header->mode |= S_IFDIR; |
| break; | |
| case 6: | |
| - | tar_entry->mode |= S_IFIFO; |
| + | file_header->mode |= S_IFIFO; |
| break; | |
| # endif | |
| # ifdef CONFIG_FEATURE_GNUTAR_LONG_FILENAME | |
| case 'L': { | |
| char *longname; | |
| - | longname = xmalloc(tar_entry->size + 1); |
| - | fread(longname, 1, tar_entry->size, tar_stream); |
| - | archive_offset += tar_entry->size; |
| - | longname[tar_entry->size] = '\0'; |
| + | longname = xmalloc(file_header->size + 1); |
| + | xread_all(archive_handle->src_fd, longname, file_header->size); |
| + | longname[file_header->size] = '\0'; |
| + | archive_handle->offset += file_header->size; |
| - | tar_entry = get_header_tar(tar_stream); |
| - | tar_entry->name = longname; |
| + | get_header_tar(archive_handle); |
| + | file_header->name = longname; |
| break; | |
| } | |
| case 'K': { | |
| - | char *longname; |
| + | char *linkname; |
| - | longname = xmalloc(tar_entry->size + 1); |
| - | fread(longname, 1, tar_entry->size, tar_stream); |
| - | archive_offset += tar_entry->size; |
| - | longname[tar_entry->size] = '\0'; |
| + | linkname = xmalloc(file_header->size + 1); |
| + | xread_all(archive_handle->src_fd, linkname, file_header->size); |
| + | linkname[file_header->size] = '\0'; |
| + | archive_handle->offset += file_header->size; |
| - | tar_entry = get_header_tar(tar_stream); |
| - | tar_entry->link_name = longname; |
| + | get_header_tar(archive_handle); |
| + | file_header->name = linkname; |
| break; | |
| } | |
| # endif | |
| } | |
| #endif | |
| - | return (tar_entry); |
| + | if (archive_handle->filter(archive_handle->accept, archive_handle->reject, archive_handle->file_header->name) == EXIT_SUCCESS) { |
| + | archive_handle->action_header(archive_handle->file_header); |
| + | archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; |
| + | archive_handle->action_data(archive_handle); |
| + | } else { |
| + | data_skip(archive_handle); |
| + | } |
| + | archive_handle->offset += file_header->size; |
| + | |
| + | return(EXIT_SUCCESS); |
| } | |
| + | |
| @@ -0,0 +1,73 @@ | |
| + | /* |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU Library General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| + | */ |
| + | |
| + | #include <sys/types.h> |
| + | #include <signal.h> |
| + | #include <stdio.h> |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <unistd.h> |
| + | #include "libbb.h" |
| + | #include "unarchive.h" |
| + | |
| + | extern char get_header_tar_gz(archive_handle_t *archive_handle) |
| + | { |
| + | int fd_pipe[2]; |
| + | int pid; |
| + | |
| + | check_header_gzip(archive_handle->src_fd); |
| + | |
| + | if (pipe(fd_pipe) != 0) { |
| + | error_msg_and_die("Can't create pipe\n"); |
| + | } |
| + | |
| + | pid = fork(); |
| + | if (pid == -1) { |
| + | error_msg_and_die("Fork failed\n"); |
| + | } |
| + | |
| + | if (pid == 0) { |
| + | /* child process */ |
| + | close(fd_pipe[0]); /* We don't wan't to read from the pipe */ |
| + | inflate(archive_handle->src_fd, fd_pipe[1]); |
| + | check_trailer_gzip(archive_handle->src_fd); |
| + | close(fd_pipe[1]); /* Send EOF */ |
| + | exit(0); |
| + | /* notreached */ |
| + | } |
| + | /* parent process */ |
| + | close(fd_pipe[1]); /* Don't want to write down the pipe */ |
| + | close(archive_handle->src_fd); |
| + | |
| + | archive_handle->src_fd = fd_pipe[0]; |
| + | |
| + | while (get_header_tar(archive_handle) == EXIT_SUCCESS); |
| + | |
| + | if (kill(pid, SIGTERM) == -1) { |
| + | error_msg_and_die("Couldnt kill gunzip process"); |
| + | } |
| + | |
| + | /* I dont think this is needed */ |
| + | #if 0 |
| + | if (waitpid(pid, NULL, 0) == -1) { |
| + | error_msg("Couldnt wait ?"); |
| + | } |
| + | #endif |
| + | |
| + | /* Can only do one file at a time */ |
| + | return(EXIT_FAILURE); |
| + | } |
| + | |
| @@ -0,0 +1,7 @@ | |
| + | #include <stdio.h> |
| + | #include "unarchive.h" |
| + | |
| + | extern void header_list(const file_header_t *file_header) |
| + | { |
| + | puts(file_header->name); |
| + | } |
| @@ -0,0 +1,7 @@ | |
| + | #include <stdio.h> |
| + | #include "unarchive.h" |
| + | |
| + | extern void header_skip(const file_header_t *file_header) |
| + | { |
| + | return; |
| + | } |
| @@ -0,0 +1,29 @@ | |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | #include <time.h> |
| + | #include "libbb.h" |
| + | #include "unarchive.h" |
| + | |
| + | extern void header_verbose_list(const file_header_t *file_header) |
| + | { |
| + | struct tm *mtime = localtime(&file_header->mtime); |
| + | |
| + | printf("%s %d/%d%10u %4u-%02u-%02u %02u:%02u:%02u %s", |
| + | mode_string(file_header->mode), |
| + | file_header->uid, |
| + | file_header->gid, |
| + | (unsigned int) file_header->size, |
| + | 1900 + mtime->tm_year, |
| + | 1 + mtime->tm_mon, |
| + | mtime->tm_mday, |
| + | mtime->tm_hour, |
| + | mtime->tm_min, |
| + | mtime->tm_sec, |
| + | file_header->name); |
| + | |
| + | if (file_header->link_name) { |
| + | printf(" -> %s", file_header->link_name); |
| + | } |
| + | /* putchar isnt used anywhere else i dont think */ |
| + | puts(""); |
| + | } |
| @@ -0,0 +1,18 @@ | |
| + | #include <string.h> |
| + | #include "libbb.h" |
| + | #include "unarchive.h" |
| + | |
| + | archive_handle_t *init_handle(void) |
| + | { |
| + | archive_handle_t *archive_handle; |
| + | |
| + | /* Initialise default values */ |
| + | archive_handle = xmalloc(sizeof(archive_handle_t)); |
| + | memset(archive_handle, 0, sizeof(archive_handle_t)); |
| + | archive_handle->file_header = xmalloc(sizeof(file_header_t)); |
| + | archive_handle->action_header = header_skip; |
| + | archive_handle->action_data = data_skip; |
| + | archive_handle->filter = filter_accept_all; |
| + | |
| + | return(archive_handle); |
| + | } |
| @@ -14,23 +14,19 @@ | |
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| */ | |
| - | #include <stdio.h> |
| + | #include <sys/types.h> |
| #include <errno.h> | |
| - | #include <stdlib.h> |
| #include <unistd.h> | |
| + | #include <stdlib.h> |
| + | #include "unarchive.h" |
| + | #include "libbb.h" |
| - | off_t archive_offset; |
| - | |
| - | void seek_sub_file(FILE *src_stream, const int count) |
| + | extern void seek_sub_file(const int src_fd, const unsigned int amount) |
| { | |
| - | /* Try to fseek as faster */ |
| - | archive_offset += count; |
| - | if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) { |
| - | int i; |
| - | for (i = 0; i < count; i++) { |
| - | fgetc(src_stream); |
| + | if ((lseek(src_fd, amount, SEEK_CUR) == -1) && (errno == ESPIPE)) { |
| + | unsigned int i; |
| + | for (i = 0; i < amount; i++) { |
| + | xread_char(src_fd); |
| } | |
| } | |
| - | return; |
| } | |
| - | |
| @@ -0,0 +1,34 @@ | |
| + | /* |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU Library General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| + | */ |
| + | #include <fcntl.h> |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <getopt.h> |
| + | #include "unarchive.h" |
| + | #include "busybox.h" |
| + | |
| + | extern void unpack_ar_archive(archive_handle_t *ar_archive) |
| + | { |
| + | char magic[7]; |
| + | |
| + | xread_all(ar_archive->src_fd, magic, 7); |
| + | if (strncmp(magic, "!<arch>", 7) != 0) { |
| + | error_msg_and_die("Invalid ar magic"); |
| + | } |
| + | ar_archive->offset += 7; |
| + | |
| + | while (get_header_ar(ar_archive) == EXIT_SUCCESS); |
| + | } |
| @@ -65,114 +65,126 @@ static char *license_msg[] = { | |
| #include <signal.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| #include "config.h" | |
| - | #include "libbb.h" |
| + | #include "busybox.h" |
| + | #include "unarchive.h" |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | int uncompress(FILE * in, FILE * out); |
| - | #endif |
| - | |
| - | static FILE *in_file, *out_file; |
| + | typedef struct huft_s { |
| + | unsigned char e; /* number of extra bits or operation */ |
| + | unsigned char b; /* number of bits in this code or subcode */ |
| + | union { |
| + | unsigned short n; /* literal, length base, or distance base */ |
| + | struct huft_s *t; /* pointer to next level of table */ |
| + | } v; |
| + | } huft_t; |
| - | /* these are freed by gz_close */ |
| - | static unsigned char *window; |
| - | static unsigned long *crc_table; |
| + | static int gunzip_src_fd; |
| + | static int gunzip_dst_fd; |
| + | unsigned int gunzip_bytes_out; /* number of output bytes */ |
| + | static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ |
| - | static unsigned long crc; /* shift register contents */ |
| + | /* This is used to sanify any unused bits from the bitbuffer |
| + | * so they arent skipped when reading trailers (trailing headers) */ |
| + | unsigned char gunzip_in_buffer_count; |
| + | unsigned char *gunzip_in_buffer; |
| - | /* Return codes from gzip */ |
| - | #define ERROR 1 |
| + | /* gunzip_window size--must be a power of two, and |
| + | * at least 32K for zip's deflate method */ |
| + | static const int gunzip_wsize = 0x8000; |
| - | /* |
| - | * window size--must be a power of two, and |
| - | * at least 32K for zip's deflate method |
| - | */ |
| - | #define WSIZE 0x8000 |
| + | static unsigned char *gunzip_window; |
| + | static unsigned int *gunzip_crc_table; |
| + | unsigned int gunzip_crc; |
| /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ | |
| #define BMAX 16 /* maximum bit length of any code (16 for explode) */ | |
| #define N_MAX 288 /* maximum number of codes in any set */ | |
| - | static long bytes_out; /* number of output bytes */ |
| - | static unsigned long outcnt; /* bytes in output buffer */ |
| - | |
| - | static unsigned hufts; /* track memory usage */ |
| - | static unsigned long bb; /* bit buffer */ |
| - | static unsigned bk; /* bits in bit buffer */ |
| - | |
| - | typedef struct huft_s { |
| - | unsigned char e; /* number of extra bits or operation */ |
| - | unsigned char b; /* number of bits in this code or subcode */ |
| - | union { |
| - | unsigned short n; /* literal, length base, or distance base */ |
| - | struct huft_s *t; /* pointer to next level of table */ |
| - | } v; |
| - | } huft_t; |
| + | static unsigned int gunzip_hufts; /* track memory usage */ |
| + | static unsigned int gunzip_bb; /* bit buffer */ |
| + | static unsigned char gunzip_bk; /* bits in bit buffer */ |
| static const unsigned short mask_bits[] = { | |
| - | 0x0000, |
| - | 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| + | 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | |
| }; | |
| - | /* static int error_number = 0; */ |
| - | /* ======================================================================== |
| - | * Signal and error handler. |
| - | */ |
| + | /* Copy lengths for literal codes 257..285 */ |
| + | static const unsigned short cplens[] = { |
| + | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, |
| + | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| + | }; |
| + | |
| + | /* note: see note #13 above about the 258 in this list. */ |
| + | /* Extra bits for literal codes 257..285 */ |
| + | static const unsigned char cplext[] = { |
| + | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, |
| + | 5, 5, 5, 0, 99, 99 |
| + | }; /* 99==invalid */ |
| + | |
| + | /* Copy offsets for distance codes 0..29 */ |
| + | static const unsigned short cpdist[] = { |
| + | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, |
| + | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 |
| + | }; |
| + | |
| + | /* Extra bits for distance codes */ |
| + | static const unsigned char cpdext[] = { |
| + | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, |
| + | 11, 11, 12, 12, 13, 13 |
| + | }; |
| + | |
| + | /* Tables for deflate from PKZIP's appnote.txt. */ |
| + | /* Order of the bit length code lengths */ |
| + | static const unsigned char border[] = { |
| + | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| + | }; |
| + | |
| + | static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) |
| + | { |
| + | while (*current < required) { |
| + | bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; |
| + | *current += 8; |
| + | } |
| + | |
| + | return(bitbuffer); |
| + | } |
| static void abort_gzip(void) | |
| { | |
| error_msg("gzip aborted\n"); | |
| - | exit(ERROR); |
| + | exit(-1); |
| } | |
| - | static void make_crc_table(void) |
| + | static void make_gunzip_crc_table(void) |
| { | |
| - | const unsigned long poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| + | const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| unsigned short i; /* counter for all possible eight bit values */ | |
| /* initial shift register value */ | |
| - | crc = 0xffffffffL; |
| - | crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); |
| + | gunzip_crc = 0xffffffffL; |
| + | gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); |
| /* Compute and print table of CRC's, five per line */ | |
| for (i = 0; i < 256; i++) { | |
| - | unsigned long table_entry; /* crc shift register */ |
| - | char k; /* byte being shifted into crc apparatus */ |
| + | unsigned int table_entry; /* crc shift register */ |
| + | unsigned char k; /* byte being shifted into crc apparatus */ |
| table_entry = i; | |
| /* The idea to initialize the register with the byte instead of | |
| * zero was stolen from Haruhiko Okumura's ar002 | |
| */ | |
| for (k = 8; k; k--) { | |
| - | table_entry = |
| - | table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> |
| - | 1; |
| - | } |
| - | crc_table[i] = table_entry; |
| + | if (table_entry & 1) { |
| + | table_entry = (table_entry >> 1) ^ poly; |
| + | } else { |
| + | table_entry >>= 1; |
| } | |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
| - | * (Used for the decompressed data only.) |
| - | */ |
| - | static void flush_window(void) |
| - | { |
| - | int n; |
| - | |
| - | if (outcnt == 0) |
| - | return; |
| - | |
| - | for (n = 0; n < outcnt; n++) { |
| - | crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); |
| } | |
| - | |
| - | if (fwrite(window, 1, outcnt, out_file) != outcnt) { |
| - | error_msg_and_die("Couldnt write"); |
| + | gunzip_crc_table[i] = table_entry; |
| } | |
| - | bytes_out += (unsigned long) outcnt; |
| - | outcnt = 0; |
| } | |
| /* | |
| @@ -183,7 +195,8 @@ static void flush_window(void) | |
| */ | |
| static int huft_free(huft_t * t) | |
| { | |
| - | huft_t *p, *q; |
| + | huft_t *p; |
| + | huft_t *q; |
| /* Go through linked list, freeing from the malloced (t[-1]) address. */ | |
| p = t; | |
| @@ -195,8 +208,6 @@ static int huft_free(huft_t * t) | |
| return 0; | |
| } | |
| - | typedef unsigned char extra_bits_t; |
| - | |
| /* Given a list of code lengths and a maximum table size, make a set of | |
| * tables to decode that set of codes. Return zero on success, one if | |
| * the given code set is incomplete (the tables are still built in this | |
| @@ -213,7 +224,7 @@ typedef unsigned char extra_bits_t; | |
| */ | |
| static int huft_build(unsigned int *b, const unsigned int n, | |
| const unsigned int s, const unsigned short *d, | |
| - | const extra_bits_t * e, huft_t ** t, int *m) |
| + | const unsigned char *e, huft_t ** t, int *m) |
| { | |
| unsigned a; /* counter for codes of length k */ | |
| unsigned c[BMAX + 1]; /* bit length count table */ | |
| @@ -251,26 +262,35 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* Find minimum and maximum length, bound *m by those */ | |
| l = *m; | |
| - | for (j = 1; j <= BMAX; j++) |
| - | if (c[j]) |
| + | for (j = 1; j <= BMAX; j++) { |
| + | if (c[j]) { |
| break; | |
| + | } |
| + | } |
| k = j; /* minimum code length */ | |
| - | if ((unsigned) l < j) |
| + | if ((unsigned) l < j) { |
| l = j; | |
| - | for (i = BMAX; i; i--) |
| - | if (c[i]) |
| + | } |
| + | for (i = BMAX; i; i--) { |
| + | if (c[i]) { |
| break; | |
| + | } |
| + | } |
| g = i; /* maximum code length */ | |
| - | if ((unsigned) l > i) |
| + | if ((unsigned) l > i) { |
| l = i; | |
| + | } |
| *m = l; | |
| /* Adjust last length count to fill out codes, if needed */ | |
| - | for (y = 1 << j; j < i; j++, y <<= 1) |
| - | if ((y -= c[j]) < 0) |
| + | for (y = 1 << j; j < i; j++, y <<= 1) { |
| + | if ((y -= c[j]) < 0) { |
| return 2; /* bad input: more codes than bits */ | |
| - | if ((y -= c[i]) < 0) |
| + | } |
| + | } |
| + | if ((y -= c[i]) < 0) { |
| return 2; | |
| + | } |
| c[i] += y; | |
| /* Generate starting offsets into the value table for each length */ | |
| @@ -285,8 +305,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| p = b; | |
| i = 0; | |
| do { | |
| - | if ((j = *p++) != 0) |
| + | if ((j = *p++) != 0) { |
| v[x[j]++] = i; | |
| + | } |
| } while (++i < n); | |
| /* Generate the Huffman codes and for each, make the table entries */ | |
| @@ -314,8 +335,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| f -= a + 1; /* deduct codes from patterns left */ | |
| xp = c + k; | |
| while (++j < z) { /* try smaller tables up to z bits */ | |
| - | if ((f <<= 1) <= *++xp) |
| + | if ((f <<= 1) <= *++xp) { |
| break; /* enough codes to use up j bits */ | |
| + | } |
| f -= *xp; /* else deduct codes from patterns */ | |
| } | |
| } | |
| @@ -324,7 +346,7 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* allocate and link in new table */ | |
| q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); | |
| - | hufts += z + 1; /* track memory usage */ |
| + | gunzip_hufts += z + 1; /* track memory usage */ |
| *t = q + 1; /* link to list for huft_free() */ | |
| *(t = &(q->v.t)) = NULL; | |
| u[h] = ++q; /* table starts after link */ | |
| @@ -342,9 +364,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* set up table entry in r */ | |
| r.b = (unsigned char) (k - w); | |
| - | if (p >= v + n) |
| + | if (p >= v + n) { |
| r.e = 99; /* out of values--invalid code */ | |
| - | else if (*p < s) { |
| + | } else if (*p < s) { |
| r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ | |
| r.v.n = (unsigned short) (*p); /* simple code is just the value */ | |
| p++; /* one compiler does not like *p++ */ | |
| @@ -355,12 +377,14 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* fill code-like entries with r */ | |
| f = 1 << (k - w); | |
| - | for (j = i >> w; j < z; j += f) |
| + | for (j = i >> w; j < z; j += f) { |
| q[j] = r; | |
| + | } |
| /* backwards increment the k-bit code i */ | |
| - | for (j = 1 << (k - 1); i & j; j >>= 1) |
| + | for (j = 1 << (k - 1); i & j; j >>= 1) { |
| i ^= j; | |
| + | } |
| i ^= j; | |
| /* backup over finished tables */ | |
| @@ -374,6 +398,25 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| return y != 0 && g != 1; | |
| } | |
| + | /* =========================================================================== |
| + | * Write the output gunzip_window gunzip_window[0..gunzip_outbuf_count-1] and update crc and gunzip_bytes_out. |
| + | * (Used for the decompressed data only.) |
| + | */ |
| + | static void flush_gunzip_window(void) |
| + | { |
| + | int n; |
| + | |
| + | for (n = 0; n < gunzip_outbuf_count; n++) { |
| + | gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); |
| + | } |
| + | |
| + | if (write(gunzip_dst_fd, gunzip_window, gunzip_outbuf_count) != gunzip_outbuf_count) { |
| + | error_msg_and_die("Couldnt write"); |
| + | } |
| + | gunzip_bytes_out += gunzip_outbuf_count; |
| + | gunzip_outbuf_count = 0; |
| + | } |
| + | |
| /* | |
| * inflate (decompress) the codes in a deflated (compressed) block. | |
| * Return an error code or zero if it all goes ok. | |
| @@ -381,32 +424,26 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| * tl, td: literal/length and distance decoder tables | |
| * bl, bd: number of bits decoded by tl[] and td[] | |
| */ | |
| - | static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) |
| + | static int inflate_codes(huft_t * tl, huft_t * td, const unsigned int bl, const unsigned int bd) |
| { | |
| - | register unsigned long e; /* table entry flag/number of extra bits */ |
| - | unsigned long n, d; /* length and index for copy */ |
| - | unsigned long w; /* current window position */ |
| + | unsigned int e; /* table entry flag/number of extra bits */ |
| + | unsigned int n, d; /* length and index for copy */ |
| + | unsigned int w; /* current gunzip_window position */ |
| huft_t *t; /* pointer to table entry */ | |
| - | unsigned ml, md; /* masks for bl and bd bits */ |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | register int input_char; |
| + | unsigned int ml, md; /* masks for bl and bd bits */ |
| + | unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b = bb; /* initialize bit buffer */ |
| - | k = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b = gunzip_bb; /* initialize bit buffer */ |
| + | k = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* inflate the coded data */ | |
| ml = mask_bits[bl]; /* precompute masks for speed */ | |
| md = mask_bits[bd]; | |
| - | for (;;) { /* do until end of block */ |
| - | while (k < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | while (1) { /* do until end of block */ |
| + | b = fill_bitbuffer(b, &k, bl); |
| if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) | |
| do { | |
| if (e == 99) { | |
| @@ -415,20 +452,16 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| if (e == 16) { /* then it's a literal */ | |
| - | window[w++] = (unsigned char) t->v.n; |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | gunzip_window[w++] = (unsigned char) t->v.n; |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| } else { /* it's an EOB or a length */ | |
| @@ -439,24 +472,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| } | |
| /* get length of block to copy */ | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| n = t->v.n + ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| /* decode distance of block to copy */ | |
| - | while (k < (unsigned) bd) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| - | |
| + | b = fill_bitbuffer(b, &k, bd); |
| if ((e = (t = td + ((unsigned) b & md))->e) > 16) | |
| do { | |
| if (e == 99) | |
| @@ -464,23 +486,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = | |
| t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| d = w - t->v.n - ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| @@ -489,60 +501,38 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| do { | |
| n -= (e = | |
| (e = | |
| - | WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); |
| - | #if !defined(NOMEMCPY) && !defined(DEBUG) |
| + | gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); |
| + | /* copy to new buffer to prevent possible overwrite */ |
| if (w - d >= e) { /* (this test assumes unsigned comparison) */ | |
| - | memcpy(window + w, window + d, e); |
| + | memcpy(gunzip_window + w, gunzip_window + d, e); |
| w += e; | |
| d += e; | |
| - | } else /* do it slow to avoid memcpy() overlap */ |
| - | #endif /* !NOMEMCPY */ |
| + | } else { |
| + | /* do it slow to avoid memcpy() overlap */ |
| + | /* !NOMEMCPY */ |
| do { | |
| - | window[w++] = window[d++]; |
| + | gunzip_window[w++] = gunzip_window[d++]; |
| } while (--e); | |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | } |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| + | |
| } while (n); | |
| } | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b; /* restore global bit buffer */ |
| - | bk = k; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b; /* restore global bit buffer */ |
| + | gunzip_bk = k; |
| /* done */ | |
| return 0; | |
| } | |
| - | static const unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ |
| - | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, |
| - | 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| - | }; |
| - | |
| - | /* note: see note #13 above about the 258 in this list. */ |
| - | static const extra_bits_t cplext[] = { /* Extra bits for literal codes 257..285 */ |
| - | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, |
| - | 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 |
| - | }; /* 99==invalid */ |
| - | static const unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ |
| - | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, |
| - | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, |
| - | 8193, 12289, 16385, 24577 |
| - | }; |
| - | static const extra_bits_t cpdext[] = { /* Extra bits for distance codes */ |
| - | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, |
| - | 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, |
| - | 12, 12, 13, 13 |
| - | }; |
| - | |
| - | /* Tables for deflate from PKZIP's appnote.txt. */ |
| - | static const extra_bits_t border[] = { /* Order of the bit length code lengths */ |
| - | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| - | }; |
| - | |
| /* | |
| * decompress an inflated block | |
| * e: last block flag | |
| @@ -552,53 +542,43 @@ static const extra_bits_t border[] = { /* Order of the bit length code lengths * | |
| static int inflate_block(int *e) | |
| { | |
| unsigned t; /* block type */ | |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | int input_char; |
| + | register unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b = bb; |
| - | k = bk; |
| + | |
| + | b = gunzip_bb; |
| + | k = gunzip_bk; |
| /* read in last block bit */ | |
| - | while (k < 1) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 1); |
| *e = (int) b & 1; | |
| b >>= 1; | |
| k -= 1; | |
| /* read in block type */ | |
| - | while (k < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 2); |
| t = (unsigned) b & 3; | |
| b >>= 2; | |
| k -= 2; | |
| /* restore the global bit buffer */ | |
| - | bb = b; |
| - | bk = k; |
| + | gunzip_bb = b; |
| + | gunzip_bk = k; |
| /* inflate that block type */ | |
| switch (t) { | |
| case 0: /* Inflate stored */ | |
| { | |
| - | unsigned long n; /* number of bytes in block */ |
| - | unsigned long w; /* current window position */ |
| - | register unsigned long b_stored; /* bit buffer */ |
| - | register unsigned long k_stored; /* number of bits in bit buffer */ |
| + | unsigned int n; /* number of bytes in block */ |
| + | unsigned int w; /* current gunzip_window position */ |
| + | unsigned int b_stored; /* bit buffer */ |
| + | unsigned int k_stored; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b_stored = bb; /* initialize bit buffer */ |
| - | k_stored = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b_stored = gunzip_bb; /* initialize bit buffer */ |
| + | k_stored = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* go to byte boundary */ | |
| n = k_stored & 7; | |
| @@ -606,21 +586,12 @@ static int inflate_block(int *e) | |
| k_stored -= n; | |
| /* get the length and its complement */ | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| n = ((unsigned) b_stored & 0xffff); | |
| b_stored >>= 16; | |
| k_stored -= 16; | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| if (n != (unsigned) ((~b_stored) & 0xffff)) { | |
| return 1; /* error in compressed data */ | |
| } | |
| @@ -629,15 +600,11 @@ static int inflate_block(int *e) | |
| /* read and output the compressed data */ | |
| while (n--) { | |
| - | while (k_stored < 8) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| - | window[w++] = (unsigned char) b_stored; |
| - | if (w == (unsigned long) WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 8); |
| + | gunzip_window[w++] = (unsigned char) b_stored; |
| + | if (w == (unsigned int) gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| b_stored >>= 8; | |
| @@ -645,9 +612,9 @@ static int inflate_block(int *e) | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b_stored; /* restore global bit buffer */ |
| - | bk = k_stored; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b_stored; /* restore global bit buffer */ |
| + | gunzip_bk = k_stored; |
| return 0; | |
| } | |
| case 1: /* Inflate fixed | |
| @@ -659,8 +626,8 @@ static int inflate_block(int *e) | |
| int i; /* temporary variable */ | |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| unsigned int l[288]; /* length list for huft_build */ | |
| /* set up literal table */ | |
| @@ -692,8 +659,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -705,53 +673,41 @@ static int inflate_block(int *e) | |
| const int dbits = 6; /* bits in base distance lookup table */ | |
| const int lbits = 9; /* bits in base literal/length lookup table */ | |
| - | int i; /* temporary variables */ |
| - | unsigned j; |
| - | unsigned l; /* last length */ |
| - | unsigned m; /* mask for bit lengths table */ |
| - | unsigned n; /* number of lengths to get */ |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| - | unsigned nb; /* number of bit length codes */ |
| - | unsigned nl; /* number of literal/length codes */ |
| - | unsigned nd; /* number of distance codes */ |
| - | |
| - | unsigned ll[286 + 30]; /* literal/length and distance code lengths */ |
| - | register unsigned long b_dynamic; /* bit buffer */ |
| - | register unsigned k_dynamic; /* number of bits in bit buffer */ |
| + | unsigned int i; /* temporary variables */ |
| + | unsigned int j; |
| + | unsigned int l; /* last length */ |
| + | unsigned int m; /* mask for bit lengths table */ |
| + | unsigned int n; /* number of lengths to get */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| + | unsigned int nb; /* number of bit length codes */ |
| + | unsigned int nl; /* number of literal/length codes */ |
| + | unsigned int nd; /* number of distance codes */ |
| + | |
| + | unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ |
| + | unsigned int b_dynamic; /* bit buffer */ |
| + | unsigned int k_dynamic; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b_dynamic = bb; |
| - | k_dynamic = bk; |
| + | b_dynamic = gunzip_bb; |
| + | k_dynamic = gunzip_bk; |
| /* read in table lengths */ | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 4) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); |
| + | nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ |
| + | |
| b_dynamic >>= 4; | |
| k_dynamic -= 4; | |
| if (nl > 286 || nd > 30) { | |
| @@ -760,13 +716,8 @@ static int inflate_block(int *e) | |
| /* read in bit-length-code lengths */ | |
| for (j = 0; j < nb; j++) { | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | ll[border[j]] = (unsigned) b_dynamic & 7; |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | ll[border[j]] = (unsigned int) b_dynamic & 7; |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| } | |
| @@ -776,7 +727,8 @@ static int inflate_block(int *e) | |
| /* build decoding table for trees--single level, 7 bit lookup */ | |
| bl = 7; | |
| - | if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { |
| + | i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); |
| + | if (i != 0) { |
| if (i == 1) { | |
| huft_free(tl); | |
| } | |
| @@ -787,46 +739,31 @@ static int inflate_block(int *e) | |
| n = nl + nd; | |
| m = mask_bits[bl]; | |
| i = l = 0; | |
| - | while ((unsigned) i < n) { |
| - | while (k_dynamic < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = (td = tl + ((unsigned) b_dynamic & m))->b; |
| + | while ((unsigned int) i < n) { |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); |
| + | j = (td = tl + ((unsigned int) b_dynamic & m))->b; |
| b_dynamic >>= j; | |
| k_dynamic -= j; | |
| j = td->v.n; | |
| if (j < 16) { /* length of code in bits (0..15) */ | |
| ll[i++] = l = j; /* save last length in l */ | |
| } else if (j == 16) { /* repeat last length 3 to 6 times */ | |
| - | while (k_dynamic < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 3); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); |
| + | j = 3 + ((unsigned int) b_dynamic & 3); |
| b_dynamic >>= 2; | |
| k_dynamic -= 2; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| ll[i++] = l; | |
| } | |
| } else if (j == 17) { /* 3 to 10 zero length codes */ | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 7); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | j = 3 + ((unsigned int) b_dynamic & 7); |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -834,16 +771,11 @@ static int inflate_block(int *e) | |
| } | |
| l = 0; | |
| } else { /* j == 18: 11 to 138 zero length codes */ | |
| - | while (k_dynamic < 7) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 11 + ((unsigned) b_dynamic & 0x7f); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); |
| + | j = 11 + ((unsigned int) b_dynamic & 0x7f); |
| b_dynamic >>= 7; | |
| k_dynamic -= 7; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -857,22 +789,24 @@ static int inflate_block(int *e) | |
| huft_free(tl); | |
| /* restore the global bit buffer */ | |
| - | bb = b_dynamic; |
| - | bk = k_dynamic; |
| + | gunzip_bb = b_dynamic; |
| + | gunzip_bk = k_dynamic; |
| /* build the decoding tables for literal/length and distance codes */ | |
| bl = lbits; | |
| + | |
| if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("Incomplete literal tree"); |
| + | error_msg_and_die("Incomplete literal tree"); |
| huft_free(tl); | |
| } | |
| return i; /* incomplete code set */ | |
| } | |
| + | |
| bd = dbits; | |
| if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("incomplete distance tree"); |
| + | error_msg_and_die("incomplete distance tree"); |
| huft_free(td); | |
| } | |
| huft_free(tl); | |
| @@ -880,8 +814,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -890,6 +825,7 @@ static int inflate_block(int *e) | |
| } | |
| default: | |
| /* bad block type */ | |
| + | error_msg("bad block type %d\n", t); |
| return 2; | |
| } | |
| } | |
| @@ -897,72 +833,24 @@ static int inflate_block(int *e) | |
| /* | |
| * decompress an inflated entry | |
| * | |
| - | * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr |
| + | * GLOBAL VARIABLES: gunzip_outbuf_count, bk, gunzip_bb, hufts, inptr |
| */ | |
| - | extern int inflate(FILE * in, FILE * out) |
| + | extern int inflate(int in, int out) |
| { | |
| + | typedef void (*sig_type) (int); |
| int e; /* last block flag */ | |
| int r; /* result code */ | |
| unsigned h = 0; /* maximum struct huft's malloc'ed */ | |
| - | /* initialize window, bit buffer */ |
| - | outcnt = 0; |
| - | bk = 0; |
| - | bb = 0; |
| - | |
| - | in_file = in; |
| - | out_file = out; |
| - | |
| /* Allocate all global buffers (for DYN_ALLOC option) */ | |
| - | window = xmalloc((size_t) (((2L * WSIZE) + 1L) * sizeof(unsigned char))); |
| - | bytes_out = 0L; |
| + | gunzip_window = xmalloc(0x8000); |
| + | gunzip_outbuf_count = 0; |
| + | gunzip_bytes_out = 0; |
| - | /* Create the crc table */ |
| - | make_crc_table(); |
| + | gunzip_src_fd = in; |
| + | gunzip_dst_fd = out; |
| - | /* decompress until the last block */ |
| - | do { |
| - | hufts = 0; |
| - | if ((r = inflate_block(&e)) != 0) { |
| - | return r; |
| - | } |
| - | if (hufts > h) { |
| - | h = hufts; |
| - | } |
| - | } while (!e); |
| - | |
| - | /* Undo too much lookahead. The next read will be byte aligned so we |
| - | * can discard unused bits in the last meaningful byte. |
| - | */ |
| - | while (bk >= 8) { |
| - | bk -= 8; |
| - | ungetc((bb << bk), in_file); |
| - | } |
| - | |
| - | /* flush out window */ |
| - | flush_window(); |
| - | free(window); |
| - | free(crc_table); |
| - | |
| - | /* return success */ |
| - | return 0; |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Unzip in to out. This routine works on gzip files only. |
| - | * |
| - | * IN assertions: the buffer inbuf contains already the beginning of |
| - | * the compressed data, from offsets inptr to insize-1 included. |
| - | * The magic header has already been checked. The output buffer is cleared. |
| - | * in, out: input and output file descriptors |
| - | */ |
| - | extern int unzip(FILE * l_in_file, FILE * l_out_file) |
| - | { |
| - | unsigned char buf[8]; /* extended local header */ |
| - | unsigned char flags; /* compression flags */ |
| - | typedef void (*sig_type) (int); |
| - | unsigned short i; |
| - | unsigned char magic[2]; |
| + | gunzip_in_buffer = malloc(8); |
| if (signal(SIGINT, SIG_IGN) != SIG_IGN) { | |
| (void) signal(SIGINT, (sig_type) abort_gzip); | |
| @@ -973,97 +861,44 @@ extern int unzip(FILE * l_in_file, FILE * l_out_file) | |
| } | |
| #endif | |
| - | magic[0] = fgetc(l_in_file); |
| - | magic[1] = fgetc(l_in_file); |
| - | |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | /* Magic header for compress files, 1F 9d = \037\235 */ |
| - | if ((magic[0] == 0x1F) && (magic[1] == 0x9d)) { |
| - | return uncompress(l_in_file, l_out_file); |
| - | } |
| - | #endif |
| - | |
| - | /* Magic header for gzip files, 1F 8B = \037\213 */ |
| - | if ((magic[0] != 0x1F) || (magic[1] != 0x8b)) { |
| - | error_msg("Invalid gzip magic"); |
| - | return EXIT_FAILURE; |
| - | } |
| - | |
| - | /* Check the compression method */ |
| - | if (fgetc(l_in_file) != 8) /* also catches EOF */ { |
| - | error_msg("Unknown compression method"); |
| - | return (-1); |
| - | } |
| - | |
| - | flags = (unsigned char) fgetc(l_in_file); |
| - | |
| - | /* Ignore time stamp(4), extra flags(1), OS type(1) */ |
| - | for (i = 0; i < 6; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| + | /* initialize gunzip_window, bit buffer */ |
| + | gunzip_bk = 0; |
| + | gunzip_bb = 0; |
| - | if (flags & 0x04) { |
| - | /* bit 2 set: extra field present */ |
| - | const unsigned short extra = |
| - | fgetc(l_in_file) + (fgetc(l_in_file) << 8); |
| - | if (feof(in_file)) return 1; |
| - | for (i = 0; i < extra; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| - | } |
| - | |
| - | /* Discard original name if any */ |
| - | if (flags & 0x08) { |
| - | /* bit 3 set: original file name present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| - | } |
| + | /* Create the crc table */ |
| + | make_gunzip_crc_table(); |
| - | /* Discard file comment if any */ |
| - | if (flags & 0x10) { |
| - | /* bit 4 set: file comment present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| + | /* decompress until the last block */ |
| + | do { |
| + | gunzip_hufts = 0; |
| + | r = inflate_block(&e); |
| + | if (r != 0) { |
| + | error_msg_and_die("inflate error %d", r); |
| + | return r; |
| } | |
| - | |
| - | /* Decompress */ |
| - | if (inflate(l_in_file, l_out_file) != 0) { |
| - | error_msg("invalid compressed data--format violated"); |
| + | if (gunzip_hufts > h) { |
| + | h = gunzip_hufts; |
| } | |
| + | } while (!e); |
| - | /* Get the crc and original length |
| - | * crc32 (see algorithm.doc) |
| - | * uncompressed input size modulo 2^32 |
| - | */ |
| - | fread(buf, 1, 8, l_in_file); |
| - | |
| - | /* Validate decompression - crc */ |
| - | if ((unsigned int) ((buf[0] | (buf[1] << 8)) | |
| - | ((buf[2] | (buf[3] << 8)) << 16)) != |
| - | (crc ^ 0xffffffffL)) { |
| - | error_msg("invalid compressed data--crc error"); |
| - | } |
| - | /* Validate decompression - size */ |
| - | if (((buf[4] | (buf[5] << 8)) | ((buf[6] | (buf[7] << 8)) << 16)) != |
| - | (unsigned long) bytes_out) { |
| - | error_msg("invalid compressed data--length error"); |
| + | /* write any buffered uncompressed data */ |
| + | flush_gunzip_window(); |
| + | free(gunzip_window); |
| + | |
| + | /* Cleanup */ |
| + | free(gunzip_crc_table); |
| + | |
| + | /* Store unused bytes in a global buffer so calling applets can access it */ |
| + | gunzip_in_buffer_count = 0; |
| + | if (gunzip_bk >= 8) { |
| + | /* Undo too much lookahead. The next read will be byte aligned |
| + | * so we can discard unused bits in the last meaningful byte. */ |
| + | gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; |
| + | gunzip_in_buffer_count++; |
| + | gunzip_bb >>= 8; |
| + | gunzip_bk -= 8; |
| } | |
| + | /* return success */ |
| return 0; | |
| } | |
| - | |
| - | /* |
| - | * This needs access to global variables window and crc_table, so its not in its own file. |
| - | */ |
| - | extern void gz_close(int gunzip_pid) |
| - | { |
| - | if (kill(gunzip_pid, SIGTERM) == -1) { |
| - | error_msg_and_die |
| - | ("*** Couldnt kill old gunzip process *** aborting"); |
| - | } |
| - | |
| - | if (waitpid(gunzip_pid, NULL, 0) == -1) { |
| - | printf("Couldnt wait ?"); |
| - | } |
| - | |
| - | free(window); |
| - | free(crc_table); |
| - | } |
| @@ -18,10 +18,13 @@ | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| - | |
| - | #include "busybox.h" |
| + | #include <sys/types.h> |
| #include <netinet/in.h> /* For ntohl & htonl function */ | |
| + | #include <fcntl.h> |
| + | #include <unistd.h> |
| #include <string.h> | |
| + | #include "busybox.h" |
| + | #include "unarchive.h" |
| #define RPM_MAGIC "\355\253\356\333" | |
| #define RPM_HEADER_MAGIC "\216\255\350" | |
| @@ -45,46 +48,54 @@ struct rpm_header { | |
| u_int32_t size; /* Size of store (4 bytes) */ | |
| }; | |
| - | void skip_header(FILE *rpmfile) |
| + | void skip_header(int rpm_fd) |
| { | |
| struct rpm_header header; | |
| - | fread(&header, sizeof(struct rpm_header), 1, rpmfile); |
| - | if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ |
| - | if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ |
| + | xread_all(rpm_fd, &header, sizeof(struct rpm_header)); |
| + | if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) { |
| + | error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ |
| + | } |
| + | if (header.version != 1) { |
| + | error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ |
| + | } |
| header.entries = ntohl(header.entries); | |
| header.size = ntohl(header.size); | |
| - | fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ |
| - | fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */ |
| + | lseek (rpm_fd, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ |
| + | lseek (rpm_fd, header.size, SEEK_CUR); /* Seek past store */ |
| } | |
| /* No getopt required */ | |
| extern int rpm2cpio_main(int argc, char **argv) | |
| { | |
| struct rpm_lead lead; | |
| - | int gunzip_pid; |
| - | FILE *rpmfile, *cpiofile; |
| + | int rpm_fd; |
| if (argc == 1) { | |
| - | rpmfile = stdin; |
| + | rpm_fd = fileno(stdin); |
| } else { | |
| - | rpmfile = xfopen(argv[1], "r"); |
| - | /* set the buffer size */ |
| - | setvbuf(rpmfile, NULL, _IOFBF, 0x8000); |
| + | rpm_fd = xopen(argv[1], O_RDONLY); |
| + | } |
| + | |
| + | xread_all(rpm_fd, &lead, sizeof(struct rpm_lead)); |
| + | if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) { |
| + | error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ |
| } | |
| - | fread (&lead, sizeof(struct rpm_lead), 1, rpmfile); |
| - | if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ |
| /* Skip the signature header */ | |
| - | skip_header(rpmfile); |
| - | fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */ |
| + | skip_header(rpm_fd); |
| + | data_align(rpm_fd, lseek(rpm_fd, 0, SEEK_CUR), 8); |
| + | |
| /* Skip the main header */ | |
| - | skip_header(rpmfile); |
| + | skip_header(rpm_fd); |
| + | |
| + | check_header_gzip(rpm_fd); |
| + | if (inflate(rpm_fd, fileno(stdout)) != 0) { |
| + | error_msg("Error inflating"); |
| + | } |
| + | check_trailer_gzip(rpm_fd); |
| - | cpiofile = gz_open(rpmfile, &gunzip_pid); |
| + | close(rpm_fd); |
| - | copyfd(fileno(cpiofile), fileno(stdout)); |
| - | gz_close(gunzip_pid); |
| - | fclose(rpmfile); |
| return 0; | |
| } | |
| @@ -115,7 +115,7 @@ struct TarBallInfo { | |
| tarball lives, so we can avoid trying | |
| to include the tarball into itself */ | |
| int verboseFlag; /* Whether to print extra stuff or not */ | |
| - | char **excludeList; /* List of files to not include */ |
| + | const llist_t *excludeList; /* List of files to not include */ |
| HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ | |
| HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ | |
| }; | |
| @@ -325,16 +325,15 @@ static inline int writeTarHeader(struct TarBallInfo *tbInfo, | |
| } | |
| # if defined CONFIG_FEATURE_TAR_EXCLUDE | |
| - | static inline int exclude_file(char **excluded_files, const char *file) |
| + | static inline int exclude_file(const llist_t *excluded_files, const char *file) |
| { | |
| - | int i; |
| - | |
| - | if (excluded_files == NULL) |
| + | if (excluded_files == NULL) { |
| return 0; | |
| + | } |
| - | for (i = 0; excluded_files[i] != NULL; i++) { |
| - | if (excluded_files[i][0] == '/') { |
| - | if (fnmatch(excluded_files[i], file, |
| + | while (excluded_files) { |
| + | if (excluded_files->data[0] == '/') { |
| + | if (fnmatch(excluded_files->data, file, |
| FNM_PATHNAME | FNM_LEADING_DIR) == 0) | |
| return 1; | |
| } else { | |
| @@ -342,11 +341,12 @@ static inline int exclude_file(char **excluded_files, const char *file) | |
| for (p = file; p[0] != '\0'; p++) { | |
| if ((p == file || p[-1] == '/') && p[0] != '/' && | |
| - | fnmatch(excluded_files[i], p, |
| + | fnmatch(excluded_files->data, p, |
| FNM_PATHNAME | FNM_LEADING_DIR) == 0) | |
| return 1; | |
| } | |
| } | |
| + | excluded_files = excluded_files->link; |
| } | |
| return 0; | |
| @@ -455,8 +455,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, | |
| return (TRUE); | |
| } | |
| - | static inline int writeTarFile(const char *tarName, int verboseFlag, |
| - | char **argv, char **excludeList, int gzip) |
| + | static inline int writeTarFile(const char *tarName, const int verboseFlag, |
| + | const llist_t *include, const llist_t *exclude, const int gzip) |
| { | |
| #ifdef CONFIG_FEATURE_TAR_GZIP | |
| int gzipDataPipe[2] = { -1, -1 }; | |
| @@ -471,8 +471,9 @@ static inline int writeTarFile(const char *tarName, int verboseFlag, | |
| tbInfo.hlInfoHead = NULL; | |
| /* Make sure there is at least one file to tar up. */ | |
| - | if (*argv == NULL) |
| + | if (include == NULL) { |
| error_msg_and_die("Cowardly refusing to create an empty archive"); | |
| + | } |
| /* Open the tar file for writing. */ | |
| if (tarName == NULL) { | |
| @@ -544,15 +545,16 @@ static inline int writeTarFile(const char *tarName, int verboseFlag, | |
| } | |
| #endif | |
| - | tbInfo.excludeList = excludeList; |
| + | tbInfo.excludeList = exclude; |
| /* Read the directory/files and iterate over them one at a time */ | |
| - | while (*argv != NULL) { |
| - | if (!recursive_action(*argv++, TRUE, FALSE, FALSE, |
| + | while (include) { |
| + | if (!recursive_action(include->data, TRUE, FALSE, FALSE, |
| writeFileToTarball, writeFileToTarball, | |
| (void *) &tbInfo)) { | |
| errorFlag = TRUE; | |
| } | |
| + | include = include->link; |
| } | |
| /* Write two empty blocks to the end of the archive */ | |
| for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { | |
| @@ -582,64 +584,48 @@ static inline int writeTarFile(const char *tarName, int verboseFlag, | |
| } | |
| #endif /* tar_create */ | |
| - | void append_file_to_list(const char *new_name, char ***list, int *list_count) |
| - | { |
| - | *list = realloc(*list, sizeof(char *) * (*list_count + 2)); |
| - | (*list)[*list_count] = xstrdup(new_name); |
| - | (*list_count)++; |
| - | (*list)[*list_count] = NULL; |
| - | } |
| - | |
| - | void append_file_list_to_list(char *filename, char ***name_list, |
| - | int *num_of_entries) |
| + | #ifdef CONFIG_FEATURE_TAR_EXCLUDE |
| + | static const llist_t *append_file_list_to_list(const char *filename, const llist_t *list) |
| { | |
| - | FILE *src_stream; |
| - | char *line; |
| - | |
| - | src_stream = xfopen(filename, "r"); |
| - | while ((line = get_line_from_file(src_stream)) != NULL) { |
| + | FILE *src_stream = xfopen(filename, "r"); |
| + | while(1) { |
| + | char *line = get_line_from_file(src_stream); |
| + | if (line == NULL) { |
| + | break; |
| + | } |
| chomp(line); | |
| - | append_file_to_list(line, name_list, num_of_entries); |
| + | list = add_to_list(list, line); |
| free(line); | |
| } | |
| fclose(src_stream); | |
| + | |
| + | return (list); |
| } | |
| + | #endif |
| int tar_main(int argc, char **argv) | |
| { | |
| - | enum untar_funct_e { |
| - | /* This is optional */ |
| - | untar_unzip = 1, |
| - | /* Require one and only one of these */ |
| - | untar_list = 2, |
| - | untar_create = 4, |
| - | untar_extract = 8 |
| - | }; |
| - | |
| - | FILE *src_stream = NULL; |
| - | FILE *uncompressed_stream = NULL; |
| - | char **include_list = NULL; |
| - | char **exclude_list = NULL; |
| - | char *src_filename = NULL; |
| - | char *dst_prefix = NULL; |
| + | #ifdef CONFIG_FEATURE_TAR_GZIP |
| + | char (*get_header_ptr)(archive_handle_t *) = get_header_tar; |
| + | #endif |
| + | archive_handle_t *tar_handle; |
| int opt; | |
| - | unsigned short untar_funct = 0; |
| - | unsigned short untar_funct_required = 0; |
| - | unsigned short extract_function = 0; |
| - | int include_list_count = 0; |
| + | char *base_dir = NULL; |
| - | #ifdef CONFIG_FEATURE_TAR_EXCLUDE |
| - | int exclude_list_count = 0; |
| - | #endif |
| - | #ifdef CONFIG_FEATURE_TAR_GZIP |
| - | int gunzip_pid; |
| - | int gz_fd = 0; |
| + | #ifdef CONFIG_FEATURE_TAR_CREATE |
| + | char *src_filename = NULL; |
| + | unsigned char tar_create = FALSE; |
| #endif | |
| if (argc < 2) { | |
| show_usage(); | |
| } | |
| + | /* Initialise default values */ |
| + | tar_handle = init_handle(); |
| + | tar_handle->src_fd = fileno(stdin); |
| + | tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS; |
| + | |
| /* Prepend '-' to the first argument if required */ | |
| if (argv[1][0] != '-') { | |
| char *tmp = xmalloc(strlen(argv[1]) + 2); | |
| @@ -648,61 +634,69 @@ int tar_main(int argc, char **argv) | |
| strcpy(tmp + 1, argv[1]); | |
| argv[1] = tmp; | |
| } | |
| - | |
| while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) { | |
| switch (opt) { | |
| - | |
| /* One and only one of these is required */ | |
| + | #ifdef CONFIG_FEATURE_TAR_CREATE |
| case 'c': | |
| - | untar_funct_required |= untar_create; |
| + | tar_create = TRUE; |
| break; | |
| + | #endif |
| case 't': | |
| - | untar_funct_required |= untar_list; |
| - | extract_function |= extract_list | extract_unconditional; |
| + | if ((tar_handle->action_header == header_list) || |
| + | (tar_handle->action_header == header_verbose_list)) { |
| + | tar_handle->action_header = header_verbose_list; |
| + | } else { |
| + | tar_handle->action_header = header_list; |
| + | } |
| break; | |
| case 'x': | |
| - | untar_funct_required |= untar_extract; |
| - | extract_function |= |
| - | (extract_all_to_fs | extract_unconditional | |
| - | extract_create_leading_dirs); |
| + | tar_handle->action_data = data_extract_all; |
| break; | |
| /* These are optional */ | |
| /* Exclude or Include files listed in <filename> */ | |
| #ifdef CONFIG_FEATURE_TAR_EXCLUDE | |
| case 'X': | |
| - | append_file_list_to_list(optarg, &exclude_list, |
| - | &exclude_list_count); |
| + | tar_handle->reject = |
| + | append_file_list_to_list(optarg, tar_handle->reject); |
| break; | |
| #endif | |
| case 'T': | |
| /* by default a list is an include list */ | |
| - | append_file_list_to_list(optarg, &include_list, |
| - | &include_list_count); |
| break; | |
| - | |
| case 'C': /* Change to dir <optarg> */ | |
| - | /* Make sure dst_prefix ends in a '/' */ |
| - | dst_prefix = concat_path_file(optarg, "/"); |
| + | base_dir = optarg; |
| break; | |
| case 'f': /* archive filename */ | |
| - | if (strcmp(optarg, "-") == 0) { |
| - | src_filename = NULL; |
| - | } else { |
| - | src_filename = xstrdup(optarg); |
| - | } |
| + | #ifdef CONFIG_FEATURE_TAR_CREATE |
| + | src_filename = optarg; |
| + | #endif |
| + | tar_handle->src_fd = xopen(optarg, O_RDONLY); |
| break; | |
| - | case 'O': |
| - | extract_function |= extract_to_stdout; |
| + | case 'O': /* To stdout */ |
| + | tar_handle->action_data = data_extract_to_stdout; |
| break; | |
| case 'p': | |
| + | tar_handle->flags |= ARCHIVE_PRESERVE_DATE; |
| break; | |
| case 'v': | |
| - | extract_function |= extract_verbose_list; |
| + | if ((tar_handle->action_header == header_list) || |
| + | (tar_handle->action_header == header_verbose_list)) { |
| + | tar_handle->action_header = header_verbose_list; |
| + | } else { |
| + | tar_handle->action_header = header_list; |
| + | } |
| break; | |
| #ifdef CONFIG_FEATURE_TAR_GZIP | |
| case 'z': | |
| - | untar_funct |= untar_unzip; |
| + | get_header_ptr = get_header_tar_gz; |
| + | break; |
| + | #endif |
| + | #ifdef CONFIG_FEATURE_TAR_BZIP2 |
| + | /* Not enabled yet */ |
| + | case 'j': |
| + | archive_handle->archive_action = bunzip2; |
| break; | |
| #endif | |
| default: | |
| @@ -710,77 +704,54 @@ int tar_main(int argc, char **argv) | |
| } | |
| } | |
| - | /* Make sure the valid arguments were passed */ |
| - | if (untar_funct_required == 0) { |
| - | error_msg_and_die("You must specify one of the `-ctx' options"); |
| - | } |
| - | if ((untar_funct_required != untar_create) && |
| - | (untar_funct_required != untar_extract) && |
| - | (untar_funct_required != untar_list)) { |
| - | error_msg_and_die("You may not specify more than one `ctx' option."); |
| - | } |
| - | untar_funct |= untar_funct_required; |
| - | |
| /* Setup an array of filenames to work with */ | |
| + | /* TODO: This is the same as in ar, seperate function ? */ |
| while (optind < argc) { | |
| - | append_file_to_list(argv[optind], &include_list, &include_list_count); |
| + | char absolute_path[PATH_MAX]; |
| + | |
| + | realpath(argv[optind], absolute_path); |
| + | tar_handle->accept = add_to_list(tar_handle->accept, absolute_path); |
| optind++; | |
| - | } |
| - | if (extract_function & (extract_list | extract_all_to_fs)) { |
| - | if (dst_prefix == NULL) { |
| - | dst_prefix = xstrdup("./"); |
| + | #ifdef CONFIG_FEATURE_TAR_EXCLUDE |
| + | if (tar_handle->reject) { |
| + | tar_handle->filter = filter_accept_reject_list; |
| + | } else |
| + | #endif |
| + | tar_handle->filter = filter_accept_list; |
| } | |
| - | /* Setup the source of the tar data */ |
| - | if (src_filename != NULL) { |
| - | src_stream = xfopen(src_filename, "r"); |
| - | } else { |
| - | src_stream = stdin; |
| + | if ((base_dir) && (chdir(base_dir))) { |
| + | perror_msg_and_die("Couldnt chdir"); |
| } | |
| - | #ifdef CONFIG_FEATURE_TAR_GZIP |
| - | /* Get a binary tree of all the tar file headers */ |
| - | if (untar_funct & untar_unzip) { |
| - | uncompressed_stream = gz_open(src_stream, &gunzip_pid); |
| - | } else |
| - | #endif /* CONFIG_FEATURE_TAR_GZIP */ |
| - | uncompressed_stream = src_stream; |
| - | /* extract or list archive */ |
| - | unarchive(uncompressed_stream, stdout, &get_header_tar, |
| - | extract_function, dst_prefix, include_list, exclude_list); |
| - | fclose(uncompressed_stream); |
| - | } |
| #ifdef CONFIG_FEATURE_TAR_CREATE | |
| /* create an archive */ | |
| - | else if (untar_funct & untar_create) { |
| + | if (tar_create == TRUE) { |
| int verboseFlag = FALSE; | |
| int gzipFlag = FALSE; | |
| - | #ifdef CONFIG_FEATURE_TAR_GZIP |
| - | if (untar_funct & untar_unzip) |
| + | # ifdef CONFIG_FEATURE_TAR_GZIP |
| + | if (get_header_ptr == get_header_tar_gz) { |
| gzipFlag = TRUE; | |
| - | |
| - | #endif /* CONFIG_FEATURE_TAR_GZIP */ |
| - | if (extract_function & extract_verbose_list) |
| + | } |
| + | # endif |
| + | if (tar_handle->action_header == header_verbose_list) { |
| verboseFlag = TRUE; | |
| - | |
| - | writeTarFile(src_filename, verboseFlag, include_list, exclude_list, |
| - | gzipFlag); |
| } | |
| - | #endif /* CONFIG_FEATURE_TAR_CREATE */ |
| - | |
| - | /* Cleanups */ |
| + | writeTarFile(src_filename, verboseFlag, tar_handle->accept, |
| + | tar_handle->reject, gzipFlag); |
| + | } else |
| + | #endif |
| #ifdef CONFIG_FEATURE_TAR_GZIP | |
| - | if (!(untar_funct & untar_create) && (untar_funct & untar_unzip)) { |
| - | fclose(src_stream); |
| - | close(gz_fd); |
| - | gz_close(gunzip_pid); |
| - | } |
| - | #endif /* CONFIG_FEATURE_TAR_GZIP */ |
| + | if (get_header_ptr == get_header_tar_gz) { |
| + | get_header_tar_gz(tar_handle); |
| + | } else |
| + | #endif |
| + | while (get_header_tar(tar_handle) == EXIT_SUCCESS); |
| + | |
| #ifdef CONFIG_FEATURE_CLEAN_UP | |
| - | if (src_filename) { |
| - | free(src_filename); |
| - | } |
| + | close(tar_handle->src_fd); |
| #endif | |
| - | return (EXIT_SUCCESS); |
| + | |
| + | return(EXIT_SUCCESS); |
| } | |
| @@ -20,6 +20,10 @@ | |
| * | |
| */ | |
| + | /* For reference to format see http://www.pkware.com/support/appnote.html */ |
| + | |
| + | /* TODO Endian issues, exclude, should we accept input from stdin ? */ |
| + | |
| #include <fcntl.h> | |
| #include <getopt.h> | |
| #include <stdlib.h> | |
| @@ -28,67 +32,213 @@ | |
| #include "unarchive.h" | |
| #include "busybox.h" | |
| + | #define ZIP_FILEHEADER_MAGIC 0x04034b50 |
| + | #define ZIP_CDS_MAGIC 0x02014b50 |
| + | #define ZIP_CDS_END_MAGIC 0x06054b50 |
| + | #define ZIP_DD_MAGIC 0x08074b50 |
| + | |
| + | extern unsigned int gunzip_crc; |
| + | extern unsigned int gunzip_bytes_out; |
| + | |
| + | static void header_list_unzip(const file_header_t *file_header) |
| + | { |
| + | printf(" inflating: %s\n", file_header->name); |
| + | } |
| + | |
| + | static void header_verbose_list_unzip(const file_header_t *file_header) |
| + | { |
| + | unsigned int dostime = (unsigned int) file_header->mtime; |
| + | |
| + | /* can printf arguments cut of the decade component ? */ |
| + | unsigned short year = 1980 + ((dostime & 0xfe000000) >> 25); |
| + | while (year >= 100) { |
| + | year -= 100; |
| + | } |
| + | |
| + | printf("%9u %02u-%02u-%02u %02u:%02u %s\n", |
| + | (unsigned int) file_header->size, |
| + | (dostime & 0x01e00000) >> 21, |
| + | (dostime & 0x001f0000) >> 16, |
| + | year, |
| + | (dostime & 0x0000f800) >> 11, |
| + | (dostime & 0x000007e0) >> 5, |
| + | file_header->name); |
| + | } |
| + | |
| extern int unzip_main(int argc, char **argv) | |
| { | |
| - | FILE *src_stream; |
| - | int extract_function = extract_all_to_fs | extract_create_leading_dirs; |
| - | char **extract_names = NULL; |
| - | char **exclude_names = NULL; |
| + | union { |
| + | unsigned char raw[26]; |
| + | struct { |
| + | unsigned short version; /* 0-1 */ |
| + | unsigned short flags; /* 2-3 */ |
| + | unsigned short method; /* 4-5 */ |
| + | unsigned short modtime; /* 6-7 */ |
| + | unsigned short moddate; /* 8-9 */ |
| + | unsigned int crc32 __attribute__ ((packed)); /* 10-13 */ |
| + | unsigned int cmpsize __attribute__ ((packed));; /* 14-17 */ |
| + | unsigned int ucmpsize __attribute__ ((packed));; /* 18-21 */ |
| + | unsigned short filename_len; /* 22-23 */ |
| + | unsigned short extra_len; /* 24-25 */ |
| + | } formated __attribute__ ((packed)); |
| + | } zip_header; |
| + | |
| + | archive_handle_t *archive_handle; |
| + | unsigned int total_size = 0; |
| + | unsigned int total_entries = 0; |
| + | char *base_dir = NULL; |
| int opt = 0; | |
| - | int num_of_entries = 0; |
| - | int exclude = 0; |
| - | char *outdir = "./"; |
| - | FILE *msgout = stdout; |
| - | while ((opt = getopt(argc, argv, "lnopqxd:")) != -1) { |
| + | /* Initialise */ |
| + | archive_handle = init_handle(); |
| + | archive_handle->action_data = NULL; |
| + | archive_handle->action_header = header_list_unzip; |
| + | |
| + | while ((opt = getopt(argc, argv, "lnopqd:")) != -1) { |
| switch (opt) { | |
| - | case 'l': |
| - | extract_function |= extract_verbose_list; |
| - | extract_function ^= extract_all_to_fs; |
| + | case 'l': /* list */ |
| + | archive_handle->action_header = header_verbose_list_unzip; |
| + | archive_handle->action_data = data_skip; |
| break; | |
| - | case 'n': |
| + | case 'n': /* never overwright existing files */ |
| break; | |
| case 'o': | |
| - | extract_function |= extract_unconditional; |
| + | archive_handle->flags = ARCHIVE_EXTRACT_UNCONDITIONAL; |
| break; | |
| - | case 'p': |
| - | extract_function |= extract_to_stdout; |
| - | extract_function ^= extract_all_to_fs; |
| - | /* FALLTHROUGH */ |
| - | case 'q': |
| - | msgout = xfopen("/dev/null", "w"); |
| + | case 'p': /* extract files to stdout */ |
| + | archive_handle->action_data = data_extract_to_stdout; |
| break; | |
| - | case 'd': |
| - | outdir = xstrdup(optarg); |
| - | strcat(outdir, "/"); |
| + | case 'q': /* Extract files quietly */ |
| + | archive_handle->action_header = header_skip; |
| break; | |
| - | case 'x': |
| - | exclude = 1; |
| + | case 'd': /* Extract files to specified base directory*/ |
| + | base_dir = optarg; |
| break; | |
| + | #if 0 |
| + | case 'x': /* Exclude the specified files */ |
| + | archive_handle->filter = filter_accept_reject_list; |
| + | break; |
| + | #endif |
| + | default: |
| + | show_usage(); |
| } | |
| } | |
| - | if (optind == argc) { |
| + | if (argc == optind) { |
| show_usage(); | |
| } | |
| - | if (*argv[optind] == '-') src_stream = stdin; |
| - | else src_stream = xfopen(argv[optind++], "r"); |
| + | printf("Archive: %s\n", argv[optind]); |
| + | if (archive_handle->action_header == header_verbose_list_unzip) { |
| + | printf(" Length Date Time Name\n"); |
| + | printf(" -------- ---- ---- ----\n"); |
| + | } |
| - | while (optind < argc) { |
| - | if (exclude) { |
| - | exclude_names = xrealloc(exclude_names, sizeof(char *) * (num_of_entries + 2)); |
| - | exclude_names[num_of_entries] = xstrdup(argv[optind]); |
| + | if (*argv[optind] == '-') { |
| + | archive_handle->src_fd = fileno(stdin); |
| } else { | |
| - | extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); |
| - | extract_names[num_of_entries] = xstrdup(argv[optind]); |
| + | archive_handle->src_fd = xopen(argv[optind++], O_RDONLY); |
| } | |
| - | num_of_entries++; |
| - | if (exclude) exclude_names[num_of_entries] = NULL; |
| - | else extract_names[num_of_entries] = NULL; |
| + | |
| + | if ((base_dir) && (chdir(base_dir))) { |
| + | perror_msg_and_die("Couldnt chdir"); |
| + | } |
| + | |
| + | while (optind < argc) { |
| + | archive_handle->filter = filter_accept_list; |
| + | archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]); |
| optind++; | |
| } | |
| - | unarchive(src_stream, msgout, &get_header_zip, extract_function, outdir, extract_names, exclude_names); |
| - | return EXIT_SUCCESS; |
| + | while (1) { |
| + | unsigned int magic; |
| + | int dst_fd; |
| + | |
| + | /* TODO Endian issues */ |
| + | xread_all(archive_handle->src_fd, &magic, 4); |
| + | archive_handle->offset += 4; |
| + | |
| + | if (magic == ZIP_CDS_MAGIC) { |
| + | break; |
| + | } |
| + | else if (magic != ZIP_FILEHEADER_MAGIC) { |
| + | error_msg_and_die("Invlaide zip magic"); |
| + | } |
| + | |
| + | /* Read the file header */ |
| + | xread_all(archive_handle->src_fd, zip_header.raw, 26); |
| + | archive_handle->offset += 26; |
| + | archive_handle->file_header->mode = S_IFREG | 0777; |
| + | |
| + | if (zip_header.formated.method != 8) { |
| + | error_msg_and_die("Unsupported compression method %d\n", zip_header.formated.method); |
| + | } |
| + | |
| + | /* Read filename */ |
| + | archive_handle->file_header->name = xmalloc(zip_header.formated.filename_len + 1); |
| + | xread_all(archive_handle->src_fd, archive_handle->file_header->name, zip_header.formated.filename_len); |
| + | archive_handle->offset += zip_header.formated.filename_len; |
| + | archive_handle->file_header->name[zip_header.formated.filename_len] = '\0'; |
| + | |
| + | /* Skip extra header bits */ |
| + | archive_handle->file_header->size = zip_header.formated.extra_len; |
| + | data_skip(archive_handle); |
| + | archive_handle->offset += zip_header.formated.extra_len; |
| + | |
| + | /* Handle directories */ |
| + | archive_handle->file_header->mode = S_IFREG | 0777; |
| + | if (last_char_is(archive_handle->file_header->name, '/')) { |
| + | archive_handle->file_header->mode ^= S_IFREG; |
| + | archive_handle->file_header->mode |= S_IFDIR; |
| + | } |
| + | |
| + | /* Data section */ |
| + | archive_handle->file_header->size = zip_header.formated.cmpsize; |
| + | if (archive_handle->action_data) { |
| + | archive_handle->action_data(archive_handle); |
| + | } else { |
| + | dst_fd = xopen(archive_handle->file_header->name, O_WRONLY | O_CREAT); |
| + | inflate(archive_handle->src_fd, dst_fd); |
| + | close(dst_fd); |
| + | chmod(archive_handle->file_header->name, archive_handle->file_header->mode); |
| + | |
| + | /* Validate decompression - crc */ |
| + | if (zip_header.formated.crc32 != (gunzip_crc ^ 0xffffffffL)) { |
| + | error_msg("Invalid compressed data--crc error"); |
| + | } |
| + | |
| + | /* Validate decompression - size */ |
| + | if (gunzip_bytes_out != zip_header.formated.ucmpsize) { |
| + | error_msg("Invalid compressed data--length error"); |
| + | } |
| + | } |
| + | |
| + | /* local file descriptor section */ |
| + | archive_handle->offset += zip_header.formated.cmpsize; |
| + | /* This ISNT unix time */ |
| + | archive_handle->file_header->mtime = zip_header.formated.modtime | (zip_header.formated.moddate << 16); |
| + | archive_handle->file_header->size = zip_header.formated.ucmpsize; |
| + | total_size += archive_handle->file_header->size; |
| + | total_entries++; |
| + | |
| + | archive_handle->action_header(archive_handle->file_header); |
| + | |
| + | /* Data descriptor section */ |
| + | if (zip_header.formated.flags & 4) { |
| + | /* skip over duplicate crc, compressed size and uncompressed size */ |
| + | unsigned short i; |
| + | for (i = 0; i != 12; i++) { |
| + | xread_char(archive_handle->src_fd); |
| + | } |
| + | archive_handle->offset += 12; |
| + | } |
| + | } |
| + | /* Central directory section */ |
| + | |
| + | if (archive_handle->action_header == header_verbose_list_unzip) { |
| + | printf(" -------- -------\n"); |
| + | printf("%9d %d files\n", total_size, total_entries); |
| + | } |
| + | |
| + | return(EXIT_SUCCESS); |
| } | |
| @@ -48,10 +48,6 @@ | |
| # include "sha1.h" | |
| #endif | |
| - | /* Compatability with ANSI C */ |
| - | #ifndef inline |
| - | # define inline |
| - | #endif |
| #if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) | |
| /* libc5 doesn't define socklen_t */ | |
| @@ -74,6 +70,9 @@ char *strtok_r(char *s, const char *delim, char **ptrptr); | |
| #define BUF_SIZE 8192 | |
| #define EXPAND_ALLOC 1024 | |
| + | static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); } |
| + | static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); } |
| + | |
| /* Macros for min/max. */ | |
| #ifndef MIN | |
| #define MIN(a,b) (((a)<(b))?(a):(b)) | |
| @@ -83,8 +82,6 @@ char *strtok_r(char *s, const char *delim, char **ptrptr); | |
| #define MAX(a,b) (((a)>(b))?(a):(b)) | |
| #endif | |
| - | |
| - | |
| extern void show_usage(void) __attribute__ ((noreturn)); | |
| extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); | |
| extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); | |
| @@ -228,10 +225,7 @@ extern long arith (const char *startbuf, int *errcode); | |
| int read_package_field(const char *package_buffer, char **field_name, char **field_value); | |
| char *fgets_str(FILE *file, const char *terminating_string); | |
| - | extern int inflate(FILE *in, FILE *out); |
| - | extern int unzip(FILE *l_in_file, FILE *l_out_file); |
| - | extern void gz_close(int gunzip_pid); |
| - | extern FILE *gz_open(FILE *compressed_file, int *pid); |
| + | extern int inflate(int in, int out); |
| extern struct hostent *xgethostbyname(const char *name); | |
| extern struct hostent *xgethostbyname2(const char *name, int af); | |
| @@ -335,4 +329,11 @@ extern char *pw_encrypt(const char *clear, const char *salt); | |
| extern struct spwd *pwd_to_spwd(const struct passwd *pw); | |
| extern int obscure(const char *old, const char *newval, const struct passwd *pwdp); | |
| + | //extern int xopen(const char *pathname, int flags, mode_t mode); |
| + | extern int xopen(const char *pathname, int flags); |
| + | extern ssize_t xread(int fd, void *buf, size_t count); |
| + | extern ssize_t xread_all_eof(int fd, void *buf, size_t count); |
| + | extern void xread_all(int fd, void *buf, size_t count); |
| + | extern unsigned char xread_char(int fd); |
| + | |
| #endif /* __LIBCONFIG_H__ */ | |
| @@ -1,21 +1,19 @@ | |
| - | #include <stdio.h> /* for FILE */ |
| - | #include <unistd.h> /* for off_t */ |
| - | |
| - | enum extract_functions_e { |
| - | extract_verbose_list = 1, |
| - | extract_list = 2, |
| - | extract_one_to_buffer = 4, |
| - | extract_to_stdout = 8, |
| - | extract_all_to_fs = 16, |
| - | extract_preserve_date = 32, |
| - | extract_data_tar_gz = 64, |
| - | extract_control_tar_gz = 128, |
| - | extract_unzip_only = 256, |
| - | extract_unconditional = 512, |
| - | extract_create_leading_dirs = 1024, |
| - | extract_quiet = 2048, |
| - | extract_exclude_list = 4096 |
| - | }; |
| + | #ifndef __UNARCHIVE_H__ |
| + | #define __UNARCHIVE_H__ |
| + | |
| + | #define ARCHIVE_PRESERVE_DATE 1 |
| + | #define ARCHIVE_CREATE_LEADING_DIRS 2 |
| + | #define ARCHIVE_EXTRACT_UNCONDITIONAL 4 |
| + | #define ARCHIVE_EXTRACT_QUIET 8 |
| + | |
| + | #include <sys/types.h> |
| + | |
| + | typedef struct gunzip_s { |
| + | unsigned short buffer_count; |
| + | unsigned char *buffer; |
| + | unsigned int crc; |
| + | unsigned int count; |
| + | } gunzip_t; |
| typedef struct file_headers_s { | |
| char *name; | |
| @@ -26,23 +24,70 @@ typedef struct file_headers_s { | |
| mode_t mode; | |
| time_t mtime; | |
| dev_t device; | |
| - | int (*extract_func) (FILE *, FILE *); |
| } file_header_t; | |
| - | file_header_t *get_header_ar(FILE * in_file); |
| - | file_header_t *get_header_cpio(FILE * src_stream); |
| - | file_header_t *get_header_tar(FILE * tar_stream); |
| - | file_header_t *get_header_zip(FILE * zip_stream); |
| + | typedef struct llist_s { |
| + | const char *data; |
| + | const struct llist_s *link; |
| + | } llist_t; |
| + | |
| + | typedef struct archive_handle_s { |
| + | /* define if the header and data compenent should processed */ |
| + | char (*filter)(const llist_t *, const llist_t *, const char *); |
| + | const llist_t *accept; |
| + | const llist_t *reject; |
| + | |
| + | /* Contains the processed header entry */ |
| + | file_header_t *file_header; |
| + | |
| + | /* process the header component, e.g. tar -t */ |
| + | void (*action_header)(const file_header_t *); |
| + | |
| + | /* process the data componenet, e.g. extract to filesystem */ |
| + | void (*action_data)(struct archive_handle_s *); |
| + | char (*action_data_subarchive)(struct archive_handle_s *); |
| + | |
| + | /* Contains the handle to a sub archive */ |
| + | struct archive_handle_s *sub_archive; |
| + | |
| + | /* The raw stream as read from disk or stdin */ |
| + | int src_fd; |
| + | |
| + | /* Count the number of bytes processed */ |
| + | off_t offset; |
| + | |
| + | /* Misc. stuff */ |
| + | unsigned char flags; |
| + | |
| + | } archive_handle_t; |
| + | |
| + | extern archive_handle_t *init_handle(void); |
| + | |
| + | extern char filter_accept_all(const llist_t *accept_list, const llist_t *reject_list, const char *key); |
| + | extern char filter_accept_list(const llist_t *accept_list, const llist_t *reject_list, const char *key); |
| + | extern char filter_accept_reject_list(const llist_t *accept_list, const llist_t *reject_list, const char *key); |
| + | |
| + | 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_to_stdout(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); |
| + | extern void header_verbose_list(const file_header_t *file_header); |
| - | void seek_sub_file(FILE * src_stream, const int count); |
| + | extern void check_header_gzip(int src_fd); |
| + | extern void check_trailer_gzip(int src_fd); |
| - | extern off_t archive_offset; |
| + | extern char get_header_ar(archive_handle_t *archive_handle); |
| + | extern char get_header_tar(archive_handle_t *archive_handle); |
| + | extern char get_header_tar_gz(archive_handle_t *archive_handle); |
| - | char *unarchive(FILE * src_stream, FILE * out_stream, |
| - | file_header_t * (*get_headers) (FILE *), |
| - | const int extract_function, const char *prefix, |
| - | char **include_name, char **exclude_name); |
| + | //extern void seek_sub_file(int src_fd, unsigned int amount); |
| + | extern const unsigned short data_align(const int src_fd, const unsigned int offset, const unsigned short align_to); |
| + | extern const llist_t *add_to_list(const llist_t *old_head, const char *new_item); |
| + | extern int copy_file_chunk_fd(int src_fd, int dst_fd, unsigned long long chunksize); |
| - | char *deb_extract(const char *package_filename, FILE * out_stream, |
| - | const int extract_function, const char *prefix, |
| - | const char *filename); |
| + | #endif |
| @@ -28,20 +28,22 @@ LIBBB_SRC:= \ | |
| copy_file_chunk.c dump.c libc5.c device_open.c error_msg.c \ | |
| error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \ | |
| find_root_device.c full_read.c full_write.c get_console.c \ | |
| - | get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \ |
| - | isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \ |
| - | mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \ |
| - | my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \ |
| - | print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \ |
| - | safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \ |
| - | trim.c unzip.c uncompress.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c \ |
| - | xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ |
| - | copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ |
| - | dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ |
| - | simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \ |
| - | correct_password.c change_identity.c setup_environment.c run_shell.c \ |
| - | pw_encrypt.c restricted_shell.c xgethostbyname2.c create_icmp6_socket.c \ |
| - | xconnect.c bb_asprintf.c |
| + | get_last_path_component.c get_line_from_file.c \ |
| + | human_readable.c isdirectory.c kernel_version.c loop.c \ |
| + | mode_string.c module_syscalls.c mtab.c mtab_file.c my_getgrnam.c \ |
| + | my_getgrgid.c my_getpwnam.c my_getpwnamegid.c my_getpwuid.c \ |
| + | parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \ |
| + | print_file.c process_escape_sequence.c read_package_field.c \ |
| + | recursive_action.c safe_read.c safe_strncpy.c syscalls.c \ |
| + | syslog_msg_with_name.c time_string.c trim.c unzip.c uncompress.c \ |
| + | vdprintf.c verror_msg.c vperror_msg.c wfopen.c xgetcwd.c xreadlink.c \ |
| + | xregcomp.c interface.c remove_file.c last_char_is.c copyfd.c \ |
| + | vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ |
| + | dirname.c make_directory.c create_icmp_socket.c u_signal_names.c \ |
| + | arith.c simplify_path.c inet_common.c inode_hash.c obscure.c \ |
| + | pwd2spwd.c xfuncs.c correct_password.c change_identity.c \ |
| + | setup_environment.c run_shell.c pw_encrypt.c restricted_shell.c \ |
| + | xgethostbyname2.c create_icmp6_socket.c xconnect.c bb_asprintf.c |
| LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC)) | |
| @@ -65,114 +65,126 @@ static char *license_msg[] = { | |
| #include <signal.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| #include "config.h" | |
| - | #include "libbb.h" |
| + | #include "busybox.h" |
| + | #include "unarchive.h" |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | int uncompress(FILE * in, FILE * out); |
| - | #endif |
| - | |
| - | static FILE *in_file, *out_file; |
| + | typedef struct huft_s { |
| + | unsigned char e; /* number of extra bits or operation */ |
| + | unsigned char b; /* number of bits in this code or subcode */ |
| + | union { |
| + | unsigned short n; /* literal, length base, or distance base */ |
| + | struct huft_s *t; /* pointer to next level of table */ |
| + | } v; |
| + | } huft_t; |
| - | /* these are freed by gz_close */ |
| - | static unsigned char *window; |
| - | static unsigned long *crc_table; |
| + | static int gunzip_src_fd; |
| + | static int gunzip_dst_fd; |
| + | unsigned int gunzip_bytes_out; /* number of output bytes */ |
| + | static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ |
| - | static unsigned long crc; /* shift register contents */ |
| + | /* This is used to sanify any unused bits from the bitbuffer |
| + | * so they arent skipped when reading trailers (trailing headers) */ |
| + | unsigned char gunzip_in_buffer_count; |
| + | unsigned char *gunzip_in_buffer; |
| - | /* Return codes from gzip */ |
| - | #define ERROR 1 |
| + | /* gunzip_window size--must be a power of two, and |
| + | * at least 32K for zip's deflate method */ |
| + | static const int gunzip_wsize = 0x8000; |
| - | /* |
| - | * window size--must be a power of two, and |
| - | * at least 32K for zip's deflate method |
| - | */ |
| - | #define WSIZE 0x8000 |
| + | static unsigned char *gunzip_window; |
| + | static unsigned int *gunzip_crc_table; |
| + | unsigned int gunzip_crc; |
| /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ | |
| #define BMAX 16 /* maximum bit length of any code (16 for explode) */ | |
| #define N_MAX 288 /* maximum number of codes in any set */ | |
| - | static long bytes_out; /* number of output bytes */ |
| - | static unsigned long outcnt; /* bytes in output buffer */ |
| - | |
| - | static unsigned hufts; /* track memory usage */ |
| - | static unsigned long bb; /* bit buffer */ |
| - | static unsigned bk; /* bits in bit buffer */ |
| - | |
| - | typedef struct huft_s { |
| - | unsigned char e; /* number of extra bits or operation */ |
| - | unsigned char b; /* number of bits in this code or subcode */ |
| - | union { |
| - | unsigned short n; /* literal, length base, or distance base */ |
| - | struct huft_s *t; /* pointer to next level of table */ |
| - | } v; |
| - | } huft_t; |
| + | static unsigned int gunzip_hufts; /* track memory usage */ |
| + | static unsigned int gunzip_bb; /* bit buffer */ |
| + | static unsigned char gunzip_bk; /* bits in bit buffer */ |
| static const unsigned short mask_bits[] = { | |
| - | 0x0000, |
| - | 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| + | 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, |
| 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | |
| }; | |
| - | /* static int error_number = 0; */ |
| - | /* ======================================================================== |
| - | * Signal and error handler. |
| - | */ |
| + | /* Copy lengths for literal codes 257..285 */ |
| + | static const unsigned short cplens[] = { |
| + | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, |
| + | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| + | }; |
| + | |
| + | /* note: see note #13 above about the 258 in this list. */ |
| + | /* Extra bits for literal codes 257..285 */ |
| + | static const unsigned char cplext[] = { |
| + | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, |
| + | 5, 5, 5, 0, 99, 99 |
| + | }; /* 99==invalid */ |
| + | |
| + | /* Copy offsets for distance codes 0..29 */ |
| + | static const unsigned short cpdist[] = { |
| + | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, |
| + | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 |
| + | }; |
| + | |
| + | /* Extra bits for distance codes */ |
| + | static const unsigned char cpdext[] = { |
| + | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, |
| + | 11, 11, 12, 12, 13, 13 |
| + | }; |
| + | |
| + | /* Tables for deflate from PKZIP's appnote.txt. */ |
| + | /* Order of the bit length code lengths */ |
| + | static const unsigned char border[] = { |
| + | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| + | }; |
| + | |
| + | static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) |
| + | { |
| + | while (*current < required) { |
| + | bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; |
| + | *current += 8; |
| + | } |
| + | |
| + | return(bitbuffer); |
| + | } |
| static void abort_gzip(void) | |
| { | |
| error_msg("gzip aborted\n"); | |
| - | exit(ERROR); |
| + | exit(-1); |
| } | |
| - | static void make_crc_table(void) |
| + | static void make_gunzip_crc_table(void) |
| { | |
| - | const unsigned long poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| + | const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ |
| unsigned short i; /* counter for all possible eight bit values */ | |
| /* initial shift register value */ | |
| - | crc = 0xffffffffL; |
| - | crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); |
| + | gunzip_crc = 0xffffffffL; |
| + | gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); |
| /* Compute and print table of CRC's, five per line */ | |
| for (i = 0; i < 256; i++) { | |
| - | unsigned long table_entry; /* crc shift register */ |
| - | char k; /* byte being shifted into crc apparatus */ |
| + | unsigned int table_entry; /* crc shift register */ |
| + | unsigned char k; /* byte being shifted into crc apparatus */ |
| table_entry = i; | |
| /* The idea to initialize the register with the byte instead of | |
| * zero was stolen from Haruhiko Okumura's ar002 | |
| */ | |
| for (k = 8; k; k--) { | |
| - | table_entry = |
| - | table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> |
| - | 1; |
| - | } |
| - | crc_table[i] = table_entry; |
| + | if (table_entry & 1) { |
| + | table_entry = (table_entry >> 1) ^ poly; |
| + | } else { |
| + | table_entry >>= 1; |
| } | |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
| - | * (Used for the decompressed data only.) |
| - | */ |
| - | static void flush_window(void) |
| - | { |
| - | int n; |
| - | |
| - | if (outcnt == 0) |
| - | return; |
| - | |
| - | for (n = 0; n < outcnt; n++) { |
| - | crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); |
| } | |
| - | |
| - | if (fwrite(window, 1, outcnt, out_file) != outcnt) { |
| - | error_msg_and_die("Couldnt write"); |
| + | gunzip_crc_table[i] = table_entry; |
| } | |
| - | bytes_out += (unsigned long) outcnt; |
| - | outcnt = 0; |
| } | |
| /* | |
| @@ -183,7 +195,8 @@ static void flush_window(void) | |
| */ | |
| static int huft_free(huft_t * t) | |
| { | |
| - | huft_t *p, *q; |
| + | huft_t *p; |
| + | huft_t *q; |
| /* Go through linked list, freeing from the malloced (t[-1]) address. */ | |
| p = t; | |
| @@ -195,8 +208,6 @@ static int huft_free(huft_t * t) | |
| return 0; | |
| } | |
| - | typedef unsigned char extra_bits_t; |
| - | |
| /* Given a list of code lengths and a maximum table size, make a set of | |
| * tables to decode that set of codes. Return zero on success, one if | |
| * the given code set is incomplete (the tables are still built in this | |
| @@ -213,7 +224,7 @@ typedef unsigned char extra_bits_t; | |
| */ | |
| static int huft_build(unsigned int *b, const unsigned int n, | |
| const unsigned int s, const unsigned short *d, | |
| - | const extra_bits_t * e, huft_t ** t, int *m) |
| + | const unsigned char *e, huft_t ** t, int *m) |
| { | |
| unsigned a; /* counter for codes of length k */ | |
| unsigned c[BMAX + 1]; /* bit length count table */ | |
| @@ -251,26 +262,35 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* Find minimum and maximum length, bound *m by those */ | |
| l = *m; | |
| - | for (j = 1; j <= BMAX; j++) |
| - | if (c[j]) |
| + | for (j = 1; j <= BMAX; j++) { |
| + | if (c[j]) { |
| break; | |
| + | } |
| + | } |
| k = j; /* minimum code length */ | |
| - | if ((unsigned) l < j) |
| + | if ((unsigned) l < j) { |
| l = j; | |
| - | for (i = BMAX; i; i--) |
| - | if (c[i]) |
| + | } |
| + | for (i = BMAX; i; i--) { |
| + | if (c[i]) { |
| break; | |
| + | } |
| + | } |
| g = i; /* maximum code length */ | |
| - | if ((unsigned) l > i) |
| + | if ((unsigned) l > i) { |
| l = i; | |
| + | } |
| *m = l; | |
| /* Adjust last length count to fill out codes, if needed */ | |
| - | for (y = 1 << j; j < i; j++, y <<= 1) |
| - | if ((y -= c[j]) < 0) |
| + | for (y = 1 << j; j < i; j++, y <<= 1) { |
| + | if ((y -= c[j]) < 0) { |
| return 2; /* bad input: more codes than bits */ | |
| - | if ((y -= c[i]) < 0) |
| + | } |
| + | } |
| + | if ((y -= c[i]) < 0) { |
| return 2; | |
| + | } |
| c[i] += y; | |
| /* Generate starting offsets into the value table for each length */ | |
| @@ -285,8 +305,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| p = b; | |
| i = 0; | |
| do { | |
| - | if ((j = *p++) != 0) |
| + | if ((j = *p++) != 0) { |
| v[x[j]++] = i; | |
| + | } |
| } while (++i < n); | |
| /* Generate the Huffman codes and for each, make the table entries */ | |
| @@ -314,8 +335,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| f -= a + 1; /* deduct codes from patterns left */ | |
| xp = c + k; | |
| while (++j < z) { /* try smaller tables up to z bits */ | |
| - | if ((f <<= 1) <= *++xp) |
| + | if ((f <<= 1) <= *++xp) { |
| break; /* enough codes to use up j bits */ | |
| + | } |
| f -= *xp; /* else deduct codes from patterns */ | |
| } | |
| } | |
| @@ -324,7 +346,7 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* allocate and link in new table */ | |
| q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); | |
| - | hufts += z + 1; /* track memory usage */ |
| + | gunzip_hufts += z + 1; /* track memory usage */ |
| *t = q + 1; /* link to list for huft_free() */ | |
| *(t = &(q->v.t)) = NULL; | |
| u[h] = ++q; /* table starts after link */ | |
| @@ -342,9 +364,9 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* set up table entry in r */ | |
| r.b = (unsigned char) (k - w); | |
| - | if (p >= v + n) |
| + | if (p >= v + n) { |
| r.e = 99; /* out of values--invalid code */ | |
| - | else if (*p < s) { |
| + | } else if (*p < s) { |
| r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ | |
| r.v.n = (unsigned short) (*p); /* simple code is just the value */ | |
| p++; /* one compiler does not like *p++ */ | |
| @@ -355,12 +377,14 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| /* fill code-like entries with r */ | |
| f = 1 << (k - w); | |
| - | for (j = i >> w; j < z; j += f) |
| + | for (j = i >> w; j < z; j += f) { |
| q[j] = r; | |
| + | } |
| /* backwards increment the k-bit code i */ | |
| - | for (j = 1 << (k - 1); i & j; j >>= 1) |
| + | for (j = 1 << (k - 1); i & j; j >>= 1) { |
| i ^= j; | |
| + | } |
| i ^= j; | |
| /* backup over finished tables */ | |
| @@ -374,6 +398,25 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| return y != 0 && g != 1; | |
| } | |
| + | /* =========================================================================== |
| + | * Write the output gunzip_window gunzip_window[0..gunzip_outbuf_count-1] and update crc and gunzip_bytes_out. |
| + | * (Used for the decompressed data only.) |
| + | */ |
| + | static void flush_gunzip_window(void) |
| + | { |
| + | int n; |
| + | |
| + | for (n = 0; n < gunzip_outbuf_count; n++) { |
| + | gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); |
| + | } |
| + | |
| + | if (write(gunzip_dst_fd, gunzip_window, gunzip_outbuf_count) != gunzip_outbuf_count) { |
| + | error_msg_and_die("Couldnt write"); |
| + | } |
| + | gunzip_bytes_out += gunzip_outbuf_count; |
| + | gunzip_outbuf_count = 0; |
| + | } |
| + | |
| /* | |
| * inflate (decompress) the codes in a deflated (compressed) block. | |
| * Return an error code or zero if it all goes ok. | |
| @@ -381,32 +424,26 @@ static int huft_build(unsigned int *b, const unsigned int n, | |
| * tl, td: literal/length and distance decoder tables | |
| * bl, bd: number of bits decoded by tl[] and td[] | |
| */ | |
| - | static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) |
| + | static int inflate_codes(huft_t * tl, huft_t * td, const unsigned int bl, const unsigned int bd) |
| { | |
| - | register unsigned long e; /* table entry flag/number of extra bits */ |
| - | unsigned long n, d; /* length and index for copy */ |
| - | unsigned long w; /* current window position */ |
| + | unsigned int e; /* table entry flag/number of extra bits */ |
| + | unsigned int n, d; /* length and index for copy */ |
| + | unsigned int w; /* current gunzip_window position */ |
| huft_t *t; /* pointer to table entry */ | |
| - | unsigned ml, md; /* masks for bl and bd bits */ |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | register int input_char; |
| + | unsigned int ml, md; /* masks for bl and bd bits */ |
| + | unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b = bb; /* initialize bit buffer */ |
| - | k = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b = gunzip_bb; /* initialize bit buffer */ |
| + | k = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* inflate the coded data */ | |
| ml = mask_bits[bl]; /* precompute masks for speed */ | |
| md = mask_bits[bd]; | |
| - | for (;;) { /* do until end of block */ |
| - | while (k < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | while (1) { /* do until end of block */ |
| + | b = fill_bitbuffer(b, &k, bl); |
| if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) | |
| do { | |
| if (e == 99) { | |
| @@ -415,20 +452,16 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| if (e == 16) { /* then it's a literal */ | |
| - | window[w++] = (unsigned char) t->v.n; |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | gunzip_window[w++] = (unsigned char) t->v.n; |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| } else { /* it's an EOB or a length */ | |
| @@ -439,24 +472,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| } | |
| /* get length of block to copy */ | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| n = t->v.n + ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| /* decode distance of block to copy */ | |
| - | while (k < (unsigned) bd) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| - | |
| + | b = fill_bitbuffer(b, &k, bd); |
| if ((e = (t = td + ((unsigned) b & md))->e) > 16) | |
| do { | |
| if (e == 99) | |
| @@ -464,23 +486,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| b >>= t->b; | |
| k -= t->b; | |
| e -= 16; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| } while ((e = | |
| (t = | |
| t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | |
| b >>= t->b; | |
| k -= t->b; | |
| - | while (k < e) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, e); |
| d = w - t->v.n - ((unsigned) b & mask_bits[e]); | |
| b >>= e; | |
| k -= e; | |
| @@ -489,60 +501,38 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) | |
| do { | |
| n -= (e = | |
| (e = | |
| - | WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); |
| - | #if !defined(NOMEMCPY) && !defined(DEBUG) |
| + | gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); |
| + | /* copy to new buffer to prevent possible overwrite */ |
| if (w - d >= e) { /* (this test assumes unsigned comparison) */ | |
| - | memcpy(window + w, window + d, e); |
| + | memcpy(gunzip_window + w, gunzip_window + d, e); |
| w += e; | |
| d += e; | |
| - | } else /* do it slow to avoid memcpy() overlap */ |
| - | #endif /* !NOMEMCPY */ |
| + | } else { |
| + | /* do it slow to avoid memcpy() overlap */ |
| + | /* !NOMEMCPY */ |
| do { | |
| - | window[w++] = window[d++]; |
| + | gunzip_window[w++] = gunzip_window[d++]; |
| } while (--e); | |
| - | if (w == WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | } |
| + | if (w == gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| + | |
| } while (n); | |
| } | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b; /* restore global bit buffer */ |
| - | bk = k; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b; /* restore global bit buffer */ |
| + | gunzip_bk = k; |
| /* done */ | |
| return 0; | |
| } | |
| - | static const unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ |
| - | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, |
| - | 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 |
| - | }; |
| - | |
| - | /* note: see note #13 above about the 258 in this list. */ |
| - | static const extra_bits_t cplext[] = { /* Extra bits for literal codes 257..285 */ |
| - | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, |
| - | 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 |
| - | }; /* 99==invalid */ |
| - | static const unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ |
| - | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, |
| - | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, |
| - | 8193, 12289, 16385, 24577 |
| - | }; |
| - | static const extra_bits_t cpdext[] = { /* Extra bits for distance codes */ |
| - | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, |
| - | 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, |
| - | 12, 12, 13, 13 |
| - | }; |
| - | |
| - | /* Tables for deflate from PKZIP's appnote.txt. */ |
| - | static const extra_bits_t border[] = { /* Order of the bit length code lengths */ |
| - | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| - | }; |
| - | |
| /* | |
| * decompress an inflated block | |
| * e: last block flag | |
| @@ -552,53 +542,43 @@ static const extra_bits_t border[] = { /* Order of the bit length code lengths * | |
| static int inflate_block(int *e) | |
| { | |
| unsigned t; /* block type */ | |
| - | register unsigned long b; /* bit buffer */ |
| - | register unsigned k; /* number of bits in bit buffer */ |
| - | int input_char; |
| + | register unsigned int b; /* bit buffer */ |
| + | unsigned int k; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b = bb; |
| - | k = bk; |
| + | |
| + | b = gunzip_bb; |
| + | k = gunzip_bk; |
| /* read in last block bit */ | |
| - | while (k < 1) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 1); |
| *e = (int) b & 1; | |
| b >>= 1; | |
| k -= 1; | |
| /* read in block type */ | |
| - | while (k < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b |= ((unsigned long)input_char) << k; |
| - | k += 8; |
| - | } |
| + | b = fill_bitbuffer(b, &k, 2); |
| t = (unsigned) b & 3; | |
| b >>= 2; | |
| k -= 2; | |
| /* restore the global bit buffer */ | |
| - | bb = b; |
| - | bk = k; |
| + | gunzip_bb = b; |
| + | gunzip_bk = k; |
| /* inflate that block type */ | |
| switch (t) { | |
| case 0: /* Inflate stored */ | |
| { | |
| - | unsigned long n; /* number of bytes in block */ |
| - | unsigned long w; /* current window position */ |
| - | register unsigned long b_stored; /* bit buffer */ |
| - | register unsigned long k_stored; /* number of bits in bit buffer */ |
| + | unsigned int n; /* number of bytes in block */ |
| + | unsigned int w; /* current gunzip_window position */ |
| + | unsigned int b_stored; /* bit buffer */ |
| + | unsigned int k_stored; /* number of bits in bit buffer */ |
| /* make local copies of globals */ | |
| - | b_stored = bb; /* initialize bit buffer */ |
| - | k_stored = bk; |
| - | w = outcnt; /* initialize window position */ |
| + | b_stored = gunzip_bb; /* initialize bit buffer */ |
| + | k_stored = gunzip_bk; |
| + | w = gunzip_outbuf_count; /* initialize gunzip_window position */ |
| /* go to byte boundary */ | |
| n = k_stored & 7; | |
| @@ -606,21 +586,12 @@ static int inflate_block(int *e) | |
| k_stored -= n; | |
| /* get the length and its complement */ | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| n = ((unsigned) b_stored & 0xffff); | |
| b_stored >>= 16; | |
| k_stored -= 16; | |
| - | while (k_stored < 16) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| + | |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); |
| if (n != (unsigned) ((~b_stored) & 0xffff)) { | |
| return 1; /* error in compressed data */ | |
| } | |
| @@ -629,15 +600,11 @@ static int inflate_block(int *e) | |
| /* read and output the compressed data */ | |
| while (n--) { | |
| - | while (k_stored < 8) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_stored |= ((unsigned long)input_char) << k_stored; |
| - | k_stored += 8; |
| - | } |
| - | window[w++] = (unsigned char) b_stored; |
| - | if (w == (unsigned long) WSIZE) { |
| - | outcnt = (w), flush_window(); |
| + | b_stored = fill_bitbuffer(b_stored, &k_stored, 8); |
| + | gunzip_window[w++] = (unsigned char) b_stored; |
| + | if (w == (unsigned int) gunzip_wsize) { |
| + | gunzip_outbuf_count = (w); |
| + | flush_gunzip_window(); |
| w = 0; | |
| } | |
| b_stored >>= 8; | |
| @@ -645,9 +612,9 @@ static int inflate_block(int *e) | |
| } | |
| /* restore the globals from the locals */ | |
| - | outcnt = w; /* restore global window pointer */ |
| - | bb = b_stored; /* restore global bit buffer */ |
| - | bk = k_stored; |
| + | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ |
| + | gunzip_bb = b_stored; /* restore global bit buffer */ |
| + | gunzip_bk = k_stored; |
| return 0; | |
| } | |
| case 1: /* Inflate fixed | |
| @@ -659,8 +626,8 @@ static int inflate_block(int *e) | |
| int i; /* temporary variable */ | |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| unsigned int l[288]; /* length list for huft_build */ | |
| /* set up literal table */ | |
| @@ -692,8 +659,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -705,53 +673,41 @@ static int inflate_block(int *e) | |
| const int dbits = 6; /* bits in base distance lookup table */ | |
| const int lbits = 9; /* bits in base literal/length lookup table */ | |
| - | int i; /* temporary variables */ |
| - | unsigned j; |
| - | unsigned l; /* last length */ |
| - | unsigned m; /* mask for bit lengths table */ |
| - | unsigned n; /* number of lengths to get */ |
| huft_t *tl; /* literal/length code table */ | |
| huft_t *td; /* distance code table */ | |
| - | int bl; /* lookup bits for tl */ |
| - | int bd; /* lookup bits for td */ |
| - | unsigned nb; /* number of bit length codes */ |
| - | unsigned nl; /* number of literal/length codes */ |
| - | unsigned nd; /* number of distance codes */ |
| - | |
| - | unsigned ll[286 + 30]; /* literal/length and distance code lengths */ |
| - | register unsigned long b_dynamic; /* bit buffer */ |
| - | register unsigned k_dynamic; /* number of bits in bit buffer */ |
| + | unsigned int i; /* temporary variables */ |
| + | unsigned int j; |
| + | unsigned int l; /* last length */ |
| + | unsigned int m; /* mask for bit lengths table */ |
| + | unsigned int n; /* number of lengths to get */ |
| + | unsigned int bl; /* lookup bits for tl */ |
| + | unsigned int bd; /* lookup bits for td */ |
| + | unsigned int nb; /* number of bit length codes */ |
| + | unsigned int nl; /* number of literal/length codes */ |
| + | unsigned int nd; /* number of distance codes */ |
| + | |
| + | unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ |
| + | unsigned int b_dynamic; /* bit buffer */ |
| + | unsigned int k_dynamic; /* number of bits in bit buffer */ |
| /* make local bit buffer */ | |
| - | b_dynamic = bb; |
| - | k_dynamic = bk; |
| + | b_dynamic = gunzip_bb; |
| + | k_dynamic = gunzip_bk; |
| /* read in table lengths */ | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 5) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); |
| + | nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ |
| + | |
| b_dynamic >>= 5; | |
| k_dynamic -= 5; | |
| - | while (k_dynamic < 4) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); |
| + | nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ |
| + | |
| b_dynamic >>= 4; | |
| k_dynamic -= 4; | |
| if (nl > 286 || nd > 30) { | |
| @@ -760,13 +716,8 @@ static int inflate_block(int *e) | |
| /* read in bit-length-code lengths */ | |
| for (j = 0; j < nb; j++) { | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | ll[border[j]] = (unsigned) b_dynamic & 7; |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | ll[border[j]] = (unsigned int) b_dynamic & 7; |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| } | |
| @@ -776,7 +727,8 @@ static int inflate_block(int *e) | |
| /* build decoding table for trees--single level, 7 bit lookup */ | |
| bl = 7; | |
| - | if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { |
| + | i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); |
| + | if (i != 0) { |
| if (i == 1) { | |
| huft_free(tl); | |
| } | |
| @@ -787,46 +739,31 @@ static int inflate_block(int *e) | |
| n = nl + nd; | |
| m = mask_bits[bl]; | |
| i = l = 0; | |
| - | while ((unsigned) i < n) { |
| - | while (k_dynamic < (unsigned) bl) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = (td = tl + ((unsigned) b_dynamic & m))->b; |
| + | while ((unsigned int) i < n) { |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); |
| + | j = (td = tl + ((unsigned int) b_dynamic & m))->b; |
| b_dynamic >>= j; | |
| k_dynamic -= j; | |
| j = td->v.n; | |
| if (j < 16) { /* length of code in bits (0..15) */ | |
| ll[i++] = l = j; /* save last length in l */ | |
| } else if (j == 16) { /* repeat last length 3 to 6 times */ | |
| - | while (k_dynamic < 2) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 3); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); |
| + | j = 3 + ((unsigned int) b_dynamic & 3); |
| b_dynamic >>= 2; | |
| k_dynamic -= 2; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| ll[i++] = l; | |
| } | |
| } else if (j == 17) { /* 3 to 10 zero length codes */ | |
| - | while (k_dynamic < 3) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 3 + ((unsigned) b_dynamic & 7); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); |
| + | j = 3 + ((unsigned int) b_dynamic & 7); |
| b_dynamic >>= 3; | |
| k_dynamic -= 3; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -834,16 +771,11 @@ static int inflate_block(int *e) | |
| } | |
| l = 0; | |
| } else { /* j == 18: 11 to 138 zero length codes */ | |
| - | while (k_dynamic < 7) { |
| - | input_char = fgetc(in_file); |
| - | if (input_char == EOF) return 1; |
| - | b_dynamic |= ((unsigned long)input_char) << k_dynamic; |
| - | k_dynamic += 8; |
| - | } |
| - | j = 11 + ((unsigned) b_dynamic & 0x7f); |
| + | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); |
| + | j = 11 + ((unsigned int) b_dynamic & 0x7f); |
| b_dynamic >>= 7; | |
| k_dynamic -= 7; | |
| - | if ((unsigned) i + j > n) { |
| + | if ((unsigned int) i + j > n) { |
| return 1; | |
| } | |
| while (j--) { | |
| @@ -857,22 +789,24 @@ static int inflate_block(int *e) | |
| huft_free(tl); | |
| /* restore the global bit buffer */ | |
| - | bb = b_dynamic; |
| - | bk = k_dynamic; |
| + | gunzip_bb = b_dynamic; |
| + | gunzip_bk = k_dynamic; |
| /* build the decoding tables for literal/length and distance codes */ | |
| bl = lbits; | |
| + | |
| if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("Incomplete literal tree"); |
| + | error_msg_and_die("Incomplete literal tree"); |
| huft_free(tl); | |
| } | |
| return i; /* incomplete code set */ | |
| } | |
| + | |
| bd = dbits; | |
| if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { | |
| if (i == 1) { | |
| - | error_msg("incomplete distance tree"); |
| + | error_msg_and_die("incomplete distance tree"); |
| huft_free(td); | |
| } | |
| huft_free(tl); | |
| @@ -880,8 +814,9 @@ static int inflate_block(int *e) | |
| } | |
| /* decompress until an end-of-block code */ | |
| - | if (inflate_codes(tl, td, bl, bd)) |
| + | if (inflate_codes(tl, td, bl, bd)) { |
| return 1; | |
| + | } |
| /* free the decoding tables, return */ | |
| huft_free(tl); | |
| @@ -890,6 +825,7 @@ static int inflate_block(int *e) | |
| } | |
| default: | |
| /* bad block type */ | |
| + | error_msg("bad block type %d\n", t); |
| return 2; | |
| } | |
| } | |
| @@ -897,72 +833,24 @@ static int inflate_block(int *e) | |
| /* | |
| * decompress an inflated entry | |
| * | |
| - | * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr |
| + | * GLOBAL VARIABLES: gunzip_outbuf_count, bk, gunzip_bb, hufts, inptr |
| */ | |
| - | extern int inflate(FILE * in, FILE * out) |
| + | extern int inflate(int in, int out) |
| { | |
| + | typedef void (*sig_type) (int); |
| int e; /* last block flag */ | |
| int r; /* result code */ | |
| unsigned h = 0; /* maximum struct huft's malloc'ed */ | |
| - | /* initialize window, bit buffer */ |
| - | outcnt = 0; |
| - | bk = 0; |
| - | bb = 0; |
| - | |
| - | in_file = in; |
| - | out_file = out; |
| - | |
| /* Allocate all global buffers (for DYN_ALLOC option) */ | |
| - | window = xmalloc((size_t) (((2L * WSIZE) + 1L) * sizeof(unsigned char))); |
| - | bytes_out = 0L; |
| + | gunzip_window = xmalloc(0x8000); |
| + | gunzip_outbuf_count = 0; |
| + | gunzip_bytes_out = 0; |
| - | /* Create the crc table */ |
| - | make_crc_table(); |
| + | gunzip_src_fd = in; |
| + | gunzip_dst_fd = out; |
| - | /* decompress until the last block */ |
| - | do { |
| - | hufts = 0; |
| - | if ((r = inflate_block(&e)) != 0) { |
| - | return r; |
| - | } |
| - | if (hufts > h) { |
| - | h = hufts; |
| - | } |
| - | } while (!e); |
| - | |
| - | /* Undo too much lookahead. The next read will be byte aligned so we |
| - | * can discard unused bits in the last meaningful byte. |
| - | */ |
| - | while (bk >= 8) { |
| - | bk -= 8; |
| - | ungetc((bb << bk), in_file); |
| - | } |
| - | |
| - | /* flush out window */ |
| - | flush_window(); |
| - | free(window); |
| - | free(crc_table); |
| - | |
| - | /* return success */ |
| - | return 0; |
| - | } |
| - | |
| - | /* =========================================================================== |
| - | * Unzip in to out. This routine works on gzip files only. |
| - | * |
| - | * IN assertions: the buffer inbuf contains already the beginning of |
| - | * the compressed data, from offsets inptr to insize-1 included. |
| - | * The magic header has already been checked. The output buffer is cleared. |
| - | * in, out: input and output file descriptors |
| - | */ |
| - | extern int unzip(FILE * l_in_file, FILE * l_out_file) |
| - | { |
| - | unsigned char buf[8]; /* extended local header */ |
| - | unsigned char flags; /* compression flags */ |
| - | typedef void (*sig_type) (int); |
| - | unsigned short i; |
| - | unsigned char magic[2]; |
| + | gunzip_in_buffer = malloc(8); |
| if (signal(SIGINT, SIG_IGN) != SIG_IGN) { | |
| (void) signal(SIGINT, (sig_type) abort_gzip); | |
| @@ -973,97 +861,44 @@ extern int unzip(FILE * l_in_file, FILE * l_out_file) | |
| } | |
| #endif | |
| - | magic[0] = fgetc(l_in_file); |
| - | magic[1] = fgetc(l_in_file); |
| - | |
| - | #ifdef CONFIG_FEATURE_UNCOMPRESS |
| - | /* Magic header for compress files, 1F 9d = \037\235 */ |
| - | if ((magic[0] == 0x1F) && (magic[1] == 0x9d)) { |
| - | return uncompress(l_in_file, l_out_file); |
| - | } |
| - | #endif |
| - | |
| - | /* Magic header for gzip files, 1F 8B = \037\213 */ |
| - | if ((magic[0] != 0x1F) || (magic[1] != 0x8b)) { |
| - | error_msg("Invalid gzip magic"); |
| - | return EXIT_FAILURE; |
| - | } |
| - | |
| - | /* Check the compression method */ |
| - | if (fgetc(l_in_file) != 8) /* also catches EOF */ { |
| - | error_msg("Unknown compression method"); |
| - | return (-1); |
| - | } |
| - | |
| - | flags = (unsigned char) fgetc(l_in_file); |
| - | |
| - | /* Ignore time stamp(4), extra flags(1), OS type(1) */ |
| - | for (i = 0; i < 6; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| + | /* initialize gunzip_window, bit buffer */ |
| + | gunzip_bk = 0; |
| + | gunzip_bb = 0; |
| - | if (flags & 0x04) { |
| - | /* bit 2 set: extra field present */ |
| - | const unsigned short extra = |
| - | fgetc(l_in_file) + (fgetc(l_in_file) << 8); |
| - | if (feof(in_file)) return 1; |
| - | for (i = 0; i < extra; i++) { |
| - | fgetc(l_in_file); |
| - | } |
| - | } |
| - | |
| - | /* Discard original name if any */ |
| - | if (flags & 0x08) { |
| - | /* bit 3 set: original file name present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| - | } |
| + | /* Create the crc table */ |
| + | make_gunzip_crc_table(); |
| - | /* Discard file comment if any */ |
| - | if (flags & 0x10) { |
| - | /* bit 4 set: file comment present */ |
| - | while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ |
| + | /* decompress until the last block */ |
| + | do { |
| + | gunzip_hufts = 0; |
| + | r = inflate_block(&e); |
| + | if (r != 0) { |
| + | error_msg_and_die("inflate error %d", r); |
| + | return r; |
| } | |
| - | |
| - | /* Decompress */ |
| - | if (inflate(l_in_file, l_out_file) != 0) { |
| - | error_msg("invalid compressed data--format violated"); |
| + | if (gunzip_hufts > h) { |
| + | h = gunzip_hufts; |
| } | |
| + | } while (!e); |
| - | /* Get the crc and original length |
| - | * crc32 (see algorithm.doc) |
| - | * uncompressed input size modulo 2^32 |
| - | */ |
| - | fread(buf, 1, 8, l_in_file); |
| - | |
| - | /* Validate decompression - crc */ |
| - | if ((unsigned int) ((buf[0] | (buf[1] << 8)) | |
| - | ((buf[2] | (buf[3] << 8)) << 16)) != |
| - | (crc ^ 0xffffffffL)) { |
| - | error_msg("invalid compressed data--crc error"); |
| - | } |
| - | /* Validate decompression - size */ |
| - | if (((buf[4] | (buf[5] << 8)) | ((buf[6] | (buf[7] << 8)) << 16)) != |
| - | (unsigned long) bytes_out) { |
| - | error_msg("invalid compressed data--length error"); |
| + | /* write any buffered uncompressed data */ |
| + | flush_gunzip_window(); |
| + | free(gunzip_window); |
| + | |
| + | /* Cleanup */ |
| + | free(gunzip_crc_table); |
| + | |
| + | /* Store unused bytes in a global buffer so calling applets can access it */ |
| + | gunzip_in_buffer_count = 0; |
| + | if (gunzip_bk >= 8) { |
| + | /* Undo too much lookahead. The next read will be byte aligned |
| + | * so we can discard unused bits in the last meaningful byte. */ |
| + | gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; |
| + | gunzip_in_buffer_count++; |
| + | gunzip_bb >>= 8; |
| + | gunzip_bk -= 8; |
| } | |
| + | /* return success */ |
| return 0; | |
| } | |
| - | |
| - | /* |
| - | * This needs access to global variables window and crc_table, so its not in its own file. |
| - | */ |
| - | extern void gz_close(int gunzip_pid) |
| - | { |
| - | if (kill(gunzip_pid, SIGTERM) == -1) { |
| - | error_msg_and_die |
| - | ("*** Couldnt kill old gunzip process *** aborting"); |
| - | } |
| - | |
| - | if (waitpid(gunzip_pid, NULL, 0) == -1) { |
| - | printf("Couldnt wait ?"); |
| - | } |
| - | |
| - | free(window); |
| - | free(crc_table); |
| - | } |
| @@ -19,10 +19,13 @@ | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| + | #include <sys/types.h> |
| + | #include <sys/stat.h> |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| + | #include <fcntl.h> |
| #include "libbb.h" | |
| @@ -85,6 +88,59 @@ FILE *xfopen(const char *path, const char *mode) | |
| return fp; | |
| } | |
| + | extern int xopen(const char *pathname, int flags) |
| + | { |
| + | int ret; |
| + | |
| + | ret = open(pathname, flags); |
| + | if (ret == -1) { |
| + | perror_msg_and_die("%s", pathname); |
| + | } |
| + | return ret; |
| + | } |
| + | |
| + | extern ssize_t xread(int fd, void *buf, size_t count) |
| + | { |
| + | ssize_t size; |
| + | |
| + | size = read(fd, buf, count); |
| + | if (size == -1) { |
| + | perror_msg_and_die("Read error"); |
| + | } |
| + | return(size); |
| + | } |
| + | |
| + | extern void xread_all(int fd, void *buf, size_t count) |
| + | { |
| + | ssize_t size; |
| + | |
| + | size = xread(fd, buf, count); |
| + | if (size != count) { |
| + | error_msg_and_die("Short read"); |
| + | } |
| + | return; |
| + | } |
| + | |
| + | extern ssize_t xread_all_eof(int fd, void *buf, size_t count) |
| + | { |
| + | ssize_t size; |
| + | |
| + | size = xread(fd, buf, count); |
| + | if ((size != 0) && (size != count)) { |
| + | error_msg_and_die("Short read"); |
| + | } |
| + | return(size); |
| + | } |
| + | |
| + | extern unsigned char xread_char(int fd) |
| + | { |
| + | char tmp; |
| + | |
| + | xread_all(fd, &tmp, 1); |
| + | |
| + | return(tmp); |
| + | } |
| + | |
| /* Stupid gcc always includes its own builtin strlen()... */ | |
| #undef strlen | |
| size_t xstrlen(const char *string) | |