igzip: Create a command line utitlity

Change-Id: If283f03231ca3a5cd6f97d01c5268ad37cb3b538
Signed-off-by: Roy Oursler <roy.j.oursler@intel.com>
This commit is contained in:
Roy Oursler 2018-07-09 17:56:26 -07:00
parent ff1928e8ec
commit 2104a77d02
6 changed files with 1011 additions and 3 deletions

View File

@ -5,6 +5,7 @@ AM_MAKEFLAGS = --no-print-directory
noinst_HEADERS =
pkginclude_HEADERS = include/test.h include/types.h
noinst_LTLIBRARIES =
bin_PROGRAMS =
INCLUDE = -I $(srcdir)/include/
lsrc=
@ -24,6 +25,7 @@ lsrc_base_aliases=
lsrc32=
unit_tests32=
perf_tests32=
progs=
# Include units
@ -33,6 +35,7 @@ include crc/Makefile.am
include igzip/Makefile.am
include tests/fuzz/Makefile.am
include examples/ec/Makefile.am
include programs/Makefile.am
# LIB version info not necessarily the same as package version
LIBISAL_CURRENT=2
@ -75,6 +78,7 @@ EXTRA_PROGRAMS += ${other_tests}
EXTRA_PROGRAMS += ${examples}
CLEANFILES += ${EXTRA_PROGRAMS}
programs:${progs}
perfs: ${perf_tests}
tests: ${unit_tests}
checks: ${check_tests}

View File

@ -27,7 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
########################################################################
units = erasure_code raid crc igzip
units = erasure_code raid crc igzip programs
default: lib

View File

@ -106,7 +106,7 @@ objs = $(addprefix $(O)/,$(notdir $(lobj)))
lib_name ?= isa-l.a
default: lib slib
default: lib slib progs
# Defaults for windows build
ifeq ($(arch),win64)
@ -121,6 +121,7 @@ unit_testswin64 = $(unit_tests)
exampleswin64 = $(examples)
perf_testswin64 = $(perf_tests)
# Build and run unit tests, performance tests, etc.
all_tests = $(notdir $(sort $(perf_tests) $(check_tests) $(unit_tests) $(examples) $(other_tests)))
all_unit_tests = $(notdir $(sort $(check_tests) $(unit_tests)))
@ -140,6 +141,8 @@ $(all_llvm_fuzz_tests): % : %.o $(lib_name)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) $(FUZZLINK) -o $@
progs: $(bin_PROGRAMS)
$(bin_PROGRAMS): CFLAGS += -DVERSION=\"$(version)\"
sim test trace: $(addsuffix .run,$(all_unit_tests))
perf: $(addsuffix .run,$(all_perf_tests))
check: $(addsuffix .run,$(all_check_tests))
@ -178,6 +181,10 @@ $(all_tests):
@echo " ---> Building Test $@ $(msg)"
@$(LINK.o) $(CFLAGS) $^ $(LDLIBS) -o $@
$(bin_PROGRAMS): % : %_cli.c $(lib_name)
@echo " ---> Building Programs $@ $(msg)"
@$(LINK.o) $(CFLAGS) $^ $(LDLIBS) -o $@
# Target to build lib files
lib: $(lib_name)
@ -265,6 +272,7 @@ else
which libtool && libtool --mode=finish $(prefix)/lib || \
echo 'Lib installed at $(prefix)/lib. Run system-dependent programs to add shared lib path.'
endif
install -m 774 $(bin_PROGRAMS) $(prefix)/bin/.
uninstall:
$(RM) $(prefix)/lib/libisal.a
@ -274,6 +282,7 @@ uninstall:
$(RM) -r $(prefix)/include/isa-l
$(RM) $(prefix)/include/isa-l.h
$(RM) $(prefix)/lib/$(basename $(so_lib_inst)).dylib
$(RM) $(prefix)/bin/$(notdir $(bin_PROGRAMS))
# Collect performance data
rpt_name = perf_report_$(shell uname -n)_$(shell date +%y%m%d).perf
@ -287,7 +296,7 @@ perf_report:
clean:
@echo Cleaning up
@$(RM) -r $(O) *.o *.a $(all_tests) $(lib_name) $(so_lib_name) $(all_llvm_fuzz_tests)
@$(RM) -r $(O) *.o *.a $(all_tests) $(bin_PROGRAMS) $(lib_name) $(so_lib_name) $(all_llvm_fuzz_tests)
doc: isa-l.h

33
programs/Makefile.am Normal file
View File

@ -0,0 +1,33 @@
########################################################################
# 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

784
programs/igzip_cli.c Normal file
View File

@ -0,0 +1,784 @@
/**********************************************************************
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 (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 UNIX 3
#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;
};
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->verbose_level = 0;
};
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] <infile>\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 ouput 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",
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;
char 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_files(FILE ** in, FILE ** out, char *infile_name, size_t infile_name_len,
char *outfile_name)
{
*in = NULL;
*out = NULL;
if (infile_name == NULL)
*in = stdin;
else
*in = fopen_safe(infile_name, "rb");
if (*in == NULL)
return;
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);
}
}
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, *outfile_name =
global_options.outfile_name;
char *suffix = global_options.suffix;
size_t infile_name_len = global_options.infile_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 &&
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 = malloc_safe(infile_name_len + suffix_len + 1);
strcpy(outfile_name, infile_name);
strcat(outfile_name, suffix);
}
open_files(&in, &out, infile_name, infile_name_len, outfile_name);
if (in == NULL || out == NULL)
goto compress_file_cleanup;
inbuf_size = BLOCK_SIZE;
outbuf_size = BLOCK_SIZE;
inbuf = malloc_safe(inbuf_size);
outbuf = malloc_safe(outbuf_size);
level_size = level_size_buf[level];
level_buf = malloc_safe(level_size);
isal_gzip_header_init(&gz_hdr);
gz_hdr.time = get_posix_filetime(in);
gz_hdr.os = UNIX;
gz_hdr.name = infile_name;
gz_hdr.name_buf_len = infile_name_len + 1;
isal_deflate_init(&stream);
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);
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 (global_options.outfile_name == NULL && outfile_name != NULL)
free(outfile_name);
if (inbuf != NULL)
free(inbuf);
if (outbuf != NULL)
free(outbuf);
if (level_buf != NULL)
free(level_buf);
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;
int ret = 0, success = 0;
char *infile_name = global_options.infile_name, *outfile_name =
global_options.outfile_name;
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;
if (infile_name_len == stdin_file_name_len &&
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) {
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) {
log_print(ERROR, "igzip: %s: unknown suffix -- ignored\n",
infile_name);
return 1;
}
outfile_name = malloc_safe(outfile_name_len + 1);
memcpy(outfile_name, infile_name, outfile_name_len);
outfile_name[outfile_name_len] = 0;
}
open_files(&in, &out, infile_name, infile_name_len, outfile_name);
if (in == NULL || out == NULL)
goto decompress_file_cleanup;
file_time = get_posix_filetime(in);
inbuf_size = BLOCK_SIZE;
outbuf_size = BLOCK_SIZE;
inbuf = malloc_safe(inbuf_size);
outbuf = malloc_safe(outbuf_size);
isal_gzip_header_init(&gz_hdr);
isal_inflate_init(&state);
state.crc_flag = IGZIP_GZIP_NO_HDR;
state.next_in = inbuf;
state.avail_in = fread_safe(state.next_in, 1, inbuf_size, in, infile_name);
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;
}
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;
}
fwrite_safe(outbuf, 1, state.next_out - outbuf, out, outfile_name);
} while (!feof(in) || state.avail_out == 0);
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 (global_options.outfile_name == NULL && outfile_name != NULL)
free(outfile_name);
if (inbuf != NULL)
free(inbuf);
if (outbuf != NULL)
free(outbuf);
return (success == 0);
}
int main(int argc, char *argv[])
{
int c;
char optstring[] = "hcdz0123456789o:S:kfqVv";
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'},
/* Possible future extensions
{"test", no_argument, NULL, 't'},
{"no-name", no_argument, NULL, 'n'},
{"name", no_argument, NULL, 'N'},
{"recursive, no_argument, NULL, 'r'},
{"check", no_argument, NULL, 'C'},
{"no-check", no_argument, NULL, 0},
{"list", no_argument, NULL, 'l'},
{"benchmark", optional_argument, NULL, 'b'},
{"benchmark_end", required_argument, NULL, 'e'},
{"threads", optional_argument, NULL, 'T'},
*/
{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 '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;
}
if (global_options.mode == COMPRESS_MODE) {
if (optind >= argc)
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)
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++;
}
}
return ret;
}

178
programs/igzip_cli_check.sh Executable file
View File

@ -0,0 +1,178 @@
#! /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=$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 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
echo "Passed all cli checks"
cleanup 0