2017-08-18 23:52:05 +00:00
/*
2016-08-30 17:04:33 +00:00
* Copyright ( c ) 2016 - present , Yann Collet , Facebook , Inc .
* All rights reserved .
*
2017-08-18 23:52:05 +00:00
* This source code is licensed under both the BSD - style license ( found in the
* LICENSE file in the root directory of this source tree ) and the GPLv2 ( found
* in the COPYING file in the root directory of this source tree ) .
2017-09-08 07:09:23 +00:00
* You may select , at your option , one of the above - listed licenses .
2016-08-30 17:04:33 +00:00
*/
2015-01-24 00:58:16 +00:00
2017-01-26 01:01:13 +00:00
2015-10-22 15:55:40 +00:00
/* *************************************
2015-01-24 00:58:16 +00:00
* Compiler Options
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-08-13 23:19:12 +00:00
# ifdef _MSC_VER /* Visual */
2016-12-21 12:47:11 +00:00
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
2016-08-13 23:19:12 +00:00
# pragma warning(disable : 4204) /* non-constant aggregate initializer */
# endif
2016-12-21 12:23:34 +00:00
# if defined(__MINGW32__) && !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1 /* disable %llu warnings with MinGW on Windows */
# endif
2015-01-24 00:58:16 +00:00
2018-09-21 21:46:09 +00:00
# if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
# define BACKTRACES_ENABLE 1
# endif
2016-11-03 00:30:49 +00:00
2016-02-12 19:19:48 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Includes
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-12-21 14:08:44 +00:00
# include "platform.h" /* Large Files support, SET_BINARY_MODE */
2017-10-17 23:14:25 +00:00
# include "util.h" /* UTIL_getFileSize, UTIL_isRegularFile */
2015-11-09 16:42:17 +00:00
# include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */
# include <stdlib.h> /* malloc, free */
# include <string.h> /* strcmp, strlen */
# include <errno.h> /* errno */
2018-09-11 18:39:49 +00:00
# include <signal.h>
2018-09-21 21:46:09 +00:00
# ifdef BACKTRACES_ENABLE
# include <execinfo.h> /* backtrace, backtrace_symbols */
2018-09-11 18:39:49 +00:00
# endif
2016-04-28 12:40:45 +00:00
2017-04-06 19:56:40 +00:00
# if defined (_MSC_VER)
# include <sys / stat.h>
# include <io.h>
# endif
2018-06-15 14:36:54 +00:00
# include "debug.h"
2016-12-21 12:23:34 +00:00
# include "mem.h"
2015-01-24 00:58:16 +00:00
# include "fileio.h"
2017-11-30 03:11:12 +00:00
# include "util.h"
2018-02-02 00:13:04 +00:00
2016-06-04 17:47:02 +00:00
# define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
# include "zstd.h"
2018-02-02 00:13:04 +00:00
# include "zstd_errors.h" /* ZSTD_error_frameParameter_windowTooLarge */
2017-02-08 15:54:23 +00:00
# if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
2017-02-06 19:32:13 +00:00
# include <zlib.h>
2017-01-20 00:59:56 +00:00
# if !defined(z_const)
# define z_const
# endif
2016-11-30 14:05:54 +00:00
# endif
2018-02-02 00:13:04 +00:00
2017-03-14 01:11:07 +00:00
# if defined(ZSTD_LZMACOMPRESS) || defined(ZSTD_LZMADECOMPRESS)
# include <lzma.h>
# endif
2015-01-24 00:58:16 +00:00
2017-04-24 23:48:25 +00:00
# define LZ4_MAGICNUMBER 0x184D2204
# if defined(ZSTD_LZ4COMPRESS) || defined(ZSTD_LZ4DECOMPRESS)
2017-09-21 18:29:35 +00:00
# define LZ4F_ENABLE_OBSOLETE_ENUMS
2017-04-24 23:48:25 +00:00
# include <lz4frame.h>
2017-04-25 18:00:54 +00:00
# include <lz4.h>
2017-04-24 23:48:25 +00:00
# endif
2015-01-24 00:58:16 +00:00
2016-02-12 19:19:48 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Constants
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-07-02 23:10:53 +00:00
# define KB *(1<<10)
# define MB *(1<<20)
# define GB *(1U<<30)
2018-08-13 20:10:42 +00:00
# define ADAPT_WINDOWLOG_DEFAULT 23 /* 8 MB */
2017-04-11 21:41:02 +00:00
# define DICTSIZE_MAX (32 MB) /* protection against large input (attack scenario) */
2016-02-12 19:19:48 +00:00
2016-04-22 11:59:05 +00:00
# define FNSPACE 30
2015-01-24 00:58:16 +00:00
2016-02-15 19:37:23 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Macros
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-01-24 00:58:16 +00:00
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
2017-06-15 19:27:32 +00:00
# define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__)
2017-01-27 21:30:18 +00:00
# define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
2017-05-17 01:10:11 +00:00
static int g_displayLevel = 2 ; /* 0 : no display; 1: errors; 2: + result + interaction + warnings; 3: + progression; 4: + information */
2016-03-10 20:02:25 +00:00
void FIO_setNotificationLevel ( unsigned level ) { g_displayLevel = level ; }
2015-01-24 00:58:16 +00:00
2017-11-30 03:11:12 +00:00
static const U64 g_refreshRate = SEC_TO_MICRO / 6 ;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER ;
2018-01-18 19:27:13 +00:00
# define READY_FOR_UPDATE() (UTIL_clockSpanMicro(g_displayClock) > g_refreshRate)
2018-03-23 00:49:46 +00:00
# define DELAY_NEXT_UPDATE() { g_displayClock = UTIL_getTime(); }
2018-01-18 00:39:02 +00:00
# define DISPLAYUPDATE(l, ...) { \
if ( g_displayLevel > = l ) { \
2018-03-23 00:49:46 +00:00
if ( READY_FOR_UPDATE ( ) | | ( g_displayLevel > = 4 ) ) { \
DELAY_NEXT_UPDATE ( ) ; \
DISPLAY ( __VA_ARGS__ ) ; \
2018-01-18 00:39:02 +00:00
if ( g_displayLevel > = 4 ) fflush ( stderr ) ; \
} } }
2015-01-24 00:58:16 +00:00
2017-05-17 01:10:11 +00:00
# undef MIN /* in case it would be already defined */
2017-04-13 22:35:05 +00:00
# define MIN(a,b) ((a) < (b) ? (a) : (b))
2016-07-02 23:10:53 +00:00
2017-04-27 07:29:04 +00:00
2017-10-19 18:56:14 +00:00
# define EXM_THROW(error, ...) \
{ \
DISPLAYLEVEL ( 1 , " zstd: " ) ; \
DEBUGLOG ( 1 , " Error defined at %s, line %i : \n " , __FILE__ , __LINE__ ) ; \
DISPLAYLEVEL ( 1 , " error %i : " , error ) ; \
DISPLAYLEVEL ( 1 , __VA_ARGS__ ) ; \
DISPLAYLEVEL ( 1 , " \n " ) ; \
exit ( error ) ; \
2017-05-18 01:36:15 +00:00
}
2017-12-14 21:00:20 +00:00
# define CHECK_V(v, f) \
v = f ; \
if ( ZSTD_isError ( v ) ) { \
2017-06-21 22:16:13 +00:00
DEBUGLOG ( 1 , " %s \n " , # f ) ; \
2017-12-14 21:00:20 +00:00
EXM_THROW ( 11 , " %s " , ZSTD_getErrorName ( v ) ) ; \
}
# define CHECK(f) { size_t err; CHECK_V(err, f); }
2017-05-18 01:36:15 +00:00
2017-10-01 19:10:26 +00:00
/*-************************************
* Signal ( Ctrl - C trapping )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-10-02 18:39:05 +00:00
static const char * g_artefact = NULL ;
static void INThandler ( int sig )
2017-10-01 19:10:26 +00:00
{
2017-10-02 07:19:47 +00:00
assert ( sig = = SIGINT ) ; ( void ) sig ;
2017-10-02 09:02:16 +00:00
# if !defined(_MSC_VER)
signal ( sig , SIG_IGN ) ; /* this invocation generates a buggy warning in Visual Studio */
2017-10-02 07:02:24 +00:00
# endif
2018-01-05 19:44:45 +00:00
if ( g_artefact ) {
assert ( UTIL_isRegularFile ( g_artefact ) ) ;
remove ( g_artefact ) ;
}
2017-10-01 19:10:26 +00:00
DISPLAY ( " \n " ) ;
2017-10-01 22:32:48 +00:00
exit ( 2 ) ;
2017-10-01 19:10:26 +00:00
}
2017-11-18 00:38:56 +00:00
static void addHandler ( char const * dstFileName )
{
if ( UTIL_isRegularFile ( dstFileName ) ) {
g_artefact = dstFileName ;
signal ( SIGINT , INThandler ) ;
} else {
g_artefact = NULL ;
}
}
/* Idempotent */
static void clearHandler ( void )
{
if ( g_artefact ) signal ( SIGINT , SIG_DFL ) ;
g_artefact = NULL ;
}
2017-10-01 19:10:26 +00:00
2018-09-11 18:39:49 +00:00
/*-*********************************************************
* Termination signal trapping ( Print debug stack trace )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-09-21 21:46:09 +00:00
# ifdef BACKTRACES_ENABLE
2018-09-11 18:39:49 +00:00
# define MAX_STACK_FRAMES 50
static void ABRThandler ( int sig ) {
2018-09-11 21:49:47 +00:00
const char * name ;
void * addrlist [ MAX_STACK_FRAMES ] ;
char * * symbollist ;
U32 addrlen , i ;
switch ( sig ) {
case SIGABRT : name = " SIGABRT " ; break ;
case SIGFPE : name = " SIGFPE " ; break ;
case SIGILL : name = " SIGILL " ; break ;
case SIGINT : name = " SIGINT " ; break ;
case SIGSEGV : name = " SIGSEGV " ; break ;
default : name = " UNKNOWN " ;
}
DISPLAY ( " Caught %s signal, printing stack: \n " , name ) ;
/* Retrieve current stack addresses. */
addrlen = backtrace ( addrlist , MAX_STACK_FRAMES ) ;
if ( addrlen = = 0 ) {
DISPLAY ( " \n " ) ;
return ;
}
/* Create readable strings to each frame. */
symbollist = backtrace_symbols ( addrlist , addrlen ) ;
/* Print the stack trace, excluding calls handling the signal. */
for ( i = ZSTD_START_SYMBOLLIST_FRAME ; i < addrlen ; i + + ) {
DISPLAY ( " %s \n " , symbollist [ i ] ) ;
}
free ( symbollist ) ;
/* Reset and raise the signal so default handler runs. */
signal ( sig , SIG_DFL ) ;
raise ( sig ) ;
2018-09-11 18:39:49 +00:00
}
# endif
void FIO_addAbortHandler ( )
{
2018-09-21 21:46:09 +00:00
# ifdef BACKTRACES_ENABLE
2018-09-11 18:39:49 +00:00
signal ( SIGABRT , ABRThandler ) ;
signal ( SIGFPE , ABRThandler ) ;
signal ( SIGILL , ABRThandler ) ;
signal ( SIGSEGV , ABRThandler ) ;
signal ( SIGBUS , ABRThandler ) ;
# endif
}
2018-09-07 01:46:52 +00:00
/*-************************************************************
2018-06-09 19:31:17 +00:00
* Avoid fseek ( ) ' s 2 GiB barrier with MSVC , macOS , * BSD , MinGW
2017-02-14 08:45:33 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-12 09:27:18 +00:00
# if defined(_MSC_VER) && _MSC_VER >= 1400
# define LONG_SEEK _fseeki64
2017-02-14 08:45:33 +00:00
# elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
2017-02-14 08:52:52 +00:00
# define LONG_SEEK fseeko
2017-02-12 09:27:18 +00:00
# elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__)
# define LONG_SEEK fseeko64
# elif defined(_WIN32) && !defined(__DJGPP__)
# include <windows.h>
static int LONG_SEEK ( FILE * file , __int64 offset , int origin ) {
LARGE_INTEGER off ;
DWORD method ;
off . QuadPart = offset ;
if ( origin = = SEEK_END )
method = FILE_END ;
else if ( origin = = SEEK_CUR )
method = FILE_CURRENT ;
else
method = FILE_BEGIN ;
if ( SetFilePointerEx ( ( HANDLE ) _get_osfhandle ( _fileno ( file ) ) , off , NULL , method ) )
2017-02-13 11:00:59 +00:00
return 0 ;
2017-02-12 09:27:18 +00:00
else
2017-02-13 11:00:59 +00:00
return - 1 ;
2017-02-12 09:27:18 +00:00
}
# else
# define LONG_SEEK fseek
# endif
2016-02-15 19:37:23 +00:00
/*-*************************************
2016-07-01 23:05:31 +00:00
* Local Parameters - Not thread safe
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-14 08:23:32 +00:00
static FIO_compressionType_t g_compressionType = FIO_zstdCompression ;
void FIO_setCompressionType ( FIO_compressionType_t compressionType ) { g_compressionType = compressionType ; }
2015-01-24 00:58:16 +00:00
static U32 g_overwrite = 0 ;
void FIO_overwriteMode ( void ) { g_overwrite = 1 ; }
2017-05-18 01:36:15 +00:00
static U32 g_sparseFileSupport = 1 ; /* 0: no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */
2016-05-23 14:56:56 +00:00
void FIO_setSparseWrite ( unsigned sparse ) { g_sparseFileSupport = sparse ; }
2016-05-31 00:29:45 +00:00
static U32 g_dictIDFlag = 1 ;
void FIO_setDictIDFlag ( unsigned dictIDFlag ) { g_dictIDFlag = dictIDFlag ; }
2016-06-20 14:31:24 +00:00
static U32 g_checksumFlag = 1 ;
2016-06-01 17:22:15 +00:00
void FIO_setChecksumFlag ( unsigned checksumFlag ) { g_checksumFlag = checksumFlag ; }
2016-06-09 20:59:51 +00:00
static U32 g_removeSrcFile = 0 ;
void FIO_setRemoveSrcFile ( unsigned flag ) { g_removeSrcFile = ( flag > 0 ) ; }
2016-10-14 20:13:13 +00:00
static U32 g_memLimit = 0 ;
void FIO_setMemLimit ( unsigned memLimit ) { g_memLimit = memLimit ; }
2018-02-02 03:29:30 +00:00
static U32 g_nbWorkers = 1 ;
void FIO_setNbWorkers ( unsigned nbWorkers ) {
2017-01-20 00:59:56 +00:00
# ifndef ZSTD_MULTITHREAD
2018-02-02 03:29:30 +00:00
if ( nbWorkers > 0 ) DISPLAYLEVEL ( 2 , " Note : multi-threading is disabled \n " ) ;
2017-01-20 00:59:56 +00:00
# endif
2018-02-02 03:29:30 +00:00
g_nbWorkers = nbWorkers ;
2017-01-20 00:59:56 +00:00
}
2017-01-25 01:02:26 +00:00
static U32 g_blockSize = 0 ;
void FIO_setBlockSize ( unsigned blockSize ) {
2018-02-02 03:29:30 +00:00
if ( blockSize & & g_nbWorkers = = 0 )
2017-01-25 01:02:26 +00:00
DISPLAYLEVEL ( 2 , " Setting block size is useless in single-thread mode \n " ) ;
g_blockSize = blockSize ;
}
2017-01-30 22:37:08 +00:00
# define FIO_OVERLAP_LOG_NOTSET 9999
static U32 g_overlapLog = FIO_OVERLAP_LOG_NOTSET ;
2017-01-30 19:17:26 +00:00
void FIO_setOverlapLog ( unsigned overlapLog ) {
2018-02-02 03:29:30 +00:00
if ( overlapLog & & g_nbWorkers = = 0 )
2017-01-30 19:17:26 +00:00
DISPLAYLEVEL ( 2 , " Setting overlapLog is useless in single-thread mode \n " ) ;
g_overlapLog = overlapLog ;
}
2018-08-12 03:48:06 +00:00
static U32 g_adaptiveMode = 0 ;
2018-09-19 21:49:13 +00:00
void FIO_setAdaptiveMode ( unsigned adapt ) {
if ( ( adapt > 0 ) & & ( g_nbWorkers = = 0 ) )
EXM_THROW ( 1 , " Adaptive mode is not compatible with single thread mode \n " ) ;
g_adaptiveMode = adapt ;
}
2017-07-28 22:51:33 +00:00
static U32 g_ldmFlag = 0 ;
void FIO_setLdmFlag ( unsigned ldmFlag ) {
g_ldmFlag = ( ldmFlag > 0 ) ;
}
2017-09-01 21:52:51 +00:00
static U32 g_ldmHashLog = 0 ;
void FIO_setLdmHashLog ( unsigned ldmHashLog ) {
g_ldmHashLog = ldmHashLog ;
}
static U32 g_ldmMinMatch = 0 ;
void FIO_setLdmMinMatch ( unsigned ldmMinMatch ) {
g_ldmMinMatch = ldmMinMatch ;
}
2017-09-03 04:10:36 +00:00
# define FIO_LDM_PARAM_NOTSET 9999
static U32 g_ldmBucketSizeLog = FIO_LDM_PARAM_NOTSET ;
void FIO_setLdmBucketSizeLog ( unsigned ldmBucketSizeLog ) {
g_ldmBucketSizeLog = ldmBucketSizeLog ;
}
static U32 g_ldmHashEveryLog = FIO_LDM_PARAM_NOTSET ;
2017-09-01 21:52:51 +00:00
void FIO_setLdmHashEveryLog ( unsigned ldmHashEveryLog ) {
g_ldmHashEveryLog = ldmHashEveryLog ;
}
2015-01-24 00:58:16 +00:00
2016-02-15 19:37:23 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Functions
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-04-06 19:56:40 +00:00
/** FIO_remove() :
* @ result : Unlink ` fileName ` , even if it ' s read - only */
static int FIO_remove ( const char * path )
{
2017-12-13 20:04:46 +00:00
if ( ! UTIL_isRegularFile ( path ) ) {
DISPLAYLEVEL ( 2 , " zstd: Refusing to remove non-regular file %s \n " , path ) ;
return 0 ;
}
2017-04-06 19:56:40 +00:00
# if defined(_WIN32) || defined(WIN32)
2017-05-06 02:15:24 +00:00
/* windows doesn't allow remove read-only files,
* so try to make it writable first */
2017-04-06 19:56:40 +00:00
chmod ( path , _S_IWRITE ) ;
# endif
return remove ( path ) ;
}
2016-11-12 01:26:54 +00:00
/** FIO_openSrcFile() :
2017-10-19 18:56:14 +00:00
* condition : ` srcFileName ` must be non - NULL .
* @ result : FILE * to ` srcFileName ` , or NULL if it fails */
2016-02-12 14:56:46 +00:00
static FILE * FIO_openSrcFile ( const char * srcFileName )
2015-12-17 01:23:58 +00:00
{
2017-10-19 18:56:14 +00:00
assert ( srcFileName ! = NULL ) ;
2016-02-02 13:36:49 +00:00
if ( ! strcmp ( srcFileName , stdinmark ) ) {
2015-12-17 01:23:58 +00:00
DISPLAYLEVEL ( 4 , " Using stdin for input \n " ) ;
SET_BINARY_MODE ( stdin ) ;
2017-10-19 18:56:14 +00:00
return stdin ;
}
if ( ! UTIL_isRegularFile ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is not a regular file -- ignored \n " ,
srcFileName ) ;
return NULL ;
2015-12-17 01:23:58 +00:00
}
2017-10-19 18:56:14 +00:00
{ FILE * const f = fopen ( srcFileName , " rb " ) ;
if ( f = = NULL )
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , srcFileName , strerror ( errno ) ) ;
return f ;
}
2016-02-12 14:56:46 +00:00
}
2016-09-15 13:38:44 +00:00
/** FIO_openDstFile() :
2017-10-19 18:56:14 +00:00
* condition : ` dstFileName ` must be non - NULL .
2016-09-15 13:38:44 +00:00
* @ result : FILE * to ` dstFileName ` , or NULL if it fails */
2016-02-12 14:56:46 +00:00
static FILE * FIO_openDstFile ( const char * dstFileName )
{
2017-10-19 18:56:14 +00:00
assert ( dstFileName ! = NULL ) ;
2016-02-02 13:36:49 +00:00
if ( ! strcmp ( dstFileName , stdoutmark ) ) {
2015-12-17 01:23:58 +00:00
DISPLAYLEVEL ( 4 , " Using stdout for output \n " ) ;
SET_BINARY_MODE ( stdout ) ;
2016-05-23 14:56:56 +00:00
if ( g_sparseFileSupport = = 1 ) {
g_sparseFileSupport = 0 ;
DISPLAYLEVEL ( 4 , " Sparse File Support is automatically disabled on stdout ; try --sparse \n " ) ;
}
2017-10-19 18:56:14 +00:00
return stdout ;
}
if ( g_sparseFileSupport = = 1 ) {
g_sparseFileSupport = ZSTD_SPARSE_DEFAULT ;
}
2017-12-13 20:04:46 +00:00
if ( UTIL_isRegularFile ( dstFileName ) ) {
FILE * fCheck ;
if ( ! strcmp ( dstFileName , nulmark ) ) {
EXM_THROW ( 40 , " %s is unexpectedly a regular file " , dstFileName ) ;
}
2017-10-19 18:56:14 +00:00
/* Check if destination file already exists */
2017-12-13 20:04:46 +00:00
fCheck = fopen ( dstFileName , " rb " ) ;
2017-10-19 18:56:14 +00:00
if ( fCheck ! = NULL ) { /* dst file exists, authorization prompt */
fclose ( fCheck ) ;
if ( ! g_overwrite ) {
if ( g_displayLevel < = 1 ) {
/* No interaction possible */
DISPLAY ( " zstd: %s already exists; not overwritten \n " ,
dstFileName ) ;
return NULL ;
}
DISPLAY ( " zstd: %s already exists; overwrite (y/N) ? " ,
dstFileName ) ;
{ int ch = getchar ( ) ;
if ( ( ch ! = ' Y ' ) & & ( ch ! = ' y ' ) ) {
DISPLAY ( " not overwritten \n " ) ;
2016-07-01 23:05:31 +00:00
return NULL ;
2015-12-29 10:57:15 +00:00
}
2017-10-19 18:56:14 +00:00
/* flush rest of input line */
while ( ( ch ! = EOF ) & & ( ch ! = ' \n ' ) ) ch = getchar ( ) ;
} }
/* need to unlink */
FIO_remove ( dstFileName ) ;
} }
{ FILE * const f = fopen ( dstFileName , " wb " ) ;
if ( f = = NULL )
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ;
return f ;
2016-02-12 14:56:46 +00:00
}
}
2017-04-11 21:41:02 +00:00
/*! FIO_createDictBuffer() :
* creates a buffer , pointed by ` * bufferPtr ` ,
* loads ` filename ` content into it , up to DICTSIZE_MAX bytes .
2017-10-19 18:56:14 +00:00
* @ return : loaded size
2017-04-11 21:41:02 +00:00
* if fileName = = NULL , returns 0 and a NULL pointer
*/
static size_t FIO_createDictBuffer ( void * * bufferPtr , const char * fileName )
2015-12-17 19:30:14 +00:00
{
FILE * fileHandle ;
U64 fileSize ;
2017-10-19 18:56:14 +00:00
assert ( bufferPtr ! = NULL ) ;
2015-12-17 19:30:14 +00:00
* bufferPtr = NULL ;
2016-02-02 13:36:49 +00:00
if ( fileName = = NULL ) return 0 ;
2015-12-17 19:30:14 +00:00
DISPLAYLEVEL ( 4 , " Loading %s as dictionary \n " , fileName ) ;
fileHandle = fopen ( fileName , " rb " ) ;
2017-10-19 18:56:14 +00:00
if ( fileHandle = = NULL ) EXM_THROW ( 31 , " %s: %s " , fileName , strerror ( errno ) ) ;
2016-04-28 10:23:33 +00:00
fileSize = UTIL_getFileSize ( fileName ) ;
2017-09-26 18:21:36 +00:00
if ( fileSize > DICTSIZE_MAX ) {
2017-05-17 01:10:11 +00:00
EXM_THROW ( 32 , " Dictionary file %s is too large (> %u MB) " ,
fileName , DICTSIZE_MAX > > 20 ) ; /* avoid extreme cases */
2017-09-26 18:21:36 +00:00
}
2016-07-01 23:05:31 +00:00
* bufferPtr = malloc ( ( size_t ) fileSize ) ;
2017-05-18 01:36:15 +00:00
if ( * bufferPtr = = NULL ) EXM_THROW ( 34 , " %s " , strerror ( errno ) ) ;
2017-09-26 18:21:36 +00:00
{ size_t const readSize = fread ( * bufferPtr , 1 , ( size_t ) fileSize , fileHandle ) ;
if ( readSize ! = fileSize )
EXM_THROW ( 35 , " Error reading dictionary file %s " , fileName ) ;
}
2015-12-17 19:30:14 +00:00
fclose ( fileHandle ) ;
return ( size_t ) fileSize ;
}
2016-04-22 11:59:05 +00:00
# ifndef ZSTD_NOCOMPRESS
2015-12-17 01:23:58 +00:00
2018-03-23 00:49:46 +00:00
/* **********************************************************************
* Compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-12-17 01:23:58 +00:00
typedef struct {
2017-01-20 00:59:56 +00:00
FILE * srcFile ;
FILE * dstFile ;
2015-12-17 01:23:58 +00:00
void * srcBuffer ;
size_t srcBufferSize ;
void * dstBuffer ;
size_t dstBufferSize ;
2016-08-13 21:45:45 +00:00
ZSTD_CStream * cctx ;
2015-12-17 01:23:58 +00:00
} cRess_t ;
2017-01-20 00:59:56 +00:00
static cRess_t FIO_createCResources ( const char * dictFileName , int cLevel ,
2017-10-02 19:29:25 +00:00
U64 srcSize ,
2018-08-13 20:02:03 +00:00
ZSTD_compressionParameters comprParams ) {
2015-12-17 01:23:58 +00:00
cRess_t ress ;
2016-07-13 15:38:39 +00:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-17 01:23:58 +00:00
2018-03-12 02:56:48 +00:00
DISPLAYLEVEL ( 6 , " FIO_createCResources \n " ) ;
2017-05-18 01:36:15 +00:00
ress . cctx = ZSTD_createCCtx ( ) ;
if ( ress . cctx = = NULL )
EXM_THROW ( 30 , " allocation error : can't create ZSTD_CCtx " ) ;
2016-08-13 21:45:45 +00:00
ress . srcBufferSize = ZSTD_CStreamInSize ( ) ;
2015-12-17 01:23:58 +00:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 21:45:45 +00:00
ress . dstBufferSize = ZSTD_CStreamOutSize ( ) ;
2015-12-17 01:23:58 +00:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
2017-05-17 00:32:33 +00:00
if ( ! ress . srcBuffer | | ! ress . dstBuffer )
2017-05-18 01:36:15 +00:00
EXM_THROW ( 31 , " allocation error : not enough memory " ) ;
2015-12-17 01:23:58 +00:00
2018-02-02 01:07:27 +00:00
/* Advanced parameters, including dictionary */
2016-09-15 13:38:44 +00:00
{ void * dictBuffer ;
2017-04-11 23:57:32 +00:00
size_t const dictBuffSize = FIO_createDictBuffer ( & dictBuffer , dictFileName ) ; /* works with dictFileName==NULL */
2017-05-17 00:32:33 +00:00
if ( dictFileName & & ( dictBuffer = = NULL ) )
2017-05-18 01:36:15 +00:00
EXM_THROW ( 32 , " allocation error : can't create dictBuffer " ) ;
2017-06-12 01:39:46 +00:00
2018-08-13 20:10:42 +00:00
if ( g_adaptiveMode & & ! g_ldmFlag & & ! comprParams . windowLog )
comprParams . windowLog = ADAPT_WINDOWLOG_DEFAULT ;
2017-10-19 18:56:14 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_contentSizeFlag , 1 ) ) ; /* always enable content size when available (note: supposed to be default) */
2017-10-19 00:01:53 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_dictIDFlag , g_dictIDFlag ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_checksumFlag , g_checksumFlag ) ) ;
/* compression level */
2018-03-12 02:56:48 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_compressionLevel , ( unsigned ) cLevel ) ) ;
2017-10-19 00:01:53 +00:00
/* long distance matching */
2018-02-02 01:07:27 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_enableLongDistanceMatching , g_ldmFlag ) ) ;
2017-10-19 00:01:53 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_ldmHashLog , g_ldmHashLog ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_ldmMinMatch , g_ldmMinMatch ) ) ;
if ( g_ldmBucketSizeLog ! = FIO_LDM_PARAM_NOTSET ) {
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_ldmBucketSizeLog , g_ldmBucketSizeLog ) ) ;
2017-05-18 01:36:15 +00:00
}
2017-10-19 00:01:53 +00:00
if ( g_ldmHashEveryLog ! = FIO_LDM_PARAM_NOTSET ) {
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_ldmHashEveryLog , g_ldmHashEveryLog ) ) ;
2017-05-18 01:36:15 +00:00
}
2017-10-19 00:01:53 +00:00
/* compression parameters */
2018-08-13 20:02:03 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_windowLog , comprParams . windowLog ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_chainLog , comprParams . chainLog ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_hashLog , comprParams . hashLog ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_searchLog , comprParams . searchLog ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_minMatch , comprParams . searchLength ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_targetLength , comprParams . targetLength ) ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_compressionStrategy , ( U32 ) comprParams . strategy ) ) ;
2017-10-19 00:01:53 +00:00
/* multi-threading */
2018-02-02 01:07:27 +00:00
# ifdef ZSTD_MULTITHREAD
2018-02-09 23:53:27 +00:00
DISPLAYLEVEL ( 5 , " set nb workers = %u \n " , g_nbWorkers ) ;
2018-02-02 03:29:30 +00:00
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_nbWorkers , g_nbWorkers ) ) ;
2018-03-28 17:33:41 +00:00
if ( ( g_overlapLog = = FIO_OVERLAP_LOG_NOTSET )
& & ( cLevel = = ZSTD_maxCLevel ( ) ) )
g_overlapLog = 9 ; /* full overlap */
if ( g_overlapLog ! = FIO_OVERLAP_LOG_NOTSET ) {
DISPLAYLEVEL ( 3 , " set overlapLog = %u \n " , g_overlapLog ) ;
CHECK ( ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_overlapSizeLog , g_overlapLog ) ) ;
}
2018-01-17 01:28:11 +00:00
# endif
2017-10-19 00:01:53 +00:00
/* dictionary */
2018-02-02 01:07:27 +00:00
CHECK ( ZSTD_CCtx_setPledgedSrcSize ( ress . cctx , srcSize ) ) ; /* set the value temporarily for dictionary loading, to adapt compression parameters */
2017-10-19 00:01:53 +00:00
CHECK ( ZSTD_CCtx_loadDictionary ( ress . cctx , dictBuffer , dictBuffSize ) ) ;
CHECK ( ZSTD_CCtx_setPledgedSrcSize ( ress . cctx , ZSTD_CONTENTSIZE_UNKNOWN ) ) ; /* reset */
2016-09-15 13:38:44 +00:00
free ( dictBuffer ) ;
}
2015-12-17 01:23:58 +00:00
return ress ;
}
static void FIO_freeCResources ( cRess_t ress )
{
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
2016-09-15 13:38:44 +00:00
ZSTD_freeCStream ( ress . cctx ) ; /* never fails */
2015-12-17 01:23:58 +00:00
}
2017-02-08 15:54:23 +00:00
# ifdef ZSTD_GZCOMPRESS
2018-09-19 21:49:13 +00:00
static unsigned long long
FIO_compressGzFrame ( cRess_t * ress ,
2017-05-17 00:32:33 +00:00
const char * srcFileName , U64 const srcFileSize ,
int compressionLevel , U64 * readsize )
2017-02-08 15:54:23 +00:00
{
unsigned long long inFileSize = 0 , outFileSize = 0 ;
z_stream strm ;
2017-02-08 16:37:14 +00:00
int ret ;
2017-02-08 15:54:23 +00:00
2017-05-17 00:32:33 +00:00
if ( compressionLevel > Z_BEST_COMPRESSION )
compressionLevel = Z_BEST_COMPRESSION ;
2017-02-13 20:00:41 +00:00
2017-02-08 15:54:23 +00:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
2017-02-08 16:37:14 +00:00
2017-05-17 00:32:33 +00:00
ret = deflateInit2 ( & strm , compressionLevel , Z_DEFLATED ,
15 /* maxWindowLogSize */ + 16 /* gzip only */ ,
8 , Z_DEFAULT_STRATEGY ) ; /* see http://www.zlib.net/manual.html */
if ( ret ! = Z_OK )
EXM_THROW ( 71 , " zstd: %s: deflateInit2 error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
2017-02-08 16:37:14 +00:00
strm . next_in = 0 ;
2017-02-27 12:21:05 +00:00
strm . avail_in = 0 ;
2017-02-08 15:54:23 +00:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
while ( 1 ) {
if ( strm . avail_in = = 0 ) {
size_t const inSize = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , ress - > srcFile ) ;
if ( inSize = = 0 ) break ;
inFileSize + = inSize ;
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
strm . avail_in = ( uInt ) inSize ;
}
ret = deflate ( & strm , Z_NO_FLUSH ) ;
2017-05-17 00:32:33 +00:00
if ( ret ! = Z_OK )
EXM_THROW ( 72 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
2017-05-17 00:32:33 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes )
EXM_THROW ( 73 , " Write error : cannot write to output file " ) ;
2017-02-08 15:54:23 +00:00
outFileSize + = decompBytes ;
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
}
}
2017-10-18 18:41:52 +00:00
if ( srcFileSize = = UTIL_FILESIZE_UNKNOWN )
2017-05-17 00:32:33 +00:00
DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 )
else
DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 ) ;
2017-02-08 15:54:23 +00:00
}
while ( 1 ) {
2017-02-08 16:37:14 +00:00
ret = deflate ( & strm , Z_FINISH ) ;
2017-02-08 15:54:23 +00:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
2017-05-17 00:32:33 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes )
EXM_THROW ( 75 , " Write error : cannot write to output file " ) ;
2017-02-08 15:54:23 +00:00
outFileSize + = decompBytes ;
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
2017-05-17 00:32:33 +00:00
} }
2017-02-08 15:54:23 +00:00
if ( ret = = Z_STREAM_END ) break ;
2017-05-17 00:32:33 +00:00
if ( ret ! = Z_BUF_ERROR )
EXM_THROW ( 77 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
}
2017-02-08 16:37:14 +00:00
ret = deflateEnd ( & strm ) ;
2017-05-17 00:32:33 +00:00
if ( ret ! = Z_OK )
EXM_THROW ( 79 , " zstd: %s: deflateEnd error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
* readsize = inFileSize ;
return outFileSize ;
}
# endif
2017-03-14 01:11:07 +00:00
# ifdef ZSTD_LZMACOMPRESS
2018-09-19 21:49:13 +00:00
static unsigned long long
FIO_compressLzmaFrame ( cRess_t * ress ,
const char * srcFileName , U64 const srcFileSize ,
int compressionLevel , U64 * readsize , int plain_lzma )
2017-03-14 01:11:07 +00:00
{
unsigned long long inFileSize = 0 , outFileSize = 0 ;
lzma_stream strm = LZMA_STREAM_INIT ;
lzma_action action = LZMA_RUN ;
lzma_ret ret ;
if ( compressionLevel < 0 ) compressionLevel = 0 ;
if ( compressionLevel > 9 ) compressionLevel = 9 ;
if ( plain_lzma ) {
lzma_options_lzma opt_lzma ;
2017-05-17 00:32:33 +00:00
if ( lzma_lzma_preset ( & opt_lzma , compressionLevel ) )
EXM_THROW ( 71 , " zstd: %s: lzma_lzma_preset error " , srcFileName ) ;
2017-03-14 01:11:07 +00:00
ret = lzma_alone_encoder ( & strm , & opt_lzma ) ; /* LZMA */
2017-05-17 00:32:33 +00:00
if ( ret ! = LZMA_OK )
EXM_THROW ( 71 , " zstd: %s: lzma_alone_encoder error %d " , srcFileName , ret ) ;
2017-03-14 01:11:07 +00:00
} else {
ret = lzma_easy_encoder ( & strm , compressionLevel , LZMA_CHECK_CRC64 ) ; /* XZ */
2017-05-17 00:32:33 +00:00
if ( ret ! = LZMA_OK )
EXM_THROW ( 71 , " zstd: %s: lzma_easy_encoder error %d " , srcFileName , ret ) ;
2017-03-14 01:11:07 +00:00
}
strm . next_in = 0 ;
strm . avail_in = 0 ;
2017-06-23 23:54:16 +00:00
strm . next_out = ( BYTE * ) ress - > dstBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_out = ress - > dstBufferSize ;
while ( 1 ) {
if ( strm . avail_in = = 0 ) {
size_t const inSize = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , ress - > srcFile ) ;
if ( inSize = = 0 ) action = LZMA_FINISH ;
inFileSize + = inSize ;
2017-06-23 23:54:16 +00:00
strm . next_in = ( BYTE const * ) ress - > srcBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_in = inSize ;
}
ret = lzma_code ( & strm , action ) ;
2017-05-17 00:32:33 +00:00
if ( ret ! = LZMA_OK & & ret ! = LZMA_STREAM_END )
EXM_THROW ( 72 , " zstd: %s: lzma_code encoding error %d " , srcFileName , ret ) ;
2017-03-14 01:11:07 +00:00
{ size_t const compBytes = ress - > dstBufferSize - strm . avail_out ;
if ( compBytes ) {
2017-05-17 00:32:33 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , compBytes , ress - > dstFile ) ! = compBytes )
EXM_THROW ( 73 , " Write error : cannot write to output file " ) ;
2017-03-14 01:11:07 +00:00
outFileSize + = compBytes ;
2017-06-23 23:54:16 +00:00
strm . next_out = ( BYTE * ) ress - > dstBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_out = ress - > dstBufferSize ;
2017-05-17 00:32:33 +00:00
} }
2017-10-18 18:41:52 +00:00
if ( srcFileSize = = UTIL_FILESIZE_UNKNOWN )
2017-05-17 00:32:33 +00:00
DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 )
else
DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 ) ;
2017-03-14 01:11:07 +00:00
if ( ret = = LZMA_STREAM_END ) break ;
}
lzma_end ( & strm ) ;
* readsize = inFileSize ;
return outFileSize ;
}
# endif
2017-04-24 23:48:25 +00:00
# ifdef ZSTD_LZ4COMPRESS
2017-10-17 05:19:29 +00:00
# if LZ4_VERSION_NUMBER <= 10600
# define LZ4F_blockLinked blockLinked
# define LZ4F_max64KB max64KB
# endif
2017-04-24 23:48:25 +00:00
static int FIO_LZ4_GetBlockSize_FromBlockId ( int id ) { return ( 1 < < ( 8 + ( 2 * id ) ) ) ; }
2018-09-19 21:49:13 +00:00
static unsigned long long
FIO_compressLz4Frame ( cRess_t * ress ,
const char * srcFileName , U64 const srcFileSize ,
int compressionLevel , U64 * readsize )
2017-04-24 23:48:25 +00:00
{
2017-10-17 05:19:29 +00:00
const size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId ( LZ4F_max64KB ) ;
2017-04-24 23:48:25 +00:00
unsigned long long inFileSize = 0 , outFileSize = 0 ;
LZ4F_preferences_t prefs ;
2017-04-25 18:00:54 +00:00
LZ4F_compressionContext_t ctx ;
2017-04-24 23:48:25 +00:00
LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext ( & ctx , LZ4F_VERSION ) ;
2017-05-17 00:32:33 +00:00
if ( LZ4F_isError ( errorCode ) )
EXM_THROW ( 31 , " zstd: failed to create lz4 compression context " ) ;
2017-04-24 23:48:25 +00:00
memset ( & prefs , 0 , sizeof ( prefs ) ) ;
2017-10-17 05:19:29 +00:00
assert ( blockSize < = ress - > srcBufferSize ) ;
2017-04-26 17:17:38 +00:00
2017-04-24 23:48:25 +00:00
prefs . autoFlush = 1 ;
prefs . compressionLevel = compressionLevel ;
2017-10-17 05:19:29 +00:00
prefs . frameInfo . blockMode = LZ4F_blockLinked ;
prefs . frameInfo . blockSizeID = LZ4F_max64KB ;
2017-04-25 18:00:54 +00:00
prefs . frameInfo . contentChecksumFlag = ( contentChecksum_t ) g_checksumFlag ;
# if LZ4_VERSION_NUMBER >= 10600
2017-10-17 23:14:25 +00:00
prefs . frameInfo . contentSize = ( srcFileSize = = UTIL_FILESIZE_UNKNOWN ) ? 0 : srcFileSize ;
2017-04-25 18:00:54 +00:00
# endif
2017-12-04 19:26:59 +00:00
assert ( LZ4F_compressBound ( blockSize , & prefs ) < = ress - > dstBufferSize ) ;
2017-04-24 23:48:25 +00:00
2017-10-17 05:19:29 +00:00
{
2017-04-24 23:48:25 +00:00
size_t readSize ;
size_t headerSize = LZ4F_compressBegin ( ctx , ress - > dstBuffer , ress - > dstBufferSize , & prefs ) ;
2017-05-17 00:32:33 +00:00
if ( LZ4F_isError ( headerSize ) )
EXM_THROW ( 33 , " File header generation failed : %s " ,
LZ4F_getErrorName ( headerSize ) ) ;
2017-10-17 23:14:25 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , headerSize , ress - > dstFile ) ! = headerSize )
EXM_THROW ( 34 , " Write error : cannot write header " ) ;
2017-04-24 23:48:25 +00:00
outFileSize + = headerSize ;
/* Read first block */
readSize = fread ( ress - > srcBuffer , ( size_t ) 1 , ( size_t ) blockSize , ress - > srcFile ) ;
inFileSize + = readSize ;
/* Main Loop */
while ( readSize > 0 ) {
size_t outSize ;
/* Compress Block */
outSize = LZ4F_compressUpdate ( ctx , ress - > dstBuffer , ress - > dstBufferSize , ress - > srcBuffer , readSize , NULL ) ;
2017-05-17 00:32:33 +00:00
if ( LZ4F_isError ( outSize ) )
EXM_THROW ( 35 , " zstd: %s: lz4 compression failed : %s " ,
srcFileName , LZ4F_getErrorName ( outSize ) ) ;
2017-04-24 23:48:25 +00:00
outFileSize + = outSize ;
2017-10-18 18:41:52 +00:00
if ( srcFileSize = = UTIL_FILESIZE_UNKNOWN )
2017-05-17 00:32:33 +00:00
DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 )
else
DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " ,
( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) ,
( double ) outFileSize / inFileSize * 100 ) ;
2017-04-24 23:48:25 +00:00
/* Write Block */
{ size_t const sizeCheck = fwrite ( ress - > dstBuffer , 1 , outSize , ress - > dstFile ) ;
if ( sizeCheck ! = outSize ) EXM_THROW ( 36 , " Write error : cannot write compressed block " ) ; }
/* Read next block */
readSize = fread ( ress - > srcBuffer , ( size_t ) 1 , ( size_t ) blockSize , ress - > srcFile ) ;
inFileSize + = readSize ;
}
if ( ferror ( ress - > srcFile ) ) EXM_THROW ( 37 , " Error reading %s " , srcFileName ) ;
/* End of Stream mark */
headerSize = LZ4F_compressEnd ( ctx , ress - > dstBuffer , ress - > dstBufferSize , NULL ) ;
2017-05-17 00:32:33 +00:00
if ( LZ4F_isError ( headerSize ) )
EXM_THROW ( 38 , " zstd: %s: lz4 end of file generation failed : %s " ,
srcFileName , LZ4F_getErrorName ( headerSize ) ) ;
2017-04-24 23:48:25 +00:00
{ size_t const sizeCheck = fwrite ( ress - > dstBuffer , 1 , headerSize , ress - > dstFile ) ;
if ( sizeCheck ! = headerSize ) EXM_THROW ( 39 , " Write error : cannot write end of stream " ) ; }
outFileSize + = headerSize ;
}
* readsize = inFileSize ;
LZ4F_freeCompressionContext ( ctx ) ;
return outFileSize ;
}
# endif
2017-03-14 01:11:07 +00:00
2018-02-02 22:24:56 +00:00
static unsigned long long
FIO_compressZstdFrame ( const cRess_t * ressPtr ,
const char * srcFileName , U64 fileSize ,
int compressionLevel , U64 * readsize )
2015-12-17 01:23:58 +00:00
{
2018-02-02 22:24:56 +00:00
cRess_t const ress = * ressPtr ;
2016-05-07 20:43:40 +00:00
FILE * const srcFile = ress . srcFile ;
FILE * const dstFile = ress . dstFile ;
2015-12-17 01:23:58 +00:00
U64 compressedfilesize = 0 ;
2017-12-14 21:00:20 +00:00
ZSTD_EndDirective directive = ZSTD_e_continue ;
2018-08-10 00:44:30 +00:00
2018-08-12 03:48:06 +00:00
/* stats */
2018-09-19 22:09:45 +00:00
ZSTD_frameProgression previous_zfp_update = { 0 , 0 , 0 , 0 , 0 , 0 } ;
ZSTD_frameProgression previous_zfp_correction = { 0 , 0 , 0 , 0 , 0 , 0 } ;
2018-08-10 00:44:30 +00:00
typedef enum { noChange , slower , faster } speedChange_e ;
speedChange_e speedChange = noChange ;
2018-08-18 01:11:54 +00:00
unsigned flushWaiting = 0 ;
2018-08-12 03:48:06 +00:00
unsigned inputPresented = 0 ;
2018-08-09 22:51:30 +00:00
unsigned inputBlocked = 0 ;
unsigned lastJobID = 0 ;
2018-02-02 22:24:56 +00:00
DISPLAYLEVEL ( 6 , " compression using zstd format \n " ) ;
2017-02-08 15:54:23 +00:00
2015-12-17 01:23:58 +00:00
/* init */
2018-06-14 23:24:18 +00:00
if ( fileSize ! = UTIL_FILESIZE_UNKNOWN ) {
CHECK ( ZSTD_CCtx_setPledgedSrcSize ( ress . cctx , fileSize ) ) ;
}
2018-09-19 22:09:45 +00:00
( void ) srcFileName ;
2015-12-17 01:23:58 +00:00
/* Main compression loop */
2017-12-14 21:00:20 +00:00
do {
2018-08-09 22:51:30 +00:00
size_t stillToFlush ;
2015-12-17 01:23:58 +00:00
/* Fill input Buffer */
2016-03-26 19:52:14 +00:00
size_t const inSize = fread ( ress . srcBuffer , ( size_t ) 1 , ress . srcBufferSize , srcFile ) ;
2017-05-18 01:36:15 +00:00
ZSTD_inBuffer inBuff = { ress . srcBuffer , inSize , 0 } ;
2018-01-19 18:01:40 +00:00
DISPLAYLEVEL ( 6 , " fread %u bytes from source \n " , ( U32 ) inSize ) ;
2018-02-02 22:24:56 +00:00
* readsize + = inSize ;
2015-12-17 01:23:58 +00:00
2018-02-02 22:24:56 +00:00
if ( ( inSize = = 0 ) | | ( * readsize = = fileSize ) )
2017-12-14 21:00:20 +00:00
directive = ZSTD_e_end ;
2018-08-09 22:51:30 +00:00
stillToFlush = 1 ;
2018-08-09 22:16:31 +00:00
while ( ( inBuff . pos ! = inBuff . size ) /* input buffer must be entirely ingested */
2018-08-09 22:51:30 +00:00
| | ( directive = = ZSTD_e_end & & stillToFlush ! = 0 ) ) {
2018-08-10 00:44:30 +00:00
2018-08-09 22:51:30 +00:00
size_t const oldIPos = inBuff . pos ;
2017-05-18 01:36:15 +00:00
ZSTD_outBuffer outBuff = { ress . dstBuffer , ress . dstBufferSize , 0 } ;
2018-08-18 01:11:54 +00:00
size_t const toFlushNow = ZSTD_toFlushNow ( ress . cctx ) ;
2018-08-09 22:51:30 +00:00
CHECK_V ( stillToFlush , ZSTD_compress_generic ( ress . cctx , & outBuff , & inBuff , directive ) ) ;
/* count stats */
2018-08-12 03:48:06 +00:00
inputPresented + + ;
2018-09-19 21:49:13 +00:00
if ( oldIPos = = inBuff . pos ) inputBlocked + + ; /* input buffer is full and can't take any more : input speed is faster than consumption rate */
2018-08-18 01:11:54 +00:00
if ( ! toFlushNow ) flushWaiting = 1 ;
2017-05-18 01:36:15 +00:00
/* Write compressed stream */
2018-08-09 22:51:30 +00:00
DISPLAYLEVEL ( 6 , " ZSTD_compress_generic(end:%u) => input pos(%u)<=(%u)size ; output generated %u bytes \n " ,
2018-01-19 18:01:40 +00:00
( U32 ) directive , ( U32 ) inBuff . pos , ( U32 ) inBuff . size , ( U32 ) outBuff . pos ) ;
2017-05-18 01:36:15 +00:00
if ( outBuff . pos ) {
size_t const sizeCheck = fwrite ( ress . dstBuffer , 1 , outBuff . pos , dstFile ) ;
2018-09-19 21:49:13 +00:00
if ( sizeCheck ! = outBuff . pos )
2018-02-02 22:24:56 +00:00
EXM_THROW ( 25 , " Write error : cannot write compressed block " ) ;
2017-05-18 01:36:15 +00:00
compressedfilesize + = outBuff . pos ;
2017-12-14 21:00:20 +00:00
}
2018-08-10 00:44:30 +00:00
/* display notification; and adapt compression level */
2018-01-19 18:01:40 +00:00
if ( READY_FOR_UPDATE ( ) ) {
ZSTD_frameProgression const zfp = ZSTD_getFrameProgression ( ress . cctx ) ;
2018-03-23 00:49:46 +00:00
double const cShare = ( double ) zfp . produced / ( zfp . consumed + ! zfp . consumed /*avoid div0*/ ) * 100 ;
2018-08-09 22:51:30 +00:00
2018-09-19 22:09:45 +00:00
/* display progress notifications */
if ( g_displayLevel > = 3 ) {
DISPLAYUPDATE ( 3 , " \r (L%i) Buffered :%4u MB - Consumed :%4u MB - Compressed :%4u MB => %.2f%% " ,
compressionLevel ,
( U32 ) ( ( zfp . ingested - zfp . consumed ) > > 20 ) ,
( U32 ) ( zfp . consumed > > 20 ) ,
( U32 ) ( zfp . produced > > 20 ) ,
cShare ) ;
} else { /* summarized notifications if == 2; */
DISPLAYLEVEL ( 2 , " \r Read : %u " , ( U32 ) ( zfp . consumed > > 20 ) ) ;
if ( fileSize ! = UTIL_FILESIZE_UNKNOWN )
DISPLAYLEVEL ( 2 , " / %u " , ( U32 ) ( fileSize > > 20 ) ) ;
DISPLAYLEVEL ( 2 , " MB ==> %2.f%% " , cShare ) ;
DELAY_NEXT_UPDATE ( ) ;
}
2018-08-10 00:44:30 +00:00
2018-09-19 22:09:45 +00:00
/* adaptive mode : statistics measurement and speed correction */
if ( g_adaptiveMode ) {
2018-09-19 21:49:13 +00:00
2018-09-19 22:09:45 +00:00
/* check output speed */
if ( zfp . currentJobID > 1 ) { /* only possible if nbWorkers >= 1 */
2018-08-10 00:44:30 +00:00
2018-09-19 22:09:45 +00:00
unsigned long long newlyProduced = zfp . produced - previous_zfp_update . produced ;
unsigned long long newlyFlushed = zfp . flushed - previous_zfp_update . flushed ;
assert ( zfp . produced > = previous_zfp_update . produced ) ;
assert ( g_nbWorkers > = 1 ) ;
2018-08-10 00:44:30 +00:00
2018-09-21 22:37:30 +00:00
/* test if output speed is so slow that all buffers are full
* and no further progress is possible
* ( neither compression nor adding more input into internal buffers ) */
2018-09-19 22:09:45 +00:00
if ( ( zfp . ingested = = previous_zfp_update . ingested ) /* no data read : input buffer full */
& & ( zfp . consumed = = previous_zfp_update . consumed ) /* no data compressed : no more buffer to compress OR compression is really slow */
& & ( zfp . nbActiveWorkers = = 0 ) /* confirmed : no compression : either no more buffer to compress OR not enough data to start first worker */
) {
DISPLAYLEVEL ( 6 , " all buffers full : compression stopped => slow down \n " )
speedChange = slower ;
}
previous_zfp_update = zfp ;
if ( ( newlyProduced > ( newlyFlushed * 9 / 8 ) ) /* compression produces more data than output can flush (though production can be spiky, due to work unit : (N==4)*block sizes) */
& & ( flushWaiting = = 0 ) /* flush speed was never slowed by lack of production, so it's operating at max capacity */
) {
DISPLAYLEVEL ( 6 , " compression faster than flush (%llu > %llu), and flushed was never slowed down by lack of production => slow down \n " , newlyProduced , newlyFlushed ) ;
2018-08-10 00:44:30 +00:00
speedChange = slower ;
}
2018-09-19 22:09:45 +00:00
flushWaiting = 0 ;
2018-08-10 00:44:30 +00:00
}
2018-09-19 22:09:45 +00:00
/* course correct only if there is at least one new job completed */
if ( zfp . currentJobID > lastJobID ) {
DISPLAYLEVEL ( 6 , " compression level adaptation check \n " )
/* check input speed */
if ( zfp . currentJobID > g_nbWorkers + 1 ) { /* warm up period, to fill all workers */
if ( inputBlocked < = 0 ) {
DISPLAYLEVEL ( 6 , " input is never blocked => input is slower than ingestion \n " ) ;
speedChange = slower ;
} else if ( speedChange = = noChange ) {
unsigned long long newlyIngested = zfp . ingested - previous_zfp_correction . ingested ;
unsigned long long newlyConsumed = zfp . consumed - previous_zfp_correction . consumed ;
unsigned long long newlyProduced = zfp . produced - previous_zfp_correction . produced ;
unsigned long long newlyFlushed = zfp . flushed - previous_zfp_correction . flushed ;
previous_zfp_correction = zfp ;
assert ( inputPresented > 0 ) ;
DISPLAYLEVEL ( 6 , " input blocked %u/%u(%.2f) - ingested:%u vs %u:consumed - flushed:%u vs %u:produced \n " ,
inputBlocked , inputPresented , ( double ) inputBlocked / inputPresented * 100 ,
( U32 ) newlyIngested , ( U32 ) newlyConsumed ,
( U32 ) newlyFlushed , ( U32 ) newlyProduced ) ;
if ( ( inputBlocked > inputPresented / 8 ) /* input is waiting often, because input buffers is full : compression or output too slow */
& & ( newlyFlushed * 33 / 32 > newlyProduced ) /* flush everything that is produced */
& & ( newlyIngested * 33 / 32 > newlyConsumed ) /* input speed as fast or faster than compression speed */
) {
DISPLAYLEVEL ( 6 , " recommend faster as in(%llu) >= (%llu)comp(%llu) <= out(%llu) \n " ,
newlyIngested , newlyConsumed , newlyProduced , newlyFlushed ) ;
speedChange = faster ;
}
}
inputBlocked = 0 ;
inputPresented = 0 ;
}
2018-08-12 03:48:06 +00:00
if ( speedChange = = slower ) {
DISPLAYLEVEL ( 6 , " slower speed , higher compression \n " )
compressionLevel + + ;
compressionLevel + = ( compressionLevel = = 0 ) ; /* skip 0 */
2018-08-17 23:01:56 +00:00
if ( compressionLevel > ZSTD_maxCLevel ( ) ) compressionLevel = ZSTD_maxCLevel ( ) ;
2018-08-12 03:48:06 +00:00
ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_compressionLevel , ( unsigned ) compressionLevel ) ;
}
if ( speedChange = = faster ) {
2018-08-17 23:01:56 +00:00
DISPLAYLEVEL ( 6 , " faster speed , lighter compression \n " )
2018-08-12 03:48:06 +00:00
compressionLevel - - ;
compressionLevel - = ( compressionLevel = = 0 ) ; /* skip 0 */
ZSTD_CCtx_setParameter ( ress . cctx , ZSTD_p_compressionLevel , ( unsigned ) compressionLevel ) ;
}
2018-08-10 00:44:30 +00:00
speedChange = noChange ;
2018-08-09 22:51:30 +00:00
2018-09-19 22:09:45 +00:00
lastJobID = zfp . currentJobID ;
} /* if (zfp.currentJobID > lastJobID) */
} /* if (g_adaptiveMode) */
} /* if (READY_FOR_UPDATE()) */
} /* while ((inBuff.pos != inBuff.size) */
2017-12-14 21:00:20 +00:00
} while ( directive ! = ZSTD_e_end ) ;
2015-12-17 01:23:58 +00:00
2018-07-17 21:57:27 +00:00
if ( ferror ( srcFile ) ) {
EXM_THROW ( 26 , " Read error : I/O error " ) ;
}
if ( fileSize ! = UTIL_FILESIZE_UNKNOWN & & * readsize ! = fileSize ) {
EXM_THROW ( 27 , " Read error : Incomplete read : %llu / %llu B " ,
( unsigned long long ) * readsize , ( unsigned long long ) fileSize ) ;
}
2018-02-02 22:24:56 +00:00
return compressedfilesize ;
}
/*! FIO_compressFilename_internal() :
* same as FIO_compressFilename_extRess ( ) , with ` ress . desFile ` already opened .
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
*/
static int
FIO_compressFilename_internal ( cRess_t ress ,
const char * dstFileName , const char * srcFileName ,
int compressionLevel )
{
U64 readsize = 0 ;
U64 compressedfilesize = 0 ;
U64 const fileSize = UTIL_getFileSize ( srcFileName ) ;
DISPLAYLEVEL ( 5 , " %s: %u bytes \n " , srcFileName , ( U32 ) fileSize ) ;
/* compression format selection */
switch ( g_compressionType ) {
default :
case FIO_zstdCompression :
compressedfilesize = FIO_compressZstdFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
break ;
case FIO_gzipCompression :
# ifdef ZSTD_GZCOMPRESS
compressedfilesize = FIO_compressGzFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
# else
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n " ,
srcFileName ) ;
# endif
break ;
case FIO_xzCompression :
case FIO_lzmaCompression :
# ifdef ZSTD_LZMACOMPRESS
compressedfilesize = FIO_compressLzmaFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize , g_compressionType = = FIO_lzmaCompression ) ;
# else
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n " ,
srcFileName ) ;
# endif
break ;
case FIO_lz4Compression :
# ifdef ZSTD_LZ4COMPRESS
compressedfilesize = FIO_compressLz4Frame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
# else
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n " ,
srcFileName ) ;
# endif
break ;
}
2015-12-17 01:23:58 +00:00
/* Status */
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2018-02-02 22:24:56 +00:00
DISPLAYLEVEL ( 2 , " %-20s :%6.2f%% (%6llu => %6llu bytes, %s) \n " ,
srcFileName ,
2018-01-13 21:18:57 +00:00
( double ) compressedfilesize / ( readsize + ( ! readsize ) /*avoid div by zero*/ ) * 100 ,
2016-07-13 17:30:40 +00:00
( unsigned long long ) readsize , ( unsigned long long ) compressedfilesize ,
dstFileName ) ;
2015-12-17 01:23:58 +00:00
return 0 ;
}
2016-07-01 23:05:31 +00:00
/*! FIO_compressFilename_srcFile() :
* note : ress . destFile already opened
2016-02-15 19:37:23 +00:00
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
*/
static int FIO_compressFilename_srcFile ( cRess_t ress ,
2017-05-17 00:32:33 +00:00
const char * dstFileName , const char * srcFileName ,
int compressionLevel )
2016-02-15 19:37:23 +00:00
{
int result ;
/* File check */
2016-06-09 20:59:51 +00:00
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
2017-01-25 12:02:33 +00:00
2016-02-15 19:37:23 +00:00
ress . srcFile = FIO_openSrcFile ( srcFileName ) ;
if ( ! ress . srcFile ) return 1 ; /* srcFile could not be opened */
2017-02-08 15:54:23 +00:00
result = FIO_compressFilename_internal ( ress , dstFileName , srcFileName , compressionLevel ) ;
2016-02-15 19:37:23 +00:00
fclose ( ress . srcFile ) ;
2017-02-27 23:57:50 +00:00
if ( g_removeSrcFile /* --rm */ & & ! result & & strcmp ( srcFileName , stdinmark ) ) {
2017-11-18 00:38:56 +00:00
/* We must clear the handler, since after this point calling it would
* delete both the source and destination files .
*/
clearHandler ( ) ;
2018-01-05 19:44:45 +00:00
if ( FIO_remove ( srcFileName ) )
2017-02-27 23:57:50 +00:00
EXM_THROW ( 1 , " zstd: %s: %s " , srcFileName , strerror ( errno ) ) ;
}
2016-02-15 19:37:23 +00:00
return result ;
}
2016-06-09 20:59:51 +00:00
/*! FIO_compressFilename_dstFile() :
2016-02-12 14:56:46 +00:00
* @ return : 0 : compression completed correctly ,
2016-06-09 20:59:51 +00:00
* 1 : pb
2016-02-12 14:56:46 +00:00
*/
2016-06-09 20:59:51 +00:00
static int FIO_compressFilename_dstFile ( cRess_t ress ,
2017-05-17 00:32:33 +00:00
const char * dstFileName ,
const char * srcFileName ,
int compressionLevel )
2016-02-12 14:56:46 +00:00
{
int result ;
2016-11-02 13:08:07 +00:00
stat_t statbuf ;
int stat_result = 0 ;
2016-02-12 14:56:46 +00:00
2018-03-12 02:56:48 +00:00
DISPLAYLEVEL ( 6 , " FIO_compressFilename_dstFile: opening dst: %s " , dstFileName ) ;
2016-02-12 14:56:46 +00:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
2016-09-15 13:38:44 +00:00
if ( ress . dstFile = = NULL ) return 1 ; /* could not open dstFileName */
2017-11-18 00:38:56 +00:00
/* Must ony be added after FIO_openDstFile() succeeds.
* Otherwise we may delete the destination file if at already exists , and
* the user presses Ctrl - C when asked if they wish to overwrite .
*/
addHandler ( dstFileName ) ;
2017-10-01 19:10:26 +00:00
2017-05-17 00:32:33 +00:00
if ( strcmp ( srcFileName , stdinmark ) & & UTIL_getFileStat ( srcFileName , & statbuf ) )
stat_result = 1 ;
2017-02-08 15:54:23 +00:00
result = FIO_compressFilename_srcFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2017-11-18 00:38:56 +00:00
clearHandler ( ) ;
2016-03-14 05:24:46 +00:00
2017-05-17 00:32:33 +00:00
if ( fclose ( ress . dstFile ) ) { /* error closing dstFile */
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ;
result = 1 ;
}
2018-01-05 19:49:55 +00:00
if ( ( result ! = 0 ) /* operation failure */
& & strcmp ( dstFileName , nulmark ) /* special case : don't remove() /dev/null */
& & strcmp ( dstFileName , stdoutmark ) ) /* special case : don't remove() stdout */
FIO_remove ( dstFileName ) ; /* remove compression artefact; note don't do anything special if remove() fails */
2018-01-05 19:44:45 +00:00
else if ( strcmp ( dstFileName , stdoutmark )
& & strcmp ( dstFileName , nulmark )
& & stat_result )
2017-05-17 00:32:33 +00:00
UTIL_setFileStat ( dstFileName , & statbuf ) ;
2017-10-01 19:10:26 +00:00
2016-02-12 14:56:46 +00:00
return result ;
}
2015-12-17 13:09:55 +00:00
int FIO_compressFilename ( const char * dstFileName , const char * srcFileName ,
2018-08-13 20:02:03 +00:00
const char * dictFileName , int compressionLevel ,
ZSTD_compressionParameters comprParams )
2015-01-24 00:58:16 +00:00
{
2016-05-31 00:29:45 +00:00
clock_t const start = clock ( ) ;
2017-10-17 23:14:25 +00:00
U64 const fileSize = UTIL_getFileSize ( srcFileName ) ;
U64 const srcSize = ( fileSize = = UTIL_FILESIZE_UNKNOWN ) ? ZSTD_CONTENTSIZE_UNKNOWN : fileSize ;
2015-01-24 00:58:16 +00:00
2017-10-02 19:29:25 +00:00
cRess_t const ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , comprParams ) ;
2017-02-08 15:54:23 +00:00
int const result = FIO_compressFilename_dstFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2015-01-24 00:58:16 +00:00
2016-07-01 23:05:31 +00:00
double const seconds = ( double ) ( clock ( ) - start ) / CLOCKS_PER_SEC ;
DISPLAYLEVEL ( 4 , " Completed in %.2f sec \n " , seconds ) ;
FIO_freeCResources ( ress ) ;
return result ;
2015-01-24 00:58:16 +00:00
}
2017-06-20 19:43:10 +00:00
2015-12-17 13:09:55 +00:00
int FIO_compressMultipleFilenames ( const char * * inFileNamesTable , unsigned nbFiles ,
2017-12-13 02:32:50 +00:00
const char * outFileName , const char * suffix ,
2016-12-13 12:24:59 +00:00
const char * dictFileName , int compressionLevel ,
2018-08-13 20:02:03 +00:00
ZSTD_compressionParameters comprParams )
2015-12-17 01:23:58 +00:00
{
int missed_files = 0 ;
size_t dfnSize = FNSPACE ;
2016-07-13 17:30:40 +00:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2016-05-07 20:43:40 +00:00
size_t const suffixSize = suffix ? strlen ( suffix ) : 0 ;
2017-10-17 23:14:25 +00:00
U64 const firstFileSize = UTIL_getFileSize ( inFileNamesTable [ 0 ] ) ;
U64 const firstSrcSize = ( firstFileSize = = UTIL_FILESIZE_UNKNOWN ) ? ZSTD_CONTENTSIZE_UNKNOWN : firstFileSize ;
U64 const srcSize = ( nbFiles ! = 1 ) ? ZSTD_CONTENTSIZE_UNKNOWN : firstSrcSize ;
2017-10-02 19:29:25 +00:00
cRess_t ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , comprParams ) ;
2015-12-17 01:23:58 +00:00
/* init */
2017-05-17 00:32:33 +00:00
if ( dstFileName = = NULL )
EXM_THROW ( 27 , " FIO_compressMultipleFilenames : allocation error for dstFileName " ) ;
2017-12-13 02:32:50 +00:00
if ( outFileName = = NULL & & suffix = = NULL )
2017-05-17 00:32:33 +00:00
EXM_THROW ( 28 , " FIO_compressMultipleFilenames : dst unknown " ) ; /* should never happen */
2015-12-17 01:23:58 +00:00
/* loop on each file */
2017-12-13 02:32:50 +00:00
if ( outFileName ! = NULL ) {
2016-05-07 20:43:40 +00:00
unsigned u ;
2017-12-13 02:32:50 +00:00
ress . dstFile = FIO_openDstFile ( outFileName ) ;
2018-01-02 15:17:32 +00:00
if ( ress . dstFile = = NULL ) { /* could not open outFileName */
missed_files = nbFiles ;
} else {
for ( u = 0 ; u < nbFiles ; u + + )
missed_files + = FIO_compressFilename_srcFile ( ress , outFileName , inFileNamesTable [ u ] , compressionLevel ) ;
if ( fclose ( ress . dstFile ) )
EXM_THROW ( 29 , " Write error : cannot properly close stdout " ) ;
}
2016-02-15 19:37:23 +00:00
} else {
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-02-12 14:56:46 +00:00
for ( u = 0 ; u < nbFiles ; u + + ) {
2017-05-17 00:32:33 +00:00
size_t const ifnSize = strlen ( inFileNamesTable [ u ] ) ;
if ( dfnSize < = ifnSize + suffixSize + 1 ) { /* resize name buffer */
free ( dstFileName ) ;
dfnSize = ifnSize + 20 ;
dstFileName = ( char * ) malloc ( dfnSize ) ;
2017-10-14 08:21:43 +00:00
if ( ! dstFileName ) {
2017-05-17 00:32:33 +00:00
EXM_THROW ( 30 , " zstd: %s " , strerror ( errno ) ) ;
2017-10-14 08:21:43 +00:00
} }
2018-08-21 02:15:24 +00:00
strncpy ( dstFileName , inFileNamesTable [ u ] , ifnSize + 1 /* Include null */ ) ;
strncat ( dstFileName , suffix , suffixSize ) ;
2017-02-08 15:54:23 +00:00
missed_files + = FIO_compressFilename_dstFile ( ress , dstFileName , inFileNamesTable [ u ] , compressionLevel ) ;
2016-02-15 19:37:23 +00:00
} }
2015-12-17 01:23:58 +00:00
FIO_freeCResources ( ress ) ;
free ( dstFileName ) ;
return missed_files ;
}
2016-05-07 20:43:40 +00:00
# endif /* #ifndef ZSTD_NOCOMPRESS */
2016-04-22 11:59:05 +00:00
2015-12-17 01:23:58 +00:00
2016-04-22 16:22:30 +00:00
# ifndef ZSTD_NODECOMPRESS
2015-12-17 01:23:58 +00:00
/* **************************************************************************
2017-08-19 01:30:41 +00:00
* Decompression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-12-17 19:30:14 +00:00
typedef struct {
void * srcBuffer ;
size_t srcBufferSize ;
2017-09-18 20:41:54 +00:00
size_t srcBufferLoaded ;
2015-12-17 19:30:14 +00:00
void * dstBuffer ;
size_t dstBufferSize ;
2016-08-13 21:45:45 +00:00
ZSTD_DStream * dctx ;
2016-02-12 17:33:26 +00:00
FILE * dstFile ;
2015-12-17 19:30:14 +00:00
} dRess_t ;
static dRess_t FIO_createDResources ( const char * dictFileName )
{
dRess_t ress ;
2016-07-13 15:38:39 +00:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-17 19:30:14 +00:00
2016-07-13 15:38:39 +00:00
/* Allocation */
2016-08-13 21:45:45 +00:00
ress . dctx = ZSTD_createDStream ( ) ;
if ( ress . dctx = = NULL ) EXM_THROW ( 60 , " Can't create ZSTD_DStream " ) ;
2017-09-25 21:26:26 +00:00
CHECK ( ZSTD_setDStreamParameter ( ress . dctx , DStream_p_maxWindowSize , g_memLimit ) ) ;
2016-08-13 21:45:45 +00:00
ress . srcBufferSize = ZSTD_DStreamInSize ( ) ;
2015-12-17 19:30:14 +00:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 21:45:45 +00:00
ress . dstBufferSize = ZSTD_DStreamOutSize ( ) ;
2015-12-17 19:30:14 +00:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
2017-05-17 00:32:33 +00:00
if ( ! ress . srcBuffer | | ! ress . dstBuffer )
EXM_THROW ( 61 , " Allocation error : not enough memory " ) ;
2015-12-17 01:23:58 +00:00
2015-12-17 19:30:14 +00:00
/* dictionary */
2016-09-14 15:26:59 +00:00
{ void * dictBuffer ;
2017-04-11 21:41:02 +00:00
size_t const dictBufferSize = FIO_createDictBuffer ( & dictBuffer , dictFileName ) ;
2017-05-18 01:36:15 +00:00
CHECK ( ZSTD_initDStream_usingDict ( ress . dctx , dictBuffer , dictBufferSize ) ) ;
2016-09-14 15:26:59 +00:00
free ( dictBuffer ) ;
}
2015-12-17 19:30:14 +00:00
return ress ;
}
static void FIO_freeDResources ( dRess_t ress )
{
2017-05-18 01:36:15 +00:00
CHECK ( ZSTD_freeDStream ( ress . dctx ) ) ;
2015-12-17 19:30:14 +00:00
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
}
2016-05-23 14:56:56 +00:00
/** FIO_fwriteSparse() :
* @ return : storedSkips , to be provided to next call to FIO_fwriteSparse ( ) of LZ4IO_fwriteSparseEnd ( ) */
static unsigned FIO_fwriteSparse ( FILE * file , const void * buffer , size_t bufferSize , unsigned storedSkips )
{
const size_t * const bufferT = ( const size_t * ) buffer ; /* Buffer is supposed malloc'ed, hence aligned on size_t */
size_t bufferSizeT = bufferSize / sizeof ( size_t ) ;
const size_t * const bufferTEnd = bufferT + bufferSizeT ;
const size_t * ptrT = bufferT ;
static const size_t segmentSizeT = ( 32 KB ) / sizeof ( size_t ) ; /* 0-test re-attempted every 32 KB */
if ( ! g_sparseFileSupport ) { /* normal write */
size_t const sizeCheck = fwrite ( buffer , 1 , bufferSize , file ) ;
if ( sizeCheck ! = bufferSize ) EXM_THROW ( 70 , " Write error : cannot write decoded block " ) ;
return 0 ;
}
/* avoid int overflow */
if ( storedSkips > 1 GB ) {
2017-02-12 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , 1 GB , SEEK_CUR ) ;
2016-05-23 14:56:56 +00:00
if ( seekResult ! = 0 ) EXM_THROW ( 71 , " 1 GB skip error (sparse file support) " ) ;
storedSkips - = 1 GB ;
}
while ( ptrT < bufferTEnd ) {
size_t seg0SizeT = segmentSizeT ;
size_t nb0T ;
/* count leading zeros */
if ( seg0SizeT > bufferSizeT ) seg0SizeT = bufferSizeT ;
bufferSizeT - = seg0SizeT ;
for ( nb0T = 0 ; ( nb0T < seg0SizeT ) & & ( ptrT [ nb0T ] = = 0 ) ; nb0T + + ) ;
storedSkips + = ( unsigned ) ( nb0T * sizeof ( size_t ) ) ;
if ( nb0T ! = seg0SizeT ) { /* not all 0s */
2017-02-12 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 14:56:56 +00:00
if ( seekResult ) EXM_THROW ( 72 , " Sparse skip error ; try --no-sparse " ) ;
storedSkips = 0 ;
seg0SizeT - = nb0T ;
ptrT + = nb0T ;
{ size_t const sizeCheck = fwrite ( ptrT , sizeof ( size_t ) , seg0SizeT , file ) ;
2017-05-17 00:32:33 +00:00
if ( sizeCheck ! = seg0SizeT )
EXM_THROW ( 73 , " Write error : cannot write decoded block " ) ;
2016-05-23 14:56:56 +00:00
} }
ptrT + = seg0SizeT ;
}
{ static size_t const maskT = sizeof ( size_t ) - 1 ;
2017-05-17 00:32:33 +00:00
if ( bufferSize & maskT ) {
/* size not multiple of sizeof(size_t) : implies end of block */
2016-05-23 14:56:56 +00:00
const char * const restStart = ( const char * ) bufferTEnd ;
const char * restPtr = restStart ;
size_t restSize = bufferSize & maskT ;
const char * const restEnd = restStart + restSize ;
for ( ; ( restPtr < restEnd ) & & ( * restPtr = = 0 ) ; restPtr + + ) ;
storedSkips + = ( unsigned ) ( restPtr - restStart ) ;
if ( restPtr ! = restEnd ) {
2017-02-12 09:27:18 +00:00
int seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2017-05-17 00:32:33 +00:00
if ( seekResult )
EXM_THROW ( 74 , " Sparse skip error ; try --no-sparse " ) ;
2016-05-23 14:56:56 +00:00
storedSkips = 0 ;
{ size_t const sizeCheck = fwrite ( restPtr , 1 , restEnd - restPtr , file ) ;
2017-05-17 00:32:33 +00:00
if ( sizeCheck ! = ( size_t ) ( restEnd - restPtr ) )
EXM_THROW ( 75 , " Write error : cannot write decoded end of block " ) ;
2016-05-23 14:56:56 +00:00
} } } }
return storedSkips ;
}
static void FIO_fwriteSparseEnd ( FILE * file , unsigned storedSkips )
{
if ( storedSkips - - > 0 ) { /* implies g_sparseFileSupport>0 */
2017-02-12 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2017-03-14 01:11:07 +00:00
if ( seekResult ! = 0 ) EXM_THROW ( 69 , " Final skip error (sparse file) " ) ;
2016-05-23 14:56:56 +00:00
{ const char lastZeroByte [ 1 ] = { 0 } ;
size_t const sizeCheck = fwrite ( lastZeroByte , 1 , 1 , file ) ;
2017-05-17 00:32:33 +00:00
if ( sizeCheck ! = 1 )
EXM_THROW ( 69 , " Write error : cannot write last zero " ) ;
2016-05-23 14:56:56 +00:00
} }
}
2016-12-05 16:39:38 +00:00
/** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode
@ return : 0 ( no error ) */
2016-12-05 17:31:14 +00:00
static unsigned FIO_passThrough ( FILE * foutput , FILE * finput , void * buffer , size_t bufferSize , size_t alreadyLoaded )
2016-12-05 16:39:38 +00:00
{
size_t const blockSize = MIN ( 64 KB , bufferSize ) ;
size_t readFromInput = 1 ;
unsigned storedSkips = 0 ;
2016-12-05 17:31:14 +00:00
/* assumption : ress->srcBufferLoaded bytes already loaded and stored within buffer */
2017-07-03 20:24:50 +00:00
{ size_t const sizeCheck = fwrite ( buffer , 1 , alreadyLoaded , foutput ) ;
if ( sizeCheck ! = alreadyLoaded ) {
DISPLAYLEVEL ( 1 , " Pass-through write error \n " ) ;
return 1 ;
} }
2016-12-05 16:39:38 +00:00
while ( readFromInput ) {
readFromInput = fread ( buffer , 1 , blockSize , finput ) ;
storedSkips = FIO_fwriteSparse ( foutput , buffer , readFromInput , storedSkips ) ;
}
FIO_fwriteSparseEnd ( foutput , storedSkips ) ;
return 0 ;
}
2018-02-02 00:13:04 +00:00
/* FIO_highbit64() :
* gives position of highest bit .
* note : only works for v > 0 !
*/
static unsigned FIO_highbit64 ( unsigned long long v )
{
unsigned count = 0 ;
assert ( v ! = 0 ) ;
v > > = 1 ;
while ( v ) { v > > = 1 ; count + + ; }
return count ;
}
/* FIO_zstdErrorHelp() :
* detailed error message when requested window size is too large */
static void FIO_zstdErrorHelp ( dRess_t * ress , size_t err , char const * srcFileName )
2017-09-22 21:04:39 +00:00
{
ZSTD_frameHeader header ;
2018-02-02 00:13:04 +00:00
/* Help message only for one specific error */
if ( ZSTD_getErrorCode ( err ) ! = ZSTD_error_frameParameter_windowTooLarge )
2017-09-22 21:04:39 +00:00
return ;
2018-02-02 00:13:04 +00:00
2017-09-22 21:04:39 +00:00
/* Try to decode the frame header */
2018-02-02 00:13:04 +00:00
err = ZSTD_getFrameHeader ( & header , ress - > srcBuffer , ress - > srcBufferLoaded ) ;
if ( err = = 0 ) {
2018-02-02 04:16:00 +00:00
unsigned long long const windowSize = header . windowSize ;
2018-02-02 00:13:04 +00:00
U32 const windowLog = FIO_highbit64 ( windowSize ) + ( ( windowSize & ( windowSize - 1 ) ) ! = 0 ) ;
U32 const windowMB = ( U32 ) ( ( windowSize > > 20 ) + ( ( windowSize & ( ( 1 MB ) - 1 ) ) ! = 0 ) ) ;
assert ( windowSize < ( U64 ) ( 1ULL < < 52 ) ) ;
2017-09-22 21:04:39 +00:00
assert ( g_memLimit > 0 ) ;
DISPLAYLEVEL ( 1 , " %s : Window size larger than maximum : %llu > %u \n " ,
2018-02-02 00:13:04 +00:00
srcFileName , windowSize , g_memLimit ) ;
2017-09-22 21:04:39 +00:00
if ( windowLog < = ZSTD_WINDOWLOG_MAX ) {
DISPLAYLEVEL ( 1 , " %s : Use --long=%u or --memory=%uMB \n " ,
srcFileName , windowLog , windowMB ) ;
return ;
}
}
2018-02-02 00:13:04 +00:00
DISPLAYLEVEL ( 1 , " %s : Window log larger than ZSTD_WINDOWLOG_MAX=%u; not supported \n " ,
2017-09-22 21:04:39 +00:00
srcFileName , ZSTD_WINDOWLOG_MAX ) ;
}
2016-12-05 16:39:38 +00:00
2016-03-15 11:56:03 +00:00
/** FIO_decompressFrame() :
2017-07-03 17:27:16 +00:00
* @ return : size of decoded zstd frame , or an error code
2016-03-15 11:56:03 +00:00
*/
2017-07-03 17:27:16 +00:00
# define FIO_ERROR_FRAME_DECODING ((unsigned long long)(-2))
unsigned long long FIO_decompressZstdFrame ( dRess_t * ress ,
2016-12-05 16:39:38 +00:00
FILE * finput ,
2017-05-06 02:15:24 +00:00
const char * srcFileName ,
2016-11-07 22:41:21 +00:00
U64 alreadyDecoded )
2015-01-24 00:58:16 +00:00
{
2016-08-28 19:47:17 +00:00
U64 frameSize = 0 ;
2016-05-23 14:56:56 +00:00
U32 storedSkips = 0 ;
2015-01-24 00:58:16 +00:00
2017-09-29 22:54:09 +00:00
size_t const srcFileLength = strlen ( srcFileName ) ;
if ( srcFileLength > 20 ) srcFileName + = srcFileLength - 20 ; /* display last 20 characters only */
2016-12-05 16:39:38 +00:00
ZSTD_resetDStream ( ress - > dctx ) ;
2016-03-15 11:56:03 +00:00
2017-09-22 21:04:39 +00:00
/* Header loading : ensures ZSTD_getFrameHeader() will succeed */
2017-09-29 22:54:09 +00:00
{ size_t const toDecode = ZSTD_FRAMEHEADERSIZE_MAX ;
if ( ress - > srcBufferLoaded < toDecode ) {
size_t const toRead = toDecode - ress - > srcBufferLoaded ;
void * const startPosition = ( char * ) ress - > srcBuffer + ress - > srcBufferLoaded ;
ress - > srcBufferLoaded + = fread ( startPosition , 1 , toRead , finput ) ;
} }
2016-03-15 11:56:03 +00:00
/* Main decompression Loop */
2016-02-02 13:36:49 +00:00
while ( 1 ) {
2016-12-05 16:39:38 +00:00
ZSTD_inBuffer inBuff = { ress - > srcBuffer , ress - > srcBufferLoaded , 0 } ;
ZSTD_outBuffer outBuff = { ress - > dstBuffer , ress - > dstBufferSize , 0 } ;
size_t const readSizeHint = ZSTD_decompressStream ( ress - > dctx , & outBuff , & inBuff ) ;
2017-05-06 02:15:24 +00:00
if ( ZSTD_isError ( readSizeHint ) ) {
DISPLAYLEVEL ( 1 , " %s : Decoding error (36) : %s \n " ,
srcFileName , ZSTD_getErrorName ( readSizeHint ) ) ;
2017-09-22 21:04:39 +00:00
FIO_zstdErrorHelp ( ress , readSizeHint , srcFileName ) ;
2017-07-03 17:27:16 +00:00
return FIO_ERROR_FRAME_DECODING ;
2017-05-06 02:15:24 +00:00
}
2015-11-25 13:42:45 +00:00
/* Write block */
2017-01-20 00:59:56 +00:00
storedSkips = FIO_fwriteSparse ( ress - > dstFile , ress - > dstBuffer , outBuff . pos , storedSkips ) ;
2016-08-16 23:39:22 +00:00
frameSize + = outBuff . pos ;
2017-05-06 02:15:24 +00:00
DISPLAYUPDATE ( 2 , " \r %-20.20s : %u MB... " ,
srcFileName , ( U32 ) ( ( alreadyDecoded + frameSize ) > > 20 ) ) ;
2015-11-25 13:42:45 +00:00
2016-12-05 16:39:38 +00:00
if ( inBuff . pos > 0 ) {
memmove ( ress - > srcBuffer , ( char * ) ress - > srcBuffer + inBuff . pos , inBuff . size - inBuff . pos ) ;
ress - > srcBufferLoaded - = inBuff . pos ;
}
2016-09-07 12:54:23 +00:00
if ( readSizeHint = = 0 ) break ; /* end of frame */
2017-05-06 02:15:24 +00:00
if ( inBuff . size ! = inBuff . pos ) {
DISPLAYLEVEL ( 1 , " %s : Decoding error (37) : should consume entire input \n " ,
srcFileName ) ;
2017-07-03 17:27:16 +00:00
return FIO_ERROR_FRAME_DECODING ;
2017-05-06 02:15:24 +00:00
}
2015-01-24 00:58:16 +00:00
/* Fill input buffer */
2017-09-29 22:54:09 +00:00
{ size_t const toDecode = MIN ( readSizeHint , ress - > srcBufferSize ) ; /* support large skippable frames */
if ( ress - > srcBufferLoaded < toDecode ) {
size_t const toRead = toDecode - ress - > srcBufferLoaded ; /* > 0 */
void * const startPosition = ( char * ) ress - > srcBuffer + ress - > srcBufferLoaded ;
size_t const readSize = fread ( startPosition , 1 , toRead , finput ) ;
if ( readSize = = 0 ) {
DISPLAYLEVEL ( 1 , " %s : Read error (39) : premature end \n " ,
srcFileName ) ;
return FIO_ERROR_FRAME_DECODING ;
}
ress - > srcBufferLoaded + = readSize ;
2017-05-06 02:15:24 +00:00
} } }
2015-01-24 00:58:16 +00:00
2016-12-05 16:39:38 +00:00
FIO_fwriteSparseEnd ( ress - > dstFile , storedSkips ) ;
2016-05-23 14:56:56 +00:00
2015-11-25 13:42:45 +00:00
return frameSize ;
2015-09-10 22:26:09 +00:00
}
2016-12-01 10:56:31 +00:00
# ifdef ZSTD_GZDECOMPRESS
2017-05-17 00:32:33 +00:00
static unsigned long long FIO_decompressGzFrame ( dRess_t * ress ,
FILE * srcFile , const char * srcFileName )
2016-12-02 12:50:29 +00:00
{
2016-12-02 20:40:57 +00:00
unsigned long long outFileSize = 0 ;
2016-12-02 14:01:31 +00:00
z_stream strm ;
2017-03-14 01:11:07 +00:00
int flush = Z_NO_FLUSH ;
2017-07-03 20:24:50 +00:00
int decodingError = 0 ;
2016-12-02 20:40:57 +00:00
2016-12-02 14:01:31 +00:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
strm . next_in = 0 ;
2017-02-27 12:21:05 +00:00
strm . avail_in = 0 ;
2017-05-17 00:32:33 +00:00
/* see http://www.zlib.net/manual.html */
if ( inflateInit2 ( & strm , 15 /* maxWindowLogSize */ + 16 /* gzip only */ ) ! = Z_OK )
2017-07-03 20:24:50 +00:00
return FIO_ERROR_FRAME_DECODING ;
2016-12-02 20:40:57 +00:00
2017-02-03 16:43:06 +00:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-05 16:39:38 +00:00
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2016-12-01 10:56:31 +00:00
2016-12-02 14:01:31 +00:00
for ( ; ; ) {
2017-07-03 20:24:50 +00:00
int ret ;
2016-12-05 16:39:38 +00:00
if ( strm . avail_in = = 0 ) {
ress - > srcBufferLoaded = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , srcFile ) ;
2017-03-14 01:11:07 +00:00
if ( ress - > srcBufferLoaded = = 0 ) flush = Z_FINISH ;
2016-12-05 16:39:38 +00:00
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-02 12:11:39 +00:00
}
2017-03-14 01:11:07 +00:00
ret = inflate ( & strm , flush ) ;
2017-07-03 20:24:50 +00:00
if ( ret = = Z_BUF_ERROR ) {
DISPLAYLEVEL ( 1 , " zstd: %s: premature gz end \n " , srcFileName ) ;
decodingError = 1 ; break ;
}
2017-05-17 00:32:33 +00:00
if ( ret ! = Z_OK & & ret ! = Z_STREAM_END ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: inflate error %d \n " , srcFileName , ret ) ;
decodingError = 1 ; break ;
2017-05-17 00:32:33 +00:00
}
2016-12-05 16:39:38 +00:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
2016-12-02 20:40:57 +00:00
if ( decompBytes ) {
2017-07-03 20:24:50 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) {
DISPLAYLEVEL ( 1 , " zstd: %s \n " , strerror ( errno ) ) ;
decodingError = 1 ; break ;
}
2016-12-02 20:40:57 +00:00
outFileSize + = decompBytes ;
2017-02-03 16:43:06 +00:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
2016-12-05 16:39:38 +00:00
}
}
if ( ret = = Z_STREAM_END ) break ;
}
2016-12-01 10:56:31 +00:00
2017-07-03 22:14:55 +00:00
if ( strm . avail_in > 0 )
memmove ( ress - > srcBuffer , strm . next_in , strm . avail_in ) ;
2016-12-05 16:39:38 +00:00
ress - > srcBufferLoaded = strm . avail_in ;
2017-07-03 20:45:09 +00:00
if ( ( inflateEnd ( & strm ) ! = Z_OK ) /* release resources ; error detected */
& & ( decodingError = = 0 ) ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: inflateEnd error \n " , srcFileName ) ;
decodingError = 1 ;
}
return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize ;
2017-03-14 01:11:07 +00:00
}
# endif
# ifdef ZSTD_LZMADECOMPRESS
static unsigned long long FIO_decompressLzmaFrame ( dRess_t * ress , FILE * srcFile , const char * srcFileName , int plain_lzma )
{
unsigned long long outFileSize = 0 ;
lzma_stream strm = LZMA_STREAM_INIT ;
lzma_action action = LZMA_RUN ;
2017-07-03 17:27:16 +00:00
lzma_ret initRet ;
int decodingError = 0 ;
2017-03-14 01:11:07 +00:00
strm . next_in = 0 ;
strm . avail_in = 0 ;
if ( plain_lzma ) {
2017-07-03 17:27:16 +00:00
initRet = lzma_alone_decoder ( & strm , UINT64_MAX ) ; /* LZMA */
2017-03-14 01:11:07 +00:00
} else {
2017-07-03 17:27:16 +00:00
initRet = lzma_stream_decoder ( & strm , UINT64_MAX , 0 ) ; /* XZ */
2017-03-14 01:11:07 +00:00
}
2017-07-03 17:27:16 +00:00
if ( initRet ! = LZMA_OK ) {
DISPLAYLEVEL ( 1 , " zstd: %s: %s error %d \n " ,
plain_lzma ? " lzma_alone_decoder " : " lzma_stream_decoder " ,
srcFileName , initRet ) ;
return FIO_ERROR_FRAME_DECODING ;
}
2017-03-14 01:11:07 +00:00
2017-06-23 23:54:16 +00:00
strm . next_out = ( BYTE * ) ress - > dstBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_out = ress - > dstBufferSize ;
2017-06-23 23:54:16 +00:00
strm . next_in = ( BYTE const * ) ress - > srcBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_in = ress - > srcBufferLoaded ;
for ( ; ; ) {
2017-07-03 17:27:16 +00:00
lzma_ret ret ;
2017-03-14 01:11:07 +00:00
if ( strm . avail_in = = 0 ) {
ress - > srcBufferLoaded = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , srcFile ) ;
if ( ress - > srcBufferLoaded = = 0 ) action = LZMA_FINISH ;
2017-06-23 23:54:16 +00:00
strm . next_in = ( BYTE const * ) ress - > srcBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_in = ress - > srcBufferLoaded ;
}
ret = lzma_code ( & strm , action ) ;
2017-07-03 17:27:16 +00:00
if ( ret = = LZMA_BUF_ERROR ) {
DISPLAYLEVEL ( 1 , " zstd: %s: premature lzma end \n " , srcFileName ) ;
decodingError = 1 ; break ;
}
2017-05-17 00:32:33 +00:00
if ( ret ! = LZMA_OK & & ret ! = LZMA_STREAM_END ) {
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: lzma_code decoding error %d \n " ,
srcFileName , ret ) ;
decodingError = 1 ; break ;
2017-05-17 00:32:33 +00:00
}
2017-03-14 01:11:07 +00:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
2017-07-03 17:27:16 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) {
DISPLAYLEVEL ( 1 , " zstd: %s \n " , strerror ( errno ) ) ;
decodingError = 1 ; break ;
}
2017-03-14 01:11:07 +00:00
outFileSize + = decompBytes ;
2017-06-23 23:54:16 +00:00
strm . next_out = ( BYTE * ) ress - > dstBuffer ;
2017-03-14 01:11:07 +00:00
strm . avail_out = ress - > dstBufferSize ;
2017-05-17 00:32:33 +00:00
} }
2017-03-14 01:11:07 +00:00
if ( ret = = LZMA_STREAM_END ) break ;
}
2017-07-03 22:14:55 +00:00
if ( strm . avail_in > 0 )
memmove ( ress - > srcBuffer , strm . next_in , strm . avail_in ) ;
2017-03-14 01:11:07 +00:00
ress - > srcBufferLoaded = strm . avail_in ;
lzma_end ( & strm ) ;
2017-07-03 17:27:16 +00:00
return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize ;
2016-12-01 10:56:31 +00:00
}
# endif
2017-04-24 23:48:25 +00:00
# ifdef ZSTD_LZ4DECOMPRESS
2017-05-17 00:32:33 +00:00
static unsigned long long FIO_decompressLz4Frame ( dRess_t * ress ,
FILE * srcFile , const char * srcFileName )
2017-04-24 23:48:25 +00:00
{
unsigned long long filesize = 0 ;
LZ4F_errorCode_t nextToLoad ;
2017-04-25 18:00:54 +00:00
LZ4F_decompressionContext_t dCtx ;
2017-04-24 23:48:25 +00:00
LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext ( & dCtx , LZ4F_VERSION ) ;
2017-07-03 18:27:29 +00:00
int decodingError = 0 ;
2017-04-24 23:48:25 +00:00
2017-07-03 18:27:29 +00:00
if ( LZ4F_isError ( errorCode ) ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: failed to create lz4 decompression context \n " ) ;
2017-07-03 18:27:29 +00:00
return FIO_ERROR_FRAME_DECODING ;
}
2017-04-24 23:48:25 +00:00
/* Init feed with magic number (already consumed from FILE* sFile) */
{ size_t inSize = 4 ;
size_t outSize = 0 ;
MEM_writeLE32 ( ress - > srcBuffer , LZ4_MAGICNUMBER ) ;
nextToLoad = LZ4F_decompress ( dCtx , ress - > dstBuffer , & outSize , ress - > srcBuffer , & inSize , NULL ) ;
2017-07-03 18:27:29 +00:00
if ( LZ4F_isError ( nextToLoad ) ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: lz4 header error : %s \n " ,
2017-05-17 00:32:33 +00:00
srcFileName , LZ4F_getErrorName ( nextToLoad ) ) ;
2017-07-03 18:27:29 +00:00
LZ4F_freeDecompressionContext ( dCtx ) ;
return FIO_ERROR_FRAME_DECODING ;
} }
2017-04-24 23:48:25 +00:00
/* Main Loop */
for ( ; nextToLoad ; ) {
size_t readSize ;
size_t pos = 0 ;
size_t decodedBytes = ress - > dstBufferSize ;
/* Read input */
if ( nextToLoad > ress - > srcBufferSize ) nextToLoad = ress - > srcBufferSize ;
readSize = fread ( ress - > srcBuffer , 1 , nextToLoad , srcFile ) ;
if ( ! readSize ) break ; /* reached end of file or stream */
while ( ( pos < readSize ) | | ( decodedBytes = = ress - > dstBufferSize ) ) { /* still to read, or still to flush */
/* Decode Input (at least partially) */
size_t remaining = readSize - pos ;
decodedBytes = ress - > dstBufferSize ;
nextToLoad = LZ4F_decompress ( dCtx , ress - > dstBuffer , & decodedBytes , ( char * ) ( ress - > srcBuffer ) + pos , & remaining , NULL ) ;
2017-07-03 18:27:29 +00:00
if ( LZ4F_isError ( nextToLoad ) ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: lz4 decompression error : %s \n " ,
2017-05-17 00:32:33 +00:00
srcFileName , LZ4F_getErrorName ( nextToLoad ) ) ;
2018-04-24 01:50:16 +00:00
decodingError = 1 ; nextToLoad = 0 ; break ;
2017-07-03 18:27:29 +00:00
}
2017-04-24 23:48:25 +00:00
pos + = remaining ;
/* Write Block */
if ( decodedBytes ) {
2017-07-03 18:27:29 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decodedBytes , ress - > dstFile ) ! = decodedBytes ) {
2017-08-14 12:03:46 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s \n " , strerror ( errno ) ) ;
2018-04-24 01:50:16 +00:00
decodingError = 1 ; nextToLoad = 0 ; break ;
2017-07-03 18:27:29 +00:00
}
2017-04-24 23:48:25 +00:00
filesize + = decodedBytes ;
DISPLAYUPDATE ( 2 , " \r Decompressed : %u MB " , ( unsigned ) ( filesize > > 20 ) ) ;
}
if ( ! nextToLoad ) break ;
}
}
/* can be out because readSize == 0, which could be an fread() error */
2017-07-03 18:27:29 +00:00
if ( ferror ( srcFile ) ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: read error \n " , srcFileName ) ;
2017-07-03 18:27:29 +00:00
decodingError = 1 ;
}
2017-04-24 23:48:25 +00:00
2017-07-03 18:27:29 +00:00
if ( nextToLoad ! = 0 ) {
2017-07-03 20:24:50 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unfinished lz4 stream \n " , srcFileName ) ;
2017-07-03 18:27:29 +00:00
decodingError = 1 ;
}
2017-04-24 23:48:25 +00:00
LZ4F_freeDecompressionContext ( dCtx ) ;
2017-07-03 22:14:55 +00:00
ress - > srcBufferLoaded = 0 ; /* LZ4F will reach exact frame boundary */
2017-04-24 23:48:25 +00:00
2017-07-03 18:27:29 +00:00
return decodingError ? FIO_ERROR_FRAME_DECODING : filesize ;
2017-04-24 23:48:25 +00:00
}
# endif
2016-12-01 10:56:31 +00:00
2017-07-03 17:27:16 +00:00
/** FIO_decompressFrames() :
* Find and decode frames inside srcFile
* srcFile presumed opened and valid
* @ return : 0 : OK
* 1 : error
*/
static int FIO_decompressFrames ( dRess_t ress , FILE * srcFile ,
const char * dstFileName , const char * srcFileName )
2015-10-18 21:18:32 +00:00
{
2016-07-26 14:44:09 +00:00
unsigned readSomething = 0 ;
2016-12-02 20:40:57 +00:00
unsigned long long filesize = 0 ;
2017-07-03 17:27:16 +00:00
assert ( srcFile ! = NULL ) ;
2016-11-30 14:05:54 +00:00
2016-12-02 14:01:31 +00:00
/* for each frame */
for ( ; ; ) {
/* check magic number -> version */
2016-12-02 15:20:16 +00:00
size_t const toRead = 4 ;
2017-07-03 17:27:16 +00:00
const BYTE * const buf = ( const BYTE * ) ress . srcBuffer ;
2017-07-03 22:14:55 +00:00
if ( ress . srcBufferLoaded < toRead ) /* load up to 4 bytes for header */
2017-05-06 02:15:24 +00:00
ress . srcBufferLoaded + = fread ( ( char * ) ress . srcBuffer + ress . srcBufferLoaded ,
( size_t ) 1 , toRead - ress . srcBufferLoaded , srcFile ) ;
2016-12-05 16:39:38 +00:00
if ( ress . srcBufferLoaded = = 0 ) {
2017-07-03 22:14:55 +00:00
if ( readSomething = = 0 ) { /* srcFile is empty (which is invalid) */
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unexpected end of file \n " , srcFileName ) ;
2017-05-06 02:15:24 +00:00
return 1 ;
2017-07-03 22:14:55 +00:00
} /* else, just reached frame boundary */
2016-12-02 15:20:16 +00:00
break ; /* no more input */
}
2017-07-03 17:27:16 +00:00
readSomething = 1 ; /* there is at least 1 byte in srcFile */
2017-05-17 00:32:33 +00:00
if ( ress . srcBufferLoaded < toRead ) {
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unknown header \n " , srcFileName ) ;
2017-05-17 00:32:33 +00:00
return 1 ;
}
2017-07-03 22:14:55 +00:00
if ( ZSTD_isFrame ( buf , ress . srcBufferLoaded ) ) {
unsigned long long const frameSize = FIO_decompressZstdFrame ( & ress , srcFile , srcFileName , filesize ) ;
if ( frameSize = = FIO_ERROR_FRAME_DECODING ) return 1 ;
filesize + = frameSize ;
} else if ( buf [ 0 ] = = 31 & & buf [ 1 ] = = 139 ) { /* gz magic number */
2016-12-02 14:01:31 +00:00
# ifdef ZSTD_GZDECOMPRESS
2017-07-03 20:47:46 +00:00
unsigned long long const frameSize = FIO_decompressGzFrame ( & ress , srcFile , srcFileName ) ;
if ( frameSize = = FIO_ERROR_FRAME_DECODING ) return 1 ;
filesize + = frameSize ;
2016-11-30 14:05:54 +00:00
# else
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: gzip file cannot be uncompressed (zstd compiled without HAVE_ZLIB) -- ignored \n " , srcFileName ) ;
2016-12-02 15:20:16 +00:00
return 1 ;
2017-03-14 01:11:07 +00:00
# endif
} else if ( ( buf [ 0 ] = = 0xFD & & buf [ 1 ] = = 0x37 ) /* xz magic number */
| | ( buf [ 0 ] = = 0x5D & & buf [ 1 ] = = 0x00 ) ) { /* lzma header (no magic number) */
# ifdef ZSTD_LZMADECOMPRESS
2017-07-03 17:27:16 +00:00
unsigned long long const frameSize = FIO_decompressLzmaFrame ( & ress , srcFile , srcFileName , buf [ 0 ] ! = 0xFD ) ;
if ( frameSize = = FIO_ERROR_FRAME_DECODING ) return 1 ;
filesize + = frameSize ;
2017-03-14 01:11:07 +00:00
# else
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: xz/lzma file cannot be uncompressed (zstd compiled without HAVE_LZMA) -- ignored \n " , srcFileName ) ;
2017-03-14 01:11:07 +00:00
return 1 ;
2017-04-24 23:48:25 +00:00
# endif
} else if ( MEM_readLE32 ( buf ) = = LZ4_MAGICNUMBER ) {
# ifdef ZSTD_LZ4DECOMPRESS
2017-07-03 18:27:29 +00:00
unsigned long long const frameSize = FIO_decompressLz4Frame ( & ress , srcFile , srcFileName ) ;
if ( frameSize = = FIO_ERROR_FRAME_DECODING ) return 1 ;
filesize + = frameSize ;
2017-04-24 23:48:25 +00:00
# else
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: lz4 file cannot be uncompressed (zstd compiled without HAVE_LZ4) -- ignored \n " , srcFileName ) ;
2017-04-24 23:48:25 +00:00
return 1 ;
2016-11-30 14:05:54 +00:00
# endif
2017-07-03 17:27:16 +00:00
} else if ( ( g_overwrite ) & & ! strcmp ( dstFileName , stdoutmark ) ) { /* pass-through mode */
return FIO_passThrough ( ress . dstFile , srcFile ,
ress . srcBuffer , ress . srcBufferSize , ress . srcBufferLoaded ) ;
2016-12-02 15:20:16 +00:00
} else {
2017-07-03 17:27:16 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unsupported format \n " , srcFileName ) ;
return 1 ;
} } /* for each frame */
2015-10-18 21:18:32 +00:00
2015-12-17 19:30:14 +00:00
/* Final Status */
2015-10-18 21:18:32 +00:00
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2016-08-28 19:47:17 +00:00
DISPLAYLEVEL ( 2 , " %-20s: %llu bytes \n " , srcFileName , filesize ) ;
2015-10-18 21:18:32 +00:00
2017-07-03 17:27:16 +00:00
return 0 ;
}
/** FIO_decompressSrcFile() :
Decompression ` srcFileName ` into ` ress . dstFile `
@ return : 0 : OK
1 : operation not started
*/
static int FIO_decompressSrcFile ( dRess_t ress , const char * dstFileName , const char * srcFileName )
{
FILE * srcFile ;
int result ;
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
srcFile = FIO_openSrcFile ( srcFileName ) ;
if ( srcFile = = NULL ) return 1 ;
result = FIO_decompressFrames ( ress , srcFile , dstFileName , srcFileName ) ;
2016-12-02 12:50:29 +00:00
/* Close file */
2017-07-03 17:27:16 +00:00
if ( fclose ( srcFile ) ) {
2017-09-18 20:41:54 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , srcFileName , strerror ( errno ) ) ; /* error should not happen */
2017-07-03 17:27:16 +00:00
return 1 ;
}
2017-07-03 20:24:50 +00:00
if ( g_removeSrcFile /* --rm */
2017-09-18 20:41:54 +00:00
& & ( result = = 0 ) /* decompression successful */
2017-07-03 20:24:50 +00:00
& & strcmp ( srcFileName , stdinmark ) ) /* not stdin */ {
2017-11-18 00:38:56 +00:00
/* We must clear the handler, since after this point calling it would
* delete both the source and destination files .
*/
clearHandler ( ) ;
2018-01-05 19:44:45 +00:00
if ( FIO_remove ( srcFileName ) ) {
2017-07-03 20:24:50 +00:00
/* failed to remove src file */
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , srcFileName , strerror ( errno ) ) ;
return 1 ;
} }
2017-07-03 17:27:16 +00:00
return result ;
2016-02-12 17:33:26 +00:00
}
/** FIO_decompressFile_extRess() :
decompress ` srcFileName ` into ` dstFileName `
@ return : 0 : OK
1 : operation aborted ( src not available , dst already taken , etc . )
*/
2016-06-09 20:59:51 +00:00
static int FIO_decompressDstFile ( dRess_t ress ,
2016-12-02 20:40:57 +00:00
const char * dstFileName , const char * srcFileName )
2016-02-12 17:33:26 +00:00
{
2016-03-14 05:24:46 +00:00
int result ;
2016-11-02 13:08:07 +00:00
stat_t statbuf ;
int stat_result = 0 ;
2016-11-02 12:08:39 +00:00
2016-02-12 17:33:26 +00:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
if ( ress . dstFile = = 0 ) return 1 ;
2017-11-18 00:38:56 +00:00
/* Must ony be added after FIO_openDstFile() succeeds.
* Otherwise we may delete the destination file if at already exists , and
* the user presses Ctrl - C when asked if they wish to overwrite .
*/
addHandler ( dstFileName ) ;
2017-10-01 19:10:26 +00:00
2017-09-18 20:41:54 +00:00
if ( strcmp ( srcFileName , stdinmark )
& & UTIL_getFileStat ( srcFileName , & statbuf ) )
2017-05-17 00:32:33 +00:00
stat_result = 1 ;
2016-12-02 23:18:57 +00:00
result = FIO_decompressSrcFile ( ress , dstFileName , srcFileName ) ;
2017-11-18 00:38:56 +00:00
clearHandler ( ) ;
2016-02-12 17:33:26 +00:00
2017-07-03 20:24:50 +00:00
if ( fclose ( ress . dstFile ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ;
result = 1 ;
}
2016-11-02 12:08:39 +00:00
2017-07-03 20:24:50 +00:00
if ( ( result ! = 0 ) /* operation failure */
2017-09-18 20:41:54 +00:00
& & strcmp ( dstFileName , nulmark ) /* special case : don't remove() /dev/null (#316) */
& & strcmp ( dstFileName , stdoutmark ) ) /* special case : don't remove() stdout */
2018-01-05 19:44:45 +00:00
FIO_remove ( dstFileName ) ; /* remove decompression artefact; note don't do anything special if remove() fails */
2017-09-18 20:41:54 +00:00
else { /* operation success */
if ( strcmp ( dstFileName , stdoutmark ) /* special case : don't chmod stdout */
& & strcmp ( dstFileName , nulmark ) /* special case : don't chmod /dev/null */
& & stat_result ) /* file permissions correctly extracted from src */
UTIL_setFileStat ( dstFileName , & statbuf ) ; /* transfer file permissions from src into dst */
}
2017-10-01 19:10:26 +00:00
signal ( SIGINT , SIG_DFL ) ;
2016-03-14 05:24:46 +00:00
return result ;
2015-10-18 21:18:32 +00:00
}
2015-12-17 19:30:14 +00:00
int FIO_decompressFilename ( const char * dstFileName , const char * srcFileName ,
const char * dictFileName )
{
2017-07-03 20:24:50 +00:00
dRess_t const ress = FIO_createDResources ( dictFileName ) ;
2015-12-17 19:30:14 +00:00
2017-07-03 20:24:50 +00:00
int const decodingError = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2015-12-17 19:30:14 +00:00
FIO_freeDResources ( ress ) ;
2017-07-03 20:24:50 +00:00
return decodingError ;
2015-12-17 19:30:14 +00:00
}
# define MAXSUFFIXSIZE 8
int FIO_decompressMultipleFilenames ( const char * * srcNamesTable , unsigned nbFiles ,
2017-12-13 02:32:50 +00:00
const char * outFileName ,
2015-12-17 19:30:14 +00:00
const char * dictFileName )
{
int skippedFiles = 0 ;
int missingFiles = 0 ;
2016-05-10 03:37:43 +00:00
dRess_t ress = FIO_createDResources ( dictFileName ) ;
2015-12-17 19:30:14 +00:00
2017-12-13 02:32:50 +00:00
if ( outFileName ) {
2016-05-07 20:43:40 +00:00
unsigned u ;
2017-12-13 02:32:50 +00:00
ress . dstFile = FIO_openDstFile ( outFileName ) ;
if ( ress . dstFile = = 0 ) EXM_THROW ( 71 , " cannot open %s " , outFileName ) ;
2016-02-15 18:33:16 +00:00
for ( u = 0 ; u < nbFiles ; u + + )
2017-12-13 02:32:50 +00:00
missingFiles + = FIO_decompressSrcFile ( ress , outFileName , srcNamesTable [ u ] ) ;
2017-05-17 00:32:33 +00:00
if ( fclose ( ress . dstFile ) )
2017-12-13 02:32:50 +00:00
EXM_THROW ( 72 , " Write error : cannot properly close output file " ) ;
2016-02-15 18:33:16 +00:00
} else {
2017-03-14 01:11:07 +00:00
size_t suffixSize ;
2016-05-10 03:37:43 +00:00
size_t dfnSize = FNSPACE ;
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-05-10 03:37:43 +00:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2017-05-17 00:32:33 +00:00
if ( dstFileName = = NULL )
EXM_THROW ( 73 , " not enough memory for dstFileName " ) ;
2016-02-12 17:33:26 +00:00
for ( u = 0 ; u < nbFiles ; u + + ) { /* create dstFileName */
2016-05-10 03:37:43 +00:00
const char * const srcFileName = srcNamesTable [ u ] ;
2017-03-14 01:11:07 +00:00
const char * const suffixPtr = strrchr ( srcFileName , ' . ' ) ;
2016-05-10 03:37:43 +00:00
size_t const sfnSize = strlen ( srcFileName ) ;
2017-03-14 01:11:07 +00:00
if ( ! suffixPtr ) {
2017-05-17 00:32:33 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unknown suffix -- ignored \n " ,
srcFileName ) ;
2017-03-14 01:11:07 +00:00
skippedFiles + + ;
continue ;
}
suffixSize = strlen ( suffixPtr ) ;
2016-02-15 18:33:16 +00:00
if ( dfnSize + suffixSize < = sfnSize + 1 ) {
free ( dstFileName ) ;
dfnSize = sfnSize + 20 ;
dstFileName = ( char * ) malloc ( dfnSize ) ;
2017-05-17 00:32:33 +00:00
if ( dstFileName = = NULL )
EXM_THROW ( 74 , " not enough memory for dstFileName " ) ;
2016-02-15 18:33:16 +00:00
}
2017-05-06 02:15:24 +00:00
if ( sfnSize < = suffixSize
| | ( strcmp ( suffixPtr , GZ_EXTENSION )
& & strcmp ( suffixPtr , XZ_EXTENSION )
& & strcmp ( suffixPtr , ZSTD_EXTENSION )
& & strcmp ( suffixPtr , LZMA_EXTENSION )
& & strcmp ( suffixPtr , LZ4_EXTENSION ) ) ) {
2018-06-01 00:47:29 +00:00
const char * suffixlist = ZSTD_EXTENSION
2018-06-14 23:24:18 +00:00
# ifdef ZSTD_GZCOMPRESS
2018-06-01 00:47:29 +00:00
" / " GZ_EXTENSION
2018-05-31 23:13:36 +00:00
# endif
# ifdef ZSTD_LZMACOMPRESS
2018-06-01 00:47:29 +00:00
" / " XZ_EXTENSION " / " LZMA_EXTENSION
2018-05-31 23:13:36 +00:00
# endif
# ifdef ZSTD_LZ4COMPRESS
2018-06-01 00:47:29 +00:00
" / " LZ4_EXTENSION
2018-05-31 23:13:36 +00:00
# endif
2018-06-01 00:47:29 +00:00
;
2018-05-31 23:13:36 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unknown suffix (%s expected) -- ignored \n " ,
srcFileName , suffixlist ) ;
2017-03-14 01:11:07 +00:00
skippedFiles + + ;
continue ;
2016-11-30 12:34:21 +00:00
} else {
memcpy ( dstFileName , srcFileName , sfnSize - suffixSize ) ;
dstFileName [ sfnSize - suffixSize ] = ' \0 ' ;
2016-02-12 17:33:26 +00:00
}
2016-06-09 20:59:51 +00:00
missingFiles + = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2016-05-10 03:37:43 +00:00
}
free ( dstFileName ) ;
}
2015-12-17 19:30:14 +00:00
FIO_freeDResources ( ress ) ;
return missingFiles + skippedFiles ;
}
2016-02-15 18:33:16 +00:00
2017-08-19 01:30:41 +00:00
/* **************************************************************************
* . zst file info ( - - list command )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct {
2017-10-04 19:23:23 +00:00
U64 decompressedSize ;
U64 compressedSize ;
U64 windowSize ;
2017-08-19 01:30:41 +00:00
int numActualFrames ;
int numSkippableFrames ;
int decompUnavailable ;
int usesCheck ;
2017-09-26 18:21:36 +00:00
U32 nbFiles ;
2017-08-19 01:30:41 +00:00
} fileInfo_t ;
/** getFileInfo() :
* Reads information from file , stores in * info
* @ return : 0 if successful
* 1 for frame analysis error
* 2 for file not compressed with zstd
* 3 for cases in which file could not be opened .
*/
2017-10-17 23:14:25 +00:00
static int getFileInfo_fileConfirmed ( fileInfo_t * info , const char * inFileName ) {
2017-08-19 01:30:41 +00:00
int detectError = 0 ;
FILE * const srcFile = FIO_openSrcFile ( inFileName ) ;
if ( srcFile = = NULL ) {
DISPLAY ( " Error: could not open source file %s \n " , inFileName ) ;
return 3 ;
}
2017-09-26 18:21:36 +00:00
info - > compressedSize = UTIL_getFileSize ( inFileName ) ;
2017-08-19 01:30:41 +00:00
/* begin analyzing frame */
for ( ; ; ) {
BYTE headerBuffer [ ZSTD_FRAMEHEADERSIZE_MAX ] ;
size_t const numBytesRead = fread ( headerBuffer , 1 , sizeof ( headerBuffer ) , srcFile ) ;
if ( numBytesRead < ZSTD_frameHeaderSize_min ) {
2017-09-26 18:21:36 +00:00
if ( feof ( srcFile )
& & ( numBytesRead = = 0 )
2017-10-17 23:14:25 +00:00
& & ( info - > compressedSize > 0 )
& & ( info - > compressedSize ! = UTIL_FILESIZE_UNKNOWN ) ) {
2017-08-19 01:30:41 +00:00
break ;
}
else if ( feof ( srcFile ) ) {
DISPLAY ( " Error: reached end of file with incomplete frame \n " ) ;
detectError = 2 ;
break ;
}
else {
DISPLAY ( " Error: did not reach end of file but ran out of frames \n " ) ;
detectError = 1 ;
break ;
}
}
{ U32 const magicNumber = MEM_readLE32 ( headerBuffer ) ;
/* Zstandard frame */
if ( magicNumber = = ZSTD_MAGICNUMBER ) {
2017-10-04 19:23:23 +00:00
ZSTD_frameHeader header ;
2017-08-19 01:30:41 +00:00
U64 const frameContentSize = ZSTD_getFrameContentSize ( headerBuffer , numBytesRead ) ;
if ( frameContentSize = = ZSTD_CONTENTSIZE_ERROR | | frameContentSize = = ZSTD_CONTENTSIZE_UNKNOWN ) {
info - > decompUnavailable = 1 ;
} else {
info - > decompressedSize + = frameContentSize ;
}
2017-10-04 19:23:23 +00:00
if ( ZSTD_getFrameHeader ( & header , headerBuffer , numBytesRead ) ! = 0 ) {
DISPLAY ( " Error: could not decode frame header \n " ) ;
detectError = 1 ;
break ;
}
info - > windowSize = header . windowSize ;
2017-08-19 01:30:41 +00:00
/* move to the end of the frame header */
{ size_t const headerSize = ZSTD_frameHeaderSize ( headerBuffer , numBytesRead ) ;
if ( ZSTD_isError ( headerSize ) ) {
DISPLAY ( " Error: could not determine frame header size \n " ) ;
detectError = 1 ;
break ;
}
{ int const ret = fseek ( srcFile , ( ( long ) headerSize ) - ( ( long ) numBytesRead ) , SEEK_CUR ) ;
if ( ret ! = 0 ) {
DISPLAY ( " Error: could not move to end of frame header \n " ) ;
detectError = 1 ;
break ;
} } }
/* skip the rest of the blocks in the frame */
{ int lastBlock = 0 ;
do {
BYTE blockHeaderBuffer [ 3 ] ;
size_t const readBytes = fread ( blockHeaderBuffer , 1 , 3 , srcFile ) ;
if ( readBytes ! = 3 ) {
DISPLAY ( " There was a problem reading the block header \n " ) ;
detectError = 1 ;
break ;
}
{ U32 const blockHeader = MEM_readLE24 ( blockHeaderBuffer ) ;
U32 const blockTypeID = ( blockHeader > > 1 ) & 3 ;
U32 const isRLE = ( blockTypeID = = 1 ) ;
U32 const isWrongBlock = ( blockTypeID = = 3 ) ;
long const blockSize = isRLE ? 1 : ( long ) ( blockHeader > > 3 ) ;
if ( isWrongBlock ) {
DISPLAY ( " Error: unsupported block type \n " ) ;
detectError = 1 ;
break ;
}
lastBlock = blockHeader & 1 ;
{ int const ret = fseek ( srcFile , blockSize , SEEK_CUR ) ;
if ( ret ! = 0 ) {
DISPLAY ( " Error: could not skip to end of block \n " ) ;
detectError = 1 ;
break ;
} } }
} while ( lastBlock ! = 1 ) ;
if ( detectError ) break ;
}
/* check if checksum is used */
{ BYTE const frameHeaderDescriptor = headerBuffer [ 4 ] ;
int const contentChecksumFlag = ( frameHeaderDescriptor & ( 1 < < 2 ) ) > > 2 ;
if ( contentChecksumFlag ) {
int const ret = fseek ( srcFile , 4 , SEEK_CUR ) ;
info - > usesCheck = 1 ;
if ( ret ! = 0 ) {
DISPLAY ( " Error: could not skip past checksum \n " ) ;
detectError = 1 ;
break ;
} } }
info - > numActualFrames + + ;
}
/* Skippable frame */
else if ( ( magicNumber & 0xFFFFFFF0U ) = = ZSTD_MAGIC_SKIPPABLE_START ) {
U32 const frameSize = MEM_readLE32 ( headerBuffer + 4 ) ;
long const seek = ( long ) ( 8 + frameSize - numBytesRead ) ;
int const ret = LONG_SEEK ( srcFile , seek , SEEK_CUR ) ;
if ( ret ! = 0 ) {
DISPLAY ( " Error: could not find end of skippable frame \n " ) ;
detectError = 1 ;
break ;
}
info - > numSkippableFrames + + ;
}
/* unknown content */
else {
detectError = 2 ;
break ;
}
}
} /* end analyzing frame */
fclose ( srcFile ) ;
2017-09-26 18:21:36 +00:00
info - > nbFiles = 1 ;
2017-08-19 01:30:41 +00:00
return detectError ;
}
2017-10-17 23:14:25 +00:00
static int getFileInfo ( fileInfo_t * info , const char * srcFileName )
{
int const isAFile = UTIL_isRegularFile ( srcFileName ) ;
if ( ! isAFile ) {
DISPLAY ( " Error : %s is not a file " , srcFileName ) ;
return 3 ;
}
return getFileInfo_fileConfirmed ( info , srcFileName ) ;
}
2017-10-14 07:02:32 +00:00
static void displayInfo ( const char * inFileName , const fileInfo_t * info , int displayLevel ) {
2017-08-19 01:30:41 +00:00
unsigned const unit = info - > compressedSize < ( 1 MB ) ? ( 1 KB ) : ( 1 MB ) ;
const char * const unitStr = info - > compressedSize < ( 1 MB ) ? " KB " : " MB " ;
2017-10-04 19:23:23 +00:00
double const windowSizeUnit = ( double ) info - > windowSize / unit ;
2017-08-19 01:30:41 +00:00
double const compressedSizeUnit = ( double ) info - > compressedSize / unit ;
double const decompressedSizeUnit = ( double ) info - > decompressedSize / unit ;
double const ratio = ( info - > compressedSize = = 0 ) ? 0 : ( ( double ) info - > decompressedSize ) / info - > compressedSize ;
const char * const checkString = ( info - > usesCheck ? " XXH64 " : " None " ) ;
if ( displayLevel < = 2 ) {
if ( ! info - > decompUnavailable ) {
2017-09-26 18:21:36 +00:00
DISPLAYOUT ( " %6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %s \n " ,
info - > numSkippableFrames + info - > numActualFrames ,
info - > numSkippableFrames ,
2017-08-19 01:30:41 +00:00
compressedSizeUnit , unitStr , decompressedSizeUnit , unitStr ,
ratio , checkString , inFileName ) ;
} else {
2017-09-26 18:21:36 +00:00
DISPLAYOUT ( " %6d %5d %7.2f %2s %5s %s \n " ,
info - > numSkippableFrames + info - > numActualFrames ,
info - > numSkippableFrames ,
compressedSizeUnit , unitStr ,
checkString , inFileName ) ;
2017-08-19 01:30:41 +00:00
}
} else {
2017-10-14 07:02:32 +00:00
DISPLAYOUT ( " %s \n " , inFileName ) ;
2017-08-19 01:30:41 +00:00
DISPLAYOUT ( " # Zstandard Frames: %d \n " , info - > numActualFrames ) ;
2017-10-14 07:02:32 +00:00
if ( info - > numSkippableFrames )
DISPLAYOUT ( " # Skippable Frames: %d \n " , info - > numSkippableFrames ) ;
2017-10-04 19:23:23 +00:00
DISPLAYOUT ( " Window Size: %.2f %2s (%llu B) \n " ,
windowSizeUnit , unitStr ,
( unsigned long long ) info - > windowSize ) ;
2017-08-19 01:30:41 +00:00
DISPLAYOUT ( " Compressed Size: %.2f %2s (%llu B) \n " ,
2017-09-26 20:53:50 +00:00
compressedSizeUnit , unitStr ,
( unsigned long long ) info - > compressedSize ) ;
2017-08-19 01:30:41 +00:00
if ( ! info - > decompUnavailable ) {
DISPLAYOUT ( " Decompressed Size: %.2f %2s (%llu B) \n " ,
2017-09-26 20:53:50 +00:00
decompressedSizeUnit , unitStr ,
( unsigned long long ) info - > decompressedSize ) ;
2017-08-19 01:30:41 +00:00
DISPLAYOUT ( " Ratio: %.4f \n " , ratio ) ;
}
DISPLAYOUT ( " Check: %s \n " , checkString ) ;
DISPLAYOUT ( " \n " ) ;
}
}
2017-09-26 18:21:36 +00:00
static fileInfo_t FIO_addFInfo ( fileInfo_t fi1 , fileInfo_t fi2 )
{
fileInfo_t total ;
2018-02-28 22:16:30 +00:00
memset ( & total , 0 , sizeof ( total ) ) ;
2017-09-26 18:21:36 +00:00
total . numActualFrames = fi1 . numActualFrames + fi2 . numActualFrames ;
total . numSkippableFrames = fi1 . numSkippableFrames + fi2 . numSkippableFrames ;
total . compressedSize = fi1 . compressedSize + fi2 . compressedSize ;
total . decompressedSize = fi1 . decompressedSize + fi2 . decompressedSize ;
total . decompUnavailable = fi1 . decompUnavailable | fi2 . decompUnavailable ;
total . usesCheck = fi1 . usesCheck & fi2 . usesCheck ;
total . nbFiles = fi1 . nbFiles + fi2 . nbFiles ;
return total ;
}
2017-08-19 01:30:41 +00:00
2017-09-26 18:21:36 +00:00
static int FIO_listFile ( fileInfo_t * total , const char * inFileName , int displayLevel ) {
2017-08-19 01:30:41 +00:00
fileInfo_t info ;
memset ( & info , 0 , sizeof ( info ) ) ;
2017-09-26 18:21:36 +00:00
{ int const error = getFileInfo ( & info , inFileName ) ;
2017-08-19 01:30:41 +00:00
if ( error = = 1 ) {
/* display error, but provide output */
2017-09-26 18:21:36 +00:00
DISPLAY ( " An error occurred while getting file info \n " ) ;
2017-08-19 01:30:41 +00:00
}
else if ( error = = 2 ) {
2017-09-26 18:21:36 +00:00
DISPLAYOUT ( " File %s not compressed by zstd \n " , inFileName ) ;
if ( displayLevel > 2 ) DISPLAYOUT ( " \n " ) ;
2017-08-19 01:30:41 +00:00
return 1 ;
}
else if ( error = = 3 ) {
2017-09-26 18:21:36 +00:00
/* error occurred while opening the file */
if ( displayLevel > 2 ) DISPLAYOUT ( " \n " ) ;
2017-08-19 01:30:41 +00:00
return 1 ;
}
displayInfo ( inFileName , & info , displayLevel ) ;
2017-09-26 18:21:36 +00:00
* total = FIO_addFInfo ( * total , info ) ;
2017-08-19 01:30:41 +00:00
return error ;
}
}
int FIO_listMultipleFiles ( unsigned numFiles , const char * * filenameTable , int displayLevel ) {
2018-06-29 19:33:44 +00:00
unsigned u ;
for ( u = 0 ; u < numFiles ; u + + ) {
if ( ! strcmp ( filenameTable [ u ] , stdinmark ) ) {
DISPLAYOUT ( " zstd: --list does not support reading from standard input \n " ) ;
return 1 ;
}
2018-06-11 19:19:15 +00:00
}
2018-06-11 17:13:00 +00:00
2017-08-19 01:30:41 +00:00
if ( numFiles = = 0 ) {
2018-06-29 19:33:44 +00:00
if ( ! IS_CONSOLE ( stdin ) ) {
DISPLAYOUT ( " zstd: --list does not support reading from standard input \n " ) ;
}
2017-08-19 01:30:41 +00:00
DISPLAYOUT ( " No files given \n " ) ;
2018-06-29 19:33:44 +00:00
return 1 ;
2017-08-19 01:30:41 +00:00
}
2017-10-04 19:23:23 +00:00
if ( displayLevel < = 2 ) {
DISPLAYOUT ( " Frames Skips Compressed Uncompressed Ratio Check Filename \n " ) ;
}
2017-09-26 18:21:36 +00:00
{ int error = 0 ;
fileInfo_t total ;
memset ( & total , 0 , sizeof ( total ) ) ;
total . usesCheck = 1 ;
2017-08-19 01:30:41 +00:00
for ( u = 0 ; u < numFiles ; u + + ) {
2017-09-26 18:21:36 +00:00
error | = FIO_listFile ( & total , filenameTable [ u ] , displayLevel ) ;
}
2017-10-14 07:02:32 +00:00
if ( numFiles > 1 & & displayLevel < = 2 ) { /* display total */
2017-09-26 18:21:36 +00:00
unsigned const unit = total . compressedSize < ( 1 MB ) ? ( 1 KB ) : ( 1 MB ) ;
const char * const unitStr = total . compressedSize < ( 1 MB ) ? " KB " : " MB " ;
double const compressedSizeUnit = ( double ) total . compressedSize / unit ;
double const decompressedSizeUnit = ( double ) total . decompressedSize / unit ;
double const ratio = ( total . compressedSize = = 0 ) ? 0 : ( ( double ) total . decompressedSize ) / total . compressedSize ;
const char * const checkString = ( total . usesCheck ? " XXH64 " : " " ) ;
DISPLAYOUT ( " ----------------------------------------------------------------- \n " ) ;
if ( total . decompUnavailable ) {
DISPLAYOUT ( " %6d %5d %7.2f %2s %5s %u files \n " ,
total . numSkippableFrames + total . numActualFrames ,
total . numSkippableFrames ,
compressedSizeUnit , unitStr ,
checkString , total . nbFiles ) ;
} else {
DISPLAYOUT ( " %6d %5d %7.2f %2s %9.2f %2s %5.3f %5s %u files \n " ,
total . numSkippableFrames + total . numActualFrames ,
total . numSkippableFrames ,
compressedSizeUnit , unitStr , decompressedSizeUnit , unitStr ,
ratio , checkString , total . nbFiles ) ;
2017-10-14 07:02:32 +00:00
} }
2017-08-19 01:30:41 +00:00
return error ;
}
}
2016-05-10 03:37:43 +00:00
# endif /* #ifndef ZSTD_NODECOMPRESS */