From 5dde00e5d33eb617673f62191781907468beadb7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Apr 2019 20:46:04 -0700 Subject: fixed version number for lz4hc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73554cd..607fc4e 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ in single-thread mode. | [Zstandard] 1.4.0 -1 | 2.883 | 515 MB/s | 1380 MB/s | | LZF v3.6 | 2.073 | 415 MB/s | 910 MB/s | | [zlib] deflate 1.2.11 -1| 2.730 | 100 MB/s | 415 MB/s | -|**LZ4 HC -9 (v1.8.2)** |**2.721**| 41 MB/s | **4900 MB/s** | +|**LZ4 HC -9 (v1.9.0)** |**2.721**| 41 MB/s | **4900 MB/s** | | [zlib] deflate 1.2.11 -6| 3.099 | 36 MB/s | 445 MB/s | [zlib]: http://www.zlib.net/ -- cgit v0.12 From 1848ea5cbd582e3728ea4fe1ff619468753debea Mon Sep 17 00:00:00 2001 From: Norm Green Date: Wed, 17 Apr 2019 09:20:09 -0700 Subject: Fix AIX errors/warnings --- lib/lz4.c | 6 ++++++ tests/fuzzer.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/lib/lz4.c b/lib/lz4.c index 693bdaf..bd8fa11 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -98,8 +98,14 @@ # define LZ4_SRC_INCLUDED 1 #endif +#ifndef LZ4_STATIC_LINKING_ONLY #define LZ4_STATIC_LINKING_ONLY +#endif + +#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ +#endif + #include "lz4.h" /* see also "memory routines" below */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 3128e6d..68e2232 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -50,6 +50,10 @@ #include #include /* INT_MAX */ +#if defined(_AIX) +# include /* mmap */ +#endif + #define LZ4_DISABLE_DEPRECATE_WARNINGS /* LZ4_decompress_fast */ #define LZ4_STATIC_LINKING_ONLY #include "lz4.h" -- cgit v0.12 From 1ed69691a1d1226a6d6e7c465eb1e8c2706833cb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Apr 2019 13:31:24 -0700 Subject: fuzzer: added tests to detect LZ4_decompress_fast() out of bound read --- tests/fuzzer.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 68e2232..0eece15 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -481,31 +481,39 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test compression */ FUZ_DISPLAYTEST("test LZ4_compress_default()"); ret = LZ4_compress_default(block, compressedBuffer, blockSize, (int)compressedBufferSize); - FUZ_CHECKTEST(ret==0, "LZ4_compress_default() failed"); + FUZ_CHECKTEST(ret<=0, "LZ4_compress_default() failed"); compressedSize = ret; /* Decompression tests */ - /* Test decoding with output size exactly correct => must work */ - FUZ_DISPLAYTEST("LZ4_decompress_fast() with exact output buffer"); - ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize); - FUZ_CHECKTEST(ret<0, "LZ4_decompress_fast failed despite correct space"); - FUZ_CHECKTEST(ret!=compressedSize, "LZ4_decompress_fast failed : did not fully read compressed data"); - { U32 const crcCheck = XXH32(decodedBuffer, blockSize, 0); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast corrupted decoded data"); - } + /* Test decompress_fast() with input buffer size exactly correct => must not read out of bound */ + { char* const cBuffer_exact = malloc((size_t)compressedSize); + assert(cBuffer_exact != NULL); + memcpy(cBuffer_exact, compressedBuffer, compressedSize); + + /* Test decoding with output size exactly correct => must work */ + FUZ_DISPLAYTEST("LZ4_decompress_fast() with exact output buffer"); + ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize); + FUZ_CHECKTEST(ret<0, "LZ4_decompress_fast failed despite correct space"); + FUZ_CHECKTEST(ret!=compressedSize, "LZ4_decompress_fast failed : did not fully read compressed data"); + { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); + FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast corrupted decoded data"); + } - /* Test decoding with one byte missing => must fail */ - FUZ_DISPLAYTEST("LZ4_decompress_fast() with output buffer 1-byte too short"); - decodedBuffer[blockSize-1] = 0; - ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize-1); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small"); - FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_fast overrun specified output buffer"); + /* Test decoding with one byte missing => must fail */ + FUZ_DISPLAYTEST("LZ4_decompress_fast() with output buffer 1-byte too short"); + decodedBuffer[blockSize-1] = 0; + ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize-1); + FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small"); + FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_fast overrun specified output buffer"); - /* Test decoding with one byte too much => must fail */ - FUZ_DISPLAYTEST(); - ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize+1); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too large"); + /* Test decoding with one byte too much => must fail */ + FUZ_DISPLAYTEST(); + ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize+1); + FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too large"); + + free(cBuffer_exact); + } /* Test decoding with empty input */ FUZ_DISPLAYTEST("LZ4_decompress_safe() with empty input"); -- cgit v0.12 From 25d96f1e4d84b9fca8f754cd91b822fc32758e5c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Apr 2019 15:01:53 -0700 Subject: fix out-of-bound read within LZ4_decompress_fast() and deprecate LZ4_decompress_fast(), with deprecation warnings enabled by default. Note that, as a consequence of the fix, LZ4_decompress_fast is now __slower__ than LZ4_decompress_safe(). That's because, since it doesn't know the input buffer size, it must progress more cautiously into the input buffer to ensure to out-of-bound read. --- lib/lz4.c | 15 +++++++++++++-- lib/lz4.h | 19 ++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/lz4.c b/lib/lz4.c index bd8fa11..2f8aa04 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -135,6 +135,9 @@ # endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ +#undef LZ4_FORCE_INLINE +#define LZ4_FORCE_INLINE static /* disable */ + /* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, * together with a simple 8-byte copy loop as a fall-back path. @@ -1671,7 +1674,10 @@ LZ4_decompress_generic( { goto safe_literal_copy; } - LZ4_wildCopy32(op, ip, cpy); + if (endOnInput) + LZ4_wildCopy32(op, ip, cpy); + else + LZ4_wildCopy(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : it doesn't know input length, and only relies on end-of-block properties */ ip += length; op = cpy; } else { cpy = op+length; @@ -1681,7 +1687,12 @@ LZ4_decompress_generic( goto safe_literal_copy; } /* Literals can only be 14, but hope compilers optimize if we copy by a register size */ - memcpy(op, ip, 16); + if (endOnInput) + memcpy(op, ip, 16); + else { /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : it doesn't know input length, and only relies on end-of-block properties */ + memcpy(op, ip, 8); + if (length > 8) memcpy(op+8, ip+8, 8); + } ip += length; op = cpy; } diff --git a/lib/lz4.h b/lib/lz4.h index 1589be9..962f5e6 100644 --- a/lib/lz4.h +++ b/lib/lz4.h @@ -631,14 +631,15 @@ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4 LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); /*! LZ4_decompress_fast() : **unsafe!** - * These functions are generally slightly faster than LZ4_decompress_safe(), - * though the difference is small (generally ~5%). - * However, the real cost is a risk : LZ4_decompress_safe() is protected vs malformed input, while `LZ4_decompress_fast()` is not, making it a security liability. + * These functions used to be faster than LZ4_decompress_safe(), + * but it has changed, and they are now slower than LZ4_decompress_safe(). + * This is because LZ4_decompress_fast() doesn't know the input size, + * and therefore must progress more cautiously in the input buffer to not read beyond the end of block. + * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. - * These functions will generate a deprecation warning in the future. * - * Last LZ4_decompress_fast() specificity is that it can decompress a block without knowing its compressed size. - * Note that even that functionality could be achieved in a more secure manner if need be, + * Only LZ4_decompress_fast() specificity is that it can decompress a block without knowing its compressed size. + * Even that functionality could be achieved in a more secure manner if need be, * though it would require new prototypes, and adaptation of the implementation to this new use case. * * Parameters: @@ -655,11 +656,11 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4 * As a consequence, use these functions in trusted environments with trusted data **only**. */ -/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") */ +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); -/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") */ +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize); -/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") */ +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize); /*! LZ4_resetStream() : -- cgit v0.12 From 5acfb15df066ab77301c32064b28ec9b3e571d67 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Apr 2019 15:33:37 -0700 Subject: re-enable FORCE_INLINE was disabled for tests --- lib/lz4.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/lz4.c b/lib/lz4.c index 2f8aa04..c38932e 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -135,9 +135,6 @@ # endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ -#undef LZ4_FORCE_INLINE -#define LZ4_FORCE_INLINE static /* disable */ - /* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, * together with a simple 8-byte copy loop as a fall-back path. -- cgit v0.12 From 8f0e7440633b956484626a432af3eae70c436419 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Apr 2019 15:44:14 -0700 Subject: fuzzer: fix explicit cast for C++ --- tests/fuzzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 0eece15..234be7c 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -487,7 +487,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Decompression tests */ /* Test decompress_fast() with input buffer size exactly correct => must not read out of bound */ - { char* const cBuffer_exact = malloc((size_t)compressedSize); + { char* const cBuffer_exact = (char*)malloc((size_t)compressedSize); assert(cBuffer_exact != NULL); memcpy(cBuffer_exact, compressedBuffer, compressedSize); -- cgit v0.12 From 3f558163ad74ee9553839aedb211c08a835f23a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 10:38:51 -0700 Subject: fuzzer: fixed scan-build leak warning the program exit(), so there is no need to track and dealloc every buffer. --- tests/fuzzer.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 234be7c..14cd8a0 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -331,7 +331,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c if (cond) { \ printf("Test %u : ", testNb); printf(__VA_ARGS__); \ printf(" (seed %u, cycle %u) \n", seed, cycleNb); \ - goto _output_error; \ + exit(1); \ } # define FUZ_DISPLAYTEST(...) { \ @@ -347,7 +347,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* init */ if(!CNBuffer || !compressedBuffer || !decodedBuffer) { DISPLAY("Not enough memory to start fuzzer tests"); - goto _output_error; + exit(1); } if ( LZ4_initStream(&LZ4dict, sizeof(LZ4dict)) == NULL) abort(); if ( LZ4_initStreamHC(&LZ4dictHC, sizeof(LZ4dictHC)) == NULL) abort(); @@ -505,7 +505,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c decodedBuffer[blockSize-1] = 0; ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize-1); FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small"); - FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_fast overrun specified output buffer"); + FUZ_CHECKTEST(decodedBuffer[blockSize-1]!=0, "LZ4_decompress_fast overrun specified output buffer"); /* Test decoding with one byte too much => must fail */ FUZ_DISPLAYTEST(); @@ -960,20 +960,13 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c printf("ratio with dict: %0.3f%%\n", (double)ccbytes/bytes*100); /* release memory */ - { -_exit: - free(CNBuffer); - free(compressedBuffer); - free(decodedBuffer); - FUZ_freeLowAddr(lowAddrBuffer, labSize); - free(stateLZ4); - free(stateLZ4HC); - return result; - -_output_error: - result = 1; - goto _exit; - } + free(CNBuffer); + free(compressedBuffer); + free(decodedBuffer); + FUZ_freeLowAddr(lowAddrBuffer, labSize); + free(stateLZ4); + free(stateLZ4HC); + return result; } @@ -1388,8 +1381,6 @@ static void FUZ_unitTests(int compressionLevel) printf("All unit tests completed successfully compressionLevel=%d \n", compressionLevel); return; -_output_error: - exit(1); } -- cgit v0.12 From 4f6de46f60fc7b158e7fc5ce24eb06c39d8b6ce2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 12:05:50 -0700 Subject: fix several minor static analyzer warnings --- programs/bench.c | 12 +++++----- tests/checkFrame.c | 2 +- tests/frametest.c | 14 +++++++----- tests/fuzzer.c | 64 +++++++++++++++++++++++++++++++----------------------- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index 11bf044..5934935 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -209,7 +209,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, blockTable[nbBlocks].cPtr = cPtr; blockTable[nbBlocks].resPtr = resPtr; blockTable[nbBlocks].srcSize = thisBlockSize; - blockTable[nbBlocks].cRoom = LZ4_compressBound((int)thisBlockSize); + blockTable[nbBlocks].cRoom = (size_t)LZ4_compressBound((int)thisBlockSize); srcPtr += thisBlockSize; cPtr += blockTable[nbBlocks].cRoom; resPtr += thisBlockSize; @@ -257,8 +257,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, for (nbLoops=0; nbLoops < nbCompressionLoops; nbLoops++) { U32 blockNb; for (blockNb=0; blockNb 0) { diff --git a/tests/checkFrame.c b/tests/checkFrame.c index 50c0405..139a599 100644 --- a/tests/checkFrame.c +++ b/tests/checkFrame.c @@ -105,7 +105,7 @@ typedef struct { LZ4F_decompressionContext_t ctx; } cRess_t; -static int createCResources(cRess_t *ress) +static int createCResources(cRess_t* ress) { ress->srcBufferSize = 4 MB; ress->srcBuffer = malloc(ress->srcBufferSize); diff --git a/tests/frametest.c b/tests/frametest.c index a5197ff..9f7cb8d 100644 --- a/tests/frametest.c +++ b/tests/frametest.c @@ -167,7 +167,7 @@ static unsigned FUZ_highbit(U32 v32) /*-******************************************************* * Tests *********************************************************/ -#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s\n", LZ4F_getErrorName(v)); goto _output_error; } +#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s \n", LZ4F_getErrorName(v)); goto _output_error; } #define CHECK(f) { LZ4F_errorCode_t const CHECK_V(err_ , f); } int basicTests(U32 seed, double compressibility) @@ -795,8 +795,9 @@ int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressi clock_t const startClock = clock(); clock_t const clockDuration = duration_s * CLOCKS_PER_SEC; # undef CHECK -# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ - DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } +# define EXIT_MSG(...) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ + DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } +# define CHECK(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__); } } /* Create buffers */ { size_t const creationStatus = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); @@ -950,9 +951,10 @@ int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressi CHECK(decSize != 0, "Frame decompression failed (error %i)", (int)decSize); if (totalOut) { /* otherwise, it's a skippable frame */ U64 const crcDecoded = XXH64_digest(&xxh64); - if (crcDecoded != crcOrig) locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst); - CHECK(crcDecoded != crcOrig, "Decompression corruption"); - } + if (crcDecoded != crcOrig) { + locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst); + EXIT_MSG("Decompression corruption"); + } } } } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 14cd8a0..78f90a1 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -327,12 +327,13 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c int result = 0; unsigned cycleNb; -# define FUZ_CHECKTEST(cond, ...) \ - if (cond) { \ - printf("Test %u : ", testNb); printf(__VA_ARGS__); \ - printf(" (seed %u, cycle %u) \n", seed, cycleNb); \ - exit(1); \ - } +# define EXIT_MSG(...) { \ + printf("Test %u : ", testNb); printf(__VA_ARGS__); \ + printf(" (seed %u, cycle %u) \n", seed, cycleNb); \ + exit(1); \ +} + +# define FUZ_CHECKTEST(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__) } } # define FUZ_DISPLAYTEST(...) { \ testNb++; \ @@ -666,8 +667,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c ret = LZ4_decompress_fast_usingDict(compressedBuffer, decodedBuffer+dictSize, blockSize, decodedBuffer, dictSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_decompress_fast_usingDict did not read all compressed block input"); { U32 const crcCheck = XXH32(decodedBuffer+dictSize, (size_t)blockSize, 0); - if (crcCheck!=crcOrig) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + if (crcCheck!=crcOrig) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + } } FUZ_DISPLAYTEST("test LZ4_decompress_safe_usingDict()"); @@ -706,9 +709,11 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c ret = LZ4_decompress_fast_usingDict(compressedBuffer, decodedBuffer, blockSize, dict, dictSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_decompress_fast_usingDict did not read all compressed block input"); FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_fast_usingDict overrun specified output buffer size"); - { U32 const crcCheck = XXH32(decodedBuffer, blockSize, 0); - if (crcCheck!=crcOrig) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); + if (crcCheck!=crcOrig) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + } } FUZ_DISPLAYTEST(); @@ -804,8 +809,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_decompress_fast_usingDict did not read all compressed block input"); FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_fast_usingDict overrun specified output buffer size"); { U32 const crcCheck = XXH32(decodedBuffer, blockSize, 0); - if (crcCheck!=crcOrig) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + if (crcCheck!=crcOrig) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize); + } } FUZ_DISPLAYTEST(); @@ -867,9 +874,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe_usingDict did not regenerate original data"); FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size"); { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); - if (crcCheck!=crcOrig) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe_usingDict corrupted decoded data"); - } + if (crcCheck!=crcOrig) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_safe_usingDict corrupted decoded data"); + } } /* Compress HC using external dictionary stream */ FUZ_DISPLAYTEST(); @@ -914,9 +922,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe_usingDict did not regenerate original data"); FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size"); { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); - if (crcCheck!=crcOrig) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe_usingDict corrupted decoded data"); - } + if (crcCheck!=crcOrig) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_safe_usingDict corrupted decoded data"); + } } /* Compress HC continue destSize */ FUZ_DISPLAYTEST(); @@ -938,9 +947,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(decodedBuffer[consumedSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size") { U32 const crcSrc = XXH32(block, (size_t)consumedSize, 0); U32 const crcDst = XXH32(decodedBuffer, (size_t)consumedSize, 0); - if (crcSrc!=crcDst) FUZ_findDiff(block, decodedBuffer); - FUZ_CHECKTEST(crcSrc!=crcDst, "LZ4_decompress_safe_usingDict corrupted decoded data"); - } + if (crcSrc!=crcDst) { + FUZ_findDiff(block, decodedBuffer); + EXIT_MSG("LZ4_decompress_safe_usingDict corrupted decoded data"); + } } } /* ***** End of tests *** */ @@ -981,9 +991,8 @@ static void FUZ_unitTests(int compressionLevel) const unsigned cycleNb= 0; char testInput[testInputSize]; char testCompressed[testCompressedSize]; - size_t const testVerifySize = testInputSize; char testVerify[testInputSize]; - char ringBuffer[ringBufferSize]; + char ringBuffer[ringBufferSize] = {0}; U32 randState = 1; /* Init */ @@ -1026,7 +1035,6 @@ static void FUZ_unitTests(int compressionLevel) U32 rNext = 0; U32 dNext = 0; const U32 dBufferSize = ringBufferSize + maxMessageSizeMask; - int compressedSize; XXH64_reset(&xxhOrig, 0); XXH64_reset(&xxhNewSafe, 0); @@ -1036,6 +1044,7 @@ static void FUZ_unitTests(int compressionLevel) LZ4_setStreamDecode(&decodeStateFast, NULL, 0); while (iNext + messageSize < testCompressedSize) { + int compressedSize; XXH64_update(&xxhOrig, testInput + iNext, messageSize); crcOrig = XXH64_digest(&xxhOrig); @@ -1231,7 +1240,6 @@ static void FUZ_unitTests(int compressionLevel) U32 rNext = 0; U32 dNext = 0; const U32 dBufferSize = ringBufferSize + maxMessageSizeMask; - int compressedSize; XXH64_reset(&xxhOrig, 0); XXH64_reset(&xxhNewSafe, 0); @@ -1241,6 +1249,7 @@ static void FUZ_unitTests(int compressionLevel) LZ4_setStreamDecode(&decodeStateFast, NULL, 0); while (iNext + messageSize < testCompressedSize) { + int compressedSize; XXH64_update(&xxhOrig, testInput + iNext, messageSize); crcOrig = XXH64_digest(&xxhOrig); @@ -1293,6 +1302,7 @@ static void FUZ_unitTests(int compressionLevel) int iNext = 0; int dNext = 0; int compressedSize; + size_t const testVerifySize = testInputSize; assert((size_t)dBufferSize * 2 + 1 < testVerifySize); /* space used by ringBufferSafe and ringBufferFast */ XXH64_reset(&xxhOrig, 0); @@ -1306,7 +1316,7 @@ static void FUZ_unitTests(int compressionLevel) /* first block */ messageSize = BSIZE1; /* note : we cheat a bit here, in theory no message should be > maxMessageSize. We just want to fill the decoding ring buffer once. */ - XXH64_update(&xxhOrig, testInput + iNext, messageSize); + XXH64_update(&xxhOrig, testInput + iNext, (size_t)messageSize); crcOrig = XXH64_digest(&xxhOrig); compressedSize = LZ4_compress_HC_continue(&sHC, testInput + iNext, testCompressed, messageSize, testCompressedSize-ringBufferSize); -- cgit v0.12 From 0b876db6d42ec22da0c635e97a0d690908f2104a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 16:06:02 -0700 Subject: address a few minor Visual warnings and created target cxx17build --- Makefile | 8 ++++++++ doc/lz4_manual.html | 29 +++++++++++++---------------- lib/lz4.h | 8 +++++--- lib/lz4hc.c | 1 + tests/frametest.c | 7 ++++--- tests/fullbench.c | 4 ++-- tests/fuzzer.c | 4 ++-- 7 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index f3c6ce2..f3844a1 100644 --- a/Makefile +++ b/Makefile @@ -181,6 +181,14 @@ gpptest gpptest32: clean CC=$(CC) $(MAKE) -C $(PRGDIR) all CFLAGS="$(CFLAGS)" CC=$(CC) $(MAKE) -C $(TESTDIR) all CFLAGS="$(CFLAGS)" +cxx17build : CC = "$(CXX) -Wno-deprecated" +cxx17build : CFLAGS = -std=c++17 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror +cxx17build : clean + $(CXX) -v + CC=$(CC) $(MAKE) -C $(LZ4DIR) all CFLAGS="$(CFLAGS)" + CC=$(CC) $(MAKE) -C $(PRGDIR) all CFLAGS="$(CFLAGS)" + CC=$(CC) $(MAKE) -C $(TESTDIR) all CFLAGS="$(CFLAGS)" + ctocpptest: LIBCC="$(CC)" ctocpptest: TESTCC="$(CXX)" ctocpptest: CFLAGS="" diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html index 356a60d..ee43b8a 100644 --- a/doc/lz4_manual.html +++ b/doc/lz4_manual.html @@ -454,21 +454,18 @@ union LZ4_streamDecode_u {


-
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") LZ4LIB_API
-int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") LZ4LIB_API
-int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") LZ4LIB_API
-int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
-

These functions used to be a bit faster than LZ4_decompress_safe(), - but situation has changed in recent versions. - Now, `LZ4_decompress_safe()` is as fast and sometimes even faster than `LZ4_decompress_fast()`. - Moreover, LZ4_decompress_safe() is protected vs malformed input, while `LZ4_decompress_fast()` is not, making it a security liability. +

These functions used to be faster than LZ4_decompress_safe(), + but it has changed, and they are now slower than LZ4_decompress_safe(). + This is because LZ4_decompress_fast() doesn't know the input size, + and therefore must progress more cautiously in the input buffer to not read beyond the end of block. + On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. - Last LZ4_decompress_fast() specificity is that it can decompress a block without knowing its compressed size. - Note that even that functionality could be achieved in a more secure manner if need be, - though it would require new prototypes, and adaptation of the implementation to this new use case. + The last remaining LZ4_decompress_fast() specificity is that + it can decompress a block without knowing its compressed size. + Such functionality could be achieved in a more secure manner, + by also providing the maximum size of input buffer, + but it would require new prototypes, and adaptation of the implementation to this new use case. Parameters: originalSize : is the uncompressed size to regenerate. @@ -477,9 +474,9 @@ int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, The function expects to finish at block's end exactly. If the source stream is detected malformed, the function stops decoding and returns a negative result. note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer. - However, since it doesn't know its 'src' size, it may read an unknown amount of input, and overflow input buffer. - Also, since match offsets are not validated, match reads from 'src' may underflow. - These issues never happen if input data is correct. + However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds. + Also, since match offsets are not validated, match reads from 'src' may underflow too. + These issues never happen if input (compressed) data is correct. But they may happen if input data is invalid (error or intentional tampering). As a consequence, use these functions in trusted environments with trusted data **only**. diff --git a/lib/lz4.h b/lib/lz4.h index 962f5e6..737a0c7 100644 --- a/lib/lz4.h +++ b/lib/lz4.h @@ -638,9 +638,11 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4 * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. * - * Only LZ4_decompress_fast() specificity is that it can decompress a block without knowing its compressed size. - * Even that functionality could be achieved in a more secure manner if need be, - * though it would require new prototypes, and adaptation of the implementation to this new use case. + * The last remaining LZ4_decompress_fast() specificity is that + * it can decompress a block without knowing its compressed size. + * Such functionality could be achieved in a more secure manner, + * by also providing the maximum size of input buffer, + * but it would require new prototypes, and adaptation of the implementation to this new use case. * * Parameters: * originalSize : is the uncompressed size to regenerate. diff --git a/lib/lz4hc.c b/lib/lz4hc.c index d5f6743..031df8f 100644 --- a/lib/lz4hc.c +++ b/lib/lz4hc.c @@ -1396,6 +1396,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, } } } /* for (cur = 1; cur <= last_match_pos; cur++) */ + assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS); best_mlen = opt[last_match_pos].mlen; best_off = opt[last_match_pos].off; cur = last_match_pos - best_mlen; diff --git a/tests/frametest.c b/tests/frametest.c index 9f7cb8d..bf95beb 100644 --- a/tests/frametest.c +++ b/tests/frametest.c @@ -667,8 +667,8 @@ int basicTests(U32 seed, double compressibility) for (blockSizeID = 4; blockSizeID < 8; ++blockSizeID) { result = LZ4F_getBlockSize(blockSizeID); CHECK(result); - DISPLAYLEVEL(3, "Returned block size of %zu bytes for blockID %u \n", - result, blockSizeID); + DISPLAYLEVEL(3, "Returned block size of %u bytes for blockID %u \n", + (unsigned)result, blockSizeID); } /* Test an invalid input that's too large */ @@ -770,7 +770,8 @@ static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, un const BYTE* b2=(const BYTE*)buff2; DISPLAY("locateBuffDiff: looking for error position \n"); if (nonContiguous) { - DISPLAY("mode %u: non-contiguous output (%zu bytes), cannot search \n", nonContiguous, size); + DISPLAY("mode %u: non-contiguous output (%u bytes), cannot search \n", + nonContiguous, (unsigned)size); return; } while (p < size && b1[p]==b2[p]) p++; diff --git a/tests/fullbench.c b/tests/fullbench.c index 1a52aab..d2af662 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -162,13 +162,13 @@ static LZ4_stream_t LZ4_stream; static void local_LZ4_resetDictT(void) { void* const r = LZ4_initStream(&LZ4_stream, sizeof(LZ4_stream)); - assert(r != NULL); + assert(r != NULL); (void)r; } static void local_LZ4_createStream(void) { void* const r = LZ4_initStream(&LZ4_stream, sizeof(LZ4_stream)); - assert(r != NULL); + assert(r != NULL); (void)r; } static int local_LZ4_saveDict(const char* in, char* out, int inSize) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 78f90a1..9908a7b 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -490,6 +490,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test decompress_fast() with input buffer size exactly correct => must not read out of bound */ { char* const cBuffer_exact = (char*)malloc((size_t)compressedSize); assert(cBuffer_exact != NULL); + assert(compressedSize <= compressedBufferSize); memcpy(cBuffer_exact, compressedBuffer, compressedSize); /* Test decoding with output size exactly correct => must work */ @@ -1302,9 +1303,8 @@ static void FUZ_unitTests(int compressionLevel) int iNext = 0; int dNext = 0; int compressedSize; - size_t const testVerifySize = testInputSize; - assert((size_t)dBufferSize * 2 + 1 < testVerifySize); /* space used by ringBufferSafe and ringBufferFast */ + assert((size_t)dBufferSize * 2 + 1 < testInputSize); /* space used by ringBufferSafe and ringBufferFast */ XXH64_reset(&xxhOrig, 0); XXH64_reset(&xxhNewSafe, 0); XXH64_reset(&xxhNewFast, 0); -- cgit v0.12 From 6cb084ed368ab8a4df3b48eb9683101c5e518418 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 16:41:27 -0700 Subject: fuzzer: reduce stack usage to please Visual static analyzer --- tests/fuzzer.c | 124 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 9908a7b..a99f2f3 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -319,8 +319,8 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c void* const lowAddrBuffer = FUZ_createLowAddr(labSize); void* const stateLZ4 = malloc((size_t)LZ4_sizeofState()); void* const stateLZ4HC = malloc((size_t)LZ4_sizeofStateHC()); - LZ4_stream_t LZ4dict; - LZ4_streamHC_t LZ4dictHC; + LZ4_stream_t LZ4dictBody; + LZ4_streamHC_t* LZ4dictHC = LZ4_createStreamHC(); U32 coreRandState = seed; clock_t const clockStart = clock(); clock_t const clockDuration = (clock_t)duration_s * CLOCKS_PER_SEC; @@ -346,12 +346,11 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* init */ - if(!CNBuffer || !compressedBuffer || !decodedBuffer) { + if(!CNBuffer || !compressedBuffer || !decodedBuffer || !LZ4dictHC) { DISPLAY("Not enough memory to start fuzzer tests"); exit(1); } - if ( LZ4_initStream(&LZ4dict, sizeof(LZ4dict)) == NULL) abort(); - if ( LZ4_initStreamHC(&LZ4dictHC, sizeof(LZ4dictHC)) == NULL) abort(); + if ( LZ4_initStream(&LZ4dictBody, sizeof(LZ4dictBody)) == NULL) abort(); { U32 randState = coreRandState ^ PRIME3; FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState); } @@ -455,42 +454,42 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test compression HC */ FUZ_DISPLAYTEST("test LZ4_compress_HC()"); - ret = LZ4_compress_HC(block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); - FUZ_CHECKTEST(ret==0, "LZ4_compress_HC() failed"); - HCcompressedSize = ret; + HCcompressedSize = LZ4_compress_HC(block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); + FUZ_CHECKTEST(HCcompressedSize==0, "LZ4_compress_HC() failed"); /* Test compression HC using external state */ FUZ_DISPLAYTEST("test LZ4_compress_HC_extStateHC()"); - ret = LZ4_compress_HC_extStateHC(stateLZ4HC, block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); - FUZ_CHECKTEST(ret==0, "LZ4_compress_HC_extStateHC() failed") + { int const r = LZ4_compress_HC_extStateHC(stateLZ4HC, block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); + FUZ_CHECKTEST(r==0, "LZ4_compress_HC_extStateHC() failed") + } /* Test compression HC using fast reset external state */ FUZ_DISPLAYTEST("test LZ4_compress_HC_extStateHC_fastReset()"); - ret = LZ4_compress_HC_extStateHC_fastReset(stateLZ4HC, block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); - FUZ_CHECKTEST(ret==0, "LZ4_compress_HC_extStateHC_fastReset() failed"); + { int const r = LZ4_compress_HC_extStateHC_fastReset(stateLZ4HC, block, compressedBuffer, blockSize, (int)compressedBufferSize, compressionLevel); + FUZ_CHECKTEST(r==0, "LZ4_compress_HC_extStateHC_fastReset() failed"); + } /* Test compression using external state */ FUZ_DISPLAYTEST("test LZ4_compress_fast_extState()"); - ret = LZ4_compress_fast_extState(stateLZ4, block, compressedBuffer, blockSize, (int)compressedBufferSize, 8); - FUZ_CHECKTEST(ret==0, "LZ4_compress_fast_extState() failed"); + { int const r = LZ4_compress_fast_extState(stateLZ4, block, compressedBuffer, blockSize, (int)compressedBufferSize, 8); + FUZ_CHECKTEST(r==0, "LZ4_compress_fast_extState() failed"); } /* Test compression using fast reset external state*/ FUZ_DISPLAYTEST(); - ret = LZ4_compress_fast_extState_fastReset(stateLZ4, block, compressedBuffer, blockSize, (int)compressedBufferSize, 8); - FUZ_CHECKTEST(ret==0, "LZ4_compress_fast_extState_fastReset() failed"); + { int const r = LZ4_compress_fast_extState_fastReset(stateLZ4, block, compressedBuffer, blockSize, (int)compressedBufferSize, 8); + FUZ_CHECKTEST(r==0, "LZ4_compress_fast_extState_fastReset() failed"); } /* Test compression */ FUZ_DISPLAYTEST("test LZ4_compress_default()"); - ret = LZ4_compress_default(block, compressedBuffer, blockSize, (int)compressedBufferSize); - FUZ_CHECKTEST(ret<=0, "LZ4_compress_default() failed"); - compressedSize = ret; + compressedSize = LZ4_compress_default(block, compressedBuffer, blockSize, (int)compressedBufferSize); + FUZ_CHECKTEST(compressedSize<=0, "LZ4_compress_default() failed"); /* Decompression tests */ /* Test decompress_fast() with input buffer size exactly correct => must not read out of bound */ { char* const cBuffer_exact = (char*)malloc((size_t)compressedSize); assert(cBuffer_exact != NULL); - assert(compressedSize <= compressedBufferSize); + assert(compressedSize <= (int)compressedBufferSize); memcpy(cBuffer_exact, compressedBuffer, compressedSize); /* Test decoding with output size exactly correct => must work */ @@ -685,20 +684,20 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST("test LZ4_compress_fast_continue(), with non-contiguous dictionary"); dict -= (size_t)(FUZ_rand(&randState) & 0xF) + 1; /* create space, so now dictionary is an ExtDict */ if (dict < (char*)CNBuffer) dict = (char*)CNBuffer; - LZ4_loadDict(&LZ4dict, dict, dictSize); - blockContinueCompressedSize = LZ4_compress_fast_continue(&LZ4dict, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); + LZ4_loadDict(&LZ4dictBody, dict, dictSize); + blockContinueCompressedSize = LZ4_compress_fast_continue(&LZ4dictBody, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_fast_continue failed"); FUZ_DISPLAYTEST("test LZ4_compress_fast_continue() with dictionary but with an output buffer too short by one byte"); - LZ4_loadDict(&LZ4dict, dict, dictSize); - ret = LZ4_compress_fast_continue(&LZ4dict, block, compressedBuffer, blockSize, blockContinueCompressedSize-1, 1); + LZ4_loadDict(&LZ4dictBody, dict, dictSize); + ret = LZ4_compress_fast_continue(&LZ4dictBody, block, compressedBuffer, blockSize, blockContinueCompressedSize-1, 1); FUZ_CHECKTEST(ret>0, "LZ4_compress_fast_continue using ExtDict should fail : one missing byte for output buffer : %i written, %i buffer", ret, blockContinueCompressedSize); FUZ_DISPLAYTEST("test LZ4_compress_fast_continue() with dictionary loaded with LZ4_loadDict()"); DISPLAYLEVEL(5, " compress %i bytes from buffer(%p) into dst(%p) using dict(%p) of size %i \n", blockSize, (const void *)block, (void *)decodedBuffer, (const void *)dict, dictSize); - LZ4_loadDict(&LZ4dict, dict, dictSize); - ret = LZ4_compress_fast_continue(&LZ4dict, block, compressedBuffer, blockSize, blockContinueCompressedSize, 1); + LZ4_loadDict(&LZ4dictBody, dict, dictSize); + ret = LZ4_compress_fast_continue(&LZ4dictBody, block, compressedBuffer, blockSize, blockContinueCompressedSize, 1); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_fast_continue should work : enough size available within output buffer"); @@ -754,15 +753,15 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c U32 expectedCrc; FUZ_DISPLAYTEST("LZ4_compress_fast_continue() after LZ4_loadDict()"); - LZ4_loadDict(&LZ4dict, dict, dictSize); - expectedSize = LZ4_compress_fast_continue(&LZ4dict, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); + LZ4_loadDict(&LZ4dictBody, dict, dictSize); + expectedSize = LZ4_compress_fast_continue(&LZ4dictBody, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); FUZ_CHECKTEST(expectedSize<=0, "LZ4_compress_fast_continue reference compression for extDictCtx should have succeeded"); expectedCrc = XXH32(compressedBuffer, expectedSize, 0); FUZ_DISPLAYTEST("LZ4_compress_fast_continue() after LZ4_attach_dictionary()"); - LZ4_loadDict(&LZ4dict, dict, dictSize); + LZ4_loadDict(&LZ4dictBody, dict, dictSize); LZ4_initStream(&LZ4_stream, sizeof(LZ4_stream)); - LZ4_attach_dictionary(&LZ4_stream, &LZ4dict); + LZ4_attach_dictionary(&LZ4_stream, &LZ4dictBody); blockContinueCompressedSize = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_fast_continue using extDictCtx failed"); FUZ_CHECKTEST(LZ4_stream.internal_donotuse.dirty, "context should be good"); @@ -777,14 +776,14 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST("LZ4_compress_fast_continue() after LZ4_attach_dictionary(), but output buffer is 1 byte too short"); LZ4_resetStream_fast(&LZ4_stream); - LZ4_attach_dictionary(&LZ4_stream, &LZ4dict); + LZ4_attach_dictionary(&LZ4_stream, &LZ4dictBody); ret = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, blockContinueCompressedSize-1, 1); FUZ_CHECKTEST(ret>0, "LZ4_compress_fast_continue using extDictCtx should fail : one missing byte for output buffer : %i written, %i buffer", ret, blockContinueCompressedSize); /* note : context is no longer dirty after a failed compressed block */ FUZ_DISPLAYTEST(); LZ4_resetStream_fast(&LZ4_stream); - LZ4_attach_dictionary(&LZ4_stream, &LZ4dict); + LZ4_attach_dictionary(&LZ4_stream, &LZ4dictBody); ret = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, blockContinueCompressedSize, 1); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_fast_continue using extDictCtx should work : enough size available within output buffer"); @@ -794,7 +793,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST(); LZ4_resetStream_fast(&LZ4_stream); - LZ4_attach_dictionary(&LZ4_stream, &LZ4dict); + LZ4_attach_dictionary(&LZ4_stream, &LZ4dictBody); ret = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, blockContinueCompressedSize, 1); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_fast_continue using extDictCtx with re-used context should work : enough size available within output buffer"); @@ -850,24 +849,24 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST("LZ4_compress_HC_continue with an external dictionary"); dict -= (FUZ_rand(&randState) & 7); /* even bigger separation */ if (dict < (char*)CNBuffer) dict = (char*)CNBuffer; - LZ4_loadDictHC(&LZ4dictHC, dict, dictSize); - LZ4_setCompressionLevel (&LZ4dictHC, compressionLevel); - blockContinueCompressedSize = LZ4_compress_HC_continue(&LZ4dictHC, block, compressedBuffer, blockSize, (int)compressedBufferSize); + LZ4_loadDictHC(LZ4dictHC, dict, dictSize); + LZ4_setCompressionLevel (LZ4dictHC, compressionLevel); + blockContinueCompressedSize = LZ4_compress_HC_continue(LZ4dictHC, block, compressedBuffer, blockSize, (int)compressedBufferSize); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_HC_continue failed"); - FUZ_CHECKTEST(LZ4dictHC.internal_donotuse.dirty, "Context should be clean"); + FUZ_CHECKTEST(LZ4dictHC->internal_donotuse.dirty, "Context should be clean"); FUZ_DISPLAYTEST("LZ4_compress_HC_continue with same external dictionary, but output buffer 1 byte too short"); - LZ4_loadDictHC(&LZ4dictHC, dict, dictSize); - ret = LZ4_compress_HC_continue(&LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1); + LZ4_loadDictHC(LZ4dictHC, dict, dictSize); + ret = LZ4_compress_HC_continue(LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1); FUZ_CHECKTEST(ret>0, "LZ4_compress_HC_continue using ExtDict should fail : one missing byte for output buffer (expected %i, but result=%i)", blockContinueCompressedSize, ret); /* note : context is no longer dirty after a failed compressed block */ FUZ_DISPLAYTEST("LZ4_compress_HC_continue with same external dictionary, and output buffer exactly the right size"); - LZ4_loadDictHC(&LZ4dictHC, dict, dictSize); - ret = LZ4_compress_HC_continue(&LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); + LZ4_loadDictHC(LZ4dictHC, dict, dictSize); + ret = LZ4_compress_HC_continue(LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue size is different : ret(%i) != expected(%i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue should work : enough size available within output buffer"); - FUZ_CHECKTEST(LZ4dictHC.internal_donotuse.dirty, "Context should be clean"); + FUZ_CHECKTEST(LZ4dictHC->internal_donotuse.dirty, "Context should be clean"); FUZ_DISPLAYTEST(); decodedBuffer[blockSize] = 0; @@ -886,8 +885,8 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c LZ4_streamHC_t LZ4_streamHC; LZ4_initStreamHC(&LZ4_streamHC, sizeof(LZ4_streamHC)); - LZ4_loadDictHC(&LZ4dictHC, dict, dictSize); - LZ4_attach_HC_dictionary(&LZ4_streamHC, &LZ4dictHC); + LZ4_loadDictHC(LZ4dictHC, dict, dictSize); + LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); LZ4_setCompressionLevel (&LZ4_streamHC, compressionLevel); blockContinueCompressedSize = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, (int)compressedBufferSize); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_HC_continue with ExtDictCtx failed"); @@ -895,14 +894,14 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST(); LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, &LZ4dictHC); + LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1); FUZ_CHECKTEST(ret>0, "LZ4_compress_HC_continue using ExtDictCtx should fail : one missing byte for output buffer (%i != %i)", ret, blockContinueCompressedSize); /* note : context is no longer dirty after a failed compressed block */ FUZ_DISPLAYTEST(); LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, &LZ4dictHC); + LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue using ExtDictCtx should work : enough size available within output buffer"); @@ -910,7 +909,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST(); LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, &LZ4dictHC); + LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx and fast reset size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue using ExtDictCtx and fast reset should work : enough size available within output buffer"); @@ -933,9 +932,9 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c { int const availableSpace = (int)(FUZ_rand(&randState) % blockSize) + 5; int consumedSize = blockSize; FUZ_DISPLAYTEST(); - LZ4_loadDictHC(&LZ4dictHC, dict, dictSize); - LZ4_setCompressionLevel(&LZ4dictHC, compressionLevel); - blockContinueCompressedSize = LZ4_compress_HC_continue_destSize(&LZ4dictHC, block, compressedBuffer, &consumedSize, availableSpace); + LZ4_loadDictHC(LZ4dictHC, dict, dictSize); + LZ4_setCompressionLevel(LZ4dictHC, compressionLevel); + blockContinueCompressedSize = LZ4_compress_HC_continue_destSize(LZ4dictHC, block, compressedBuffer, &consumedSize, availableSpace); DISPLAYLEVEL(5, " LZ4_compress_HC_continue_destSize : compressed %6i/%6i into %6i/%6i at cLevel=%i\n", consumedSize, blockSize, blockContinueCompressedSize, availableSpace, compressionLevel); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_HC_continue_destSize failed"); FUZ_CHECKTEST(blockContinueCompressedSize > availableSpace, "LZ4_compress_HC_continue_destSize write overflow"); @@ -975,6 +974,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c free(compressedBuffer); free(decodedBuffer); FUZ_freeLowAddr(lowAddrBuffer, labSize); + LZ4_freeStreamHC(LZ4dictHC); free(stateLZ4); free(stateLZ4HC); return result; @@ -990,28 +990,31 @@ static void FUZ_unitTests(int compressionLevel) const unsigned testNb = 0; const unsigned seed = 0; const unsigned cycleNb= 0; - char testInput[testInputSize]; - char testCompressed[testCompressedSize]; - char testVerify[testInputSize]; + char* testInput = (char*)malloc(testInputSize); + char* testCompressed = (char*)malloc(testCompressedSize); + char* testVerify = (char*)malloc(testInputSize); char ringBuffer[ringBufferSize] = {0}; U32 randState = 1; /* Init */ + if (!testInput || !testCompressed || !testVerify) { + EXIT_MSG("not enough memory for FUZ_unitTests"); + } FUZ_fillCompressibleNoiseBuffer(testInput, testInputSize, 0.50, &randState); /* 32-bits address space overflow test */ FUZ_AddressOverflow(); /* LZ4 streaming tests */ - { LZ4_stream_t* statePtr; - LZ4_stream_t streamingState; + { LZ4_stream_t streamingState; U64 crcOrig; int result; /* Allocation test */ - statePtr = LZ4_createStream(); - FUZ_CHECKTEST(statePtr==NULL, "LZ4_createStream() allocation failed"); - LZ4_freeStream(statePtr); + { LZ4_stream_t* const statePtr = LZ4_createStream(); + FUZ_CHECKTEST(statePtr==NULL, "LZ4_createStream() allocation failed"); + LZ4_freeStream(statePtr); + } /* simple compression test */ crcOrig = XXH64(testInput, testCompressedSize, 0); @@ -1389,6 +1392,11 @@ static void FUZ_unitTests(int compressionLevel) } } + /* clean up */ + free(testInput); + free(testCompressed); + free(testVerify); + printf("All unit tests completed successfully compressionLevel=%d \n", compressionLevel); return; } -- cgit v0.12 From 4790994568d4d3ba492857c4c567ea6517588a45 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 17:12:14 -0700 Subject: fuzzer : reduced stack usage --- tests/fuzzer.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index a99f2f3..ffbeefc 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -881,39 +881,39 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Compress HC using external dictionary stream */ FUZ_DISPLAYTEST(); - { - LZ4_streamHC_t LZ4_streamHC; - LZ4_initStreamHC(&LZ4_streamHC, sizeof(LZ4_streamHC)); + { LZ4_streamHC_t* LZ4_streamHC = LZ4_createStreamHC(); LZ4_loadDictHC(LZ4dictHC, dict, dictSize); - LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); - LZ4_setCompressionLevel (&LZ4_streamHC, compressionLevel); - blockContinueCompressedSize = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, (int)compressedBufferSize); + LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); + LZ4_setCompressionLevel (LZ4_streamHC, compressionLevel); + blockContinueCompressedSize = LZ4_compress_HC_continue(LZ4_streamHC, block, compressedBuffer, blockSize, (int)compressedBufferSize); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_HC_continue with ExtDictCtx failed"); - FUZ_CHECKTEST(LZ4_streamHC.internal_donotuse.dirty, "Context should be clean"); + FUZ_CHECKTEST(LZ4_streamHC->internal_donotuse.dirty, "Context should be clean"); FUZ_DISPLAYTEST(); - LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); - ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1); + LZ4_resetStreamHC_fast (LZ4_streamHC, compressionLevel); + LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); + ret = LZ4_compress_HC_continue(LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1); FUZ_CHECKTEST(ret>0, "LZ4_compress_HC_continue using ExtDictCtx should fail : one missing byte for output buffer (%i != %i)", ret, blockContinueCompressedSize); /* note : context is no longer dirty after a failed compressed block */ FUZ_DISPLAYTEST(); - LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); - ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); + LZ4_resetStreamHC_fast (LZ4_streamHC, compressionLevel); + LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); + ret = LZ4_compress_HC_continue(LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue using ExtDictCtx should work : enough size available within output buffer"); - FUZ_CHECKTEST(LZ4_streamHC.internal_donotuse.dirty, "Context should be clean"); + FUZ_CHECKTEST(LZ4_streamHC->internal_donotuse.dirty, "Context should be clean"); FUZ_DISPLAYTEST(); - LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel); - LZ4_attach_HC_dictionary(&LZ4_streamHC, LZ4dictHC); - ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); + LZ4_resetStreamHC_fast (LZ4_streamHC, compressionLevel); + LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); + ret = LZ4_compress_HC_continue(LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx and fast reset size is different (%i != %i)", ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue using ExtDictCtx and fast reset should work : enough size available within output buffer"); - FUZ_CHECKTEST(LZ4_streamHC.internal_donotuse.dirty, "Context should be clean"); + FUZ_CHECKTEST(LZ4_streamHC->internal_donotuse.dirty, "Context should be clean"); + + LZ4_freeStreamHC(LZ4_streamHC); } FUZ_DISPLAYTEST(); -- cgit v0.12 From 4e4f1ad623cca9ebd212400b5783c63fd76dc868 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 17:26:01 -0700 Subject: ensure list of names is large enough --- programs/util.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/programs/util.h b/programs/util.h index 6a35481..1dd515c 100644 --- a/programs/util.h +++ b/programs/util.h @@ -379,7 +379,7 @@ UTIL_STATIC U64 UTIL_getTotalFileSize(const char** fileNamesTable, unsigned nbFi */ UTIL_STATIC void* UTIL_realloc(void* ptr, size_t size) { - void* newptr = realloc(ptr, size); + void* const newptr = realloc(ptr, size); if (newptr) return newptr; free(ptr); return NULL; @@ -529,7 +529,8 @@ UTIL_STATIC int UTIL_prepareFileList(const char* dirName, char** bufStart, size_ * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called. */ UTIL_STATIC const char** -UTIL_createFileList(const char** inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb) +UTIL_createFileList(const char** inputNames, unsigned inputNamesNb, + char** allocatedBuffer, unsigned* allocatedNamesNb) { size_t pos; unsigned i, nbFiles; @@ -543,16 +544,14 @@ UTIL_createFileList(const char** inputNames, unsigned inputNamesNb, char** alloc if (!UTIL_isDirectory(inputNames[i])) { size_t const len = strlen(inputNames[i]); if (pos + len >= bufSize) { - size_t newListSize = bufSize + LIST_SIZE_INCREASE; - buf = (char*)UTIL_realloc(buf, newListSize); - bufSize = newListSize; + while (pos + len >= bufSize) bufSize += LIST_SIZE_INCREASE; + buf = (char*)UTIL_realloc(buf, bufSize); if (!buf) return NULL; } - if (pos + len < bufSize) { - strncpy(buf + pos, inputNames[i], bufSize - pos); - pos += len + 1; - nbFiles++; - } + assert(pos + len < bufSize); + strncpy(buf + pos, inputNames[i], bufSize - pos); + pos += len + 1; + nbFiles++; } else { char* bufend = buf + bufSize; nbFiles += (unsigned)UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend); -- cgit v0.12 From ae199124e5aef12f6e467bc8cf30bffece55d55c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Apr 2019 18:50:51 -0700 Subject: fixed read-after input in LZ4_decompress_safe() --- lib/lz4.c | 57 ++++++++++----------- lib/lz4hc.c | 2 +- tests/fuzzer.c | 156 ++++++++++++++++++++++++++++++--------------------------- 3 files changed, 112 insertions(+), 103 deletions(-) diff --git a/lib/lz4.c b/lib/lz4.c index c38932e..e614c45 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -136,7 +136,7 @@ #endif /* LZ4_FORCE_INLINE */ /* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE - * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, + * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8, * together with a simple 8-byte copy loop as a fall-back path. * However, this optimization hurts the decompression speed by >30%, * because the execution does not go to the optimized loop @@ -144,10 +144,10 @@ * before going to the fall-back path become useless overhead. * This optimization happens only with the -O3 flag, and -O2 generates * a simple 8-byte copy loop. - * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy + * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8 * functions are annotated with __attribute__((optimize("O2"))), - * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute - * of LZ4_wildCopy does not affect the compression speed. + * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute + * of LZ4_wildCopy8 does not affect the compression speed. */ #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__) # define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2"))) @@ -301,7 +301,7 @@ static void LZ4_writeLE16(void* memPtr, U16 value) /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ LZ4_FORCE_O2_INLINE_GCC_PPC64LE -void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) +void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; @@ -342,7 +342,7 @@ LZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, con srcPtr += 8; } - LZ4_wildCopy(dstPtr, srcPtr, dstEnd); + LZ4_wildCopy8(dstPtr, srcPtr, dstEnd); } /* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd @@ -946,7 +946,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( else *token = (BYTE)(litLength<= FASTLOOP_SAFE_DISTANCE); - + if (endOnInput) assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ @@ -1666,27 +1668,26 @@ LZ4_decompress_generic( /* copy literals */ cpy = op+length; LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); - if ( ((endOnInput) && ((cpy>oend-FASTLOOP_SAFE_DISTANCE) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-FASTLOOP_SAFE_DISTANCE)) ) - { - goto safe_literal_copy; - } - if (endOnInput) + if (endOnInput) { /* LZ4_decompress_safe() */ + if ((cpy>oend-32) || (ip+length>iend-32)) goto safe_literal_copy; LZ4_wildCopy32(op, ip, cpy); - else - LZ4_wildCopy(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : it doesn't know input length, and only relies on end-of-block properties */ + } else { /* LZ4_decompress_fast() */ + if (cpy>oend-8) goto safe_literal_copy; + LZ4_wildCopy8(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : + * it doesn't know input length, and only relies on end-of-block properties */ + } ip += length; op = cpy; } else { cpy = op+length; - /* We don't need to check oend, since we check it once for each loop below */ - if ( ((endOnInput) && (ip+16>iend-(2+1+LASTLITERALS)))) - { - goto safe_literal_copy; - } - /* Literals can only be 14, but hope compilers optimize if we copy by a register size */ - if (endOnInput) + if (endOnInput) { /* LZ4_decompress_safe() */ + DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); + /* We don't need to check oend, since we check it once for each loop below */ + if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) goto safe_literal_copy; + /* Literals can only be 14, but hope compilers optimize if we copy by a register size */ memcpy(op, ip, 16); - else { /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : it doesn't know input length, and only relies on end-of-block properties */ + } else { /* LZ4_decompress_fast() */ + /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time : + * it doesn't know input length, and relies on end-of-block properties */ memcpy(op, ip, 8); if (length > 8) memcpy(op+8, ip+8, 8); } @@ -1852,7 +1853,7 @@ LZ4_decompress_generic( } } else { - LZ4_wildCopy(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */ + LZ4_wildCopy8(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */ ip += length; op = cpy; } @@ -1947,14 +1948,14 @@ LZ4_decompress_generic( BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1); if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); + LZ4_wildCopy8(op, match, oCopyLimit); match += oCopyLimit - op; op = oCopyLimit; } while (op < cpy) *op++ = *match++; } else { memcpy(op, match, 8); - if (length > 16) LZ4_wildCopy(op+8, match+8, cpy); + if (length > 16) LZ4_wildCopy8(op+8, match+8, cpy); } op = cpy; /* wildcopy correction */ } diff --git a/lib/lz4hc.c b/lib/lz4hc.c index 031df8f..936f739 100644 --- a/lib/lz4hc.c +++ b/lib/lz4hc.c @@ -442,7 +442,7 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence ( } /* Copy Literals */ - LZ4_wildCopy(*op, *anchor, (*op) + length); + LZ4_wildCopy8(*op, *anchor, (*op) + length); *op += length; /* Encode Offset */ diff --git a/tests/fuzzer.c b/tests/fuzzer.c index ffbeefc..a5b5c93 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -494,9 +494,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test decoding with output size exactly correct => must work */ FUZ_DISPLAYTEST("LZ4_decompress_fast() with exact output buffer"); - ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize); - FUZ_CHECKTEST(ret<0, "LZ4_decompress_fast failed despite correct space"); - FUZ_CHECKTEST(ret!=compressedSize, "LZ4_decompress_fast failed : did not fully read compressed data"); + { int const r = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize); + FUZ_CHECKTEST(r<0, "LZ4_decompress_fast failed despite correct space"); + FUZ_CHECKTEST(r!=compressedSize, "LZ4_decompress_fast failed : did not fully read compressed data"); + } { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast corrupted decoded data"); } @@ -504,92 +505,75 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test decoding with one byte missing => must fail */ FUZ_DISPLAYTEST("LZ4_decompress_fast() with output buffer 1-byte too short"); decodedBuffer[blockSize-1] = 0; - ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize-1); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small"); + { int const r = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize-1); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small"); + } FUZ_CHECKTEST(decodedBuffer[blockSize-1]!=0, "LZ4_decompress_fast overrun specified output buffer"); /* Test decoding with one byte too much => must fail */ FUZ_DISPLAYTEST(); - ret = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize+1); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too large"); - - free(cBuffer_exact); - } - - /* Test decoding with empty input */ - FUZ_DISPLAYTEST("LZ4_decompress_safe() with empty input"); - LZ4_decompress_safe(compressedBuffer, decodedBuffer, 0, blockSize); + { int const r = LZ4_decompress_fast(cBuffer_exact, decodedBuffer, blockSize+1); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_fast should have failed, due to Output Size being too large"); + } - /* Test decoding with a one byte input */ - FUZ_DISPLAYTEST("LZ4_decompress_safe() with one byte input"); - { char const tmp = (char)0xFF; - LZ4_decompress_safe(&tmp, decodedBuffer, 1, blockSize); - } + /* Test decoding with output size exactly what's necessary => must work */ + FUZ_DISPLAYTEST(); + decodedBuffer[blockSize] = 0; + { int const r = LZ4_decompress_safe(cBuffer_exact, decodedBuffer, compressedSize, blockSize); + FUZ_CHECKTEST(r<0, "LZ4_decompress_safe failed despite sufficient space"); + FUZ_CHECKTEST(r!=blockSize, "LZ4_decompress_safe did not regenerate original data"); + } + FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe overrun specified output buffer size"); + { U32 const crcCheck = XXH32(decodedBuffer, blockSize, 0); + FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data"); + } - /* Test decoding shortcut edge case */ - FUZ_DISPLAYTEST("LZ4_decompress_safe() with shortcut edge case"); - { char tmp[17]; - /* 14 bytes of literals, followed by a 14 byte match. - * Should not read beyond the end of the buffer. - * See https://github.com/lz4/lz4/issues/508. */ - *tmp = (char)0xEE; - memset(tmp + 1, 0, 14); - tmp[15] = 14; - tmp[16] = 0; - ret = LZ4_decompress_safe(tmp, decodedBuffer, sizeof(tmp), blockSize); - FUZ_CHECKTEST(ret >= 0, "LZ4_decompress_safe() should fail"); - } + /* Test decoding with more than enough output size => must work */ + FUZ_DISPLAYTEST(); + decodedBuffer[blockSize] = 0; + decodedBuffer[blockSize+1] = 0; + { int const r = LZ4_decompress_safe(cBuffer_exact, decodedBuffer, compressedSize, blockSize+1); + FUZ_CHECKTEST(r<0, "LZ4_decompress_safe failed despite amply sufficient space"); + FUZ_CHECKTEST(r!=blockSize, "LZ4_decompress_safe did not regenerate original data"); + } + FUZ_CHECKTEST(decodedBuffer[blockSize+1], "LZ4_decompress_safe overrun specified output buffer size"); + { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); + FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data"); + } + /* Test decoding with output size being one byte too short => must fail */ + FUZ_DISPLAYTEST(); + decodedBuffer[blockSize-1] = 0; + { int const r = LZ4_decompress_safe(cBuffer_exact, decodedBuffer, compressedSize, blockSize-1); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_safe should have failed, due to Output Size being one byte too short"); + } + FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_safe overrun specified output buffer size"); - /* Test decoding with output size exactly what's necessary => must work */ - FUZ_DISPLAYTEST(); - decodedBuffer[blockSize] = 0; - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize); - FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe failed despite sufficient space"); - FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe did not regenerate original data"); - FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe overrun specified output buffer size"); - { U32 const crcCheck = XXH32(decodedBuffer, blockSize, 0); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data"); - } + /* Test decoding with output size being 10 bytes too short => must fail */ + FUZ_DISPLAYTEST(); + if (blockSize>10) { + decodedBuffer[blockSize-10] = 0; + { int const r = LZ4_decompress_safe(cBuffer_exact, decodedBuffer, compressedSize, blockSize-10); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_safe should have failed, due to Output Size being 10 bytes too short"); + } + FUZ_CHECKTEST(decodedBuffer[blockSize-10], "LZ4_decompress_safe overrun specified output buffer size"); + } - // Test decoding with more than enough output size => must work - FUZ_DISPLAYTEST(); - decodedBuffer[blockSize] = 0; - decodedBuffer[blockSize+1] = 0; - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize+1); - FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe failed despite amply sufficient space"); - FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe did not regenerate original data"); - FUZ_CHECKTEST(decodedBuffer[blockSize+1], "LZ4_decompress_safe overrun specified output buffer size"); - { U32 const crcCheck = XXH32(decodedBuffer, (size_t)blockSize, 0); - FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data"); + free(cBuffer_exact); } - // Test decoding with output size being one byte too short => must fail + /* Test decoding with input size being one byte too short => must fail */ FUZ_DISPLAYTEST(); - decodedBuffer[blockSize-1] = 0; - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-1); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being one byte too short"); - FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_safe overrun specified output buffer size"); - - // Test decoding with output size being 10 bytes too short => must fail - FUZ_DISPLAYTEST(); - if (blockSize>10) { - decodedBuffer[blockSize-10] = 0; - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-10); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being 10 bytes too short"); - FUZ_CHECKTEST(decodedBuffer[blockSize-10], "LZ4_decompress_safe overrun specified output buffer size"); + { int const r = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize-1, blockSize); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_safe should have failed, due to input size being one byte too short (blockSize=%i, ret=%i, compressedSize=%i)", blockSize, ret, compressedSize); } - // Test decoding with input size being one byte too short => must fail - FUZ_DISPLAYTEST(); - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize-1, blockSize); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being one byte too short (blockSize=%i, ret=%i, compressedSize=%i)", blockSize, ret, compressedSize); - - // Test decoding with input size being one byte too large => must fail + /* Test decoding with input size being one byte too large => must fail */ FUZ_DISPLAYTEST(); decodedBuffer[blockSize] = 0; - ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize+1, blockSize); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being too large"); + { int const r = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize+1, blockSize); + FUZ_CHECKTEST(r>=0, "LZ4_decompress_safe should have failed, due to input size being too large"); + } FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe overrun specified output buffer size"); /* Test partial decoding => must work */ @@ -881,7 +865,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Compress HC using external dictionary stream */ FUZ_DISPLAYTEST(); - { LZ4_streamHC_t* LZ4_streamHC = LZ4_createStreamHC(); + { LZ4_streamHC_t* const LZ4_streamHC = LZ4_createStreamHC(); LZ4_loadDictHC(LZ4dictHC, dict, dictSize); LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); @@ -1005,6 +989,30 @@ static void FUZ_unitTests(int compressionLevel) /* 32-bits address space overflow test */ FUZ_AddressOverflow(); + /* Test decoding with empty input */ + DISPLAYLEVEL(3, "LZ4_decompress_safe() with empty input"); + LZ4_decompress_safe(testCompressed, testVerify, 0, testInputSize); + + /* Test decoding with a one byte input */ + DISPLAYLEVEL(3, "LZ4_decompress_safe() with one byte input"); + { char const tmp = (char)0xFF; + LZ4_decompress_safe(&tmp, testVerify, 1, testInputSize); + } + + /* Test decoding shortcut edge case */ + DISPLAYLEVEL(3, "LZ4_decompress_safe() with shortcut edge case"); + { char tmp[17]; + /* 14 bytes of literals, followed by a 14 byte match. + * Should not read beyond the end of the buffer. + * See https://github.com/lz4/lz4/issues/508. */ + *tmp = (char)0xEE; + memset(tmp + 1, 0, 14); + tmp[15] = 14; + tmp[16] = 0; + { int const r = LZ4_decompress_safe(tmp, testVerify, sizeof(tmp), testInputSize); + FUZ_CHECKTEST(r >= 0, "LZ4_decompress_safe() should fail"); + } } + /* LZ4 streaming tests */ { LZ4_stream_t streamingState; U64 crcOrig; -- cgit v0.12 From af35920c81e388f7d5f8be5560d791a9f265a4f5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 19 Apr 2019 10:23:50 -0700 Subject: lz4frame: initializers compatibility with C++ fix #679, reported by @degski --- Makefile | 2 +- lib/lz4frame.c | 8 +++++--- lib/lz4frame.h | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f3844a1..4edb47a 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,7 @@ gpptest gpptest32: clean CC=$(CC) $(MAKE) -C $(TESTDIR) all CFLAGS="$(CFLAGS)" cxx17build : CC = "$(CXX) -Wno-deprecated" -cxx17build : CFLAGS = -std=c++17 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror +cxx17build : CFLAGS = -std=c++17 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -pedantic cxx17build : clean $(CXX) -v CC=$(CC) $(MAKE) -C $(LZ4DIR) all CFLAGS="$(CFLAGS)" diff --git a/lib/lz4frame.c b/lib/lz4frame.c index 42124e9..a10e4af 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -325,8 +325,7 @@ static size_t LZ4F_compressBound_internal(size_t srcSize, const LZ4F_preferences_t* preferencesPtr, size_t alreadyBuffered) { - LZ4F_preferences_t prefsNull; - MEM_INIT(&prefsNull, 0, sizeof(prefsNull)); + LZ4F_preferences_t prefsNull = LZ4F_INIT_PREFERENCES; prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */ { const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr; U32 const flush = prefsPtr->autoFlush | (srcSize==0); @@ -1065,7 +1064,10 @@ struct LZ4F_dctx_s { LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) { LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOC_AND_ZERO(sizeof(LZ4F_dctx)); - if (dctx==NULL) return err0r(LZ4F_ERROR_GENERIC); + if (dctx == NULL) { /* failed allocation */ + *LZ4F_decompressionContextPtr = NULL; + return err0r(LZ4F_ERROR_allocation_failed); + } dctx->version = versionNumber; *LZ4F_decompressionContextPtr = dctx; diff --git a/lib/lz4frame.h b/lib/lz4frame.h index ca20dc9..742c252 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -176,7 +176,7 @@ typedef struct { LZ4F_blockChecksum_t blockChecksumFlag; /* 1: each block followed by a checksum of block's compressed data; 0: disabled (default) */ } LZ4F_frameInfo_t; -#define LZ4F_INIT_FRAMEINFO { 0, 0, 0, 0, 0, 0, 0 } /* v1.8.3+ */ +#define LZ4F_INIT_FRAMEINFO { LZ4F_default, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum } /* v1.8.3+ */ /*! LZ4F_preferences_t : * makes it possible to supply advanced compression instructions to streaming interface. @@ -191,7 +191,7 @@ typedef struct { unsigned reserved[3]; /* must be zero for forward compatibility */ } LZ4F_preferences_t; -#define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0, 0, { 0, 0, 0 } } /* v1.8.3+ */ +#define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } } /* v1.8.3+ */ /*-********************************* -- cgit v0.12 From 7a4e3b1fac5cd9d4ec7c8d0091329ba107ec2131 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 19 Apr 2019 11:54:01 -0700 Subject: bumped version number to v1.9.1 --- NEWS | 5 +++++ doc/lz4_manual.html | 4 ++-- doc/lz4frame_manual.html | 4 ++-- lib/lz4.h | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 2d85607..7722d73 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +v1.9.1 +fix : decompression functions were reading beyond input size (introduced in v1.9.0, reported by @ppodolsky and @danlark1) +api : fix : lz4frame initializers compatibility with c++, reported by @degski +build: AIX, by Norman Green + v1.9.0 perf: large decompression speed improvement on x86/x64 (up to +20%) by @djwatson api : changed : _destSize() compression variants are promoted to stable API diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html index ee43b8a..3a9e0db 100644 --- a/doc/lz4_manual.html +++ b/doc/lz4_manual.html @@ -1,10 +1,10 @@ -1.9.0 Manual +1.9.1 Manual -

1.9.0 Manual

+

1.9.1 Manual


Contents

    diff --git a/doc/lz4frame_manual.html b/doc/lz4frame_manual.html index 914405f..2cf4f03 100644 --- a/doc/lz4frame_manual.html +++ b/doc/lz4frame_manual.html @@ -1,10 +1,10 @@ -1.9.0 Manual +1.9.1 Manual -

    1.9.0 Manual

    +

    1.9.1 Manual


    Contents

      diff --git a/lib/lz4.h b/lib/lz4.h index 737a0c7..a9c932c 100644 --- a/lib/lz4.h +++ b/lib/lz4.h @@ -97,7 +97,7 @@ extern "C" { /*------ Version ------*/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) -- cgit v0.12 From 5f8ac02b7707c03f93ff10ac1362d2c618bd3c42 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 19 Apr 2019 17:08:40 -0700 Subject: cli: display a warning whenever default output is stdout while input != stdin This behavior has been preserved for compatibility with existing ecosystem. But it's problematic, as some environment start `lz4` without identifying stdout as console by default, leading to a change of behavior for a same line of script. A more sensible policy would be to default to stdout only when input is stdin. Soft change for the time being : keep the behavior, just print a warning message. User should prefer `-c` to explicitly select `stdout`. Also : updated tests in Makefile to explicitly select `stdout` with `-c`. --- programs/lz4cli.c | 36 +++++++++++++++++++++++++----------- tests/Makefile | 26 +++++++++++++------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 8bd7042..279aaf1 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -652,7 +652,15 @@ int main(int argc, const char** argv) /* No output filename ==> try to select one automatically (when possible) */ while ((!output_filename) && (multiple_inputs==0)) { - if (!IS_CONSOLE(stdout)) { output_filename=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */ + + if (!IS_CONSOLE(stdout)) { + /* Default to stdout whenever stdout is not the console. + * Note : this policy is likely to change in the future, don't rely on it ! + * prefer using an explicit `-c` flag */ + DISPLAYLEVEL(1, "Warning : using stdout as default output. Do not rely on this behavior: use explicit `-c` instead ! \n"); + output_filename=stdoutmark; + break; + } if (mode == om_auto) { /* auto-determine compression or decompression, based on file extension */ mode = determineOpMode(input_filename); } @@ -682,10 +690,14 @@ int main(int argc, const char** argv) break; } - /* Check if output is defined as console; trigger an error in this case */ + if (multiple_inputs==0) assert(output_filename); + /* when multiple_inputs==1, output_filename may simply be useless, + * however, output_filename must be !NULL for next strcmp() tests */ if (!output_filename) output_filename = "*\\dummy^!//"; + + /* Check if output is defined as console; trigger an error in this case */ if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) { - DISPLAYLEVEL(1, "refusing to write to console without -c\n"); + DISPLAYLEVEL(1, "refusing to write to console without -c \n"); exit(1); } /* Downgrade notification level in stdout and multiple file mode */ @@ -701,21 +713,23 @@ int main(int argc, const char** argv) LZ4IO_setNotificationLevel((int)displayLevel); if (ifnIdx == 0) multiple_inputs = 0; if (mode == om_decompress) { - if (multiple_inputs) - operationResult = LZ4IO_decompressMultipleFilenames(prefs, inFileNames, ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); - else + if (multiple_inputs) { + assert(ifnIdx <= INT_MAX); + operationResult = LZ4IO_decompressMultipleFilenames(prefs, inFileNames, (int)ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); + } else { operationResult = DEFAULT_DECOMPRESSOR(prefs, input_filename, output_filename); + } } else { /* compression is default action */ if (legacy_format) { DISPLAYLEVEL(3, "! Generating LZ4 Legacy format (deprecated) ! \n"); LZ4IO_compressFilename_Legacy(prefs, input_filename, output_filename, cLevel); } else { - if (multiple_inputs) - operationResult = LZ4IO_compressMultipleFilenames(prefs, inFileNames, ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION, cLevel); - else + if (multiple_inputs) { + assert(ifnIdx <= INT_MAX); + operationResult = LZ4IO_compressMultipleFilenames(prefs, inFileNames, (int)ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION, cLevel); + } else { operationResult = DEFAULT_COMPRESSOR(prefs, input_filename, output_filename, cLevel); - } - } + } } } _cleanup: if (main_pause) waitEnter(); diff --git a/tests/Makefile b/tests/Makefile index 70cae63..579999c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -176,15 +176,15 @@ test-install: lz4 lib liblz4.pc test-lz4-sparse: lz4 datagen @echo "\n ---- test sparse file support ----" ./datagen -g5M -P100 > tmplsdg5M - $(LZ4) -B4D tmplsdg5M | $(LZ4) -dv --sparse > tmplscB4 + $(LZ4) -B4D tmplsdg5M -c | $(LZ4) -dv --sparse > tmplscB4 $(DIFF) -s tmplsdg5M tmplscB4 - $(LZ4) -B5D tmplsdg5M | $(LZ4) -dv --sparse > tmplscB5 + $(LZ4) -B5D tmplsdg5M -c | $(LZ4) -dv --sparse > tmplscB5 $(DIFF) -s tmplsdg5M tmplscB5 - $(LZ4) -B6D tmplsdg5M | $(LZ4) -dv --sparse > tmplscB6 + $(LZ4) -B6D tmplsdg5M -c | $(LZ4) -dv --sparse > tmplscB6 $(DIFF) -s tmplsdg5M tmplscB6 - $(LZ4) -B7D tmplsdg5M | $(LZ4) -dv --sparse > tmplscB7 + $(LZ4) -B7D tmplsdg5M -c | $(LZ4) -dv --sparse > tmplscB7 $(DIFF) -s tmplsdg5M tmplscB7 - $(LZ4) tmplsdg5M | $(LZ4) -dv --no-sparse > tmplsnosparse + $(LZ4) tmplsdg5M -c | $(LZ4) -dv --no-sparse > tmplsnosparse $(DIFF) -s tmplsdg5M tmplsnosparse ls -ls tmpls* ./datagen -s1 -g1200007 -P100 | $(LZ4) | $(LZ4) -dv --sparse > tmplsodd # Odd size file (to generate non-full last block) @@ -200,7 +200,7 @@ test-lz4-sparse: lz4 datagen cat tmplsdg1M tmplsdg1M > tmpls2M $(LZ4) -B5 -v tmplsdg1M tmplsc $(LZ4) -d -v tmplsc tmplsr - $(LZ4) -d -v tmplsc >> tmplsr + $(LZ4) -d -v tmplsc -c >> tmplsr ls -ls tmp* $(DIFF) tmpls2M tmplsr @$(RM) tmpls* @@ -208,8 +208,8 @@ test-lz4-sparse: lz4 datagen test-lz4-contentSize: lz4 datagen @echo "\n ---- test original size support ----" ./datagen -g15M > tmplc1 - $(LZ4) -v tmplc1 | $(LZ4) -t - $(LZ4) -v --content-size tmplc1 | $(LZ4) -d > tmplc2 + $(LZ4) -v tmplc1 -c | $(LZ4) -t + $(LZ4) -v --content-size tmplc1 -c | $(LZ4) -d > tmplc2 $(DIFF) -s tmplc1 tmplc2 @$(RM) tmplc* @@ -218,10 +218,10 @@ test-lz4-frame-concatenation: lz4 datagen @echo -n > tmp-lfc-empty @echo hi > tmp-lfc-nonempty cat tmp-lfc-nonempty tmp-lfc-empty tmp-lfc-nonempty > tmp-lfc-src - @$(LZ4) -zq tmp-lfc-empty > tmp-lfc-empty.lz4 - @$(LZ4) -zq tmp-lfc-nonempty > tmp-lfc-nonempty.lz4 + $(LZ4) -zq tmp-lfc-empty -c > tmp-lfc-empty.lz4 + $(LZ4) -zq tmp-lfc-nonempty -c > tmp-lfc-nonempty.lz4 cat tmp-lfc-nonempty.lz4 tmp-lfc-empty.lz4 tmp-lfc-nonempty.lz4 > tmp-lfc-concat.lz4 - $(LZ4) -d tmp-lfc-concat.lz4 > tmp-lfc-result + $(LZ4) -d tmp-lfc-concat.lz4 -c > tmp-lfc-result cmp tmp-lfc-src tmp-lfc-result @$(RM) tmp-lfc-* @echo frame concatenation test completed @@ -341,8 +341,8 @@ test-lz4-dict: lz4 datagen for l in 0 1 4 128 32767 32768 32769 65535 65536 65537 98303 98304 98305 131071 131072 131073; do \ ./datagen -g$$l > tmp-dict-$$l; \ $(DD) if=tmp-dict-$$l of=tmp-dict-$$l-tail bs=1 count=65536 skip=$$((l > 65536 ? l - 65536 : 0)); \ - < tmp-dict-$$l $(LZ4) -D stdin tmp-dict-data-128KB | $(LZ4) -dD tmp-dict-$$l-tail | $(DIFF) - tmp-dict-data-128KB; \ - < tmp-dict-$$l-tail $(LZ4) -D stdin tmp-dict-data-128KB | $(LZ4) -dD tmp-dict-$$l | $(DIFF) - tmp-dict-data-128KB; \ + < tmp-dict-$$l $(LZ4) -D stdin tmp-dict-data-128KB -c | $(LZ4) -dD tmp-dict-$$l-tail | $(DIFF) - tmp-dict-data-128KB; \ + < tmp-dict-$$l-tail $(LZ4) -D stdin tmp-dict-data-128KB -c | $(LZ4) -dD tmp-dict-$$l | $(DIFF) - tmp-dict-data-128KB; \ done @$(RM) tmp-dict* -- cgit v0.12 From 55ab3c48aef50fbf56203eb15fd37d84be5cbd46 Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Sat, 20 Apr 2019 22:06:10 +0100 Subject: Add --list option to display compressed file information. --- programs/lz4cli.c | 34 ++++++++++++++++++++++++++++++++-- programs/lz4io.c | 40 +++++++++++++++++++++++++++++++++++++++- programs/lz4io.h | 11 +++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 8bd7042..adfabc3 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -40,6 +40,7 @@ #include /* exit, calloc, free */ #include /* strcmp, strlen */ #include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ +#include "lz4frame.h" #include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ #include "lz4hc.h" /* LZ4HC_CLEVEL_MAX */ #include "lz4.h" /* LZ4_VERSION_STRING */ @@ -141,6 +142,7 @@ static int usage_advanced(const char* exeName) DISPLAY( " -BX : enable block checksum (default:disabled) \n"); DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled) \n"); DISPLAY( "--content-size : compressed frame includes original size (default:not present)\n"); + DISPLAY( "--list : list information about .lz4 files. Only useful if compressed with --content-size flag.\n"); DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n"); DISPLAY( "--favor-decSpeed: compressed files decompress faster, but are less compressed \n"); DISPLAY( "--fast[=#]: switch to ultra fast compression level (default: %i)\n", 1); @@ -286,7 +288,7 @@ static int longCommandWArg(const char** stringPtr, const char* longCommand) return result; } -typedef enum { om_auto, om_compress, om_decompress, om_test, om_bench } operationMode_e; +typedef enum { om_auto, om_compress, om_decompress, om_test, om_bench, om_list } operationMode_e; /** determineOpMode() : * auto-determine operation mode, based on input filename extension @@ -383,6 +385,7 @@ int main(int argc, const char** argv) if (!strcmp(argument, "--no-frame-crc")) { LZ4IO_setStreamChecksumMode(prefs, 0); continue; } if (!strcmp(argument, "--content-size")) { LZ4IO_setContentSize(prefs, 1); continue; } if (!strcmp(argument, "--no-content-size")) { LZ4IO_setContentSize(prefs, 0); continue; } + if (!strcmp(argument, "--list")) { mode = om_list; continue; } if (!strcmp(argument, "--sparse")) { LZ4IO_setSparseFile(prefs, 2); continue; } if (!strcmp(argument, "--no-sparse")) { LZ4IO_setSparseFile(prefs, 0); continue; } if (!strcmp(argument, "--favor-decSpeed")) { LZ4IO_favorDecSpeed(prefs, 1); continue; } @@ -705,7 +708,34 @@ int main(int argc, const char** argv) operationResult = LZ4IO_decompressMultipleFilenames(prefs, inFileNames, ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); else operationResult = DEFAULT_DECOMPRESSOR(prefs, input_filename, output_filename); - } else { /* compression is default action */ + } else if (mode == om_list){ + LZ4F_compFileInfo_t cfinfo; + if(!multiple_inputs){ + inFileNames[ifnIdx++] = input_filename; + } + DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); + for(i=0; i /* clock */ #include /* stat64 */ #include /* stat64 */ -#include "lz4io.h" #include "lz4.h" /* still required for legacy format */ #include "lz4hc.h" /* still required for legacy format */ #define LZ4F_STATIC_LINKING_ONLY #include "lz4frame.h" +#include "lz4io.h" /***************************** @@ -1265,3 +1265,41 @@ int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** i free(outFileName); return missingFiles + skippedFiles; } + +size_t LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ + /* Get file size */ + stat_t statbuf; + if (!UTIL_getFileStat(input_filename, &statbuf)){ + EXM_THROW(60, "Can't stat file : %s", input_filename); + } + cfinfo->fileSize = statbuf.st_size; + /* Get basename without extension */ + const char *b = strrchr(input_filename, '/'); + if (b && b != input_filename){ + b++; + } else{ + b=input_filename; + } + const char *e = strrchr(b, '.'); + cfinfo->fileName = malloc( (e-b+1) * sizeof(char)); + strncpy(cfinfo->fileName, b, (e-b)); + cfinfo->fileName[e-b] = '\0'; + /* init */ + dRess_t ress; + LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); + if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); + FILE* const finput = LZ4IO_openSrcFile(input_filename); + if (finput==NULL) return 1; + /* Allocate Memory */ + ress.srcBuffer = malloc(LZ4IO_dBufferSize); + size_t readSize = LZ4F_HEADER_SIZE_MAX; + if (!fread(ress.srcBuffer, readSize, 1, finput)){ + EXM_THROW(30, "Error reading %s ", input_filename); + } + cfinfo->frameInfo = (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO; + LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); + /* Close input/free resources */ + fclose(finput); + free(ress.srcBuffer); + return readSize; +} diff --git a/programs/lz4io.h b/programs/lz4io.h index 54d49be..bf1fa76 100644 --- a/programs/lz4io.h +++ b/programs/lz4io.h @@ -54,6 +54,14 @@ static const char nulmark[] = "/dev/null"; typedef struct LZ4IO_prefs_s LZ4IO_prefs_t; +typedef struct { + LZ4F_frameInfo_t frameInfo; + char* fileName; + unsigned long long fileSize; + double compressionRatio; +} LZ4F_compFileInfo_t; + + LZ4IO_prefs_t* LZ4IO_defaultPreferences(void); void LZ4IO_freePreferences(LZ4IO_prefs_t* const prefs); @@ -116,6 +124,9 @@ int LZ4IO_setSparseFile(LZ4IO_prefs_t* const prefs, int enable); /* Default setting : 0 == no content size present in frame header */ int LZ4IO_setContentSize(LZ4IO_prefs_t* const prefs, int enable); +/* */ +size_t LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo); + /* Default setting : 0 == src file preserved */ void LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t* const prefs, unsigned flag); -- cgit v0.12 From 55484191c40a2909bf08eb23754a136199c134c2 Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Sun, 21 Apr 2019 00:20:38 +0100 Subject: correctly use unisgned int for index --- programs/lz4cli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/lz4cli.c b/programs/lz4cli.c index adfabc3..54d93f1 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -714,9 +714,9 @@ int main(int argc, const char** argv) inFileNames[ifnIdx++] = input_filename; } DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); - for(i=0; i Date: Sun, 21 Apr 2019 17:43:57 +0100 Subject: FR #598 Improve initial design, test mallocs, support C90. --- programs/lz4.1.md | 6 +++ programs/lz4cli.c | 26 ++----------- programs/lz4io.c | 112 ++++++++++++++++++++++++++++++++++++++---------------- programs/lz4io.h | 10 +++-- 4 files changed, 94 insertions(+), 60 deletions(-) diff --git a/programs/lz4.1.md b/programs/lz4.1.md index 10449a0..7db9f19 100644 --- a/programs/lz4.1.md +++ b/programs/lz4.1.md @@ -114,6 +114,11 @@ only the latest one will be applied. * `-b#`: Benchmark mode, using `#` compression level. +* `--list`: + List mode. + Lists information about .lz4 files. + Useful if compressed with --content-size flag. + ### Operation modifiers * `-#`: @@ -161,6 +166,7 @@ only the latest one will be applied. Multiple input files. Compressed file names will be appended a `.lz4` suffix. This mode also reduces notification level. + Can also be used to list multiple files. `lz4 -m` has a behavior equivalent to `gzip -k` (it preserves source files by default). diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 54d93f1..23c4be7 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -142,7 +142,7 @@ static int usage_advanced(const char* exeName) DISPLAY( " -BX : enable block checksum (default:disabled) \n"); DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled) \n"); DISPLAY( "--content-size : compressed frame includes original size (default:not present)\n"); - DISPLAY( "--list : list information about .lz4 files. Only useful if compressed with --content-size flag.\n"); + DISPLAY( "--list : lists information about .lz4 files. Useful if compressed with --content-size flag.\n"); DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n"); DISPLAY( "--favor-decSpeed: compressed files decompress faster, but are less compressed \n"); DISPLAY( "--fast[=#]: switch to ultra fast compression level (default: %i)\n", 1); @@ -709,31 +709,11 @@ int main(int argc, const char** argv) else operationResult = DEFAULT_DECOMPRESSOR(prefs, input_filename, output_filename); } else if (mode == om_list){ - LZ4F_compFileInfo_t cfinfo; if(!multiple_inputs){ inFileNames[ifnIdx++] = input_filename; } - DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); - for(unsigned int j=0; jfileSize = statbuf.st_size; - /* Get basename without extension */ - const char *b = strrchr(input_filename, '/'); - if (b && b != input_filename){ - b++; - } else{ - b=input_filename; + if(cfinfo.frameInfo.contentSize){ + DISPLAY("%-16d\t%-20llu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize,cfinfo.frameInfo.contentSize, cfinfo.ratio, cfinfo.fileName); } - const char *e = strrchr(b, '.'); - cfinfo->fileName = malloc( (e-b+1) * sizeof(char)); - strncpy(cfinfo->fileName, b, (e-b)); - cfinfo->fileName[e-b] = '\0'; - /* init */ - dRess_t ress; - LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); - if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); - FILE* const finput = LZ4IO_openSrcFile(input_filename); - if (finput==NULL) return 1; - /* Allocate Memory */ - ress.srcBuffer = malloc(LZ4IO_dBufferSize); - size_t readSize = LZ4F_HEADER_SIZE_MAX; - if (!fread(ress.srcBuffer, readSize, 1, finput)){ - EXM_THROW(30, "Error reading %s ", input_filename); + else{ + DISPLAY("%-16d\t%-20llu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize, "-", "-", cfinfo.fileName); } - cfinfo->frameInfo = (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO; - LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); - /* Close input/free resources */ - fclose(finput); - free(ress.srcBuffer); - return readSize; + } + return op_result; +} + +int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ + const char *b, + *e; + char *t; + stat_t statbuf; + size_t readSize = LZ4F_HEADER_SIZE_MAX; + LZ4F_errorCode_t errorCode; + dRess_t ress; + /* Open file */ + FILE* const finput = LZ4IO_openSrcFile(input_filename); + if (finput==NULL) return 0; + *cfinfo = (LZ4F_compFileInfo_t) LZ4F_INIT_FILEINFO; + /* Get file size */ + if (!UTIL_getFileStat(input_filename, &statbuf)){ + EXM_THROW(60, "Can't stat file : %s", input_filename); + } + cfinfo->fileSize = statbuf.st_size; + + /* Get basename without extension */ + b = strrchr(input_filename, '/'); + if (!b){ + b = strrchr(input_filename, '\\'); + } + if (b && b != input_filename){ + b++; + } else{ + b=input_filename; + } + e = strrchr(b, '.'); + /* Allocate Memory */ + t = malloc( (e-b+1) * sizeof(char)); + ress.srcBuffer = malloc(LZ4IO_dBufferSize); + if (!t || !ress.srcBuffer) + EXM_THROW(21, "Allocation error : not enough memory"); + strncpy(t, b, (e-b)); + t[e-b] = '\0'; + cfinfo->fileName = t; + + /* init */ + errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); + if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); + + if (!fread(ress.srcBuffer, readSize, 1, finput)){ + EXM_THROW(30, "Error reading %s ", input_filename); + } + // cfinfo->frameInfo = (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO; + LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); + if(cfinfo->frameInfo.contentSize){ + cfinfo->ratio = (double)cfinfo->fileSize / cfinfo->frameInfo.contentSize; + } else { + cfinfo->ratio = -1; + } + + /* Close input/free resources */ + fclose(finput); + free(ress.srcBuffer); + return 0; } diff --git a/programs/lz4io.h b/programs/lz4io.h index bf1fa76..707f233 100644 --- a/programs/lz4io.h +++ b/programs/lz4io.h @@ -56,11 +56,12 @@ typedef struct LZ4IO_prefs_s LZ4IO_prefs_t; typedef struct { LZ4F_frameInfo_t frameInfo; - char* fileName; + const char* fileName; unsigned long long fileSize; - double compressionRatio; + double ratio; } LZ4F_compFileInfo_t; +#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0ULL, -1.f } LZ4IO_prefs_t* LZ4IO_defaultPreferences(void); void LZ4IO_freePreferences(LZ4IO_prefs_t* const prefs); @@ -124,8 +125,9 @@ int LZ4IO_setSparseFile(LZ4IO_prefs_t* const prefs, int enable); /* Default setting : 0 == no content size present in frame header */ int LZ4IO_setContentSize(LZ4IO_prefs_t* const prefs, int enable); -/* */ -size_t LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo); +int LZ4IO_getCompressedFilesInfo(const char** inFileNames,const size_t ifnIdx); + +int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo); /* Default setting : 0 == src file preserved */ void LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t* const prefs, unsigned flag); -- cgit v0.12 From 467e352de929fa664af03ece065c89e9997d1bf1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 21 Apr 2019 12:42:13 -0700 Subject: tests/Makefile : created CMP variable for potential redirection, if need be. note : should probably converge all comparison operations onto CMP --- tests/Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 579999c..209a530 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -144,6 +144,8 @@ ifneq (,$(filter $(shell uname), Darwin )) MD5:=md5 -r endif +# note : we should probably settle on a single compare utility +CMP:=cmp DIFF:=diff ifneq (,$(filter $(shell uname),SunOS)) DIFF:=gdiff @@ -222,7 +224,7 @@ test-lz4-frame-concatenation: lz4 datagen $(LZ4) -zq tmp-lfc-nonempty -c > tmp-lfc-nonempty.lz4 cat tmp-lfc-nonempty.lz4 tmp-lfc-empty.lz4 tmp-lfc-nonempty.lz4 > tmp-lfc-concat.lz4 $(LZ4) -d tmp-lfc-concat.lz4 -c > tmp-lfc-result - cmp tmp-lfc-src tmp-lfc-result + $(CMP) tmp-lfc-src tmp-lfc-result @$(RM) tmp-lfc-* @echo frame concatenation test completed @@ -241,15 +243,15 @@ test-lz4-multiple: lz4 datagen mv tmp-tlm2 tmp-tlm2-orig mv tmp-tlm3 tmp-tlm3-orig $(LZ4) -d -f -m tmp-tlm*.lz4 - cmp tmp-tlm1 tmp-tlm1-orig # must be identical - cmp tmp-tlm2 tmp-tlm2-orig - cmp tmp-tlm3 tmp-tlm3-orig + $(CMP) tmp-tlm1 tmp-tlm1-orig # must be identical + $(CMP) tmp-tlm2 tmp-tlm2-orig + $(CMP) tmp-tlm3 tmp-tlm3-orig # compress multiple files into stdout cat tmp-tlm1.lz4 tmp-tlm2.lz4 tmp-tlm3.lz4 > tmp-tlm-concat1 $(RM) *.lz4 $(LZ4) -m tmp-tlm1 tmp-tlm2 tmp-tlm3 -c > tmp-tlm-concat2 test ! -f tmp-tlm1.lz4 # must not create .lz4 artefact - cmp tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent + $(CMP) tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent # decompress multiple files into stdout $(RM) tmp-tlm-concat1 tmp-tlm-concat2 $(LZ4) -f -m tmp-tlm1 tmp-tlm2 tmp-tlm3 # generate .lz4 to decompress @@ -257,7 +259,7 @@ test-lz4-multiple: lz4 datagen $(RM) tmp-tlm1 tmp-tlm2 tmp-tlm3 $(LZ4) -d -m tmp-tlm1.lz4 tmp-tlm2.lz4 tmp-tlm3.lz4 -c > tmp-tlm-concat2 test ! -f tmp-tlm1 # must not create file artefact - cmp tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent + $(CMP) tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent # compress multiple files, one of which is absent (must fail) ! $(LZ4) -f -m tmp-tlm-concat1 notHere tmp-tlm-concat2 # must fail : notHere not present @$(RM) tmp-tlm* -- cgit v0.12 From 22fae16c6f4c4f118e93468ede884295d365fcef Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 21 Apr 2019 17:01:03 -0700 Subject: ensure tests work when `stdout` is not the console ensure this case is continuously tested on travis. Update documentation on implicit output, invite to not rely on implicit output in scripts. --- .travis.yml | 2 +- programs/lz4.1.md | 27 +++++++++++++-------------- programs/lz4cli.c | 5 +++-- tests/Makefile | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 301d294..2065478 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ matrix: os: osx compiler: clang script: - - make -C tests test-lz4 MOREFLAGS='-Werror -Wconversion -Wno-sign-conversion' + - make -C tests test-lz4 MOREFLAGS='-Werror -Wconversion -Wno-sign-conversion' | tee # test scenario where `stdout` is not the console - CFLAGS=-m32 make -C tests clean test-lz4-contentSize # Container-based 12.04 LTS Server Edition 64 bit (doesn't support 32-bit includes) diff --git a/programs/lz4.1.md b/programs/lz4.1.md index 10449a0..ffda3ff 100644 --- a/programs/lz4.1.md +++ b/programs/lz4.1.md @@ -31,29 +31,29 @@ The native file format is the `.lz4` format. `lz4` supports a command line syntax similar _but not identical_ to `gzip(1)`. Differences are : - * `lz4` preserves original files * `lz4` compresses a single file by default (see `-m` for multiple files) * `lz4 file1 file2` means : compress file1 _into_ file2 * `lz4 file.lz4` will default to decompression (use `-z` to force compression) + * `lz4` preserves original files * `lz4` shows real-time notification statistics during compression or decompression of a single file (use `-q` to silence them) - * If no destination name is provided, result is sent to `stdout` - _except if stdout is the console_. - * If no destination name is provided, __and__ if `stdout` is the console, - `file` is compressed into `file.lz4`. - * As a consequence of previous rules, note the following example : - `lz4 file | consumer` sends compressed data to `consumer` through `stdout`, - hence it does _not_ create `file.lz4`. - * Another consequence of those rules is that to run `lz4` under `nohup`, - you should provide a destination file: `nohup lz4 file file.lz4`, - because `nohup` writes the specified command's output to a file. + * When no destination is specified, result is sent on implicit output, + which depends on `stdout` status. + When `stdout` _is Not the console_, it becomes the implicit output. + Otherwise, if `stdout` is the console, the implicit output is `filename.lz4`. + * It is considered bad practice to rely on implicit output in scripts. + because the script's environment may change. + Always use explicit output in scripts. + `-c` ensures that output will be `stdout`. + Conversely, providing a destination name, or using `-m` + ensures that the output will be either the specified name, or `filename.lz4` respectively. Default behaviors can be modified by opt-in commands, detailed below. * `lz4 -m` makes it possible to provide multiple input filenames, which will be compressed into files using suffix `.lz4`. - Progress notifications are also disabled by default (use `-v` to enable them). + Progress notifications become disabled by default (use `-v` to enable them). This mode has a behavior which more closely mimics `gzip` command line, with the main remaining difference being that source files are preserved by default. * Similarly, `lz4 -m -d` can decompress multiple `*.lz4` files. @@ -81,8 +81,7 @@ In some cases, some options can be expressed using short command `-x` or long command `--long-word`. Short commands can be concatenated together. For example, `-d -c` is equivalent to `-dc`. -Long commands cannot be concatenated. -They must be clearly separated by a space. +Long commands cannot be concatenated. They must be clearly separated by a space. ### Multiple commands diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 279aaf1..82f2fac 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -655,8 +655,9 @@ int main(int argc, const char** argv) if (!IS_CONSOLE(stdout)) { /* Default to stdout whenever stdout is not the console. - * Note : this policy is likely to change in the future, don't rely on it ! - * prefer using an explicit `-c` flag */ + * Note : this policy may change in the future, therefore don't rely on it ! + * To ensure `stdout` is explicitly selected, use `-c` command flag. + * Conversely, to ensure output will not become `stdout`, use `-m` command flag */ DISPLAYLEVEL(1, "Warning : using stdout as default output. Do not rely on this behavior: use explicit `-c` instead ! \n"); output_filename=stdoutmark; break; diff --git a/tests/Makefile b/tests/Makefile index 209a530..ddc6d1e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -317,7 +317,7 @@ test-lz4-basic: lz4 datagen unlz4 lz4cat ! $(LZ4) -c --fast=-1 tmp-tlb-dg20K # lz4 should fail when fast=-1 # Test for #596 @echo "TEST" > tmp-tlb-test - $(LZ4) tmp-tlb-test + $(LZ4) -m tmp-tlb-test $(LZ4) tmp-tlb-test.lz4 tmp-tlb-test2 $(DIFF) -q tmp-tlb-test tmp-tlb-test2 @$(RM) tmp-tlb* -- cgit v0.12 From 2133366da080aaa2dbec2a33b52ad236cb493b01 Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Mon, 22 Apr 2019 09:00:20 +0100 Subject: FR #598 - Make LZ4IO_getCompressedFileInfo internal and reword func --- programs/lz4cli.c | 3 +- programs/lz4io.c | 132 ++++++++++++++++++++++++++---------------------------- programs/lz4io.h | 9 ++-- 3 files changed, 68 insertions(+), 76 deletions(-) diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 23c4be7..9a74286 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -40,7 +40,6 @@ #include /* exit, calloc, free */ #include /* strcmp, strlen */ #include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ -#include "lz4frame.h" #include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ #include "lz4hc.h" /* LZ4HC_CLEVEL_MAX */ #include "lz4.h" /* LZ4_VERSION_STRING */ @@ -712,7 +711,7 @@ int main(int argc, const char** argv) if(!multiple_inputs){ inFileNames[ifnIdx++] = input_filename; } - operationResult = LZ4IO_getCompressedFilesInfo(inFileNames, ifnIdx); + operationResult = LZ4IO_displayCompressedFilesInfo(inFileNames, ifnIdx); inFileNames=NULL; } else { /* compression is default action */ diff --git a/programs/lz4io.c b/programs/lz4io.c index 2e38d2f..61fa13f 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1214,6 +1214,60 @@ static int LZ4IO_decompressDstFile(LZ4IO_prefs_t* const prefs, dRess_t ress, con } +static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ + const char *b, + *e; + char *t; + size_t readSize = LZ4F_HEADER_SIZE_MAX; + LZ4F_errorCode_t errorCode; + dRess_t ress; + // LZ4F_compFileInfo_t cfinfo = (LZ4F_compFileInfo_t) LZ4F_INIT_FILEINFO; + /* Open file */ + FILE* const finput = LZ4IO_openSrcFile(input_filename); + if (finput==NULL) return 1; + + /* Get file size */ + if (!UTIL_getFileStat(input_filename, &cfinfo->fileStat)){ + EXM_THROW(60, "Can't stat file : %s", input_filename); + } + + /* Get basename without extension */ + b = strrchr(input_filename, '/'); + if (!b){ + b = strrchr(input_filename, '\\'); + } + if (b && b != input_filename){ + b++; + } else{ + b=input_filename; + } + e = strrchr(b, '.'); + + /* Allocate Memory */ + t = malloc( (e-b+1) * sizeof(char)); + ress.srcBuffer = malloc(LZ4IO_dBufferSize); + if (!t || !ress.srcBuffer) + EXM_THROW(21, "Allocation error : not enough memory"); + strncpy(t, b, (e-b)); + t[e-b] = '\0'; + cfinfo->fileName = t; + + /* init */ + errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); + if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); + + if (!fread(ress.srcBuffer, readSize, 1, finput)){ + EXM_THROW(30, "Error reading %s ", input_filename); + } + LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); + + /* Close input/free resources */ + fclose(finput); + free(ress.srcBuffer); + return 0; +} + + int LZ4IO_decompressFilename(LZ4IO_prefs_t* const prefs, const char* input_filename, const char* output_filename) { dRess_t const ress = LZ4IO_createDResources(prefs); @@ -1266,86 +1320,28 @@ int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** i return missingFiles + skippedFiles; } -int LZ4IO_getCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx){ + +int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx){ size_t idx; int op_result=0; - LZ4F_compFileInfo_t cfinfo = (LZ4F_compFileInfo_t) LZ4F_INIT_FILEINFO; + double ratio; + LZ4F_compFileInfo_t cfinfo; DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); for(idx=0; idxfileSize = statbuf.st_size; - - /* Get basename without extension */ - b = strrchr(input_filename, '/'); - if (!b){ - b = strrchr(input_filename, '\\'); - } - if (b && b != input_filename){ - b++; - } else{ - b=input_filename; - } - e = strrchr(b, '.'); - /* Allocate Memory */ - t = malloc( (e-b+1) * sizeof(char)); - ress.srcBuffer = malloc(LZ4IO_dBufferSize); - if (!t || !ress.srcBuffer) - EXM_THROW(21, "Allocation error : not enough memory"); - strncpy(t, b, (e-b)); - t[e-b] = '\0'; - cfinfo->fileName = t; - - /* init */ - errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); - if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); - - if (!fread(ress.srcBuffer, readSize, 1, finput)){ - EXM_THROW(30, "Error reading %s ", input_filename); - } - // cfinfo->frameInfo = (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO; - LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); - if(cfinfo->frameInfo.contentSize){ - cfinfo->ratio = (double)cfinfo->fileSize / cfinfo->frameInfo.contentSize; - } else { - cfinfo->ratio = -1; - } - - /* Close input/free resources */ - fclose(finput); - free(ress.srcBuffer); - return 0; -} diff --git a/programs/lz4io.h b/programs/lz4io.h index 707f233..3d37bd0 100644 --- a/programs/lz4io.h +++ b/programs/lz4io.h @@ -57,11 +57,10 @@ typedef struct LZ4IO_prefs_s LZ4IO_prefs_t; typedef struct { LZ4F_frameInfo_t frameInfo; const char* fileName; - unsigned long long fileSize; - double ratio; + stat_t fileStat; } LZ4F_compFileInfo_t; -#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0ULL, -1.f } +#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, stat_t() } LZ4IO_prefs_t* LZ4IO_defaultPreferences(void); void LZ4IO_freePreferences(LZ4IO_prefs_t* const prefs); @@ -125,9 +124,7 @@ int LZ4IO_setSparseFile(LZ4IO_prefs_t* const prefs, int enable); /* Default setting : 0 == no content size present in frame header */ int LZ4IO_setContentSize(LZ4IO_prefs_t* const prefs, int enable); -int LZ4IO_getCompressedFilesInfo(const char** inFileNames,const size_t ifnIdx); - -int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo); +int LZ4IO_displayCompressedFilesInfo(const char** inFileNames,const size_t ifnIdx); /* Default setting : 0 == src file preserved */ void LZ4IO_setRemoveSrcFile(LZ4IO_prefs_t* const prefs, unsigned flag); -- cgit v0.12 From 0acebbe53dd1b15071f2c48a7b060299b5d03622 Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Mon, 22 Apr 2019 09:58:26 +0100 Subject: FR #598 - Move LZ4F_compFileInfo_t def to lz4frame.h discard output_file assert if in om_list mode --- lib/lz4frame.h | 7 +++++++ programs/lz4cli.c | 13 ++++++++++--- programs/lz4io.c | 11 +++++++---- programs/lz4io.h | 8 -------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 742c252..5945647 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -193,6 +193,13 @@ typedef struct { #define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } } /* v1.8.3+ */ +typedef struct { + LZ4F_frameInfo_t frameInfo; + const char* fileName; + unsigned long fileSize; +} LZ4F_compFileInfo_t; + +#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0UL } /*-********************************* * Simple compression function diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 3315773..443e4b4 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -693,7 +693,7 @@ int main(int argc, const char** argv) break; } - if (multiple_inputs==0) assert(output_filename); + if (multiple_inputs==0 && mode != om_list) assert(output_filename); /* when multiple_inputs==1, output_filename may simply be useless, * however, output_filename must be !NULL for next strcmp() tests */ if (!output_filename) output_filename = "*\\dummy^!//"; @@ -721,7 +721,14 @@ int main(int argc, const char** argv) operationResult = LZ4IO_decompressMultipleFilenames(prefs, inFileNames, (int)ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); } else { operationResult = DEFAULT_DECOMPRESSOR(prefs, input_filename, output_filename); - + } + } else if (mode == om_list){ + if(!multiple_inputs){ + inFileNames[ifnIdx++] = input_filename; + } + operationResult = LZ4IO_displayCompressedFilesInfo(inFileNames, ifnIdx); + inFileNames=NULL; + } else { /* compression is default action */ if (legacy_format) { DISPLAYLEVEL(3, "! Generating LZ4 Legacy format (deprecated) ! \n"); LZ4IO_compressFilename_Legacy(prefs, input_filename, output_filename, cLevel); @@ -745,4 +752,4 @@ _cleanup: LZ4IO_freePreferences(prefs); free((void*)inFileNames); return operationResult; -} +} \ No newline at end of file diff --git a/programs/lz4io.c b/programs/lz4io.c index 61fa13f..070e22a 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1218,6 +1218,7 @@ static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFil const char *b, *e; char *t; + stat_t statbuf; size_t readSize = LZ4F_HEADER_SIZE_MAX; LZ4F_errorCode_t errorCode; dRess_t ress; @@ -1227,10 +1228,12 @@ static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFil if (finput==NULL) return 1; /* Get file size */ - if (!UTIL_getFileStat(input_filename, &cfinfo->fileStat)){ + if (!UTIL_getFileStat(input_filename, &statbuf)){ EXM_THROW(60, "Can't stat file : %s", input_filename); } + cfinfo->fileSize = statbuf.st_size; + /* Get basename without extension */ b = strrchr(input_filename, '/'); if (!b){ @@ -1336,11 +1339,11 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnI break; } if(cfinfo.frameInfo.contentSize){ - ratio = (double)cfinfo.fileStat.st_size / cfinfo.frameInfo.contentSize; - DISPLAY("%-16d\t%-20lu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileStat.st_size,cfinfo.frameInfo.contentSize, ratio, cfinfo.fileName); + ratio = (double)cfinfo.fileSize / cfinfo.frameInfo.contentSize; + DISPLAY("%-16d\t%-20lu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize,cfinfo.frameInfo.contentSize, ratio, cfinfo.fileName); } else{ - DISPLAY("%-16d\t%-20lu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileStat.st_size, "-", "-", cfinfo.fileName); + DISPLAY("%-16d\t%-20lu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize, "-", "-", cfinfo.fileName); } } return op_result; diff --git a/programs/lz4io.h b/programs/lz4io.h index fcda5f1..2008b55 100644 --- a/programs/lz4io.h +++ b/programs/lz4io.h @@ -52,14 +52,6 @@ static const char nulmark[] = "/dev/null"; /* ****************** Type Definitions ************** */ /* ************************************************** */ -typedef struct { - LZ4F_frameInfo_t frameInfo; - const char* fileName; - stat_t fileStat; -} LZ4F_compFileInfo_t; - -#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, stat_t() } - typedef struct LZ4IO_prefs_s LZ4IO_prefs_t; LZ4IO_prefs_t* LZ4IO_defaultPreferences(void); -- cgit v0.12 From e31b6dc03ca464de55ebb403fb0ef6470d99e1a0 Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Mon, 22 Apr 2019 10:35:29 +0100 Subject: FR #598 - Make fileSize unsigned long long --- lib/lz4frame.h | 4 ++-- programs/lz4io.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 5945647..8c07e86 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -196,10 +196,10 @@ typedef struct { typedef struct { LZ4F_frameInfo_t frameInfo; const char* fileName; - unsigned long fileSize; + unsigned long long fileSize; } LZ4F_compFileInfo_t; -#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0UL } +#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0ULL } /*-********************************* * Simple compression function diff --git a/programs/lz4io.c b/programs/lz4io.c index 070e22a..9aa2b94 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1340,10 +1340,10 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnI } if(cfinfo.frameInfo.contentSize){ ratio = (double)cfinfo.fileSize / cfinfo.frameInfo.contentSize; - DISPLAY("%-16d\t%-20lu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize,cfinfo.frameInfo.contentSize, ratio, cfinfo.fileName); + DISPLAY("%-16d\t%-20llu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize,cfinfo.frameInfo.contentSize, ratio, cfinfo.fileName); } else{ - DISPLAY("%-16d\t%-20lu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize, "-", "-", cfinfo.fileName); + DISPLAY("%-16d\t%-20llu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize, "-", "-", cfinfo.fileName); } } return op_result; -- cgit v0.12 From 84f978a2f3a787c7646ab3773fa7c41bddbb849e Mon Sep 17 00:00:00 2001 From: gabrielstedman Date: Mon, 22 Apr 2019 11:07:08 +0100 Subject: FR #598 - Correctly initialize cfinfo & cast malloc res to (char*) --- programs/lz4io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/lz4io.c b/programs/lz4io.c index 9aa2b94..175157e 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1222,7 +1222,6 @@ static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFil size_t readSize = LZ4F_HEADER_SIZE_MAX; LZ4F_errorCode_t errorCode; dRess_t ress; - // LZ4F_compFileInfo_t cfinfo = (LZ4F_compFileInfo_t) LZ4F_INIT_FILEINFO; /* Open file */ FILE* const finput = LZ4IO_openSrcFile(input_filename); if (finput==NULL) return 1; @@ -1247,7 +1246,7 @@ static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFil e = strrchr(b, '.'); /* Allocate Memory */ - t = malloc( (e-b+1) * sizeof(char)); + t = (char*)malloc( (e-b+1) * sizeof(char)); ress.srcBuffer = malloc(LZ4IO_dBufferSize); if (!t || !ress.srcBuffer) EXM_THROW(21, "Allocation error : not enough memory"); @@ -1332,6 +1331,7 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnI DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); for(idx=0; idx Date: Mon, 22 Apr 2019 13:48:59 -0400 Subject: Initial commits from diff I submitted earlier --- Makefile | 53 +++++++++++++++++++++++++++++++++++++---- examples/Makefile | 47 ++++++++++++++++++++++++++++++++---- lib/Makefile | 42 +++++++++++++++++++++++--------- programs/Makefile | 41 ++++++++++++++++++++++++++++---- tests/Makefile | 71 +++++++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 221 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index f3c6ce2..51b4216 100644 --- a/Makefile +++ b/Makefile @@ -36,15 +36,50 @@ TESTDIR = tests EXDIR = examples -# Define nul output -ifneq (,$(filter Windows%,$(OS))) +# Define *.exe as extension for targetting Windows systems +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif + +ifneq (,$(filter Windows%,$(TARGET_OS))) +LIBLZ4 = liblz4-$(LIBVER_MAJOR) +EXT = .exe +else +EXT = .exe +ifneq (,$(filter MINGW%,$(TARGET_OS))) +EXT = .exe +else +ifneq (,$(filter MSYS%,$(TARGET_OS))) +EXT = .exe +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) EXT = .exe -VOID = nul else EXT = -VOID = /dev/null +endif +endif +endif endif +#determine if dev/nul based on host environment +ifneq (,$(filter MINGW%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter MSYS%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter CYGWIN%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter Windows%,$(OS))) +VOID := nul +else +VOID := /dev/null +endif +endif +endif +endif .PHONY: default default: lib-release lz4-release @@ -93,7 +128,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT-6.1 MINGW64_NT-6.1 MINGW32_NT-10.0 MINGW64_NT-10.0)) +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) HOST_OS = POSIX .PHONY: install uninstall @@ -181,6 +216,14 @@ gpptest gpptest32: clean CC=$(CC) $(MAKE) -C $(PRGDIR) all CFLAGS="$(CFLAGS)" CC=$(CC) $(MAKE) -C $(TESTDIR) all CFLAGS="$(CFLAGS)" +cxx17build : CC = "$(CXX) -Wno-deprecated" +cxx17build : CFLAGS = -std=c++17 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -pedantic +cxx17build : clean + $(CXX) -v + CC=$(CC) $(MAKE) -C $(LZ4DIR) all CFLAGS="$(CFLAGS)" + CC=$(CC) $(MAKE) -C $(PRGDIR) all CFLAGS="$(CFLAGS)" + CC=$(CC) $(MAKE) -C $(TESTDIR) all CFLAGS="$(CFLAGS)" + ctocpptest: LIBCC="$(CC)" ctocpptest: TESTCC="$(CXX)" ctocpptest: CFLAGS="" diff --git a/examples/Makefile b/examples/Makefile index 103e7ec..26aaafd 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -38,14 +38,51 @@ LZ4 = ../programs/lz4 # Define *.exe as extension for Windows systems -ifneq (,$(filter Windows%,$(OS))) -EXT =.exe -VOID = nul + +# Define *.exe as extension for targetting Windows systems +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif + +ifneq (,$(filter Windows%,$(TARGET_OS))) +LIBLZ4 = liblz4-$(LIBVER_MAJOR) +EXT = .exe +else +EXT = .exe +ifneq (,$(filter MINGW%,$(TARGET_OS))) +EXT = .exe else -EXT = -VOID = /dev/null +ifneq (,$(filter MSYS%,$(TARGET_OS))) +EXT = .exe +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) +EXT = .exe +else +EXT = +endif +endif +endif endif +#determine if dev/nul based on host environment +ifneq (,$(filter MINGW%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter MSYS%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter CYGWIN%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter Windows%,$(OS))) +VOID := nul +else +VOID := /dev/null +endif +endif +endif +endif default: all diff --git a/lib/Makefile b/lib/Makefile index cb1571c..4e96b57 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -45,7 +45,10 @@ LIBVER := $(shell echo $(LIBVER_SCRIPT)) BUILD_SHARED:=yes BUILD_STATIC:=yes -OS ?= $(shell uname) +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif CPPFLAGS+= -DXXH_NAMESPACE=LZ4_ CFLAGS ?= -O3 DEBUGFLAGS:= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ @@ -71,10 +74,26 @@ else SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER) endif -ifneq (,$(filter Windows%,$(OS))) +WINBASED = yes +ifneq (,$(filter Windows%,$(TARGET_OS))) LIBLZ4 = liblz4-$(LIBVER_MAJOR) +LIBLZ4_EXP = liblz4.lib +else +LIBLZ4_EXP = liblz4.dll.a +ifneq (,$(filter MINGW%,$(TARGET_OS))) +LIBLZ4 = liblz4 +else +ifneq (,$(filter MSYS%,$(TARGET_OS))) +LIBLZ4 = msys-lz4-$(LIBVER_MAJOR) +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) +LIBLZ4 = cyglz4-$(LIBVER_MAJOR) else LIBLZ4 = liblz4.$(SHARED_EXT_VER) +WINBASED = no +endif +endif +endif endif .PHONY: default @@ -106,8 +125,8 @@ endif $(LIBLZ4): $(SRCFILES) ifeq ($(BUILD_SHARED),yes) # can be disabled on command line @echo compiling dynamic library $(LIBVER) -ifneq (,$(filter Windows%,$(OS))) - $(Q)$(CC) $(FLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o dll/$@.dll -Wl,--out-implib,dll/liblz4.lib +ifeq ($(WINBASED),yes) + $(Q)$(CC) $(FLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o dll/$@.dll -Wl,--out-implib,dll/$(LIBLZ4_EXP) else $(Q)$(CC) $(FLAGS) -shared $^ -fPIC -fvisibility=hidden $(SONAME_FLAGS) -o $@ @echo creating versioned links @@ -116,18 +135,19 @@ else endif endif +ifeq (,$(filter MINGW%,$(TARGET_OS))) liblz4: $(LIBLZ4) +endif clean: - $(Q)$(RM) core *.o liblz4.pc dll/liblz4.dll dll/liblz4.lib + $(Q)$(RM) core *.o liblz4.pc dll/$(LIBLZ4).dll dll/$(LIBLZ4_EXP) $(Q)$(RM) *.a *.$(SHARED_EXT) *.$(SHARED_EXT_MAJOR) *.$(SHARED_EXT_VER) @echo Cleaning library completed - #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT-6.1 MINGW64_NT-6.1 MINGW32_NT-10.0 MINGW64_NT-10.0)) +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT% MINGW64_NT% MSYS% CYGWIN_NT%,$(shell uname))) .PHONY: listL120 listL120: # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (note : $$, for Makefile compatibility) @@ -184,9 +204,9 @@ ifeq ($(BUILD_SHARED),yes) # Traditionnally, one installs the DLLs in the bin directory as programs # search them first in their directory. This allows to not pollute system # directories (like c:/windows/system32), nor modify the PATH variable. -ifneq (,$(filter Windows%,$(OS))) +ifeq ($(WINBASED),yes) $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4).dll $(DESTDIR)$(bindir) - $(Q)$(INSTALL_PROGRAM) dll/liblz4.lib $(DESTDIR)$(libdir) + $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4_EXP) $(DESTDIR)$(libdir) else $(Q)$(INSTALL_PROGRAM) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir) $(Q)ln -sf liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) @@ -201,9 +221,9 @@ endif uninstall: $(Q)$(RM) $(DESTDIR)$(pkgconfigdir)/liblz4.pc -ifneq (,$(filter Windows%,$(OS))) +ifeq (WINBASED,1) $(Q)$(RM) $(DESTDIR)$(bindir)/$(LIBLZ4).dll - $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.lib + $(Q)$(RM) $(DESTDIR)$(libdir)/$(LIBLZ4_EXP) else $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) diff --git a/programs/Makefile b/programs/Makefile index 92fd683..47912d8 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -56,17 +56,48 @@ LZ4_VERSION=$(LIBVER) MD2ROFF = ronn MD2ROFF_FLAGS = --roff --warnings --manual="User Commands" --organization="lz4 $(LZ4_VERSION)" +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif # Define *.exe as extension for Windows systems -ifneq (,$(filter Windows%,$(OS))) +ifneq (,$(filter Windows%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter MINGW%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter MSYS%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) EXT :=.exe -VOID := nul else EXT := -VOID := /dev/null +endif +endif +endif endif - +#determine if dev/nul based on host environment +ifneq (,$(filter MINGW%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter MSYS%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter CYGWIN%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter Windows%,$(OS))) +VOID := nul +else +VOID := /dev/null +endif +endif +endif +endif default: lz4-release @@ -109,7 +140,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT-6.1 MINGW64_NT-6.1 MINGW32_NT-10.0 MINGW64_NT-10.0)) +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT% MINGW64_NT% MSYS% CYGWIN_NT%,$(shell uname))) unlz4: lz4 ln -s lz4$(EXT) unlz4$(EXT) diff --git a/tests/Makefile b/tests/Makefile index 70cae63..d8104de 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -43,15 +43,72 @@ CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) CPPFLAGS+= -I$(LZ4DIR) -I$(PRGDIR) -DXXH_NAMESPACE=LZ4_ FLAGS = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) - # Define *.exe as extension for Windows systems +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif + +ifneq (,$(filter Windows%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter MINGW%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter MSYS%,$(TARGET_OS))) +EXT :=.exe +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) +EXT :=.exe +else +EXT := +endif +endif +endif +endif + +# determine name of .DLL for the target +WINBASED = yes +ifneq (,$(filter Windows%,$(TARGET_OS))) +LIBLZ4 = liblz4-$(LIBVER_MAJOR) +LIBLZ4_EXP = liblz4.lib +else +LIBLZ4_EXP = liblz4.dll.a +ifneq (,$(filter MINGW%,$(TARGET_OS))) +LIBLZ4 = liblz4 +else +ifneq (,$(filter MSYS%,$(TARGET_OS))) +LIBLZ4 = msys-lz4-$(LIBVER_MAJOR) +else +ifneq (,$(filter CYGWIN%,$(TARGET_OS))) +LIBLZ4 = cyglz4-$(LIBVER_MAJOR) +else +LIBLZ4 = liblz4.$(SHARED_EXT_VER) +WINBASED = no +endif +endif +endif +endif + +#determine if dev/nul based on host environment +ifneq (,$(filter MINGW%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter MSYS%,$(shell uname))) +VOID := /dev/null +else +ifneq (,$(filter CYGWIN%,$(shell uname))) +VOID := /dev/null +else ifneq (,$(filter Windows%,$(OS))) -EXT =.exe -VOID = nul +VOID := nul else -EXT = -VOID = /dev/null +VOID := /dev/null +endif endif +endif +endif + LZ4 := $(PRGDIR)/lz4$(EXT) @@ -95,7 +152,7 @@ fullbench-lib: fullbench.c $(LZ4DIR)/liblz4.a fullbench-dll: fullbench.c $(LZ4DIR)/xxhash.c $(MAKE) -C $(LZ4DIR) liblz4 - $(CC) $(FLAGS) $^ -o $@$(EXT) -DLZ4_DLL_IMPORT=1 $(LZ4DIR)/dll/liblz4.dll + $(CC) $(FLAGS) $^ -o $@$(EXT) -DLZ4_DLL_IMPORT=1 $(LZ4DIR)/dll/$(LIBLZ4).dll fuzzer : lz4.o lz4hc.o xxhash.o fuzzer.c $(CC) $(FLAGS) $^ -o $@$(EXT) @@ -137,7 +194,7 @@ checkTag: checkTag.c $(LZ4DIR)/lz4.h #----------------------------------------------------------------------------- # validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD)) +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) MD5:=md5sum ifneq (,$(filter $(shell uname), Darwin )) -- cgit v0.12 From ae5cea9112479df58d226f79ae34c07bc636a04d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 22 Apr 2019 12:27:25 -0700 Subject: fixed C90 compliance re-structure code, have everything into a single section of lz4io.c --- lib/lz4frame.h | 7 --- programs/lz4cli.c | 2 +- programs/lz4io.c | 127 +++++++++++++++++++++++++++++------------------------- programs/lz4io.h | 6 ++- 4 files changed, 74 insertions(+), 68 deletions(-) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 8c07e86..742c252 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -193,13 +193,6 @@ typedef struct { #define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } } /* v1.8.3+ */ -typedef struct { - LZ4F_frameInfo_t frameInfo; - const char* fileName; - unsigned long long fileSize; -} LZ4F_compFileInfo_t; - -#define LZ4F_INIT_FILEINFO { (LZ4F_frameInfo_t) LZ4F_INIT_FRAMEINFO, NULL, 0ULL } /*-********************************* * Simple compression function diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 443e4b4..39ff1ea 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -752,4 +752,4 @@ _cleanup: LZ4IO_freePreferences(prefs); free((void*)inFileNames); return operationResult; -} \ No newline at end of file +} diff --git a/programs/lz4io.c b/programs/lz4io.c index 175157e..1e6efe1 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1214,62 +1214,6 @@ static int LZ4IO_decompressDstFile(LZ4IO_prefs_t* const prefs, dRess_t ress, con } -static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ - const char *b, - *e; - char *t; - stat_t statbuf; - size_t readSize = LZ4F_HEADER_SIZE_MAX; - LZ4F_errorCode_t errorCode; - dRess_t ress; - /* Open file */ - FILE* const finput = LZ4IO_openSrcFile(input_filename); - if (finput==NULL) return 1; - - /* Get file size */ - if (!UTIL_getFileStat(input_filename, &statbuf)){ - EXM_THROW(60, "Can't stat file : %s", input_filename); - } - - cfinfo->fileSize = statbuf.st_size; - - /* Get basename without extension */ - b = strrchr(input_filename, '/'); - if (!b){ - b = strrchr(input_filename, '\\'); - } - if (b && b != input_filename){ - b++; - } else{ - b=input_filename; - } - e = strrchr(b, '.'); - - /* Allocate Memory */ - t = (char*)malloc( (e-b+1) * sizeof(char)); - ress.srcBuffer = malloc(LZ4IO_dBufferSize); - if (!t || !ress.srcBuffer) - EXM_THROW(21, "Allocation error : not enough memory"); - strncpy(t, b, (e-b)); - t[e-b] = '\0'; - cfinfo->fileName = t; - - /* init */ - errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); - if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); - - if (!fread(ress.srcBuffer, readSize, 1, finput)){ - EXM_THROW(30, "Error reading %s ", input_filename); - } - LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); - - /* Close input/free resources */ - fclose(finput); - free(ress.srcBuffer); - return 0; -} - - int LZ4IO_decompressFilename(LZ4IO_prefs_t* const prefs, const char* input_filename, const char* output_filename) { dRess_t const ress = LZ4IO_createDResources(prefs); @@ -1323,15 +1267,82 @@ int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** i } +/* ********************************************************************* */ +/* ********************** LZ4 --list command *********************** */ +/* ********************************************************************* */ + +typedef struct { + LZ4F_frameInfo_t frameInfo; + const char* fileName; + unsigned long long fileSize; +} LZ4F_compFileInfo_t; + +#define LZ4F_INIT_FILEINFO { LZ4F_INIT_FRAMEINFO, NULL, 0ULL } + + +static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ + const char *b, + *e; + char *t; + stat_t statbuf; + size_t readSize = LZ4F_HEADER_SIZE_MAX; + LZ4F_errorCode_t errorCode; + dRess_t ress; + /* Open file */ + FILE* const finput = LZ4IO_openSrcFile(input_filename); + if (finput==NULL) return 1; + + /* Get file size */ + if (!UTIL_getFileStat(input_filename, &statbuf)){ + EXM_THROW(60, "Can't stat file : %s", input_filename); + } + + cfinfo->fileSize = (unsigned long long)statbuf.st_size; + + /* Get basename without extension */ + b = strrchr(input_filename, '/'); + if (!b){ + b = strrchr(input_filename, '\\'); + } + if (b && b != input_filename){ + b++; + } else{ + b=input_filename; + } + e = strrchr(b, '.'); + + /* Allocate Memory */ + t = (char*)malloc( (size_t)(e-b+1) * sizeof(char)); + ress.srcBuffer = malloc(LZ4IO_dBufferSize); + if (!t || !ress.srcBuffer) + EXM_THROW(21, "Allocation error : not enough memory"); + strncpy(t, b, (e-b)); + t[e-b] = '\0'; + cfinfo->fileName = t; + + /* init */ + errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); + if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); + + if (!fread(ress.srcBuffer, readSize, 1, finput)){ + EXM_THROW(30, "Error reading %s ", input_filename); + } + LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); + + /* Close input/free resources */ + fclose(finput); + free(ress.srcBuffer); + return 0; +} + int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx){ size_t idx; int op_result=0; double ratio; - LZ4F_compFileInfo_t cfinfo; DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); for(idx=0; idx Date: Mon, 22 Apr 2019 15:48:48 -0400 Subject: Try to put some tests I made in ONE place. I also moved a test for "install" in one place to try to isolate it. --- Makefile | 48 ++------------------------------------ Makefile.inc | 59 +++++++++++++++++++++++++++++++++++++++++++++++ examples/Makefile | 48 +------------------------------------- lib/Makefile | 28 ++-------------------- tests/Makefile | 69 ++----------------------------------------------------- 5 files changed, 66 insertions(+), 186 deletions(-) create mode 100644 Makefile.inc diff --git a/Makefile b/Makefile index 51b4216..b7926b7 100644 --- a/Makefile +++ b/Makefile @@ -35,51 +35,7 @@ PRGDIR = programs TESTDIR = tests EXDIR = examples - -# Define *.exe as extension for targetting Windows systems -TARGET_OS ?= $(shell uname) -ifeq ($(TARGET_OS),) - TARGET_OS ?= $(OS) -endif - -ifneq (,$(filter Windows%,$(TARGET_OS))) -LIBLZ4 = liblz4-$(LIBVER_MAJOR) -EXT = .exe -else -EXT = .exe -ifneq (,$(filter MINGW%,$(TARGET_OS))) -EXT = .exe -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -EXT = .exe -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -EXT = .exe -else -EXT = -endif -endif -endif -endif - -#determine if dev/nul based on host environment -ifneq (,$(filter MINGW%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter MSYS%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter CYGWIN%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter Windows%,$(OS))) -VOID := nul -else -VOID := /dev/null -endif -endif -endif -endif +include Makefile.inc .PHONY: default default: lib-release lz4-release @@ -128,7 +84,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) +ifeq ($(POSIX_ENV),yes) HOST_OS = POSIX .PHONY: install uninstall diff --git a/Makefile.inc b/Makefile.inc new file mode 100644 index 0000000..d9dc891 --- /dev/null +++ b/Makefile.inc @@ -0,0 +1,59 @@ +TARGET_OS ?= $(shell uname) +ifeq ($(TARGET_OS),) + TARGET_OS ?= $(OS) +endif + +ifneq (,$(filter Windows%,$(TARGET_OS))) +LIBLZ4 = liblz4-$(LIBVER_MAJOR) +LIBLZ4_EXP = liblz4.lib +WINBASED = yes +else +LIBLZ4_EXP = liblz4.dll.a + ifneq (,$(filter MINGW%,$(TARGET_OS))) +LIBLZ4 = liblz4 +WINBASED = yes + else + ifneq (,$(filter MSYS%,$(TARGET_OS))) +LIBLZ4 = msys-lz4-$(LIBVER_MAJOR) +WINBASED = yes + else + ifneq (,$(filter CYGWIN%,$(TARGET_OS))) +LIBLZ4 = cyglz4-$(LIBVER_MAJOR) +WINBASED = yes + else +LIBLZ4 = liblz4.$(SHARED_EXT_VER) +WINBASED = no +EXT = + endif + endif + endif +endif + +ifeq ($(WINBASED),yes) +EXT = .exe +endif + +#determine if dev/nul based on host environment +ifneq (,$(filter MINGW%,$(shell uname))) +VOID := /dev/null +else + ifneq (,$(filter MSYS%,$(shell uname))) +VOID := /dev/null + else + ifneq (,$(filter CYGWIN%,$(shell uname))) +VOID := /dev/null + else + ifneq (,$(filter Windows%,$(OS))) +VOID := nul + else +VOID := /dev/null + endif + endif + endif +endif + +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) +POSIX_ENV = Yes +else +POSIX_ENV = No +endif diff --git a/examples/Makefile b/examples/Makefile index 26aaafd..6a34b33 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -36,53 +36,7 @@ TESTFILE = Makefile LZ4DIR := ../lib LZ4 = ../programs/lz4 - -# Define *.exe as extension for Windows systems - -# Define *.exe as extension for targetting Windows systems -TARGET_OS ?= $(shell uname) -ifeq ($(TARGET_OS),) - TARGET_OS ?= $(OS) -endif - -ifneq (,$(filter Windows%,$(TARGET_OS))) -LIBLZ4 = liblz4-$(LIBVER_MAJOR) -EXT = .exe -else -EXT = .exe -ifneq (,$(filter MINGW%,$(TARGET_OS))) -EXT = .exe -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -EXT = .exe -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -EXT = .exe -else -EXT = -endif -endif -endif -endif - -#determine if dev/nul based on host environment -ifneq (,$(filter MINGW%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter MSYS%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter CYGWIN%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter Windows%,$(OS))) -VOID := nul -else -VOID := /dev/null -endif -endif -endif -endif +include ../Makefile.inc default: all diff --git a/lib/Makefile b/lib/Makefile index 4e96b57..0546031 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -45,10 +45,6 @@ LIBVER := $(shell echo $(LIBVER_SCRIPT)) BUILD_SHARED:=yes BUILD_STATIC:=yes -TARGET_OS ?= $(shell uname) -ifeq ($(TARGET_OS),) - TARGET_OS ?= $(OS) -endif CPPFLAGS+= -DXXH_NAMESPACE=LZ4_ CFLAGS ?= -O3 DEBUGFLAGS:= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ @@ -74,27 +70,7 @@ else SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER) endif -WINBASED = yes -ifneq (,$(filter Windows%,$(TARGET_OS))) -LIBLZ4 = liblz4-$(LIBVER_MAJOR) -LIBLZ4_EXP = liblz4.lib -else -LIBLZ4_EXP = liblz4.dll.a -ifneq (,$(filter MINGW%,$(TARGET_OS))) -LIBLZ4 = liblz4 -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -LIBLZ4 = msys-lz4-$(LIBVER_MAJOR) -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -LIBLZ4 = cyglz4-$(LIBVER_MAJOR) -else -LIBLZ4 = liblz4.$(SHARED_EXT_VER) -WINBASED = no -endif -endif -endif -endif +include ../Makefile.inc .PHONY: default default: lib-release @@ -147,7 +123,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT% MINGW64_NT% MSYS% CYGWIN_NT%,$(shell uname))) +ifeq ($(POSIX_ENV),yes) .PHONY: listL120 listL120: # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (note : $$, for Makefile compatibility) diff --git a/tests/Makefile b/tests/Makefile index d8104de..b9afb02 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -43,71 +43,7 @@ CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS) CPPFLAGS+= -I$(LZ4DIR) -I$(PRGDIR) -DXXH_NAMESPACE=LZ4_ FLAGS = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -# Define *.exe as extension for Windows systems -TARGET_OS ?= $(shell uname) -ifeq ($(TARGET_OS),) - TARGET_OS ?= $(OS) -endif - -ifneq (,$(filter Windows%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter MINGW%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -EXT :=.exe -else -EXT := -endif -endif -endif -endif - -# determine name of .DLL for the target -WINBASED = yes -ifneq (,$(filter Windows%,$(TARGET_OS))) -LIBLZ4 = liblz4-$(LIBVER_MAJOR) -LIBLZ4_EXP = liblz4.lib -else -LIBLZ4_EXP = liblz4.dll.a -ifneq (,$(filter MINGW%,$(TARGET_OS))) -LIBLZ4 = liblz4 -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -LIBLZ4 = msys-lz4-$(LIBVER_MAJOR) -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -LIBLZ4 = cyglz4-$(LIBVER_MAJOR) -else -LIBLZ4 = liblz4.$(SHARED_EXT_VER) -WINBASED = no -endif -endif -endif -endif - -#determine if dev/nul based on host environment -ifneq (,$(filter MINGW%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter MSYS%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter CYGWIN%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter Windows%,$(OS))) -VOID := nul -else -VOID := /dev/null -endif -endif -endif -endif +include ../Makefile.inc LZ4 := $(PRGDIR)/lz4$(EXT) @@ -117,7 +53,6 @@ TEST_FILES := COPYING FUZZER_TIME := -T90s NB_LOOPS ?= -i1 - default: all all: fullbench fuzzer frametest roundTripTest datagen checkFrame @@ -194,7 +129,7 @@ checkTag: checkTag.c $(LZ4DIR)/lz4.h #----------------------------------------------------------------------------- # validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) +ifeq ($(POSIX_ENV),yes) MD5:=md5sum ifneq (,$(filter $(shell uname), Darwin )) -- cgit v0.12 From 2acddd9918bdef87179d63fd06dc31e9d9bc3f1e Mon Sep 17 00:00:00 2001 From: JPeterMugaas Date: Mon, 22 Apr 2019 16:06:04 -0400 Subject: Fix a test for mingw --- Makefile | 2 +- Makefile.inc | 2 +- lib/Makefile | 2 +- tests/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b7926b7..dd731eb 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifeq ($(POSIX_ENV),yes) +ifeq ($(POSIX_ENV),Yes) HOST_OS = POSIX .PHONY: install uninstall diff --git a/Makefile.inc b/Makefile.inc index d9dc891..c09ba62 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -52,7 +52,7 @@ VOID := /dev/null endif endif -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32% MINGW64% CYGWIN% MSYS%,$(shell uname))) +ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW% CYGWIN% MSYS%,$(shell uname))) POSIX_ENV = Yes else POSIX_ENV = No diff --git a/lib/Makefile b/lib/Makefile index 0546031..28853df 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -123,7 +123,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifeq ($(POSIX_ENV),yes) +ifeq ($(POSIX_ENV),Yes) .PHONY: listL120 listL120: # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (note : $$, for Makefile compatibility) diff --git a/tests/Makefile b/tests/Makefile index b9afb02..9b7ed8d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -129,7 +129,7 @@ checkTag: checkTag.c $(LZ4DIR)/lz4.h #----------------------------------------------------------------------------- # validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifeq ($(POSIX_ENV),yes) +ifeq ($(POSIX_ENV),Yes) MD5:=md5sum ifneq (,$(filter $(shell uname), Darwin )) -- cgit v0.12 From 0d4c885abb793b3bdb7ad6c815671e5847b53e6e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 22 Apr 2019 14:01:19 -0700 Subject: refactored --list function better handling of special conditions, better scoping of variables. Also : updated man page --- programs/lz4.1 | 24 ++++---- programs/lz4io.c | 176 ++++++++++++++++++++++++++++++------------------------- programs/lz4io.h | 3 +- tests/Makefile | 1 + 4 files changed, 111 insertions(+), 93 deletions(-) diff --git a/programs/lz4.1 b/programs/lz4.1 index 1576e45..eb82b68 100644 --- a/programs/lz4.1 +++ b/programs/lz4.1 @@ -1,5 +1,5 @@ . -.TH "LZ4" "1" "April 2019" "lz4 1.9.0" "User Commands" +.TH "LZ4" "1" "April 2019" "lz4 1.9.1" "User Commands" . .SH "NAME" \fBlz4\fR \- lz4, unlz4, lz4cat \- Compress or decompress \.lz4 files @@ -23,9 +23,6 @@ When writing scripts that need to decompress files, it is recommended to always \fBlz4\fR supports a command line syntax similar \fIbut not identical\fR to \fBgzip(1)\fR\. Differences are : . .IP "\(bu" 4 -\fBlz4\fR preserves original files -. -.IP "\(bu" 4 \fBlz4\fR compresses a single file by default (see \fB\-m\fR for multiple files) . .IP "\(bu" 4 @@ -35,19 +32,16 @@ When writing scripts that need to decompress files, it is recommended to always \fBlz4 file\.lz4\fR will default to decompression (use \fB\-z\fR to force compression) . .IP "\(bu" 4 -\fBlz4\fR shows real\-time notification statistics during compression or decompression of a single file (use \fB\-q\fR to silence them) -. -.IP "\(bu" 4 -If no destination name is provided, result is sent to \fBstdout\fR \fIexcept if stdout is the console\fR\. +\fBlz4\fR preserves original files . .IP "\(bu" 4 -If no destination name is provided, \fBand\fR if \fBstdout\fR is the console, \fBfile\fR is compressed into \fBfile\.lz4\fR\. +\fBlz4\fR shows real\-time notification statistics during compression or decompression of a single file (use \fB\-q\fR to silence them) . .IP "\(bu" 4 -As a consequence of previous rules, note the following example : \fBlz4 file | consumer\fR sends compressed data to \fBconsumer\fR through \fBstdout\fR, hence it does \fInot\fR create \fBfile\.lz4\fR\. +When no destination is specified, result is sent on implicit output, which depends on \fBstdout\fR status\. When \fBstdout\fR \fIis Not the console\fR, it becomes the implicit output\. Otherwise, if \fBstdout\fR is the console, the implicit output is \fBfilename\.lz4\fR\. . .IP "\(bu" 4 -Another consequence of those rules is that to run \fBlz4\fR under \fBnohup\fR, you should provide a destination file: \fBnohup lz4 file file\.lz4\fR, because \fBnohup\fR writes the specified command\'s output to a file\. +It is considered bad practice to rely on implicit output in scripts\. because the script\'s environment may change\. Always use explicit output in scripts\. \fB\-c\fR ensures that output will be \fBstdout\fR\. Conversely, providing a destination name, or using \fB\-m\fR ensures that the output will be either the specified name, or \fBfilename\.lz4\fR respectively\. . .IP "" 0 . @@ -55,7 +49,7 @@ Another consequence of those rules is that to run \fBlz4\fR under \fBnohup\fR, y Default behaviors can be modified by opt\-in commands, detailed below\. . .IP "\(bu" 4 -\fBlz4 \-m\fR makes it possible to provide multiple input filenames, which will be compressed into files using suffix \fB\.lz4\fR\. Progress notifications are also disabled by default (use \fB\-v\fR to enable them)\. This mode has a behavior which more closely mimics \fBgzip\fR command line, with the main remaining difference being that source files are preserved by default\. +\fBlz4 \-m\fR makes it possible to provide multiple input filenames, which will be compressed into files using suffix \fB\.lz4\fR\. Progress notifications become disabled by default (use \fB\-v\fR to enable them)\. This mode has a behavior which more closely mimics \fBgzip\fR command line, with the main remaining difference being that source files are preserved by default\. . .IP "\(bu" 4 Similarly, \fBlz4 \-m \-d\fR can decompress multiple \fB*\.lz4\fR files\. @@ -111,6 +105,10 @@ Test the integrity of compressed \fB\.lz4\fR files\. The decompressed data is di \fB\-b#\fR Benchmark mode, using \fB#\fR compression level\. . +.TP +\fB\-\-list\fR +List mode\. Lists information about \.lz4 files\. Useful if compressed with \-\-content\-size flag\. +. .SS "Operation modifiers" . .TP @@ -145,7 +143,7 @@ Force write to standard output, even if it is the console\. . .TP \fB\-m\fR \fB\-\-multiple\fR -Multiple input files\. Compressed file names will be appended a \fB\.lz4\fR suffix\. This mode also reduces notification level\. \fBlz4 \-m\fR has a behavior equivalent to \fBgzip \-k\fR (it preserves source files by default)\. +Multiple input files\. Compressed file names will be appended a \fB\.lz4\fR suffix\. This mode also reduces notification level\. Can also be used to list multiple files\. \fBlz4 \-m\fR has a behavior equivalent to \fBgzip \-k\fR (it preserves source files by default)\. . .TP \fB\-r\fR diff --git a/programs/lz4io.c b/programs/lz4io.c index 1e6efe1..e3eed93 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1275,87 +1275,105 @@ typedef struct { LZ4F_frameInfo_t frameInfo; const char* fileName; unsigned long long fileSize; -} LZ4F_compFileInfo_t; - -#define LZ4F_INIT_FILEINFO { LZ4F_INIT_FRAMEINFO, NULL, 0ULL } - - -static int LZ4IO_getCompressedFileInfo(const char* input_filename, LZ4F_compFileInfo_t* cfinfo){ - const char *b, - *e; - char *t; - stat_t statbuf; - size_t readSize = LZ4F_HEADER_SIZE_MAX; - LZ4F_errorCode_t errorCode; - dRess_t ress; - /* Open file */ - FILE* const finput = LZ4IO_openSrcFile(input_filename); - if (finput==NULL) return 1; - - /* Get file size */ - if (!UTIL_getFileStat(input_filename, &statbuf)){ - EXM_THROW(60, "Can't stat file : %s", input_filename); - } - - cfinfo->fileSize = (unsigned long long)statbuf.st_size; - - /* Get basename without extension */ - b = strrchr(input_filename, '/'); - if (!b){ - b = strrchr(input_filename, '\\'); - } - if (b && b != input_filename){ - b++; - } else{ - b=input_filename; - } - e = strrchr(b, '.'); - - /* Allocate Memory */ - t = (char*)malloc( (size_t)(e-b+1) * sizeof(char)); - ress.srcBuffer = malloc(LZ4IO_dBufferSize); - if (!t || !ress.srcBuffer) - EXM_THROW(21, "Allocation error : not enough memory"); - strncpy(t, b, (e-b)); - t[e-b] = '\0'; - cfinfo->fileName = t; - - /* init */ - errorCode = LZ4F_createDecompressionContext(&ress.dCtx, LZ4F_VERSION); - if (LZ4F_isError(errorCode)) EXM_THROW(60, "Can't create LZ4F context : %s", LZ4F_getErrorName(errorCode)); - - if (!fread(ress.srcBuffer, readSize, 1, finput)){ - EXM_THROW(30, "Error reading %s ", input_filename); - } - LZ4F_getFrameInfo(ress.dCtx, &cfinfo->frameInfo, ress.srcBuffer, &readSize); - - /* Close input/free resources */ - fclose(finput); - free(ress.srcBuffer); - return 0; -} +} LZ4IO_cFileInfo_t; + +#define LZ4IO_INIT_CFILEINFO { LZ4F_INIT_FRAMEINFO, NULL, 0ULL } + + +/* This function is limited, + * it only works fine for a file consisting of a single valid frame. + * It will / may stop program execution if a single filename is wrong. + * It will not look at content beyond first frame header. + * + * Things to improve : + * - continue execution after an error, just report an error code, keep all memory clean + * - check the entire file for additional content after first frame + * + combine results from multiple frames, give total + * - Optional : + * + report nb of blocks, hence max. possible decompressed size (when not reported in header) + * + report block type (B4D, B7I, etc.) + */ +static int +LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filename) +{ + /* Get file size */ + cfinfo->fileSize = UTIL_getFileSize(input_filename); /* returns 0 if cannot read information */ -int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx){ - size_t idx; - int op_result=0; - double ratio; - DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n","BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); - for(idx=0; idxfileName = b; } - if(cfinfo.frameInfo.contentSize){ - ratio = (double)cfinfo.fileSize / cfinfo.frameInfo.contentSize; - DISPLAY("%-16d\t%-20llu\t%-20llu\t%-8.4f\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize,cfinfo.frameInfo.contentSize, ratio, cfinfo.fileName); + + /* Read file and extract header */ + { size_t readSize = LZ4F_HEADER_SIZE_MAX; + void* buffer = malloc(readSize); + LZ4F_dctx* dctx; + + if (!buffer) EXM_THROW(21, "Allocation error : not enough memory"); + { LZ4F_errorCode_t const errorCode = + LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION); + if (LZ4F_isError(errorCode)) + EXM_THROW(60, "Can't create LZ4F context : %s", + LZ4F_getErrorName(errorCode)); + } + + { FILE* const finput = LZ4IO_openSrcFile(input_filename); + if (finput==NULL) return 1; + if (!fread(buffer, readSize, 1, finput)) { + EXM_THROW(30, "Error reading %s ", input_filename); + } + fclose(finput); + } + + { LZ4F_errorCode_t const errorCode = + LZ4F_getFrameInfo(dctx, &cfinfo->frameInfo, buffer, &readSize); + if (LZ4F_isError(errorCode)) + EXM_THROW(60, "Cannot interpret LZ4 frame : %s", + LZ4F_getErrorName(errorCode)); + } + + /* clean */ + free(buffer); + LZ4F_freeDecompressionContext(dctx); } - else{ - DISPLAY("%-16d\t%-20llu\t%-20s\t%-10s\t%s\n",cfinfo.frameInfo.blockChecksumFlag,cfinfo.fileSize, "-", "-", cfinfo.fileName); + + return 0; +} + +int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx) +{ + size_t idx; + + DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n", + "BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); + + for (idx=0; idx> tmp-tlb-hw.lz4 $(LZ4) -f tmp-tlb-hw.lz4 # uncompress valid frame followed by invalid data $(LZ4) -BX tmp-tlb-hw -c -q | $(LZ4) -tv # test block checksum -- cgit v0.12 From 5e6807fd95284fcef48a976e2a28617f8ff134d7 Mon Sep 17 00:00:00 2001 From: JPeterMugaas Date: Mon, 22 Apr 2019 17:38:43 -0400 Subject: Make programs/Makefile use the includes. --- programs/Makefile | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 47912d8..e055491 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -56,48 +56,7 @@ LZ4_VERSION=$(LIBVER) MD2ROFF = ronn MD2ROFF_FLAGS = --roff --warnings --manual="User Commands" --organization="lz4 $(LZ4_VERSION)" -TARGET_OS ?= $(shell uname) -ifeq ($(TARGET_OS),) - TARGET_OS ?= $(OS) -endif - -# Define *.exe as extension for Windows systems -ifneq (,$(filter Windows%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter MINGW%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter MSYS%,$(TARGET_OS))) -EXT :=.exe -else -ifneq (,$(filter CYGWIN%,$(TARGET_OS))) -EXT :=.exe -else -EXT := -endif -endif -endif -endif - -#determine if dev/nul based on host environment -ifneq (,$(filter MINGW%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter MSYS%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter CYGWIN%,$(shell uname))) -VOID := /dev/null -else -ifneq (,$(filter Windows%,$(OS))) -VOID := nul -else -VOID := /dev/null -endif -endif -endif -endif +include ../Makefile.inc default: lz4-release -- cgit v0.12 From f401f1de7eba98ee5acde5b8dd9681ff1aa76b56 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 22 Apr 2019 15:01:20 -0700 Subject: --list can resume after a failed file --- programs/lz4io.c | 103 ++++++++++++++++++++++++++++++++----------------------- programs/lz4io.h | 2 +- 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/programs/lz4io.c b/programs/lz4io.c index e3eed93..2a7b4b9 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1230,7 +1230,9 @@ int LZ4IO_decompressFilename(LZ4IO_prefs_t* const prefs, const char* input_filen } -int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** inFileNamesTable, int ifntSize, const char* suffix) +int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, + const char** inFileNamesTable, int ifntSize, + const char* suffix) { int i; int skippedFiles = 0; @@ -1250,7 +1252,12 @@ int LZ4IO_decompressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** i missingFiles += LZ4IO_decompressSrcFile(prefs, ress, inFileNamesTable[i], stdoutmark); continue; } - if (ofnSize <= ifnSize-suffixSize+1) { free(outFileName); ofnSize = ifnSize + 20; outFileName = (char*)malloc(ofnSize); if (outFileName==NULL) return ifntSize; } + if (ofnSize <= ifnSize-suffixSize+1) { + free(outFileName); + ofnSize = ifnSize + 20; + outFileName = (char*)malloc(ofnSize); + if (outFileName==NULL) return ifntSize; + } if (ifnSize <= suffixSize || strcmp(suffixPtr, suffix) != 0) { DISPLAYLEVEL(1, "File extension doesn't match expected LZ4_EXTENSION (%4s); will not process file: %s\n", suffix, inFileNamesTable[i]); skippedFiles++; @@ -1279,6 +1286,13 @@ typedef struct { #define LZ4IO_INIT_CFILEINFO { LZ4F_INIT_FRAMEINFO, NULL, 0ULL } +#define CHECK_Z_THROW(f) { \ + LZ4F_errorCode_t const ec = (f); \ + if (LZ4F_isError(ec)) \ + EXM_THROW(1, "LZ4F error : %s", LZ4F_getErrorName(ec)); \ +} + +typedef enum { LZ4IO_LZ4F_OK, LZ4IO_format_not_known, LZ4IO_not_a_file } LZ4IO_infoResult; /* This function is limited, * it only works fine for a file consisting of a single valid frame. @@ -1286,17 +1300,18 @@ typedef struct { * It will not look at content beyond first frame header. * * Things to improve : - * - continue execution after an error, just report an error code, keep all memory clean * - check the entire file for additional content after first frame * + combine results from multiple frames, give total * - Optional : * + report nb of blocks, hence max. possible decompressed size (when not reported in header) * + report block type (B4D, B7I, etc.) */ -static int +static LZ4IO_infoResult LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filename) { - /* Get file size */ + LZ4IO_infoResult result = LZ4IO_format_not_known; /* default result (error) */ + + if (!UTIL_isRegFile(input_filename)) return LZ4IO_not_a_file; cfinfo->fileSize = UTIL_getFileSize(input_filename); /* returns 0 if cannot read information */ /* Get filename without path prefix */ @@ -1313,67 +1328,69 @@ LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filenam } /* Read file and extract header */ - { size_t readSize = LZ4F_HEADER_SIZE_MAX; - void* buffer = malloc(readSize); - LZ4F_dctx* dctx; + { size_t const hSize = LZ4F_HEADER_SIZE_MAX; + size_t readSize=0; + void* const buffer = malloc(hSize); if (!buffer) EXM_THROW(21, "Allocation error : not enough memory"); - { LZ4F_errorCode_t const errorCode = - LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION); - if (LZ4F_isError(errorCode)) - EXM_THROW(60, "Can't create LZ4F context : %s", - LZ4F_getErrorName(errorCode)); - } - { FILE* const finput = LZ4IO_openSrcFile(input_filename); - if (finput==NULL) return 1; - if (!fread(buffer, readSize, 1, finput)) { - EXM_THROW(30, "Error reading %s ", input_filename); - } - fclose(finput); - } + if (finput) { + readSize = fread(buffer, 1, hSize, finput); + fclose(finput); + } } - { LZ4F_errorCode_t const errorCode = - LZ4F_getFrameInfo(dctx, &cfinfo->frameInfo, buffer, &readSize); - if (LZ4F_isError(errorCode)) - EXM_THROW(60, "Cannot interpret LZ4 frame : %s", - LZ4F_getErrorName(errorCode)); + if (readSize > 0) { + LZ4F_dctx* dctx; + CHECK_Z_THROW(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)); + if (!LZ4F_isError(LZ4F_getFrameInfo(dctx, &cfinfo->frameInfo, buffer, &readSize))) { + result = LZ4IO_LZ4F_OK; + } + LZ4F_freeDecompressionContext(dctx); } /* clean */ free(buffer); - LZ4F_freeDecompressionContext(dctx); } - return 0; + return result; } -int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, const size_t ifnIdx) +int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx) { + int result = 0; size_t idx; - DISPLAY("%16s\t%-20s\t%-20s\t%-10s\t%s\n", - "BlockChecksumFlag","Compressed", "Uncompressed", "Ratio", "Filename"); + DISPLAY("%20s %20s %10s %7s %s\n", + "Compressed", "Uncompressed", "Ratio", "Check", "Filename"); for (idx=0; idx Date: Mon, 22 Apr 2019 15:14:53 -0700 Subject: --list gives block type --- programs/lz4.1 | 2 +- programs/lz4.1.md | 5 ++--- programs/lz4io.c | 26 +++++++++++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/programs/lz4.1 b/programs/lz4.1 index eb82b68..ad0c12c 100644 --- a/programs/lz4.1 +++ b/programs/lz4.1 @@ -107,7 +107,7 @@ Benchmark mode, using \fB#\fR compression level\. . .TP \fB\-\-list\fR -List mode\. Lists information about \.lz4 files\. Useful if compressed with \-\-content\-size flag\. +List information about \.lz4 files\. note : current implementation is limited to single\-frame \.lz4 files\. . .SS "Operation modifiers" . diff --git a/programs/lz4.1.md b/programs/lz4.1.md index 62f672e..8874467 100644 --- a/programs/lz4.1.md +++ b/programs/lz4.1.md @@ -114,9 +114,8 @@ only the latest one will be applied. Benchmark mode, using `#` compression level. * `--list`: - List mode. - Lists information about .lz4 files. - Useful if compressed with --content-size flag. + List information about .lz4 files. + note : current implementation is limited to single-frame .lz4 files. ### Operation modifiers diff --git a/programs/lz4io.c b/programs/lz4io.c index 2a7b4b9..5393cd0 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1304,7 +1304,6 @@ typedef enum { LZ4IO_LZ4F_OK, LZ4IO_format_not_known, LZ4IO_not_a_file } LZ4IO_i * + combine results from multiple frames, give total * - Optional : * + report nb of blocks, hence max. possible decompressed size (when not reported in header) - * + report block type (B4D, B7I, etc.) */ static LZ4IO_infoResult LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filename) @@ -1355,13 +1354,26 @@ LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filenam return result; } + +/* buffer : must be a valid memory area of at least 4 bytes */ +const char* LZ4IO_blockTypeID(int sizeID, int blockMode, char* buffer) +{ + buffer[0] = 'B'; + assert(sizeID >= 4); assert(sizeID <=7); + buffer[1] = (char)(sizeID + '0'); + buffer[2] = (blockMode == LZ4F_blockIndependent) ? 'I' : 'D'; + buffer[3] = 0; + return buffer; +} + + int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx) { int result = 0; size_t idx; - DISPLAY("%20s %20s %10s %7s %s\n", - "Compressed", "Uncompressed", "Ratio", "Check", "Filename"); + DISPLAY("%5s %20s %20s %10s %7s %s\n", + "Block", "Compressed", "Uncompressed", "Ratio", "Check", "Filename"); for (idx=0; idx Date: Mon, 22 Apr 2019 15:24:44 -0700 Subject: updated code comments --- programs/lz4io.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/programs/lz4io.c b/programs/lz4io.c index 5393cd0..105718d 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1295,9 +1295,9 @@ typedef struct { typedef enum { LZ4IO_LZ4F_OK, LZ4IO_format_not_known, LZ4IO_not_a_file } LZ4IO_infoResult; /* This function is limited, - * it only works fine for a file consisting of a single valid frame. - * It will / may stop program execution if a single filename is wrong. + * it only works fine for a file consisting of a single valid frame using LZ4 Frame specification. * It will not look at content beyond first frame header. + * It's also unable to parse legacy frames, nor skippable ones. * * Things to improve : * - check the entire file for additional content after first frame @@ -1311,7 +1311,7 @@ LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filenam LZ4IO_infoResult result = LZ4IO_format_not_known; /* default result (error) */ if (!UTIL_isRegFile(input_filename)) return LZ4IO_not_a_file; - cfinfo->fileSize = UTIL_getFileSize(input_filename); /* returns 0 if cannot read information */ + cfinfo->fileSize = UTIL_getFileSize(input_filename); /* Get filename without path prefix */ { const char* b = strrchr(input_filename, '/'); @@ -1329,9 +1329,10 @@ LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filenam /* Read file and extract header */ { size_t const hSize = LZ4F_HEADER_SIZE_MAX; size_t readSize=0; - void* const buffer = malloc(hSize); + void* const buffer = malloc(hSize); if (!buffer) EXM_THROW(21, "Allocation error : not enough memory"); + { FILE* const finput = LZ4IO_openSrcFile(input_filename); if (finput) { readSize = fread(buffer, 1, hSize, finput); -- cgit v0.12 From 35b83a921f8030ee9b71cbb7324dc7aafaeb9878 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 22 Apr 2019 16:06:22 -0700 Subject: fix: no leak when LZ4F_dctx creation fails strange, because it previous implementation, it would `exit()`, so it should not matter ... --- programs/lz4io.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/programs/lz4io.c b/programs/lz4io.c index 105718d..960c451 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -1286,11 +1286,6 @@ typedef struct { #define LZ4IO_INIT_CFILEINFO { LZ4F_INIT_FRAMEINFO, NULL, 0ULL } -#define CHECK_Z_THROW(f) { \ - LZ4F_errorCode_t const ec = (f); \ - if (LZ4F_isError(ec)) \ - EXM_THROW(1, "LZ4F error : %s", LZ4F_getErrorName(ec)); \ -} typedef enum { LZ4IO_LZ4F_OK, LZ4IO_format_not_known, LZ4IO_not_a_file } LZ4IO_infoResult; @@ -1341,10 +1336,10 @@ LZ4IO_getCompressedFileInfo(LZ4IO_cFileInfo_t* cfinfo, const char* input_filenam if (readSize > 0) { LZ4F_dctx* dctx; - CHECK_Z_THROW(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)); - if (!LZ4F_isError(LZ4F_getFrameInfo(dctx, &cfinfo->frameInfo, buffer, &readSize))) { - result = LZ4IO_LZ4F_OK; - } + if (!LZ4F_isError(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION))) { + if (!LZ4F_isError(LZ4F_getFrameInfo(dctx, &cfinfo->frameInfo, buffer, &readSize))) { + result = LZ4IO_LZ4F_OK; + } } LZ4F_freeDecompressionContext(dctx); } -- cgit v0.12 From 1e700b6f85bbc9e7052190f2f686041367321766 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 22 Apr 2019 17:45:24 -0700 Subject: updated NEWS for v1.9.1 --- NEWS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 7722d73..860f15b 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ v1.9.1 -fix : decompression functions were reading beyond input size (introduced in v1.9.0, reported by @ppodolsky and @danlark1) +fix : decompression functions were reading a few bytes beyond input size (introduced in v1.9.0, reported by @ppodolsky and @danlark1) api : fix : lz4frame initializers compatibility with c++, reported by @degski +cli : added command --list, based on a patch by @gabrielstedman +build: improved Windows build, by @JPeterMugaas build: AIX, by Norman Green v1.9.0 -- cgit v0.12 From 7136489d336fd2e584eb13cb858983caac5ad2e8 Mon Sep 17 00:00:00 2001 From: JPeterMugaas Date: Tue, 23 Apr 2019 07:44:00 -0400 Subject: More build imrpvements Moved a few other tests to Makefiles.inc. Other things might need to go there. Made a test for symlink appropriateness. Windows can NOT handle them the same way Unix-like operating systems do (if at all). This is mostly the same as the Visual C projects. embed version info into .dll and .exes that are redistributed. --- Makefile.inc | 50 +++++++++++++++++++++++++-------- lib/Makefile | 75 ++++++++++++++++++++++++++------------------------ lib/liblz4-dll.rc.in | 35 +++++++++++++++++++++++ programs/Makefile | 53 +++++++++++++++++++++-------------- programs/lz4-exe.rc.in | 27 ++++++++++++++++++ tests/Makefile | 2 +- 6 files changed, 173 insertions(+), 69 deletions(-) create mode 100644 lib/liblz4-dll.rc.in create mode 100644 programs/lz4-exe.rc.in diff --git a/Makefile.inc b/Makefile.inc index c09ba62..2d64405 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1,3 +1,9 @@ +ifeq ($(V), 1) +Q = +else +Q = @ +endif + TARGET_OS ?= $(shell uname) ifeq ($(TARGET_OS),) TARGET_OS ?= $(OS) @@ -31,24 +37,17 @@ endif ifeq ($(WINBASED),yes) EXT = .exe +WINDRES = windres endif #determine if dev/nul based on host environment -ifneq (,$(filter MINGW%,$(shell uname))) +ifneq (,$(filter MINGW% MSYS% CYGWIN%,$(shell uname))) VOID := /dev/null else - ifneq (,$(filter MSYS%,$(shell uname))) -VOID := /dev/null - else - ifneq (,$(filter CYGWIN%,$(shell uname))) -VOID := /dev/null - else - ifneq (,$(filter Windows%,$(OS))) + ifneq (,$(filter Windows%,$(OS))) VOID := nul - else + else VOID := /dev/null - endif - endif endif endif @@ -57,3 +56,32 @@ POSIX_ENV = Yes else POSIX_ENV = No endif + +# Avoid symlinks when targetting Windows or building on a Windows host +ifeq ($(WINBASED),yes) +LN_S = cp -p +LN_SF = cp -p +else + ifneq (,$(filter MINGW% MSYS% CYGWIN%,$(shell uname))) +LN_S = cp -p +LN_SF = cp -p + else + ifneq (,$(filter Windows%,$(OS))) +LN_S = cp -p +LN_SF = cp -p + else +LN_S = ln -s +LN_SF = ln -sf + endif + endif +endif + +ifneq (,$(filter $(shell uname),SunOS)) +INSTALL ?= ginstall +else +INSTALL ?= install +endif + +INSTALL_PROGRAM ?= $(INSTALL) -m 755 +INSTALL_DATA ?= $(INSTALL) -m 644 +INSTALL_DIR ?= $(INSTALL) -d -m 755 diff --git a/lib/Makefile b/lib/Makefile index 28853df..330642a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -85,12 +85,6 @@ all: lib all32: CFLAGS+=-m32 all32: all -ifeq ($(V), 1) -Q = -else -Q = @ -endif - liblz4.a: $(SRCFILES) ifeq ($(BUILD_STATIC),yes) # can be disabled on command line @echo compiling static library @@ -98,17 +92,32 @@ ifeq ($(BUILD_STATIC),yes) # can be disabled on command line $(Q)$(AR) rcs $@ *.o endif +ifeq ($(WINBASED),yes) +liblz4-dll.rc: liblz4-dll.rc.in + @echo creating library resource + $(Q)sed -e 's|@LIBLZ4@|$(LIBLZ4)|' \ + -e 's|@LIBVER_MAJOR@|$(LIBVER_MAJOR)|g' \ + -e 's|@LIBVER_MINOR@|$(LIBVER_MINOR)|g' \ + -e 's|@LIBVER_PATCH@|$(LIBVER_PATCH)|g' \ + $< >$@ + +liblz4-dll.o: liblz4-dll.rc + $(WINDRES) -i liblz4-dll.rc -o liblz4-dll.o + +$(LIBLZ4): $(SRCFILES) liblz4-dll.o +else $(LIBLZ4): $(SRCFILES) +endif ifeq ($(BUILD_SHARED),yes) # can be disabled on command line @echo compiling dynamic library $(LIBVER) -ifeq ($(WINBASED),yes) + ifeq ($(WINBASED),yes) $(Q)$(CC) $(FLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o dll/$@.dll -Wl,--out-implib,dll/$(LIBLZ4_EXP) -else + else $(Q)$(CC) $(FLAGS) -shared $^ -fPIC -fvisibility=hidden $(SONAME_FLAGS) -o $@ @echo creating versioned links - $(Q)ln -sf $@ liblz4.$(SHARED_EXT_MAJOR) - $(Q)ln -sf $@ liblz4.$(SHARED_EXT) -endif + $(Q)$(LN_SF) $@ liblz4.$(SHARED_EXT_MAJOR) + $(Q)$(LN_SF) $@ liblz4.$(SHARED_EXT) + endif endif ifeq (,$(filter MINGW%,$(TARGET_OS))) @@ -116,6 +125,9 @@ liblz4: $(LIBLZ4) endif clean: +ifeq ($(WINBASED),yes) + $(Q)$(RM) *.rc +endif $(Q)$(RM) core *.o liblz4.pc dll/$(LIBLZ4).dll dll/$(LIBLZ4_EXP) $(Q)$(RM) *.a *.$(SHARED_EXT) *.$(SHARED_EXT_MAJOR) *.$(SHARED_EXT_VER) @echo Cleaning library completed @@ -144,22 +156,13 @@ libdir ?= $(LIBDIR) INCLUDEDIR ?= $(prefix)/include includedir ?= $(INCLUDEDIR) -ifneq (,$(filter $(OS),OpenBSD FreeBSD NetBSD DragonFly MidnightBSD)) + ifneq (,$(filter $(TARGET_OS),OpenBSD FreeBSD NetBSD DragonFly MidnightBSD)) PKGCONFIGDIR ?= $(prefix)/libdata/pkgconfig -else + else PKGCONFIGDIR ?= $(libdir)/pkgconfig -endif + endif pkgconfigdir ?= $(PKGCONFIGDIR) -ifneq (,$(filter $(OS),SunOS)) -INSTALL ?= ginstall -else -INSTALL ?= install -endif - -INSTALL_PROGRAM ?= $(INSTALL) -INSTALL_DATA ?= $(INSTALL) -m 644 - liblz4.pc: liblz4.pc.in Makefile @echo creating pkgconfig $(Q)sed -e 's|@PREFIX@|$(prefix)|' \ @@ -169,26 +172,26 @@ liblz4.pc: liblz4.pc.in Makefile $< >$@ install: lib liblz4.pc - $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(pkgconfigdir)/ $(DESTDIR)$(includedir)/ $(DESTDIR)$(libdir)/ $(DESTDIR)$(bindir)/ + $(Q)$(INSTALL_DIR) $(DESTDIR)$(pkgconfigdir)/ $(DESTDIR)$(includedir)/ $(DESTDIR)$(libdir)/ $(DESTDIR)$(bindir)/ $(Q)$(INSTALL_DATA) liblz4.pc $(DESTDIR)$(pkgconfigdir)/ @echo Installing libraries -ifeq ($(BUILD_STATIC),yes) + ifeq ($(BUILD_STATIC),yes) $(Q)$(INSTALL_DATA) liblz4.a $(DESTDIR)$(libdir)/liblz4.a $(Q)$(INSTALL_DATA) lz4frame_static.h $(DESTDIR)$(includedir)/lz4frame_static.h -endif -ifeq ($(BUILD_SHARED),yes) + endif + ifeq ($(BUILD_SHARED),yes) # Traditionnally, one installs the DLLs in the bin directory as programs # search them first in their directory. This allows to not pollute system # directories (like c:/windows/system32), nor modify the PATH variable. -ifeq ($(WINBASED),yes) + ifeq ($(WINBASED),yes) $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4).dll $(DESTDIR)$(bindir) $(Q)$(INSTALL_PROGRAM) dll/$(LIBLZ4_EXP) $(DESTDIR)$(libdir) -else + else $(Q)$(INSTALL_PROGRAM) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir) - $(Q)ln -sf liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) - $(Q)ln -sf liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) -endif -endif + $(Q)$(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) + $(Q)$(LN_SF) liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) + endif + endif @echo Installing headers in $(includedir) $(Q)$(INSTALL_DATA) lz4.h $(DESTDIR)$(includedir)/lz4.h $(Q)$(INSTALL_DATA) lz4hc.h $(DESTDIR)$(includedir)/lz4hc.h @@ -197,14 +200,14 @@ endif uninstall: $(Q)$(RM) $(DESTDIR)$(pkgconfigdir)/liblz4.pc -ifeq (WINBASED,1) + ifeq (WINBASED,1) $(Q)$(RM) $(DESTDIR)$(bindir)/$(LIBLZ4).dll $(Q)$(RM) $(DESTDIR)$(libdir)/$(LIBLZ4_EXP) -else + else $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT) $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_MAJOR) $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.$(SHARED_EXT_VER) -endif + endif $(Q)$(RM) $(DESTDIR)$(libdir)/liblz4.a $(Q)$(RM) $(DESTDIR)$(includedir)/lz4.h $(Q)$(RM) $(DESTDIR)$(includedir)/lz4hc.h diff --git a/lib/liblz4-dll.rc.in b/lib/liblz4-dll.rc.in new file mode 100644 index 0000000..bf9adf5 --- /dev/null +++ b/lib/liblz4-dll.rc.in @@ -0,0 +1,35 @@ +#include + +// DLL version information. +1 VERSIONINFO +FILEVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 +PRODUCTVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE +#else + FILEFLAGS 0 +#endif +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Yann Collet" + VALUE "FileDescription", "Extremely fast compression" + VALUE "FileVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" + VALUE "InternalName", "@LIBLZ4@" + VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "OriginalFilename", "@LIBLZ4@.dll" + VALUE "ProductName", "LZ4" + VALUE "ProductVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END diff --git a/programs/Makefile b/programs/Makefile index e055491..4994551 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -65,14 +65,32 @@ all: lz4 lz4c all32: CFLAGS+=-m32 all32: all +ifeq ($(WINBASED),yes) +lz4-exe.rc: lz4-exe.rc.in + @echo creating executable resource + $(Q)sed -e 's|@PROGNAME@|lz4|' \ + -e 's|@LIBVER_MAJOR@|$(LIBVER_MAJOR)|g' \ + -e 's|@LIBVER_MINOR@|$(LIBVER_MINOR)|g' \ + -e 's|@LIBVER_PATCH@|$(LIBVER_PATCH)|g' \ + -e 's|@EXT@|$(EXT)|g' \ + $< >$@ + +lz4-exe.o: lz4-exe.rc + $(WINDRES) -i lz4-exe.rc -o lz4-exe.o + +lz4: $(OBJFILES) lz4-exe.o + $(CC) $(FLAGS) $^ -o $@$(EXT) +else lz4: $(OBJFILES) $(CC) $(FLAGS) $^ -o $@$(EXT) +endif + lz4-release: DEBUGFLAGS= lz4-release: lz4 lz4c: lz4 - ln -s lz4$(EXT) lz4c$(EXT) + $(LN_SF) lz4$(EXT) lz4c$(EXT) lz4c32: CFLAGS += -m32 lz4c32 : $(SRCFILES) @@ -90,6 +108,9 @@ preview-man: clean-man man man ./lz4.1 clean: +ifeq ($(WINBASED),yes) + $(Q)$(RM) *.rc +endif @$(MAKE) -C $(LZ4DIR) $@ > $(VOID) @$(RM) core *.o *.test tmp* \ lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) unlz4$(EXT) lz4cat$(EXT) @@ -99,13 +120,13 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku MidnightBSD MINGW32_NT% MINGW64_NT% MSYS% CYGWIN_NT%,$(shell uname))) +ifeq ($(POSIX_ENV),Yes) unlz4: lz4 - ln -s lz4$(EXT) unlz4$(EXT) + $(LN_SF) lz4$(EXT) unlz4$(EXT) lz4cat: lz4 - ln -s lz4$(EXT) lz4cat$(EXT) + $(LN_SF) lz4$(EXT) lz4cat$(EXT) DESTDIR ?= # directory variables : GNU conventions prefer lowercase @@ -124,28 +145,18 @@ mandir ?= $(MANDIR) MAN1DIR ?= $(mandir)/man1 man1dir ?= $(MAN1DIR) -ifneq (,$(filter $(shell uname),SunOS)) -INSTALL ?= ginstall -else -INSTALL ?= install -endif - -INSTALL_PROGRAM ?= $(INSTALL) -m 755 -INSTALL_DATA ?= $(INSTALL) -m 644 - - install: lz4 @echo Installing binaries - @$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)/ $(DESTDIR)$(man1dir)/ + @$(INSTALL_DIR) $(DESTDIR)$(bindir)/ $(DESTDIR)$(man1dir)/ @$(INSTALL_PROGRAM) lz4$(EXT) $(DESTDIR)$(bindir)/lz4$(EXT) - @ln -sf lz4$(EXT) $(DESTDIR)$(bindir)/lz4c$(EXT) - @ln -sf lz4$(EXT) $(DESTDIR)$(bindir)/lz4cat$(EXT) - @ln -sf lz4$(EXT) $(DESTDIR)$(bindir)/unlz4$(EXT) + @$(LN_S) lz4$(EXT) $(DESTDIR)$(bindir)/lz4c$(EXT) + @$(LN_S) lz4$(EXT) $(DESTDIR)$(bindir)/lz4cat$(EXT) + @$(LN_S) lz4$(EXT) $(DESTDIR)$(bindir)/unlz4$(EXT) @echo Installing man pages @$(INSTALL_DATA) lz4.1 $(DESTDIR)$(man1dir)/lz4.1 - @ln -sf lz4.1 $(DESTDIR)$(man1dir)/lz4c.1 - @ln -sf lz4.1 $(DESTDIR)$(man1dir)/lz4cat.1 - @ln -sf lz4.1 $(DESTDIR)$(man1dir)/unlz4.1 + @$(LN_SF) lz4.1 $(DESTDIR)$(man1dir)/lz4c.1 + @$(LN_SF) lz4.1 $(DESTDIR)$(man1dir)/lz4cat.1 + @$(LN_SF) lz4.1 $(DESTDIR)$(man1dir)/unlz4.1 @echo lz4 installation completed uninstall: diff --git a/programs/lz4-exe.rc.in b/programs/lz4-exe.rc.in new file mode 100644 index 0000000..7b81030 --- /dev/null +++ b/programs/lz4-exe.rc.in @@ -0,0 +1,27 @@ +1 VERSIONINFO +FILEVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 +PRODUCTVERSION @LIBVER_MAJOR@,@LIBVER_MINOR@,@LIBVER_PATCH@,0 +FILEFLAGSMASK 0 +FILEOS 0x40000 +FILETYPE 1 +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "CompanyName", "Yann Collet" + VALUE "FileDescription", "Extremely fast compression" + VALUE "FileVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" + VALUE "InternalName", "@PROGNAME@" + VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "OriginalFilename", "@PROGNAME@.@EXT@" + VALUE "ProductName", "LZ4" + VALUE "ProductVersion", "@LIBVER_MAJOR@.@LIBVER_MINOR@.@LIBVER_PATCH@.0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 1200 + } +} + diff --git a/tests/Makefile b/tests/Makefile index 02c2ab6..67514e4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -67,7 +67,7 @@ lib liblz4.pc: $(MAKE) -C $(LZ4DIR) $@ CFLAGS="$(CFLAGS)" lz4c unlz4 lz4cat: lz4 - ln -sf $(LZ4) $(PRGDIR)/$@ + $(LN_SF) $(LZ4) $(PRGDIR)/$@ lz4c32: # create a 32-bits version for 32/64 interop tests $(MAKE) -C $(PRGDIR) $@ CFLAGS="-m32 $(CFLAGS)" -- cgit v0.12