12104a77dSRoy Oursler /**********************************************************************
22104a77dSRoy Oursler Copyright(c) 2011-2018 Intel Corporation All rights reserved.
32104a77dSRoy Oursler
42104a77dSRoy Oursler Redistribution and use in source and binary forms, with or without
52104a77dSRoy Oursler modification, are permitted provided that the following conditions
62104a77dSRoy Oursler are met:
72104a77dSRoy Oursler * Redistributions of source code must retain the above copyright
82104a77dSRoy Oursler notice, this list of conditions and the following disclaimer.
92104a77dSRoy Oursler * Redistributions in binary form must reproduce the above copyright
102104a77dSRoy Oursler notice, this list of conditions and the following disclaimer in
112104a77dSRoy Oursler the documentation and/or other materials provided with the
122104a77dSRoy Oursler distribution.
132104a77dSRoy Oursler * Neither the name of Intel Corporation nor the names of its
142104a77dSRoy Oursler contributors may be used to endorse or promote products derived
152104a77dSRoy Oursler from this software without specific prior written permission.
162104a77dSRoy Oursler
172104a77dSRoy Oursler THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182104a77dSRoy Oursler "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192104a77dSRoy Oursler LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202104a77dSRoy Oursler A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212104a77dSRoy Oursler OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222104a77dSRoy Oursler SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232104a77dSRoy Oursler LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242104a77dSRoy Oursler DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252104a77dSRoy Oursler THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262104a77dSRoy Oursler (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272104a77dSRoy Oursler OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282104a77dSRoy Oursler **********************************************************************/
292104a77dSRoy Oursler
302104a77dSRoy Oursler #define _FILE_OFFSET_BITS 64
312104a77dSRoy Oursler #include <stdio.h>
322104a77dSRoy Oursler #include <stdlib.h>
332104a77dSRoy Oursler #include <assert.h>
342104a77dSRoy Oursler #include <string.h>
352104a77dSRoy Oursler #include <getopt.h>
362104a77dSRoy Oursler #include <sys/stat.h>
372104a77dSRoy Oursler #include <utime.h>
382104a77dSRoy Oursler #include <unistd.h>
392104a77dSRoy Oursler #include <stdbool.h>
402104a77dSRoy Oursler #include <stdarg.h>
41722144eeSTomasz Kantecki #include <errno.h>
422104a77dSRoy Oursler #include "igzip_lib.h" /* Normally you use isa-l.h instead for external programs */
432104a77dSRoy Oursler
440a7e3167SGreg Tucker #if defined(HAVE_THREADS)
450a7e3167SGreg Tucker #include <pthread.h>
460a7e3167SGreg Tucker #include "crc.h"
470a7e3167SGreg Tucker #endif
480a7e3167SGreg Tucker
492104a77dSRoy Oursler #if !defined(VERSION)
502104a77dSRoy Oursler #if defined(ISAL_VERSION)
512104a77dSRoy Oursler #define VERSION ISAL_VERSION
522104a77dSRoy Oursler #else
532104a77dSRoy Oursler #define VERSION "unknown version"
542104a77dSRoy Oursler #endif
552104a77dSRoy Oursler #endif
562104a77dSRoy Oursler
572104a77dSRoy Oursler #define BAD_OPTION 1
582104a77dSRoy Oursler #define BAD_LEVEL 1
592104a77dSRoy Oursler #define FILE_EXISTS 0
602104a77dSRoy Oursler #define MALLOC_FAILED -1
612104a77dSRoy Oursler #define FILE_OPEN_ERROR -2
622104a77dSRoy Oursler #define FILE_READ_ERROR -3
632104a77dSRoy Oursler #define FILE_WRITE_ERROR -4
642104a77dSRoy Oursler
652104a77dSRoy Oursler #define BUF_SIZE 1024
662104a77dSRoy Oursler #define BLOCK_SIZE (1024 * 1024)
672104a77dSRoy Oursler
68cd5de57fSRoy Oursler #define MAX_FILEPATH_BUF 4096
69cd5de57fSRoy Oursler
702104a77dSRoy Oursler #define UNIX 3
712104a77dSRoy Oursler
72cd5de57fSRoy Oursler #define NAME_DEFAULT 0
73cd5de57fSRoy Oursler #define NO_NAME 1
74cd5de57fSRoy Oursler #define YES_NAME 2
75cd5de57fSRoy Oursler
767177ff99SRoy Oursler #define NO_TEST 0
777177ff99SRoy Oursler #define TEST 1
787177ff99SRoy Oursler
792104a77dSRoy Oursler #define LEVEL_DEFAULT 2
802104a77dSRoy Oursler #define DEFAULT_SUFFIX_LEN 3
812104a77dSRoy Oursler char *default_suffixes[] = { ".gz", ".z" };
822104a77dSRoy Oursler int default_suffixes_lens[] = { 3, 2 };
832104a77dSRoy Oursler
842104a77dSRoy Oursler char stdin_file_name[] = "-";
852104a77dSRoy Oursler int stdin_file_name_len = 1;
862104a77dSRoy Oursler
87*cf610527SMarcel Cornu enum compression_modes { COMPRESS_MODE, DECOMPRESS_MODE };
882104a77dSRoy Oursler
89*cf610527SMarcel Cornu enum long_only_opt_val { RM };
902104a77dSRoy Oursler
91*cf610527SMarcel Cornu enum log_types { INFORM, WARN, ERROR, VERBOSE };
922104a77dSRoy Oursler
932104a77dSRoy Oursler int level_size_buf[10] = {
942104a77dSRoy Oursler #ifdef ISAL_DEF_LVL0_DEFAULT
952104a77dSRoy Oursler ISAL_DEF_LVL0_DEFAULT,
962104a77dSRoy Oursler #else
972104a77dSRoy Oursler 0,
982104a77dSRoy Oursler #endif
992104a77dSRoy Oursler #ifdef ISAL_DEF_LVL1_DEFAULT
1002104a77dSRoy Oursler ISAL_DEF_LVL1_DEFAULT,
1012104a77dSRoy Oursler #else
1022104a77dSRoy Oursler 0,
1032104a77dSRoy Oursler #endif
1042104a77dSRoy Oursler #ifdef ISAL_DEF_LVL2_DEFAULT
1052104a77dSRoy Oursler ISAL_DEF_LVL2_DEFAULT,
1062104a77dSRoy Oursler #else
1072104a77dSRoy Oursler 0,
1082104a77dSRoy Oursler #endif
1092104a77dSRoy Oursler #ifdef ISAL_DEF_LVL3_DEFAULT
1102104a77dSRoy Oursler ISAL_DEF_LVL3_DEFAULT,
1112104a77dSRoy Oursler #else
1122104a77dSRoy Oursler 0,
1132104a77dSRoy Oursler #endif
1142104a77dSRoy Oursler #ifdef ISAL_DEF_LVL4_DEFAULT
1152104a77dSRoy Oursler ISAL_DEF_LVL4_DEFAULT,
1162104a77dSRoy Oursler #else
1172104a77dSRoy Oursler 0,
1182104a77dSRoy Oursler #endif
1192104a77dSRoy Oursler #ifdef ISAL_DEF_LVL5_DEFAULT
1202104a77dSRoy Oursler ISAL_DEF_LVL5_DEFAULT,
1212104a77dSRoy Oursler #else
1222104a77dSRoy Oursler 0,
1232104a77dSRoy Oursler #endif
1242104a77dSRoy Oursler #ifdef ISAL_DEF_LVL6_DEFAULT
1252104a77dSRoy Oursler ISAL_DEF_LVL6_DEFAULT,
1262104a77dSRoy Oursler #else
1272104a77dSRoy Oursler 0,
1282104a77dSRoy Oursler #endif
1292104a77dSRoy Oursler #ifdef ISAL_DEF_LVL7_DEFAULT
1302104a77dSRoy Oursler ISAL_DEF_LVL7_DEFAULT,
1312104a77dSRoy Oursler #else
1322104a77dSRoy Oursler 0,
1332104a77dSRoy Oursler #endif
1342104a77dSRoy Oursler #ifdef ISAL_DEF_LVL8_DEFAULT
1352104a77dSRoy Oursler ISAL_DEF_LVL8_DEFAULT,
1362104a77dSRoy Oursler #else
1372104a77dSRoy Oursler 0,
1382104a77dSRoy Oursler #endif
1392104a77dSRoy Oursler #ifdef ISAL_DEF_LVL9_DEFAULT
1402104a77dSRoy Oursler ISAL_DEF_LVL9_DEFAULT,
1412104a77dSRoy Oursler #else
1422104a77dSRoy Oursler 0,
1432104a77dSRoy Oursler #endif
1442104a77dSRoy Oursler };
1452104a77dSRoy Oursler
1462104a77dSRoy Oursler struct cli_options {
1472104a77dSRoy Oursler char *infile_name;
1482104a77dSRoy Oursler size_t infile_name_len;
1492104a77dSRoy Oursler char *outfile_name;
1502104a77dSRoy Oursler size_t outfile_name_len;
1512104a77dSRoy Oursler char *suffix;
1522104a77dSRoy Oursler size_t suffix_len;
1532104a77dSRoy Oursler int level;
1542104a77dSRoy Oursler int mode;
1552104a77dSRoy Oursler int use_stdout;
1562104a77dSRoy Oursler int remove;
1572104a77dSRoy Oursler int force;
1582104a77dSRoy Oursler int quiet_level;
1592104a77dSRoy Oursler int verbose_level;
160cd5de57fSRoy Oursler int name;
1617177ff99SRoy Oursler int test;
1620a7e3167SGreg Tucker int threads;
1630a7e3167SGreg Tucker uint8_t *in_buf;
1640a7e3167SGreg Tucker uint8_t *out_buf;
1650a7e3167SGreg Tucker uint8_t *level_buf;
1660a7e3167SGreg Tucker size_t in_buf_size;
1670a7e3167SGreg Tucker size_t out_buf_size;
1680a7e3167SGreg Tucker size_t level_buf_size;
1692104a77dSRoy Oursler };
1702104a77dSRoy Oursler
1712104a77dSRoy Oursler struct cli_options global_options;
1722104a77dSRoy Oursler
173*cf610527SMarcel Cornu void
init_options(struct cli_options * options)174*cf610527SMarcel Cornu init_options(struct cli_options *options)
1752104a77dSRoy Oursler {
1762104a77dSRoy Oursler options->infile_name = NULL;
1772104a77dSRoy Oursler options->infile_name_len = 0;
1782104a77dSRoy Oursler options->outfile_name = NULL;
1792104a77dSRoy Oursler options->outfile_name_len = 0;
1802104a77dSRoy Oursler options->suffix = NULL;
1812104a77dSRoy Oursler options->suffix_len = 0;
1822104a77dSRoy Oursler options->level = LEVEL_DEFAULT;
1832104a77dSRoy Oursler options->mode = COMPRESS_MODE;
1842104a77dSRoy Oursler options->use_stdout = false;
1852104a77dSRoy Oursler options->remove = false;
1862104a77dSRoy Oursler options->force = false;
1872104a77dSRoy Oursler options->quiet_level = 0;
1882104a77dSRoy Oursler options->verbose_level = 0;
189cd5de57fSRoy Oursler options->name = NAME_DEFAULT;
1907177ff99SRoy Oursler options->test = NO_TEST;
1910a7e3167SGreg Tucker options->in_buf = NULL;
1920a7e3167SGreg Tucker options->out_buf = NULL;
1930a7e3167SGreg Tucker options->level_buf = NULL;
1940a7e3167SGreg Tucker options->in_buf_size = 0;
1950a7e3167SGreg Tucker options->out_buf_size = 0;
1960a7e3167SGreg Tucker options->level_buf_size = 0;
1970a7e3167SGreg Tucker options->threads = 1;
1982104a77dSRoy Oursler };
1992104a77dSRoy Oursler
200*cf610527SMarcel Cornu int
is_interactive(void)201*cf610527SMarcel Cornu is_interactive(void)
2022104a77dSRoy Oursler {
2032104a77dSRoy Oursler int ret;
2042104a77dSRoy Oursler ret = !global_options.force && !global_options.quiet_level && isatty(fileno(stdin));
2052104a77dSRoy Oursler return ret;
2062104a77dSRoy Oursler }
2072104a77dSRoy Oursler
208*cf610527SMarcel Cornu size_t
get_filesize(FILE * fp)209*cf610527SMarcel Cornu get_filesize(FILE *fp)
2102104a77dSRoy Oursler {
2112104a77dSRoy Oursler size_t file_size;
2122104a77dSRoy Oursler fpos_t pos, pos_curr;
2132104a77dSRoy Oursler
2142104a77dSRoy Oursler fgetpos(fp, &pos_curr); /* Save current position */
2152104a77dSRoy Oursler #if defined(_WIN32) || defined(_WIN64)
2162104a77dSRoy Oursler _fseeki64(fp, 0, SEEK_END);
2172104a77dSRoy Oursler #else
2182104a77dSRoy Oursler fseeko(fp, 0, SEEK_END);
2192104a77dSRoy Oursler #endif
2202104a77dSRoy Oursler fgetpos(fp, &pos);
2212104a77dSRoy Oursler file_size = *(size_t *) &pos;
2222104a77dSRoy Oursler fsetpos(fp, &pos_curr); /* Restore position */
2232104a77dSRoy Oursler
2242104a77dSRoy Oursler return file_size;
2252104a77dSRoy Oursler }
2262104a77dSRoy Oursler
227*cf610527SMarcel Cornu int
get_posix_filetime(FILE * fp,uint32_t * time)228*cf610527SMarcel Cornu get_posix_filetime(FILE *fp, uint32_t *time)
2292104a77dSRoy Oursler {
2302104a77dSRoy Oursler struct stat file_stats;
231a139dd73STomasz Kantecki const int ret = fstat(fileno(fp), &file_stats);
232a139dd73STomasz Kantecki if (time != NULL && ret == 0)
233a139dd73STomasz Kantecki *time = file_stats.st_mtime;
234a139dd73STomasz Kantecki return ret;
2352104a77dSRoy Oursler }
2362104a77dSRoy Oursler
237*cf610527SMarcel Cornu uint32_t
set_filetime(char * file_name,uint32_t posix_time)238*cf610527SMarcel Cornu set_filetime(char *file_name, uint32_t posix_time)
2392104a77dSRoy Oursler {
2402104a77dSRoy Oursler struct utimbuf new_time;
2412104a77dSRoy Oursler new_time.actime = posix_time;
2422104a77dSRoy Oursler new_time.modtime = posix_time;
2432104a77dSRoy Oursler return utime(file_name, &new_time);
2442104a77dSRoy Oursler }
2452104a77dSRoy Oursler
246*cf610527SMarcel Cornu void
log_print(int log_type,char * format,...)247*cf610527SMarcel Cornu log_print(int log_type, char *format, ...)
2482104a77dSRoy Oursler {
2492104a77dSRoy Oursler va_list args;
2502104a77dSRoy Oursler va_start(args, format);
2512104a77dSRoy Oursler
2522104a77dSRoy Oursler switch (log_type) {
2532104a77dSRoy Oursler case INFORM:
2542104a77dSRoy Oursler vfprintf(stdout, format, args);
2552104a77dSRoy Oursler break;
2562104a77dSRoy Oursler case WARN:
2572104a77dSRoy Oursler if (global_options.quiet_level <= 0)
2582104a77dSRoy Oursler vfprintf(stderr, format, args);
2592104a77dSRoy Oursler break;
2602104a77dSRoy Oursler case ERROR:
2612104a77dSRoy Oursler if (global_options.quiet_level <= 1)
2622104a77dSRoy Oursler vfprintf(stderr, format, args);
2632104a77dSRoy Oursler break;
2642104a77dSRoy Oursler case VERBOSE:
2652104a77dSRoy Oursler if (global_options.verbose_level > 0)
2662104a77dSRoy Oursler vfprintf(stderr, format, args);
2672104a77dSRoy Oursler break;
2682104a77dSRoy Oursler }
2692104a77dSRoy Oursler
2702104a77dSRoy Oursler va_end(args);
2712104a77dSRoy Oursler }
2722104a77dSRoy Oursler
273*cf610527SMarcel Cornu int
usage(int exit_code)274*cf610527SMarcel Cornu usage(int exit_code)
2752104a77dSRoy Oursler {
2762104a77dSRoy Oursler int log_type = exit_code ? WARN : INFORM;
2772104a77dSRoy Oursler log_print(log_type,
278391db331SGreg Tucker "Usage: igzip [options] [infiles]\n\n"
279391db331SGreg Tucker "Options:\n"
2802104a77dSRoy Oursler " -h, --help help, print this message\n"
2812104a77dSRoy Oursler " -# use compression level # with 0 <= # <= %d\n"
2822104a77dSRoy Oursler " -o <file> output file\n"
2832104a77dSRoy Oursler " -c, --stdout write to stdout\n"
2842104a77dSRoy Oursler " -d, --decompress decompress file\n"
2852104a77dSRoy Oursler " -z, --compress compress file (default)\n"
286391db331SGreg Tucker " -f, --force overwrite output without prompting\n"
2872104a77dSRoy Oursler " --rm remove source files after successful (de)compression\n"
2882104a77dSRoy Oursler " -k, --keep keep source files (default)\n"
289391db331SGreg Tucker " -S, --suffix <.suf> suffix to use while (de)compressing\n"
290391db331SGreg Tucker " -V, --version show version number\n"
291391db331SGreg Tucker " -v, --verbose verbose mode\n"
292cd5de57fSRoy Oursler " -N, --name save/use file name and timestamp in compress/decompress\n"
293*cf610527SMarcel Cornu " -n, --no-name do not save/use file name and timestamp in "
294*cf610527SMarcel Cornu "compress/decompress\n"
2957177ff99SRoy Oursler " -t, --test test compressed file integrity\n"
2960a7e3167SGreg Tucker " -T, --threads <n> use n threads to compress if enabled\n"
297391db331SGreg Tucker " -q, --quiet suppress warnings\n\n"
298391db331SGreg Tucker "with no infile, or when infile is - , read standard input\n\n",
2992104a77dSRoy Oursler ISAL_DEF_MAX_LEVEL);
3002104a77dSRoy Oursler
3012104a77dSRoy Oursler exit(exit_code);
3022104a77dSRoy Oursler }
3032104a77dSRoy Oursler
304*cf610527SMarcel Cornu void
print_version(void)305*cf610527SMarcel Cornu print_version(void)
3062104a77dSRoy Oursler {
3072104a77dSRoy Oursler log_print(INFORM, "igzip command line interface %s\n", VERSION);
3082104a77dSRoy Oursler }
3092104a77dSRoy Oursler
310*cf610527SMarcel Cornu void *
malloc_safe(size_t size)311*cf610527SMarcel Cornu malloc_safe(size_t size)
3122104a77dSRoy Oursler {
3132104a77dSRoy Oursler void *ptr = NULL;
3142104a77dSRoy Oursler if (size == 0)
3152104a77dSRoy Oursler return ptr;
3162104a77dSRoy Oursler
3172104a77dSRoy Oursler ptr = malloc(size);
3182104a77dSRoy Oursler if (ptr == NULL) {
3192104a77dSRoy Oursler log_print(ERROR, "igzip: Failed to allocate memory\n");
3202104a77dSRoy Oursler exit(MALLOC_FAILED);
3212104a77dSRoy Oursler }
3222104a77dSRoy Oursler
3232104a77dSRoy Oursler return ptr;
3242104a77dSRoy Oursler }
3252104a77dSRoy Oursler
326*cf610527SMarcel Cornu FILE *
fopen_safe(const char * file_name,const char * mode)327*cf610527SMarcel Cornu fopen_safe(const char *file_name, const char *mode)
3282104a77dSRoy Oursler {
3292104a77dSRoy Oursler FILE *file;
3302104a77dSRoy Oursler
3312104a77dSRoy Oursler /* Assumes write mode always starts with w */
3322104a77dSRoy Oursler if (mode[0] == 'w') {
3332104a77dSRoy Oursler if (access(file_name, F_OK) == 0) {
334722144eeSTomasz Kantecki int answer = 0, tmp;
335722144eeSTomasz Kantecki
3362104a77dSRoy Oursler log_print(WARN, "igzip: %s already exists;", file_name);
3372104a77dSRoy Oursler if (is_interactive()) {
3382104a77dSRoy Oursler log_print(WARN, " do you wish to overwrite (y/n)?");
3392104a77dSRoy Oursler answer = getchar();
3402104a77dSRoy Oursler
3412104a77dSRoy Oursler tmp = answer;
3422104a77dSRoy Oursler while (tmp != '\n' && tmp != EOF)
3432104a77dSRoy Oursler tmp = getchar();
3442104a77dSRoy Oursler
3452104a77dSRoy Oursler if (answer != 'y' && answer != 'Y') {
3462104a77dSRoy Oursler log_print(WARN, " not overwritten\n");
3472104a77dSRoy Oursler return NULL;
3482104a77dSRoy Oursler }
3492104a77dSRoy Oursler } else if (!global_options.force) {
3502104a77dSRoy Oursler log_print(WARN, " not overwritten\n");
3512104a77dSRoy Oursler return NULL;
3522104a77dSRoy Oursler }
3532104a77dSRoy Oursler }
3542104a77dSRoy Oursler }
3552104a77dSRoy Oursler
3562104a77dSRoy Oursler file = fopen(file_name, mode);
3572104a77dSRoy Oursler if (!file) {
358722144eeSTomasz Kantecki const char *error_str = strerror(errno);
359722144eeSTomasz Kantecki
360722144eeSTomasz Kantecki log_print(ERROR, "igzip: Failed to open %s : %s\n", file_name, error_str);
3612104a77dSRoy Oursler return NULL;
3622104a77dSRoy Oursler }
3632104a77dSRoy Oursler
3642104a77dSRoy Oursler return file;
3652104a77dSRoy Oursler }
3662104a77dSRoy Oursler
367*cf610527SMarcel Cornu size_t
fread_safe(void * buf,size_t word_size,size_t buf_size,FILE * in,char * file_name)368*cf610527SMarcel Cornu fread_safe(void *buf, size_t word_size, size_t buf_size, FILE *in, char *file_name)
3692104a77dSRoy Oursler {
3702104a77dSRoy Oursler size_t read_size;
3712104a77dSRoy Oursler read_size = fread(buf, word_size, buf_size, in);
3722104a77dSRoy Oursler if (ferror(in)) {
373*cf610527SMarcel Cornu log_print(ERROR, "igzip: Error encountered while reading file %s\n", file_name);
3742104a77dSRoy Oursler exit(FILE_READ_ERROR);
3752104a77dSRoy Oursler }
3762104a77dSRoy Oursler return read_size;
3772104a77dSRoy Oursler }
3782104a77dSRoy Oursler
379*cf610527SMarcel Cornu size_t
fwrite_safe(void * buf,size_t word_size,size_t buf_size,FILE * out,char * file_name)380*cf610527SMarcel Cornu fwrite_safe(void *buf, size_t word_size, size_t buf_size, FILE *out, char *file_name)
3812104a77dSRoy Oursler {
3822104a77dSRoy Oursler size_t write_size;
3832104a77dSRoy Oursler write_size = fwrite(buf, word_size, buf_size, out);
3842104a77dSRoy Oursler if (ferror(out)) {
385*cf610527SMarcel Cornu log_print(ERROR, "igzip: Error encountered while writing to file %s\n", file_name);
3862104a77dSRoy Oursler exit(FILE_WRITE_ERROR);
3872104a77dSRoy Oursler }
3882104a77dSRoy Oursler return write_size;
3892104a77dSRoy Oursler }
3902104a77dSRoy Oursler
391*cf610527SMarcel Cornu void
open_in_file(FILE ** in,char * infile_name)392*cf610527SMarcel Cornu open_in_file(FILE **in, char *infile_name)
3932104a77dSRoy Oursler {
3942104a77dSRoy Oursler *in = NULL;
3952104a77dSRoy Oursler if (infile_name == NULL)
3962104a77dSRoy Oursler *in = stdin;
3972104a77dSRoy Oursler else
3982104a77dSRoy Oursler *in = fopen_safe(infile_name, "rb");
3996f3599c1SRoy Oursler }
4002104a77dSRoy Oursler
401*cf610527SMarcel Cornu void
open_out_file(FILE ** out,char * outfile_name)402*cf610527SMarcel Cornu open_out_file(FILE **out, char *outfile_name)
4036f3599c1SRoy Oursler {
4046f3599c1SRoy Oursler *out = NULL;
4052104a77dSRoy Oursler if (global_options.use_stdout)
4062104a77dSRoy Oursler *out = stdout;
4072104a77dSRoy Oursler else if (outfile_name != NULL)
4082104a77dSRoy Oursler *out = fopen_safe(outfile_name, "wb");
4092104a77dSRoy Oursler else if (!isatty(fileno(stdout)) || global_options.force)
4102104a77dSRoy Oursler *out = stdout;
4112104a77dSRoy Oursler else {
4122104a77dSRoy Oursler log_print(WARN, "igzip: No output location. Use -c to output to terminal\n");
4132104a77dSRoy Oursler exit(FILE_OPEN_ERROR);
4142104a77dSRoy Oursler }
4152104a77dSRoy Oursler }
4162104a77dSRoy Oursler
4170a7e3167SGreg Tucker #if defined(HAVE_THREADS)
4180a7e3167SGreg Tucker
4190a7e3167SGreg Tucker #define MAX_THREADS 8
4200a7e3167SGreg Tucker #define MAX_JOBQUEUE 16 /* must be a power of 2 */
4210a7e3167SGreg Tucker
422*cf610527SMarcel Cornu enum job_status { JOB_UNALLOCATED = 0, JOB_ALLOCATED, JOB_SUCCESS, JOB_FAIL };
4230a7e3167SGreg Tucker
4240a7e3167SGreg Tucker struct thread_job {
4250a7e3167SGreg Tucker uint8_t *next_in;
4260a7e3167SGreg Tucker uint32_t avail_in;
4270a7e3167SGreg Tucker uint8_t *next_out;
4280a7e3167SGreg Tucker uint32_t avail_out;
4290a7e3167SGreg Tucker uint32_t total_out;
4300a7e3167SGreg Tucker uint32_t type;
4310a7e3167SGreg Tucker uint32_t status;
4320a7e3167SGreg Tucker };
4330a7e3167SGreg Tucker struct thread_pool {
4340a7e3167SGreg Tucker pthread_t threads[MAX_THREADS];
4350a7e3167SGreg Tucker struct thread_job job[MAX_JOBQUEUE];
4360a7e3167SGreg Tucker pthread_mutex_t mutex;
4370a7e3167SGreg Tucker pthread_cond_t cond;
4380a7e3167SGreg Tucker int head;
4390a7e3167SGreg Tucker int tail;
4400a7e3167SGreg Tucker int queue;
4410a7e3167SGreg Tucker int shutdown;
4420a7e3167SGreg Tucker };
4430a7e3167SGreg Tucker
4440a7e3167SGreg Tucker // Globals for thread pool
4450a7e3167SGreg Tucker struct thread_pool pool;
4460a7e3167SGreg Tucker
447*cf610527SMarcel Cornu static inline int
pool_has_space(void)448*cf610527SMarcel Cornu pool_has_space(void)
4490a7e3167SGreg Tucker {
4500a7e3167SGreg Tucker return ((pool.head + 1) % MAX_JOBQUEUE) != pool.tail;
4510a7e3167SGreg Tucker }
4520a7e3167SGreg Tucker
453*cf610527SMarcel Cornu static inline int
pool_has_work(void)454*cf610527SMarcel Cornu pool_has_work(void)
4550a7e3167SGreg Tucker {
4560a7e3167SGreg Tucker return (pool.queue != pool.head);
4570a7e3167SGreg Tucker }
4580a7e3167SGreg Tucker
459*cf610527SMarcel Cornu int
pool_get_work(void)460*cf610527SMarcel Cornu pool_get_work(void)
4610a7e3167SGreg Tucker {
4620a7e3167SGreg Tucker assert(pool.queue != pool.head);
4630a7e3167SGreg Tucker pool.queue = (pool.queue + 1) % MAX_JOBQUEUE;
4640a7e3167SGreg Tucker return pool.queue;
4650a7e3167SGreg Tucker }
4660a7e3167SGreg Tucker
467*cf610527SMarcel Cornu int
pool_put_work(struct isal_zstream * stream)468*cf610527SMarcel Cornu pool_put_work(struct isal_zstream *stream)
4690a7e3167SGreg Tucker {
4700a7e3167SGreg Tucker pthread_mutex_lock(&pool.mutex);
4710a7e3167SGreg Tucker if (!pool_has_space() || pool.shutdown) {
4720a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
4730a7e3167SGreg Tucker return 1;
4740a7e3167SGreg Tucker }
4750a7e3167SGreg Tucker int idx = (pool.head + 1) % MAX_JOBQUEUE;
4760a7e3167SGreg Tucker pool.job[idx].next_in = stream->next_in;
4770a7e3167SGreg Tucker pool.job[idx].avail_in = stream->avail_in;
4780a7e3167SGreg Tucker pool.job[idx].next_out = stream->next_out;
4790a7e3167SGreg Tucker pool.job[idx].avail_out = stream->avail_out;
4800a7e3167SGreg Tucker pool.job[idx].status = JOB_ALLOCATED;
4810a7e3167SGreg Tucker pool.job[idx].type = stream->end_of_stream == 0 ? 0 : 1;
4820a7e3167SGreg Tucker pool.head = idx;
4830a7e3167SGreg Tucker pthread_cond_signal(&pool.cond);
4840a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
4850a7e3167SGreg Tucker return 0;
4860a7e3167SGreg Tucker }
4870a7e3167SGreg Tucker
488*cf610527SMarcel Cornu void *
thread_worker(void * none)489*cf610527SMarcel Cornu thread_worker(void *none)
4900a7e3167SGreg Tucker {
4910a7e3167SGreg Tucker struct isal_zstream wstream;
4920a7e3167SGreg Tucker int check;
4930a7e3167SGreg Tucker int work_idx;
4940a7e3167SGreg Tucker int level = global_options.level;
4950a7e3167SGreg Tucker int level_size = level_size_buf[level];
4960a7e3167SGreg Tucker uint8_t *level_buf = malloc_safe(level_size);
4970a7e3167SGreg Tucker log_print(VERBOSE, "Start worker\n");
4980a7e3167SGreg Tucker
4990a7e3167SGreg Tucker while (!pool.shutdown) {
5000a7e3167SGreg Tucker pthread_mutex_lock(&pool.mutex);
5010a7e3167SGreg Tucker while (!pool_has_work() && !pool.shutdown) {
5020a7e3167SGreg Tucker pthread_cond_wait(&pool.cond, &pool.mutex);
5030a7e3167SGreg Tucker }
5040a7e3167SGreg Tucker if (pool.shutdown) {
5050a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
5060a7e3167SGreg Tucker continue;
5070a7e3167SGreg Tucker }
5080a7e3167SGreg Tucker
5090a7e3167SGreg Tucker work_idx = pool_get_work();
5100a7e3167SGreg Tucker pthread_cond_signal(&pool.cond);
5110a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
5120a7e3167SGreg Tucker
5130a7e3167SGreg Tucker isal_deflate_stateless_init(&wstream);
5140a7e3167SGreg Tucker wstream.next_in = pool.job[work_idx].next_in;
5150a7e3167SGreg Tucker wstream.next_out = pool.job[work_idx].next_out;
5160a7e3167SGreg Tucker wstream.avail_in = pool.job[work_idx].avail_in;
5170a7e3167SGreg Tucker wstream.avail_out = pool.job[work_idx].avail_out;
5180a7e3167SGreg Tucker wstream.end_of_stream = pool.job[work_idx].type;
5190a7e3167SGreg Tucker wstream.flush = FULL_FLUSH;
5200a7e3167SGreg Tucker wstream.level = global_options.level;
5210a7e3167SGreg Tucker wstream.level_buf = level_buf;
5220a7e3167SGreg Tucker wstream.level_buf_size = level_size;
5230a7e3167SGreg Tucker
5240a7e3167SGreg Tucker check = isal_deflate_stateless(&wstream);
525*cf610527SMarcel Cornu log_print(VERBOSE, "Worker finished job %d, out=%d\n", work_idx, wstream.total_out);
5260a7e3167SGreg Tucker
5270a7e3167SGreg Tucker pool.job[work_idx].total_out = wstream.total_out;
5280a7e3167SGreg Tucker pool.job[work_idx].status = JOB_SUCCESS + check; // complete or fail
5290a7e3167SGreg Tucker if (check)
5300a7e3167SGreg Tucker break;
5310a7e3167SGreg Tucker }
5320a7e3167SGreg Tucker free(level_buf);
5330a7e3167SGreg Tucker log_print(VERBOSE, "Worker quit\n");
5340a7e3167SGreg Tucker pthread_exit(NULL);
5350a7e3167SGreg Tucker }
5360a7e3167SGreg Tucker
537*cf610527SMarcel Cornu int
pool_create(void)538*cf610527SMarcel Cornu pool_create(void)
5390a7e3167SGreg Tucker {
5400a7e3167SGreg Tucker int i;
5410a7e3167SGreg Tucker int nthreads = global_options.threads - 1;
5420a7e3167SGreg Tucker pool.head = 0;
5430a7e3167SGreg Tucker pool.tail = 0;
5440a7e3167SGreg Tucker pool.queue = 0;
5450a7e3167SGreg Tucker pool.shutdown = 0;
5460a7e3167SGreg Tucker for (i = 0; i < nthreads; i++)
5470a7e3167SGreg Tucker pthread_create(&pool.threads[i], NULL, thread_worker, NULL);
5480a7e3167SGreg Tucker
5490a7e3167SGreg Tucker log_print(VERBOSE, "Created %d pool threads\n", nthreads);
5500a7e3167SGreg Tucker return 0;
5510a7e3167SGreg Tucker }
5520a7e3167SGreg Tucker
553*cf610527SMarcel Cornu void
pool_quit(void)554*cf610527SMarcel Cornu pool_quit(void)
5550a7e3167SGreg Tucker {
5560a7e3167SGreg Tucker int i;
5570a7e3167SGreg Tucker pthread_mutex_lock(&pool.mutex);
5580a7e3167SGreg Tucker pool.shutdown = 1;
5590a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
5600a7e3167SGreg Tucker pthread_cond_broadcast(&pool.cond);
5610a7e3167SGreg Tucker for (i = 0; i < global_options.threads - 1; i++)
5620a7e3167SGreg Tucker pthread_join(pool.threads[i], NULL);
5630a7e3167SGreg Tucker log_print(VERBOSE, "Deleted %d pool threads\n", i);
5640a7e3167SGreg Tucker }
5650a7e3167SGreg Tucker
5660a7e3167SGreg Tucker #endif // defined(HAVE_THREADS)
5670a7e3167SGreg Tucker
568*cf610527SMarcel Cornu int
compress_file(void)569*cf610527SMarcel Cornu compress_file(void)
5702104a77dSRoy Oursler {
5712104a77dSRoy Oursler FILE *in = NULL, *out = NULL;
5722104a77dSRoy Oursler unsigned char *inbuf = NULL, *outbuf = NULL, *level_buf = NULL;
5732104a77dSRoy Oursler size_t inbuf_size, outbuf_size;
5742104a77dSRoy Oursler int level_size = 0;
5752104a77dSRoy Oursler struct isal_zstream stream;
5762104a77dSRoy Oursler struct isal_gzip_header gz_hdr;
5772104a77dSRoy Oursler int ret, success = 0;
5782104a77dSRoy Oursler
5791ba280faSGreg Tucker char *infile_name = global_options.infile_name;
5801ba280faSGreg Tucker char *outfile_name = global_options.outfile_name;
5811ba280faSGreg Tucker char *allocated_name = NULL;
5822104a77dSRoy Oursler char *suffix = global_options.suffix;
5832104a77dSRoy Oursler size_t infile_name_len = global_options.infile_name_len;
5846f3599c1SRoy Oursler size_t outfile_name_len = global_options.outfile_name_len;
5852104a77dSRoy Oursler size_t suffix_len = global_options.suffix_len;
5866f3599c1SRoy Oursler
5872104a77dSRoy Oursler int level = global_options.level;
5882104a77dSRoy Oursler
5892104a77dSRoy Oursler if (suffix == NULL) {
5902104a77dSRoy Oursler suffix = default_suffixes[0];
5912104a77dSRoy Oursler suffix_len = default_suffixes_lens[0];
5922104a77dSRoy Oursler }
5932104a77dSRoy Oursler
594*cf610527SMarcel Cornu if (infile_name_len == stdin_file_name_len && infile_name != NULL &&
5952104a77dSRoy Oursler memcmp(infile_name, stdin_file_name, infile_name_len) == 0) {
5962104a77dSRoy Oursler infile_name = NULL;
5972104a77dSRoy Oursler infile_name_len = 0;
5982104a77dSRoy Oursler }
5992104a77dSRoy Oursler
6002104a77dSRoy Oursler if (outfile_name == NULL && infile_name != NULL && !global_options.use_stdout) {
6016f3599c1SRoy Oursler outfile_name_len = infile_name_len + suffix_len;
6021ba280faSGreg Tucker allocated_name = malloc_safe(outfile_name_len + 1);
6031ba280faSGreg Tucker outfile_name = allocated_name;
6041ba280faSGreg Tucker strncpy(outfile_name, infile_name, infile_name_len + 1);
60508f021c4STomasz Kantecki strncat(outfile_name, suffix, suffix_len);
6062104a77dSRoy Oursler }
6072104a77dSRoy Oursler
6086f3599c1SRoy Oursler open_in_file(&in, infile_name);
6096f3599c1SRoy Oursler if (in == NULL)
6106f3599c1SRoy Oursler goto compress_file_cleanup;
6116f3599c1SRoy Oursler
612*cf610527SMarcel Cornu if (infile_name_len != 0 && infile_name_len == outfile_name_len && infile_name != NULL &&
613*cf610527SMarcel Cornu outfile_name != NULL && strncmp(infile_name, outfile_name, infile_name_len) == 0) {
6146f3599c1SRoy Oursler log_print(ERROR, "igzip: Error input and output file names must differ\n");
6156f3599c1SRoy Oursler goto compress_file_cleanup;
6166f3599c1SRoy Oursler }
6176f3599c1SRoy Oursler
6186f3599c1SRoy Oursler open_out_file(&out, outfile_name);
6196f3599c1SRoy Oursler if (out == NULL)
6202104a77dSRoy Oursler goto compress_file_cleanup;
6212104a77dSRoy Oursler
6220a7e3167SGreg Tucker inbuf_size = global_options.in_buf_size;
6230a7e3167SGreg Tucker outbuf_size = global_options.out_buf_size;
6242104a77dSRoy Oursler
6250a7e3167SGreg Tucker inbuf = global_options.in_buf;
6260a7e3167SGreg Tucker outbuf = global_options.out_buf;
6270a7e3167SGreg Tucker level_size = global_options.level_buf_size;
6280a7e3167SGreg Tucker level_buf = global_options.level_buf;
6292104a77dSRoy Oursler
6302104a77dSRoy Oursler isal_gzip_header_init(&gz_hdr);
631cd5de57fSRoy Oursler if (global_options.name == NAME_DEFAULT || global_options.name == YES_NAME) {
632a139dd73STomasz Kantecki if (get_posix_filetime(in, &gz_hdr.time) != 0)
633a139dd73STomasz Kantecki goto compress_file_cleanup;
6342104a77dSRoy Oursler gz_hdr.name = infile_name;
635cd5de57fSRoy Oursler }
636cd5de57fSRoy Oursler gz_hdr.os = UNIX;
6372104a77dSRoy Oursler gz_hdr.name_buf_len = infile_name_len + 1;
6382104a77dSRoy Oursler
6392104a77dSRoy Oursler isal_deflate_init(&stream);
640f7628833SRoy Oursler stream.avail_in = 0;
6412104a77dSRoy Oursler stream.flush = NO_FLUSH;
6422104a77dSRoy Oursler stream.level = level;
6432104a77dSRoy Oursler stream.level_buf = level_buf;
6442104a77dSRoy Oursler stream.level_buf_size = level_size;
6452104a77dSRoy Oursler stream.gzip_flag = IGZIP_GZIP_NO_HDR;
6462104a77dSRoy Oursler stream.next_out = outbuf;
6472104a77dSRoy Oursler stream.avail_out = outbuf_size;
6482104a77dSRoy Oursler
6492104a77dSRoy Oursler isal_write_gzip_header(&stream, &gz_hdr);
6502104a77dSRoy Oursler
6510a7e3167SGreg Tucker if (global_options.threads > 1) {
6520a7e3167SGreg Tucker #if defined(HAVE_THREADS)
6530a7e3167SGreg Tucker int q;
6540a7e3167SGreg Tucker int end_of_stream = 0;
6550a7e3167SGreg Tucker uint32_t crc = 0;
6560a7e3167SGreg Tucker uint64_t total_in = 0;
6570a7e3167SGreg Tucker
6580a7e3167SGreg Tucker // Write the header
6590a7e3167SGreg Tucker fwrite_safe(outbuf, 1, stream.total_out, out, outfile_name);
6600a7e3167SGreg Tucker
6610a7e3167SGreg Tucker do {
6620a7e3167SGreg Tucker size_t nread;
6630a7e3167SGreg Tucker size_t inbuf_used = 0;
6640a7e3167SGreg Tucker size_t outbuf_used = 0;
6650a7e3167SGreg Tucker uint8_t *iptr = inbuf;
6660a7e3167SGreg Tucker uint8_t *optr = outbuf;
6670a7e3167SGreg Tucker
6680a7e3167SGreg Tucker for (q = 0; q < MAX_JOBQUEUE - 1; q++) {
6690a7e3167SGreg Tucker inbuf_used += BLOCK_SIZE;
6700a7e3167SGreg Tucker outbuf_used += 2 * BLOCK_SIZE;
6710a7e3167SGreg Tucker if (inbuf_used > inbuf_size || outbuf_used > outbuf_size)
6720a7e3167SGreg Tucker break;
6730a7e3167SGreg Tucker
6740a7e3167SGreg Tucker nread = fread_safe(iptr, 1, BLOCK_SIZE, in, infile_name);
6750a7e3167SGreg Tucker crc = crc32_gzip_refl(crc, iptr, nread);
6760a7e3167SGreg Tucker end_of_stream = feof(in);
6770a7e3167SGreg Tucker total_in += nread;
6780a7e3167SGreg Tucker stream.next_in = iptr;
6790a7e3167SGreg Tucker stream.next_out = optr;
6800a7e3167SGreg Tucker stream.avail_in = nread;
6810a7e3167SGreg Tucker stream.avail_out = 2 * BLOCK_SIZE;
6820a7e3167SGreg Tucker stream.end_of_stream = end_of_stream;
6830a7e3167SGreg Tucker ret = pool_put_work(&stream);
6840a7e3167SGreg Tucker if (ret || end_of_stream)
6850a7e3167SGreg Tucker break;
6860a7e3167SGreg Tucker
6870a7e3167SGreg Tucker iptr += BLOCK_SIZE;
6880a7e3167SGreg Tucker optr += 2 * BLOCK_SIZE;
6890a7e3167SGreg Tucker }
6900a7e3167SGreg Tucker
6910a7e3167SGreg Tucker while (pool.tail != pool.head) { // Unprocessed jobs
6920a7e3167SGreg Tucker int t = (pool.tail + 1) % MAX_JOBQUEUE;
6930a7e3167SGreg Tucker if (pool.job[t].status >= JOB_SUCCESS) { // Finished next
6940a7e3167SGreg Tucker if (pool.job[t].status > JOB_SUCCESS) {
6950a7e3167SGreg Tucker success = 0;
6960a7e3167SGreg Tucker log_print(ERROR,
697*cf610527SMarcel Cornu "igzip: Error encountered while "
698*cf610527SMarcel Cornu "compressing file %s\n",
6990a7e3167SGreg Tucker infile_name);
7000a7e3167SGreg Tucker goto compress_file_cleanup;
7010a7e3167SGreg Tucker }
702*cf610527SMarcel Cornu fwrite_safe(pool.job[t].next_out, 1, pool.job[t].total_out,
703*cf610527SMarcel Cornu out, outfile_name);
7040a7e3167SGreg Tucker
7050a7e3167SGreg Tucker pool.job[t].total_out = 0;
7060a7e3167SGreg Tucker pool.job[t].status = 0;
7070a7e3167SGreg Tucker pool.tail = t;
7080a7e3167SGreg Tucker pthread_cond_broadcast(&pool.cond);
7090a7e3167SGreg Tucker }
7100a7e3167SGreg Tucker // Pick up a job while we wait
7110a7e3167SGreg Tucker pthread_mutex_lock(&pool.mutex);
7120a7e3167SGreg Tucker if (!pool_has_work()) {
7130a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
7140a7e3167SGreg Tucker continue;
7150a7e3167SGreg Tucker }
7160a7e3167SGreg Tucker
7170a7e3167SGreg Tucker int work_idx = pool_get_work();
7180a7e3167SGreg Tucker pthread_cond_signal(&pool.cond);
7190a7e3167SGreg Tucker pthread_mutex_unlock(&pool.mutex);
7200a7e3167SGreg Tucker
7210a7e3167SGreg Tucker isal_deflate_stateless_init(&stream);
7220a7e3167SGreg Tucker stream.next_in = pool.job[work_idx].next_in;
7230a7e3167SGreg Tucker stream.next_out = pool.job[work_idx].next_out;
7240a7e3167SGreg Tucker stream.avail_in = pool.job[work_idx].avail_in;
7250a7e3167SGreg Tucker stream.avail_out = pool.job[work_idx].avail_out;
7260a7e3167SGreg Tucker stream.end_of_stream = pool.job[work_idx].type;
7270a7e3167SGreg Tucker stream.flush = FULL_FLUSH;
7280a7e3167SGreg Tucker stream.level = global_options.level;
7290a7e3167SGreg Tucker stream.level_buf = level_buf;
7300a7e3167SGreg Tucker stream.level_buf_size = level_size;
7310a7e3167SGreg Tucker int check = isal_deflate_stateless(&stream);
732*cf610527SMarcel Cornu log_print(VERBOSE, "Self finished job %d, out=%d\n", work_idx,
733*cf610527SMarcel Cornu stream.total_out);
7340a7e3167SGreg Tucker pool.job[work_idx].total_out = stream.total_out;
7350a7e3167SGreg Tucker pool.job[work_idx].status = JOB_SUCCESS + check; // complete or fail
7360a7e3167SGreg Tucker }
7370a7e3167SGreg Tucker } while (!end_of_stream);
7380a7e3167SGreg Tucker
7390a7e3167SGreg Tucker // Write gzip trailer
7401ba280faSGreg Tucker fwrite_safe(&crc, sizeof(uint32_t), 1, out, outfile_name);
7411ba280faSGreg Tucker fwrite_safe(&total_in, sizeof(uint32_t), 1, out, outfile_name);
7420a7e3167SGreg Tucker
7430a7e3167SGreg Tucker #else // No compiled threading support but asked for threads > 1
7440a7e3167SGreg Tucker assert(1);
7450a7e3167SGreg Tucker #endif
7460a7e3167SGreg Tucker } else { // Single thread
7472104a77dSRoy Oursler do {
7482104a77dSRoy Oursler if (stream.avail_in == 0) {
7492104a77dSRoy Oursler stream.next_in = inbuf;
7502104a77dSRoy Oursler stream.avail_in =
7512104a77dSRoy Oursler fread_safe(stream.next_in, 1, inbuf_size, in, infile_name);
7522104a77dSRoy Oursler stream.end_of_stream = feof(in);
7532104a77dSRoy Oursler }
7542104a77dSRoy Oursler
7552104a77dSRoy Oursler if (stream.next_out == NULL) {
7562104a77dSRoy Oursler stream.next_out = outbuf;
7572104a77dSRoy Oursler stream.avail_out = outbuf_size;
7582104a77dSRoy Oursler }
7592104a77dSRoy Oursler
7602104a77dSRoy Oursler ret = isal_deflate(&stream);
7612104a77dSRoy Oursler
7622104a77dSRoy Oursler if (ret != ISAL_DECOMP_OK) {
7632104a77dSRoy Oursler log_print(ERROR,
7642104a77dSRoy Oursler "igzip: Error encountered while compressing file %s\n",
7652104a77dSRoy Oursler infile_name);
7662104a77dSRoy Oursler goto compress_file_cleanup;
7672104a77dSRoy Oursler }
7682104a77dSRoy Oursler
7692104a77dSRoy Oursler fwrite_safe(outbuf, 1, stream.next_out - outbuf, out, outfile_name);
7702104a77dSRoy Oursler stream.next_out = NULL;
7712104a77dSRoy Oursler
7722104a77dSRoy Oursler } while (!feof(in) || stream.avail_out == 0);
7730a7e3167SGreg Tucker }
7740a7e3167SGreg Tucker
7752104a77dSRoy Oursler success = 1;
7762104a77dSRoy Oursler
7772104a77dSRoy Oursler compress_file_cleanup:
7782104a77dSRoy Oursler if (out != NULL && out != stdout)
7792104a77dSRoy Oursler fclose(out);
7802104a77dSRoy Oursler
7812104a77dSRoy Oursler if (in != NULL && in != stdin) {
7822104a77dSRoy Oursler fclose(in);
7832104a77dSRoy Oursler if (success && global_options.remove)
7842104a77dSRoy Oursler remove(infile_name);
7852104a77dSRoy Oursler }
7862104a77dSRoy Oursler
7871ba280faSGreg Tucker if (allocated_name != NULL)
7881ba280faSGreg Tucker free(allocated_name);
7892104a77dSRoy Oursler
7902104a77dSRoy Oursler return (success == 0);
7912104a77dSRoy Oursler }
7922104a77dSRoy Oursler
793*cf610527SMarcel Cornu int
decompress_file(void)794*cf610527SMarcel Cornu decompress_file(void)
7952104a77dSRoy Oursler {
7962104a77dSRoy Oursler FILE *in = NULL, *out = NULL;
7972104a77dSRoy Oursler unsigned char *inbuf = NULL, *outbuf = NULL;
7982104a77dSRoy Oursler size_t inbuf_size, outbuf_size;
7992104a77dSRoy Oursler struct inflate_state state;
8002104a77dSRoy Oursler struct isal_gzip_header gz_hdr;
801cd5de57fSRoy Oursler const int terminal = 0, implicit = 1, stripped = 2;
802cd5de57fSRoy Oursler int ret = 0, success = 0, outfile_type = terminal;
8032104a77dSRoy Oursler
8041ba280faSGreg Tucker char *infile_name = global_options.infile_name;
8051ba280faSGreg Tucker char *outfile_name = global_options.outfile_name;
8061ba280faSGreg Tucker char *allocated_name = NULL;
8072104a77dSRoy Oursler char *suffix = global_options.suffix;
8082104a77dSRoy Oursler size_t infile_name_len = global_options.infile_name_len;
8092104a77dSRoy Oursler size_t outfile_name_len = global_options.outfile_name_len;
8102104a77dSRoy Oursler size_t suffix_len = global_options.suffix_len;
8112104a77dSRoy Oursler int suffix_index = 0;
8122104a77dSRoy Oursler uint32_t file_time;
8132104a77dSRoy Oursler
814ae45f60eSGreg Tucker // Allocate mem and setup to hold gzip header info
815*cf610527SMarcel Cornu if (infile_name_len == stdin_file_name_len && infile_name != NULL &&
8162104a77dSRoy Oursler memcmp(infile_name, stdin_file_name, infile_name_len) == 0) {
8172104a77dSRoy Oursler infile_name = NULL;
8182104a77dSRoy Oursler infile_name_len = 0;
8192104a77dSRoy Oursler }
8202104a77dSRoy Oursler
821cd5de57fSRoy Oursler if (outfile_name == NULL && !global_options.use_stdout) {
822cd5de57fSRoy Oursler if (infile_name != NULL) {
823cd5de57fSRoy Oursler outfile_type = stripped;
824cd5de57fSRoy Oursler while (suffix_index <
825cd5de57fSRoy Oursler sizeof(default_suffixes) / sizeof(*default_suffixes)) {
8262104a77dSRoy Oursler if (suffix == NULL) {
8272104a77dSRoy Oursler suffix = default_suffixes[suffix_index];
8282104a77dSRoy Oursler suffix_len = default_suffixes_lens[suffix_index];
8292104a77dSRoy Oursler suffix_index++;
8302104a77dSRoy Oursler }
8312104a77dSRoy Oursler
8322104a77dSRoy Oursler outfile_name_len = infile_name_len - suffix_len;
833*cf610527SMarcel Cornu if (infile_name_len >= suffix_len &&
834*cf610527SMarcel Cornu memcmp(infile_name + outfile_name_len, suffix, suffix_len) == 0)
8352104a77dSRoy Oursler break;
8362104a77dSRoy Oursler suffix = NULL;
8372104a77dSRoy Oursler suffix_len = 0;
8382104a77dSRoy Oursler }
8392104a77dSRoy Oursler
8407177ff99SRoy Oursler if (suffix == NULL && global_options.test == NO_TEST) {
8412104a77dSRoy Oursler log_print(ERROR, "igzip: %s: unknown suffix -- ignored\n",
8422104a77dSRoy Oursler infile_name);
8432104a77dSRoy Oursler return 1;
8442104a77dSRoy Oursler }
845cd5de57fSRoy Oursler }
846cd5de57fSRoy Oursler if (global_options.name == YES_NAME) {
847cd5de57fSRoy Oursler outfile_name_len = 0;
848cd5de57fSRoy Oursler outfile_type = implicit;
849cd5de57fSRoy Oursler }
8501ba280faSGreg Tucker if (outfile_type != terminal) {
851*cf610527SMarcel Cornu allocated_name = malloc_safe(outfile_name_len >= MAX_FILEPATH_BUF
852*cf610527SMarcel Cornu ? outfile_name_len + 1
853*cf610527SMarcel Cornu : MAX_FILEPATH_BUF);
8541ba280faSGreg Tucker outfile_name = allocated_name;
8551ba280faSGreg Tucker }
8562104a77dSRoy Oursler }
8572104a77dSRoy Oursler
8586f3599c1SRoy Oursler open_in_file(&in, infile_name);
8596f3599c1SRoy Oursler if (in == NULL)
8606f3599c1SRoy Oursler goto decompress_file_cleanup;
8616f3599c1SRoy Oursler
862a139dd73STomasz Kantecki if (get_posix_filetime(in, &file_time) != 0)
863a139dd73STomasz Kantecki goto decompress_file_cleanup;
8642104a77dSRoy Oursler
8650a7e3167SGreg Tucker inbuf_size = global_options.in_buf_size;
8660a7e3167SGreg Tucker outbuf_size = global_options.out_buf_size;
8670a7e3167SGreg Tucker inbuf = global_options.in_buf;
8680a7e3167SGreg Tucker outbuf = global_options.out_buf;
8692104a77dSRoy Oursler
8702104a77dSRoy Oursler isal_gzip_header_init(&gz_hdr);
871cd5de57fSRoy Oursler if (outfile_type == implicit) {
872cd5de57fSRoy Oursler gz_hdr.name = outfile_name;
873cd5de57fSRoy Oursler gz_hdr.name_buf_len = MAX_FILEPATH_BUF;
874cd5de57fSRoy Oursler }
875cd5de57fSRoy Oursler
8762104a77dSRoy Oursler isal_inflate_init(&state);
877ebab4454SRoy Oursler state.crc_flag = ISAL_GZIP_NO_HDR_VER;
8782104a77dSRoy Oursler state.next_in = inbuf;
8792104a77dSRoy Oursler state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
8802104a77dSRoy Oursler
881ae45f60eSGreg Tucker // Actually read and save the header info
8822104a77dSRoy Oursler ret = isal_read_gzip_header(&state, &gz_hdr);
8832104a77dSRoy Oursler if (ret != ISAL_DECOMP_OK) {
8842104a77dSRoy Oursler log_print(ERROR, "igzip: Error invalid gzip header found for file %s\n",
8852104a77dSRoy Oursler infile_name);
8862104a77dSRoy Oursler goto decompress_file_cleanup;
8872104a77dSRoy Oursler }
8882104a77dSRoy Oursler
889cd5de57fSRoy Oursler if (outfile_type == implicit)
890cd5de57fSRoy Oursler file_time = gz_hdr.time;
891cd5de57fSRoy Oursler
892*cf610527SMarcel Cornu if (outfile_name != NULL && infile_name != NULL &&
893*cf610527SMarcel Cornu (outfile_type == stripped || (outfile_type == implicit && outfile_name[0] == 0))) {
894cd5de57fSRoy Oursler outfile_name_len = infile_name_len - suffix_len;
895cd5de57fSRoy Oursler memcpy(outfile_name, infile_name, outfile_name_len);
896cd5de57fSRoy Oursler outfile_name[outfile_name_len] = 0;
897cd5de57fSRoy Oursler }
898cd5de57fSRoy Oursler
899*cf610527SMarcel Cornu if (infile_name_len != 0 && infile_name_len == outfile_name_len && infile_name != NULL &&
900*cf610527SMarcel Cornu outfile_name != NULL && strncmp(infile_name, outfile_name, infile_name_len) == 0) {
901cd5de57fSRoy Oursler log_print(ERROR, "igzip: Error input and output file names must differ\n");
902cd5de57fSRoy Oursler goto decompress_file_cleanup;
903cd5de57fSRoy Oursler }
904cd5de57fSRoy Oursler
9057177ff99SRoy Oursler if (global_options.test == NO_TEST) {
906cd5de57fSRoy Oursler open_out_file(&out, outfile_name);
907cd5de57fSRoy Oursler if (out == NULL)
908cd5de57fSRoy Oursler goto decompress_file_cleanup;
9097177ff99SRoy Oursler }
910cd5de57fSRoy Oursler
911ae45f60eSGreg Tucker // Start reading in compressed data and decompress
9122104a77dSRoy Oursler do {
9132104a77dSRoy Oursler if (state.avail_in == 0) {
9142104a77dSRoy Oursler state.next_in = inbuf;
915*cf610527SMarcel Cornu state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
9162104a77dSRoy Oursler }
9172104a77dSRoy Oursler
9182104a77dSRoy Oursler state.next_out = outbuf;
9192104a77dSRoy Oursler state.avail_out = outbuf_size;
9202104a77dSRoy Oursler
9212104a77dSRoy Oursler ret = isal_inflate(&state);
9222104a77dSRoy Oursler if (ret != ISAL_DECOMP_OK) {
923*cf610527SMarcel Cornu log_print(ERROR, "igzip: Error encountered while decompressing file %s\n",
9242104a77dSRoy Oursler infile_name);
9252104a77dSRoy Oursler goto decompress_file_cleanup;
9262104a77dSRoy Oursler }
9272104a77dSRoy Oursler
9287177ff99SRoy Oursler if (out != NULL)
9292104a77dSRoy Oursler fwrite_safe(outbuf, 1, state.next_out - outbuf, out, outfile_name);
9302104a77dSRoy Oursler
931ae45f60eSGreg Tucker } while (state.block_state != ISAL_BLOCK_FINISH // while not done
932ae45f60eSGreg Tucker && (!feof(in) || state.avail_out == 0) // and work to do
933ae45f60eSGreg Tucker );
934ae45f60eSGreg Tucker
935ae45f60eSGreg Tucker // Add the following to look for and decode additional concatenated files
936ae45f60eSGreg Tucker if (!feof(in) && state.avail_in == 0) {
937ae45f60eSGreg Tucker state.next_in = inbuf;
938ae45f60eSGreg Tucker state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
939ae45f60eSGreg Tucker }
940ae45f60eSGreg Tucker
941ae45f60eSGreg Tucker while (state.avail_in > 0 && state.next_in[0] == 31) {
942ae45f60eSGreg Tucker // Look for magic numbers for gzip header. Follows the gzread() decision
943ae45f60eSGreg Tucker // whether to treat as trailing junk
944ae45f60eSGreg Tucker if (state.avail_in > 1 && state.next_in[1] != 139)
945ae45f60eSGreg Tucker break;
946ae45f60eSGreg Tucker
947ae45f60eSGreg Tucker isal_inflate_reset(&state);
948ae45f60eSGreg Tucker state.crc_flag = ISAL_GZIP; // Let isal_inflate() process extra headers
949ae45f60eSGreg Tucker do {
950ae45f60eSGreg Tucker if (state.avail_in == 0 && !feof(in)) {
951ae45f60eSGreg Tucker state.next_in = inbuf;
952ae45f60eSGreg Tucker state.avail_in =
953ae45f60eSGreg Tucker fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
954ae45f60eSGreg Tucker }
955ae45f60eSGreg Tucker
956ae45f60eSGreg Tucker state.next_out = outbuf;
957ae45f60eSGreg Tucker state.avail_out = outbuf_size;
958ae45f60eSGreg Tucker
959ae45f60eSGreg Tucker ret = isal_inflate(&state);
960ae45f60eSGreg Tucker if (ret != ISAL_DECOMP_OK) {
961ae45f60eSGreg Tucker log_print(ERROR,
962ae45f60eSGreg Tucker "igzip: Error while decompressing extra concatenated"
963*cf610527SMarcel Cornu "gzip files on %s\n",
964*cf610527SMarcel Cornu infile_name);
965ae45f60eSGreg Tucker goto decompress_file_cleanup;
966ae45f60eSGreg Tucker }
967ae45f60eSGreg Tucker
968ae45f60eSGreg Tucker if (out != NULL)
969*cf610527SMarcel Cornu fwrite_safe(outbuf, 1, state.next_out - outbuf, out, outfile_name);
970ae45f60eSGreg Tucker
971*cf610527SMarcel Cornu } while (state.block_state != ISAL_BLOCK_FINISH &&
972*cf610527SMarcel Cornu (!feof(in) || state.avail_out == 0));
973ae45f60eSGreg Tucker
974ae45f60eSGreg Tucker if (!feof(in) && state.avail_in == 0) {
975ae45f60eSGreg Tucker state.next_in = inbuf;
976*cf610527SMarcel Cornu state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
977ae45f60eSGreg Tucker }
978ae45f60eSGreg Tucker }
9792104a77dSRoy Oursler
9802104a77dSRoy Oursler if (state.block_state != ISAL_BLOCK_FINISH)
9812104a77dSRoy Oursler log_print(ERROR, "igzip: Error %s does not contain a complete gzip file\n",
9822104a77dSRoy Oursler infile_name);
9832104a77dSRoy Oursler else
9842104a77dSRoy Oursler success = 1;
9852104a77dSRoy Oursler
9862104a77dSRoy Oursler decompress_file_cleanup:
9872104a77dSRoy Oursler if (out != NULL && out != stdout) {
9882104a77dSRoy Oursler fclose(out);
9892104a77dSRoy Oursler if (success)
9902104a77dSRoy Oursler set_filetime(outfile_name, file_time);
9912104a77dSRoy Oursler }
9922104a77dSRoy Oursler
9932104a77dSRoy Oursler if (in != NULL && in != stdin) {
9942104a77dSRoy Oursler fclose(in);
9952104a77dSRoy Oursler if (success && global_options.remove)
9962104a77dSRoy Oursler remove(infile_name);
9972104a77dSRoy Oursler }
9982104a77dSRoy Oursler
9991ba280faSGreg Tucker if (allocated_name != NULL)
10001ba280faSGreg Tucker free(allocated_name);
10012104a77dSRoy Oursler
10022104a77dSRoy Oursler return (success == 0);
10032104a77dSRoy Oursler }
10042104a77dSRoy Oursler
1005*cf610527SMarcel Cornu int
main(int argc,char * argv[])1006*cf610527SMarcel Cornu main(int argc, char *argv[])
10072104a77dSRoy Oursler {
10082104a77dSRoy Oursler int c;
10090a7e3167SGreg Tucker char optstring[] = "hcdz0123456789o:S:kfqVvNntT:";
10102104a77dSRoy Oursler int long_only_flag;
10112104a77dSRoy Oursler int ret = 0;
10122104a77dSRoy Oursler int bad_option = 0;
10132104a77dSRoy Oursler int bad_level = 0;
10142104a77dSRoy Oursler int bad_c = 0;
10152104a77dSRoy Oursler
1016*cf610527SMarcel Cornu struct option long_options[] = { { "help", no_argument, NULL, 'h' },
10172104a77dSRoy Oursler { "stdout", no_argument, NULL, 'c' },
10182104a77dSRoy Oursler { "to-stdout", no_argument, NULL, 'c' },
10192104a77dSRoy Oursler { "compress", no_argument, NULL, 'z' },
10202104a77dSRoy Oursler { "decompress", no_argument, NULL, 'd' },
10212104a77dSRoy Oursler { "uncompress", no_argument, NULL, 'd' },
10222104a77dSRoy Oursler { "keep", no_argument, NULL, 'k' },
10232104a77dSRoy Oursler { "rm", no_argument, &long_only_flag, RM },
10242104a77dSRoy Oursler { "suffix", no_argument, NULL, 'S' },
10252104a77dSRoy Oursler { "fast", no_argument, NULL, '1' },
10262104a77dSRoy Oursler { "best", no_argument, NULL, '0' + ISAL_DEF_MAX_LEVEL },
10272104a77dSRoy Oursler { "force", no_argument, NULL, 'f' },
10282104a77dSRoy Oursler { "quiet", no_argument, NULL, 'q' },
10292104a77dSRoy Oursler { "version", no_argument, NULL, 'V' },
10302104a77dSRoy Oursler { "verbose", no_argument, NULL, 'v' },
10312104a77dSRoy Oursler { "no-name", no_argument, NULL, 'n' },
10322104a77dSRoy Oursler { "name", no_argument, NULL, 'N' },
1033cd5de57fSRoy Oursler { "test", no_argument, NULL, 't' },
10340a7e3167SGreg Tucker { "threads", required_argument, NULL, 'T' },
10357177ff99SRoy Oursler /* Possible future extensions
10362104a77dSRoy Oursler {"recursive, no_argument, NULL, 'r'},
10372104a77dSRoy Oursler {"list", no_argument, NULL, 'l'},
10382104a77dSRoy Oursler {"benchmark", optional_argument, NULL, 'b'},
10392104a77dSRoy Oursler {"benchmark_end", required_argument, NULL, 'e'},
10402104a77dSRoy Oursler */
1041*cf610527SMarcel Cornu { 0, 0, 0, 0 } };
10422104a77dSRoy Oursler
10432104a77dSRoy Oursler init_options(&global_options);
10442104a77dSRoy Oursler
10452104a77dSRoy Oursler opterr = 0;
10462104a77dSRoy Oursler while ((c = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
10472104a77dSRoy Oursler if (c >= '0' && c <= '9') {
10482104a77dSRoy Oursler if (c > '0' + ISAL_DEF_MAX_LEVEL)
10492104a77dSRoy Oursler bad_level = 1;
10502104a77dSRoy Oursler else
10512104a77dSRoy Oursler global_options.level = c - '0';
10522104a77dSRoy Oursler
10532104a77dSRoy Oursler continue;
10542104a77dSRoy Oursler }
10552104a77dSRoy Oursler
10562104a77dSRoy Oursler switch (c) {
10572104a77dSRoy Oursler case 0:
10582104a77dSRoy Oursler switch (long_only_flag) {
10592104a77dSRoy Oursler case RM:
10602104a77dSRoy Oursler global_options.remove = true;
10612104a77dSRoy Oursler break;
10622104a77dSRoy Oursler default:
10632104a77dSRoy Oursler bad_option = 1;
10642104a77dSRoy Oursler bad_c = c;
10652104a77dSRoy Oursler break;
10662104a77dSRoy Oursler }
10672104a77dSRoy Oursler break;
10682104a77dSRoy Oursler case 'o':
10692104a77dSRoy Oursler global_options.outfile_name = optarg;
10702104a77dSRoy Oursler global_options.outfile_name_len = strlen(global_options.outfile_name);
10712104a77dSRoy Oursler break;
10722104a77dSRoy Oursler case 'c':
10732104a77dSRoy Oursler global_options.use_stdout = true;
10742104a77dSRoy Oursler break;
10752104a77dSRoy Oursler case 'z':
10762104a77dSRoy Oursler global_options.mode = COMPRESS_MODE;
10772104a77dSRoy Oursler break;
10782104a77dSRoy Oursler case 'd':
10792104a77dSRoy Oursler global_options.mode = DECOMPRESS_MODE;
10802104a77dSRoy Oursler break;
10812104a77dSRoy Oursler case 'S':
10822104a77dSRoy Oursler global_options.suffix = optarg;
10832104a77dSRoy Oursler global_options.suffix_len = strlen(global_options.suffix);
10842104a77dSRoy Oursler break;
10852104a77dSRoy Oursler case 'k':
10862104a77dSRoy Oursler global_options.remove = false;
10872104a77dSRoy Oursler break;
10882104a77dSRoy Oursler case 'f':
10892104a77dSRoy Oursler global_options.force = true;
10902104a77dSRoy Oursler break;
10912104a77dSRoy Oursler case 'q':
10922104a77dSRoy Oursler global_options.quiet_level++;
10932104a77dSRoy Oursler break;
10942104a77dSRoy Oursler case 'v':
10952104a77dSRoy Oursler global_options.verbose_level++;
10962104a77dSRoy Oursler break;
10972104a77dSRoy Oursler case 'V':
10982104a77dSRoy Oursler print_version();
10992104a77dSRoy Oursler return 0;
1100cd5de57fSRoy Oursler case 'N':
1101cd5de57fSRoy Oursler global_options.name = YES_NAME;
1102cd5de57fSRoy Oursler break;
1103cd5de57fSRoy Oursler case 'n':
1104cd5de57fSRoy Oursler global_options.name = NO_NAME;
1105cd5de57fSRoy Oursler break;
11067177ff99SRoy Oursler case 't':
11077177ff99SRoy Oursler global_options.test = TEST;
11087177ff99SRoy Oursler global_options.mode = DECOMPRESS_MODE;
11097177ff99SRoy Oursler break;
11100a7e3167SGreg Tucker case 'T':
11110a7e3167SGreg Tucker #if defined(HAVE_THREADS)
11120a7e3167SGreg Tucker c = atoi(optarg);
11130a7e3167SGreg Tucker c = c > MAX_THREADS ? MAX_THREADS : c;
11140a7e3167SGreg Tucker c = c < 1 ? 1 : c;
11150a7e3167SGreg Tucker global_options.threads = c;
11160a7e3167SGreg Tucker #endif
11170a7e3167SGreg Tucker break;
11182104a77dSRoy Oursler case 'h':
11192104a77dSRoy Oursler usage(0);
11202104a77dSRoy Oursler default:
11212104a77dSRoy Oursler bad_option = 1;
11222104a77dSRoy Oursler bad_c = optopt;
11232104a77dSRoy Oursler break;
11242104a77dSRoy Oursler }
11252104a77dSRoy Oursler }
11262104a77dSRoy Oursler
11272104a77dSRoy Oursler if (bad_option) {
11282104a77dSRoy Oursler log_print(ERROR, "igzip: invalid option ");
11292104a77dSRoy Oursler if (bad_c)
11302104a77dSRoy Oursler log_print(ERROR, "-%c\n", bad_c);
11312104a77dSRoy Oursler
11322104a77dSRoy Oursler else
11332104a77dSRoy Oursler log_print(ERROR, ("\n"));
11342104a77dSRoy Oursler
11352104a77dSRoy Oursler usage(BAD_OPTION);
11362104a77dSRoy Oursler }
11372104a77dSRoy Oursler
11382104a77dSRoy Oursler if (bad_level) {
11392104a77dSRoy Oursler log_print(ERROR, "igzip: invalid compression level\n");
11402104a77dSRoy Oursler usage(BAD_LEVEL);
11412104a77dSRoy Oursler }
11422104a77dSRoy Oursler
11432104a77dSRoy Oursler if (global_options.outfile_name && optind < argc - 1) {
11442104a77dSRoy Oursler log_print(ERROR,
11452104a77dSRoy Oursler "igzip: An output file may be specified with only one input file\n");
11462104a77dSRoy Oursler return 0;
11472104a77dSRoy Oursler }
11482104a77dSRoy Oursler
11490a7e3167SGreg Tucker global_options.in_buf_size = BLOCK_SIZE;
11500a7e3167SGreg Tucker global_options.out_buf_size = BLOCK_SIZE;
11510a7e3167SGreg Tucker
11520a7e3167SGreg Tucker #if defined(HAVE_THREADS)
11530a7e3167SGreg Tucker if (global_options.threads > 1) {
11540a7e3167SGreg Tucker global_options.in_buf_size += (BLOCK_SIZE * MAX_JOBQUEUE);
11550a7e3167SGreg Tucker global_options.out_buf_size += (BLOCK_SIZE * MAX_JOBQUEUE * 2);
11560a7e3167SGreg Tucker pool_create();
11570a7e3167SGreg Tucker }
11580a7e3167SGreg Tucker #endif
11590a7e3167SGreg Tucker global_options.in_buf = malloc_safe(global_options.in_buf_size);
11600a7e3167SGreg Tucker global_options.out_buf = malloc_safe(global_options.out_buf_size);
11610a7e3167SGreg Tucker global_options.level_buf_size = level_size_buf[global_options.level];
11620a7e3167SGreg Tucker global_options.level_buf = malloc_safe(global_options.level_buf_size);
11630a7e3167SGreg Tucker
11642104a77dSRoy Oursler if (global_options.mode == COMPRESS_MODE) {
11652104a77dSRoy Oursler if (optind >= argc)
11660a7e3167SGreg Tucker ret |= compress_file();
11672104a77dSRoy Oursler while (optind < argc) {
11682104a77dSRoy Oursler global_options.infile_name = argv[optind];
11692104a77dSRoy Oursler global_options.infile_name_len = strlen(global_options.infile_name);
11702104a77dSRoy Oursler ret |= compress_file();
11712104a77dSRoy Oursler optind++;
11722104a77dSRoy Oursler }
11732104a77dSRoy Oursler
11742104a77dSRoy Oursler } else if (global_options.mode == DECOMPRESS_MODE) {
11752104a77dSRoy Oursler if (optind >= argc)
11760a7e3167SGreg Tucker ret |= decompress_file();
11772104a77dSRoy Oursler while (optind < argc) {
11782104a77dSRoy Oursler global_options.infile_name = argv[optind];
11792104a77dSRoy Oursler global_options.infile_name_len = strlen(global_options.infile_name);
11802104a77dSRoy Oursler ret |= decompress_file();
11812104a77dSRoy Oursler optind++;
11822104a77dSRoy Oursler }
11832104a77dSRoy Oursler }
11840a7e3167SGreg Tucker #if defined(HAVE_THREADS)
11850a7e3167SGreg Tucker if (global_options.threads > 1)
11860a7e3167SGreg Tucker pool_quit();
11870a7e3167SGreg Tucker #endif
11882104a77dSRoy Oursler
11890a7e3167SGreg Tucker free(global_options.in_buf);
11900a7e3167SGreg Tucker free(global_options.out_buf);
11910a7e3167SGreg Tucker free(global_options.level_buf);
11922104a77dSRoy Oursler return ret;
11932104a77dSRoy Oursler }
1194