Remove trailing whitespace. Sorry if this breaks your patches.
[project/opkg-lede.git] / libbb / unarchive.c
index 3108f37bae03b2a55bd915451ec302bca86b5c52..0e820c8646a0946a3c7814e7731ca3e7d796d806 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  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
@@ -47,8 +47,8 @@ seek_by_read(FILE* fd, size_t len)
         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;
@@ -61,26 +61,30 @@ seek_by_read(FILE* fd, size_t len)
 }
 
 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,
@@ -96,7 +100,7 @@ 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 */
@@ -125,11 +129,11 @@ extract_archive(FILE *src_stream, FILE *out_stream,
 
        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);
@@ -185,7 +189,7 @@ extract_archive(FILE *src_stream, FILE *out_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;
@@ -194,7 +198,7 @@ extract_archive(FILE *src_stream, FILE *out_stream,
                                        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);
                                                }
                                        }
                                }
@@ -226,7 +230,7 @@ extract_archive(FILE *src_stream, FILE *out_stream,
 
                }
 
-               /* 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)) {
@@ -243,7 +247,7 @@ extract_archive(FILE *src_stream, FILE *out_stream,
                        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);
@@ -252,7 +256,7 @@ extract_archive(FILE *src_stream, FILE *out_stream,
        /* 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));
        }
@@ -313,6 +317,7 @@ unarchive(FILE *src_stream, FILE *out_stream,
                        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;
@@ -368,7 +373,7 @@ get_header_ar(FILE *src_stream)
                /* 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);
@@ -404,7 +409,7 @@ get_header_ar(FILE *src_stream)
        }
        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);
@@ -461,7 +466,7 @@ get_header_tar(FILE *tar_stream)
        }
 
        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);
@@ -500,10 +505,6 @@ get_header_tar(FILE *tar_stream)
         if (longname) {
                 tar_entry->name = longname;
                 longname = NULL;
-        }
-        else if (linkname) {
-                tar_entry->name = linkname;
-                linkname = NULL;
         } else
 #endif
         {
@@ -529,7 +530,16 @@ get_header_tar(FILE *tar_stream)
        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);
 
@@ -545,7 +555,7 @@ get_header_tar(FILE *tar_stream)
 # 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;
@@ -581,7 +591,6 @@ get_header_tar(FILE *tar_stream)
                        linkname[tar_entry->size] = '\0';
                        archive_offset += tar_entry->size;
 
-                       tar_entry->name = linkname;
                        return(get_header_tar(tar_stream));
                }
        case 'D':
@@ -614,7 +623,7 @@ free_header_tar(file_header_t *tar_entry)
 }
 
 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)
 {
@@ -624,6 +633,7 @@ deb_extract(const char *package_filename, FILE *out_stream,
        char *output_buffer = NULL;
        char *ared_file = NULL;
        char ar_magic[8];
+       int gz_err;
 
        *err = 0;
 
@@ -632,14 +642,15 @@ deb_extract(const char *package_filename, FILE *out_stream,
                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;
         }
@@ -666,7 +677,6 @@ deb_extract(const char *package_filename, FILE *out_stream,
                                /* 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;
                                }
@@ -678,11 +688,18 @@ deb_extract(const char *package_filename, FILE *out_stream,
                                                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;
@@ -692,13 +709,17 @@ deb_extract(const char *package_filename, FILE *out_stream,
                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;
@@ -715,26 +736,29 @@ deb_extract(const char *package_filename, FILE *out_stream,
                                }
                                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 {