/*
* Copyright (C) 2000 by Glenn McGrath
* Copyright (C) 2001 by Laurence Anderson
- *
+ *
* Based on previous work by busybox developers and others.
*
* This program is free software; you can redistribute it and/or modify
char buf[SEEK_BUF];
while (len) {
- cc = fread(buf, sizeof(buf[0]),
- len > SEEK_BUF ? SEEK_BUF : len,
+ cc = fread(buf, sizeof(buf[0]),
+ len > SEEK_BUF ? SEEK_BUF : len,
fd);
total += cc;
}
static void
-seek_sub_file(FILE *src_stream, const int count)
+seek_sub_file(FILE *fd, const int count)
{
- /* Try to fseek as faster */
archive_offset += count;
- seek_by_read(src_stream, count);
+
+ /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the
+ * stream at an undefined location.
+ */
+ seek_by_read(fd, count);
+
return;
}
-/* Extract the data postioned at src_stream to either filesystem, stdout or
- * buffer depending on the value of 'function' which is defined in libbb.h
+/* Extract the data postioned at src_stream to either filesystem, stdout or
+ * buffer depending on the value of 'function' which is defined in libbb.h
*
* prefix doesnt have to be just a directory, it may prefix the filename as well.
*
- * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
- * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
+ * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
+ * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
* 'dpkg.' as their prefix
*
* For this reason if prefix does point to a dir then it must end with a
- * trailing '/' or else the last dir will be assumed to be the file prefix
+ * trailing '/' or else the last dir will be assumed to be the file prefix
*/
static char *
extract_archive(FILE *src_stream, FILE *out_stream,
*err = 0;
- /* prefix doesnt have to be a proper path it may prepend
+ /* prefix doesnt have to be a proper path it may prepend
* the filename as well */
if (prefix != NULL) {
/* strip leading '/' in filename to extract as prefix may not be dir */
if (function & extract_to_stream) {
if (S_ISREG(file_entry->mode)) {
- *err = copy_file_chunk(src_stream, out_stream, file_entry->size);
+ *err = copy_file_chunk(src_stream, out_stream, file_entry->size);
archive_offset += file_entry->size;
}
}
- else if (function & extract_one_to_buffer) {
+ else if (function & extract_one_to_buffer) {
if (S_ISREG(file_entry->mode)) {
buffer = (char *) xmalloc(file_entry->size + 1);
fread(buffer, 1, file_entry->size, src_stream);
goto cleanup;
}
archive_offset += file_entry->size;
- copy_file_chunk(src_stream, dst_stream, file_entry->size);
+ *err = copy_file_chunk(src_stream, dst_stream, file_entry->size);
fclose(dst_stream);
}
break;
if (mkdir(full_name, file_entry->mode) < 0) {
if ((function & extract_quiet) != extract_quiet) {
*err = -1;
- perror_msg("%s: %s", __FUNCTION__, full_name);
+ perror_msg("Cannot make dir %s", full_name);
}
}
}
}
- /* Changing a symlink's properties normally changes the properties of the
+ /* Changing a symlink's properties normally changes the properties of the
* file pointed to, so dont try and change the date or mode, lchown does
* does the right thing, but isnt available in older versions of libc */
if (S_ISLNK(file_entry->mode)) {
chmod(full_name, file_entry->mode);
}
} else {
- /* If we arent extracting data we have to skip it,
+ /* If we arent extracting data we have to skip it,
* if data size is 0 then then just do it anyway
* (saves testing for it) */
seek_sub_file(src_stream, file_entry->size);
/* extract_list and extract_verbose_list can be used in conjunction
* with one of the above four extraction functions, so do this seperately */
if (function & extract_verbose_list) {
- fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode),
+ fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode),
file_entry->uid, file_entry->gid,
(int) file_entry->size, time_string(file_entry->mtime));
}
buffer = extract_archive(src_stream, out_stream,
file_entry, extract_function,
prefix, err);
+ *err = 0; /* XXX: ignore extraction errors */
if (*err) {
free_headers(file_entry);
break;
/* 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->name[strcspn(typed->name, " /")]='\0';
- /* convert the rest of the now valid char header to its typed struct */
+ /* convert the rest of the now valid char header to its typed struct */
parse_mode(ar.formated.mode, &typed->mode);
typed->mtime = atoi(ar.formated.date);
typed->uid = atoi(ar.formated.uid);
}
if (fread(tar.raw, 1, 512, tar_stream) != 512) {
- /* Unfortunatly its common for tar files to have all sorts of
+ /* Unfortunately its common for tar files to have all sorts of
* trailing garbage, fail silently */
// error_msg("Couldnt read header");
return(NULL);
if (longname) {
tar_entry->name = longname;
longname = NULL;
- }
- else if (linkname) {
- tar_entry->name = linkname;
- linkname = NULL;
} else
#endif
{
tar_entry->gid = strtol(tar.formated.gid, NULL, 8);
tar_entry->size = strtol(tar.formated.size, NULL, 8);
tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
- tar_entry->link_name = *tar.formated.linkname != '\0' ? xstrndup(tar.formated.linkname, 100) : NULL;
+#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+ if (linkname) {
+ tar_entry->link_name = linkname;
+ linkname = NULL;
+ } else
+#endif
+ {
+ tar_entry->link_name = *tar.formated.linkname != '\0' ?
+ xstrndup(tar.formated.linkname, 100) : NULL;
+ }
tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
strtol(tar.formated.devminor, NULL, 8);
# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
if (last_char_is(tar_entry->name, '/')) {
tar_entry->mode |= S_IFDIR;
- } else
+ } else
# endif
tar_entry->mode |= S_IFREG;
break;
linkname[tar_entry->size] = '\0';
archive_offset += tar_entry->size;
- tar_entry->name = linkname;
return(get_header_tar(tar_stream));
}
case 'D':
}
char *
-deb_extract(const char *package_filename, FILE *out_stream,
+deb_extract(const char *package_filename, FILE *out_stream,
const int extract_function, const char *prefix,
const char *filename, int *err)
{
char *output_buffer = NULL;
char *ared_file = NULL;
char ar_magic[8];
+ int gz_err;
*err = 0;
file_list[0] = filename;
file_list[1] = NULL;
}
-
+
if (extract_function & extract_control_tar_gz) {
ared_file = "control.tar.gz";
}
- else if (extract_function & extract_data_tar_gz) {
+ else if (extract_function & extract_data_tar_gz) {
ared_file = "data.tar.gz";
} else {
- fprintf(stderr, "no file specified to extract -- extract_function=%x\n", extract_function);
+ opkg_msg(ERROR, "Internal error: extract_function=%x\n",
+ extract_function);
*err = -1;
goto cleanup;
}
/* open a stream of decompressed data */
uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
if (uncompressed_stream == NULL) {
- printf("%s: %d\n", __FUNCTION__, __LINE__);
*err = -1;
goto cleanup;
}
extract_function, prefix,
file_list, err);
fclose(uncompressed_stream);
- gz_close(gunzip_pid);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
free_header_ar(ar_header);
break;
}
- seek_sub_file(deb_stream, ar_header->size);
+ if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ free_header_ar(ar_header);
+ goto cleanup;
+ }
free_header_ar(ar_header);
}
goto cleanup;
FILE *unzipped_opkg_stream;
file_header_t *tar_header;
archive_offset = 0;
- fseek(deb_stream, 0, SEEK_SET);
+ if (fseek(deb_stream, 0, SEEK_SET) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ goto cleanup;
+ }
unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid);
if (unzipped_opkg_stream == NULL) {
*err = -1;
goto cleanup;
}
-
+
/* walk through outer tar file to find ared_file */
while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) {
int name_offset = 0;
}
archive_offset = 0;
- output_buffer = unarchive(uncompressed_stream,
- out_stream,
+ output_buffer = unarchive(uncompressed_stream,
+ out_stream,
get_header_tar,
free_header_tar,
- extract_function,
- prefix,
+ extract_function,
+ prefix,
file_list,
err);
free_header_tar(tar_header);
fclose(uncompressed_stream);
- gz_close(gunzip_pid);
- free_header_tar(tar_header);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
break;
}
seek_sub_file(unzipped_opkg_stream, tar_header->size);
free_header_tar(tar_header);
}
fclose(unzipped_opkg_stream);
- gz_close(unzipped_opkg_pid);
+ gz_err = gz_close(unzipped_opkg_pid);
+ if (gz_err)
+ *err = -1;
goto cleanup;
} else {