diff options
Diffstat (limited to 'programs/lz4cli.c')
-rw-r--r-- | programs/lz4cli.c | 235 |
1 files changed, 157 insertions, 78 deletions
diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 26a8089..523b8a8 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -67,6 +67,7 @@ static int g_lz4c_legacy_commands = 0; /*-************************************ * Macros ***************************************/ +#define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__) #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } static unsigned displayLevel = 2; /* 0 : no display ; 1: errors only ; 2 : downgradable normal ; 3 : non-downgradable normal; 4 : + information */ @@ -92,8 +93,11 @@ static unsigned displayLevel = 2; /* 0 : no display ; 1: errors only ; 2 : dow ***************************************/ #define DEFAULT_COMPRESSOR LZ4IO_compressFilename #define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename -int LZ4IO_compressFilename_Legacy(const char* input_filename, const char* output_filename, int compressionlevel); /* hidden function */ - +int LZ4IO_compressFilename_Legacy(const char* input_filename, const char* output_filename, int compressionlevel, const LZ4IO_prefs_t* prefs); /* hidden function */ +int LZ4IO_compressMultipleFilenames_Legacy( + const char** inFileNamesTable, int ifntSize, + const char* suffix, + int compressionLevel, const LZ4IO_prefs_t* prefs); /*-*************************** * Functions @@ -134,20 +138,22 @@ static int usage_advanced(const char* exeName) DISPLAY( " -r : operate recursively on directories (sets also -m) \n"); #endif DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\n"); - DISPLAY( " -B# : Block size [4-7] (default : 7) \n"); - DISPLAY( " -BD : Block dependency (improve compression ratio) \n"); + DISPLAY( " -B# : cut file into blocks of size # bytes [32+] \n"); + DISPLAY( " or predefined block size [4-7] (default: 7) \n"); + DISPLAY( " -BI : Block Independence (default) \n"); + DISPLAY( " -BD : Block dependency (improves compression ratio) \n"); 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 FILE : lists information about .lz4 files (useful for files 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: %u)\n", 1); + DISPLAY( "--fast[=#]: switch to ultra fast compression level (default: %i)\n", 1); + DISPLAY( "--best : same as -%d\n", LZ4HC_CLEVEL_MAX); DISPLAY( "Benchmark arguments : \n"); DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); DISPLAY( " -e# : test all compression levels from -bX to # (default : 1)\n"); DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s) \n"); - DISPLAY( " -B# : cut file into independent blocks of size # bytes [32+] \n"); - DISPLAY( " or predefined block size [4-7] (default: 7) \n"); if (g_lz4c_legacy_commands) { DISPLAY( "Legacy arguments : \n"); DISPLAY( " -c0 : fast compression \n"); @@ -251,16 +257,16 @@ static int exeNameMatch(const char* exeName, const char* test) } /*! readU32FromChar() : - @return : unsigned integer value read from input in `char` format - allows and interprets K, KB, KiB, M, MB and MiB suffix. - Will also modify `*stringPtr`, advancing it to position where it stopped reading. - Note : function result can overflow if digit string > MAX_UINT */ + * @return : unsigned integer value read from input in `char` format + * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * Will also modify `*stringPtr`, advancing it to position where it stopped reading. + * Note : function result can overflow if digit string > MAX_UINT */ static unsigned readU32FromChar(const char** stringPtr) { unsigned result = 0; while ((**stringPtr >='0') && (**stringPtr <='9')) { result *= 10; - result += **stringPtr - '0'; + result += (unsigned)(**stringPtr - '0'); (*stringPtr)++ ; } if ((**stringPtr=='K') || (**stringPtr=='M')) { @@ -278,7 +284,7 @@ static unsigned readU32FromChar(const char** stringPtr) * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand. * @return 0 and doesn't modify *stringPtr otherwise. */ -static unsigned longCommandWArg(const char** stringPtr, const char* longCommand) +static int longCommandWArg(const char** stringPtr, const char* longCommand) { size_t const comSize = strlen(longCommand); int const result = !strncmp(*stringPtr, longCommand, comSize); @@ -286,7 +292,20 @@ static unsigned 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 + * @return `om_decompress` if input filename has .lz4 extension and `om_compress` otherwise. + */ +static operationMode_e determineOpMode(const char* inputFilename) +{ + size_t const inSize = strlen(inputFilename); + size_t const extSize = strlen(LZ4_EXTENSION); + size_t const extStart= (inSize > extSize) ? inSize-extSize : 0; + if (!strcmp(inputFilename+extStart, LZ4_EXTENSION)) return om_decompress; + else return om_compress; +} int main(int argc, const char** argv) { @@ -304,11 +323,12 @@ int main(int argc, const char** argv) const char* output_filename= NULL; const char* dictionary_filename = NULL; char* dynNameSpace = NULL; - const char** inFileNames = (const char**) calloc(argc, sizeof(char*)); + const char** inFileNames = (const char**)calloc((size_t)argc, sizeof(char*)); unsigned ifnIdx=0; + LZ4IO_prefs_t* const prefs = LZ4IO_defaultPreferences(); const char nullOutput[] = NULL_OUTPUT; const char extension[] = LZ4_EXTENSION; - size_t blockSize = LZ4IO_setBlockSizeID(LZ4_BLOCKSIZEID_DEFAULT); + size_t blockSize = LZ4IO_setBlockSizeID(prefs, LZ4_BLOCKSIZEID_DEFAULT); const char* const exeName = lastNameFromPath(argv[0]); #ifdef UTIL_HAS_CREATEFILELIST const char** extendedFileList = NULL; @@ -322,13 +342,14 @@ int main(int argc, const char** argv) return 1; } inFileNames[0] = stdinmark; - LZ4IO_setOverwrite(0); + LZ4IO_setOverwrite(prefs, 0); /* predefined behaviors, based on binary/link name */ if (exeNameMatch(exeName, LZ4CAT)) { mode = om_decompress; - LZ4IO_setOverwrite(1); - LZ4IO_setRemoveSrcFile(0); + LZ4IO_setOverwrite(prefs, 1); + LZ4IO_setPassThrough(prefs, 1); + LZ4IO_setRemoveSrcFile(prefs, 0); forceStdout=1; output_filename=stdoutmark; displayLevel=1; @@ -360,23 +381,24 @@ int main(int argc, const char** argv) || (!strcmp(argument, "--uncompress"))) { mode = om_decompress; continue; } if (!strcmp(argument, "--multiple")) { multiple_inputs = 1; continue; } if (!strcmp(argument, "--test")) { mode = om_test; continue; } - if (!strcmp(argument, "--force")) { LZ4IO_setOverwrite(1); continue; } - if (!strcmp(argument, "--no-force")) { LZ4IO_setOverwrite(0); continue; } + if (!strcmp(argument, "--force")) { LZ4IO_setOverwrite(prefs, 1); continue; } + if (!strcmp(argument, "--no-force")) { LZ4IO_setOverwrite(prefs, 0); continue; } if ((!strcmp(argument, "--stdout")) || (!strcmp(argument, "--to-stdout"))) { forceStdout=1; output_filename=stdoutmark; continue; } - if (!strcmp(argument, "--frame-crc")) { LZ4IO_setStreamChecksumMode(1); continue; } - if (!strcmp(argument, "--no-frame-crc")) { LZ4IO_setStreamChecksumMode(0); continue; } - if (!strcmp(argument, "--content-size")) { LZ4IO_setContentSize(1); continue; } - if (!strcmp(argument, "--no-content-size")) { LZ4IO_setContentSize(0); continue; } - if (!strcmp(argument, "--sparse")) { LZ4IO_setSparseFile(2); continue; } - if (!strcmp(argument, "--no-sparse")) { LZ4IO_setSparseFile(0); continue; } - if (!strcmp(argument, "--favor-decSpeed")) { LZ4IO_favorDecSpeed(1); continue; } + if (!strcmp(argument, "--frame-crc")) { LZ4IO_setStreamChecksumMode(prefs, 1); continue; } + 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; } if (!strcmp(argument, "--verbose")) { displayLevel++; continue; } if (!strcmp(argument, "--quiet")) { if (displayLevel) displayLevel--; continue; } - if (!strcmp(argument, "--version")) { DISPLAY(WELCOME_MESSAGE); return 0; } + if (!strcmp(argument, "--version")) { DISPLAYOUT(WELCOME_MESSAGE); goto _cleanup; } if (!strcmp(argument, "--help")) { usage_advanced(exeName); goto _cleanup; } - if (!strcmp(argument, "--keep")) { LZ4IO_setRemoveSrcFile(0); continue; } /* keep source file (default) */ - if (!strcmp(argument, "--rm")) { LZ4IO_setRemoveSrcFile(1); continue; } + if (!strcmp(argument, "--keep")) { LZ4IO_setRemoveSrcFile(prefs, 0); continue; } /* keep source file (default) */ + if (!strcmp(argument, "--rm")) { LZ4IO_setRemoveSrcFile(prefs, 1); continue; } if (longCommandWArg(&argument, "--fast")) { /* Parse optional acceleration factor */ if (*argument == '=') { @@ -396,6 +418,9 @@ int main(int argc, const char** argv) } continue; } + + /* For gzip(1) compatibility */ + if (!strcmp(argument, "--best")) { cLevel=LZ4HC_CLEVEL_MAX; continue; } } while (argument[1]!=0) { @@ -407,11 +432,11 @@ int main(int argc, const char** argv) if (!strcmp(argument, "c1")) { cLevel=9; argument++; continue; } /* -c1 (high compression) */ if (!strcmp(argument, "c2")) { cLevel=12; argument++; continue; } /* -c2 (very high compression) */ if (!strcmp(argument, "hc")) { cLevel=12; argument++; continue; } /* -hc (very high compression) */ - if (!strcmp(argument, "y")) { LZ4IO_setOverwrite(1); continue; } /* -y (answer 'yes' to overwrite permission) */ + if (!strcmp(argument, "y")) { LZ4IO_setOverwrite(prefs, 1); continue; } /* -y (answer 'yes' to overwrite permission) */ } if ((*argument>='0') && (*argument<='9')) { - cLevel = readU32FromChar(&argument); + cLevel = (int)readU32FromChar(&argument); argument--; continue; } @@ -420,13 +445,13 @@ int main(int argc, const char** argv) switch(argument[0]) { /* Display help */ - case 'V': DISPLAY(WELCOME_MESSAGE); goto _cleanup; /* Version */ + case 'V': DISPLAYOUT(WELCOME_MESSAGE); goto _cleanup; /* Version */ case 'h': usage_advanced(exeName); goto _cleanup; case 'H': usage_longhelp(exeName); goto _cleanup; case 'e': argument++; - cLevelLast = readU32FromChar(&argument); + cLevelLast = (int)readU32FromChar(&argument); argument--; break; @@ -456,13 +481,17 @@ int main(int argc, const char** argv) case 'd': mode = om_decompress; break; /* Force stdout, even if stdout==console */ - case 'c': forceStdout=1; output_filename=stdoutmark; break; + case 'c': + forceStdout=1; + output_filename=stdoutmark; + LZ4IO_setPassThrough(prefs, 1); + break; /* Test integrity */ case 't': mode = om_test; break; /* Overwrite */ - case 'f': LZ4IO_setOverwrite(1); break; + case 'f': LZ4IO_setOverwrite(prefs, 1); break; /* Verbose mode */ case 'v': displayLevel++; break; @@ -471,7 +500,7 @@ int main(int argc, const char** argv) case 'q': if (displayLevel) displayLevel--; break; /* keep source file (default anyway, so useless) (for xz/lzma compatibility) */ - case 'k': LZ4IO_setRemoveSrcFile(0); break; + case 'k': LZ4IO_setRemoveSrcFile(prefs, 0); break; /* Modify Block Properties */ case 'B': @@ -479,8 +508,9 @@ int main(int argc, const char** argv) int exitBlockProperties=0; switch(argument[1]) { - case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break; - case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* disabled by default */ + case 'D': LZ4IO_setBlockMode(prefs, LZ4IO_blockLinked); argument++; break; + case 'I': LZ4IO_setBlockMode(prefs, LZ4IO_blockIndependent); argument++; break; + case 'X': LZ4IO_setBlockChecksumMode(prefs, 1); argument ++; break; /* disabled by default */ default : if (argument[1] < '0' || argument[1] > '9') { exitBlockProperties=1; @@ -492,16 +522,17 @@ int main(int argc, const char** argv) argument--; if (B < 4) badusage(exeName); if (B <= 7) { - blockSize = LZ4IO_setBlockSizeID(B); + blockSize = LZ4IO_setBlockSizeID(prefs, B); BMK_setBlockSize(blockSize); DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); } else { if (B < 32) badusage(exeName); - BMK_setBlockSize(B); - if (B >= 1024) { - DISPLAYLEVEL(2, "bench: using blocks of size %u KB \n", (U32)(B>>10)); + blockSize = LZ4IO_setBlockSize(prefs, B); + BMK_setBlockSize(blockSize); + if (blockSize >= 1024) { + DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); } else { - DISPLAYLEVEL(2, "bench: using blocks of size %u bytes \n", (U32)(B)); + DISPLAYLEVEL(2, "using blocks of size %u bytes \n", (U32)(blockSize)); } } break; @@ -597,27 +628,27 @@ int main(int argc, const char** argv) #endif } + if (dictionary_filename) { + if (!strcmp(dictionary_filename, stdinmark) && IS_CONSOLE(stdin)) { + DISPLAYLEVEL(1, "refusing to read from a console\n"); + exit(1); + } + LZ4IO_setDictionaryFilename(prefs, dictionary_filename); + } + /* benchmark and test modes */ if (mode == om_bench) { BMK_setNotificationLevel(displayLevel); - operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast); + operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast, dictionary_filename); goto _cleanup; } if (mode == om_test) { - LZ4IO_setTestMode(1); + LZ4IO_setTestMode(prefs, 1); output_filename = nulmark; mode = om_decompress; /* defer to decompress */ } - if (dictionary_filename) { - if (!strcmp(dictionary_filename, stdinmark) && IS_CONSOLE(stdin)) { - DISPLAYLEVEL(1, "refusing to read from a console\n"); - exit(1); - } - LZ4IO_setDictionaryFilename(dictionary_filename); - } - /* compress or decompress */ if (!input_filename) input_filename = stdinmark; /* Check if input is defined as console; trigger an error in this case */ @@ -625,19 +656,34 @@ int main(int argc, const char** argv) DISPLAYLEVEL(1, "refusing to read from a console\n"); exit(1); } - /* if input==stdin and no output defined, stdout becomes default output */ - if (!strcmp(input_filename, stdinmark) && !output_filename) - output_filename = stdoutmark; + if (!strcmp(input_filename, stdinmark)) { + /* if input==stdin and no output defined, stdout becomes default output */ + if (!output_filename) output_filename = stdoutmark; + } + else{ +#ifdef UTIL_HAS_CREATEFILELIST + if (!recursive && !UTIL_isRegFile(input_filename)) { +#else + if (!UTIL_isRegFile(input_filename)) { +#endif + DISPLAYLEVEL(1, "%s: is not a regular file \n", input_filename); + exit(1); + } + } /* 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) && mode != om_list) { + /* Default to stdout whenever stdout is not the console. + * 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; + } if (mode == om_auto) { /* auto-determine compression or decompression, based on file extension */ - size_t const inSize = strlen(input_filename); - size_t const extSize = strlen(LZ4_EXTENSION); - size_t const extStart= (inSize > extSize) ? inSize-extSize : 0; - if (!strcmp(input_filename+extStart, LZ4_EXTENSION)) mode = om_decompress; - else mode = om_compress; + mode = determineOpMode(input_filename); } if (mode == om_compress) { /* compression to file */ size_t const l = strlen(input_filename); @@ -665,35 +711,67 @@ int main(int argc, const char** argv) break; } - /* Check if output is defined as console; trigger an error in this case */ + if (mode == om_list){ + /* Exit if trying to read from stdin as this isn't supported in this mode */ + if(!strcmp(input_filename, stdinmark)){ + DISPLAYLEVEL(1, "refusing to read from standard input in --list mode\n"); + exit(1); + } + if(!multiple_inputs){ + inFileNames[ifnIdx++] = input_filename; + } + } + else{ + 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 */ if (!strcmp(output_filename,stdoutmark) && (displayLevel==2)) displayLevel=1; if ((multiple_inputs) && (displayLevel==2)) displayLevel=1; + /* Auto-determine compression or decompression, based on file extension */ + if (mode == om_auto) { + mode = determineOpMode(input_filename); + } + /* IO Stream/File */ - LZ4IO_setNotificationLevel(displayLevel); + LZ4IO_setNotificationLevel((int)displayLevel); if (ifnIdx == 0) multiple_inputs = 0; if (mode == om_decompress) { - if (multiple_inputs) - operationResult = LZ4IO_decompressMultipleFilenames(inFileNames, ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION); - else - operationResult = DEFAULT_DECOMPRESSOR(input_filename, output_filename); + if (multiple_inputs) { + const char* const dec_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION; + assert(ifnIdx <= INT_MAX); + operationResult = LZ4IO_decompressMultipleFilenames(inFileNames, (int)ifnIdx, dec_extension, prefs); + } else { + operationResult = DEFAULT_DECOMPRESSOR(input_filename, output_filename, prefs); + } + } else if (mode == om_list){ + operationResult = LZ4IO_displayCompressedFilesInfo(inFileNames, ifnIdx); } else { /* compression is default action */ if (legacy_format) { DISPLAYLEVEL(3, "! Generating LZ4 Legacy format (deprecated) ! \n"); - LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel); + if(multiple_inputs){ + const char* const leg_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION; + LZ4IO_compressMultipleFilenames_Legacy(inFileNames, (int)ifnIdx, leg_extension, cLevel, prefs); + } else { + LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel, prefs); + } } else { - if (multiple_inputs) - operationResult = LZ4IO_compressMultipleFilenames(inFileNames, ifnIdx, LZ4_EXTENSION, cLevel); - else - operationResult = DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel); - } - } + if (multiple_inputs) { + const char* const comp_extension = !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION; + assert(ifnIdx <= INT_MAX); + operationResult = LZ4IO_compressMultipleFilenames(inFileNames, (int)ifnIdx, comp_extension, cLevel, prefs); + } else { + operationResult = DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel, prefs); + } } } _cleanup: if (main_pause) waitEnter(); @@ -704,6 +782,7 @@ _cleanup: inFileNames = NULL; } #endif + LZ4IO_freePreferences(prefs); free((void*)inFileNames); return operationResult; } |