diff options
Diffstat (limited to 'src/isa-l/programs')
-rw-r--r-- | src/isa-l/programs/Makefile.am | 38 | ||||
-rw-r--r-- | src/isa-l/programs/igzip.1 | 87 | ||||
-rw-r--r-- | src/isa-l/programs/igzip.1.h2m | 31 | ||||
-rw-r--r-- | src/isa-l/programs/igzip_cli.c | 1206 | ||||
-rwxr-xr-x | src/isa-l/programs/igzip_cli_check.sh | 261 |
5 files changed, 1623 insertions, 0 deletions
diff --git a/src/isa-l/programs/Makefile.am b/src/isa-l/programs/Makefile.am new file mode 100644 index 000000000..46f2a2306 --- /dev/null +++ b/src/isa-l/programs/Makefile.am @@ -0,0 +1,38 @@ +######################################################################## +# Copyright(c) 2011-2018 Intel Corporation All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +######################################################################## + + +bin_PROGRAMS += programs/igzip +programs_igzip_SOURCES = programs/igzip_cli.c +programs_igzip_LDADD = libisal.la +dist_man_MANS = programs/igzip.1 +other_src += programs/igzip.1.h2m + +programs/igzip.1: % : %.h2m programs/igzip_cli.c + -help2man -o $@ -i $< -N ./programs/igzip diff --git a/src/isa-l/programs/igzip.1 b/src/isa-l/programs/igzip.1 new file mode 100644 index 000000000..fd20512df --- /dev/null +++ b/src/isa-l/programs/igzip.1 @@ -0,0 +1,87 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.11. +.TH IGZIP "1" "November 2020" "igzip command line interface 2.30.0" "User Commands" +.SH NAME +igzip \- compress or decompress files similar to gzip +.SH SYNOPSIS +.B igzip +[\fI\,options\/\fR] [\fI\,infiles\/\fR] +.SH DESCRIPTION + +Compress or decompress files similar to gzip using the ISA-L fast deflate library. + +Output .gz files are compatible with gzip and [RFC-1952]. + +Options are similar to gzip except --keep is default. +.SH OPTIONS +.TP +\fB\-h\fR, \fB\-\-help\fR +help, print this message +.TP +\-# +use compression level # with 0 <= # <= 3 +.TP +\fB\-o\fR +<file> output file +.TP +\fB\-c\fR, \fB\-\-stdout\fR +write to stdout +.TP +\fB\-d\fR, \fB\-\-decompress\fR +decompress file +.TP +\fB\-z\fR, \fB\-\-compress\fR +compress file (default) +.TP +\fB\-f\fR, \fB\-\-force\fR +overwrite output without prompting +.TP +\fB\-\-rm\fR +remove source files after successful (de)compression +.TP +\fB\-k\fR, \fB\-\-keep\fR +keep source files (default) +.TP +\fB\-S\fR, \fB\-\-suffix\fR <.suf> +suffix to use while (de)compressing +.TP +\fB\-V\fR, \fB\-\-version\fR +show version number +.TP +\fB\-v\fR, \fB\-\-verbose\fR +verbose mode +.TP +\fB\-N\fR, \fB\-\-name\fR +save/use file name and timestamp in compress/decompress +.TP +\fB\-n\fR, \fB\-\-no\-name\fR +do not save/use file name and timestamp in compress/decompress +.TP +\fB\-t\fR, \fB\-\-test\fR +test compressed file integrity +.TP +\fB\-T\fR, \fB\-\-threads\fR <n> +use n threads to compress if enabled +.TP +\fB\-q\fR, \fB\-\-quiet\fR +suppress warnings +.PP +with no infile, or when infile is \- , read standard input +.SH EXAMPLES + +Make compressed file1.gz and file2.gz and keep file1 and file2. +.RS +.B igzip file1 file2 +.RE + +Piped compression and decompression. +.RS +.B igzip -c file.txt | igzip -d -c - +.RE + +Streaming compression from output of tar, compress level 2. +.RS +.B tar cf - dir1 | igzip -2 > dir1.tar.gz +.RE +.SH "REPORTING BUGS" + +Report bugs to https://github.com/intel/isa-l/issues diff --git a/src/isa-l/programs/igzip.1.h2m b/src/isa-l/programs/igzip.1.h2m new file mode 100644 index 000000000..819cd2d45 --- /dev/null +++ b/src/isa-l/programs/igzip.1.h2m @@ -0,0 +1,31 @@ +[Name] +igzip \- compress or decompress files similar to gzip + +[Description] + +Compress or decompress files similar to gzip using the ISA-L fast deflate library. + +Output .gz files are compatible with gzip and [RFC-1952]. + +Options are similar to gzip except --keep is default. + +[Examples] + +Make compressed file1.gz and file2.gz and keep file1 and file2. +.RS +.B igzip file1 file2 +.RE + +Piped compression and decompression. +.RS +.B igzip -c file.txt | igzip -d -c - +.RE + +Streaming compression from output of tar, compress level 2. +.RS +.B tar cf - dir1 | igzip -2 > dir1.tar.gz +.RE + +[Reporting Bugs] + +Report bugs to https://github.com/intel/isa-l/issues diff --git a/src/isa-l/programs/igzip_cli.c b/src/isa-l/programs/igzip_cli.c new file mode 100644 index 000000000..53124af21 --- /dev/null +++ b/src/isa-l/programs/igzip_cli.c @@ -0,0 +1,1206 @@ +/********************************************************************** + Copyright(c) 2011-2018 Intel Corporation All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**********************************************************************/ + +#define _FILE_OFFSET_BITS 64 +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <getopt.h> +#include <sys/stat.h> +#include <utime.h> +#include <unistd.h> +#include <stdbool.h> +#include <stdarg.h> +#include "igzip_lib.h" /* Normally you use isa-l.h instead for external programs */ + +#if defined (HAVE_THREADS) +# include <pthread.h> +# include "crc.h" +#endif + +#if !defined (VERSION) +# if defined (ISAL_VERSION) +# define VERSION ISAL_VERSION +# else +# define VERSION "unknown version" +# endif +#endif + +#define BAD_OPTION 1 +#define BAD_LEVEL 1 +#define FILE_EXISTS 0 +#define MALLOC_FAILED -1 +#define FILE_OPEN_ERROR -2 +#define FILE_READ_ERROR -3 +#define FILE_WRITE_ERROR -4 + +#define BUF_SIZE 1024 +#define BLOCK_SIZE (1024 * 1024) + +#define MAX_FILEPATH_BUF 4096 + +#define UNIX 3 + +#define NAME_DEFAULT 0 +#define NO_NAME 1 +#define YES_NAME 2 + +#define NO_TEST 0 +#define TEST 1 + +#define LEVEL_DEFAULT 2 +#define DEFAULT_SUFFIX_LEN 3 +char *default_suffixes[] = { ".gz", ".z" }; +int default_suffixes_lens[] = { 3, 2 }; + +char stdin_file_name[] = "-"; +int stdin_file_name_len = 1; + +enum compression_modes { + COMPRESS_MODE, + DECOMPRESS_MODE +}; + +enum long_only_opt_val { + RM +}; + +enum log_types { + INFORM, + WARN, + ERROR, + VERBOSE +}; + +int level_size_buf[10] = { +#ifdef ISAL_DEF_LVL0_DEFAULT + ISAL_DEF_LVL0_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL1_DEFAULT + ISAL_DEF_LVL1_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL2_DEFAULT + ISAL_DEF_LVL2_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL3_DEFAULT + ISAL_DEF_LVL3_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL4_DEFAULT + ISAL_DEF_LVL4_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL5_DEFAULT + ISAL_DEF_LVL5_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL6_DEFAULT + ISAL_DEF_LVL6_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL7_DEFAULT + ISAL_DEF_LVL7_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL8_DEFAULT + ISAL_DEF_LVL8_DEFAULT, +#else + 0, +#endif +#ifdef ISAL_DEF_LVL9_DEFAULT + ISAL_DEF_LVL9_DEFAULT, +#else + 0, +#endif +}; + +struct cli_options { + char *infile_name; + size_t infile_name_len; + char *outfile_name; + size_t outfile_name_len; + char *suffix; + size_t suffix_len; + int level; + int mode; + int use_stdout; + int remove; + int force; + int quiet_level; + int verbose_level; + int name; + int test; + int threads; + uint8_t *in_buf; + uint8_t *out_buf; + uint8_t *level_buf; + size_t in_buf_size; + size_t out_buf_size; + size_t level_buf_size; +}; + +struct cli_options global_options; + +void init_options(struct cli_options *options) +{ + options->infile_name = NULL; + options->infile_name_len = 0; + options->outfile_name = NULL; + options->outfile_name_len = 0; + options->suffix = NULL; + options->suffix_len = 0; + options->level = LEVEL_DEFAULT; + options->mode = COMPRESS_MODE; + options->use_stdout = false; + options->remove = false; + options->force = false; + options->quiet_level = 0; + options->verbose_level = 0; + options->name = NAME_DEFAULT; + options->test = NO_TEST; + options->in_buf = NULL; + options->out_buf = NULL; + options->level_buf = NULL; + options->in_buf_size = 0; + options->out_buf_size = 0; + options->level_buf_size = 0; + options->threads = 1; +}; + +int is_interactive(void) +{ + int ret; + ret = !global_options.force && !global_options.quiet_level && isatty(fileno(stdin)); + return ret; +} + +size_t get_filesize(FILE * fp) +{ + size_t file_size; + fpos_t pos, pos_curr; + + fgetpos(fp, &pos_curr); /* Save current position */ +#if defined(_WIN32) || defined(_WIN64) + _fseeki64(fp, 0, SEEK_END); +#else + fseeko(fp, 0, SEEK_END); +#endif + fgetpos(fp, &pos); + file_size = *(size_t *)&pos; + fsetpos(fp, &pos_curr); /* Restore position */ + + return file_size; +} + +uint32_t get_posix_filetime(FILE * fp) +{ + struct stat file_stats; + fstat(fileno(fp), &file_stats); + return file_stats.st_mtime; +} + +uint32_t set_filetime(char *file_name, uint32_t posix_time) +{ + struct utimbuf new_time; + new_time.actime = posix_time; + new_time.modtime = posix_time; + return utime(file_name, &new_time); +} + +void log_print(int log_type, char *format, ...) +{ + va_list args; + va_start(args, format); + + switch (log_type) { + case INFORM: + vfprintf(stdout, format, args); + break; + case WARN: + if (global_options.quiet_level <= 0) + vfprintf(stderr, format, args); + break; + case ERROR: + if (global_options.quiet_level <= 1) + vfprintf(stderr, format, args); + break; + case VERBOSE: + if (global_options.verbose_level > 0) + vfprintf(stderr, format, args); + break; + } + + va_end(args); +} + +int usage(int exit_code) +{ + int log_type = exit_code ? WARN : INFORM; + log_print(log_type, + "Usage: igzip [options] [infiles]\n\n" + "Options:\n" + " -h, --help help, print this message\n" + " -# use compression level # with 0 <= # <= %d\n" + " -o <file> output file\n" + " -c, --stdout write to stdout\n" + " -d, --decompress decompress file\n" + " -z, --compress compress file (default)\n" + " -f, --force overwrite output without prompting\n" + " --rm remove source files after successful (de)compression\n" + " -k, --keep keep source files (default)\n" + " -S, --suffix <.suf> suffix to use while (de)compressing\n" + " -V, --version show version number\n" + " -v, --verbose verbose mode\n" + " -N, --name save/use file name and timestamp in compress/decompress\n" + " -n, --no-name do not save/use file name and timestamp in compress/decompress\n" + " -t, --test test compressed file integrity\n" + " -T, --threads <n> use n threads to compress if enabled\n" + " -q, --quiet suppress warnings\n\n" + "with no infile, or when infile is - , read standard input\n\n", + ISAL_DEF_MAX_LEVEL); + + exit(exit_code); +} + +void print_version(void) +{ + log_print(INFORM, "igzip command line interface %s\n", VERSION); +} + +void *malloc_safe(size_t size) +{ + void *ptr = NULL; + if (size == 0) + return ptr; + + ptr = malloc(size); + if (ptr == NULL) { + log_print(ERROR, "igzip: Failed to allocate memory\n"); + exit(MALLOC_FAILED); + } + + return ptr; +} + +FILE *fopen_safe(char *file_name, char *mode) +{ + FILE *file; + int answer = 0, tmp; + + /* Assumes write mode always starts with w */ + if (mode[0] == 'w') { + if (access(file_name, F_OK) == 0) { + log_print(WARN, "igzip: %s already exists;", file_name); + if (is_interactive()) { + log_print(WARN, " do you wish to overwrite (y/n)?"); + answer = getchar(); + + tmp = answer; + while (tmp != '\n' && tmp != EOF) + tmp = getchar(); + + if (answer != 'y' && answer != 'Y') { + log_print(WARN, " not overwritten\n"); + return NULL; + } + } else if (!global_options.force) { + log_print(WARN, " not overwritten\n"); + return NULL; + } + + if (access(file_name, W_OK) != 0) { + log_print(ERROR, "igzip: %s: Permission denied\n", file_name); + return NULL; + } + } + } + + /* Assumes read mode always starts with r */ + if (mode[0] == 'r') { + if (access(file_name, F_OK) != 0) { + log_print(ERROR, "igzip: %s does not exist\n", file_name); + return NULL; + } + + if (access(file_name, R_OK) != 0) { + log_print(ERROR, "igzip: %s: Permission denied\n", file_name); + return NULL; + } + } + + file = fopen(file_name, mode); + if (!file) { + log_print(ERROR, "igzip: Failed to open %s\n", file_name); + return NULL; + } + + return file; +} + +size_t fread_safe(void *buf, size_t word_size, size_t buf_size, FILE * in, char *file_name) +{ + size_t read_size; + read_size = fread(buf, word_size, buf_size, in); + if (ferror(in)) { + log_print(ERROR, "igzip: Error encountered while reading file %s\n", + file_name); + exit(FILE_READ_ERROR); + } + return read_size; +} + +size_t fwrite_safe(void *buf, size_t word_size, size_t buf_size, FILE * out, char *file_name) +{ + size_t write_size; + write_size = fwrite(buf, word_size, buf_size, out); + if (ferror(out)) { + log_print(ERROR, "igzip: Error encountered while writing to file %s\n", + file_name); + exit(FILE_WRITE_ERROR); + } + return write_size; +} + +void open_in_file(FILE ** in, char *infile_name) +{ + *in = NULL; + if (infile_name == NULL) + *in = stdin; + else + *in = fopen_safe(infile_name, "rb"); +} + +void open_out_file(FILE ** out, char *outfile_name) +{ + *out = NULL; + if (global_options.use_stdout) + *out = stdout; + else if (outfile_name != NULL) + *out = fopen_safe(outfile_name, "wb"); + else if (!isatty(fileno(stdout)) || global_options.force) + *out = stdout; + else { + log_print(WARN, "igzip: No output location. Use -c to output to terminal\n"); + exit(FILE_OPEN_ERROR); + } +} + +#if defined(HAVE_THREADS) + +#define MAX_THREADS 8 +#define MAX_JOBQUEUE 16 /* must be a power of 2 */ + +enum job_status { + JOB_UNALLOCATED = 0, + JOB_ALLOCATED, + JOB_SUCCESS, + JOB_FAIL +}; + +struct thread_job { + uint8_t *next_in; + uint32_t avail_in; + uint8_t *next_out; + uint32_t avail_out; + uint32_t total_out; + uint32_t type; + uint32_t status; +}; +struct thread_pool { + pthread_t threads[MAX_THREADS]; + struct thread_job job[MAX_JOBQUEUE]; + pthread_mutex_t mutex; + pthread_cond_t cond; + int head; + int tail; + int queue; + int shutdown; +}; + +// Globals for thread pool +struct thread_pool pool; + +static inline int pool_has_space() +{ + return ((pool.head + 1) % MAX_JOBQUEUE) != pool.tail; +} + +static inline int pool_has_work() +{ + return (pool.queue != pool.head); +} + +int pool_get_work() +{ + assert(pool.queue != pool.head); + pool.queue = (pool.queue + 1) % MAX_JOBQUEUE; + return pool.queue; +} + +int pool_put_work(struct isal_zstream *stream) +{ + pthread_mutex_lock(&pool.mutex); + if (!pool_has_space() || pool.shutdown) { + pthread_mutex_unlock(&pool.mutex); + return 1; + } + int idx = (pool.head + 1) % MAX_JOBQUEUE; + pool.job[idx].next_in = stream->next_in; + pool.job[idx].avail_in = stream->avail_in; + pool.job[idx].next_out = stream->next_out; + pool.job[idx].avail_out = stream->avail_out; + pool.job[idx].status = JOB_ALLOCATED; + pool.job[idx].type = stream->end_of_stream == 0 ? 0 : 1; + pool.head = idx; + pthread_cond_signal(&pool.cond); + pthread_mutex_unlock(&pool.mutex); + return 0; +} + +void *thread_worker(void *none) +{ + struct isal_zstream wstream; + int check; + int work_idx; + int level = global_options.level; + int level_size = level_size_buf[level]; + uint8_t *level_buf = malloc_safe(level_size); + log_print(VERBOSE, "Start worker\n"); + + while (!pool.shutdown) { + pthread_mutex_lock(&pool.mutex); + while (!pool_has_work() && !pool.shutdown) { + pthread_cond_wait(&pool.cond, &pool.mutex); + } + if (pool.shutdown) { + pthread_mutex_unlock(&pool.mutex); + continue; + } + + work_idx = pool_get_work(); + pthread_cond_signal(&pool.cond); + pthread_mutex_unlock(&pool.mutex); + + isal_deflate_stateless_init(&wstream); + wstream.next_in = pool.job[work_idx].next_in; + wstream.next_out = pool.job[work_idx].next_out; + wstream.avail_in = pool.job[work_idx].avail_in; + wstream.avail_out = pool.job[work_idx].avail_out; + wstream.end_of_stream = pool.job[work_idx].type; + wstream.flush = FULL_FLUSH; + wstream.level = global_options.level; + wstream.level_buf = level_buf; + wstream.level_buf_size = level_size; + + check = isal_deflate_stateless(&wstream); + log_print(VERBOSE, "Worker finished job %d, out=%d\n", + work_idx, wstream.total_out); + + pool.job[work_idx].total_out = wstream.total_out; + pool.job[work_idx].status = JOB_SUCCESS + check; // complete or fail + if (check) + break; + } + free(level_buf); + log_print(VERBOSE, "Worker quit\n"); + pthread_exit(NULL); +} + +int pool_create() +{ + int i; + int nthreads = global_options.threads - 1; + pool.head = 0; + pool.tail = 0; + pool.queue = 0; + pool.shutdown = 0; + for (i = 0; i < nthreads; i++) + pthread_create(&pool.threads[i], NULL, thread_worker, NULL); + + log_print(VERBOSE, "Created %d pool threads\n", nthreads); + return 0; +} + +void pool_quit() +{ + int i; + pthread_mutex_lock(&pool.mutex); + pool.shutdown = 1; + pthread_mutex_unlock(&pool.mutex); + pthread_cond_broadcast(&pool.cond); + for (i = 0; i < global_options.threads - 1; i++) + pthread_join(pool.threads[i], NULL); + log_print(VERBOSE, "Deleted %d pool threads\n", i); +} + +#endif // defined(HAVE_THREADS) + +int compress_file(void) +{ + FILE *in = NULL, *out = NULL; + unsigned char *inbuf = NULL, *outbuf = NULL, *level_buf = NULL; + size_t inbuf_size, outbuf_size; + int level_size = 0; + struct isal_zstream stream; + struct isal_gzip_header gz_hdr; + int ret, success = 0; + + char *infile_name = global_options.infile_name; + char *outfile_name = global_options.outfile_name; + char *allocated_name = NULL; + char *suffix = global_options.suffix; + size_t infile_name_len = global_options.infile_name_len; + size_t outfile_name_len = global_options.outfile_name_len; + size_t suffix_len = global_options.suffix_len; + + int level = global_options.level; + + if (suffix == NULL) { + suffix = default_suffixes[0]; + suffix_len = default_suffixes_lens[0]; + } + + if (infile_name_len == stdin_file_name_len && + infile_name != NULL && + memcmp(infile_name, stdin_file_name, infile_name_len) == 0) { + infile_name = NULL; + infile_name_len = 0; + } + + if (outfile_name == NULL && infile_name != NULL && !global_options.use_stdout) { + outfile_name_len = infile_name_len + suffix_len; + allocated_name = malloc_safe(outfile_name_len + 1); + outfile_name = allocated_name; + strncpy(outfile_name, infile_name, infile_name_len + 1); + strncat(outfile_name, suffix, outfile_name_len + 1); + } + + open_in_file(&in, infile_name); + if (in == NULL) + goto compress_file_cleanup; + + if (infile_name_len != 0 && infile_name_len == outfile_name_len + && infile_name != NULL && outfile_name != NULL + && strncmp(infile_name, outfile_name, infile_name_len) == 0) { + log_print(ERROR, "igzip: Error input and output file names must differ\n"); + goto compress_file_cleanup; + } + + open_out_file(&out, outfile_name); + if (out == NULL) + goto compress_file_cleanup; + + inbuf_size = global_options.in_buf_size; + outbuf_size = global_options.out_buf_size; + + inbuf = global_options.in_buf; + outbuf = global_options.out_buf; + level_size = global_options.level_buf_size; + level_buf = global_options.level_buf; + + isal_gzip_header_init(&gz_hdr); + if (global_options.name == NAME_DEFAULT || global_options.name == YES_NAME) { + gz_hdr.time = get_posix_filetime(in); + gz_hdr.name = infile_name; + } + gz_hdr.os = UNIX; + gz_hdr.name_buf_len = infile_name_len + 1; + + isal_deflate_init(&stream); + stream.avail_in = 0; + stream.flush = NO_FLUSH; + stream.level = level; + stream.level_buf = level_buf; + stream.level_buf_size = level_size; + stream.gzip_flag = IGZIP_GZIP_NO_HDR; + stream.next_out = outbuf; + stream.avail_out = outbuf_size; + + isal_write_gzip_header(&stream, &gz_hdr); + + if (global_options.threads > 1) { +#if defined(HAVE_THREADS) + int q; + int end_of_stream = 0; + uint32_t crc = 0; + uint64_t total_in = 0; + + // Write the header + fwrite_safe(outbuf, 1, stream.total_out, out, outfile_name); + + do { + size_t nread; + size_t inbuf_used = 0; + size_t outbuf_used = 0; + uint8_t *iptr = inbuf; + uint8_t *optr = outbuf; + + for (q = 0; q < MAX_JOBQUEUE - 1; q++) { + inbuf_used += BLOCK_SIZE; + outbuf_used += 2 * BLOCK_SIZE; + if (inbuf_used > inbuf_size || outbuf_used > outbuf_size) + break; + + nread = fread_safe(iptr, 1, BLOCK_SIZE, in, infile_name); + crc = crc32_gzip_refl(crc, iptr, nread); + end_of_stream = feof(in); + total_in += nread; + stream.next_in = iptr; + stream.next_out = optr; + stream.avail_in = nread; + stream.avail_out = 2 * BLOCK_SIZE; + stream.end_of_stream = end_of_stream; + ret = pool_put_work(&stream); + if (ret || end_of_stream) + break; + + iptr += BLOCK_SIZE; + optr += 2 * BLOCK_SIZE; + } + + while (pool.tail != pool.head) { // Unprocessed jobs + int t = (pool.tail + 1) % MAX_JOBQUEUE; + if (pool.job[t].status >= JOB_SUCCESS) { // Finished next + if (pool.job[t].status > JOB_SUCCESS) { + success = 0; + log_print(ERROR, + "igzip: Error encountered while compressing file %s\n", + infile_name); + goto compress_file_cleanup; + } + fwrite_safe(pool.job[t].next_out, 1, + pool.job[t].total_out, out, outfile_name); + + pool.job[t].total_out = 0; + pool.job[t].status = 0; + pool.tail = t; + pthread_cond_broadcast(&pool.cond); + } + // Pick up a job while we wait + pthread_mutex_lock(&pool.mutex); + if (!pool_has_work()) { + pthread_mutex_unlock(&pool.mutex); + continue; + } + + int work_idx = pool_get_work(); + pthread_cond_signal(&pool.cond); + pthread_mutex_unlock(&pool.mutex); + + isal_deflate_stateless_init(&stream); + stream.next_in = pool.job[work_idx].next_in; + stream.next_out = pool.job[work_idx].next_out; + stream.avail_in = pool.job[work_idx].avail_in; + stream.avail_out = pool.job[work_idx].avail_out; + stream.end_of_stream = pool.job[work_idx].type; + stream.flush = FULL_FLUSH; + stream.level = global_options.level; + stream.level_buf = level_buf; + stream.level_buf_size = level_size; + int check = isal_deflate_stateless(&stream); + log_print(VERBOSE, "Self finished job %d, out=%d\n", + work_idx, stream.total_out); + pool.job[work_idx].total_out = stream.total_out; + pool.job[work_idx].status = JOB_SUCCESS + check; // complete or fail + } + } while (!end_of_stream); + + // Write gzip trailer + fwrite_safe(&crc, sizeof(uint32_t), 1, out, outfile_name); + fwrite_safe(&total_in, sizeof(uint32_t), 1, out, outfile_name); + +#else // No compiled threading support but asked for threads > 1 + assert(1); +#endif + } else { // Single thread + do { + if (stream.avail_in == 0) { + stream.next_in = inbuf; + stream.avail_in = + fread_safe(stream.next_in, 1, inbuf_size, in, infile_name); + stream.end_of_stream = feof(in); + } + + if (stream.next_out == NULL) { + stream.next_out = outbuf; + stream.avail_out = outbuf_size; + } + + ret = isal_deflate(&stream); + + if (ret != ISAL_DECOMP_OK) { + log_print(ERROR, + "igzip: Error encountered while compressing file %s\n", + infile_name); + goto compress_file_cleanup; + } + + fwrite_safe(outbuf, 1, stream.next_out - outbuf, out, outfile_name); + stream.next_out = NULL; + + } while (!feof(in) || stream.avail_out == 0); + } + + success = 1; + + compress_file_cleanup: + if (out != NULL && out != stdout) + fclose(out); + + if (in != NULL && in != stdin) { + fclose(in); + if (success && global_options.remove) + remove(infile_name); + } + + if (allocated_name != NULL) + free(allocated_name); + + return (success == 0); +} + +int decompress_file(void) +{ + FILE *in = NULL, *out = NULL; + unsigned char *inbuf = NULL, *outbuf = NULL; + size_t inbuf_size, outbuf_size; + struct inflate_state state; + struct isal_gzip_header gz_hdr; + const int terminal = 0, implicit = 1, stripped = 2; + int ret = 0, success = 0, outfile_type = terminal; + + char *infile_name = global_options.infile_name; + char *outfile_name = global_options.outfile_name; + char *allocated_name = NULL; + char *suffix = global_options.suffix; + size_t infile_name_len = global_options.infile_name_len; + size_t outfile_name_len = global_options.outfile_name_len; + size_t suffix_len = global_options.suffix_len; + int suffix_index = 0; + uint32_t file_time; + + // Allocate mem and setup to hold gzip header info + if (infile_name_len == stdin_file_name_len && + infile_name != NULL && + memcmp(infile_name, stdin_file_name, infile_name_len) == 0) { + infile_name = NULL; + infile_name_len = 0; + } + + if (outfile_name == NULL && !global_options.use_stdout) { + if (infile_name != NULL) { + outfile_type = stripped; + while (suffix_index < + sizeof(default_suffixes) / sizeof(*default_suffixes)) { + if (suffix == NULL) { + suffix = default_suffixes[suffix_index]; + suffix_len = default_suffixes_lens[suffix_index]; + suffix_index++; + } + + outfile_name_len = infile_name_len - suffix_len; + if (infile_name_len >= suffix_len + && memcmp(infile_name + outfile_name_len, suffix, + suffix_len) == 0) + break; + suffix = NULL; + suffix_len = 0; + } + + if (suffix == NULL && global_options.test == NO_TEST) { + log_print(ERROR, "igzip: %s: unknown suffix -- ignored\n", + infile_name); + return 1; + } + } + if (global_options.name == YES_NAME) { + outfile_name_len = 0; + outfile_type = implicit; + } + if (outfile_type != terminal) { + allocated_name = malloc_safe(outfile_name_len >= + MAX_FILEPATH_BUF ? outfile_name_len + + 1 : MAX_FILEPATH_BUF); + outfile_name = allocated_name; + } + } + + open_in_file(&in, infile_name); + if (in == NULL) + goto decompress_file_cleanup; + + file_time = get_posix_filetime(in); + + inbuf_size = global_options.in_buf_size; + outbuf_size = global_options.out_buf_size; + inbuf = global_options.in_buf; + outbuf = global_options.out_buf; + + isal_gzip_header_init(&gz_hdr); + if (outfile_type == implicit) { + gz_hdr.name = outfile_name; + gz_hdr.name_buf_len = MAX_FILEPATH_BUF; + } + + isal_inflate_init(&state); + state.crc_flag = ISAL_GZIP_NO_HDR_VER; + state.next_in = inbuf; + state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name); + + // Actually read and save the header info + ret = isal_read_gzip_header(&state, &gz_hdr); + if (ret != ISAL_DECOMP_OK) { + log_print(ERROR, "igzip: Error invalid gzip header found for file %s\n", + infile_name); + goto decompress_file_cleanup; + } + + if (outfile_type == implicit) + file_time = gz_hdr.time; + + if (outfile_name != NULL && infile_name != NULL + && (outfile_type == stripped + || (outfile_type == implicit && outfile_name[0] == 0))) { + outfile_name_len = infile_name_len - suffix_len; + memcpy(outfile_name, infile_name, outfile_name_len); + outfile_name[outfile_name_len] = 0; + } + + if (infile_name_len != 0 && infile_name_len == outfile_name_len + && infile_name != NULL && outfile_name != NULL + && strncmp(infile_name, outfile_name, infile_name_len) == 0) { + log_print(ERROR, "igzip: Error input and output file names must differ\n"); + goto decompress_file_cleanup; + } + + if (global_options.test == NO_TEST) { + open_out_file(&out, outfile_name); + if (out == NULL) + goto decompress_file_cleanup; + } + + // Start reading in compressed data and decompress + do { + if (state.avail_in == 0) { + state.next_in = inbuf; + state.avail_in = + fread_safe(state.next_in, 1, inbuf_size, in, infile_name); + } + + state.next_out = outbuf; + state.avail_out = outbuf_size; + + ret = isal_inflate(&state); + if (ret != ISAL_DECOMP_OK) { + log_print(ERROR, + "igzip: Error encountered while decompressing file %s\n", + infile_name); + goto decompress_file_cleanup; + } + + if (out != NULL) + fwrite_safe(outbuf, 1, state.next_out - outbuf, out, outfile_name); + + } while (state.block_state != ISAL_BLOCK_FINISH // while not done + && (!feof(in) || state.avail_out == 0) // and work to do + ); + + // Add the following to look for and decode additional concatenated files + if (!feof(in) && state.avail_in == 0) { + state.next_in = inbuf; + state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name); + } + + while (state.avail_in > 0 && state.next_in[0] == 31) { + // Look for magic numbers for gzip header. Follows the gzread() decision + // whether to treat as trailing junk + if (state.avail_in > 1 && state.next_in[1] != 139) + break; + + isal_inflate_reset(&state); + state.crc_flag = ISAL_GZIP; // Let isal_inflate() process extra headers + do { + if (state.avail_in == 0 && !feof(in)) { + state.next_in = inbuf; + state.avail_in = + fread_safe(state.next_in, 1, inbuf_size, in, infile_name); + } + + state.next_out = outbuf; + state.avail_out = outbuf_size; + + ret = isal_inflate(&state); + if (ret != ISAL_DECOMP_OK) { + log_print(ERROR, + "igzip: Error while decompressing extra concatenated" + "gzip files on %s\n", infile_name); + goto decompress_file_cleanup; + } + + if (out != NULL) + fwrite_safe(outbuf, 1, state.next_out - outbuf, out, + outfile_name); + + } while (state.block_state != ISAL_BLOCK_FINISH + && (!feof(in) || state.avail_out == 0)); + + if (!feof(in) && state.avail_in == 0) { + state.next_in = inbuf; + state.avail_in = + fread_safe(state.next_in, 1, inbuf_size, in, infile_name); + } + } + + if (state.block_state != ISAL_BLOCK_FINISH) + log_print(ERROR, "igzip: Error %s does not contain a complete gzip file\n", + infile_name); + else + success = 1; + + decompress_file_cleanup: + if (out != NULL && out != stdout) { + fclose(out); + if (success) + set_filetime(outfile_name, file_time); + } + + if (in != NULL && in != stdin) { + fclose(in); + if (success && global_options.remove) + remove(infile_name); + } + + if (allocated_name != NULL) + free(allocated_name); + + return (success == 0); +} + +int main(int argc, char *argv[]) +{ + int c; + char optstring[] = "hcdz0123456789o:S:kfqVvNntT:"; + int long_only_flag; + int ret = 0; + int bad_option = 0; + int bad_level = 0; + int bad_c = 0; + + struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"stdout", no_argument, NULL, 'c'}, + {"to-stdout", no_argument, NULL, 'c'}, + {"compress", no_argument, NULL, 'z'}, + {"decompress", no_argument, NULL, 'd'}, + {"uncompress", no_argument, NULL, 'd'}, + {"keep", no_argument, NULL, 'k'}, + {"rm", no_argument, &long_only_flag, RM}, + {"suffix", no_argument, NULL, 'S'}, + {"fast", no_argument, NULL, '1'}, + {"best", no_argument, NULL, '0' + ISAL_DEF_MAX_LEVEL}, + {"force", no_argument, NULL, 'f'}, + {"quiet", no_argument, NULL, 'q'}, + {"version", no_argument, NULL, 'V'}, + {"verbose", no_argument, NULL, 'v'}, + {"no-name", no_argument, NULL, 'n'}, + {"name", no_argument, NULL, 'N'}, + {"test", no_argument, NULL, 't'}, + {"threads", required_argument, NULL, 'T'}, + /* Possible future extensions + {"recursive, no_argument, NULL, 'r'}, + {"list", no_argument, NULL, 'l'}, + {"benchmark", optional_argument, NULL, 'b'}, + {"benchmark_end", required_argument, NULL, 'e'}, + */ + {0, 0, 0, 0} + }; + + init_options(&global_options); + + opterr = 0; + while ((c = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + if (c >= '0' && c <= '9') { + if (c > '0' + ISAL_DEF_MAX_LEVEL) + bad_level = 1; + else + global_options.level = c - '0'; + + continue; + } + + switch (c) { + case 0: + switch (long_only_flag) { + case RM: + global_options.remove = true; + break; + default: + bad_option = 1; + bad_c = c; + break; + } + break; + case 'o': + global_options.outfile_name = optarg; + global_options.outfile_name_len = strlen(global_options.outfile_name); + break; + case 'c': + global_options.use_stdout = true; + break; + case 'z': + global_options.mode = COMPRESS_MODE; + break; + case 'd': + global_options.mode = DECOMPRESS_MODE; + break; + case 'S': + global_options.suffix = optarg; + global_options.suffix_len = strlen(global_options.suffix); + break; + case 'k': + global_options.remove = false; + break; + case 'f': + global_options.force = true; + break; + case 'q': + global_options.quiet_level++; + break; + case 'v': + global_options.verbose_level++; + break; + case 'V': + print_version(); + return 0; + case 'N': + global_options.name = YES_NAME; + break; + case 'n': + global_options.name = NO_NAME; + break; + case 't': + global_options.test = TEST; + global_options.mode = DECOMPRESS_MODE; + break; + case 'T': +#if defined(HAVE_THREADS) + c = atoi(optarg); + c = c > MAX_THREADS ? MAX_THREADS : c; + c = c < 1 ? 1 : c; + global_options.threads = c; +#endif + break; + case 'h': + usage(0); + default: + bad_option = 1; + bad_c = optopt; + break; + } + } + + if (bad_option) { + log_print(ERROR, "igzip: invalid option "); + if (bad_c) + log_print(ERROR, "-%c\n", bad_c); + + else + log_print(ERROR, ("\n")); + + usage(BAD_OPTION); + } + + if (bad_level) { + log_print(ERROR, "igzip: invalid compression level\n"); + usage(BAD_LEVEL); + } + + if (global_options.outfile_name && optind < argc - 1) { + log_print(ERROR, + "igzip: An output file may be specified with only one input file\n"); + return 0; + } + + global_options.in_buf_size = BLOCK_SIZE; + global_options.out_buf_size = BLOCK_SIZE; + +#if defined(HAVE_THREADS) + if (global_options.threads > 1) { + global_options.in_buf_size += (BLOCK_SIZE * MAX_JOBQUEUE); + global_options.out_buf_size += (BLOCK_SIZE * MAX_JOBQUEUE * 2); + pool_create(); + } +#endif + global_options.in_buf = malloc_safe(global_options.in_buf_size); + global_options.out_buf = malloc_safe(global_options.out_buf_size); + global_options.level_buf_size = level_size_buf[global_options.level]; + global_options.level_buf = malloc_safe(global_options.level_buf_size); + + if (global_options.mode == COMPRESS_MODE) { + if (optind >= argc) + ret |= compress_file(); + while (optind < argc) { + global_options.infile_name = argv[optind]; + global_options.infile_name_len = strlen(global_options.infile_name); + ret |= compress_file(); + optind++; + } + + } else if (global_options.mode == DECOMPRESS_MODE) { + if (optind >= argc) + ret |= decompress_file(); + while (optind < argc) { + global_options.infile_name = argv[optind]; + global_options.infile_name_len = strlen(global_options.infile_name); + ret |= decompress_file(); + optind++; + } + } +#if defined(HAVE_THREADS) + if (global_options.threads > 1) + pool_quit(); +#endif + + free(global_options.in_buf); + free(global_options.out_buf); + free(global_options.level_buf); + return ret; +} diff --git a/src/isa-l/programs/igzip_cli_check.sh b/src/isa-l/programs/igzip_cli_check.sh new file mode 100755 index 000000000..5d97763c6 --- /dev/null +++ b/src/isa-l/programs/igzip_cli_check.sh @@ -0,0 +1,261 @@ +#! /bin/bash +set -o pipefail + +CWD=$PWD +SRC_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +IGZIP="$SRC_DIR/igzip $@" +TEST_DIR="/tmp/igzip_cli_test_$$/" +TEST_FILE=$SRC_DIR/igzip +DIFF="diff -q" + +mkdir -p $TEST_DIR +cd $TEST_DIR + +cleanup () +{ + cd $CWD + rm -rf $TEST_DIR + exit $1 +} + +clear_dir () +{ + cd /tmp/ + rm -rf $TEST_DIR + mkdir -p $TEST_DIR + cd $TEST_DIR +} + +pass_check() +{ + if [ $1 -eq 0 ]; then + echo -e "\e[1;32mPass\e[0;39m: " $2 + else + echo -e "\e[1;31mFail\e[0;39m: " $2 + cleanup 1 + fi +} + +fail_check() +{ + if [ $1 -ne 0 ]; then + echo -e "\e[1;32mPass\e[0;39m: " $2 + else + echo -e "\e[1;31mFail\e[0;39m: " $2 + cleanup 1 + fi +} + +file1=tmp +file2=jnk +file3=blah +bad_file=not_a_file +dir=this_is_a_directory + +default_suffix=".gz" +ds=$default_suffix +gzip_standard_suffixes=(".gz" ".z") +bad_suffix=".bad" +custom_suffix=".custom" + +# Test basic compression and decompression +ret=0 +cp $TEST_FILE $file1 +$IGZIP $file1 && rm $file1 || ret=1 +for suffix in ${gzip_standard_suffixes[@]}; do + if [ "$ds" != "$suffix" ]; then + cp -u $file1$ds $file1$suffix + fi + $IGZIP -d $file1$suffix && $DIFF $file1 $TEST_FILE || ret=1 + rm $file1 +done +pass_check $ret "Basic compression and decompression" +clear_dir + +# Test piping +cat $TEST_FILE | $IGZIP | $IGZIP -d | $DIFF $TEST_FILE - || ret=1 +cat $TEST_FILE | $IGZIP - | $IGZIP -d - | $DIFF $TEST_FILE - || ret=1 +pass_check $ret "Piping compression and decompression" + +# Test multiple concatenated gzip files +ret=0 +(for i in `seq 3`; do $IGZIP -c $TEST_FILE ; done) | $IGZIP -t || ret=1 +pass_check $ret "Multiple gzip concatenated files" + +if command -V md5sum >/dev/null 2>&1; then + sum1=$((for i in `seq 15`; do $IGZIP -c $TEST_FILE; done) | $IGZIP -cd | md5sum) + sum2=$((for i in `seq 15`; do cat $TEST_FILE; done) | md5sum) + [[ "$sum1" == "$sum2" ]] && ret=0 || ret=1 + pass_check $ret "Multiple large gzip concat test" + clear_dir +else + echo "Skip: Multiple large gzip concat test" +fi + + +#Test outifle options +$IGZIP $TEST_FILE -o $file2$ds && $IGZIP $file2$ds -d -o $file1 && \ + test -f $file2$ds && test -f $file1 && $DIFF $TEST_FILE $file1 +pass_check $? "Setting outfile name" +clear_dir + +# Not a file test +ret=0 +$IGZIP $bad_file &> /dev/null && ret=1 +test -f $bad_file$ds && ret=1 +pass_check $ret "Bad file" +clear_dir + +# Multiple files +cp $TEST_FILE $file1 && cp $TEST_FILE $file2 && cp $TEST_FILE $file3 && \ + $IGZIP $file1 $file2 $file3 && rm $file1 && rm $file2 && rm $file3 && \ + $IGZIP -d $file1$ds $file2$ds $file3$ds && \ + $DIFF $TEST_FILE $file1 && $DIFF $TEST_FILE $file2 && $DIFF $TEST_FILE $file3 +pass_check $? "Multiple files compression and decompression" +clear_dir + +# Multiple files, one doesn't exist +ret=0 +cp $TEST_FILE $file1 && cp $TEST_FILE $file2 || ret=1 +$IGZIP $file1 $bad_file $file2 &> /dev/null && ret=1 +rm $file1 && rm $file2 || ret=1 +$IGZIP -d $file1$ds $bad_file$ds $file2$ds &> /dev/null && ret=1 +$DIFF $TEST_FILE $file1 && $DIFF $TEST_FILE $file2 || ret=1 +pass_check $ret "Multiple files with a bad file" +clear_dir + +# Custom suffix test +cp $TEST_FILE $file1 && $IGZIP -S $custom_suffix $file1 && rm $file1 && \ + $IGZIP -d -S $custom_suffix $file1$custom_suffix && $DIFF $TEST_FILE $file1 +pass_check $? "Custom suffix" + +# Bad suffix test +ret=0 +cp $TEST_FILE $file1 && $IGZIP -S $bad_suffix $file1 && rm $file1 || ret=1 +$IGZIP -d $file1$custom_suffix &> /dev/null && ret=1 +pass_check $ret "Bad suffix" +clear_dir + +# Remove file test +ret=0 +cp $TEST_FILE $file1 && $IGZIP --rm $file1 || ret=1 +test -f $file1 && ret=1 +$IGZIP --rm -d $file1$ds || ret=1 +test -f $file1$ds && ret=1 +pass_check $ret "Remove file" +clear_dir + +# Pass a directory negative test +ret=0 +mkdir -p $dir || ret=0 +$IGZIP $dir &> /dev/null && ret=1 +clear_dir + +mkdir -p $dir$ds || ret=1 +$IGZIP -d $dir &> /dev/null && ret=1 +pass_check $ret "Compress/Decompress Directory without -r" +clear_dir + +# Write permissions test +cp $TEST_FILE $file1 +chmod 400 $file1 +chmod 500 $TEST_DIR +$IGZIP $file1 &> /dev/null +fail_check $? "don't have write permissions" +chmod -R 700 $TEST_DIR +clear_dir + +# Read permissions test +cp $TEST_FILE $file1 +chmod 000 $file1 +$IGZIP $file1 &> /dev/null +fail_check $? "don't have read permissions" +clear_dir + +# File overwrite test -f +ret=0 +cp $TEST_FILE $file1 && touch $file1$ds || ret=1 +yes | $IGZIP $file1 &> /dev/null && ret=1 +$IGZIP -f $file1 &> /dev/null && cp $file1$ds $file1 || ret=1 +yes | $IGZIP -d $file1 &> /dev/null && ret=1 +$IGZIP -df $file1$ds &> /dev/null && $DIFF $TEST_FILE $file1 || ret=1 +pass_check $ret "Existing file overwrite only with force" +clear_dir + +# Quiet suppresses interactivity +ret=0 +cp $TEST_FILE $file1 && touch $file1$ds || ret=1 +$IGZIP -q $file1 &> /dev/null && ret=1 +$IGZIP -dq $file1 &> /dev/null && ret=1 +pass_check $ret "Quiet will not overwrite" +clear_dir + +# Input file and output file cannot be the same +ret=0 +cp $TEST_FILE $file1 && $IGZIP $file1 -o $file1 &> /dev/null && ret=1 +$DIFF $TEST_FILE $file1 &> /dev/null || ret=1 +pass_check $ret "No in place compression" +clear_dir + +# Input file and output file cannot be the same +ret=0 +cp $TEST_FILE $file1 && $IGZIP $file1 -o $file1$ds &> /dev/null || ret=1 +$IGZIP -do $file1 $file1 &> /dev/null && ret=1 +$DIFF $TEST_FILE $file1 &> /dev/null || ret=1 +pass_check $ret "No in place decompression" +clear_dir + +ret=0 +$IGZIP -n $TEST_FILE -o $file1$ds && $IGZIP -Nd $file1$ds && $DIFF $file1 $TEST_FILE || ret=1 +pass_check $ret "Decompress name with no-name info" +clear_dir + +ret=0 +cp -p $TEST_FILE $file1 && sleep 1 &&\ +$IGZIP -N $file1 -o $file1$ds && $IGZIP -Nfqd $file1$ds || ret=1 +TIME_ORIG=$(stat --printf=\("%Y\n"\) $TEST_FILE) +TIME_NEW=$(stat --printf=\("%Y\n"\) $file1) +if [ "$TIME_ORIG" != "$TIME_NEW" ] ; then + ret=1 +fi +pass_check $ret "Decompress with name info" +clear_dir + +ret=0 +cp -p $TEST_FILE $file1 && touch $file2\\ +$IGZIP $file1 -o $file1$ds || ret=1 +$IGZIP -t $file1$ds || ret=1 +$IGZIP -t $file2 &> /dev/null && ret=1 +cp $file1$ds $file2 && $IGZIP -t $file1$ds || ret=1 +truncate -s -1 $file1$ds +$IGZIP -t $file1$ds &> /dev/null && ret=1 +pass_check $ret "Test test" +clear_dir + +# Large stream test with threading if enabled +ret=0 +(for i in `seq 100`; do cat $TEST_FILE ; done) | $IGZIP -c -T 4 | $IGZIP -t || ret=1 +pass_check $ret "Large stream test" + + +# Large stream tests with decompression and threading if enabled +if command -V md5sum >/dev/null 2>&1 && command -V dd >/dev/null 2>&1; then + ret=0 + dd if=<(for i in `seq 1000`; do cat $TEST_FILE; done) iflag=fullblock bs=1M count=201 2> out.stder | tee >(md5sum > out.sum1) \ + | $IGZIP -c -T 4 | $IGZIP -d | md5sum > out.sum2 \ + && $DIFF out.sum1 out.sum2 || ret=1 + pass_check $ret "Large stream compresss test" + clear_dir + + if test -e /dev/urandom; then + ret=0 + dd if=/dev/urandom iflag=fullblock bs=1M count=200 2> out.stder | tee >(md5sum > out.sum3) \ + | $IGZIP -c -T 2 | $IGZIP -d | md5sum > out.sum4 \ + && $DIFF out.sum3 out.sum4 || ret=1 + pass_check $ret "Large stream random data test" + clear_dir + fi +fi + +echo "Passed all cli checks" +cleanup 0 |