mirror of
https://github.com/ckolivas/lrzip.git
synced 2025-12-06 07:12:00 +01:00
rebase-of-function-split-and-control-additions-to-fu
This commit is contained in:
parent
f0828d5b38
commit
f6f0a25ef6
|
|
@ -31,6 +31,9 @@ lrztar_SCRIPTS = lrztar
|
||||||
bin_PROGRAMS = lrzip
|
bin_PROGRAMS = lrzip
|
||||||
lrzip_SOURCES = \
|
lrzip_SOURCES = \
|
||||||
zpipe.cpp \
|
zpipe.cpp \
|
||||||
|
liblrzip.h \
|
||||||
|
lrzip.c \
|
||||||
|
lrzip.h \
|
||||||
main.c \
|
main.c \
|
||||||
rzip.h \
|
rzip.h \
|
||||||
rzip.c \
|
rzip.c \
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/ioctl.h errno.h)
|
||||||
|
|
||||||
AC_TYPE_OFF_T
|
AC_TYPE_OFF_T
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
|
AC_C___ATTRIBUTE__
|
||||||
AC_CHECK_SIZEOF(int)
|
AC_CHECK_SIZEOF(int)
|
||||||
AC_CHECK_SIZEOF(long)
|
AC_CHECK_SIZEOF(long)
|
||||||
AC_CHECK_SIZEOF(short)
|
AC_CHECK_SIZEOF(short)
|
||||||
|
|
|
||||||
70
liblrzip.h
Normal file
70
liblrzip.h
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2006-2011 Con Kolivas
|
||||||
|
Copyright (C) 2011 Peter Hyman
|
||||||
|
Copyright (C) 1998-2003 Andrew Tridgell
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(LIBLRZIP_H) && !defined(MAIN_C)
|
||||||
|
#define LIBLRZIP_H
|
||||||
|
|
||||||
|
#define FLAG_VERBOSE (FLAG_VERBOSITY | FLAG_VERBOSITY_MAX)
|
||||||
|
#define FLAG_NOT_LZMA (FLAG_NO_COMPRESS | FLAG_LZO_COMPRESS | FLAG_BZIP2_COMPRESS | FLAG_ZLIB_COMPRESS | FLAG_ZPAQ_COMPRESS)
|
||||||
|
#define LZMA_COMPRESS (!(control->flags & FLAG_NOT_LZMA))
|
||||||
|
|
||||||
|
#define SHOW_PROGRESS (control->flags & FLAG_SHOW_PROGRESS)
|
||||||
|
#define KEEP_FILES (control->flags & FLAG_KEEP_FILES)
|
||||||
|
#define TEST_ONLY (control->flags & FLAG_TEST_ONLY)
|
||||||
|
#define FORCE_REPLACE (control->flags & FLAG_FORCE_REPLACE)
|
||||||
|
#define DECOMPRESS (control->flags & FLAG_DECOMPRESS)
|
||||||
|
#define NO_COMPRESS (control->flags & FLAG_NO_COMPRESS)
|
||||||
|
#define LZO_COMPRESS (control->flags & FLAG_LZO_COMPRESS)
|
||||||
|
#define BZIP2_COMPRESS (control->flags & FLAG_BZIP2_COMPRESS)
|
||||||
|
#define ZLIB_COMPRESS (control->flags & FLAG_ZLIB_COMPRESS)
|
||||||
|
#define ZPAQ_COMPRESS (control->flags & FLAG_ZPAQ_COMPRESS)
|
||||||
|
#define VERBOSE (control->flags & FLAG_VERBOSE)
|
||||||
|
#define VERBOSITY (control->flags & FLAG_VERBOSITY)
|
||||||
|
#define MAX_VERBOSE (control->flags & FLAG_VERBOSITY_MAX)
|
||||||
|
#define STDIN (control->flags & FLAG_STDIN)
|
||||||
|
#define STDOUT (control->flags & FLAG_STDOUT)
|
||||||
|
#define INFO (control->flags & FLAG_INFO)
|
||||||
|
#define UNLIMITED (control->flags & FLAG_UNLIMITED)
|
||||||
|
#define HASH_CHECK (control->flags & FLAG_HASH)
|
||||||
|
#define HAS_MD5 (control->flags & FLAG_MD5)
|
||||||
|
#define CHECK_FILE (control->flags & FLAG_CHECK)
|
||||||
|
#define KEEP_BROKEN (control->flags & FLAG_KEEP_BROKEN)
|
||||||
|
#define LZO_TEST (control->flags & FLAG_THRESHOLD)
|
||||||
|
|
||||||
|
#define print_output(format, args...) do {\
|
||||||
|
fprintf(control->msgout, format, ##args); \
|
||||||
|
fflush(control->msgout); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_progress(format, args...) do {\
|
||||||
|
if (SHOW_PROGRESS) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_verbose(format, args...) do {\
|
||||||
|
if (VERBOSE) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_maxverbose(format, args...) do {\
|
||||||
|
if (MAX_VERBOSE) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
668
lrzip.c
Normal file
668
lrzip.c
Normal file
|
|
@ -0,0 +1,668 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2006-2011 Con Kolivas
|
||||||
|
Copyright (C) 2011 Peter Hyman
|
||||||
|
Copyright (C) 1998-2003 Andrew Tridgell
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rzip.h"
|
||||||
|
#include "liblrzip.h" /* flag defines */
|
||||||
|
|
||||||
|
void write_magic(rzip_control *control, int fd_in, int fd_out)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char magic[24];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(magic, 0, sizeof(magic));
|
||||||
|
strcpy(magic, "LRZI");
|
||||||
|
magic[4] = LRZIP_MAJOR_VERSION;
|
||||||
|
magic[5] = LRZIP_MINOR_VERSION;
|
||||||
|
|
||||||
|
if (unlikely(fstat(fd_in, &st)))
|
||||||
|
fatal("bad magic file descriptor!?\n");
|
||||||
|
|
||||||
|
memcpy(&magic[6], &control->st_size, 8);
|
||||||
|
|
||||||
|
/* save LZMA compression flags */
|
||||||
|
if (LZMA_COMPRESS) {
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
magic[i + 16] = (char)control->lzma_properties[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a flag that the archive contains an md5 sum at the end
|
||||||
|
* which can be used as an integrity check instead of crc check.
|
||||||
|
* crc is still stored for compatibility with 0.5 versions.
|
||||||
|
*/
|
||||||
|
magic[21] = 1;
|
||||||
|
|
||||||
|
if (unlikely(lseek(fd_out, 0, SEEK_SET)))
|
||||||
|
fatal("Failed to seek to BOF to write Magic Header\n");
|
||||||
|
|
||||||
|
if (unlikely(write(fd_out, magic, sizeof(magic)) != sizeof(magic)))
|
||||||
|
fatal("Failed to write magic header\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_magic(rzip_control *control, int fd_in, i64 *expected_size)
|
||||||
|
{
|
||||||
|
char magic[24];
|
||||||
|
uint32_t v;
|
||||||
|
int md5, i;
|
||||||
|
|
||||||
|
if (unlikely(read(fd_in, magic, sizeof(magic)) != sizeof(magic)))
|
||||||
|
fatal("Failed to read magic header\n");
|
||||||
|
|
||||||
|
*expected_size = 0;
|
||||||
|
|
||||||
|
if (unlikely(strncmp(magic, "LRZI", 4)))
|
||||||
|
failure("Not an lrzip file\n");
|
||||||
|
|
||||||
|
memcpy(&control->major_version, &magic[4], 1);
|
||||||
|
memcpy(&control->minor_version, &magic[5], 1);
|
||||||
|
|
||||||
|
/* Support the convoluted way we described size in versions < 0.40 */
|
||||||
|
if (control->major_version == 0 && control->minor_version < 4) {
|
||||||
|
memcpy(&v, &magic[6], 4);
|
||||||
|
*expected_size = ntohl(v);
|
||||||
|
memcpy(&v, &magic[10], 4);
|
||||||
|
*expected_size |= ((i64)ntohl(v)) << 32;
|
||||||
|
} else
|
||||||
|
memcpy(expected_size, &magic[6], 8);
|
||||||
|
|
||||||
|
/* restore LZMA compression flags only if stored */
|
||||||
|
if ((int) magic[16]) {
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
control->lzma_properties[i] = magic[i + 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whether this archive contains md5 data at the end or not */
|
||||||
|
md5 = magic[21];
|
||||||
|
if (md5 == 1)
|
||||||
|
control->flags |= FLAG_MD5;
|
||||||
|
|
||||||
|
print_verbose("Detected lrzip version %d.%d file.\n", control->major_version, control->minor_version);
|
||||||
|
if (control->major_version > LRZIP_MAJOR_VERSION ||
|
||||||
|
(control->major_version == LRZIP_MAJOR_VERSION && control->minor_version > LRZIP_MINOR_VERSION))
|
||||||
|
print_output("Attempting to work with file produced by newer lrzip version %d.%d file.\n", control->major_version, control->minor_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preserve ownership and permissions where possible */
|
||||||
|
void preserve_perms(rzip_control *control, int fd_in, int fd_out)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (unlikely(fstat(fd_in, &st)))
|
||||||
|
fatal("Failed to fstat input file\n");
|
||||||
|
if (unlikely(fchmod(fd_out, (st.st_mode & 0777))))
|
||||||
|
print_err("Warning, unable to set permissions on %s\n", control->outfile);
|
||||||
|
|
||||||
|
/* chown fail is not fatal */
|
||||||
|
if (unlikely(fchown(fd_out, st.st_uid, st.st_gid)))
|
||||||
|
print_err("Warning, unable to set owner on %s\n", control->outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open a temporary outputfile to emulate stdout */
|
||||||
|
int open_tmpoutfile(rzip_control *control)
|
||||||
|
{
|
||||||
|
int fd_out;
|
||||||
|
|
||||||
|
if (STDOUT)
|
||||||
|
print_verbose("Outputting to stdout.\n");
|
||||||
|
if (control->tmpdir) {
|
||||||
|
control->outfile = realloc(NULL, strlen(control->tmpdir)+16);
|
||||||
|
if (unlikely(!control->outfile))
|
||||||
|
fatal("Failed to allocate outfile name\n");
|
||||||
|
strcpy(control->outfile, control->tmpdir);
|
||||||
|
strcat(control->outfile, "lrzipout.XXXXXX");
|
||||||
|
} else {
|
||||||
|
control->outfile = realloc(NULL, 16);
|
||||||
|
if (unlikely(!control->outfile))
|
||||||
|
fatal("Failed to allocate outfile name\n");
|
||||||
|
strcpy(control->outfile, "lrzipout.XXXXXX");
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_out = mkstemp(control->outfile);
|
||||||
|
if (unlikely(fd_out == -1))
|
||||||
|
fatal("Failed to create out tmpfile: %s\n", strerror(errno));
|
||||||
|
register_outfile(control->outfile, TEST_ONLY || STDOUT || !KEEP_BROKEN);
|
||||||
|
return fd_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump temporary outputfile to perform stdout */
|
||||||
|
void dump_tmpoutfile(rzip_control *control, int fd_out)
|
||||||
|
{
|
||||||
|
FILE *tmpoutfp;
|
||||||
|
int tmpchar;
|
||||||
|
|
||||||
|
print_progress("Dumping to stdout.\n");
|
||||||
|
/* flush anything not yet in the temporary file */
|
||||||
|
fsync(fd_out);
|
||||||
|
tmpoutfp = fdopen(fd_out, "r");
|
||||||
|
if (unlikely(tmpoutfp == NULL))
|
||||||
|
fatal("Failed to fdopen out tmpfile: %s\n", strerror(errno));
|
||||||
|
rewind(tmpoutfp);
|
||||||
|
|
||||||
|
while ((tmpchar = fgetc(tmpoutfp)) != EOF)
|
||||||
|
putchar(tmpchar);
|
||||||
|
|
||||||
|
fflush(control->msgout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open a temporary inputfile to perform stdin decompression */
|
||||||
|
int open_tmpinfile(rzip_control *control)
|
||||||
|
{
|
||||||
|
int fd_in;
|
||||||
|
|
||||||
|
if (control->tmpdir) {
|
||||||
|
control->infile = malloc(strlen(control->tmpdir)+15);
|
||||||
|
if (unlikely(!control->infile))
|
||||||
|
fatal("Failed to allocate infile name\n");
|
||||||
|
strcpy(control->infile, control->tmpdir);
|
||||||
|
strcat(control->infile, "lrzipin.XXXXXX");
|
||||||
|
} else {
|
||||||
|
control->infile = malloc(15);
|
||||||
|
if (unlikely(!control->infile))
|
||||||
|
fatal("Failed to allocate infile name\n");
|
||||||
|
strcpy(control->infile, "lrzipin.XXXXXX");
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_in = mkstemp(control->infile);
|
||||||
|
if (unlikely(fd_in == -1))
|
||||||
|
fatal("Failed to create in tmpfile: %s\n", strerror(errno));
|
||||||
|
register_infile(control->infile, (DECOMPRESS || TEST_ONLY) && STDIN);
|
||||||
|
return fd_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read data from stdin into temporary inputfile */
|
||||||
|
void read_tmpinfile(rzip_control *control, int fd_in)
|
||||||
|
{
|
||||||
|
FILE *tmpinfp;
|
||||||
|
int tmpchar;
|
||||||
|
|
||||||
|
if (control->flags & FLAG_SHOW_PROGRESS)
|
||||||
|
fprintf(control->msgout, "Copying from stdin.\n");
|
||||||
|
tmpinfp = fdopen(fd_in, "w+");
|
||||||
|
if (unlikely(tmpinfp == NULL))
|
||||||
|
fatal("Failed to fdopen in tmpfile: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
while ((tmpchar = getchar()) != EOF)
|
||||||
|
fputc(tmpchar, tmpinfp);
|
||||||
|
|
||||||
|
fflush(tmpinfp);
|
||||||
|
rewind(tmpinfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
decompress one file from the command line
|
||||||
|
*/
|
||||||
|
void decompress_file(rzip_control *control)
|
||||||
|
{
|
||||||
|
char *tmp, *tmpoutfile, *infilecopy = NULL;
|
||||||
|
int fd_in, fd_out = -1, fd_hist = -1;
|
||||||
|
i64 expected_size, free_space;
|
||||||
|
struct statvfs fbuf;
|
||||||
|
|
||||||
|
if (!STDIN) {
|
||||||
|
if ((tmp = strrchr(control->infile, '.')) && strcmp(tmp,control->suffix)) {
|
||||||
|
/* make sure infile has an extension. If not, add it
|
||||||
|
* because manipulations may be made to input filename, set local ptr
|
||||||
|
*/
|
||||||
|
infilecopy = malloc(strlen(control->infile) + strlen(control->suffix) + 1);
|
||||||
|
if (unlikely(infilecopy == NULL))
|
||||||
|
fatal("Failed to allocate memory for infile suffix\n");
|
||||||
|
else {
|
||||||
|
strcpy(infilecopy, control->infile);
|
||||||
|
strcat(infilecopy, control->suffix);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
infilecopy = strdup(control->infile);
|
||||||
|
/* regardless, infilecopy has the input filename */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STDOUT && !TEST_ONLY) {
|
||||||
|
/* if output name already set, use it */
|
||||||
|
if (control->outname) {
|
||||||
|
control->outfile = strdup(control->outname);
|
||||||
|
} else {
|
||||||
|
/* default output name from infilecopy
|
||||||
|
* test if outdir specified. If so, strip path from filename of
|
||||||
|
* infilecopy, then remove suffix.
|
||||||
|
*/
|
||||||
|
if (control->outdir && (tmp = strrchr(infilecopy, '/')))
|
||||||
|
tmpoutfile = strdup(tmp + 1);
|
||||||
|
else
|
||||||
|
tmpoutfile = strdup(infilecopy);
|
||||||
|
|
||||||
|
/* remove suffix to make outfile name */
|
||||||
|
if ((tmp = strrchr(tmpoutfile, '.')) && !strcmp(tmp, control->suffix))
|
||||||
|
*tmp='\0';
|
||||||
|
|
||||||
|
control->outfile = malloc((control->outdir == NULL? 0: strlen(control->outdir)) + strlen(tmpoutfile) + 1);
|
||||||
|
if (unlikely(!control->outfile))
|
||||||
|
fatal("Failed to allocate outfile name\n");
|
||||||
|
|
||||||
|
if (control->outdir) { /* prepend control->outdir */
|
||||||
|
strcpy(control->outfile, control->outdir);
|
||||||
|
strcat(control->outfile, tmpoutfile);
|
||||||
|
} else
|
||||||
|
strcpy(control->outfile, tmpoutfile);
|
||||||
|
free(tmpoutfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STDOUT)
|
||||||
|
print_progress("Output filename is: %s...Decompressing...\n", control->outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STDIN) {
|
||||||
|
fd_in = open_tmpinfile(control);
|
||||||
|
read_tmpinfile(control, fd_in);
|
||||||
|
} else {
|
||||||
|
fd_in = open(infilecopy, O_RDONLY);
|
||||||
|
if (unlikely(fd_in == -1)) {
|
||||||
|
fatal("Failed to open %s: %s\n",
|
||||||
|
infilecopy,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TEST_ONLY | STDOUT)) {
|
||||||
|
if (FORCE_REPLACE)
|
||||||
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
else
|
||||||
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||||
|
if (unlikely(fd_out == -1)) {
|
||||||
|
/* We must ensure we don't delete a file that already
|
||||||
|
* exists just because we tried to create a new one */
|
||||||
|
control->flags |= FLAG_KEEP_BROKEN;
|
||||||
|
fatal("Failed to create %s: %s\n", control->outfile, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
preserve_perms(control, fd_in, fd_out);
|
||||||
|
} else
|
||||||
|
fd_out = open_tmpoutfile(control);
|
||||||
|
control->fd_out = fd_out;
|
||||||
|
|
||||||
|
/* Check if there's enough free space on the device chosen to fit the
|
||||||
|
* decompressed file. */
|
||||||
|
if (unlikely(fstatvfs(fd_out, &fbuf)))
|
||||||
|
fatal("Failed to fstatvfs in decompress_file\n");
|
||||||
|
free_space = fbuf.f_bsize * fbuf.f_bavail;
|
||||||
|
if (free_space < expected_size) {
|
||||||
|
if (FORCE_REPLACE)
|
||||||
|
print_err("Warning, inadequate free space detected, but attempting to decompress due to -f option being used.\n");
|
||||||
|
else
|
||||||
|
failure("Inadequate free space to decompress file, use -f to override.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_hist = open(control->outfile, O_RDONLY);
|
||||||
|
if (unlikely(fd_hist == -1))
|
||||||
|
fatal("Failed to open history file %s\n", control->outfile);
|
||||||
|
|
||||||
|
read_magic(control, fd_in, &expected_size);
|
||||||
|
if (NO_MD5)
|
||||||
|
print_verbose("Not performing MD5 hash check\n");
|
||||||
|
if (HAS_MD5)
|
||||||
|
print_verbose("MD5 ");
|
||||||
|
else
|
||||||
|
print_verbose("CRC32 ");
|
||||||
|
print_verbose("being used for integrity testing.\n");
|
||||||
|
|
||||||
|
print_progress("Decompressing...");
|
||||||
|
|
||||||
|
runzip_fd(control, fd_in, fd_out, fd_hist, expected_size);
|
||||||
|
|
||||||
|
if (STDOUT)
|
||||||
|
dump_tmpoutfile(control, fd_out);
|
||||||
|
|
||||||
|
/* if we get here, no fatal errors during decompression */
|
||||||
|
print_progress("\r");
|
||||||
|
if (!(STDOUT | TEST_ONLY))
|
||||||
|
print_output("Output filename is: %s: ", control->outfile);
|
||||||
|
print_progress("[OK] - %lld bytes \n", expected_size);
|
||||||
|
|
||||||
|
if (unlikely(close(fd_hist) || close(fd_out)))
|
||||||
|
fatal("Failed to close files\n");
|
||||||
|
|
||||||
|
if (TEST_ONLY | STDOUT) {
|
||||||
|
/* Delete temporary files generated for testing or faking stdout */
|
||||||
|
if (unlikely(unlink(control->outfile)))
|
||||||
|
fatal("Failed to unlink tmpfile: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd_in);
|
||||||
|
|
||||||
|
if (!(KEEP_FILES | TEST_ONLY) || STDIN) {
|
||||||
|
if (unlikely(unlink(control->infile)))
|
||||||
|
fatal("Failed to unlink %s: %s\n", infilecopy, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(control->outfile);
|
||||||
|
free(infilecopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_header_info(rzip_control *control, int fd_in, uchar *ctype, i64 *c_len, i64 *u_len, i64 *last_head)
|
||||||
|
{
|
||||||
|
if (unlikely(read(fd_in, ctype, 1) != 1))
|
||||||
|
fatal("Failed to read in get_header_info\n");
|
||||||
|
|
||||||
|
if (control->major_version == 0 && control->minor_version < 4) {
|
||||||
|
u32 c_len32, u_len32, last_head32;
|
||||||
|
|
||||||
|
if (unlikely(read(fd_in, &c_len32, 4) != 4))
|
||||||
|
fatal("Failed to read in get_header_info");
|
||||||
|
if (unlikely(read(fd_in, &u_len32, 4) != 4))
|
||||||
|
fatal("Failed to read in get_header_info");
|
||||||
|
if (unlikely(read(fd_in, &last_head32, 4) != 4))
|
||||||
|
fatal("Failed to read in get_header_info");
|
||||||
|
*c_len = c_len32;
|
||||||
|
*u_len = u_len32;
|
||||||
|
*last_head = last_head32;
|
||||||
|
} else {
|
||||||
|
if (unlikely(read(fd_in, c_len, 8) != 8))
|
||||||
|
fatal("Failed to read in get_header_info");
|
||||||
|
if (unlikely(read(fd_in, u_len, 8) != 8))
|
||||||
|
fatal("Failed to read in get_header_info");
|
||||||
|
if (unlikely(read(fd_in, last_head, 8) != 8))
|
||||||
|
fatal("Failed to read_i64 in get_header_info");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_fileinfo(rzip_control *control)
|
||||||
|
{
|
||||||
|
i64 expected_size, infile_size;
|
||||||
|
int seekspot, fd_in;
|
||||||
|
long double cratio;
|
||||||
|
uchar ctype = 0;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
char *tmp, *infilecopy = NULL;
|
||||||
|
|
||||||
|
if (!STDIN) {
|
||||||
|
if ((tmp = strrchr(control->infile, '.')) && strcmp(tmp,control->suffix)) {
|
||||||
|
infilecopy = malloc(strlen(control->infile) + strlen(control->suffix) + 1);
|
||||||
|
if (unlikely(infilecopy == NULL))
|
||||||
|
fatal("Failed to allocate memory for infile suffix\n");
|
||||||
|
else {
|
||||||
|
strcpy(infilecopy, control->infile);
|
||||||
|
strcat(infilecopy, control->suffix);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
infilecopy = strdup(control->infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STDIN)
|
||||||
|
fd_in = 0;
|
||||||
|
else {
|
||||||
|
fd_in = open(infilecopy, O_RDONLY);
|
||||||
|
if (unlikely(fd_in == -1))
|
||||||
|
fatal("Failed to open %s: %s\n", infilecopy, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get file size */
|
||||||
|
if (unlikely(fstat(fd_in, &st)))
|
||||||
|
fatal("bad magic file descriptor!?\n");
|
||||||
|
memcpy(&infile_size, &st.st_size, 8);
|
||||||
|
|
||||||
|
/* Get decompressed size */
|
||||||
|
read_magic(control, fd_in, &expected_size);
|
||||||
|
|
||||||
|
/* Version < 0.4 had different file format */
|
||||||
|
if (control->major_version == 0 && control->minor_version < 4)
|
||||||
|
seekspot = 50;
|
||||||
|
else if (control->major_version == 0 && control->minor_version == 4)
|
||||||
|
seekspot = 74;
|
||||||
|
else
|
||||||
|
seekspot = 75;
|
||||||
|
if (unlikely(lseek(fd_in, seekspot, SEEK_SET) == -1))
|
||||||
|
fatal("Failed to lseek in get_fileinfo: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
/* Read the compression type of the first block. It's possible that
|
||||||
|
not all blocks are compressed so this may not be accurate.
|
||||||
|
*/
|
||||||
|
if (unlikely(read(fd_in, &ctype, 1) != 1))
|
||||||
|
fatal("Failed to read in get_fileinfo\n");
|
||||||
|
|
||||||
|
cratio = (long double)expected_size / (long double)infile_size;
|
||||||
|
|
||||||
|
print_output("%s:\nlrzip version: %d.%d file\n", infilecopy, control->major_version, control->minor_version);
|
||||||
|
print_output("Compression: ");
|
||||||
|
if (ctype == CTYPE_NONE)
|
||||||
|
print_output("rzip alone\n");
|
||||||
|
else if (ctype == CTYPE_BZIP2)
|
||||||
|
print_output("rzip + bzip2\n");
|
||||||
|
else if (ctype == CTYPE_LZO)
|
||||||
|
print_output("rzip + lzo\n");
|
||||||
|
else if (ctype == CTYPE_LZMA)
|
||||||
|
print_output("rzip + lzma\n");
|
||||||
|
else if (ctype == CTYPE_GZIP)
|
||||||
|
print_output("rzip + gzip\n");
|
||||||
|
else if (ctype == CTYPE_ZPAQ)
|
||||||
|
print_output("rzip + zpaq\n");
|
||||||
|
else
|
||||||
|
print_output("Dunno wtf\n");
|
||||||
|
print_output("Decompressed file size: %llu\n", expected_size);
|
||||||
|
print_output("Compressed file size: %llu\n", infile_size);
|
||||||
|
print_output("Compression ratio: %.3Lf\n", cratio);
|
||||||
|
|
||||||
|
if (HAS_MD5) {
|
||||||
|
char md5_stored[MD5_DIGEST_SIZE];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
print_output("MD5 used for integrity testing\n");
|
||||||
|
if (unlikely(lseek(fd_in, -MD5_DIGEST_SIZE, SEEK_END)) == -1)
|
||||||
|
fatal("Failed to seek to md5 data in runzip_fd\n");
|
||||||
|
if (unlikely(read(fd_in, md5_stored, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
|
||||||
|
fatal("Failed to read md5 data in runzip_fd\n");
|
||||||
|
print_output("MD5: ");
|
||||||
|
for (i = 0; i < MD5_DIGEST_SIZE; i++)
|
||||||
|
print_output("%02x", md5_stored[i] & 0xFF);
|
||||||
|
print_output("\n");
|
||||||
|
} else
|
||||||
|
print_output("CRC32 used for integrity testing\n");
|
||||||
|
|
||||||
|
if (VERBOSE || MAX_VERBOSE) {
|
||||||
|
i64 u_len, c_len, last_head, utotal = 0, ctotal = 0, ofs = 25,
|
||||||
|
stream_head[2];
|
||||||
|
int header_length = 25, stream = 0, chunk = 0;
|
||||||
|
|
||||||
|
if (control->major_version == 0 && control->minor_version < 4)
|
||||||
|
header_length = 13;
|
||||||
|
next_chunk:
|
||||||
|
stream = 0;
|
||||||
|
stream_head[0] = 0;
|
||||||
|
stream_head[1] = stream_head[0] + header_length;
|
||||||
|
|
||||||
|
print_output("Rzip chunk %d:\n", ++chunk);
|
||||||
|
while (stream < NUM_STREAMS) {
|
||||||
|
int block = 1;
|
||||||
|
|
||||||
|
if (unlikely(lseek(fd_in, stream_head[stream] + ofs, SEEK_SET)) == -1)
|
||||||
|
fatal("Failed to seek to header data in get_fileinfo\n");
|
||||||
|
get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head);
|
||||||
|
|
||||||
|
print_output("Stream: %d\n", stream);
|
||||||
|
print_maxverbose("Offset: %lld\n", ofs);
|
||||||
|
print_output("Block\tComp\tPercent\tSize\n");
|
||||||
|
do {
|
||||||
|
i64 head_off;
|
||||||
|
|
||||||
|
if (unlikely(last_head + ofs > infile_size))
|
||||||
|
failure("Offset greater than archive size, likely corrupted/truncated archive.\n");
|
||||||
|
if (unlikely(head_off = lseek(fd_in, last_head + ofs, SEEK_SET)) == -1)
|
||||||
|
fatal("Failed to seek to header data in get_fileinfo\n");
|
||||||
|
get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head);
|
||||||
|
if (unlikely(last_head < 0 || c_len < 0 || u_len < 0))
|
||||||
|
failure("Entry negative, likely corrupted archive.\n");
|
||||||
|
print_output("%d\t", block);
|
||||||
|
if (ctype == CTYPE_NONE)
|
||||||
|
print_output("none");
|
||||||
|
else if (ctype == CTYPE_BZIP2)
|
||||||
|
print_output("bzip2");
|
||||||
|
else if (ctype == CTYPE_LZO)
|
||||||
|
print_output("lzo");
|
||||||
|
else if (ctype == CTYPE_LZMA)
|
||||||
|
print_output("lzma");
|
||||||
|
else if (ctype == CTYPE_GZIP)
|
||||||
|
print_output("gzip");
|
||||||
|
else if (ctype == CTYPE_ZPAQ)
|
||||||
|
print_output("zpaq");
|
||||||
|
else
|
||||||
|
print_output("Dunno wtf");
|
||||||
|
utotal += u_len;
|
||||||
|
ctotal += c_len;
|
||||||
|
print_output("\t%.1f%%\t%lld / %lld", (double)c_len / (double)(u_len / 100), c_len, u_len);
|
||||||
|
print_maxverbose("\tOffset: %lld\tHead: %lld", head_off, last_head);
|
||||||
|
print_output("\n");
|
||||||
|
block++;
|
||||||
|
} while (last_head);
|
||||||
|
++stream;
|
||||||
|
}
|
||||||
|
ofs = lseek(fd_in, 0, SEEK_CUR) + c_len;
|
||||||
|
/* Chunk byte entry */
|
||||||
|
if (control->major_version == 0 && control->minor_version > 4)
|
||||||
|
ofs++;
|
||||||
|
if (ofs < infile_size - MD5_DIGEST_SIZE)
|
||||||
|
goto next_chunk;
|
||||||
|
if (unlikely(ofs > infile_size))
|
||||||
|
failure("Offset greater than archive size, likely corrupted/truncated archive.\n");
|
||||||
|
print_output("Rzip compression: %.1f%% %lld / %lld\n",
|
||||||
|
(double)utotal / (double)(expected_size / 100),
|
||||||
|
utotal, expected_size);
|
||||||
|
print_output("Back end compression: %.1f%% %lld / %lld\n",
|
||||||
|
(double)ctotal / (double)(utotal / 100),
|
||||||
|
ctotal, utotal);
|
||||||
|
print_output("Overall compression: %.1f%% %lld / %lld\n",
|
||||||
|
(double)ctotal / (double)(expected_size / 100),
|
||||||
|
ctotal, expected_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STDIN) {
|
||||||
|
if (unlikely(unlink(control->infile)))
|
||||||
|
fatal("Failed to unlink %s: %s\n", infilecopy, strerror(errno));
|
||||||
|
} else
|
||||||
|
if (unlikely(close(fd_in)))
|
||||||
|
fatal("Failed to close fd_in in get_fileinfo\n");
|
||||||
|
|
||||||
|
free(control->outfile);
|
||||||
|
free(infilecopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
compress one file from the command line
|
||||||
|
*/
|
||||||
|
void compress_file(rzip_control *control)
|
||||||
|
{
|
||||||
|
const char *tmp, *tmpinfile; /* we're just using this as a proxy for control->infile.
|
||||||
|
* Spares a compiler warning
|
||||||
|
*/
|
||||||
|
int fd_in, fd_out;
|
||||||
|
char header[24];
|
||||||
|
|
||||||
|
memset(header, 0, sizeof(header));
|
||||||
|
|
||||||
|
if (!STDIN) {
|
||||||
|
/* is extension at end of infile? */
|
||||||
|
if ((tmp = strrchr(control->infile, '.')) && !strcmp(tmp, control->suffix)) {
|
||||||
|
print_err("%s: already has %s suffix. Skipping...\n", control->infile, control->suffix);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_in = open(control->infile, O_RDONLY);
|
||||||
|
if (unlikely(fd_in == -1))
|
||||||
|
fatal("Failed to open %s: %s\n", control->infile, strerror(errno));
|
||||||
|
} else
|
||||||
|
fd_in = 0;
|
||||||
|
|
||||||
|
if (!STDOUT) {
|
||||||
|
if (control->outname) {
|
||||||
|
/* check if outname has control->suffix */
|
||||||
|
if (*(control->suffix) == '\0') /* suffix is empty string */
|
||||||
|
control->outfile = strdup(control->outname);
|
||||||
|
else if ((tmp=strrchr(control->outname, '.')) && strcmp(tmp, control->suffix)) {
|
||||||
|
control->outfile = malloc(strlen(control->outname) + strlen(control->suffix) + 1);
|
||||||
|
if (unlikely(!control->outfile))
|
||||||
|
fatal("Failed to allocate outfile name\n");
|
||||||
|
strcpy(control->outfile, control->outname);
|
||||||
|
strcat(control->outfile, control->suffix);
|
||||||
|
print_output("Suffix added to %s.\nFull pathname is: %s\n", control->outname, control->outfile);
|
||||||
|
} else /* no, already has suffix */
|
||||||
|
control->outfile = strdup(control->outname);
|
||||||
|
} else {
|
||||||
|
/* default output name from control->infile
|
||||||
|
* test if outdir specified. If so, strip path from filename of
|
||||||
|
* control->infile
|
||||||
|
*/
|
||||||
|
if (control->outdir && (tmp = strrchr(control->infile, '/')))
|
||||||
|
tmpinfile = tmp + 1;
|
||||||
|
else
|
||||||
|
tmpinfile = control->infile;
|
||||||
|
|
||||||
|
control->outfile = malloc((control->outdir == NULL? 0: strlen(control->outdir)) + strlen(tmpinfile) + strlen(control->suffix) + 1);
|
||||||
|
if (unlikely(!control->outfile))
|
||||||
|
fatal("Failed to allocate outfile name\n");
|
||||||
|
|
||||||
|
if (control->outdir) { /* prepend control->outdir */
|
||||||
|
strcpy(control->outfile, control->outdir);
|
||||||
|
strcat(control->outfile, tmpinfile);
|
||||||
|
} else
|
||||||
|
strcpy(control->outfile, tmpinfile);
|
||||||
|
strcat(control->outfile, control->suffix);
|
||||||
|
print_progress("Output filename is: %s\n", control->outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FORCE_REPLACE)
|
||||||
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
else
|
||||||
|
fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||||
|
if (unlikely(fd_out == -1)) {
|
||||||
|
/* We must ensure we don't delete a file that already
|
||||||
|
* exists just because we tried to create a new one */
|
||||||
|
control->flags |= FLAG_KEEP_BROKEN;
|
||||||
|
fatal("Failed to create %s: %s\n", control->outfile, strerror(errno));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
fd_out = open_tmpoutfile(control);
|
||||||
|
control->fd_out = fd_out;
|
||||||
|
|
||||||
|
preserve_perms(control, fd_in, fd_out);
|
||||||
|
|
||||||
|
/* write zeroes to 24 bytes at beginning of file */
|
||||||
|
if (unlikely(write(fd_out, header, sizeof(header)) != sizeof(header)))
|
||||||
|
fatal("Cannot write file header\n");
|
||||||
|
|
||||||
|
rzip_fd(control, fd_in, fd_out);
|
||||||
|
|
||||||
|
/* write magic at end b/c lzma does not tell us properties until it is done */
|
||||||
|
write_magic(control, fd_in, fd_out);
|
||||||
|
|
||||||
|
if (STDOUT)
|
||||||
|
dump_tmpoutfile(control, fd_out);
|
||||||
|
|
||||||
|
if (unlikely(close(fd_in) || close(fd_out)))
|
||||||
|
fatal("Failed to close files\n");
|
||||||
|
|
||||||
|
if (STDOUT) {
|
||||||
|
/* Delete temporary files generated for testing or faking stdout */
|
||||||
|
if (unlikely(unlink(control->outfile)))
|
||||||
|
fatal("Failed to unlink tmpfile: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!KEEP_FILES) {
|
||||||
|
if (unlikely(unlink(control->infile)))
|
||||||
|
fatal("Failed to unlink %s: %s\n", control->infile, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(control->outfile);
|
||||||
|
}
|
||||||
115
lrzip.h
Normal file
115
lrzip.h
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2006-2011 Con Kolivas
|
||||||
|
Copyright (C) 2011 Peter Hyman
|
||||||
|
Copyright (C) 1998-2003 Andrew Tridgell
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef LRZIP_H
|
||||||
|
#define LRZIP_H
|
||||||
|
|
||||||
|
#define LRZIP_MAJOR_VERSION 0
|
||||||
|
#define LRZIP_MINOR_VERSION 5
|
||||||
|
#define LRZIP_MINOR_SUBVERSION 70
|
||||||
|
|
||||||
|
#define NUM_STREAMS 2
|
||||||
|
#define STREAM_BUFSIZE (1024 * 1024 * 10)
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifndef uchar
|
||||||
|
#define uchar unsigned char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef int32
|
||||||
|
#if (SIZEOF_INT == 4)
|
||||||
|
#define int32 int
|
||||||
|
#elif (SIZEOF_LONG == 4)
|
||||||
|
#define int32 long
|
||||||
|
#elif (SIZEOF_SHORT == 4)
|
||||||
|
#define int32 short
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef int16
|
||||||
|
#if (SIZEOF_INT == 2)
|
||||||
|
#define int16 int
|
||||||
|
#elif (SIZEOF_SHORT == 2)
|
||||||
|
#define int16 short
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef uint32
|
||||||
|
#define uint32 unsigned int32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef uint16
|
||||||
|
#define uint16 unsigned int16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b)? (a): (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b)? (a): (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !HAVE_STRERROR
|
||||||
|
extern char *sys_errlist[];
|
||||||
|
#define strerror(i) sys_errlist[i]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_ERRNO_H
|
||||||
|
extern int errno;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
|
||||||
|
typedef long long int i64;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
|
||||||
|
#ifndef MAP_ANONYMOUS
|
||||||
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NOTHREAD) || !defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
#define PROCESSORS (1)
|
||||||
|
#else
|
||||||
|
#define PROCESSORS (sysconf(_SC_NPROCESSORS_ONLN))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _SC_PAGE_SIZE
|
||||||
|
#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
|
||||||
|
#else
|
||||||
|
#define PAGE_SIZE (4096)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct rzip_control rzip_control;
|
||||||
|
|
||||||
|
void write_magic(rzip_control *control, int fd_in, int fd_out);
|
||||||
|
void read_magic(rzip_control *control, int fd_in, i64 *expected_size);
|
||||||
|
void preserve_perms(rzip_control *control, int fd_in, int fd_out);
|
||||||
|
int open_tmpoutfile(rzip_control *control);
|
||||||
|
void dump_tmpoutfile(rzip_control *control, int fd_out);
|
||||||
|
int open_tmpinfile(rzip_control *control);
|
||||||
|
void read_tmpinfile(rzip_control *control, int fd_in);
|
||||||
|
void decompress_file(rzip_control *control);
|
||||||
|
void get_header_info(rzip_control *control, int fd_in, uchar *ctype, i64 *c_len, i64 *u_len, i64 *last_head);
|
||||||
|
void get_fileinfo(rzip_control *control);
|
||||||
|
void compress_file(rzip_control *control);
|
||||||
|
#endif
|
||||||
47
m4/ac_attribute.m4
Normal file
47
m4/ac_attribute.m4
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
dnl Copyright (C) 2004-2008 Kim Woelders
|
||||||
|
dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
|
||||||
|
dnl That code is public domain and can be freely used or copied.
|
||||||
|
dnl Originally snatched from somewhere...
|
||||||
|
|
||||||
|
dnl Macro for checking if the compiler supports __attribute__
|
||||||
|
|
||||||
|
dnl Usage: AC_C___ATTRIBUTE__
|
||||||
|
dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
|
||||||
|
dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
|
||||||
|
dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
|
||||||
|
dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
|
||||||
|
dnl defined to nothing.
|
||||||
|
|
||||||
|
AC_DEFUN([AC_C___ATTRIBUTE__],
|
||||||
|
[
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for __attribute__])
|
||||||
|
|
||||||
|
AC_CACHE_VAL([ac_cv___attribute__],
|
||||||
|
[AC_TRY_COMPILE(
|
||||||
|
[
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int func(int x);
|
||||||
|
int foo(int x __attribute__ ((unused)))
|
||||||
|
{
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[ac_cv___attribute__="yes"],
|
||||||
|
[ac_cv___attribute__="no"]
|
||||||
|
)])
|
||||||
|
|
||||||
|
AC_MSG_RESULT($ac_cv___attribute__)
|
||||||
|
|
||||||
|
if test "x${ac_cv___attribute__}" = "xyes" ; then
|
||||||
|
AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
|
||||||
|
AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
|
||||||
|
else
|
||||||
|
AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
|
||||||
|
fi
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl End of ac_attribute.m4
|
||||||
707
main.c
707
main.c
|
|
@ -17,7 +17,55 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/* lrzip compression - main program */
|
/* lrzip compression - main program */
|
||||||
|
#define MAIN_C
|
||||||
#include "rzip.h"
|
#include "rzip.h"
|
||||||
|
/* main() defines, different from liblrzip defines */
|
||||||
|
#define FLAG_VERBOSE (FLAG_VERBOSITY | FLAG_VERBOSITY_MAX)
|
||||||
|
#define FLAG_NOT_LZMA (FLAG_NO_COMPRESS | FLAG_LZO_COMPRESS | FLAG_BZIP2_COMPRESS | FLAG_ZLIB_COMPRESS | FLAG_ZPAQ_COMPRESS)
|
||||||
|
#define LZMA_COMPRESS (!(control.flags & FLAG_NOT_LZMA))
|
||||||
|
|
||||||
|
#define SHOW_PROGRESS (control.flags & FLAG_SHOW_PROGRESS)
|
||||||
|
#define KEEP_FILES (control.flags & FLAG_KEEP_FILES)
|
||||||
|
#define TEST_ONLY (control.flags & FLAG_TEST_ONLY)
|
||||||
|
#define FORCE_REPLACE (control.flags & FLAG_FORCE_REPLACE)
|
||||||
|
#define DECOMPRESS (control.flags & FLAG_DECOMPRESS)
|
||||||
|
#define NO_COMPRESS (control.flags & FLAG_NO_COMPRESS)
|
||||||
|
#define LZO_COMPRESS (control.flags & FLAG_LZO_COMPRESS)
|
||||||
|
#define BZIP2_COMPRESS (control.flags & FLAG_BZIP2_COMPRESS)
|
||||||
|
#define ZLIB_COMPRESS (control.flags & FLAG_ZLIB_COMPRESS)
|
||||||
|
#define ZPAQ_COMPRESS (control.flags & FLAG_ZPAQ_COMPRESS)
|
||||||
|
#define VERBOSE (control.flags & FLAG_VERBOSE)
|
||||||
|
#define VERBOSITY (control.flags & FLAG_VERBOSITY)
|
||||||
|
#define MAX_VERBOSE (control.flags & FLAG_VERBOSITY_MAX)
|
||||||
|
#define STDIN (control.flags & FLAG_STDIN)
|
||||||
|
#define STDOUT (control.flags & FLAG_STDOUT)
|
||||||
|
#define INFO (control.flags & FLAG_INFO)
|
||||||
|
#define UNLIMITED (control.flags & FLAG_UNLIMITED)
|
||||||
|
#define HASH_CHECK (control.flags & FLAG_HASH)
|
||||||
|
#define HAS_MD5 (control.flags & FLAG_MD5)
|
||||||
|
#define CHECK_FILE (control.flags & FLAG_CHECK)
|
||||||
|
#define KEEP_BROKEN (control.flags & FLAG_KEEP_BROKEN)
|
||||||
|
#define LZO_TEST (control.flags & FLAG_THRESHOLD)
|
||||||
|
|
||||||
|
#define print_output(format, args...) do {\
|
||||||
|
fprintf(control.msgout, format, ##args); \
|
||||||
|
fflush(control.msgout); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_progress(format, args...) do {\
|
||||||
|
if (SHOW_PROGRESS) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_verbose(format, args...) do {\
|
||||||
|
if (VERBOSE) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define print_maxverbose(format, args...) do {\
|
||||||
|
if (MAX_VERBOSE) \
|
||||||
|
print_output(format, ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
struct rzip_control control;
|
struct rzip_control control;
|
||||||
|
|
||||||
|
|
@ -66,652 +114,6 @@ static void usage(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_magic(int fd_in, int fd_out)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
char magic[24];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(magic, 0, sizeof(magic));
|
|
||||||
strcpy(magic, "LRZI");
|
|
||||||
magic[4] = LRZIP_MAJOR_VERSION;
|
|
||||||
magic[5] = LRZIP_MINOR_VERSION;
|
|
||||||
|
|
||||||
if (unlikely(fstat(fd_in, &st)))
|
|
||||||
fatal("bad magic file descriptor!?\n");
|
|
||||||
|
|
||||||
memcpy(&magic[6], &control.st_size, 8);
|
|
||||||
|
|
||||||
/* save LZMA compression flags */
|
|
||||||
if (LZMA_COMPRESS) {
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
magic[i + 16] = (char)control.lzma_properties[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is a flag that the archive contains an md5 sum at the end
|
|
||||||
* which can be used as an integrity check instead of crc check.
|
|
||||||
* crc is still stored for compatibility with 0.5 versions.
|
|
||||||
*/
|
|
||||||
magic[21] = 1;
|
|
||||||
|
|
||||||
if (unlikely(lseek(fd_out, 0, SEEK_SET)))
|
|
||||||
fatal("Failed to seek to BOF to write Magic Header\n");
|
|
||||||
|
|
||||||
if (unlikely(write(fd_out, magic, sizeof(magic)) != sizeof(magic)))
|
|
||||||
fatal("Failed to write magic header\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_magic(int fd_in, i64 *expected_size)
|
|
||||||
{
|
|
||||||
char magic[24];
|
|
||||||
uint32_t v;
|
|
||||||
int md5, i;
|
|
||||||
|
|
||||||
if (unlikely(read(fd_in, magic, sizeof(magic)) != sizeof(magic)))
|
|
||||||
fatal("Failed to read magic header\n");
|
|
||||||
|
|
||||||
*expected_size = 0;
|
|
||||||
|
|
||||||
if (unlikely(strncmp(magic, "LRZI", 4)))
|
|
||||||
failure("Not an lrzip file\n");
|
|
||||||
|
|
||||||
memcpy(&control.major_version, &magic[4], 1);
|
|
||||||
memcpy(&control.minor_version, &magic[5], 1);
|
|
||||||
|
|
||||||
/* Support the convoluted way we described size in versions < 0.40 */
|
|
||||||
if (control.major_version == 0 && control.minor_version < 4) {
|
|
||||||
memcpy(&v, &magic[6], 4);
|
|
||||||
*expected_size = ntohl(v);
|
|
||||||
memcpy(&v, &magic[10], 4);
|
|
||||||
*expected_size |= ((i64)ntohl(v)) << 32;
|
|
||||||
} else
|
|
||||||
memcpy(expected_size, &magic[6], 8);
|
|
||||||
|
|
||||||
/* restore LZMA compression flags only if stored */
|
|
||||||
if ((int) magic[16]) {
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
control.lzma_properties[i] = magic[i + 16];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Whether this archive contains md5 data at the end or not */
|
|
||||||
md5 = magic[21];
|
|
||||||
if (md5 == 1)
|
|
||||||
control.flags |= FLAG_MD5;
|
|
||||||
|
|
||||||
print_verbose("Detected lrzip version %d.%d file.\n", control.major_version, control.minor_version);
|
|
||||||
if (control.major_version > LRZIP_MAJOR_VERSION ||
|
|
||||||
(control.major_version == LRZIP_MAJOR_VERSION && control.minor_version > LRZIP_MINOR_VERSION))
|
|
||||||
print_output("Attempting to work with file produced by newer lrzip version %d.%d file.\n", control.major_version, control.minor_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* preserve ownership and permissions where possible */
|
|
||||||
static void preserve_perms(int fd_in, int fd_out)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (unlikely(fstat(fd_in, &st)))
|
|
||||||
fatal("Failed to fstat input file\n");
|
|
||||||
if (unlikely(fchmod(fd_out, (st.st_mode & 0777))))
|
|
||||||
print_err("Warning, unable to set permissions on %s\n", control.outfile);
|
|
||||||
|
|
||||||
/* chown fail is not fatal */
|
|
||||||
if (unlikely(fchown(fd_out, st.st_uid, st.st_gid)))
|
|
||||||
print_err("Warning, unable to set owner on %s\n", control.outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open a temporary outputfile to emulate stdout */
|
|
||||||
static int open_tmpoutfile(void)
|
|
||||||
{
|
|
||||||
int fd_out;
|
|
||||||
|
|
||||||
if (STDOUT && !TEST_ONLY)
|
|
||||||
print_verbose("Outputting to stdout.\n");
|
|
||||||
if (control.tmpdir) {
|
|
||||||
control.outfile = realloc(NULL, strlen(control.tmpdir) + 16);
|
|
||||||
if (unlikely(!control.outfile))
|
|
||||||
fatal("Failed to allocate outfile name\n");
|
|
||||||
strcpy(control.outfile, control.tmpdir);
|
|
||||||
strcat(control.outfile, "lrzipout.XXXXXX");
|
|
||||||
} else {
|
|
||||||
control.outfile = realloc(NULL, 16);
|
|
||||||
if (unlikely(!control.outfile))
|
|
||||||
fatal("Failed to allocate outfile name\n");
|
|
||||||
strcpy(control.outfile, "lrzipout.XXXXXX");
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_out = mkstemp(control.outfile);
|
|
||||||
if (unlikely(fd_out == -1))
|
|
||||||
fatal("Failed to create out tmpfile: %s\n", control.outfile);
|
|
||||||
return fd_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dump temporary outputfile to perform stdout */
|
|
||||||
void dump_tmpoutfile(int fd_out)
|
|
||||||
{
|
|
||||||
FILE *tmpoutfp;
|
|
||||||
int tmpchar;
|
|
||||||
|
|
||||||
/* flush anything not yet in the temporary file */
|
|
||||||
fsync(fd_out);
|
|
||||||
tmpoutfp = fdopen(fd_out, "r");
|
|
||||||
if (unlikely(tmpoutfp == NULL))
|
|
||||||
fatal("Failed to fdopen out tmpfile\n");
|
|
||||||
rewind(tmpoutfp);
|
|
||||||
|
|
||||||
if (!TEST_ONLY) {
|
|
||||||
print_verbose("Dumping temporary file to stdout.\n");
|
|
||||||
while ((tmpchar = fgetc(tmpoutfp)) != EOF)
|
|
||||||
putchar(tmpchar);
|
|
||||||
fflush(stdout);
|
|
||||||
rewind(tmpoutfp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(ftruncate(fd_out, 0)))
|
|
||||||
fatal("Failed to ftruncate fd_out in dump_tmpoutfile\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open a temporary inputfile to perform stdin decompression */
|
|
||||||
static int open_tmpinfile(void)
|
|
||||||
{
|
|
||||||
int fd_in;
|
|
||||||
|
|
||||||
if (control.tmpdir) {
|
|
||||||
control.infile = malloc(strlen(control.tmpdir) + 15);
|
|
||||||
if (unlikely(!control.infile))
|
|
||||||
fatal("Failed to allocate infile name\n");
|
|
||||||
strcpy(control.infile, control.tmpdir);
|
|
||||||
strcat(control.infile, "lrzipin.XXXXXX");
|
|
||||||
} else {
|
|
||||||
control.infile = malloc(15);
|
|
||||||
if (unlikely(!control.infile))
|
|
||||||
fatal("Failed to allocate infile name\n");
|
|
||||||
strcpy(control.infile, "lrzipin.XXXXXX");
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_in = mkstemp(control.infile);
|
|
||||||
if (unlikely(fd_in == -1))
|
|
||||||
fatal("Failed to create in tmpfile: %s\n", control.infile);
|
|
||||||
/* Unlink temporary file immediately to minimise chance of files left
|
|
||||||
* lying around in cases of failure. */
|
|
||||||
if (unlikely(unlink(control.infile)))
|
|
||||||
fatal("Failed to unlink tmpfile: %s\n", control.infile);
|
|
||||||
return fd_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read data from stdin into temporary inputfile */
|
|
||||||
static void read_tmpinfile(int fd_in)
|
|
||||||
{
|
|
||||||
FILE *tmpinfp;
|
|
||||||
int tmpchar;
|
|
||||||
|
|
||||||
if (control.flags & FLAG_SHOW_PROGRESS)
|
|
||||||
fprintf(control.msgout, "Copying from stdin.\n");
|
|
||||||
tmpinfp = fdopen(fd_in, "w+");
|
|
||||||
if (unlikely(tmpinfp == NULL))
|
|
||||||
fatal("Failed to fdopen in tmpfile\n");
|
|
||||||
|
|
||||||
while ((tmpchar = getchar()) != EOF)
|
|
||||||
fputc(tmpchar, tmpinfp);
|
|
||||||
|
|
||||||
fflush(tmpinfp);
|
|
||||||
rewind(tmpinfp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
decompress one file from the command line
|
|
||||||
*/
|
|
||||||
static void decompress_file(void)
|
|
||||||
{
|
|
||||||
char *tmp, *tmpoutfile, *infilecopy = NULL;
|
|
||||||
int fd_in, fd_out = -1, fd_hist = -1;
|
|
||||||
i64 expected_size, free_space;
|
|
||||||
struct statvfs fbuf;
|
|
||||||
|
|
||||||
if (!STDIN) {
|
|
||||||
if ((tmp = strrchr(control.infile, '.')) && strcmp(tmp,control.suffix)) {
|
|
||||||
/* make sure infile has an extension. If not, add it
|
|
||||||
* because manipulations may be made to input filename, set local ptr
|
|
||||||
*/
|
|
||||||
infilecopy = malloc(strlen(control.infile) + strlen(control.suffix) + 1);
|
|
||||||
if (unlikely(infilecopy == NULL))
|
|
||||||
fatal("Failed to allocate memory for infile suffix\n");
|
|
||||||
else {
|
|
||||||
strcpy(infilecopy, control.infile);
|
|
||||||
strcat(infilecopy, control.suffix);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
infilecopy = strdup(control.infile);
|
|
||||||
/* regardless, infilecopy has the input filename */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!STDOUT && !TEST_ONLY) {
|
|
||||||
/* if output name already set, use it */
|
|
||||||
if (control.outname) {
|
|
||||||
control.outfile = strdup(control.outname);
|
|
||||||
} else {
|
|
||||||
/* default output name from infilecopy
|
|
||||||
* test if outdir specified. If so, strip path from filename of
|
|
||||||
* infilecopy, then remove suffix.
|
|
||||||
*/
|
|
||||||
if (control.outdir && (tmp = strrchr(infilecopy, '/')))
|
|
||||||
tmpoutfile = strdup(tmp + 1);
|
|
||||||
else
|
|
||||||
tmpoutfile = strdup(infilecopy);
|
|
||||||
|
|
||||||
/* remove suffix to make outfile name */
|
|
||||||
if ((tmp = strrchr(tmpoutfile, '.')) && !strcmp(tmp, control.suffix))
|
|
||||||
*tmp='\0';
|
|
||||||
|
|
||||||
control.outfile = malloc((control.outdir == NULL? 0: strlen(control.outdir)) + strlen(tmpoutfile) + 1);
|
|
||||||
if (unlikely(!control.outfile))
|
|
||||||
fatal("Failed to allocate outfile name\n");
|
|
||||||
|
|
||||||
if (control.outdir) { /* prepend control.outdir */
|
|
||||||
strcpy(control.outfile, control.outdir);
|
|
||||||
strcat(control.outfile, tmpoutfile);
|
|
||||||
} else
|
|
||||||
strcpy(control.outfile, tmpoutfile);
|
|
||||||
free(tmpoutfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!STDOUT)
|
|
||||||
print_progress("Output filename is: %s...Decompressing...\n", control.outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (STDIN) {
|
|
||||||
fd_in = open_tmpinfile();
|
|
||||||
read_tmpinfile(fd_in);
|
|
||||||
} else {
|
|
||||||
fd_in = open(infilecopy, O_RDONLY);
|
|
||||||
if (unlikely(fd_in == -1)) {
|
|
||||||
fatal("Failed to open %s\n",infilecopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(TEST_ONLY | STDOUT)) {
|
|
||||||
if (FORCE_REPLACE)
|
|
||||||
fd_out = open(control.outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
|
||||||
else
|
|
||||||
fd_out = open(control.outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
|
||||||
if (unlikely(fd_out == -1)) {
|
|
||||||
/* We must ensure we don't delete a file that already
|
|
||||||
* exists just because we tried to create a new one */
|
|
||||||
control.flags |= FLAG_KEEP_BROKEN;
|
|
||||||
fatal("Failed to create %s\n", control.outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
preserve_perms(fd_in, fd_out);
|
|
||||||
} else
|
|
||||||
fd_out = open_tmpoutfile();
|
|
||||||
control.fd_out = fd_out;
|
|
||||||
|
|
||||||
read_magic(fd_in, &expected_size);
|
|
||||||
|
|
||||||
if (!STDOUT) {
|
|
||||||
/* Check if there's enough free space on the device chosen to fit the
|
|
||||||
* decompressed file. */
|
|
||||||
if (unlikely(fstatvfs(fd_out, &fbuf)))
|
|
||||||
fatal("Failed to fstatvfs in decompress_file\n");
|
|
||||||
free_space = fbuf.f_bsize * fbuf.f_bavail;
|
|
||||||
if (free_space < expected_size) {
|
|
||||||
if (FORCE_REPLACE)
|
|
||||||
print_err("Warning, inadequate free space detected, but attempting to decompress due to -f option being used.\n");
|
|
||||||
else
|
|
||||||
failure("Inadequate free space to decompress file, use -f to override.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_hist = open(control.outfile, O_RDONLY);
|
|
||||||
if (unlikely(fd_hist == -1))
|
|
||||||
fatal("Failed to open history file %s\n", control.outfile);
|
|
||||||
|
|
||||||
/* Unlink temporary file as soon as possible */
|
|
||||||
if (unlikely((STDOUT || TEST_ONLY) && unlink(control.outfile)))
|
|
||||||
fatal("Failed to unlink tmpfile: %s\n", control.outfile);
|
|
||||||
|
|
||||||
if (NO_MD5)
|
|
||||||
print_verbose("Not performing MD5 hash check\n");
|
|
||||||
if (HAS_MD5)
|
|
||||||
print_verbose("MD5 ");
|
|
||||||
else
|
|
||||||
print_verbose("CRC32 ");
|
|
||||||
print_verbose("being used for integrity testing.\n");
|
|
||||||
|
|
||||||
print_progress("Decompressing...");
|
|
||||||
|
|
||||||
runzip_fd(fd_in, fd_out, fd_hist, expected_size);
|
|
||||||
|
|
||||||
if (STDOUT)
|
|
||||||
dump_tmpoutfile(fd_out);
|
|
||||||
|
|
||||||
/* if we get here, no fatal errors during decompression */
|
|
||||||
print_progress("\r");
|
|
||||||
if (!(STDOUT | TEST_ONLY))
|
|
||||||
print_output("Output filename is: %s: ", control.outfile);
|
|
||||||
print_progress("[OK] - %lld bytes \n", expected_size);
|
|
||||||
|
|
||||||
if (unlikely(close(fd_hist) || close(fd_out)))
|
|
||||||
fatal("Failed to close files\n");
|
|
||||||
|
|
||||||
close(fd_in);
|
|
||||||
|
|
||||||
if (!KEEP_FILES) {
|
|
||||||
if (unlikely(unlink(control.infile)))
|
|
||||||
fatal("Failed to unlink %s\n", infilecopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(control.outfile);
|
|
||||||
free(infilecopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_header_info(int fd_in, uchar *ctype, i64 *c_len, i64 *u_len, i64 *last_head)
|
|
||||||
{
|
|
||||||
if (unlikely(read(fd_in, ctype, 1) != 1))
|
|
||||||
fatal("Failed to read in get_header_info\n");
|
|
||||||
|
|
||||||
if (control.major_version == 0 && control.minor_version < 4) {
|
|
||||||
u32 c_len32, u_len32, last_head32;
|
|
||||||
|
|
||||||
if (unlikely(read(fd_in, &c_len32, 4) != 4))
|
|
||||||
fatal("Failed to read in get_header_info");
|
|
||||||
if (unlikely(read(fd_in, &u_len32, 4) != 4))
|
|
||||||
fatal("Failed to read in get_header_info");
|
|
||||||
if (unlikely(read(fd_in, &last_head32, 4) != 4))
|
|
||||||
fatal("Failed to read in get_header_info");
|
|
||||||
*c_len = c_len32;
|
|
||||||
*u_len = u_len32;
|
|
||||||
*last_head = last_head32;
|
|
||||||
} else {
|
|
||||||
if (unlikely(read(fd_in, c_len, 8) != 8))
|
|
||||||
fatal("Failed to read in get_header_info");
|
|
||||||
if (unlikely(read(fd_in, u_len, 8) != 8))
|
|
||||||
fatal("Failed to read in get_header_info");
|
|
||||||
if (unlikely(read(fd_in, last_head, 8) != 8))
|
|
||||||
fatal("Failed to read_i64 in get_header_info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_fileinfo(void)
|
|
||||||
{
|
|
||||||
i64 expected_size, infile_size;
|
|
||||||
int seekspot, fd_in;
|
|
||||||
long double cratio;
|
|
||||||
uchar ctype = 0;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
char *tmp, *infilecopy = NULL;
|
|
||||||
|
|
||||||
if (!STDIN) {
|
|
||||||
if ((tmp = strrchr(control.infile, '.')) && strcmp(tmp,control.suffix)) {
|
|
||||||
infilecopy = malloc(strlen(control.infile) + strlen(control.suffix) + 1);
|
|
||||||
if (unlikely(infilecopy == NULL))
|
|
||||||
fatal("Failed to allocate memory for infile suffix\n");
|
|
||||||
else {
|
|
||||||
strcpy(infilecopy, control.infile);
|
|
||||||
strcat(infilecopy, control.suffix);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
infilecopy = strdup(control.infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (STDIN)
|
|
||||||
fd_in = 0;
|
|
||||||
else {
|
|
||||||
fd_in = open(infilecopy, O_RDONLY);
|
|
||||||
if (unlikely(fd_in == -1))
|
|
||||||
fatal("Failed to open %s\n", infilecopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get file size */
|
|
||||||
if (unlikely(fstat(fd_in, &st)))
|
|
||||||
fatal("bad magic file descriptor!?\n");
|
|
||||||
memcpy(&infile_size, &st.st_size, 8);
|
|
||||||
|
|
||||||
/* Get decompressed size */
|
|
||||||
read_magic(fd_in, &expected_size);
|
|
||||||
|
|
||||||
/* Version < 0.4 had different file format */
|
|
||||||
if (control.major_version == 0 && control.minor_version < 4)
|
|
||||||
seekspot = 50;
|
|
||||||
else if (control.major_version == 0 && control.minor_version == 4)
|
|
||||||
seekspot = 74;
|
|
||||||
else
|
|
||||||
seekspot = 75;
|
|
||||||
if (unlikely(lseek(fd_in, seekspot, SEEK_SET) == -1))
|
|
||||||
fatal("Failed to lseek in get_fileinfo\n");
|
|
||||||
|
|
||||||
/* Read the compression type of the first block. It's possible that
|
|
||||||
not all blocks are compressed so this may not be accurate.
|
|
||||||
*/
|
|
||||||
if (unlikely(read(fd_in, &ctype, 1) != 1))
|
|
||||||
fatal("Failed to read in get_fileinfo\n");
|
|
||||||
|
|
||||||
cratio = (long double)expected_size / (long double)infile_size;
|
|
||||||
|
|
||||||
print_output("%s:\nlrzip version: %d.%d file\n", infilecopy, control.major_version, control.minor_version);
|
|
||||||
print_output("Compression: ");
|
|
||||||
if (ctype == CTYPE_NONE)
|
|
||||||
print_output("rzip alone\n");
|
|
||||||
else if (ctype == CTYPE_BZIP2)
|
|
||||||
print_output("rzip + bzip2\n");
|
|
||||||
else if (ctype == CTYPE_LZO)
|
|
||||||
print_output("rzip + lzo\n");
|
|
||||||
else if (ctype == CTYPE_LZMA)
|
|
||||||
print_output("rzip + lzma\n");
|
|
||||||
else if (ctype == CTYPE_GZIP)
|
|
||||||
print_output("rzip + gzip\n");
|
|
||||||
else if (ctype == CTYPE_ZPAQ)
|
|
||||||
print_output("rzip + zpaq\n");
|
|
||||||
else
|
|
||||||
print_output("Dunno wtf\n");
|
|
||||||
print_output("Decompressed file size: %llu\n", expected_size);
|
|
||||||
print_output("Compressed file size: %llu\n", infile_size);
|
|
||||||
print_output("Compression ratio: %.3Lf\n", cratio);
|
|
||||||
|
|
||||||
if (HAS_MD5) {
|
|
||||||
char md5_stored[MD5_DIGEST_SIZE];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
print_output("MD5 used for integrity testing\n");
|
|
||||||
if (unlikely(lseek(fd_in, -MD5_DIGEST_SIZE, SEEK_END)) == -1)
|
|
||||||
fatal("Failed to seek to md5 data in runzip_fd\n");
|
|
||||||
if (unlikely(read(fd_in, md5_stored, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
|
|
||||||
fatal("Failed to read md5 data in runzip_fd\n");
|
|
||||||
print_output("MD5: ");
|
|
||||||
for (i = 0; i < MD5_DIGEST_SIZE; i++)
|
|
||||||
print_output("%02x", md5_stored[i] & 0xFF);
|
|
||||||
print_output("\n");
|
|
||||||
} else
|
|
||||||
print_output("CRC32 used for integrity testing\n");
|
|
||||||
|
|
||||||
if (VERBOSE || MAX_VERBOSE) {
|
|
||||||
i64 u_len, c_len, last_head, utotal = 0, ctotal = 0, ofs = 25,
|
|
||||||
stream_head[2];
|
|
||||||
int header_length = 25, stream = 0, chunk = 0;
|
|
||||||
|
|
||||||
if (control.major_version == 0 && control.minor_version < 4)
|
|
||||||
header_length = 13;
|
|
||||||
next_chunk:
|
|
||||||
stream = 0;
|
|
||||||
stream_head[0] = 0;
|
|
||||||
stream_head[1] = stream_head[0] + header_length;
|
|
||||||
|
|
||||||
print_output("Rzip chunk %d:\n", ++chunk);
|
|
||||||
while (stream < NUM_STREAMS) {
|
|
||||||
int block = 1;
|
|
||||||
|
|
||||||
if (unlikely(lseek(fd_in, stream_head[stream] + ofs, SEEK_SET)) == -1)
|
|
||||||
fatal("Failed to seek to header data in get_fileinfo\n");
|
|
||||||
get_header_info(fd_in, &ctype, &c_len, &u_len, &last_head);
|
|
||||||
|
|
||||||
print_output("Stream: %d\n", stream);
|
|
||||||
print_maxverbose("Offset: %lld\n", ofs);
|
|
||||||
print_output("Block\tComp\tPercent\tSize\n");
|
|
||||||
do {
|
|
||||||
i64 head_off;
|
|
||||||
|
|
||||||
if (unlikely(last_head + ofs > infile_size))
|
|
||||||
failure("Offset greater than archive size, likely corrupted/truncated archive.\n");
|
|
||||||
if (unlikely(head_off = lseek(fd_in, last_head + ofs, SEEK_SET)) == -1)
|
|
||||||
fatal("Failed to seek to header data in get_fileinfo\n");
|
|
||||||
get_header_info(fd_in, &ctype, &c_len, &u_len, &last_head);
|
|
||||||
if (unlikely(last_head < 0 || c_len < 0 || u_len < 0))
|
|
||||||
failure("Entry negative, likely corrupted archive.\n");
|
|
||||||
print_output("%d\t", block);
|
|
||||||
if (ctype == CTYPE_NONE)
|
|
||||||
print_output("none");
|
|
||||||
else if (ctype == CTYPE_BZIP2)
|
|
||||||
print_output("bzip2");
|
|
||||||
else if (ctype == CTYPE_LZO)
|
|
||||||
print_output("lzo");
|
|
||||||
else if (ctype == CTYPE_LZMA)
|
|
||||||
print_output("lzma");
|
|
||||||
else if (ctype == CTYPE_GZIP)
|
|
||||||
print_output("gzip");
|
|
||||||
else if (ctype == CTYPE_ZPAQ)
|
|
||||||
print_output("zpaq");
|
|
||||||
else
|
|
||||||
print_output("Dunno wtf");
|
|
||||||
utotal += u_len;
|
|
||||||
ctotal += c_len;
|
|
||||||
print_output("\t%.1f%%\t%lld / %lld", (double)c_len / (double)(u_len / 100), c_len, u_len);
|
|
||||||
print_maxverbose("\tOffset: %lld\tHead: %lld", head_off, last_head);
|
|
||||||
print_output("\n");
|
|
||||||
block++;
|
|
||||||
} while (last_head);
|
|
||||||
++stream;
|
|
||||||
}
|
|
||||||
ofs = lseek(fd_in, 0, SEEK_CUR) + c_len;
|
|
||||||
/* Chunk byte entry */
|
|
||||||
if (control.major_version == 0 && control.minor_version > 4)
|
|
||||||
ofs++;
|
|
||||||
if (ofs < infile_size - MD5_DIGEST_SIZE)
|
|
||||||
goto next_chunk;
|
|
||||||
if (unlikely(ofs > infile_size))
|
|
||||||
failure("Offset greater than archive size, likely corrupted/truncated archive.\n");
|
|
||||||
print_output("Rzip compression: %.1f%% %lld / %lld\n",
|
|
||||||
(double)utotal / (double)(expected_size / 100),
|
|
||||||
utotal, expected_size);
|
|
||||||
print_output("Back end compression: %.1f%% %lld / %lld\n",
|
|
||||||
(double)ctotal / (double)(utotal / 100),
|
|
||||||
ctotal, utotal);
|
|
||||||
print_output("Overall compression: %.1f%% %lld / %lld\n",
|
|
||||||
(double)ctotal / (double)(expected_size / 100),
|
|
||||||
ctotal, expected_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(close(fd_in)))
|
|
||||||
fatal("Failed to close fd_in in get_fileinfo\n");
|
|
||||||
|
|
||||||
free(control.outfile);
|
|
||||||
free(infilecopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
compress one file from the command line
|
|
||||||
*/
|
|
||||||
static void compress_file(void)
|
|
||||||
{
|
|
||||||
const char *tmp, *tmpinfile; /* we're just using this as a proxy for control.infile.
|
|
||||||
* Spares a compiler warning
|
|
||||||
*/
|
|
||||||
int fd_in, fd_out;
|
|
||||||
char header[24];
|
|
||||||
|
|
||||||
memset(header, 0, sizeof(header));
|
|
||||||
|
|
||||||
if (!STDIN) {
|
|
||||||
/* is extension at end of infile? */
|
|
||||||
if ((tmp = strrchr(control.infile, '.')) && !strcmp(tmp, control.suffix)) {
|
|
||||||
print_err("%s: already has %s suffix. Skipping...\n", control.infile, control.suffix);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_in = open(control.infile, O_RDONLY);
|
|
||||||
if (unlikely(fd_in == -1))
|
|
||||||
fatal("Failed to open %s\n", control.infile);
|
|
||||||
} else
|
|
||||||
fd_in = 0;
|
|
||||||
|
|
||||||
if (!STDOUT) {
|
|
||||||
if (control.outname) {
|
|
||||||
/* check if outname has control.suffix */
|
|
||||||
if (*(control.suffix) == '\0') /* suffix is empty string */
|
|
||||||
control.outfile = strdup(control.outname);
|
|
||||||
else if ((tmp=strrchr(control.outname, '.')) && strcmp(tmp, control.suffix)) {
|
|
||||||
control.outfile = malloc(strlen(control.outname) + strlen(control.suffix) + 1);
|
|
||||||
if (unlikely(!control.outfile))
|
|
||||||
fatal("Failed to allocate outfile name\n");
|
|
||||||
strcpy(control.outfile, control.outname);
|
|
||||||
strcat(control.outfile, control.suffix);
|
|
||||||
print_output("Suffix added to %s.\nFull pathname is: %s\n", control.outname, control.outfile);
|
|
||||||
} else /* no, already has suffix */
|
|
||||||
control.outfile = strdup(control.outname);
|
|
||||||
} else {
|
|
||||||
/* default output name from control.infile
|
|
||||||
* test if outdir specified. If so, strip path from filename of
|
|
||||||
* control.infile
|
|
||||||
*/
|
|
||||||
if (control.outdir && (tmp = strrchr(control.infile, '/')))
|
|
||||||
tmpinfile = tmp + 1;
|
|
||||||
else
|
|
||||||
tmpinfile = control.infile;
|
|
||||||
|
|
||||||
control.outfile = malloc((control.outdir == NULL? 0: strlen(control.outdir)) + strlen(tmpinfile) + strlen(control.suffix) + 1);
|
|
||||||
if (unlikely(!control.outfile))
|
|
||||||
fatal("Failed to allocate outfile name\n");
|
|
||||||
|
|
||||||
if (control.outdir) { /* prepend control.outdir */
|
|
||||||
strcpy(control.outfile, control.outdir);
|
|
||||||
strcat(control.outfile, tmpinfile);
|
|
||||||
} else
|
|
||||||
strcpy(control.outfile, tmpinfile);
|
|
||||||
strcat(control.outfile, control.suffix);
|
|
||||||
print_progress("Output filename is: %s\n", control.outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FORCE_REPLACE)
|
|
||||||
fd_out = open(control.outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
|
||||||
else
|
|
||||||
fd_out = open(control.outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
|
||||||
if (unlikely(fd_out == -1)) {
|
|
||||||
/* We must ensure we don't delete a file that already
|
|
||||||
* exists just because we tried to create a new one */
|
|
||||||
control.flags |= FLAG_KEEP_BROKEN;
|
|
||||||
fatal("Failed to create %s\n", control.outfile);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
fd_out = open_tmpoutfile();
|
|
||||||
control.fd_out = fd_out;
|
|
||||||
|
|
||||||
if (unlikely(STDOUT && unlink(control.outfile)))
|
|
||||||
fatal("Failed to unlink tmpfile: %s\n", control.outfile);
|
|
||||||
|
|
||||||
preserve_perms(fd_in, fd_out);
|
|
||||||
|
|
||||||
/* write zeroes to 24 bytes at beginning of file */
|
|
||||||
if (unlikely(write(fd_out, header, sizeof(header)) != sizeof(header)))
|
|
||||||
fatal("Cannot write file header\n");
|
|
||||||
|
|
||||||
rzip_fd(fd_in, fd_out);
|
|
||||||
|
|
||||||
/* write magic at end b/c lzma does not tell us properties until it is done */
|
|
||||||
write_magic(fd_in, fd_out);
|
|
||||||
|
|
||||||
if (STDOUT)
|
|
||||||
dump_tmpoutfile(fd_out);
|
|
||||||
|
|
||||||
if (unlikely(close(fd_in) || close(fd_out)))
|
|
||||||
fatal("Failed to close files\n");
|
|
||||||
|
|
||||||
if (!KEEP_FILES) {
|
|
||||||
if (unlikely(unlink(control.infile)))
|
|
||||||
fatal("Failed to unlink %s\n", control.infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(control.outfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_summary(void)
|
static void show_summary(void)
|
||||||
{
|
{
|
||||||
/* OK, if verbosity set, print summary of options selected */
|
/* OK, if verbosity set, print summary of options selected */
|
||||||
|
|
@ -790,6 +192,7 @@ int main(int argc, char *argv[])
|
||||||
memset(&control, 0, sizeof(control));
|
memset(&control, 0, sizeof(control));
|
||||||
|
|
||||||
control.msgout = stderr;
|
control.msgout = stderr;
|
||||||
|
register_outputfile(control.msgout);
|
||||||
control.flags = FLAG_SHOW_PROGRESS | FLAG_KEEP_FILES | FLAG_THRESHOLD;
|
control.flags = FLAG_SHOW_PROGRESS | FLAG_KEEP_FILES | FLAG_THRESHOLD;
|
||||||
control.suffix = ".lrz";
|
control.suffix = ".lrz";
|
||||||
control.outdir = NULL;
|
control.outdir = NULL;
|
||||||
|
|
@ -1013,16 +416,20 @@ int main(int argc, char *argv[])
|
||||||
if (control.outname && (strcmp(control.outname, "-") == 0)) {
|
if (control.outname && (strcmp(control.outname, "-") == 0)) {
|
||||||
control.flags |= FLAG_STDOUT;
|
control.flags |= FLAG_STDOUT;
|
||||||
control.msgout = stderr;
|
control.msgout = stderr;
|
||||||
|
register_outputfile(control.msgout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're using stdin and no output filename, use stdout */
|
/* If we're using stdin and no output filename, use stdout */
|
||||||
if (STDIN && !control.outname) {
|
if (STDIN && !control.outname) {
|
||||||
control.flags |= FLAG_STDOUT;
|
control.flags |= FLAG_STDOUT;
|
||||||
control.msgout = stderr;
|
control.msgout = stderr;
|
||||||
|
register_outputfile(control.msgout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!STDOUT)
|
if (!STDOUT) {
|
||||||
control.msgout = stdout;
|
control.msgout = stdout;
|
||||||
|
register_outputfile(control.msgout);
|
||||||
|
}
|
||||||
/* Implement signal handler only once flags are set */
|
/* Implement signal handler only once flags are set */
|
||||||
handler.sa_handler = &sighandler;
|
handler.sa_handler = &sighandler;
|
||||||
sigaction(SIGTERM, &handler, 0);
|
sigaction(SIGTERM, &handler, 0);
|
||||||
|
|
@ -1056,11 +463,11 @@ int main(int argc, char *argv[])
|
||||||
gettimeofday(&start_time, NULL);
|
gettimeofday(&start_time, NULL);
|
||||||
|
|
||||||
if (control.flags & (FLAG_DECOMPRESS | FLAG_TEST_ONLY))
|
if (control.flags & (FLAG_DECOMPRESS | FLAG_TEST_ONLY))
|
||||||
decompress_file();
|
decompress_file(&control);
|
||||||
else if (INFO)
|
else if (INFO)
|
||||||
get_fileinfo();
|
get_fileinfo(&control);
|
||||||
else
|
else
|
||||||
compress_file();
|
compress_file(&control);
|
||||||
|
|
||||||
/* compute total time */
|
/* compute total time */
|
||||||
gettimeofday(&end_time, NULL);
|
gettimeofday(&end_time, NULL);
|
||||||
|
|
|
||||||
58
runzip.c
58
runzip.c
|
|
@ -19,26 +19,26 @@
|
||||||
|
|
||||||
#include "rzip.h"
|
#include "rzip.h"
|
||||||
|
|
||||||
static inline uchar read_u8(void *ss, int stream)
|
static inline uchar read_u8(rzip_control *control, void *ss, int stream)
|
||||||
{
|
{
|
||||||
uchar b;
|
uchar b;
|
||||||
|
|
||||||
if (unlikely(read_stream(ss, stream, &b, 1) != 1))
|
if (unlikely(read_stream(control, ss, stream, &b, 1) != 1))
|
||||||
fatal("Stream read u8 failed\n");
|
fatal("Stream read u8 failed\n");
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 read_u32(void *ss, int stream)
|
static inline u32 read_u32(rzip_control *control, void *ss, int stream)
|
||||||
{
|
{
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
|
||||||
if (unlikely(read_stream(ss, stream, (uchar *)&ret, 4) != 4))
|
if (unlikely(read_stream(control, ss, stream, (uchar *)&ret, 4) != 4))
|
||||||
fatal("Stream read u32 failed\n");
|
fatal("Stream read u32 failed\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a variable length of chars dependant on how big the chunk was */
|
/* Read a variable length of chars dependant on how big the chunk was */
|
||||||
static inline i64 read_vchars(void *ss, int stream, int length)
|
static inline i64 read_vchars(rzip_control *control, void *ss, int stream, int length)
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
i64 s = 0;
|
i64 s = 0;
|
||||||
|
|
@ -46,24 +46,24 @@ static inline i64 read_vchars(void *ss, int stream, int length)
|
||||||
for (bytes = 0; bytes < length; bytes++) {
|
for (bytes = 0; bytes < length; bytes++) {
|
||||||
int bits = bytes * 8;
|
int bits = bytes * 8;
|
||||||
|
|
||||||
uchar sb = read_u8(ss, stream);
|
uchar sb = read_u8(control, ss, stream);
|
||||||
s |= (i64)sb << bits;
|
s |= (i64)sb << bits;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static i64 read_header(void *ss, uchar *head)
|
static i64 read_header(rzip_control *control, void *ss, uchar *head)
|
||||||
{
|
{
|
||||||
int chunk_bytes = 2;
|
int chunk_bytes = 2;
|
||||||
|
|
||||||
/* All chunks were unnecessarily encoded 8 bytes wide version 0.4x */
|
/* All chunks were unnecessarily encoded 8 bytes wide version 0.4x */
|
||||||
if (control.major_version == 0 && control.minor_version == 4)
|
if (control->major_version == 0 && control->minor_version == 4)
|
||||||
chunk_bytes = 8;
|
chunk_bytes = 8;
|
||||||
*head = read_u8(ss, 0);
|
*head = read_u8(control, ss, 0);
|
||||||
return read_vchars(ss, 0, chunk_bytes);
|
return read_vchars(control, ss, 0, chunk_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static i64 unzip_literal(void *ss, i64 len, int fd_out, uint32 *cksum)
|
static i64 unzip_literal(rzip_control *control, void *ss, i64 len, int fd_out, uint32 *cksum)
|
||||||
{
|
{
|
||||||
i64 stream_read;
|
i64 stream_read;
|
||||||
uchar *buf;
|
uchar *buf;
|
||||||
|
|
@ -75,7 +75,7 @@ static i64 unzip_literal(void *ss, i64 len, int fd_out, uint32 *cksum)
|
||||||
if (unlikely(!buf))
|
if (unlikely(!buf))
|
||||||
fatal("Failed to malloc literal buffer of size %lld\n", len);
|
fatal("Failed to malloc literal buffer of size %lld\n", len);
|
||||||
|
|
||||||
stream_read = read_stream(ss, 1, buf, len);
|
stream_read = read_stream(control, ss, 1, buf, len);
|
||||||
if (unlikely(stream_read == -1 ))
|
if (unlikely(stream_read == -1 ))
|
||||||
fatal("Failed to read_stream in unzip_literal\n");
|
fatal("Failed to read_stream in unzip_literal\n");
|
||||||
|
|
||||||
|
|
@ -85,13 +85,13 @@ static i64 unzip_literal(void *ss, i64 len, int fd_out, uint32 *cksum)
|
||||||
if (!HAS_MD5)
|
if (!HAS_MD5)
|
||||||
*cksum = CrcUpdate(*cksum, buf, stream_read);
|
*cksum = CrcUpdate(*cksum, buf, stream_read);
|
||||||
if (!NO_MD5)
|
if (!NO_MD5)
|
||||||
md5_process_bytes(buf, stream_read, &control.ctx);
|
md5_process_bytes(buf, stream_read, &control->ctx);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
return stream_read;
|
return stream_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static i64 unzip_match(void *ss, i64 len, int fd_out, int fd_hist, uint32 *cksum, int chunk_bytes)
|
static i64 unzip_match(rzip_control *control, void *ss, i64 len, int fd_out, int fd_hist, uint32 *cksum, int chunk_bytes)
|
||||||
{
|
{
|
||||||
i64 offset, n, total, cur_pos;
|
i64 offset, n, total, cur_pos;
|
||||||
uchar *buf, *off_buf;
|
uchar *buf, *off_buf;
|
||||||
|
|
@ -105,7 +105,7 @@ static i64 unzip_match(void *ss, i64 len, int fd_out, int fd_hist, uint32 *cksum
|
||||||
fatal("Seek failed on out file in unzip_match.\n");
|
fatal("Seek failed on out file in unzip_match.\n");
|
||||||
|
|
||||||
/* Note the offset is in a different format v0.40+ */
|
/* Note the offset is in a different format v0.40+ */
|
||||||
offset = read_vchars(ss, 0, chunk_bytes);
|
offset = read_vchars(control, ss, 0, chunk_bytes);
|
||||||
if (unlikely(lseek(fd_hist, cur_pos - offset, SEEK_SET) == -1))
|
if (unlikely(lseek(fd_hist, cur_pos - offset, SEEK_SET) == -1))
|
||||||
fatal("Seek failed by %d from %d on history file in unzip_match\n",
|
fatal("Seek failed by %d from %d on history file in unzip_match\n",
|
||||||
offset, cur_pos);
|
offset, cur_pos);
|
||||||
|
|
@ -127,7 +127,7 @@ static i64 unzip_match(void *ss, i64 len, int fd_out, int fd_hist, uint32 *cksum
|
||||||
if (!HAS_MD5)
|
if (!HAS_MD5)
|
||||||
*cksum = CrcUpdate(*cksum, off_buf, n);
|
*cksum = CrcUpdate(*cksum, off_buf, n);
|
||||||
if (!NO_MD5)
|
if (!NO_MD5)
|
||||||
md5_process_bytes(off_buf, n, &control.ctx);
|
md5_process_bytes(off_buf, n, &control->ctx);
|
||||||
|
|
||||||
len -= n;
|
len -= n;
|
||||||
off_buf += n;
|
off_buf += n;
|
||||||
|
|
@ -142,7 +142,7 @@ static i64 unzip_match(void *ss, i64 len, int fd_out, int fd_hist, uint32 *cksum
|
||||||
/* decompress a section of an open file. Call fatal() on error
|
/* decompress a section of an open file. Call fatal() on error
|
||||||
return the number of bytes that have been retrieved
|
return the number of bytes that have been retrieved
|
||||||
*/
|
*/
|
||||||
static i64 runzip_chunk(int fd_in, int fd_out, int fd_hist, i64 expected_size, i64 tally)
|
static i64 runzip_chunk(rzip_control *control, int fd_in, int fd_out, int fd_hist, i64 expected_size, i64 tally)
|
||||||
{
|
{
|
||||||
uint32 good_cksum, cksum = 0;
|
uint32 good_cksum, cksum = 0;
|
||||||
i64 len, ofs, total = 0;
|
i64 len, ofs, total = 0;
|
||||||
|
|
@ -172,9 +172,9 @@ static i64 runzip_chunk(int fd_in, int fd_out, int fd_hist, i64 expected_size, i
|
||||||
/* Determine the chunk_byte width size. Versions < 0.4 used 4
|
/* Determine the chunk_byte width size. Versions < 0.4 used 4
|
||||||
* bytes for all offsets, version 0.4 used 8 bytes. Versions 0.5+ use
|
* bytes for all offsets, version 0.4 used 8 bytes. Versions 0.5+ use
|
||||||
* a variable number of bytes depending on chunk size.*/
|
* a variable number of bytes depending on chunk size.*/
|
||||||
if (control.major_version == 0 && control.minor_version < 4)
|
if (control->major_version == 0 && control->minor_version < 4)
|
||||||
chunk_bytes = 4;
|
chunk_bytes = 4;
|
||||||
else if (control.major_version == 0 && control.minor_version == 4)
|
else if (control->major_version == 0 && control->minor_version == 4)
|
||||||
chunk_bytes = 8;
|
chunk_bytes = 8;
|
||||||
else {
|
else {
|
||||||
/* Read in the stored chunk byte width from the file */
|
/* Read in the stored chunk byte width from the file */
|
||||||
|
|
@ -192,18 +192,18 @@ static i64 runzip_chunk(int fd_in, int fd_out, int fd_hist, i64 expected_size, i
|
||||||
if (fstat(fd_in, &st) || st.st_size - ofs == 0)
|
if (fstat(fd_in, &st) || st.st_size - ofs == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ss = open_stream_in(fd_in, NUM_STREAMS);
|
ss = open_stream_in(control, fd_in, NUM_STREAMS);
|
||||||
if (unlikely(!ss))
|
if (unlikely(!ss))
|
||||||
fatal("Failed to open_stream_in in runzip_chunk\n");
|
fatal("Failed to open_stream_in in runzip_chunk\n");
|
||||||
|
|
||||||
while ((len = read_header(ss, &head)) || head) {
|
while ((len = read_header(control, ss, &head)) || head) {
|
||||||
switch (head) {
|
switch (head) {
|
||||||
case 0:
|
case 0:
|
||||||
total += unzip_literal(ss, len, fd_out, &cksum);
|
total += unzip_literal(control, ss, len, fd_out, &cksum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
total += unzip_match(ss, len, fd_out, fd_hist, &cksum, chunk_bytes);
|
total += unzip_match(control, ss, len, fd_out, fd_hist, &cksum, chunk_bytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p = 100 * ((double)(tally + total) / (double)expected_size);
|
p = 100 * ((double)(tally + total) / (double)expected_size);
|
||||||
|
|
@ -216,7 +216,7 @@ static i64 runzip_chunk(int fd_in, int fd_out, int fd_hist, i64 expected_size, i
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HAS_MD5) {
|
if (!HAS_MD5) {
|
||||||
good_cksum = read_u32(ss, 0);
|
good_cksum = read_u32(control, ss, 0);
|
||||||
if (unlikely(good_cksum != cksum))
|
if (unlikely(good_cksum != cksum))
|
||||||
failure("Bad checksum: 0x%08x - expected: 0x%08x\n", cksum, good_cksum);
|
failure("Bad checksum: 0x%08x - expected: 0x%08x\n", cksum, good_cksum);
|
||||||
print_maxverbose("Checksum for block: 0x%08x\n", cksum);
|
print_maxverbose("Checksum for block: 0x%08x\n", cksum);
|
||||||
|
|
@ -231,7 +231,7 @@ static i64 runzip_chunk(int fd_in, int fd_out, int fd_hist, i64 expected_size, i
|
||||||
/* Decompress an open file. Call fatal() on error
|
/* Decompress an open file. Call fatal() on error
|
||||||
return the number of bytes that have been retrieved
|
return the number of bytes that have been retrieved
|
||||||
*/
|
*/
|
||||||
i64 runzip_fd(int fd_in, int fd_out, int fd_hist, i64 expected_size)
|
i64 runzip_fd(rzip_control *control, int fd_in, int fd_out, int fd_hist, i64 expected_size)
|
||||||
{
|
{
|
||||||
char md5_resblock[MD5_DIGEST_SIZE];
|
char md5_resblock[MD5_DIGEST_SIZE];
|
||||||
char md5_stored[MD5_DIGEST_SIZE];
|
char md5_stored[MD5_DIGEST_SIZE];
|
||||||
|
|
@ -239,13 +239,13 @@ i64 runzip_fd(int fd_in, int fd_out, int fd_hist, i64 expected_size)
|
||||||
i64 total = 0;
|
i64 total = 0;
|
||||||
|
|
||||||
if (!NO_MD5)
|
if (!NO_MD5)
|
||||||
md5_init_ctx (&control.ctx);
|
md5_init_ctx (&control->ctx);
|
||||||
gettimeofday(&start,NULL);
|
gettimeofday(&start,NULL);
|
||||||
|
|
||||||
while (total < expected_size) {
|
while (total < expected_size) {
|
||||||
total += runzip_chunk(fd_in, fd_out, fd_hist, expected_size, total);
|
total += runzip_chunk(control, fd_in, fd_out, fd_hist, expected_size, total);
|
||||||
if (STDOUT)
|
if (STDOUT)
|
||||||
dump_tmpoutfile(fd_out);
|
dump_tmpoutfile(control, fd_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&end,NULL);
|
gettimeofday(&end,NULL);
|
||||||
|
|
@ -255,7 +255,7 @@ i64 runzip_fd(int fd_in, int fd_out, int fd_hist, i64 expected_size)
|
||||||
if (!NO_MD5) {
|
if (!NO_MD5) {
|
||||||
int i,j;
|
int i,j;
|
||||||
|
|
||||||
md5_finish_ctx (&control.ctx, md5_resblock);
|
md5_finish_ctx (&control->ctx, md5_resblock);
|
||||||
if (HAS_MD5) {
|
if (HAS_MD5) {
|
||||||
if (unlikely(lseek(fd_in, -MD5_DIGEST_SIZE, SEEK_END)) == -1)
|
if (unlikely(lseek(fd_in, -MD5_DIGEST_SIZE, SEEK_END)) == -1)
|
||||||
fatal("Failed to seek to md5 data in runzip_fd\n");
|
fatal("Failed to seek to md5 data in runzip_fd\n");
|
||||||
|
|
|
||||||
194
rzip.c
194
rzip.c
|
|
@ -100,7 +100,7 @@ struct sliding_buffer {
|
||||||
int fd; /* The fd of the mmap */
|
int fd; /* The fd of the mmap */
|
||||||
} sb; /* Sliding buffer */
|
} sb; /* Sliding buffer */
|
||||||
|
|
||||||
static void remap_low_sb(void)
|
static void remap_low_sb(rzip_control *control)
|
||||||
{
|
{
|
||||||
i64 new_offset;
|
i64 new_offset;
|
||||||
|
|
||||||
|
|
@ -117,14 +117,14 @@ static void remap_low_sb(void)
|
||||||
fatal("Failed to re mmap in remap_low_sb\n");
|
fatal("Failed to re mmap in remap_low_sb\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void remap_high_sb(i64 p)
|
static inline void remap_high_sb(rzip_control *control, i64 p)
|
||||||
{
|
{
|
||||||
if (unlikely(munmap(sb.buf_high, sb.size_high)))
|
if (unlikely(munmap(sb.buf_high, sb.size_high)))
|
||||||
fatal("Failed to munmap in remap_high_sb\n");
|
fatal("Failed to munmap in remap_high_sb\n");
|
||||||
sb.size_high = sb.high_length; /* In case we shrunk it when we hit the end of the file */
|
sb.size_high = sb.high_length; /* In case we shrunk it when we hit the end of the file */
|
||||||
sb.offset_high = p;
|
sb.offset_high = p;
|
||||||
/* Make sure offset is rounded to page size of total offset */
|
/* Make sure offset is rounded to page size of total offset */
|
||||||
sb.offset_high -= (sb.offset_high + sb.orig_offset) % control.page_size;
|
sb.offset_high -= (sb.offset_high + sb.orig_offset) % control->page_size;
|
||||||
if (unlikely(sb.offset_high + sb.size_high > sb.orig_size))
|
if (unlikely(sb.offset_high + sb.size_high > sb.orig_size))
|
||||||
sb.size_high = sb.orig_size - sb.offset_high;
|
sb.size_high = sb.orig_size - sb.offset_high;
|
||||||
sb.buf_high = (uchar *)mmap(sb.buf_high, sb.size_high, PROT_READ, MAP_SHARED, sb.fd, sb.orig_offset + sb.offset_high);
|
sb.buf_high = (uchar *)mmap(sb.buf_high, sb.size_high, PROT_READ, MAP_SHARED, sb.fd, sb.orig_offset + sb.offset_high);
|
||||||
|
|
@ -138,36 +138,36 @@ static inline void remap_high_sb(i64 p)
|
||||||
* it, and a 64k mmap block that slides up and down as is required for any
|
* it, and a 64k mmap block that slides up and down as is required for any
|
||||||
* offsets outside the range of the lower one. This is much slower than mmap
|
* offsets outside the range of the lower one. This is much slower than mmap
|
||||||
* but makes it possible to have unlimited sized compression windows. */
|
* but makes it possible to have unlimited sized compression windows. */
|
||||||
static uchar *get_sb(i64 p)
|
static uchar *get_sb(rzip_control *control, i64 p)
|
||||||
{
|
{
|
||||||
i64 low_end = sb.offset_low + sb.size_low;
|
i64 low_end = sb.offset_low + sb.size_low;
|
||||||
|
|
||||||
if (unlikely(sb.offset_search > low_end))
|
if (unlikely(sb.offset_search > low_end))
|
||||||
remap_low_sb();
|
remap_low_sb(control);
|
||||||
if (p >= sb.offset_low && p < low_end)
|
if (p >= sb.offset_low && p < low_end)
|
||||||
return (sb.buf_low + p - sb.offset_low);
|
return (sb.buf_low + p - sb.offset_low);
|
||||||
if (p >= sb.offset_high && p < (sb.offset_high + sb.size_high))
|
if (p >= sb.offset_high && p < (sb.offset_high + sb.size_high))
|
||||||
return (sb.buf_high + (p - sb.offset_high));
|
return (sb.buf_high + (p - sb.offset_high));
|
||||||
/* p is not within the low or high buffer range */
|
/* p is not within the low or high buffer range */
|
||||||
remap_high_sb(p);
|
remap_high_sb(control, p);
|
||||||
return (sb.buf_high + (p - sb.offset_high));
|
return (sb.buf_high + (p - sb.offset_high));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All put_u8/u32/vchars go to stream 0 */
|
/* All put_u8/u32/vchars go to stream 0 */
|
||||||
static inline void put_u8(void *ss, uchar b)
|
static inline void put_u8(rzip_control *control, void *ss, uchar b)
|
||||||
{
|
{
|
||||||
if (unlikely(write_stream(ss, 0, &b, 1)))
|
if (unlikely(write_stream(control, ss, 0, &b, 1)))
|
||||||
fatal("Failed to put_u8\n");
|
fatal("Failed to put_u8\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void put_u32(void *ss, uint32_t s)
|
static inline void put_u32(rzip_control *control, void *ss, uint32_t s)
|
||||||
{
|
{
|
||||||
if (unlikely(write_stream(ss, 0, (uchar *)&s, 4)))
|
if (unlikely(write_stream(control, ss, 0, (uchar *)&s, 4)))
|
||||||
fatal("Failed to put_u32\n");
|
fatal("Failed to put_u32\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put a variable length of bytes dependant on how big the chunk is */
|
/* Put a variable length of bytes dependant on how big the chunk is */
|
||||||
static inline void put_vchars(void *ss, i64 s, int length)
|
static inline void put_vchars(rzip_control *control, void *ss, i64 s, int length)
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
|
|
@ -175,17 +175,17 @@ static inline void put_vchars(void *ss, i64 s, int length)
|
||||||
int bits = bytes * 8;
|
int bits = bytes * 8;
|
||||||
uchar sb = (s >> bits) & (i64)0XFF;
|
uchar sb = (s >> bits) & (i64)0XFF;
|
||||||
|
|
||||||
put_u8(ss, sb);
|
put_u8(control, ss, sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_header(void *ss, uchar head, i64 len)
|
static void put_header(rzip_control *control, void *ss, uchar head, i64 len)
|
||||||
{
|
{
|
||||||
put_u8(ss, head);
|
put_u8(control, ss, head);
|
||||||
put_vchars(ss, len, 2);
|
put_vchars(control, ss, len, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_match(struct rzip_state *st, i64 p, i64 offset, i64 len)
|
static void put_match(rzip_control *control, struct rzip_state *st, i64 p, i64 offset, i64 len)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
i64 ofs;
|
i64 ofs;
|
||||||
|
|
@ -194,8 +194,8 @@ static void put_match(struct rzip_state *st, i64 p, i64 offset, i64 len)
|
||||||
n = 0xFFFF;
|
n = 0xFFFF;
|
||||||
|
|
||||||
ofs = (p - offset);
|
ofs = (p - offset);
|
||||||
put_header(st->ss, 1, n);
|
put_header(control, st->ss, 1, n);
|
||||||
put_vchars(st->ss, ofs, st->chunk_bytes);
|
put_vchars(control, st->ss, ofs, st->chunk_bytes);
|
||||||
|
|
||||||
st->stats.matches++;
|
st->stats.matches++;
|
||||||
st->stats.match_bytes += n;
|
st->stats.match_bytes += n;
|
||||||
|
|
@ -206,7 +206,7 @@ static void put_match(struct rzip_state *st, i64 p, i64 offset, i64 len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write some data to a stream mmap encoded. Return -1 on failure */
|
/* write some data to a stream mmap encoded. Return -1 on failure */
|
||||||
int write_sbstream(void *ss, int stream, i64 p, i64 len)
|
int write_sbstream(rzip_control *control, void *ss, int stream, i64 p, i64 len)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo = ss;
|
struct stream_info *sinfo = ss;
|
||||||
|
|
||||||
|
|
@ -217,19 +217,19 @@ int write_sbstream(void *ss, int stream, i64 p, i64 len)
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
memcpy(sinfo->s[stream].buf + sinfo->s[stream].buflen + i,
|
memcpy(sinfo->s[stream].buf + sinfo->s[stream].buflen + i,
|
||||||
get_sb(p + i), 1);
|
get_sb(control, p + i), 1);
|
||||||
}
|
}
|
||||||
sinfo->s[stream].buflen += n;
|
sinfo->s[stream].buflen += n;
|
||||||
p += n;
|
p += n;
|
||||||
len -= n;
|
len -= n;
|
||||||
|
|
||||||
if (sinfo->s[stream].buflen == sinfo->bufsize)
|
if (sinfo->s[stream].buflen == sinfo->bufsize)
|
||||||
flush_buffer(sinfo, stream);
|
flush_buffer(control, sinfo, stream);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_literal(struct rzip_state *st, i64 last, i64 p)
|
static void put_literal(rzip_control *control, struct rzip_state *st, i64 last, i64 p)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
i64 len = p - last;
|
i64 len = p - last;
|
||||||
|
|
@ -239,9 +239,9 @@ static void put_literal(struct rzip_state *st, i64 last, i64 p)
|
||||||
st->stats.literals++;
|
st->stats.literals++;
|
||||||
st->stats.literal_bytes += len;
|
st->stats.literal_bytes += len;
|
||||||
|
|
||||||
put_header(st->ss, 0, len);
|
put_header(control, st->ss, 0, len);
|
||||||
|
|
||||||
if (unlikely(len && write_sbstream(st->ss, 1, last, len)))
|
if (unlikely(len && write_sbstream(control, st->ss, 1, last, len)))
|
||||||
fatal("Failed to write_stream in put_literal\n");
|
fatal("Failed to write_stream in put_literal\n");
|
||||||
last += len;
|
last += len;
|
||||||
} while (p > last);
|
} while (p > last);
|
||||||
|
|
@ -337,7 +337,7 @@ static void insert_hash(struct rzip_state *st, tag t, i64 offset)
|
||||||
|
|
||||||
/* Eliminate one hash entry with minimum number of lower bits set.
|
/* Eliminate one hash entry with minimum number of lower bits set.
|
||||||
Returns tag requirement for any new entries. */
|
Returns tag requirement for any new entries. */
|
||||||
static tag clean_one_from_hash(struct rzip_state *st)
|
static tag clean_one_from_hash(rzip_control *control, struct rzip_state *st)
|
||||||
{
|
{
|
||||||
tag better_than_min;
|
tag better_than_min;
|
||||||
|
|
||||||
|
|
@ -364,24 +364,24 @@ again:
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline tag next_tag(struct rzip_state *st, i64 p, tag t)
|
static inline tag next_tag(rzip_control *control, struct rzip_state *st, i64 p, tag t)
|
||||||
{
|
{
|
||||||
t ^= st->hash_index[*get_sb(p - 1)];
|
t ^= st->hash_index[*get_sb(control, p - 1)];
|
||||||
t ^= st->hash_index[*get_sb(p + MINIMUM_MATCH - 1)];
|
t ^= st->hash_index[*get_sb(control, p + MINIMUM_MATCH - 1)];
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline tag full_tag(struct rzip_state *st, i64 p)
|
static inline tag full_tag(rzip_control *control, struct rzip_state *st, i64 p)
|
||||||
{
|
{
|
||||||
tag ret = 0;
|
tag ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MINIMUM_MATCH; i++)
|
for (i = 0; i < MINIMUM_MATCH; i++)
|
||||||
ret ^= st->hash_index[*get_sb(p + i)];
|
ret ^= st->hash_index[*get_sb(control, p + i)];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline i64 match_len(struct rzip_state *st, i64 p0, i64 op, i64 end,
|
static inline i64 match_len(rzip_control *control, struct rzip_state *st, i64 p0, i64 op, i64 end,
|
||||||
i64 *rev)
|
i64 *rev)
|
||||||
{
|
{
|
||||||
i64 p = p0;
|
i64 p = p0;
|
||||||
|
|
@ -390,7 +390,7 @@ static inline i64 match_len(struct rzip_state *st, i64 p0, i64 op, i64 end,
|
||||||
if (op >= p0)
|
if (op >= p0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while ((*get_sb(p) == *get_sb(op)) && (p < end)) {
|
while ((*get_sb(control, p) == *get_sb(control, op)) && (p < end)) {
|
||||||
p++;
|
p++;
|
||||||
op++;
|
op++;
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +403,7 @@ static inline i64 match_len(struct rzip_state *st, i64 p0, i64 op, i64 end,
|
||||||
if (end < st->last_match)
|
if (end < st->last_match)
|
||||||
end = st->last_match;
|
end = st->last_match;
|
||||||
|
|
||||||
while (p > end && op > 0 && *get_sb(op - 1) == *get_sb(p - 1)) {
|
while (p > end && op > 0 && *get_sb(control, op - 1) == *get_sb(control, p - 1)) {
|
||||||
op--;
|
op--;
|
||||||
p--;
|
p--;
|
||||||
}
|
}
|
||||||
|
|
@ -417,7 +417,7 @@ static inline i64 match_len(struct rzip_state *st, i64 p0, i64 op, i64 end,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static i64 find_best_match(struct rzip_state *st, tag t, i64 p, i64 end,
|
static i64 find_best_match(rzip_control *control, struct rzip_state *st, tag t, i64 p, i64 end,
|
||||||
i64 *offset, i64 *reverse)
|
i64 *offset, i64 *reverse)
|
||||||
{
|
{
|
||||||
i64 length = 0;
|
i64 length = 0;
|
||||||
|
|
@ -434,7 +434,7 @@ static i64 find_best_match(struct rzip_state *st, tag t, i64 p, i64 end,
|
||||||
i64 mlen;
|
i64 mlen;
|
||||||
|
|
||||||
if (t == st->hash_table[h].t) {
|
if (t == st->hash_table[h].t) {
|
||||||
mlen = match_len(st, p, st->hash_table[h].offset, end,
|
mlen = match_len(control, st, p, st->hash_table[h].offset, end,
|
||||||
&rev);
|
&rev);
|
||||||
|
|
||||||
if (mlen)
|
if (mlen)
|
||||||
|
|
@ -457,7 +457,7 @@ static i64 find_best_match(struct rzip_state *st, tag t, i64 p, i64 end,
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_distrib(struct rzip_state *st)
|
static void show_distrib(rzip_control *control, struct rzip_state *st)
|
||||||
{
|
{
|
||||||
i64 primary = 0;
|
i64 primary = 0;
|
||||||
i64 total = 0;
|
i64 total = 0;
|
||||||
|
|
@ -478,7 +478,7 @@ static void show_distrib(struct rzip_state *st)
|
||||||
primary*100.0/total);
|
primary*100.0/total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hash_search(struct rzip_state *st, double pct_base, double pct_multiple)
|
static void hash_search(rzip_control *control, struct rzip_state *st, double pct_base, double pct_multiple)
|
||||||
{
|
{
|
||||||
i64 cksum_limit = 0, p, end;
|
i64 cksum_limit = 0, p, end;
|
||||||
tag t = 0;
|
tag t = 0;
|
||||||
|
|
@ -520,7 +520,7 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
current.p = p;
|
current.p = p;
|
||||||
current.ofs = 0;
|
current.ofs = 0;
|
||||||
|
|
||||||
t = full_tag(st, p);
|
t = full_tag(control, st, p);
|
||||||
|
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
int lastpct = 0, last_chunkpct = 0;
|
int lastpct = 0, last_chunkpct = 0;
|
||||||
|
|
@ -528,14 +528,14 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
|
|
||||||
p++;
|
p++;
|
||||||
sb.offset_search = p;
|
sb.offset_search = p;
|
||||||
t = next_tag(st, p, t);
|
t = next_tag(control, st, p, t);
|
||||||
|
|
||||||
/* Don't look for a match if there are no tags with
|
/* Don't look for a match if there are no tags with
|
||||||
this number of bits in the hash table. */
|
this number of bits in the hash table. */
|
||||||
if ((t & st->minimum_tag_mask) != st->minimum_tag_mask)
|
if ((t & st->minimum_tag_mask) != st->minimum_tag_mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mlen = find_best_match(st, t, p, end, &offset, &reverse);
|
mlen = find_best_match(control, st, t, p, end, &offset, &reverse);
|
||||||
|
|
||||||
/* Only insert occasionally into hash. */
|
/* Only insert occasionally into hash. */
|
||||||
if ((t & tag_mask) == tag_mask) {
|
if ((t & tag_mask) == tag_mask) {
|
||||||
|
|
@ -543,7 +543,7 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
st->hash_count++;
|
st->hash_count++;
|
||||||
insert_hash(st, t, p);
|
insert_hash(st, t, p);
|
||||||
if (st->hash_count > st->hash_limit)
|
if (st->hash_count > st->hash_limit)
|
||||||
tag_mask = clean_one_from_hash(st);
|
tag_mask = clean_one_from_hash(control, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mlen > current.len) {
|
if (mlen > current.len) {
|
||||||
|
|
@ -555,12 +555,12 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
if ((current.len >= GREAT_MATCH || p >= current.p + MINIMUM_MATCH)
|
if ((current.len >= GREAT_MATCH || p >= current.p + MINIMUM_MATCH)
|
||||||
&& current.len >= MINIMUM_MATCH) {
|
&& current.len >= MINIMUM_MATCH) {
|
||||||
if (st->last_match < current.p)
|
if (st->last_match < current.p)
|
||||||
put_literal(st, st->last_match, current.p);
|
put_literal(control, st, st->last_match, current.p);
|
||||||
put_match(st, current.p, current.ofs, current.len);
|
put_match(control, st, current.p, current.ofs, current.len);
|
||||||
st->last_match = current.p + current.len;
|
st->last_match = current.p + current.len;
|
||||||
current.p = p = st->last_match;
|
current.p = p = st->last_match;
|
||||||
current.len = 0;
|
current.len = 0;
|
||||||
t = full_tag(st, p);
|
t = full_tag(control, st, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(p % 128 == 0)) {
|
if (unlikely(p % 128 == 0)) {
|
||||||
|
|
@ -579,25 +579,25 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p > (i64)cksum_limit) {
|
if (p > (i64)cksum_limit) {
|
||||||
i64 i, n = MIN(st->chunk_size - p, control.page_size);
|
i64 i, n = MIN(st->chunk_size - p, control->page_size);
|
||||||
uchar *ckbuf = malloc(n);
|
uchar *ckbuf = malloc(n);
|
||||||
|
|
||||||
if (unlikely(!ckbuf))
|
if (unlikely(!ckbuf))
|
||||||
fatal("Failed to malloc ckbuf in hash_search\n");
|
fatal("Failed to malloc ckbuf in hash_search\n");
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
memcpy(ckbuf + i, get_sb(cksum_limit + i), 1);
|
memcpy(ckbuf + i, get_sb(control, cksum_limit + i), 1);
|
||||||
st->cksum = CrcUpdate(st->cksum, ckbuf, n);
|
st->cksum = CrcUpdate(st->cksum, ckbuf, n);
|
||||||
md5_process_bytes(ckbuf, n, &control.ctx);
|
md5_process_bytes(ckbuf, n, &control->ctx);
|
||||||
cksum_limit += n;
|
cksum_limit += n;
|
||||||
free(ckbuf);
|
free(ckbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MAX_VERBOSE)
|
if (MAX_VERBOSE)
|
||||||
show_distrib(st);
|
show_distrib(control, st);
|
||||||
|
|
||||||
if (st->last_match < st->chunk_size)
|
if (st->last_match < st->chunk_size)
|
||||||
put_literal(st, st->last_match, st->chunk_size);
|
put_literal(control, st, st->last_match, st->chunk_size);
|
||||||
|
|
||||||
if (st->chunk_size > cksum_limit) {
|
if (st->chunk_size > cksum_limit) {
|
||||||
i64 i, n = st->chunk_size - cksum_limit;
|
i64 i, n = st->chunk_size - cksum_limit;
|
||||||
|
|
@ -606,15 +606,15 @@ static void hash_search(struct rzip_state *st, double pct_base, double pct_multi
|
||||||
if (unlikely(!ckbuf))
|
if (unlikely(!ckbuf))
|
||||||
fatal("Failed to malloc ckbuf in hash_search\n");
|
fatal("Failed to malloc ckbuf in hash_search\n");
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
memcpy(ckbuf + i, get_sb(cksum_limit + i), 1);
|
memcpy(ckbuf + i, get_sb(control, cksum_limit + i), 1);
|
||||||
st->cksum = CrcUpdate(st->cksum, ckbuf, n);
|
st->cksum = CrcUpdate(st->cksum, ckbuf, n);
|
||||||
md5_process_bytes(ckbuf, n, &control.ctx);
|
md5_process_bytes(ckbuf, n, &control->ctx);
|
||||||
cksum_limit += n;
|
cksum_limit += n;
|
||||||
free(ckbuf);
|
free(ckbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_literal(st, 0, 0);
|
put_literal(control, st, 0, 0);
|
||||||
put_u32(st->ss, st->cksum);
|
put_u32(control, st->ss, st->cksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -639,7 +639,7 @@ static inline void *fake_mremap(void *old_address, size_t old_size, size_t new_s
|
||||||
* anonymous ram and reading stdin into it. It means the maximum ram
|
* anonymous ram and reading stdin into it. It means the maximum ram
|
||||||
* we can use will be less but we will already have determined this in
|
* we can use will be less but we will already have determined this in
|
||||||
* rzip_chunk */
|
* rzip_chunk */
|
||||||
static void mmap_stdin(uchar *buf, struct rzip_state *st)
|
static void mmap_stdin(rzip_control *control, uchar *buf, struct rzip_state *st)
|
||||||
{
|
{
|
||||||
i64 len = st->chunk_size;
|
i64 len = st->chunk_size;
|
||||||
uchar *offset_buf = buf;
|
uchar *offset_buf = buf;
|
||||||
|
|
@ -669,17 +669,17 @@ static void mmap_stdin(uchar *buf, struct rzip_state *st)
|
||||||
offset_buf += ret;
|
offset_buf += ret;
|
||||||
len -= ret;
|
len -= ret;
|
||||||
}
|
}
|
||||||
control.st_size += total;
|
control->st_size += total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_sliding_mmap(struct rzip_state *st, int fd_in, i64 offset)
|
static void init_sliding_mmap(rzip_control *control, struct rzip_state *st, int fd_in, i64 offset)
|
||||||
{
|
{
|
||||||
/* Initialise the high buffer */
|
/* Initialise the high buffer */
|
||||||
if (!STDIN) {
|
if (!STDIN) {
|
||||||
sb.high_length = 65536;
|
sb.high_length = 65536;
|
||||||
/* Round up to the next biggest page size */
|
/* Round up to the next biggest page size */
|
||||||
if (sb.high_length % control.page_size)
|
if (sb.high_length % control->page_size)
|
||||||
sb.high_length += control.page_size - (sb.high_length % control.page_size);
|
sb.high_length += control->page_size - (sb.high_length % control->page_size);
|
||||||
sb.buf_high = (uchar *)mmap(NULL, sb.high_length, PROT_READ, MAP_SHARED, fd_in, offset);
|
sb.buf_high = (uchar *)mmap(NULL, sb.high_length, PROT_READ, MAP_SHARED, fd_in, offset);
|
||||||
if (unlikely(sb.buf_high == MAP_FAILED))
|
if (unlikely(sb.buf_high == MAP_FAILED))
|
||||||
fatal("Unable to mmap buf_high in init_sliding_mmap\n");
|
fatal("Unable to mmap buf_high in init_sliding_mmap\n");
|
||||||
|
|
@ -695,17 +695,17 @@ static void init_sliding_mmap(struct rzip_state *st, int fd_in, i64 offset)
|
||||||
|
|
||||||
/* compress a chunk of an open file. Assumes that the file is able to
|
/* compress a chunk of an open file. Assumes that the file is able to
|
||||||
be mmap'd and is seekable */
|
be mmap'd and is seekable */
|
||||||
static void rzip_chunk(struct rzip_state *st, int fd_in, int fd_out, i64 offset,
|
static void rzip_chunk(rzip_control *control, struct rzip_state *st, int fd_in, int fd_out, i64 offset,
|
||||||
double pct_base, double pct_multiple)
|
double pct_base, double pct_multiple)
|
||||||
{
|
{
|
||||||
init_sliding_mmap(st, fd_in, offset);
|
init_sliding_mmap(control, st, fd_in, offset);
|
||||||
|
|
||||||
st->ss = open_stream_out(fd_out, NUM_STREAMS, st->chunk_size, st->chunk_bytes);
|
st->ss = open_stream_out(control, fd_out, NUM_STREAMS, st->chunk_size, st->chunk_bytes);
|
||||||
if (unlikely(!st->ss))
|
if (unlikely(!st->ss))
|
||||||
fatal("Failed to open streams in rzip_chunk\n");
|
fatal("Failed to open streams in rzip_chunk\n");
|
||||||
|
|
||||||
print_verbose("Beginning rzip pre-processing phase\n");
|
print_verbose("Beginning rzip pre-processing phase\n");
|
||||||
hash_search(st, pct_base, pct_multiple);
|
hash_search(control, st, pct_base, pct_multiple);
|
||||||
|
|
||||||
/* unmap buffer before closing and reallocating streams */
|
/* unmap buffer before closing and reallocating streams */
|
||||||
if (unlikely(munmap(sb.buf_low, sb.size_low)))
|
if (unlikely(munmap(sb.buf_low, sb.size_low)))
|
||||||
|
|
@ -715,7 +715,7 @@ static void rzip_chunk(struct rzip_state *st, int fd_in, int fd_out, i64 offset,
|
||||||
fatal("Failed to munmap in rzip_chunk\n");
|
fatal("Failed to munmap in rzip_chunk\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(close_stream_out(st->ss)))
|
if (unlikely(close_stream_out(control, st->ss)))
|
||||||
fatal("Failed to flush/close streams in rzip_chunk\n");
|
fatal("Failed to flush/close streams in rzip_chunk\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -723,7 +723,7 @@ static void rzip_chunk(struct rzip_state *st, int fd_in, int fd_out, i64 offset,
|
||||||
const i64 two_gig = (1ull << 31) - 4096;
|
const i64 two_gig = (1ull << 31) - 4096;
|
||||||
|
|
||||||
/* compress a whole file chunks at a time */
|
/* compress a whole file chunks at a time */
|
||||||
void rzip_fd(int fd_in, int fd_out)
|
void rzip_fd(rzip_control *control, int fd_in, int fd_out)
|
||||||
{
|
{
|
||||||
/* add timers for ETA estimates
|
/* add timers for ETA estimates
|
||||||
* Base it off the file size and number of iterations required
|
* Base it off the file size and number of iterations required
|
||||||
|
|
@ -741,7 +741,7 @@ void rzip_fd(int fd_in, int fd_out)
|
||||||
double chunkmbs;
|
double chunkmbs;
|
||||||
i64 free_space;
|
i64 free_space;
|
||||||
|
|
||||||
md5_init_ctx (&control.ctx);
|
md5_init_ctx (&control->ctx);
|
||||||
|
|
||||||
st = calloc(sizeof(*st), 1);
|
st = calloc(sizeof(*st), 1);
|
||||||
if (unlikely(!st))
|
if (unlikely(!st))
|
||||||
|
|
@ -756,10 +756,10 @@ void rzip_fd(int fd_in, int fd_out)
|
||||||
fatal("Failed to stat fd_in in rzip_fd\n");
|
fatal("Failed to stat fd_in in rzip_fd\n");
|
||||||
|
|
||||||
if (!STDIN) {
|
if (!STDIN) {
|
||||||
len = control.st_size = s.st_size;
|
len = control->st_size = s.st_size;
|
||||||
print_verbose("File size: %lld\n", len);
|
print_verbose("File size: %lld\n", len);
|
||||||
} else
|
} else
|
||||||
control.st_size = 0;
|
control->st_size = 0;
|
||||||
|
|
||||||
/* Check if there's enough free space on the device chosen to fit the
|
/* Check if there's enough free space on the device chosen to fit the
|
||||||
* compressed file, based on the compressed file being as large as the
|
* compressed file, based on the compressed file being as large as the
|
||||||
|
|
@ -767,7 +767,7 @@ void rzip_fd(int fd_in, int fd_out)
|
||||||
if (unlikely(fstatvfs(fd_out, &fbuf)))
|
if (unlikely(fstatvfs(fd_out, &fbuf)))
|
||||||
fatal("Failed to fstatvfs in compress_file\n");
|
fatal("Failed to fstatvfs in compress_file\n");
|
||||||
free_space = fbuf.f_bsize * fbuf.f_bavail;
|
free_space = fbuf.f_bsize * fbuf.f_bavail;
|
||||||
if (free_space < control.st_size) {
|
if (free_space < control->st_size) {
|
||||||
if (FORCE_REPLACE)
|
if (FORCE_REPLACE)
|
||||||
print_err("Warning, possibly inadequate free space detected, but attempting to compress due to -f option being used.\n");
|
print_err("Warning, possibly inadequate free space detected, but attempting to compress due to -f option being used.\n");
|
||||||
else
|
else
|
||||||
|
|
@ -778,35 +778,35 @@ void rzip_fd(int fd_in, int fd_out)
|
||||||
* allocate 1/3 of it to the main buffer and use a sliding mmap
|
* allocate 1/3 of it to the main buffer and use a sliding mmap
|
||||||
* buffer to work on 2/3 ram size, leaving enough ram for the
|
* buffer to work on 2/3 ram size, leaving enough ram for the
|
||||||
* compression backends */
|
* compression backends */
|
||||||
control.max_mmap = control.maxram;
|
control->max_mmap = control->maxram;
|
||||||
|
|
||||||
/* On 32 bits we can have a big window with sliding mmap, but can
|
/* On 32 bits we can have a big window with sliding mmap, but can
|
||||||
* not enable much per mmap/malloc */
|
* not enable much per mmap/malloc */
|
||||||
if (BITS32)
|
if (BITS32)
|
||||||
control.max_mmap = MIN(control.max_mmap, two_gig);
|
control->max_mmap = MIN(control->max_mmap, two_gig);
|
||||||
round_to_page(&control.max_mmap);
|
round_to_page(&control->max_mmap);
|
||||||
|
|
||||||
/* Set maximum chunk size to 2/3 of ram if not unlimited or specified
|
/* Set maximum chunk size to 2/3 of ram if not unlimited or specified
|
||||||
* by a control window. When it's smaller than the file size, round it
|
* by a control window. When it's smaller than the file size, round it
|
||||||
* to page size for efficiency. */
|
* to page size for efficiency. */
|
||||||
if (UNLIMITED)
|
if (UNLIMITED)
|
||||||
control.max_chunk = control.st_size;
|
control->max_chunk = control->st_size;
|
||||||
else if (control.window)
|
else if (control->window)
|
||||||
control.max_chunk = control.window * CHUNK_MULTIPLE;
|
control->max_chunk = control->window * CHUNK_MULTIPLE;
|
||||||
else
|
else
|
||||||
control.max_chunk = control.ramsize / 3 * 2;
|
control->max_chunk = control->ramsize / 3 * 2;
|
||||||
control.max_mmap = MIN(control.max_mmap, control.max_chunk);
|
control->max_mmap = MIN(control->max_mmap, control->max_chunk);
|
||||||
if (control.max_chunk < control.st_size)
|
if (control->max_chunk < control->st_size)
|
||||||
round_to_page(&control.max_chunk);
|
round_to_page(&control->max_chunk);
|
||||||
|
|
||||||
if (!STDIN)
|
if (!STDIN)
|
||||||
st->chunk_size = MIN(control.max_chunk, len);
|
st->chunk_size = MIN(control->max_chunk, len);
|
||||||
else
|
else
|
||||||
st->chunk_size = control.max_mmap;
|
st->chunk_size = control->max_mmap;
|
||||||
if (st->chunk_size < len)
|
if (st->chunk_size < len)
|
||||||
round_to_page(&st->chunk_size);
|
round_to_page(&st->chunk_size);
|
||||||
|
|
||||||
st->level = &levels[control.compression_level];
|
st->level = &levels[control->compression_level];
|
||||||
st->fd_in = fd_in;
|
st->fd_in = fd_in;
|
||||||
st->fd_out = fd_out;
|
st->fd_out = fd_out;
|
||||||
st->stdin_eof = 0;
|
st->stdin_eof = 0;
|
||||||
|
|
@ -819,15 +819,15 @@ void rzip_fd(int fd_in, int fd_out)
|
||||||
last.tv_sec = last.tv_usec = 0;
|
last.tv_sec = last.tv_usec = 0;
|
||||||
gettimeofday(&start, NULL);
|
gettimeofday(&start, NULL);
|
||||||
|
|
||||||
prepare_streamout_threads();
|
prepare_streamout_threads(control);
|
||||||
|
|
||||||
while (len > 0 || (STDIN && !st->stdin_eof)) {
|
while (len > 0 || (STDIN && !st->stdin_eof)) {
|
||||||
double pct_base, pct_multiple;
|
double pct_base, pct_multiple;
|
||||||
i64 offset = s.st_size - len;
|
i64 offset = s.st_size - len;
|
||||||
int bits = 8;
|
int bits = 8;
|
||||||
|
|
||||||
st->chunk_size = control.max_chunk;
|
st->chunk_size = control->max_chunk;
|
||||||
st->mmap_size = control.max_mmap;
|
st->mmap_size = control->max_mmap;
|
||||||
if (!STDIN) {
|
if (!STDIN) {
|
||||||
st->chunk_size = MIN(st->chunk_size, len);
|
st->chunk_size = MIN(st->chunk_size, len);
|
||||||
st->mmap_size = MIN(st->mmap_size, len);
|
st->mmap_size = MIN(st->mmap_size, len);
|
||||||
|
|
@ -840,7 +840,7 @@ retry:
|
||||||
/* Better to shrink the window to the largest size that works than fail */
|
/* Better to shrink the window to the largest size that works than fail */
|
||||||
if (sb.buf_low == MAP_FAILED) {
|
if (sb.buf_low == MAP_FAILED) {
|
||||||
if (unlikely(errno != ENOMEM))
|
if (unlikely(errno != ENOMEM))
|
||||||
fatal("Failed to mmap %s\n", control.infile);
|
fatal("Failed to mmap %s\n", control->infile);
|
||||||
st->mmap_size = st->mmap_size / 10 * 9;
|
st->mmap_size = st->mmap_size / 10 * 9;
|
||||||
round_to_page(&st->mmap_size);
|
round_to_page(&st->mmap_size);
|
||||||
if (unlikely(!st->mmap_size))
|
if (unlikely(!st->mmap_size))
|
||||||
|
|
@ -848,13 +848,13 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
st->chunk_size = st->mmap_size;
|
st->chunk_size = st->mmap_size;
|
||||||
mmap_stdin(sb.buf_low, st);
|
mmap_stdin(control, sb.buf_low, st);
|
||||||
} else {
|
} else {
|
||||||
/* NOTE The buf is saved here for !STDIN mode */
|
/* NOTE The buf is saved here for !STDIN mode */
|
||||||
sb.buf_low = (uchar *)mmap(sb.buf_low, st->mmap_size, PROT_READ, MAP_SHARED, fd_in, offset);
|
sb.buf_low = (uchar *)mmap(sb.buf_low, st->mmap_size, PROT_READ, MAP_SHARED, fd_in, offset);
|
||||||
if (sb.buf_low == MAP_FAILED) {
|
if (sb.buf_low == MAP_FAILED) {
|
||||||
if (unlikely(errno != ENOMEM))
|
if (unlikely(errno != ENOMEM))
|
||||||
fatal("Failed to mmap %s\n", control.infile);
|
fatal("Failed to mmap %s\n", control->infile);
|
||||||
st->mmap_size = st->mmap_size / 10 * 9;
|
st->mmap_size = st->mmap_size / 10 * 9;
|
||||||
round_to_page(&st->mmap_size);
|
round_to_page(&st->mmap_size);
|
||||||
if (unlikely(!st->mmap_size))
|
if (unlikely(!st->mmap_size))
|
||||||
|
|
@ -866,7 +866,7 @@ retry:
|
||||||
}
|
}
|
||||||
print_maxverbose("Succeeded in testing %lld sized mmap for rzip pre-processing\n", st->mmap_size);
|
print_maxverbose("Succeeded in testing %lld sized mmap for rzip pre-processing\n", st->mmap_size);
|
||||||
|
|
||||||
if (st->chunk_size > control.ramsize)
|
if (st->chunk_size > control->ramsize)
|
||||||
print_verbose("Compression window is larger than ram, will proceed with unlimited mode possibly much slower\n");
|
print_verbose("Compression window is larger than ram, will proceed with unlimited mode possibly much slower\n");
|
||||||
|
|
||||||
if (!passes && !STDIN) {
|
if (!passes && !STDIN) {
|
||||||
|
|
@ -893,10 +893,10 @@ retry:
|
||||||
print_maxverbose("Byte width: %d\n", st->chunk_bytes);
|
print_maxverbose("Byte width: %d\n", st->chunk_bytes);
|
||||||
|
|
||||||
if (STDIN)
|
if (STDIN)
|
||||||
pct_base = (100.0 * -len) / control.st_size;
|
pct_base = (100.0 * -len) / control->st_size;
|
||||||
else
|
else
|
||||||
pct_base = (100.0 * (control.st_size - len)) / control.st_size;
|
pct_base = (100.0 * (control->st_size - len)) / control->st_size;
|
||||||
pct_multiple = ((double)st->chunk_size) / control.st_size;
|
pct_multiple = ((double)st->chunk_size) / control->st_size;
|
||||||
pass++;
|
pass++;
|
||||||
if (st->stdin_eof)
|
if (st->stdin_eof)
|
||||||
passes = pass;
|
passes = pass;
|
||||||
|
|
@ -929,28 +929,28 @@ retry:
|
||||||
last.tv_sec = current.tv_sec;
|
last.tv_sec = current.tv_sec;
|
||||||
last.tv_usec = current.tv_usec;
|
last.tv_usec = current.tv_usec;
|
||||||
|
|
||||||
rzip_chunk(st, fd_in, fd_out, offset, pct_base, pct_multiple);
|
rzip_chunk(control, st, fd_in, fd_out, offset, pct_base, pct_multiple);
|
||||||
|
|
||||||
/* st->chunk_size may be shrunk in rzip_chunk */
|
/* st->chunk_size may be shrunk in rzip_chunk */
|
||||||
last_chunk = st->chunk_size;
|
last_chunk = st->chunk_size;
|
||||||
len -= st->chunk_size;
|
len -= st->chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
close_streamout_threads();
|
close_streamout_threads(control);
|
||||||
|
|
||||||
md5_finish_ctx (&control.ctx, md5_resblock);
|
md5_finish_ctx (&control->ctx, md5_resblock);
|
||||||
if (HASH_CHECK || MAX_VERBOSE) {
|
if (HASH_CHECK || MAX_VERBOSE) {
|
||||||
print_output("MD5: ");
|
print_output("MD5: ");
|
||||||
for (j = 0; j < MD5_DIGEST_SIZE; j++)
|
for (j = 0; j < MD5_DIGEST_SIZE; j++)
|
||||||
print_output("%02x", md5_resblock[j] & 0xFF);
|
print_output("%02x", md5_resblock[j] & 0xFF);
|
||||||
print_output("\n");
|
print_output("\n");
|
||||||
}
|
}
|
||||||
if (unlikely(write(control.fd_out, md5_resblock, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
|
if (unlikely(write(control->fd_out, md5_resblock, MD5_DIGEST_SIZE) != MD5_DIGEST_SIZE))
|
||||||
fatal("Failed to write md5 in rzip_fd\n");
|
fatal("Failed to write md5 in rzip_fd\n");
|
||||||
|
|
||||||
gettimeofday(¤t, NULL);
|
gettimeofday(¤t, NULL);
|
||||||
if (STDIN)
|
if (STDIN)
|
||||||
s.st_size = control.st_size;
|
s.st_size = control->st_size;
|
||||||
chunkmbs = (s.st_size / 1024 / 1024) / ((double)(current.tv_sec-start.tv_sec)? : 1);
|
chunkmbs = (s.st_size / 1024 / 1024) / ((double)(current.tv_sec-start.tv_sec)? : 1);
|
||||||
|
|
||||||
fstat(fd_out, &s2);
|
fstat(fd_out, &s2);
|
||||||
|
|
@ -966,7 +966,7 @@ retry:
|
||||||
(1.0 + st->stats.match_bytes) / st->stats.literal_bytes);
|
(1.0 + st->stats.match_bytes) / st->stats.literal_bytes);
|
||||||
|
|
||||||
if (!STDIN)
|
if (!STDIN)
|
||||||
print_progress("%s - ", control.infile);
|
print_progress("%s - ", control->infile);
|
||||||
print_progress("Compression Ratio: %.3f. Average Compression Speed: %6.3fMB/s.\n",
|
print_progress("Compression Ratio: %.3f. Average Compression Speed: %6.3fMB/s.\n",
|
||||||
1.0 * s.st_size / s2.st_size, chunkmbs);
|
1.0 * s.st_size / s2.st_size, chunkmbs);
|
||||||
|
|
||||||
|
|
|
||||||
158
rzip.h
158
rzip.h
|
|
@ -17,14 +17,10 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LRZIP_MAJOR_VERSION 0
|
#ifndef RZIP_H
|
||||||
#define LRZIP_MINOR_VERSION 5
|
#define RZIP_H
|
||||||
#define LRZIP_MINOR_SUBVERSION 71
|
#include "lrzip.h" /* includes config.h */
|
||||||
|
#include "liblrzip.h"
|
||||||
#define NUM_STREAMS 2
|
|
||||||
#define STREAM_BUFSIZE (1024 * 1024 * 10)
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -75,76 +71,6 @@
|
||||||
/* needed for CRC routines */
|
/* needed for CRC routines */
|
||||||
#include "lzma/C/7zCrc.h"
|
#include "lzma/C/7zCrc.h"
|
||||||
|
|
||||||
#ifndef uchar
|
|
||||||
#define uchar unsigned char
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef int32
|
|
||||||
#if (SIZEOF_INT == 4)
|
|
||||||
#define int32 int
|
|
||||||
#elif (SIZEOF_LONG == 4)
|
|
||||||
#define int32 long
|
|
||||||
#elif (SIZEOF_SHORT == 4)
|
|
||||||
#define int32 short
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef int16
|
|
||||||
#if (SIZEOF_INT == 2)
|
|
||||||
#define int16 int
|
|
||||||
#elif (SIZEOF_SHORT == 2)
|
|
||||||
#define int16 short
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef uint32
|
|
||||||
#define uint32 unsigned int32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef uint16
|
|
||||||
#define uint16 unsigned int16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a, b) ((a) < (b)? (a): (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a, b) ((a) > (b)? (a): (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !HAVE_STRERROR
|
|
||||||
extern char *sys_errlist[];
|
|
||||||
#define strerror(i) sys_errlist[i]
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_ERRNO_H
|
|
||||||
extern int errno;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
|
||||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
|
||||||
|
|
||||||
typedef long long int i64;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
|
|
||||||
#ifndef MAP_ANONYMOUS
|
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(NOTHREAD) || !defined(_SC_NPROCESSORS_ONLN)
|
|
||||||
#define PROCESSORS (1)
|
|
||||||
#else
|
|
||||||
#define PROCESSORS (sysconf(_SC_NPROCESSORS_ONLN))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _SC_PAGE_SIZE
|
|
||||||
#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
|
|
||||||
#else
|
|
||||||
#define PAGE_SIZE (4096)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void fatal(const char *format, ...);
|
void fatal(const char *format, ...);
|
||||||
void failure(const char *format, ...);
|
void failure(const char *format, ...);
|
||||||
|
|
||||||
|
|
@ -222,33 +148,6 @@ static inline i64 get_ram(void)
|
||||||
#define FLAG_KEEP_BROKEN (1 << 19)
|
#define FLAG_KEEP_BROKEN (1 << 19)
|
||||||
#define FLAG_THRESHOLD (1 << 20)
|
#define FLAG_THRESHOLD (1 << 20)
|
||||||
|
|
||||||
#define FLAG_VERBOSE (FLAG_VERBOSITY | FLAG_VERBOSITY_MAX)
|
|
||||||
#define FLAG_NOT_LZMA (FLAG_NO_COMPRESS | FLAG_LZO_COMPRESS | FLAG_BZIP2_COMPRESS | FLAG_ZLIB_COMPRESS | FLAG_ZPAQ_COMPRESS)
|
|
||||||
#define LZMA_COMPRESS (!(control.flags & FLAG_NOT_LZMA))
|
|
||||||
|
|
||||||
#define SHOW_PROGRESS (control.flags & FLAG_SHOW_PROGRESS)
|
|
||||||
#define KEEP_FILES (control.flags & FLAG_KEEP_FILES)
|
|
||||||
#define TEST_ONLY (control.flags & FLAG_TEST_ONLY)
|
|
||||||
#define FORCE_REPLACE (control.flags & FLAG_FORCE_REPLACE)
|
|
||||||
#define DECOMPRESS (control.flags & FLAG_DECOMPRESS)
|
|
||||||
#define NO_COMPRESS (control.flags & FLAG_NO_COMPRESS)
|
|
||||||
#define LZO_COMPRESS (control.flags & FLAG_LZO_COMPRESS)
|
|
||||||
#define BZIP2_COMPRESS (control.flags & FLAG_BZIP2_COMPRESS)
|
|
||||||
#define ZLIB_COMPRESS (control.flags & FLAG_ZLIB_COMPRESS)
|
|
||||||
#define ZPAQ_COMPRESS (control.flags & FLAG_ZPAQ_COMPRESS)
|
|
||||||
#define VERBOSE (control.flags & FLAG_VERBOSE)
|
|
||||||
#define VERBOSITY (control.flags & FLAG_VERBOSITY)
|
|
||||||
#define MAX_VERBOSE (control.flags & FLAG_VERBOSITY_MAX)
|
|
||||||
#define STDIN (control.flags & FLAG_STDIN)
|
|
||||||
#define STDOUT (control.flags & FLAG_STDOUT)
|
|
||||||
#define INFO (control.flags & FLAG_INFO)
|
|
||||||
#define UNLIMITED (control.flags & FLAG_UNLIMITED)
|
|
||||||
#define HASH_CHECK (control.flags & FLAG_HASH)
|
|
||||||
#define HAS_MD5 (control.flags & FLAG_MD5)
|
|
||||||
#define CHECK_FILE (control.flags & FLAG_CHECK)
|
|
||||||
#define KEEP_BROKEN (control.flags & FLAG_KEEP_BROKEN)
|
|
||||||
#define LZO_TEST (control.flags & FLAG_THRESHOLD)
|
|
||||||
|
|
||||||
#define NO_MD5 (!(HASH_CHECK) && !(HAS_MD5))
|
#define NO_MD5 (!(HASH_CHECK) && !(HAS_MD5))
|
||||||
|
|
||||||
#define BITS32 (sizeof(long) == 4)
|
#define BITS32 (sizeof(long) == 4)
|
||||||
|
|
@ -285,8 +184,9 @@ struct rzip_control {
|
||||||
long page_size;
|
long page_size;
|
||||||
int fd_out;
|
int fd_out;
|
||||||
struct md5_ctx ctx;
|
struct md5_ctx ctx;
|
||||||
|
void *data; // random data pointer associated for use in callbacks
|
||||||
i64 md5_read; // How far into the file the md5 has done so far
|
i64 md5_read; // How far into the file the md5 has done so far
|
||||||
} control;
|
};
|
||||||
|
|
||||||
struct stream {
|
struct stream {
|
||||||
i64 last_head;
|
i64 last_head;
|
||||||
|
|
@ -316,52 +216,36 @@ struct stream_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
void sighandler();
|
void sighandler();
|
||||||
i64 runzip_fd(int fd_in, int fd_out, int fd_hist, i64 expected_size);
|
i64 runzip_fd(rzip_control *control, int fd_in, int fd_out, int fd_hist, i64 expected_size);
|
||||||
void rzip_fd(int fd_in, int fd_out);
|
void rzip_fd(rzip_control *control, int fd_in, int fd_out);
|
||||||
void *open_stream_out(int f, int n, i64 limit, char cbytes);
|
void *open_stream_out(rzip_control *control, int f, int n, i64 limit, char cbytes);
|
||||||
void *open_stream_in(int f, int n);
|
void *open_stream_in(rzip_control *control, int f, int n);
|
||||||
int write_stream(void *ss, int stream, uchar *p, i64 len);
|
int write_stream(rzip_control *control, void *ss, int stream, uchar *p, i64 len);
|
||||||
i64 read_stream(void *ss, int stream, uchar *p, i64 len);
|
i64 read_stream(rzip_control *control, void *ss, int stream, uchar *p, i64 len);
|
||||||
int close_stream_out(void *ss);
|
int close_stream_out(rzip_control *control, void *ss);
|
||||||
int close_stream_in(void *ss);
|
int close_stream_in(void *ss);
|
||||||
void flush_buffer(struct stream_info *sinfo, int stream);
|
void flush_buffer(rzip_control *control, struct stream_info *sinfo, int stream);
|
||||||
void read_config(struct rzip_control *s);
|
void read_config(struct rzip_control *s);
|
||||||
ssize_t write_1g(int fd, void *buf, i64 len);
|
ssize_t write_1g(int fd, void *buf, i64 len);
|
||||||
ssize_t read_1g(int fd, void *buf, i64 len);
|
ssize_t read_1g(int fd, void *buf, i64 len);
|
||||||
void zpipe_compress(FILE *in, FILE *out, FILE *msgout, long long int buf_len, int progress, long thread);
|
void zpipe_compress(FILE *in, FILE *out, FILE *msgout, long long int buf_len, int progress, long thread);
|
||||||
void zpipe_decompress(FILE *in, FILE *out, FILE *msgout, long long int buf_len, int progress, long thread);
|
void zpipe_decompress(FILE *in, FILE *out, FILE *msgout, long long int buf_len, int progress, long thread);
|
||||||
const i64 two_gig;
|
const i64 two_gig;
|
||||||
void prepare_streamout_threads(void);
|
void prepare_streamout_threads(rzip_control *control);
|
||||||
void close_streamout_threads(void);
|
void close_streamout_threads(rzip_control *control);
|
||||||
void round_to_page(i64 *size);
|
void round_to_page(i64 *size);
|
||||||
void dump_tmpoutfile(int fd_out);
|
|
||||||
|
void register_infile(const char *name, char delete);
|
||||||
|
void register_outfile(const char *name, char delete);
|
||||||
|
void register_outputfile(FILE *f);
|
||||||
|
|
||||||
#define print_err(format, args...) do {\
|
#define print_err(format, args...) do {\
|
||||||
fprintf(stderr, format, ##args); \
|
fprintf(stderr, format, ##args); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define print_output(format, args...) do {\
|
|
||||||
fprintf(control.msgout, format, ##args); \
|
|
||||||
fflush(control.msgout); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define print_progress(format, args...) do {\
|
|
||||||
if (SHOW_PROGRESS) \
|
|
||||||
print_output(format, ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define print_verbose(format, args...) do {\
|
|
||||||
if (VERBOSE) \
|
|
||||||
print_output(format, ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define print_maxverbose(format, args...) do {\
|
|
||||||
if (MAX_VERBOSE) \
|
|
||||||
print_output(format, ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Macros for testing parameters */
|
/* Macros for testing parameters */
|
||||||
|
|
||||||
#define isparameter( parmstring, value ) (!strcasecmp( parmstring, value ))
|
#define isparameter( parmstring, value ) (!strcasecmp( parmstring, value ))
|
||||||
#define iscaseparameter( parmvalue, value ) (!strcmp( parmvalue, value ))
|
#define iscaseparameter( parmvalue, value ) (!strcmp( parmvalue, value ))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
176
stream.c
176
stream.c
|
|
@ -88,7 +88,7 @@ void join_pthread(pthread_t th, void **thread_return)
|
||||||
/* just to keep things clean, declare function here
|
/* just to keep things clean, declare function here
|
||||||
* but move body to the end since it's a work function
|
* but move body to the end since it's a work function
|
||||||
*/
|
*/
|
||||||
static int lzo_compresses(uchar *s_buf, i64 s_len);
|
static int lzo_compresses(rzip_control *control, uchar *s_buf, i64 s_len);
|
||||||
|
|
||||||
static inline FILE *fake_fmemopen(void *buf, size_t buflen, char *mode)
|
static inline FILE *fake_fmemopen(void *buf, size_t buflen, char *mode)
|
||||||
{
|
{
|
||||||
|
|
@ -145,13 +145,13 @@ static inline int fake_open_memstream_update_buffer(FILE *fp, uchar **buf, size_
|
||||||
length in c_len
|
length in c_len
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int zpaq_compress_buf(struct compress_thread *cthread, long thread)
|
static int zpaq_compress_buf(rzip_control *control, struct compress_thread *cthread, long thread)
|
||||||
{
|
{
|
||||||
uchar *c_buf = NULL;
|
uchar *c_buf = NULL;
|
||||||
size_t dlen = 0;
|
size_t dlen = 0;
|
||||||
FILE *in, *out;
|
FILE *in, *out;
|
||||||
|
|
||||||
if (!lzo_compresses(cthread->s_buf, cthread->s_len))
|
if (!lzo_compresses(control, cthread->s_buf, cthread->s_len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
in = fmemopen(cthread->s_buf, cthread->s_len, "r");
|
in = fmemopen(cthread->s_buf, cthread->s_len, "r");
|
||||||
|
|
@ -166,7 +166,7 @@ static int zpaq_compress_buf(struct compress_thread *cthread, long thread)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
zpipe_compress(in, out, control.msgout, cthread->s_len,
|
zpipe_compress(in, out, control->msgout, cthread->s_len,
|
||||||
(int)(SHOW_PROGRESS), thread);
|
(int)(SHOW_PROGRESS), thread);
|
||||||
|
|
||||||
if (unlikely(memstream_update_buffer(out, &c_buf, &dlen)))
|
if (unlikely(memstream_update_buffer(out, &c_buf, &dlen)))
|
||||||
|
|
@ -189,13 +189,13 @@ static int zpaq_compress_buf(struct compress_thread *cthread, long thread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bzip2_compress_buf(struct compress_thread *cthread)
|
static int bzip2_compress_buf(rzip_control *control, struct compress_thread *cthread)
|
||||||
{
|
{
|
||||||
u32 dlen = cthread->s_len;
|
u32 dlen = cthread->s_len;
|
||||||
int bzip2_ret;
|
int bzip2_ret;
|
||||||
uchar *c_buf;
|
uchar *c_buf;
|
||||||
|
|
||||||
if (!lzo_compresses(cthread->s_buf, cthread->s_len))
|
if (!lzo_compresses(control, cthread->s_buf, cthread->s_len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
c_buf = malloc(dlen);
|
c_buf = malloc(dlen);
|
||||||
|
|
@ -206,7 +206,7 @@ static int bzip2_compress_buf(struct compress_thread *cthread)
|
||||||
|
|
||||||
bzip2_ret = BZ2_bzBuffToBuffCompress((char *)c_buf, &dlen,
|
bzip2_ret = BZ2_bzBuffToBuffCompress((char *)c_buf, &dlen,
|
||||||
(char *)cthread->s_buf, cthread->s_len,
|
(char *)cthread->s_buf, cthread->s_len,
|
||||||
control.compression_level, 0, control.compression_level * 10);
|
control->compression_level, 0, control->compression_level * 10);
|
||||||
|
|
||||||
/* if compressed data is bigger then original data leave as
|
/* if compressed data is bigger then original data leave as
|
||||||
* CTYPE_NONE */
|
* CTYPE_NONE */
|
||||||
|
|
@ -238,7 +238,7 @@ static int bzip2_compress_buf(struct compress_thread *cthread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gzip_compress_buf(struct compress_thread *cthread)
|
static int gzip_compress_buf(rzip_control *control, struct compress_thread *cthread)
|
||||||
{
|
{
|
||||||
unsigned long dlen = cthread->s_len;
|
unsigned long dlen = cthread->s_len;
|
||||||
uchar *c_buf;
|
uchar *c_buf;
|
||||||
|
|
@ -251,7 +251,7 @@ static int gzip_compress_buf(struct compress_thread *cthread)
|
||||||
}
|
}
|
||||||
|
|
||||||
gzip_ret = compress2(c_buf, &dlen, cthread->s_buf, cthread->s_len,
|
gzip_ret = compress2(c_buf, &dlen, cthread->s_buf, cthread->s_len,
|
||||||
control.compression_level);
|
control->compression_level);
|
||||||
|
|
||||||
/* if compressed data is bigger then original data leave as
|
/* if compressed data is bigger then original data leave as
|
||||||
* CTYPE_NONE */
|
* CTYPE_NONE */
|
||||||
|
|
@ -283,18 +283,18 @@ static int gzip_compress_buf(struct compress_thread *cthread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzma_compress_buf(struct compress_thread *cthread)
|
static int lzma_compress_buf(rzip_control *control, struct compress_thread *cthread)
|
||||||
{
|
{
|
||||||
int lzma_level, lzma_ret;
|
int lzma_level, lzma_ret;
|
||||||
size_t prop_size = 5; /* return value for lzma_properties */
|
size_t prop_size = 5; /* return value for lzma_properties */
|
||||||
uchar *c_buf;
|
uchar *c_buf;
|
||||||
size_t dlen;
|
size_t dlen;
|
||||||
|
|
||||||
if (!lzo_compresses(cthread->s_buf, cthread->s_len))
|
if (!lzo_compresses(control, cthread->s_buf, cthread->s_len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* only 7 levels with lzma, scale them */
|
/* only 7 levels with lzma, scale them */
|
||||||
lzma_level = control.compression_level * 7 / 9 ? : 1;
|
lzma_level = control->compression_level * 7 / 9 ? : 1;
|
||||||
|
|
||||||
print_verbose("Starting lzma back end compression thread...\n");
|
print_verbose("Starting lzma back end compression thread...\n");
|
||||||
retry:
|
retry:
|
||||||
|
|
@ -309,11 +309,11 @@ retry:
|
||||||
* and receive properties in control->lzma_properties */
|
* and receive properties in control->lzma_properties */
|
||||||
|
|
||||||
lzma_ret = LzmaCompress(c_buf, &dlen, cthread->s_buf,
|
lzma_ret = LzmaCompress(c_buf, &dlen, cthread->s_buf,
|
||||||
(size_t)cthread->s_len, control.lzma_properties, &prop_size,
|
(size_t)cthread->s_len, control->lzma_properties, &prop_size,
|
||||||
lzma_level,
|
lzma_level,
|
||||||
0, /* dict size. set default, choose by level */
|
0, /* dict size. set default, choose by level */
|
||||||
-1, -1, -1, -1, /* lc, lp, pb, fb */
|
-1, -1, -1, -1, /* lc, lp, pb, fb */
|
||||||
control.threads);
|
control->threads);
|
||||||
if (lzma_ret != SZ_OK) {
|
if (lzma_ret != SZ_OK) {
|
||||||
switch (lzma_ret) {
|
switch (lzma_ret) {
|
||||||
case SZ_ERROR_MEM:
|
case SZ_ERROR_MEM:
|
||||||
|
|
@ -343,7 +343,7 @@ retry:
|
||||||
* fall back to bzip2 compression so the block doesn't
|
* fall back to bzip2 compression so the block doesn't
|
||||||
* remain uncompressed */
|
* remain uncompressed */
|
||||||
print_verbose("Unable to allocate enough RAM for any sized compression window, falling back to bzip2 compression.\n");
|
print_verbose("Unable to allocate enough RAM for any sized compression window, falling back to bzip2 compression.\n");
|
||||||
return bzip2_compress_buf(cthread);
|
return bzip2_compress_buf(control, cthread);
|
||||||
} else if (lzma_ret == SZ_ERROR_OUTPUT_EOF)
|
} else if (lzma_ret == SZ_ERROR_OUTPUT_EOF)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -363,7 +363,7 @@ retry:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzo_compress_buf(struct compress_thread *cthread)
|
static int lzo_compress_buf(rzip_control *control, struct compress_thread *cthread)
|
||||||
{
|
{
|
||||||
lzo_uint in_len = cthread->s_len;
|
lzo_uint in_len = cthread->s_len;
|
||||||
lzo_uint dlen = in_len + in_len / 16 + 64 + 3;
|
lzo_uint dlen = in_len + in_len / 16 + 64 + 3;
|
||||||
|
|
@ -411,7 +411,7 @@ out_free:
|
||||||
try to decompress a buffer. Return 0 on success and -1 on failure.
|
try to decompress a buffer. Return 0 on success and -1 on failure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int zpaq_decompress_buf(struct uncomp_thread *ucthread, long thread)
|
static int zpaq_decompress_buf(rzip_control *control, struct uncomp_thread *ucthread, long thread)
|
||||||
{
|
{
|
||||||
uchar *c_buf = NULL;
|
uchar *c_buf = NULL;
|
||||||
size_t dlen = 0;
|
size_t dlen = 0;
|
||||||
|
|
@ -428,7 +428,7 @@ static int zpaq_decompress_buf(struct uncomp_thread *ucthread, long thread)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
zpipe_decompress(in, out, control.msgout, ucthread->u_len, (int)(SHOW_PROGRESS), thread);
|
zpipe_decompress(in, out, control->msgout, ucthread->u_len, (int)(SHOW_PROGRESS), thread);
|
||||||
|
|
||||||
if (unlikely(memstream_update_buffer(out, &c_buf, &dlen)))
|
if (unlikely(memstream_update_buffer(out, &c_buf, &dlen)))
|
||||||
fatal("Failed to memstream_update_buffer in zpaq_decompress_buf");
|
fatal("Failed to memstream_update_buffer in zpaq_decompress_buf");
|
||||||
|
|
@ -447,7 +447,7 @@ static int zpaq_decompress_buf(struct uncomp_thread *ucthread, long thread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bzip2_decompress_buf(struct uncomp_thread *ucthread)
|
static int bzip2_decompress_buf(rzip_control *control __UNUSED__, struct uncomp_thread *ucthread)
|
||||||
{
|
{
|
||||||
u32 dlen = ucthread->u_len;
|
u32 dlen = ucthread->u_len;
|
||||||
int ret = 0, bzerr;
|
int ret = 0, bzerr;
|
||||||
|
|
@ -481,7 +481,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gzip_decompress_buf(struct uncomp_thread *ucthread)
|
static int gzip_decompress_buf(rzip_control *control __UNUSED__, struct uncomp_thread *ucthread)
|
||||||
{
|
{
|
||||||
unsigned long dlen = ucthread->u_len;
|
unsigned long dlen = ucthread->u_len;
|
||||||
int ret = 0, gzerr;
|
int ret = 0, gzerr;
|
||||||
|
|
@ -515,7 +515,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzma_decompress_buf(struct uncomp_thread *ucthread)
|
static int lzma_decompress_buf(rzip_control *control, struct uncomp_thread *ucthread)
|
||||||
{
|
{
|
||||||
size_t dlen = (size_t)ucthread->u_len;
|
size_t dlen = (size_t)ucthread->u_len;
|
||||||
int ret = 0, lzmaerr;
|
int ret = 0, lzmaerr;
|
||||||
|
|
@ -529,9 +529,9 @@ static int lzma_decompress_buf(struct uncomp_thread *ucthread)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* With LZMA SDK 4.63 we pass control.lzma_properties
|
/* With LZMA SDK 4.63 we pass control->lzma_properties
|
||||||
* which is needed for proper uncompress */
|
* which is needed for proper uncompress */
|
||||||
lzmaerr = LzmaUncompress(ucthread->s_buf, &dlen, c_buf, (SizeT *)&ucthread->c_len, control.lzma_properties, 5);
|
lzmaerr = LzmaUncompress(ucthread->s_buf, &dlen, c_buf, (SizeT *)&ucthread->c_len, control->lzma_properties, 5);
|
||||||
if (unlikely(lzmaerr)) {
|
if (unlikely(lzmaerr)) {
|
||||||
print_err("Failed to decompress buffer - lzmaerr=%d\n", lzmaerr);
|
print_err("Failed to decompress buffer - lzmaerr=%d\n", lzmaerr);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
@ -551,7 +551,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzo_decompress_buf(struct uncomp_thread *ucthread)
|
static int lzo_decompress_buf(rzip_control *control __UNUSED__, struct uncomp_thread *ucthread)
|
||||||
{
|
{
|
||||||
lzo_uint dlen = ucthread->u_len;
|
lzo_uint dlen = ucthread->u_len;
|
||||||
int ret = 0, lzerr;
|
int ret = 0, lzerr;
|
||||||
|
|
@ -718,7 +718,7 @@ static int seekto(struct stream_info *sinfo, i64 pos)
|
||||||
|
|
||||||
static pthread_t *threads;
|
static pthread_t *threads;
|
||||||
|
|
||||||
void prepare_streamout_threads(void)
|
void prepare_streamout_threads(rzip_control *control)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -726,19 +726,19 @@ void prepare_streamout_threads(void)
|
||||||
* pre-processing stage, it's faster to have one more thread available
|
* pre-processing stage, it's faster to have one more thread available
|
||||||
* to keep all CPUs busy. There is no point splitting up the chunks
|
* to keep all CPUs busy. There is no point splitting up the chunks
|
||||||
* into multiple threads if there will be no compression back end. */
|
* into multiple threads if there will be no compression back end. */
|
||||||
if (control.threads > 1)
|
if (control->threads > 1)
|
||||||
++control.threads;
|
++control->threads;
|
||||||
if (NO_COMPRESS)
|
if (NO_COMPRESS)
|
||||||
control.threads = 1;
|
control->threads = 1;
|
||||||
threads = calloc(sizeof(pthread_t), control.threads);
|
threads = calloc(sizeof(pthread_t), control->threads);
|
||||||
if (unlikely(!threads))
|
if (unlikely(!threads))
|
||||||
fatal("Unable to calloc threads in prepare_streamout_threads\n");
|
fatal("Unable to calloc threads in prepare_streamout_threads\n");
|
||||||
|
|
||||||
cthread = calloc(sizeof(struct compress_thread), control.threads);
|
cthread = calloc(sizeof(struct compress_thread), control->threads);
|
||||||
if (unlikely(!cthread))
|
if (unlikely(!cthread))
|
||||||
fatal("Unable to calloc cthread in prepare_streamout_threads\n");
|
fatal("Unable to calloc cthread in prepare_streamout_threads\n");
|
||||||
|
|
||||||
for (i = 0; i < control.threads; i++)
|
for (i = 0; i < control->threads; i++)
|
||||||
init_mutex(&cthread[i].mutex);
|
init_mutex(&cthread[i].mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -746,15 +746,15 @@ static long output_thread;
|
||||||
static pthread_mutex_t output_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t output_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static pthread_cond_t output_cond = PTHREAD_COND_INITIALIZER;
|
static pthread_cond_t output_cond = PTHREAD_COND_INITIALIZER;
|
||||||
|
|
||||||
void close_streamout_threads(void)
|
void close_streamout_threads(rzip_control *control)
|
||||||
{
|
{
|
||||||
int i, close_thread = output_thread;
|
int i, close_thread = output_thread;
|
||||||
|
|
||||||
/* Wait for the threads in the correct order in case they end up
|
/* Wait for the threads in the correct order in case they end up
|
||||||
* serialised */
|
* serialised */
|
||||||
for (i = 0; i < control.threads; i++) {
|
for (i = 0; i < control->threads; i++) {
|
||||||
lock_mutex(&cthread[close_thread].mutex);
|
lock_mutex(&cthread[close_thread].mutex);
|
||||||
if (++close_thread == control.threads)
|
if (++close_thread == control->threads)
|
||||||
close_thread = 0;
|
close_thread = 0;
|
||||||
}
|
}
|
||||||
free(cthread);
|
free(cthread);
|
||||||
|
|
@ -763,7 +763,7 @@ void close_streamout_threads(void)
|
||||||
|
|
||||||
/* open a set of output streams, compressing with the given
|
/* open a set of output streams, compressing with the given
|
||||||
compression level and algorithm */
|
compression level and algorithm */
|
||||||
void *open_stream_out(int f, int n, i64 chunk_limit, char cbytes)
|
void *open_stream_out(rzip_control *control, int f, int n, i64 chunk_limit, char cbytes)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo;
|
struct stream_info *sinfo;
|
||||||
i64 testsize, limit;
|
i64 testsize, limit;
|
||||||
|
|
@ -799,24 +799,24 @@ void *open_stream_out(int f, int n, i64 chunk_limit, char cbytes)
|
||||||
/* Serious limits imposed on 32 bit capabilities */
|
/* Serious limits imposed on 32 bit capabilities */
|
||||||
if (BITS32)
|
if (BITS32)
|
||||||
limit = MIN(limit, (two_gig / testbufs) -
|
limit = MIN(limit, (two_gig / testbufs) -
|
||||||
(control.overhead * control.threads));
|
(control->overhead * control->threads));
|
||||||
|
|
||||||
testsize = (limit * testbufs) + (control.overhead * control.threads);
|
testsize = (limit * testbufs) + (control->overhead * control->threads);
|
||||||
if (testsize > control.maxram)
|
if (testsize > control->maxram)
|
||||||
limit = (control.maxram - (control.overhead * control.threads)) / testbufs;
|
limit = (control->maxram - (control->overhead * control->threads)) / testbufs;
|
||||||
|
|
||||||
/* If we don't have enough ram for the number of threads, decrease the
|
/* If we don't have enough ram for the number of threads, decrease the
|
||||||
* number of threads till we do, or only have one thread. */
|
* number of threads till we do, or only have one thread. */
|
||||||
while (limit < STREAM_BUFSIZE && limit < chunk_limit) {
|
while (limit < STREAM_BUFSIZE && limit < chunk_limit) {
|
||||||
if (control.threads > 1)
|
if (control->threads > 1)
|
||||||
--control.threads;
|
--control->threads;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
limit = (control.maxram - (control.overhead * control.threads)) / testbufs;
|
limit = (control->maxram - (control->overhead * control->threads)) / testbufs;
|
||||||
limit = MIN(limit, chunk_limit);
|
limit = MIN(limit, chunk_limit);
|
||||||
}
|
}
|
||||||
retest_malloc:
|
retest_malloc:
|
||||||
testsize = (limit * testbufs) + (control.overhead * control.threads);
|
testsize = (limit * testbufs) + (control->overhead * control->threads);
|
||||||
testmalloc = malloc(testsize);
|
testmalloc = malloc(testsize);
|
||||||
if (!testmalloc) {
|
if (!testmalloc) {
|
||||||
limit = limit / 10 * 9;
|
limit = limit / 10 * 9;
|
||||||
|
|
@ -827,12 +827,12 @@ retest_malloc:
|
||||||
|
|
||||||
/* Make the bufsize no smaller than STREAM_BUFSIZE. Round up the
|
/* Make the bufsize no smaller than STREAM_BUFSIZE. Round up the
|
||||||
* bufsize to fit X threads into it */
|
* bufsize to fit X threads into it */
|
||||||
sinfo->bufsize = MIN(limit, MAX((limit + control.threads - 1) / control.threads,
|
sinfo->bufsize = MIN(limit, MAX((limit + control->threads - 1) / control->threads,
|
||||||
STREAM_BUFSIZE));
|
STREAM_BUFSIZE));
|
||||||
|
|
||||||
if (control.threads > 1)
|
if (control->threads > 1)
|
||||||
print_maxverbose("Using up to %d threads to compress up to %lld bytes each.\n",
|
print_maxverbose("Using up to %d threads to compress up to %lld bytes each.\n",
|
||||||
control.threads, sinfo->bufsize);
|
control->threads, sinfo->bufsize);
|
||||||
else
|
else
|
||||||
print_maxverbose("Using only 1 thread to compress up to %lld bytes\n",
|
print_maxverbose("Using only 1 thread to compress up to %lld bytes\n",
|
||||||
sinfo->bufsize);
|
sinfo->bufsize);
|
||||||
|
|
@ -847,7 +847,7 @@ retest_malloc:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare a set of n streams for reading on file descriptor f */
|
/* prepare a set of n streams for reading on file descriptor f */
|
||||||
void *open_stream_in(int f, int n)
|
void *open_stream_in(rzip_control *control, int f, int n)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo;
|
struct stream_info *sinfo;
|
||||||
int total_threads, i;
|
int total_threads, i;
|
||||||
|
|
@ -859,10 +859,10 @@ void *open_stream_in(int f, int n)
|
||||||
|
|
||||||
/* We have one thread dedicated to stream 0, and one more thread than
|
/* We have one thread dedicated to stream 0, and one more thread than
|
||||||
* CPUs to keep them busy, unless we're running single-threaded. */
|
* CPUs to keep them busy, unless we're running single-threaded. */
|
||||||
if (control.threads > 1)
|
if (control->threads > 1)
|
||||||
total_threads = control.threads + 2;
|
total_threads = control->threads + 2;
|
||||||
else
|
else
|
||||||
total_threads = control.threads + 1;
|
total_threads = control->threads + 1;
|
||||||
threads = calloc(sizeof(pthread_t), total_threads);
|
threads = calloc(sizeof(pthread_t), total_threads);
|
||||||
if (unlikely(!threads))
|
if (unlikely(!threads))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -897,7 +897,7 @@ again:
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
/* Compatibility crap for versions < 0.40 */
|
/* Compatibility crap for versions < 0.40 */
|
||||||
if (control.major_version == 0 && control.minor_version < 4) {
|
if (control->major_version == 0 && control->minor_version < 4) {
|
||||||
u32 v132, v232, last_head32;
|
u32 v132, v232, last_head32;
|
||||||
|
|
||||||
if (unlikely(read_u32(f, &v132)))
|
if (unlikely(read_u32(f, &v132)))
|
||||||
|
|
@ -953,14 +953,16 @@ failed:
|
||||||
|
|
||||||
/* Enter with s_buf allocated,s_buf points to the compressed data after the
|
/* Enter with s_buf allocated,s_buf points to the compressed data after the
|
||||||
* backend compression and is then freed here */
|
* backend compression and is then freed here */
|
||||||
static void *compthread(void *t)
|
static void *compthread(void *data)
|
||||||
{
|
{
|
||||||
long i = (long)t;
|
rzip_control *control = data;
|
||||||
|
long i = (long)control->data;
|
||||||
|
control->data = NULL;
|
||||||
struct compress_thread *cti = &cthread[i];
|
struct compress_thread *cti = &cthread[i];
|
||||||
struct stream_info *ctis = cti->sinfo;
|
struct stream_info *ctis = cti->sinfo;
|
||||||
int waited = 0, ret = 0;
|
int waited = 0, ret = 0;
|
||||||
|
|
||||||
if (unlikely(setpriority(PRIO_PROCESS, 0, control.nice_val) == -1))
|
if (unlikely(setpriority(PRIO_PROCESS, 0, control->nice_val) == -1))
|
||||||
print_err("Warning, unable to set nice value on thread\n");
|
print_err("Warning, unable to set nice value on thread\n");
|
||||||
|
|
||||||
cti->c_type = CTYPE_NONE;
|
cti->c_type = CTYPE_NONE;
|
||||||
|
|
@ -972,15 +974,15 @@ static void *compthread(void *t)
|
||||||
retry:
|
retry:
|
||||||
if (!NO_COMPRESS && cti->c_len) {
|
if (!NO_COMPRESS && cti->c_len) {
|
||||||
if (LZMA_COMPRESS)
|
if (LZMA_COMPRESS)
|
||||||
ret = lzma_compress_buf(cti);
|
ret = lzma_compress_buf(control, cti);
|
||||||
else if (LZO_COMPRESS)
|
else if (LZO_COMPRESS)
|
||||||
ret = lzo_compress_buf(cti);
|
ret = lzo_compress_buf(control, cti);
|
||||||
else if (BZIP2_COMPRESS)
|
else if (BZIP2_COMPRESS)
|
||||||
ret = bzip2_compress_buf(cti);
|
ret = bzip2_compress_buf(control, cti);
|
||||||
else if (ZLIB_COMPRESS)
|
else if (ZLIB_COMPRESS)
|
||||||
ret = gzip_compress_buf(cti);
|
ret = gzip_compress_buf(control, cti);
|
||||||
else if (ZPAQ_COMPRESS)
|
else if (ZPAQ_COMPRESS)
|
||||||
ret = zpaq_compress_buf(cti, i);
|
ret = zpaq_compress_buf(control, cti, i);
|
||||||
else failure("Dunno wtf compression to use!\n");
|
else failure("Dunno wtf compression to use!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1047,7 +1049,7 @@ retry:
|
||||||
free(cti->s_buf);
|
free(cti->s_buf);
|
||||||
|
|
||||||
lock_mutex(&output_lock);
|
lock_mutex(&output_lock);
|
||||||
if (++output_thread == control.threads)
|
if (++output_thread == control->threads)
|
||||||
output_thread = 0;
|
output_thread = 0;
|
||||||
cond_broadcast(&output_cond);
|
cond_broadcast(&output_cond);
|
||||||
unlock_mutex(&output_lock);
|
unlock_mutex(&output_lock);
|
||||||
|
|
@ -1057,7 +1059,7 @@ retry:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_buffer(struct stream_info *sinfo, int stream, int newbuf)
|
static void clear_buffer(rzip_control *control, struct stream_info *sinfo, int stream, int newbuf)
|
||||||
{
|
{
|
||||||
static long i = 0;
|
static long i = 0;
|
||||||
|
|
||||||
|
|
@ -1071,7 +1073,8 @@ static void clear_buffer(struct stream_info *sinfo, int stream, int newbuf)
|
||||||
|
|
||||||
print_maxverbose("Starting thread %ld to compress %lld bytes from stream %d\n",
|
print_maxverbose("Starting thread %ld to compress %lld bytes from stream %d\n",
|
||||||
i, cthread[i].s_len, stream);
|
i, cthread[i].s_len, stream);
|
||||||
create_pthread(&threads[i], NULL, compthread, (void *)i);
|
control->data = (void*)i;
|
||||||
|
create_pthread(&threads[i], NULL, compthread, control);
|
||||||
|
|
||||||
if (newbuf) {
|
if (newbuf) {
|
||||||
/* The stream buffer has been given to the thread, allocate a new one */
|
/* The stream buffer has been given to the thread, allocate a new one */
|
||||||
|
|
@ -1081,42 +1084,44 @@ static void clear_buffer(struct stream_info *sinfo, int stream, int newbuf)
|
||||||
sinfo->s[stream].buflen = 0;
|
sinfo->s[stream].buflen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++i == control.threads)
|
if (++i == control->threads)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flush out any data in a stream buffer */
|
/* flush out any data in a stream buffer */
|
||||||
void flush_buffer(struct stream_info *sinfo, int stream)
|
void flush_buffer(rzip_control *control, struct stream_info *sinfo, int stream)
|
||||||
{
|
{
|
||||||
clear_buffer(sinfo, stream, 1);
|
clear_buffer(control, sinfo, stream, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *ucompthread(void *t)
|
static void *ucompthread(void *data)
|
||||||
{
|
{
|
||||||
long i = (long)t;
|
rzip_control *control = data;
|
||||||
|
long i = (long)control->data;
|
||||||
|
control->data = NULL;
|
||||||
struct uncomp_thread *uci = &ucthread[i];
|
struct uncomp_thread *uci = &ucthread[i];
|
||||||
int waited = 0, ret = 0;
|
int waited = 0, ret = 0;
|
||||||
|
|
||||||
if (unlikely(setpriority(PRIO_PROCESS, 0, control.nice_val) == -1))
|
if (unlikely(setpriority(PRIO_PROCESS, 0, control->nice_val) == -1))
|
||||||
print_err("Warning, unable to set nice value on thread\n");
|
print_err("Warning, unable to set nice value on thread\n");
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
if (uci->c_type != CTYPE_NONE) {
|
if (uci->c_type != CTYPE_NONE) {
|
||||||
switch (uci->c_type) {
|
switch (uci->c_type) {
|
||||||
case CTYPE_LZMA:
|
case CTYPE_LZMA:
|
||||||
ret = lzma_decompress_buf(uci);
|
ret = lzma_decompress_buf(control, uci);
|
||||||
break;
|
break;
|
||||||
case CTYPE_LZO:
|
case CTYPE_LZO:
|
||||||
ret = lzo_decompress_buf(uci);
|
ret = lzo_decompress_buf(control, uci);
|
||||||
break;
|
break;
|
||||||
case CTYPE_BZIP2:
|
case CTYPE_BZIP2:
|
||||||
ret = bzip2_decompress_buf(uci);
|
ret = bzip2_decompress_buf(control, uci);
|
||||||
break;
|
break;
|
||||||
case CTYPE_GZIP:
|
case CTYPE_GZIP:
|
||||||
ret = gzip_decompress_buf(uci);
|
ret = gzip_decompress_buf(control, uci);
|
||||||
break;
|
break;
|
||||||
case CTYPE_ZPAQ:
|
case CTYPE_ZPAQ:
|
||||||
ret = zpaq_decompress_buf(uci, i);
|
ret = zpaq_decompress_buf(control, uci, i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
failure("Dunno wtf decompression type to use!\n");
|
failure("Dunno wtf decompression type to use!\n");
|
||||||
|
|
@ -1147,7 +1152,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill a buffer from a stream - return -1 on failure */
|
/* fill a buffer from a stream - return -1 on failure */
|
||||||
static int fill_buffer(struct stream_info *sinfo, int stream)
|
static int fill_buffer(rzip_control *control, struct stream_info *sinfo, int stream)
|
||||||
{
|
{
|
||||||
i64 header_length, u_len, c_len, last_head;
|
i64 header_length, u_len, c_len, last_head;
|
||||||
struct stream *s = &sinfo->s[stream];
|
struct stream *s = &sinfo->s[stream];
|
||||||
|
|
@ -1168,7 +1173,7 @@ fill_another:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Compatibility crap for versions < 0.4 */
|
/* Compatibility crap for versions < 0.4 */
|
||||||
if (control.major_version == 0 && control.minor_version < 4) {
|
if (control->major_version == 0 && control->minor_version < 4) {
|
||||||
u32 c_len32, u_len32, last_head32;
|
u32 c_len32, u_len32, last_head32;
|
||||||
|
|
||||||
if (unlikely(read_u32(sinfo->fd, &c_len32)))
|
if (unlikely(read_u32(sinfo->fd, &c_len32)))
|
||||||
|
|
@ -1193,7 +1198,7 @@ fill_another:
|
||||||
|
|
||||||
sinfo->total_read += header_length;
|
sinfo->total_read += header_length;
|
||||||
|
|
||||||
fsync(control.fd_out);
|
fsync(control->fd_out);
|
||||||
|
|
||||||
s_buf = malloc(u_len);
|
s_buf = malloc(u_len);
|
||||||
if (unlikely(u_len && !s_buf))
|
if (unlikely(u_len && !s_buf))
|
||||||
|
|
@ -1216,7 +1221,8 @@ fill_another:
|
||||||
ucthread[s->uthread_no].busy = 1;
|
ucthread[s->uthread_no].busy = 1;
|
||||||
print_maxverbose("Starting thread %ld to decompress %lld bytes from stream %d\n",
|
print_maxverbose("Starting thread %ld to decompress %lld bytes from stream %d\n",
|
||||||
s->uthread_no, c_len, stream);
|
s->uthread_no, c_len, stream);
|
||||||
create_pthread(&threads[s->uthread_no], NULL, ucompthread, (void *)s->uthread_no);
|
control->data = (void*)s->uthread_no;
|
||||||
|
create_pthread(&threads[s->uthread_no], NULL, ucompthread, control);
|
||||||
|
|
||||||
if (++s->uthread_no == s->base_thread + s->total_threads)
|
if (++s->uthread_no == s->base_thread + s->total_threads)
|
||||||
s->uthread_no = s->base_thread;
|
s->uthread_no = s->base_thread;
|
||||||
|
|
@ -1228,7 +1234,7 @@ fill_another:
|
||||||
if (!last_head)
|
if (!last_head)
|
||||||
s->eos = 1;
|
s->eos = 1;
|
||||||
else if (s->uthread_no != s->unext_thread && !ucthread[s->uthread_no].busy &&
|
else if (s->uthread_no != s->unext_thread && !ucthread[s->uthread_no].busy &&
|
||||||
sinfo->ram_alloced < control.ramsize / 3)
|
sinfo->ram_alloced < control->ramsize / 3)
|
||||||
goto fill_another;
|
goto fill_another;
|
||||||
out:
|
out:
|
||||||
lock_mutex(&output_lock);
|
lock_mutex(&output_lock);
|
||||||
|
|
@ -1253,7 +1259,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write some data to a stream. Return -1 on failure */
|
/* write some data to a stream. Return -1 on failure */
|
||||||
int write_stream(void *ss, int stream, uchar *p, i64 len)
|
int write_stream(rzip_control *control, void *ss, int stream, uchar *p, i64 len)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo = ss;
|
struct stream_info *sinfo = ss;
|
||||||
|
|
||||||
|
|
@ -1269,14 +1275,14 @@ int write_stream(void *ss, int stream, uchar *p, i64 len)
|
||||||
|
|
||||||
/* Flush the buffer every sinfo->bufsize into one thread */
|
/* Flush the buffer every sinfo->bufsize into one thread */
|
||||||
if (sinfo->s[stream].buflen == sinfo->bufsize)
|
if (sinfo->s[stream].buflen == sinfo->bufsize)
|
||||||
flush_buffer(sinfo, stream);
|
flush_buffer(control, sinfo, stream);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read some data from a stream. Return number of bytes read, or -1
|
/* read some data from a stream. Return number of bytes read, or -1
|
||||||
on failure */
|
on failure */
|
||||||
i64 read_stream(void *ss, int stream, uchar *p, i64 len)
|
i64 read_stream(rzip_control *control, void *ss, int stream, uchar *p, i64 len)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo = ss;
|
struct stream_info *sinfo = ss;
|
||||||
i64 ret = 0;
|
i64 ret = 0;
|
||||||
|
|
@ -1295,7 +1301,7 @@ i64 read_stream(void *ss, int stream, uchar *p, i64 len)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len && sinfo->s[stream].bufp == sinfo->s[stream].buflen) {
|
if (len && sinfo->s[stream].bufp == sinfo->s[stream].buflen) {
|
||||||
if (unlikely(fill_buffer(sinfo, stream)))
|
if (unlikely(fill_buffer(control, sinfo, stream)))
|
||||||
return -1;
|
return -1;
|
||||||
if (sinfo->s[stream].bufp == sinfo->s[stream].buflen)
|
if (sinfo->s[stream].bufp == sinfo->s[stream].buflen)
|
||||||
break;
|
break;
|
||||||
|
|
@ -1306,14 +1312,14 @@ i64 read_stream(void *ss, int stream, uchar *p, i64 len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flush and close down a stream. return -1 on failure */
|
/* flush and close down a stream. return -1 on failure */
|
||||||
int close_stream_out(void *ss)
|
int close_stream_out(rzip_control *control, void *ss)
|
||||||
{
|
{
|
||||||
struct stream_info *sinfo = ss;
|
struct stream_info *sinfo = ss;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < sinfo->num_streams; i++) {
|
for (i = 0; i < sinfo->num_streams; i++) {
|
||||||
if (sinfo->s[i].buflen)
|
if (sinfo->s[i].buflen)
|
||||||
clear_buffer(sinfo, i, 0);
|
clear_buffer(control, sinfo, i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -1351,7 +1357,7 @@ int close_stream_in(void *ss)
|
||||||
to see if there is any compression at all with lzo first. It is unlikely
|
to see if there is any compression at all with lzo first. It is unlikely
|
||||||
that others will be able to compress if lzo is unable to drop a single byte
|
that others will be able to compress if lzo is unable to drop a single byte
|
||||||
so do not compress any block that is incompressible by lzo. */
|
so do not compress any block that is incompressible by lzo. */
|
||||||
static int lzo_compresses(uchar *s_buf, i64 s_len)
|
static int lzo_compresses(rzip_control *control, uchar *s_buf, i64 s_len)
|
||||||
{
|
{
|
||||||
lzo_bytep wrkmem = NULL;
|
lzo_bytep wrkmem = NULL;
|
||||||
lzo_uint in_len, test_len = s_len, save_len = s_len;
|
lzo_uint in_len, test_len = s_len, save_len = s_len;
|
||||||
|
|
|
||||||
38
util.c
38
util.c
|
|
@ -32,20 +32,44 @@
|
||||||
|
|
||||||
#include "rzip.h"
|
#include "rzip.h"
|
||||||
|
|
||||||
|
static const char *infile = NULL;
|
||||||
|
static char delete_infile = 0;
|
||||||
|
static const char *outfile = NULL;
|
||||||
|
static char delete_outfile = 0;
|
||||||
|
static FILE *outputfile = NULL;
|
||||||
|
|
||||||
|
void register_infile(const char *name, char delete)
|
||||||
|
{
|
||||||
|
infile = name;
|
||||||
|
delete_infile = delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_outfile(const char *name, char delete)
|
||||||
|
{
|
||||||
|
outfile = name;
|
||||||
|
delete_outfile = delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_outputfile(FILE *f)
|
||||||
|
{
|
||||||
|
outputfile = f;
|
||||||
|
}
|
||||||
|
|
||||||
static void unlink_files(void)
|
static void unlink_files(void)
|
||||||
{
|
{
|
||||||
/* Delete temporary files generated for testing or faking stdio */
|
/* Delete temporary files generated for testing or faking stdio */
|
||||||
if (TEST_ONLY || STDOUT || !KEEP_BROKEN)
|
if (outfile && delete_outfile)
|
||||||
unlink(control.outfile);
|
unlink(outfile);
|
||||||
|
|
||||||
if ((DECOMPRESS || TEST_ONLY) && STDIN)
|
if (infile && delete_infile)
|
||||||
unlink(control.infile);
|
unlink(infile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal_exit(void)
|
static void fatal_exit(void)
|
||||||
{
|
{
|
||||||
unlink_files();
|
unlink_files();
|
||||||
print_output("Fatal error - exiting\n");
|
fprintf(outputfile, "Fatal error - exiting\n");
|
||||||
|
fflush(outputfile);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,9 +109,9 @@ void sighandler()
|
||||||
|
|
||||||
void round_to_page(i64 *size)
|
void round_to_page(i64 *size)
|
||||||
{
|
{
|
||||||
*size -= *size % control.page_size;
|
*size -= *size % PAGE_SIZE;
|
||||||
if (unlikely(!*size))
|
if (unlikely(!*size))
|
||||||
*size = control.page_size;
|
*size = PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_config( struct rzip_control *control )
|
void read_config( struct rzip_control *control )
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue