New common unarchive code.
This commit is contained in:
parent
ecfa290cfd
commit
7ca04f328e
123
archival/ar.c
123
archival/ar.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
220
archival/cpio.c
220
archival/cpio.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
15
archival/libunarchive/add_to_list.c
Normal file
15
archival/libunarchive/add_to_list.c
Normal 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);
|
||||||
|
}
|
75
archival/libunarchive/check_header_gzip.c
Normal file
75
archival/libunarchive/check_header_gzip.c
Normal 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;
|
||||||
|
}
|
62
archival/libunarchive/check_trailer_gzip.c
Normal file
62
archival/libunarchive/check_trailer_gzip.c
Normal 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
archival/libunarchive/copy_file_chunk_fd.c
Normal file
33
archival/libunarchive/copy_file_chunk_fd.c
Normal 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;
|
||||||
|
}
|
13
archival/libunarchive/data_align.c
Normal file
13
archival/libunarchive/data_align.c
Normal 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);
|
||||||
|
}
|
76
archival/libunarchive/data_extract_all.c
Normal file
76
archival/libunarchive/data_extract_all.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
8
archival/libunarchive/data_extract_to_stdout.c
Normal file
8
archival/libunarchive/data_extract_to_stdout.c
Normal 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);
|
||||||
|
}
|
27
archival/libunarchive/data_skip.c
Normal file
27
archival/libunarchive/data_skip.c
Normal 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
10
archival/libunarchive/filter_accept_all.c
Normal file
10
archival/libunarchive/filter_accept_all.c
Normal 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);
|
||||||
|
}
|
16
archival/libunarchive/filter_accept_list.c
Normal file
16
archival/libunarchive/filter_accept_list.c
Normal 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);
|
||||||
|
}
|
34
archival/libunarchive/filter_accept_reject_list.c
Normal file
34
archival/libunarchive/filter_accept_reject_list.c
Normal 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);
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
73
archival/libunarchive/get_header_tar_gz.c
Normal file
73
archival/libunarchive/get_header_tar_gz.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
7
archival/libunarchive/header_list.c
Normal file
7
archival/libunarchive/header_list.c
Normal 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);
|
||||||
|
}
|
7
archival/libunarchive/header_skip.c
Normal file
7
archival/libunarchive/header_skip.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "unarchive.h"
|
||||||
|
|
||||||
|
extern void header_skip(const file_header_t *file_header)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
29
archival/libunarchive/header_verbose_list.c
Normal file
29
archival/libunarchive/header_verbose_list.c
Normal 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("");
|
||||||
|
}
|
18
archival/libunarchive/init_handle.c
Normal file
18
archival/libunarchive/init_handle.c
Normal 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);
|
||||||
|
}
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
archival/libunarchive/unpack_ar_archive.c
Normal file
34
archival/libunarchive/unpack_ar_archive.c
Normal 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
@ -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;
|
||||||
}
|
}
|
||||||
|
253
archival/tar.c
253
archival/tar.c
@ -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);
|
||||||
}
|
}
|
||||||
|
232
archival/unzip.c
232
archival/unzip.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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__ */
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
|
||||||
|
751
libbb/unzip.c
751
libbb/unzip.c
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user