"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "pigz.c" between
pigz-2.5.tar.gz and pigz-2.6.tar.gz

About: pigz is a parallel implementation of gzip for modern multi-processor, multi-core machines.

pigz.c  (pigz-2.5):pigz.c  (pigz-2.6)
/* pigz.c -- parallel implementation of gzip /* pigz.c -- parallel implementation of gzip
* Copyright (C) 2007-2021 Mark Adler * Copyright (C) 2007-2021 Mark Adler
* Version 2.5 23 Jan 2021 Mark Adler * Version 2.6 6 Feb 2021 Mark Adler
*/ */
/* /*
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages warranty. In no event will the author be held liable for any damages
arising from the use of this software. arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions: freely, subject to the following restrictions:
skipping to change at line 198 skipping to change at line 198
Fix sign error in compression reduction percentage Fix sign error in compression reduction percentage
2.5 23 Jan 2021 Add --alias/-A option to set .zip name for stdin input 2.5 23 Jan 2021 Add --alias/-A option to set .zip name for stdin input
Add --comment/-C option to add comment in .gz or .zip Add --comment/-C option to add comment in .gz or .zip
Fix a bug that misidentified a multi-entry .zip Fix a bug that misidentified a multi-entry .zip
Fix a bug that did not emit double syncs for -i -p 1 Fix a bug that did not emit double syncs for -i -p 1
Fix a bug in yarn that could try to access freed data Fix a bug in yarn that could try to access freed data
Do not delete multi-entry .zip files when extracting Do not delete multi-entry .zip files when extracting
Do not reject .zip entries with bit 11 set Do not reject .zip entries with bit 11 set
Avoid a possible threads lock-order inversion Avoid a possible threads lock-order inversion
Ignore trailing junk after a gzip stream by default Ignore trailing junk after a gzip stream by default
2.6 6 Feb 2021 Add --huffman/-H and --rle/U strategy options
Fix issue when compiling for no threads
Fail silently on a broken pipe
*/ */
#define VERSION "pigz 2.5" #define VERSION "pigz 2.6"
/* To-do: /* To-do:
- make source portable for Windows, VMS, etc. (see gzip source code) - make source portable for Windows, VMS, etc. (see gzip source code)
- make build portable (currently good for Unixish) - make build portable (currently good for Unixish)
*/ */
/* /*
pigz compresses using threads to make use of multiple processors and cores. pigz compresses using threads to make use of multiple processors and cores.
The input is broken up into 128 KB chunks with each compressed in parallel. The input is broken up into 128 KB chunks with each compressed in parallel.
The individual check value for each chunk is also calculated in parallel. The individual check value for each chunk is also calculated in parallel.
skipping to change at line 336 skipping to change at line 339
of compression threads. In the case that reading is fast as compared to of compression threads. In the case that reading is fast as compared to
compression, that number allows a second set of buffers to be read while the compression, that number allows a second set of buffers to be read while the
first set of compressions are being performed. The number of output buffers first set of compressions are being performed. The number of output buffers
is not directly limited, but is indirectly limited by the release of input is not directly limited, but is indirectly limited by the release of input
buffers to about the same number. buffers to about the same number.
*/ */
// Portability defines. // Portability defines.
#define _FILE_OFFSET_BITS 64 // Use large file functions #define _FILE_OFFSET_BITS 64 // Use large file functions
#define _LARGE_FILES // Same thing for AIX #define _LARGE_FILES // Same thing for AIX
#define _POSIX_C_SOURCE 200809L // For MinGW #define _XOPEN_SOURCE 700 // For POSIX 2008
// Included headers and what is expected from each. // Included headers and what is expected from each.
#include <stdio.h> // fflush(), fprintf(), fputs(), getchar(), putc(), #include <stdio.h> // fflush(), fprintf(), fputs(), getchar(), putc(),
// puts(), printf(), vasprintf(), stderr, EOF, NULL, // puts(), printf(), vasprintf(), stderr, EOF, NULL,
// SEEK_END, size_t, off_t // SEEK_END, size_t, off_t
#include <stdlib.h> // exit(), malloc(), free(), realloc(), atol(), atoi(), #include <stdlib.h> // exit(), malloc(), free(), realloc(), atol(), atoi(),
// getenv() // getenv()
#include <stdarg.h> // va_start(), va_arg(), va_end(), va_list #include <stdarg.h> // va_start(), va_arg(), va_end(), va_list
#include <string.h> // memset(), memchr(), memcpy(), strcmp(), strcpy(), #include <string.h> // memset(), memchr(), memcpy(), strcmp(), strcpy(),
// strncpy(), strlen(), strcat(), strrchr(), // strncpy(), strlen(), strcat(), strrchr(),
skipping to change at line 541 skipping to change at line 544
int recurse; // true to dive down into directory structure int recurse; // true to dive down into directory structure
char *sufx; // suffix to use (".gz" or user supplied) char *sufx; // suffix to use (".gz" or user supplied)
char *name; // name for gzip or zip header char *name; // name for gzip or zip header
char *alias; // name for zip header when input is stdin char *alias; // name for zip header when input is stdin
char *comment; // comment for gzip or zip header. char *comment; // comment for gzip or zip header.
time_t mtime; // time stamp from input file for gzip header time_t mtime; // time stamp from input file for gzip header
int list; // true to list files instead of compress int list; // true to list files instead of compress
int first; // true if we need to print listing header int first; // true if we need to print listing header
int decode; // 0 to compress, 1 to decompress, 2 to test int decode; // 0 to compress, 1 to decompress, 2 to test
int level; // compression level int level; // compression level
int strategy; // compression strategy
#ifndef NOZOPFLI #ifndef NOZOPFLI
ZopfliOptions zopts; // zopfli compression options ZopfliOptions zopts; // zopfli compression options
#endif #endif
int rsync; // true for rsync blocking int rsync; // true for rsync blocking
int procs; // maximum number of compression threads (>= 1) int procs; // maximum number of compression threads (>= 1)
int setdict; // true to initialize dictionary in each thread int setdict; // true to initialize dictionary in each thread
size_t block; // uncompressed input size per thread (>= 32K) size_t block; // uncompressed input size per thread (>= 32K)
#ifndef NOTHREAD
crc_t shift; // pre-calculated CRC-32 shift for length block crc_t shift; // pre-calculated CRC-32 shift for length block
#endif
// saved gzip/zip header data for decompression, testing, and listing // saved gzip/zip header data for decompression, testing, and listing
time_t stamp; // time stamp from gzip header time_t stamp; // time stamp from gzip header
char *hname; // name from header (allocated) char *hname; // name from header (allocated)
char *hcomm; // comment from header (allocated) char *hcomm; // comment from header (allocated)
unsigned long zip_crc; // local header crc unsigned long zip_crc; // local header crc
length_t zip_clen; // local header compressed length length_t zip_clen; // local header compressed length
length_t zip_ulen; // local header uncompressed length length_t zip_ulen; // local header uncompressed length
int zip64; // true if has zip64 extended information int zip64; // true if has zip64 extended information
skipping to change at line 875 skipping to change at line 881
} }
// Show entries until no more, free log. // Show entries until no more, free log.
local void log_dump(void) { local void log_dump(void) {
if (log_tail == NULL) if (log_tail == NULL)
return; return;
while (log_show()) while (log_show())
; ;
log_free(); log_free();
if (mem_track.num || mem_track.size) if (mem_track.num || mem_track.size)
complain("memory leak: %lu allocs of %lu bytes total", complain("memory leak: %zu allocs of %zu bytes total",
mem_track.num, mem_track.size); mem_track.num, mem_track.size);
if (mem_track.max) if (mem_track.max)
fprintf(stderr, "%lu bytes of memory used in %lu allocs\n", fprintf(stderr, "%zu bytes of memory used in %zu allocs\n",
mem_track.max, mem_track.tot); mem_track.max, mem_track.tot);
} }
// Debugging macro. // Debugging macro.
#define Trace(x) \ #define Trace(x) \
do { \ do { \
if (g.verbosity > 2) { \ if (g.verbosity > 2) { \
log_add x; \ log_add x; \
} \ } \
} while (0) } while (0)
skipping to change at line 914 skipping to change at line 920
RELEASE(g.outf); RELEASE(g.outf);
g.outd = -1; g.outd = -1;
} }
log_dump(); log_dump();
_exit(sig < 0 ? -sig : EINTR); _exit(sig < 0 ? -sig : EINTR);
} }
// Common code for catch block of top routine in the thread. // Common code for catch block of top routine in the thread.
#define THREADABORT(ball) \ #define THREADABORT(ball) \
do { \ do { \
complain("abort: %s", (ball).why); \ if ((ball).code != EPIPE) \
complain("abort: %s", (ball).why); \
drop(ball); \ drop(ball); \
cut_short(-(ball).code); \ cut_short(-(ball).code); \
} while (0) } while (0)
// Compute next size up by multiplying by about 2**(1/3) and rounding to the // Compute next size up by multiplying by about 2**(1/3) and rounding to the
// next power of 2 if close (three applications results in doubling). If small, // next power of 2 if close (three applications results in doubling). If small,
// go up to at least 16, if overflow, go to max size_t value. // go up to at least 16, if overflow, go to max size_t value.
local inline size_t grow(size_t size) { local inline size_t grow(size_t size) {
size_t was, top; size_t was, top;
int shift; int shift;
skipping to change at line 994 skipping to change at line 1001
} }
return got; return got;
} }
// Write len bytes, repeating write() calls as needed. Return len. // Write len bytes, repeating write() calls as needed. Return len.
local size_t writen(int desc, void const *buf, size_t len) { local size_t writen(int desc, void const *buf, size_t len) {
char const *next = buf; char const *next = buf;
size_t left = len; size_t left = len;
while (left) { while (left) {
size_t const max = SIZE_MAX >> 1; // max ssize_t size_t const max = SSIZE_MAX;
ssize_t ret = write(desc, next, left > max ? max : left); ssize_t ret = write(desc, next, left > max ? max : left);
if (ret < 1) if (ret < 1)
throw(errno, "write error on %s (%s)", g.outf, strerror(errno)); throw(errno, "write error on %s (%s)", g.outf, strerror(errno));
next += ret; next += ret;
left -= (size_t)ret; left -= (size_t)ret;
} }
return len; return len;
} }
// Convert Unix time to MS-DOS date and time, assuming the current timezone. // Convert Unix time to MS-DOS date and time, assuming the current timezone.
skipping to change at line 1670 skipping to change at line 1677
local void compress_thread(void *dummy) { local void compress_thread(void *dummy) {
struct job *job; // job pulled and working on struct job *job; // job pulled and working on
struct job *here, **prior; // pointers for inserting in write list struct job *here, **prior; // pointers for inserting in write list
unsigned long check; // check value of input unsigned long check; // check value of input
unsigned char *next; // pointer for blocks, check value data unsigned char *next; // pointer for blocks, check value data
size_t left; // input left to process size_t left; // input left to process
size_t len; // remaining bytes to compress/check size_t len; // remaining bytes to compress/check
#if ZLIB_VERNUM >= 0x1260 #if ZLIB_VERNUM >= 0x1260
int bits; // deflate pending bits int bits; // deflate pending bits
#endif #endif
#ifndef NOZOPFLI
struct space *temp = NULL; // temporary space for zopfli input
#endif
int ret; // zlib return code int ret; // zlib return code
z_stream strm; // deflate stream
ball_t err; // error information from throw() ball_t err; // error information from throw()
(void)dummy; (void)dummy;
try { try {
// initialize the deflate stream for this thread z_stream strm; // deflate stream
strm.zfree = ZFREE; #ifndef NOZOPFLI
strm.zalloc = ZALLOC; struct space *temp = NULL;
strm.opaque = OPAQUE; // get temporary space for zopfli input
ret = deflateInit2(&strm, 6, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); if (g.level > 9)
if (ret == Z_MEM_ERROR) temp = get_space(&out_pool);
throw(ENOMEM, "not enough memory"); else
if (ret != Z_OK) #endif
throw(EINVAL, "internal error"); {
// initialize the deflate stream for this thread
strm.zfree = ZFREE;
strm.zalloc = ZALLOC;
strm.opaque = OPAQUE;
ret = deflateInit2(&strm, 6, Z_DEFLATED, -15, 8, g.strategy);
if (ret == Z_MEM_ERROR)
throw(ENOMEM, "not enough memory");
if (ret != Z_OK)
throw(EINVAL, "internal error");
}
// keep looking for work // keep looking for work
for (;;) { for (;;) {
// get a job (like I tell my son) // get a job (like I tell my son)
possess(compress_have); possess(compress_have);
wait_for(compress_have, NOT_TO_BE, 0); wait_for(compress_have, NOT_TO_BE, 0);
job = compress_head; job = compress_head;
assert(job != NULL); assert(job != NULL);
if (job->seq == -1) if (job->seq == -1)
break; break;
skipping to change at line 1712 skipping to change at line 1725
twist(compress_have, BY, -1); twist(compress_have, BY, -1);
// got a job -- initialize and set the compression level (note that // got a job -- initialize and set the compression level (note that
// if deflateParams() is called immediately after deflateReset(), // if deflateParams() is called immediately after deflateReset(),
// there is no need to initialize input/output for the stream) // there is no need to initialize input/output for the stream)
Trace(("-- compressing #%ld", job->seq)); Trace(("-- compressing #%ld", job->seq));
#ifndef NOZOPFLI #ifndef NOZOPFLI
if (g.level <= 9) { if (g.level <= 9) {
#endif #endif
(void)deflateReset(&strm); (void)deflateReset(&strm);
(void)deflateParams(&strm, g.level, Z_DEFAULT_STRATEGY); (void)deflateParams(&strm, g.level, g.strategy);
#ifndef NOZOPFLI #ifndef NOZOPFLI
} }
else { else
if (temp == NULL)
temp = get_space(&out_pool);
temp->len = 0; temp->len = 0;
}
#endif #endif
// set dictionary if provided, release that input or dictionary // set dictionary if provided, release that input or dictionary
// buffer (not NULL if g.setdict is true and if this is not the // buffer (not NULL if g.setdict is true and if this is not the
// first work unit) // first work unit)
if (job->out != NULL) { if (job->out != NULL) {
len = job->out->len; len = job->out->len;
left = len < DICT ? len : DICT; left = len < DICT ? len : DICT;
#ifndef NOZOPFLI #ifndef NOZOPFLI
if (g.level <= 9) if (g.level <= 9)
skipping to change at line 1913 skipping to change at line 1923
drop_space(job->in); drop_space(job->in);
job->check = check; job->check = check;
Trace(("-- checked #%ld%s", job->seq, job->more ? "" : " (last)")); Trace(("-- checked #%ld%s", job->seq, job->more ? "" : " (last)"));
possess(job->calc); possess(job->calc);
twist(job->calc, TO, 1); twist(job->calc, TO, 1);
// done with that one -- go find another job // done with that one -- go find another job
} }
// found job with seq == -1 -- return to join // found job with seq == -1 -- return to join
release(compress_have);
#ifndef NOZOPFLI #ifndef NOZOPFLI
drop_space(temp); if (g.level > 9)
drop_space(temp);
else
#endif #endif
release(compress_have); {
(void)deflateEnd(&strm); (void)deflateEnd(&strm);
}
} }
catch (err) { catch (err) {
THREADABORT(err); THREADABORT(err);
} }
} }
// Collect the write jobs off of the list in sequence order and write out the // Collect the write jobs off of the list in sequence order and write out the
// compressed data until the last chunk is written. Also write the header and // compressed data until the last chunk is written. Also write the header and
// trailer and combine the individual check values of the input buffers. // trailer and combine the individual check values of the input buffers.
local void write_thread(void *dummy) { local void write_thread(void *dummy) {
skipping to change at line 2273 skipping to change at line 2287
int ret; // zlib return code int ret; // zlib return code
out_size = g.block > MAXP2 ? MAXP2 : (unsigned)g.block; out_size = g.block > MAXP2 ? MAXP2 : (unsigned)g.block;
in = alloc(NULL, g.block + DICT); in = alloc(NULL, g.block + DICT);
next = alloc(NULL, g.block + DICT); next = alloc(NULL, g.block + DICT);
out = alloc(NULL, out_size); out = alloc(NULL, out_size);
strm = alloc(NULL, sizeof(z_stream)); strm = alloc(NULL, sizeof(z_stream));
strm->zfree = ZFREE; strm->zfree = ZFREE;
strm->zalloc = ZALLOC; strm->zalloc = ZALLOC;
strm->opaque = OPAQUE; strm->opaque = OPAQUE;
ret = deflateInit2(strm, 6, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); ret = deflateInit2(strm, 6, Z_DEFLATED, -15, 8, g.strategy);
if (ret == Z_MEM_ERROR) if (ret == Z_MEM_ERROR)
throw(ENOMEM, "not enough memory"); throw(ENOMEM, "not enough memory");
if (ret != Z_OK) if (ret != Z_OK)
throw(EINVAL, "internal error"); throw(EINVAL, "internal error");
} }
// write header // write header
head = put_header(); head = put_header();
// set compression level in case it changed // set compression level in case it changed
#ifndef NOZOPFLI #ifndef NOZOPFLI
if (g.level <= 9) { if (g.level <= 9) {
#endif #endif
(void)deflateReset(strm); (void)deflateReset(strm);
(void)deflateParams(strm, g.level, Z_DEFAULT_STRATEGY); (void)deflateParams(strm, g.level, g.strategy);
#ifndef NOZOPFLI #ifndef NOZOPFLI
} }
#endif #endif
// do raw deflate and calculate check value // do raw deflate and calculate check value
got = 0; got = 0;
more = readn(g.ind, next, g.block); more = readn(g.ind, next, g.block);
ulen = more; ulen = more;
start = 0; start = 0;
hist = 0; hist = 0;
skipping to change at line 3079 skipping to change at line 3093
char mod[26]; // modification time in text char mod[26]; // modification time in text
char tag[NAMEMAX1+1]; // header or file name, possibly truncated char tag[NAMEMAX1+1]; // header or file name, possibly truncated
// create abbreviated name from header file name or actual file name // create abbreviated name from header file name or actual file name
max = g.verbosity > 1 ? NAMEMAX2 : NAMEMAX1; max = g.verbosity > 1 ? NAMEMAX2 : NAMEMAX1;
memset(tag, 0, max + 1); memset(tag, 0, max + 1);
if (cont) if (cont)
strncpy(tag, "<...>", max + 1); strncpy(tag, "<...>", max + 1);
else if (g.hname == NULL) { else if (g.hname == NULL) {
n = strlen(g.inf) - compressed_suffix(g.inf); n = strlen(g.inf) - compressed_suffix(g.inf);
strncpy(tag, g.inf, n > max + 1 ? max + 1 : n); memcpy(tag, g.inf, n > max + 1 ? max + 1 : n);
if (strcmp(g.inf + n, ".tgz") == 0 && n < max + 1) if (strcmp(g.inf + n, ".tgz") == 0 && n < max + 1)
strncpy(tag + n, ".tar", max + 1 - n); strncpy(tag + n, ".tar", max + 1 - n);
} }
else else
strncpy(tag, g.hname, max + 1); strncpy(tag, g.hname, max + 1);
if (tag[max]) if (tag[max])
strcpy(tag + max - 3, "..."); strcpy(tag + max - 3, "...");
// convert time stamp to text // convert time stamp to text
if (g.stamp) { if (g.stamp) {
skipping to change at line 3803 skipping to change at line 3817
// --- file processing --- // --- file processing ---
// Extract file name from path. // Extract file name from path.
local char *justname(char *path) { local char *justname(char *path) {
char *p; char *p;
p = strrchr(path, '/'); p = strrchr(path, '/');
return p == NULL ? path : p + 1; return p == NULL ? path : p + 1;
} }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
// Copy file attributes, from -> to, as best we can. This is best effort, so no // Copy file attributes, from -> to, as best we can. This is best effort, so no
// errors are reported. The mode bits, including suid, sgid, and the sticky bit // errors are reported. The mode bits, including suid, sgid, and the sticky bit
// are copied (if allowed), the owner's user id and group id are copied (again // are copied (if allowed), the owner's user id and group id are copied (again
// if allowed), and the access and modify times are copied. // if allowed), and the access and modify times are copied.
local void copymeta(char *from, char *to) { local int copymeta(char *from, char *to) {
struct stat st; struct stat st;
struct timeval times[2]; struct timeval times[2];
// get all of from's Unix meta data, return if not a regular file // get all of from's Unix meta data, return if not a regular file
if (stat(from, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG) if (stat(from, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
return; return -4;
// set to's mode bits, ignore errors // set to's mode bits, ignore errors
(void)chmod(to, st.st_mode & 07777); int ret = chmod(to, st.st_mode & 07777);
// copy owner's user and group, ignore errors // copy owner's user and group, ignore errors
(void)chown(to, st.st_uid, st.st_gid); ret += chown(to, st.st_uid, st.st_gid);
// copy access and modify times, ignore errors // copy access and modify times, ignore errors
times[0].tv_sec = st.st_atime; times[0].tv_sec = st.st_atime;
times[0].tv_usec = 0; times[0].tv_usec = 0;
times[1].tv_sec = st.st_mtime; times[1].tv_sec = st.st_mtime;
times[1].tv_usec = 0; times[1].tv_usec = 0;
(void)utimes(to, times); ret += utimes(to, times);
return ret;
} }
#pragma GCC diagnostic pop
// Set the access and modify times of fd to t. // Set the access and modify times of fd to t.
local void touch(char *path, time_t t) { local void touch(char *path, time_t t) {
struct timeval times[2]; struct timeval times[2];
times[0].tv_sec = t; times[0].tv_sec = t;
times[0].tv_usec = 0; times[0].tv_usec = 0;
times[1].tv_sec = t; times[1].tv_sec = t;
times[1].tv_usec = 0; times[1].tv_usec = 0;
(void)utimes(path, times); (void)utimes(path, times);
} }
skipping to change at line 4206 skipping to change at line 4216
" -A, --alias xxx Use xxx as the name for any --zip entry from stdin", " -A, --alias xxx Use xxx as the name for any --zip entry from stdin",
" -b, --blocksize mmm Set compression block size to mmmK (default 128K)", " -b, --blocksize mmm Set compression block size to mmmK (default 128K)",
" -c, --stdout Write all processed output to stdout (won't delete)", " -c, --stdout Write all processed output to stdout (won't delete)",
" -C, --comment ccc Put comment ccc in the gzip or zip header", " -C, --comment ccc Put comment ccc in the gzip or zip header",
" -d, --decompress Decompress the compressed input", " -d, --decompress Decompress the compressed input",
" -f, --force Force overwrite, compress .gz, links, and to terminal", " -f, --force Force overwrite, compress .gz, links, and to terminal",
#ifndef NOZOPFLI #ifndef NOZOPFLI
" -F --first Do iterations first, before block split for -11", " -F --first Do iterations first, before block split for -11",
#endif #endif
" -h, --help Display a help screen and quit", " -h, --help Display a help screen and quit",
" -H, --huffman Use only Huffman coding for compression",
" -i, --independent Compress blocks independently for damage recovery", " -i, --independent Compress blocks independently for damage recovery",
#ifndef NOZOPFLI #ifndef NOZOPFLI
" -I, --iterations n Number of iterations for -11 optimization", " -I, --iterations n Number of iterations for -11 optimization",
" -J, --maxsplits n Maximum number of split blocks for -11", " -J, --maxsplits n Maximum number of split blocks for -11",
#endif #endif
" -k, --keep Do not delete original file after processing", " -k, --keep Do not delete original file after processing",
" -K, --zip Compress to PKWare zip (.zip) single entry format", " -K, --zip Compress to PKWare zip (.zip) single entry format",
" -l, --list List the contents of the compressed input", " -l, --list List the contents of the compressed input",
" -L, --license Display the pigz license and quit", " -L, --license Display the pigz license and quit",
" -m, --no-time Do not store or restore mod time", " -m, --no-time Do not store or restore mod time",
skipping to change at line 4231 skipping to change at line 4242
#endif #endif
#ifndef NOTHREAD #ifndef NOTHREAD
" -p, --processes n Allow up to n compression threads (default is the", " -p, --processes n Allow up to n compression threads (default is the",
" number of online processors, or 8 if unknown)", " number of online processors, or 8 if unknown)",
#endif #endif
" -q, --quiet Print no messages, even on error", " -q, --quiet Print no messages, even on error",
" -r, --recursive Process the contents of all subdirectories", " -r, --recursive Process the contents of all subdirectories",
" -R, --rsyncable Input-determined block locations for rsync", " -R, --rsyncable Input-determined block locations for rsync",
" -S, --suffix .sss Use suffix .sss instead of .gz (for compression)", " -S, --suffix .sss Use suffix .sss instead of .gz (for compression)",
" -t, --test Test the integrity of the compressed input", " -t, --test Test the integrity of the compressed input",
" -U, --rle Use run-length encoding for compression",
#ifdef PIGZ_DEBUG #ifdef PIGZ_DEBUG
" -v, --verbose Provide more verbose output (-vv to debug)", " -v, --verbose Provide more verbose output (-vv to debug)",
#else #else
" -v, --verbose Provide more verbose output", " -v, --verbose Provide more verbose output",
#endif #endif
" -V --version Show the version of pigz", " -V --version Show the version of pigz",
" -Y --synchronous Force output file write to permanent storage", " -Y --synchronous Force output file write to permanent storage",
" -z, --zlib Compress to zlib (.zz) instead of gzip format", " -z, --zlib Compress to zlib (.zz) instead of gzip format",
" -- All arguments after \"--\" are treated as files" " -- All arguments after \"--\" are treated as files"
}; };
skipping to change at line 4280 skipping to change at line 4292
# endif # endif
# endif # endif
return n; return n;
} }
#endif #endif
// Set option defaults. // Set option defaults.
local void defaults(void) { local void defaults(void) {
g.level = Z_DEFAULT_COMPRESSION; g.level = Z_DEFAULT_COMPRESSION;
g.strategy = Z_DEFAULT_STRATEGY;
#ifndef NOZOPFLI #ifndef NOZOPFLI
// default zopfli options as set by ZopfliInitOptions(): // default zopfli options as set by ZopfliInitOptions():
// verbose = 0 // verbose = 0
// numiterations = 15 // numiterations = 15
// blocksplitting = 1 // blocksplitting = 1
// blocksplittinglast = 0 // blocksplittinglast = 0
// blocksplittingmax = 15 // blocksplittingmax = 15
ZopfliInitOptions(&g.zopts); ZopfliInitOptions(&g.zopts);
#endif #endif
g.block = 131072UL; // 128K
#ifdef NOTHREAD #ifdef NOTHREAD
g.procs = 1; g.procs = 1;
#else #else
g.procs = nprocs(8); g.procs = nprocs(8);
#endif
g.block = 131072UL; // 128K
g.shift = x2nmodp(g.block, 3); g.shift = x2nmodp(g.block, 3);
#endif
g.rsync = 0; // don't do rsync blocking g.rsync = 0; // don't do rsync blocking
g.setdict = 1; // initialize dictionary each thread g.setdict = 1; // initialize dictionary each thread
g.verbosity = 1; // normal message level g.verbosity = 1; // normal message level
g.headis = 3; // store name and time (low bits == 11), g.headis = 3; // store name and time (low bits == 11),
// restore neither (next bits == 00), // restore neither (next bits == 00),
// where 01 is name and 10 is time // where 01 is name and 10 is time
g.pipeout = 0; // don't force output to stdout g.pipeout = 0; // don't force output to stdout
g.sufx = ".gz"; // compressed file suffix g.sufx = ".gz"; // compressed file suffix
g.comment = NULL; // no comment g.comment = NULL; // no comment
g.decode = 0; // compress g.decode = 0; // compress
skipping to change at line 4327 skipping to change at line 4340
{"bits", "Z"}, {"blocksize", "b"}, {"decompress", "d"}, {"fast", "1"}, {"bits", "Z"}, {"blocksize", "b"}, {"decompress", "d"}, {"fast", "1"},
{"force", "f"}, {"comment", "C"}, {"force", "f"}, {"comment", "C"},
#ifndef NOZOPFLI #ifndef NOZOPFLI
{"first", "F"}, {"iterations", "I"}, {"maxsplits", "J"}, {"oneblock", "O"}, {"first", "F"}, {"iterations", "I"}, {"maxsplits", "J"}, {"oneblock", "O"},
#endif #endif
{"help", "h"}, {"independent", "i"}, {"keep", "k"}, {"license", "L"}, {"help", "h"}, {"independent", "i"}, {"keep", "k"}, {"license", "L"},
{"list", "l"}, {"name", "N"}, {"no-name", "n"}, {"no-time", "m"}, {"list", "l"}, {"name", "N"}, {"no-name", "n"}, {"no-time", "m"},
{"processes", "p"}, {"quiet", "q"}, {"recursive", "r"}, {"rsyncable", "R"}, {"processes", "p"}, {"quiet", "q"}, {"recursive", "r"}, {"rsyncable", "R"},
{"silent", "q"}, {"stdout", "c"}, {"suffix", "S"}, {"synchronous", "Y"}, {"silent", "q"}, {"stdout", "c"}, {"suffix", "S"}, {"synchronous", "Y"},
{"test", "t"}, {"time", "M"}, {"to-stdout", "c"}, {"uncompress", "d"}, {"test", "t"}, {"time", "M"}, {"to-stdout", "c"}, {"uncompress", "d"},
{"verbose", "v"}, {"version", "V"}, {"zip", "K"}, {"zlib", "z"}}; {"verbose", "v"}, {"version", "V"}, {"zip", "K"}, {"zlib", "z"},
{"huffman", "H"}, {"rle", "U"}};
#define NLOPTS (sizeof(longopts) / (sizeof(char *) << 1)) #define NLOPTS (sizeof(longopts) / (sizeof(char *) << 1))
// Either new buffer size, new compression level, or new number of processes. // Either new buffer size, new compression level, or new number of processes.
// Get rid of old buffers and threads to force the creation of new ones with // Get rid of old buffers and threads to force the creation of new ones with
// the new settings. // the new settings.
local void new_opts(void) { local void new_opts(void) {
single_compress(1); single_compress(1);
#ifndef NOTHREAD #ifndef NOTHREAD
finish_jobs(); finish_jobs();
#endif #endif
skipping to change at line 4422 skipping to change at line 4436
g.level = g.level * 10 + *++arg - '0'; g.level = g.level * 10 + *++arg - '0';
} }
if (g.level == 10 || g.level > 11) if (g.level == 10 || g.level > 11)
throw(EINVAL, "only levels 0..9 and 11 are allowed"); throw(EINVAL, "only levels 0..9 and 11 are allowed");
break; break;
case 'A': get = 6; break; case 'A': get = 6; break;
case 'C': get = 7; break; case 'C': get = 7; break;
#ifndef NOZOPFLI #ifndef NOZOPFLI
case 'F': g.zopts.blocksplittinglast = 1; break; case 'F': g.zopts.blocksplittinglast = 1; break;
case 'I': get = 4; break; case 'I': get = 4; break;
case 'H': g.strategy = Z_HUFFMAN_ONLY; break;
case 'J': get = 5; break; case 'J': get = 5; break;
#endif #endif
case 'K': g.form = 2; g.sufx = ".zip"; break; case 'K': g.form = 2; g.sufx = ".zip"; break;
case 'L': case 'L':
puts(VERSION); puts(VERSION);
puts("Copyright (C) 2007-2021 Mark Adler"); puts("Copyright (C) 2007-2021 Mark Adler");
puts("Subject to the terms of the zlib license."); puts("Subject to the terms of the zlib license.");
puts("No warranty is provided or implied."); puts("No warranty is provided or implied.");
exit(0); exit(0);
break; // avoid warning
case 'M': g.headis |= 0xa; break; case 'M': g.headis |= 0xa; break;
case 'N': g.headis = 0xf; break; case 'N': g.headis = 0xf; break;
#ifndef NOZOPFLI #ifndef NOZOPFLI
case 'O': g.zopts.blocksplitting = 0; break; case 'O': g.zopts.blocksplitting = 0; break;
#endif #endif
case 'R': g.rsync = 1; break; case 'R': g.rsync = 1; break;
case 'S': get = 3; break; case 'S': get = 3; break;
// -T defined below as an alternative for -m // -T defined below as an alternative for -m
case 'V': case 'V':
puts(VERSION); puts(VERSION);
if (g.verbosity > 1) if (g.verbosity > 1)
printf("zlib %s\n", zlibVersion()); printf("zlib %s\n", zlibVersion());
exit(0); exit(0);
break; // avoid warning
case 'Y': g.sync = 1; break; case 'Y': g.sync = 1; break;
case 'Z': case 'Z':
throw(EINVAL, "invalid option: LZW output not supported: %s", throw(EINVAL, "invalid option: LZW output not supported: %s",
bad); bad);
break; // avoid warning
case 'a': case 'a':
throw(EINVAL, "invalid option: no ascii conversion: %s", throw(EINVAL, "invalid option: no ascii conversion: %s",
bad); bad);
break; // avoid warning
case 'b': get = 1; break; case 'b': get = 1; break;
case 'c': g.pipeout = 1; break; case 'c': g.pipeout = 1; break;
case 'd': if (!g.decode) g.headis >>= 2; g.decode = 1; break; case 'd': if (!g.decode) g.headis >>= 2; g.decode = 1; break;
case 'f': g.force = 1; break; case 'f': g.force = 1; break;
case 'h': help(); break; case 'h': help(); break;
case 'i': g.setdict = 0; break; case 'i': g.setdict = 0; break;
case 'k': g.keep = 1; break; case 'k': g.keep = 1; break;
case 'l': g.list = 1; break; case 'l': g.list = 1; break;
case 'n': g.headis = 0; break; case 'n': g.headis = 0; break;
case 'T': case 'T':
case 'm': g.headis &= ~0xa; break; case 'm': g.headis &= ~0xa; break;
case 'p': get = 2; break; case 'p': get = 2; break;
case 'q': g.verbosity = 0; break; case 'q': g.verbosity = 0; break;
case 'r': g.recurse = 1; break; case 'r': g.recurse = 1; break;
case 't': g.decode = 2; break; case 't': g.decode = 2; break;
case 'U': g.strategy = Z_RLE; break;
case 'v': g.verbosity++; break; case 'v': g.verbosity++; break;
case 'z': g.form = 1; g.sufx = ".zz"; break; case 'z': g.form = 1; g.sufx = ".zz"; break;
default: default:
throw(EINVAL, "invalid option: %s", bad); throw(EINVAL, "invalid option: %s", bad);
} }
} while (*++arg); } while (*++arg);
if (*arg == 0) if (*arg == 0)
return 1; return 1;
} }
// process option parameter for -b, -p, -A, -S, -I, or -J // process option parameter for -b, -p, -A, -S, -I, or -J
if (get) { if (get) {
size_t n; size_t n;
if (get == 1) { if (get == 1) {
n = num(arg); n = num(arg);
g.block = n << 10; // chunk size g.block = n << 10; // chunk size
#ifndef NOTHREAD
g.shift = x2nmodp(g.block, 3); g.shift = x2nmodp(g.block, 3);
#endif
if (g.block < DICT) if (g.block < DICT)
throw(EINVAL, "block size too small (must be >= 32K)"); throw(EINVAL, "block size too small (must be >= 32K)");
if (n != g.block >> 10 || if (n != g.block >> 10 ||
OUTPOOL(g.block) < g.block || OUTPOOL(g.block) < g.block ||
(ssize_t)OUTPOOL(g.block) < 0 || (ssize_t)OUTPOOL(g.block) < 0 ||
g.block > (1UL << 29)) // limited by append_len() g.block > (1UL << 29)) // limited by append_len()
throw(EINVAL, "block size too large: %s", arg); throw(EINVAL, "block size too large: %s", arg);
} }
else if (get == 2) { else if (get == 2) {
n = num(arg); n = num(arg);
 End of changes. 45 change blocks. 
44 lines changed or deleted 66 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)