New common unarchive code.

This commit is contained in:
Glenn L McGrath 2002-09-25 02:47:48 +00:00
parent ecfa290cfd
commit 7ca04f328e
36 changed files with 2436 additions and 1914 deletions

View File

@ -21,41 +21,100 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 <fcntl.h>
#include <fnmatch.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include "unarchive.h" #include "unarchive.h"
#include "busybox.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) extern int ar_main(int argc, char **argv)
{ {
FILE *src_stream = NULL; archive_handle_t *archive_handle;
char **extract_names = NULL;
char ar_magic[8];
int extract_function = extract_unconditional;
int opt; 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) { switch (opt) {
case 'o': case 'p': /* print */
extract_function |= extract_preserve_date; archive_handle->action_data = data_extract_to_stdout;
break; break;
case 'v': case 't': /* list contents */
extract_function |= extract_verbose_list; archive_handle->action_header = header_list;
break; break;
case 't': case 'X':
extract_function |= extract_list; 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; break;
case 'p': /* Modifiers */
extract_function |= extract_to_stdout; case 'o': /* preserve original dates */
archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
break; break;
case 'x': case 'v': /* verbose */
extract_function |= extract_all_to_fs; archive_handle->action_header = header_verbose_list_ar;
break; break;
default: default:
show_usage(); show_usage();
@ -67,24 +126,26 @@ extern int ar_main(int argc, char **argv)
show_usage(); show_usage();
} }
src_stream = xfopen(argv[optind++], "r"); archive_handle->src_fd = xopen(argv[optind++], O_RDONLY);
/* check ar magic */ /* TODO: This is the same as in tar, seperate function ? */
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 */
while (optind < argc) { while (optind < argc) {
extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); archive_handle->filter = filter_accept_list;
extract_names[num_of_entries] = xstrdup(argv[optind]); archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]);
num_of_entries++;
extract_names[num_of_entries] = NULL;
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; return EXIT_SUCCESS;
} }

View File

@ -7,10 +7,16 @@ mainmenu_option next_comment
comment 'Archival Utilities' comment 'Archival Utilities'
bool 'ar' CONFIG_AR 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 'bunzip2' CONFIG_BUNZIP2
bool 'cpio' CONFIG_CPIO bool 'cpio' CONFIG_CPIO
bool 'dpkg' CONFIG_DPKG bool 'dpkg' CONFIG_DPKG
bool 'dpkg_deb' CONFIG_DPKG_DEB 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 'gunzip' CONFIG_GUNZIP
bool 'gzip' CONFIG_GZIP bool 'gzip' CONFIG_GZIP
bool 'rpm2cpio' CONFIG_RPM2CPIO bool 'rpm2cpio' CONFIG_RPM2CPIO

View File

@ -31,66 +31,210 @@
#include "unarchive.h" #include "unarchive.h"
#include "busybox.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) extern int cpio_main(int argc, char **argv)
{ {
FILE *src_stream = stdin; archive_handle_t *archive_handle;
char **extract_names = NULL; int opt;
int extract_function = 0;
int num_of_entries = 0; /* Initialise */
int opt = 0; archive_handle = init_handle();
mode_t oldmask = 0; archive_handle->src_fd = fileno(stdin);
archive_handle->action_header = header_list;
while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
switch (opt) { switch (opt) {
case 'i': // extract case 'i': /* extract */
extract_function |= extract_all_to_fs; archive_handle->action_data = data_extract_all;
break; break;
case 'd': // create _leading_ directories case 'd': /* create _leading_ directories */
extract_function |= extract_create_leading_dirs; archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
oldmask = umask(077); /* Make make_directory act like GNU cpio */
break; break;
case 'm': // preserve modification time case 'm': /* preserve modification time */
extract_function |= extract_preserve_date; archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
break; break;
case 'v': // verbosly list files case 'v': /* verbosly list files */
extract_function |= extract_verbose_list; archive_handle->action_header = header_verbose_list;
break; break;
case 'u': // unconditional case 'u': /* unconditional */
extract_function |= extract_unconditional; archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
break; break;
case 't': // list files case 't': /* list files */
extract_function |= extract_list; archive_handle->action_header = header_list;
break; break;
case 'F': case 'F':
src_stream = xfopen(optarg, "r"); archive_handle->src_fd = xopen(optarg, O_RDONLY);
break; break;
default: default:
show_usage(); 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*/
}
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 (optind < argc) { while (optind < argc) {
extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); archive_handle->filter = filter_accept_list;
extract_names[num_of_entries] = xstrdup(argv[optind]); archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]);
num_of_entries++;
extract_names[num_of_entries] = NULL;
optind++; optind++;
} }
unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names, NULL); while (1) {
if (oldmask) { static hardlinks_t *saved_hardlinks = NULL;
umask(oldmask); /* Restore umask if we changed it */ 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 */
} }
return EXIT_SUCCESS;
/* 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;
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);
} }

View File

@ -13,119 +13,100 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include "unarchive.h" #include "unarchive.h"
#include "busybox.h" #include "busybox.h"
extern int dpkg_deb_main(int argc, char **argv) extern int dpkg_deb_main(int argc, char **argv)
{ {
char *prefix = NULL; archive_handle_t *ar_archive;
char *filename = NULL; archive_handle_t *tar_gz_archive;
char *output_buffer = NULL;
int opt = 0; int opt = 0;
int arg_type = 0; #ifndef CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY
int deb_extract_funct = extract_create_leading_dirs | extract_unconditional; const llist_t *control_tar_gz_llist = add_to_list(NULL, "control.tar.gz");
#endif
#ifndef CONFIG_AR
char magic[7];
#endif
const int arg_type_prefix = 1; /* a .deb file is an ar archive that contain three files,
const int arg_type_field = 2; * data.tar.gz, control.tar.gz and debian
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) { switch (opt) {
#ifndef CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY
case 'c': case 'c':
deb_extract_funct |= extract_data_tar_gz; tar_gz_archive->action_header = header_verbose_list;
deb_extract_funct |= extract_verbose_list;
break; break;
case 'e': case 'e':
arg_type = arg_type_prefix; ar_archive->accept = control_tar_gz_llist;
deb_extract_funct |= extract_control_tar_gz; tar_gz_archive->action_data = data_extract_all;
deb_extract_funct |= extract_all_to_fs;
break; break;
case 'f': case 'f':
arg_type = arg_type_field; /* Print the entire control file
deb_extract_funct |= extract_control_tar_gz; * it should accept a second argument which specifies a
deb_extract_funct |= extract_one_to_buffer; * specific field to print */
filename = xstrdup("./control"); ar_archive->accept = control_tar_gz_llist;
break; tar_gz_archive->accept = add_to_list(NULL, "./control");;
case 't': /* --fsys-tarfile, i just made up this short name */ tar_gz_archive->filter = filter_accept_list;
/* Integrate the functionality needed with some code from ar.c */ tar_gz_archive->action_data = data_extract_to_stdout;
error_msg_and_die("Option disabled");
// arg_type = arg_type_un_ar_gz;
break; break;
case 'X': case 'X':
arg_type = arg_type_prefix; tar_gz_archive->action_header = header_list;
deb_extract_funct |= extract_data_tar_gz; #endif
deb_extract_funct |= extract_all_to_fs;
deb_extract_funct |= extract_list;
case 'x': case 'x':
arg_type = arg_type_prefix; tar_gz_archive->action_data = data_extract_all;
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;
break; break;
default: default:
show_usage(); show_usage();
} }
} }
if (optind == argc) { if (optind + 2 < argc) {
show_usage(); show_usage();
} }
tar_gz_archive->src_fd = ar_archive->src_fd = xopen(argv[optind++], O_RDONLY);
/* Workout where to extract the files */ /* Workout where to extract the files */
if (arg_type == arg_type_prefix) { /* 2nd argument is a dir name */
/* argument is a dir name */ mkdir(argv[optind], 0777);
if ((optind + 1) == argc ) { chdir(argv[optind]);
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);
}
if (arg_type == arg_type_filename) { #ifdef CONFIG_AR
if ((optind + 1) != argc) { unpack_ar_archive(ar_archive);
filename = xstrdup(argv[optind + 1]); #else
} else { xread_all(ar_archive->src_fd, magic, 7);
error_msg_and_die("-I currently requires a filename to be specified"); 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)) { /* Cleanup */
puts(output_buffer); close (ar_archive->src_fd);
}
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);
}
}
return(EXIT_SUCCESS); return(EXIT_SUCCESS);
} }

View File

@ -64,7 +64,12 @@ static char *license_msg[] = {
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "busybox.h" #include "busybox.h"
#include "unarchive.h"
const char gunzip_to_stdout = 1; const char gunzip_to_stdout = 1;
const char gunzip_force = 2; const char gunzip_force = 2;
@ -100,23 +105,20 @@ extern int gunzip_main(int argc, char **argv)
} }
do { do {
FILE *in_file, *out_file;
struct stat stat_buf; struct stat stat_buf;
const char *old_path = argv[optind]; const char *old_path = argv[optind];
const char *delete_path = NULL; const char *delete_path = NULL;
char *new_path = NULL; char *new_path = NULL;
int src_fd;
int dst_fd;
optind++; optind++;
if (old_path == NULL || strcmp(old_path, "-") == 0) { if (old_path == NULL || strcmp(old_path, "-") == 0) {
in_file = stdin; src_fd = fileno(stdin);
flags |= gunzip_to_stdout; flags |= gunzip_to_stdout;
} else { } else {
in_file = wfopen(old_path, "r"); src_fd = xopen(old_path, O_RDONLY);
if (in_file == NULL) {
status = EXIT_FAILURE;
break;
}
/* Get the time stamp on the input file. */ /* Get the time stamp on the input file. */
if (stat(old_path, &stat_buf) < 0) { 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. */ /* 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 error_msg_and_die
("compressed data not read from terminal. Use -f to force it."); ("compressed data not read from terminal. Use -f to force it.");
} }
/* Set output filename and number */ /* Set output filename and number */
if (flags & gunzip_test) { 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) { } else if (flags & gunzip_to_stdout) {
out_file = stdout; dst_fd = fileno(stdout);
} else { } else {
char *extension; char *extension;
@ -151,7 +153,7 @@ extern int gunzip_main(int argc, char **argv)
} }
/* Open output file */ /* Open output file */
out_file = xfopen(new_path, "w"); dst_fd = xopen(new_path, O_WRONLY | O_CREAT);
/* Set permissions on the file */ /* Set permissions on the file */
chmod(new_path, stat_buf.st_mode); chmod(new_path, stat_buf.st_mode);
@ -161,16 +163,22 @@ extern int gunzip_main(int argc, char **argv)
} }
/* do the decompression, and cleanup */ /* 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 */ /* Unzip failed, remove new path instead of old path */
delete_path = new_path; delete_path = new_path;
} }
if (out_file != stdout) { if (dst_fd != fileno(stdout)) {
fclose(out_file); close(dst_fd);
} }
if (in_file != stdin) { if (src_fd != fileno(stdin)) {
fclose(in_file); close(src_fd);
} }
/* delete_path will be NULL if in test mode or from stdin */ /* delete_path will be NULL if in test mode or from stdin */

View File

@ -22,14 +22,41 @@ ifndef $(LIBUNARCHIVE_DIR)
LIBUNARCHIVE_DIR:=$(TOPDIR)archival/libunarchive/ LIBUNARCHIVE_DIR:=$(TOPDIR)archival/libunarchive/
endif endif
LIBUNARCHIVE-y:=unarchive.o seek_sub_file.o LIBUNARCHIVE-y:= \
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 data_skip.o \
LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o data_extract_all.o \
LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o data_extract_to_stdout.o \
LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += get_header_cpio.o \
LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o filter_accept_all.o \
LIBUNARCHIVE-$(CONFIG_UNZIP) += get_header_zip.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) libraries-y+=$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR)

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -17,12 +17,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "unarchive.h" #include "unarchive.h"
#include "libbb.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 { union {
char raw[60]; char raw[60];
struct { struct {
@ -35,72 +36,87 @@ file_header_t *get_header_ar(FILE *src_stream)
char magic[2]; char magic[2];
} formated; } formated;
} ar; } ar;
#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES
static char *ar_long_names; static char *ar_long_names;
static unsigned int ar_long_name_size;
#endif
if (fread(ar.raw, 1, 60, src_stream) != 60) { /* dont use xread as we want to handle the error ourself */
return(NULL); 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 */
memmove(ar.raw, &ar.raw[1], 59);
ar.raw[59] = xread_char(archive_handle->src_fd);
archive_handle->offset++;
} }
archive_offset += 60; archive_handle->offset += 60;
/* align the headers based on the header magic */ /* align the headers based on the header magic */
if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
/* some version of ar, have an extra '\n' after each data entry, error_msg_and_die("Invalid ar header");
* 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);
}
/* 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);
} }
typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
typed->size = (size_t) atoi(ar.formated.size); 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);
/* long filenames have '/' as the first character */ /* long filenames have '/' as the first character */
if (ar.formated.name[0] == '/') { if (ar.formated.name[0] == '/') {
#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES
if (ar.formated.name[1] == '/') { if (ar.formated.name[1] == '/') {
/* If the second char is a '/' then this entries data section /* If the second char is a '/' then this entries data section
* stores long filename for multiple entries, they are stored * stores long filename for multiple entries, they are stored
* in static variable long_names for use in future entries */ * in static variable long_names for use in future entries */
ar_long_names = (char *) xrealloc(ar_long_names, typed->size); ar_long_name_size = typed->size;
fread(ar_long_names, 1, typed->size, src_stream); ar_long_names = xmalloc(ar_long_name_size);
archive_offset += typed->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 /* This ar entries data section only contained filenames for other records
* they are stored in the static ar_long_names for future reference */ * 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] == ' ') { } else if (ar.formated.name[1] == ' ') {
/* This is the index of symbols in the file for compilers */ /* This is the index of symbols in the file for compilers */
seek_sub_file(src_stream, typed->size); data_skip(archive_handle);
return (get_header_ar(src_stream)); /* Return next header */ return (get_header_ar(archive_handle)); /* Return next header */
} else { } else {
/* The number after the '/' indicates the offset in the ar data section /* The number after the '/' indicates the offset in the ar data section
(saved in variable long_name) that conatains the real filename */ (saved in variable long_name) that conatains the real filename */
if (!ar_long_names) { const unsigned int long_offset = atoi(&ar.formated.name[1]);
error_msg("Cannot resolve long file name"); if (long_offset >= ar_long_name_size) {
return (NULL); 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 { } else {
/* short filenames */ /* short filenames */
typed->name = xstrndup(ar.formated.name, 16); 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 */ typed->name[strcspn(typed->name, " /")] = '\0';
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);
return(typed); 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(EXIT_SUCCESS);
} }

View File

@ -20,8 +20,9 @@
#include "unarchive.h" #include "unarchive.h"
#include "libbb.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 { union {
unsigned char raw[512]; unsigned char raw[512];
struct { struct {
@ -44,20 +45,22 @@ file_header_t *get_header_tar(FILE * tar_stream)
char padding[12]; /* 500-512 */ char padding[12]; /* 500-512 */
} formated; } formated;
} tar; } tar;
file_header_t *tar_entry = NULL;
long sum = 0; long sum = 0;
long i; long i;
if (archive_offset % 512 != 0) { /* Align header */
seek_sub_file(tar_stream, 512 - (archive_offset % 512)); archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 512);
}
if (fread(tar.raw, 1, 512, tar_stream) != 512) { if (xread_all_eof(archive_handle->src_fd, tar.raw, 512) == 0) {
/* Unfortunatly its common for tar files to have all sorts of /* End of file */
* trailing garbage, fail silently */ return(EXIT_FAILURE);
return (NULL); }
archive_handle->offset += 512;
/* 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 /* Check header has valid magic, "ustar" is for the proper tar
* 0's are for the old tar format * 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 #ifdef CONFIG_FEATURE_TAR_OLD_FORMAT
if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0)
#endif #endif
return (NULL); error_msg_and_die("Invalid tar magic");
}
/* If there is no filename its an empty header, skip it */
if (tar.formated.name[0] == 0) {
return (NULL);
} }
/* Do checksum on headers */ /* Do checksum on headers */
for (i = 0; i < 148; i++) { for (i = 0; i < 148 ; i++) {
sum += tar.raw[i]; sum += tar.raw[i];
} }
sum += ' ' * 8; sum += ' ' * 8;
for (i = 156; i < 512; i++) { for (i = 156; i < 512 ; i++) {
sum += tar.raw[i]; sum += tar.raw[i];
} }
if (sum != strtol(tar.formated.chksum, NULL, 8)) { if (sum != strtol(tar.formated.chksum, NULL, 8)) {
error_msg("Invalid tar header checksum"); error_msg("Invalid tar header checksum");
return (NULL); return(EXIT_FAILURE);
} }
/* convert to type'ed variables */ /* convert to type'ed variables */
tar_entry = xcalloc(1, sizeof(file_header_t));
if (tar.formated.prefix[0] == 0) { if (tar.formated.prefix[0] == 0) {
tar_entry->name = xstrdup(tar.formated.name); file_header->name = strdup(tar.formated.name);
} else { } else {
tar_entry->name = file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name);
concat_path_file(tar.formated.prefix, tar.formated.name);
} }
file_header->mode = strtol(tar.formated.mode, NULL, 8);
tar_entry->mode = strtol(tar.formated.mode, NULL, 8); file_header->uid = strtol(tar.formated.uid, NULL, 8);
tar_entry->uid = strtol(tar.formated.uid, NULL, 8); file_header->gid = strtol(tar.formated.gid, NULL, 8);
tar_entry->gid = strtol(tar.formated.gid, NULL, 8); file_header->size = strtol(tar.formated.size, NULL, 8);
tar_entry->size = strtol(tar.formated.size, NULL, 8); file_header->mtime = strtol(tar.formated.mtime, NULL, 8);
tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); file_header->link_name = (tar.formated.linkname[0] != '\0') ?
tar_entry->link_name = xstrdup(tar.formated.linkname) : NULL;
strlen(tar.formated.linkname) ? xstrdup(tar.formated.linkname) : NULL; file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) +
tar_entry->device =
(dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) +
strtol(tar.formated.devminor, NULL, 8)); strtol(tar.formated.devminor, NULL, 8));
#if defined CONFIG_FEATURE_TAR_OLD_FORMAT || defined CONFIG_FEATURE_GNUTAR_LONG_FILENAME #if defined CONFIG_FEATURE_TAR_OLD_FORMAT || defined CONFIG_FEATURE_GNUTAR_LONG_FILENAME
/* Fix mode, used by the old format */
switch (tar.formated.typeflag) { switch (tar.formated.typeflag) {
# ifdef CONFIG_FEATURE_TAR_OLD_FORMAT # ifdef CONFIG_FEATURE_TAR_OLD_FORMAT
case 0: case 0:
tar_entry->mode |= S_IFREG; file_header->mode |= S_IFREG;
break; break;
case 1: case 1:
error_msg("internal hard link not handled\n"); error_msg("Internal hard link not supported");
break; break;
case 2: case 2:
tar_entry->mode |= S_IFLNK; file_header->mode |= S_IFLNK;
break; break;
case 3: case 3:
tar_entry->mode |= S_IFCHR; file_header->mode |= S_IFCHR;
break; break;
case 4: case 4:
tar_entry->mode |= S_IFBLK; file_header->mode |= S_IFBLK;
break; break;
case 5: case 5:
tar_entry->mode |= S_IFDIR; file_header->mode |= S_IFDIR;
break; break;
case 6: case 6:
tar_entry->mode |= S_IFIFO; file_header->mode |= S_IFIFO;
break; break;
# endif # endif
# ifdef CONFIG_FEATURE_GNUTAR_LONG_FILENAME # ifdef CONFIG_FEATURE_GNUTAR_LONG_FILENAME
case 'L': { case 'L': {
char *longname; char *longname;
longname = xmalloc(tar_entry->size + 1); longname = xmalloc(file_header->size + 1);
fread(longname, 1, tar_entry->size, tar_stream); xread_all(archive_handle->src_fd, longname, file_header->size);
archive_offset += tar_entry->size; longname[file_header->size] = '\0';
longname[tar_entry->size] = '\0'; archive_handle->offset += file_header->size;
tar_entry = get_header_tar(tar_stream); get_header_tar(archive_handle);
tar_entry->name = longname; file_header->name = longname;
break; break;
} }
case 'K': { case 'K': {
char *longname; char *linkname;
longname = xmalloc(tar_entry->size + 1); linkname = xmalloc(file_header->size + 1);
fread(longname, 1, tar_entry->size, tar_stream); xread_all(archive_handle->src_fd, linkname, file_header->size);
archive_offset += tar_entry->size; linkname[file_header->size] = '\0';
longname[tar_entry->size] = '\0'; archive_handle->offset += file_header->size;
tar_entry = get_header_tar(tar_stream); get_header_tar(archive_handle);
tar_entry->link_name = longname; file_header->name = linkname;
break; break;
} }
# endif # endif
} }
#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);
} }

View File

@ -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);
}

View File

@ -0,0 +1,7 @@
#include <stdio.h>
#include "unarchive.h"
extern void header_list(const file_header_t *file_header)
{
puts(file_header->name);
}

View File

@ -0,0 +1,7 @@
#include <stdio.h>
#include "unarchive.h"
extern void header_skip(const file_header_t *file_header)
{
return;
}

View File

@ -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("");
}

View File

@ -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);
}

View File

@ -14,23 +14,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include "unarchive.h"
#include "libbb.h"
off_t archive_offset; extern void seek_sub_file(const int src_fd, const unsigned int amount)
void seek_sub_file(FILE *src_stream, const int count)
{ {
/* Try to fseek as faster */ if ((lseek(src_fd, amount, SEEK_CUR) == -1) && (errno == ESPIPE)) {
archive_offset += count; unsigned int i;
if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) { for (i = 0; i < amount; i++) {
int i; xread_char(src_fd);
for (i = 0; i < count; i++) {
fgetc(src_stream);
} }
} }
return;
} }

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -18,10 +18,13 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <sys/types.h>
#include "busybox.h"
#include <netinet/in.h> /* For ntohl & htonl function */ #include <netinet/in.h> /* For ntohl & htonl function */
#include <fcntl.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#include "busybox.h"
#include "unarchive.h"
#define RPM_MAGIC "\355\253\356\333" #define RPM_MAGIC "\355\253\356\333"
#define RPM_HEADER_MAGIC "\216\255\350" #define RPM_HEADER_MAGIC "\216\255\350"
@ -45,46 +48,54 @@ struct rpm_header {
u_int32_t size; /* Size of store (4 bytes) */ u_int32_t size; /* Size of store (4 bytes) */
}; };
void skip_header(FILE *rpmfile) void skip_header(int rpm_fd)
{ {
struct rpm_header header; struct rpm_header header;
fread(&header, sizeof(struct rpm_header), 1, rpmfile); 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 (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) {
if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ 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.entries = ntohl(header.entries);
header.size = ntohl(header.size); header.size = ntohl(header.size);
fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ lseek (rpm_fd, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */ lseek (rpm_fd, header.size, SEEK_CUR); /* Seek past store */
} }
/* No getopt required */ /* No getopt required */
extern int rpm2cpio_main(int argc, char **argv) extern int rpm2cpio_main(int argc, char **argv)
{ {
struct rpm_lead lead; struct rpm_lead lead;
int gunzip_pid; int rpm_fd;
FILE *rpmfile, *cpiofile;
if (argc == 1) { if (argc == 1) {
rpmfile = stdin; rpm_fd = fileno(stdin);
} else { } else {
rpmfile = xfopen(argv[1], "r"); rpm_fd = xopen(argv[1], O_RDONLY);
/* set the buffer size */ }
setvbuf(rpmfile, NULL, _IOFBF, 0x8000);
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 the signature header */
skip_header(rpmfile); skip_header(rpm_fd);
fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */ data_align(rpm_fd, lseek(rpm_fd, 0, SEEK_CUR), 8);
/* Skip the main header */ /* Skip the main header */
skip_header(rpmfile); skip_header(rpm_fd);
cpiofile = gz_open(rpmfile, &gunzip_pid); check_header_gzip(rpm_fd);
if (inflate(rpm_fd, fileno(stdout)) != 0) {
error_msg("Error inflating");
}
check_trailer_gzip(rpm_fd);
close(rpm_fd);
copyfd(fileno(cpiofile), fileno(stdout));
gz_close(gunzip_pid);
fclose(rpmfile);
return 0; return 0;
} }

View File

@ -115,7 +115,7 @@ struct TarBallInfo {
tarball lives, so we can avoid trying tarball lives, so we can avoid trying
to include the tarball into itself */ to include the tarball into itself */
int verboseFlag; /* Whether to print extra stuff or not */ 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 *hlInfoHead; /* Hard Link Tracking Information */
HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ 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 # 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; return 0;
}
for (i = 0; excluded_files[i] != NULL; i++) { while (excluded_files) {
if (excluded_files[i][0] == '/') { if (excluded_files->data[0] == '/') {
if (fnmatch(excluded_files[i], file, if (fnmatch(excluded_files->data, file,
FNM_PATHNAME | FNM_LEADING_DIR) == 0) FNM_PATHNAME | FNM_LEADING_DIR) == 0)
return 1; return 1;
} else { } else {
@ -342,11 +341,12 @@ static inline int exclude_file(char **excluded_files, const char *file)
for (p = file; p[0] != '\0'; p++) { for (p = file; p[0] != '\0'; p++) {
if ((p == file || p[-1] == '/') && p[0] != '/' && if ((p == file || p[-1] == '/') && p[0] != '/' &&
fnmatch(excluded_files[i], p, fnmatch(excluded_files->data, p,
FNM_PATHNAME | FNM_LEADING_DIR) == 0) FNM_PATHNAME | FNM_LEADING_DIR) == 0)
return 1; return 1;
} }
} }
excluded_files = excluded_files->link;
} }
return 0; return 0;
@ -455,8 +455,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf,
return (TRUE); return (TRUE);
} }
static inline int writeTarFile(const char *tarName, int verboseFlag, static inline int writeTarFile(const char *tarName, const int verboseFlag,
char **argv, char **excludeList, int gzip) const llist_t *include, const llist_t *exclude, const int gzip)
{ {
#ifdef CONFIG_FEATURE_TAR_GZIP #ifdef CONFIG_FEATURE_TAR_GZIP
int gzipDataPipe[2] = { -1, -1 }; int gzipDataPipe[2] = { -1, -1 };
@ -471,8 +471,9 @@ static inline int writeTarFile(const char *tarName, int verboseFlag,
tbInfo.hlInfoHead = NULL; tbInfo.hlInfoHead = NULL;
/* Make sure there is at least one file to tar up. */ /* 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"); error_msg_and_die("Cowardly refusing to create an empty archive");
}
/* Open the tar file for writing. */ /* Open the tar file for writing. */
if (tarName == NULL) { if (tarName == NULL) {
@ -544,15 +545,16 @@ static inline int writeTarFile(const char *tarName, int verboseFlag,
} }
#endif #endif
tbInfo.excludeList = excludeList; tbInfo.excludeList = exclude;
/* Read the directory/files and iterate over them one at a time */ /* Read the directory/files and iterate over them one at a time */
while (*argv != NULL) { while (include) {
if (!recursive_action(*argv++, TRUE, FALSE, FALSE, if (!recursive_action(include->data, TRUE, FALSE, FALSE,
writeFileToTarball, writeFileToTarball, writeFileToTarball, writeFileToTarball,
(void *) &tbInfo)) { (void *) &tbInfo)) {
errorFlag = TRUE; errorFlag = TRUE;
} }
include = include->link;
} }
/* Write two empty blocks to the end of the archive */ /* Write two empty blocks to the end of the archive */
for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { 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 */ #endif /* tar_create */
void append_file_to_list(const char *new_name, char ***list, int *list_count) #ifdef CONFIG_FEATURE_TAR_EXCLUDE
static const llist_t *append_file_list_to_list(const char *filename, const llist_t *list)
{ {
*list = realloc(*list, sizeof(char *) * (*list_count + 2)); FILE *src_stream = xfopen(filename, "r");
(*list)[*list_count] = xstrdup(new_name); while(1) {
(*list_count)++; char *line = get_line_from_file(src_stream);
(*list)[*list_count] = NULL; if (line == NULL) {
} break;
}
void append_file_list_to_list(char *filename, char ***name_list,
int *num_of_entries)
{
FILE *src_stream;
char *line;
src_stream = xfopen(filename, "r");
while ((line = get_line_from_file(src_stream)) != NULL) {
chomp(line); chomp(line);
append_file_to_list(line, name_list, num_of_entries); list = add_to_list(list, line);
free(line); free(line);
} }
fclose(src_stream); fclose(src_stream);
return (list);
} }
#endif
int tar_main(int argc, char **argv) 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;
int opt;
unsigned short untar_funct = 0;
unsigned short untar_funct_required = 0;
unsigned short extract_function = 0;
int include_list_count = 0;
#ifdef CONFIG_FEATURE_TAR_EXCLUDE
int exclude_list_count = 0;
#endif
#ifdef CONFIG_FEATURE_TAR_GZIP #ifdef CONFIG_FEATURE_TAR_GZIP
int gunzip_pid; char (*get_header_ptr)(archive_handle_t *) = get_header_tar;
int gz_fd = 0; #endif
archive_handle_t *tar_handle;
int opt;
char *base_dir = NULL;
#ifdef CONFIG_FEATURE_TAR_CREATE
char *src_filename = NULL;
unsigned char tar_create = FALSE;
#endif #endif
if (argc < 2) { if (argc < 2) {
show_usage(); 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 */ /* Prepend '-' to the first argument if required */
if (argv[1][0] != '-') { if (argv[1][0] != '-') {
char *tmp = xmalloc(strlen(argv[1]) + 2); char *tmp = xmalloc(strlen(argv[1]) + 2);
@ -648,61 +634,69 @@ int tar_main(int argc, char **argv)
strcpy(tmp + 1, argv[1]); strcpy(tmp + 1, argv[1]);
argv[1] = tmp; argv[1] = tmp;
} }
while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) { while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) {
switch (opt) { switch (opt) {
/* One and only one of these is required */ /* One and only one of these is required */
#ifdef CONFIG_FEATURE_TAR_CREATE
case 'c': case 'c':
untar_funct_required |= untar_create; tar_create = TRUE;
break; break;
#endif
case 't': case 't':
untar_funct_required |= untar_list; if ((tar_handle->action_header == header_list) ||
extract_function |= extract_list | extract_unconditional; (tar_handle->action_header == header_verbose_list)) {
tar_handle->action_header = header_verbose_list;
} else {
tar_handle->action_header = header_list;
}
break; break;
case 'x': case 'x':
untar_funct_required |= untar_extract; tar_handle->action_data = data_extract_all;
extract_function |=
(extract_all_to_fs | extract_unconditional |
extract_create_leading_dirs);
break; break;
/* These are optional */ /* These are optional */
/* Exclude or Include files listed in <filename> */ /* Exclude or Include files listed in <filename> */
#ifdef CONFIG_FEATURE_TAR_EXCLUDE #ifdef CONFIG_FEATURE_TAR_EXCLUDE
case 'X': case 'X':
append_file_list_to_list(optarg, &exclude_list, tar_handle->reject =
&exclude_list_count); append_file_list_to_list(optarg, tar_handle->reject);
break; break;
#endif #endif
case 'T': case 'T':
/* by default a list is an include list */ /* by default a list is an include list */
append_file_list_to_list(optarg, &include_list,
&include_list_count);
break; break;
case 'C': /* Change to dir <optarg> */ case 'C': /* Change to dir <optarg> */
/* Make sure dst_prefix ends in a '/' */ base_dir = optarg;
dst_prefix = concat_path_file(optarg, "/");
break; break;
case 'f': /* archive filename */ case 'f': /* archive filename */
if (strcmp(optarg, "-") == 0) { #ifdef CONFIG_FEATURE_TAR_CREATE
src_filename = NULL; src_filename = optarg;
} else { #endif
src_filename = xstrdup(optarg); tar_handle->src_fd = xopen(optarg, O_RDONLY);
}
break; break;
case 'O': case 'O': /* To stdout */
extract_function |= extract_to_stdout; tar_handle->action_data = data_extract_to_stdout;
break; break;
case 'p': case 'p':
tar_handle->flags |= ARCHIVE_PRESERVE_DATE;
break; break;
case 'v': 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; break;
#ifdef CONFIG_FEATURE_TAR_GZIP #ifdef CONFIG_FEATURE_TAR_GZIP
case 'z': 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; break;
#endif #endif
default: 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 */ /* Setup an array of filenames to work with */
/* TODO: This is the same as in ar, seperate function ? */
while (optind < argc) { 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++; optind++;
} #ifdef CONFIG_FEATURE_TAR_EXCLUDE
if (extract_function & (extract_list | extract_all_to_fs)) { if (tar_handle->reject) {
if (dst_prefix == NULL) { tar_handle->filter = filter_accept_reject_list;
dst_prefix = xstrdup("./");
}
/* Setup the source of the tar data */
if (src_filename != NULL) {
src_stream = xfopen(src_filename, "r");
} else {
src_stream = stdin;
}
#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 } else
#endif /* CONFIG_FEATURE_TAR_GZIP */ #endif
uncompressed_stream = src_stream; tar_handle->filter = filter_accept_list;
}
if ((base_dir) && (chdir(base_dir))) {
perror_msg_and_die("Couldnt chdir");
}
/* 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 #ifdef CONFIG_FEATURE_TAR_CREATE
/* create an archive */ /* create an archive */
else if (untar_funct & untar_create) { if (tar_create == TRUE) {
int verboseFlag = FALSE; int verboseFlag = FALSE;
int gzipFlag = FALSE; int gzipFlag = FALSE;
#ifdef CONFIG_FEATURE_TAR_GZIP # ifdef CONFIG_FEATURE_TAR_GZIP
if (untar_funct & untar_unzip) if (get_header_ptr == get_header_tar_gz) {
gzipFlag = TRUE; gzipFlag = TRUE;
}
#endif /* CONFIG_FEATURE_TAR_GZIP */ # endif
if (extract_function & extract_verbose_list) if (tar_handle->action_header == header_verbose_list) {
verboseFlag = TRUE; verboseFlag = TRUE;
writeTarFile(src_filename, verboseFlag, include_list, exclude_list,
gzipFlag);
}
#endif /* CONFIG_FEATURE_TAR_CREATE */
/* Cleanups */
#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 */
#ifdef CONFIG_FEATURE_CLEAN_UP
if (src_filename) {
free(src_filename);
} }
writeTarFile(src_filename, verboseFlag, tar_handle->accept,
tar_handle->reject, gzipFlag);
} else
#endif #endif
return (EXIT_SUCCESS); #ifdef 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
close(tar_handle->src_fd);
#endif
return(EXIT_SUCCESS);
} }

View File

@ -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 <fcntl.h>
#include <getopt.h> #include <getopt.h>
#include <stdlib.h> #include <stdlib.h>
@ -28,67 +32,213 @@
#include "unarchive.h" #include "unarchive.h"
#include "busybox.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) extern int unzip_main(int argc, char **argv)
{ {
FILE *src_stream; union {
int extract_function = extract_all_to_fs | extract_create_leading_dirs; unsigned char raw[26];
char **extract_names = NULL; struct {
char **exclude_names = NULL; unsigned short version; /* 0-1 */
int opt = 0; unsigned short flags; /* 2-3 */
int num_of_entries = 0; unsigned short method; /* 4-5 */
int exclude = 0; unsigned short modtime; /* 6-7 */
char *outdir = "./"; unsigned short moddate; /* 8-9 */
FILE *msgout = stdout; 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;
while ((opt = getopt(argc, argv, "lnopqxd:")) != -1) { archive_handle_t *archive_handle;
unsigned int total_size = 0;
unsigned int total_entries = 0;
char *base_dir = NULL;
int opt = 0;
/* 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) { switch (opt) {
case 'l': case 'l': /* list */
extract_function |= extract_verbose_list; archive_handle->action_header = header_verbose_list_unzip;
extract_function ^= extract_all_to_fs; archive_handle->action_data = data_skip;
break; break;
case 'n': case 'n': /* never overwright existing files */
break; break;
case 'o': case 'o':
extract_function |= extract_unconditional; archive_handle->flags = ARCHIVE_EXTRACT_UNCONDITIONAL;
break; break;
case 'p': case 'p': /* extract files to stdout */
extract_function |= extract_to_stdout; archive_handle->action_data = data_extract_to_stdout;
extract_function ^= extract_all_to_fs;
/* FALLTHROUGH */
case 'q':
msgout = xfopen("/dev/null", "w");
break; break;
case 'd': case 'q': /* Extract files quietly */
outdir = xstrdup(optarg); archive_handle->action_header = header_skip;
strcat(outdir, "/");
break; break;
case 'x': case 'd': /* Extract files to specified base directory*/
exclude = 1; base_dir = optarg;
break; 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(); show_usage();
} }
if (*argv[optind] == '-') src_stream = stdin; printf("Archive: %s\n", argv[optind]);
else src_stream = xfopen(argv[optind++], "r"); if (archive_handle->action_header == header_verbose_list_unzip) {
printf(" Length Date Time Name\n");
printf(" -------- ---- ---- ----\n");
}
if (*argv[optind] == '-') {
archive_handle->src_fd = fileno(stdin);
} else {
archive_handle->src_fd = xopen(argv[optind++], O_RDONLY);
}
if ((base_dir) && (chdir(base_dir))) {
perror_msg_and_die("Couldnt chdir");
}
while (optind < argc) { while (optind < argc) {
if (exclude) { archive_handle->filter = filter_accept_list;
exclude_names = xrealloc(exclude_names, sizeof(char *) * (num_of_entries + 2)); archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]);
exclude_names[num_of_entries] = xstrdup(argv[optind]);
} else {
extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
extract_names[num_of_entries] = xstrdup(argv[optind]);
}
num_of_entries++;
if (exclude) exclude_names[num_of_entries] = NULL;
else extract_names[num_of_entries] = NULL;
optind++; optind++;
} }
unarchive(src_stream, msgout, &get_header_zip, extract_function, outdir, extract_names, exclude_names); while (1) {
return EXIT_SUCCESS; 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);
} }

View File

@ -48,10 +48,6 @@
# include "sha1.h" # include "sha1.h"
#endif #endif
/* Compatability with ANSI C */
#ifndef inline
# define inline
#endif
#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) #if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
/* libc5 doesn't define socklen_t */ /* 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 BUF_SIZE 8192
#define EXPAND_ALLOC 1024 #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. */ /* Macros for min/max. */
#ifndef MIN #ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b)) #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)) #define MAX(a,b) (((a)>(b))?(a):(b))
#endif #endif
extern void show_usage(void) __attribute__ ((noreturn)); extern void show_usage(void) __attribute__ ((noreturn));
extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); 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))); 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); int read_package_field(const char *package_buffer, char **field_name, char **field_value);
char *fgets_str(FILE *file, const char *terminating_string); char *fgets_str(FILE *file, const char *terminating_string);
extern int inflate(FILE *in, FILE *out); extern int inflate(int in, int 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 struct hostent *xgethostbyname(const char *name); extern struct hostent *xgethostbyname(const char *name);
extern struct hostent *xgethostbyname2(const char *name, int af); 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 struct spwd *pwd_to_spwd(const struct passwd *pw);
extern int obscure(const char *old, const char *newval, const struct passwd *pwdp); 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__ */ #endif /* __LIBCONFIG_H__ */

View File

@ -1,21 +1,19 @@
#include <stdio.h> /* for FILE */ #ifndef __UNARCHIVE_H__
#include <unistd.h> /* for off_t */ #define __UNARCHIVE_H__
enum extract_functions_e { #define ARCHIVE_PRESERVE_DATE 1
extract_verbose_list = 1, #define ARCHIVE_CREATE_LEADING_DIRS 2
extract_list = 2, #define ARCHIVE_EXTRACT_UNCONDITIONAL 4
extract_one_to_buffer = 4, #define ARCHIVE_EXTRACT_QUIET 8
extract_to_stdout = 8,
extract_all_to_fs = 16, #include <sys/types.h>
extract_preserve_date = 32,
extract_data_tar_gz = 64, typedef struct gunzip_s {
extract_control_tar_gz = 128, unsigned short buffer_count;
extract_unzip_only = 256, unsigned char *buffer;
extract_unconditional = 512, unsigned int crc;
extract_create_leading_dirs = 1024, unsigned int count;
extract_quiet = 2048, } gunzip_t;
extract_exclude_list = 4096
};
typedef struct file_headers_s { typedef struct file_headers_s {
char *name; char *name;
@ -26,23 +24,70 @@ typedef struct file_headers_s {
mode_t mode; mode_t mode;
time_t mtime; time_t mtime;
dev_t device; dev_t device;
int (*extract_func) (FILE *, FILE *);
} file_header_t; } file_header_t;
file_header_t *get_header_ar(FILE * in_file); typedef struct llist_s {
file_header_t *get_header_cpio(FILE * src_stream); const char *data;
file_header_t *get_header_tar(FILE * tar_stream); const struct llist_s *link;
file_header_t *get_header_zip(FILE * zip_stream); } llist_t;
void seek_sub_file(FILE * src_stream, const int count); 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;
extern off_t archive_offset; /* Contains the processed header entry */
file_header_t *file_header;
char *unarchive(FILE * src_stream, FILE * out_stream, /* process the header component, e.g. tar -t */
file_header_t * (*get_headers) (FILE *), void (*action_header)(const file_header_t *);
const int extract_function, const char *prefix,
char **include_name, char **exclude_name);
char *deb_extract(const char *package_filename, FILE * out_stream, /* process the data componenet, e.g. extract to filesystem */
const int extract_function, const char *prefix, void (*action_data)(struct archive_handle_s *);
const char *filename); 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);
extern void check_header_gzip(int src_fd);
extern void check_trailer_gzip(int src_fd);
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);
//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);
#endif

View File

@ -28,20 +28,22 @@ LIBBB_SRC:= \
copy_file_chunk.c dump.c libc5.c device_open.c error_msg.c \ 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 \ 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 \ 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 \ get_last_path_component.c get_line_from_file.c \
isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \ human_readable.c isdirectory.c kernel_version.c loop.c \
mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \ mode_string.c module_syscalls.c mtab.c mtab_file.c my_getgrnam.c \
my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \ my_getgrgid.c my_getpwnam.c my_getpwnamegid.c my_getpwuid.c \
print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \ parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \
safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \ print_file.c process_escape_sequence.c read_package_field.c \
trim.c unzip.c uncompress.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c \ recursive_action.c safe_read.c safe_strncpy.c syscalls.c \
xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ syslog_msg_with_name.c time_string.c trim.c unzip.c uncompress.c \
copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ vdprintf.c verror_msg.c vperror_msg.c wfopen.c xgetcwd.c xreadlink.c \
dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ xregcomp.c interface.c remove_file.c last_char_is.c copyfd.c \
simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \ vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
correct_password.c change_identity.c setup_environment.c run_shell.c \ dirname.c make_directory.c create_icmp_socket.c u_signal_names.c \
pw_encrypt.c restricted_shell.c xgethostbyname2.c create_icmp6_socket.c \ arith.c simplify_path.c inet_common.c inode_hash.c obscure.c \
xconnect.c bb_asprintf.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)) LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC))

File diff suppressed because it is too large Load Diff

View File

@ -19,10 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include "libbb.h" #include "libbb.h"
@ -85,6 +88,59 @@ FILE *xfopen(const char *path, const char *mode)
return fp; 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()... */ /* Stupid gcc always includes its own builtin strlen()... */
#undef strlen #undef strlen
size_t xstrlen(const char *string) size_t xstrlen(const char *string)