1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Simple single-threaded tool to uncompress .xz or .lzma files
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
31 # define TOOL_FORMAT "lzma"
33 # define TOOL_FORMAT "xz"
37 /// Number of bytes to use memory at maximum
38 static uint64_t memlimit;
40 /// Error messages are suppressed if this is zero, which is the case when
41 /// --quiet has been given at least twice.
42 static unsigned int display_errors = 2;
44 /// Program name to be shown in error messages
45 static const char *argv0;
48 static void lzma_attribute((format(printf, 1, 2)))
49 my_errorf(const char *fmt, ...)
55 fprintf(stderr, "%s: ", argv0);
56 vfprintf(stderr, fmt, ap);
57 fprintf(stderr, "\n");
65 static void lzma_attribute((noreturn))
68 int status = EXIT_SUCCESS;
70 // Close stdout. We don't care about stderr, because we write to it
71 // only when an error has already occurred.
72 const int ferror_err = ferror(stdout);
73 const int fclose_err = fclose(stdout);
75 if (ferror_err || fclose_err) {
76 // If it was fclose() that failed, we have the reason
77 // in errno. If only ferror() indicated an error,
78 // we have no idea what the reason was.
79 my_errorf("Cannot write to standard output: %s", fclose_err
80 ? strerror(errno) : "Unknown error");
81 status = EXIT_FAILURE;
88 static void lzma_attribute((noreturn))
92 "Usage: %s [OPTION]... [FILE]...\n"
93 "Uncompress files in the ." TOOL_FORMAT " format to the standard output.\n"
95 " -c, --stdout (ignored)\n"
96 " -d, --decompress (ignored)\n"
97 " -k, --keep (ignored)\n"
98 " -f, --force (ignored)\n"
99 " -M, --memory=NUM use NUM bytes of memory at maximum (0 means default);\n"
100 " the suffixes k, M, G, Ki, Mi, and Gi are supported.\n"
101 " -q, --quiet specify *twice* to suppress errors\n"
102 " -Q, --no-warn (ignored)\n"
103 " -h, --help display this help and exit\n"
104 " -V, --version display the version number and exit\n"
106 "With no FILE, or when FILE is -, read standard input.\n"
108 "On this system and configuration, this program will use at maximum of roughly\n"
109 "%" PRIu64 " MiB RAM.\n"
111 "Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n"
112 "XZ Utils home page: <http://tukaani.org/xz/>\n",
113 argv0, memlimit / (1024 * 1024));
118 static void lzma_attribute((noreturn))
121 printf(TOOL_FORMAT "dec " LZMA_VERSION_STRING "\n"
122 "liblzma %s\n", lzma_version_string());
128 /// Finds out the amount of physical memory in the system, and sets
129 /// a default memory usage limit.
131 set_default_memlimit(void)
133 const uint64_t mem = physmem();
136 // Cannot autodetect, use 10 MiB as the default limit.
137 memlimit = UINT64_C(10) * 1024 * 1024;
139 // Limit is 40 % of RAM.
140 memlimit = mem * 2 / 5;
146 /// \brief Converts a string to uint64_t
148 /// This is rudely copied from src/xz/util.c and modified a little. :-(
151 str_to_uint64(const char *value)
155 // Accept special value "max".
156 if (strcmp(value, "max") == 0)
159 if (*value < '0' || *value > '9') {
160 my_errorf("%s: Not a number", value);
166 if (result > (UINT64_MAX - 9) / 10)
170 result += *value - '0';
172 } while (*value >= '0' && *value <= '9');
174 if (*value != '\0') {
176 static const struct {
185 { "GB", 1000000000 },
190 { "Gi", 1073741824 },
191 { "GiB", 1073741824 }
194 uint32_t multiplier = 0;
195 for (size_t i = 0; i < ARRAY_SIZE(suffixes); ++i) {
196 if (strcmp(value, suffixes[i].name) == 0) {
197 multiplier = suffixes[i].multiplier;
202 if (multiplier == 0) {
203 my_errorf("%s: Invalid suffix", value);
207 // Don't overflow here either.
208 if (result > UINT64_MAX / multiplier)
211 result *= multiplier;
218 /// Parses command line options.
220 parse_options(int argc, char **argv)
222 static const char short_opts[] = "cdkfM:hqQV";
223 static const struct option long_opts[] = {
224 { "stdout", no_argument, NULL, 'c' },
225 { "to-stdout", no_argument, NULL, 'c' },
226 { "decompress", no_argument, NULL, 'd' },
227 { "uncompress", no_argument, NULL, 'd' },
228 { "force", no_argument, NULL, 'f' },
229 { "keep", no_argument, NULL, 'k' },
230 { "memory", required_argument, NULL, 'M' },
231 { "quiet", no_argument, NULL, 'q' },
232 { "no-warn", no_argument, NULL, 'Q' },
233 { "help", no_argument, NULL, 'h' },
234 { "version", no_argument, NULL, 'V' },
240 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
251 memlimit = str_to_uint64(optarg);
253 set_default_memlimit();
258 if (display_errors > 0)
279 uncompress(lzma_stream *strm, FILE *file, const char *filename)
283 // Initialize the decoder
285 ret = lzma_alone_decoder(strm, memlimit);
287 ret = lzma_stream_decoder(strm, memlimit, LZMA_CONCATENATED);
290 // The only reasonable error here is LZMA_MEM_ERROR.
291 // FIXME: Maybe also LZMA_MEMLIMIT_ERROR in future?
292 if (ret != LZMA_OK) {
293 my_errorf("%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM)
294 : "Internal program error (bug)");
298 // Input and output buffers
299 uint8_t in_buf[BUFSIZ];
300 uint8_t out_buf[BUFSIZ];
303 strm->next_out = out_buf;
304 strm->avail_out = BUFSIZ;
306 lzma_action action = LZMA_RUN;
309 if (strm->avail_in == 0) {
310 strm->next_in = in_buf;
311 strm->avail_in = fread(in_buf, 1, BUFSIZ, file);
314 // POSIX says that fread() sets errno if
315 // an error occurred. ferror() doesn't
317 my_errorf("%s: Error reading input file: %s",
318 filename, strerror(errno));
323 // When using LZMA_CONCATENATED, we need to tell
324 // liblzma when it has got all the input.
326 action = LZMA_FINISH;
330 ret = lzma_code(strm, action);
332 // Write and check write error before checking decoder error.
333 // This way as much data as possible gets written to output
334 // even if decoder detected an error.
335 if (strm->avail_out == 0 || ret != LZMA_OK) {
336 const size_t write_size = BUFSIZ - strm->avail_out;
338 if (fwrite(out_buf, 1, write_size, stdout)
340 // Wouldn't be a surprise if writing to stderr
341 // would fail too but at least try to show an
343 my_errorf("Cannot write to standard output: "
344 "%s", strerror(errno));
348 strm->next_out = out_buf;
349 strm->avail_out = BUFSIZ;
352 if (ret != LZMA_OK) {
353 if (ret == LZMA_STREAM_END) {
355 // Check that there's no trailing garbage.
356 if (strm->avail_in != 0
357 || fread(in_buf, 1, 1, file)
360 ret = LZMA_DATA_ERROR;
364 // lzma_stream_decoder() already guarantees
365 // that there's no trailing garbage.
366 assert(strm->avail_in == 0);
367 assert(action == LZMA_FINISH);
376 msg = strerror(ENOMEM);
379 case LZMA_MEMLIMIT_ERROR:
380 msg = "Memory usage limit reached";
383 case LZMA_FORMAT_ERROR:
384 msg = "File format not recognized";
387 case LZMA_OPTIONS_ERROR:
388 // FIXME: Better message?
389 msg = "Unsupported compression options";
392 case LZMA_DATA_ERROR:
393 msg = "File is corrupt";
397 msg = "Unexpected end of input";
401 msg = "Internal program error (bug)";
405 my_errorf("%s: %s", filename, msg);
413 main(int argc, char **argv)
415 // Set the argv0 global so that we can print the command name in
416 // error and help messages.
419 // Detect amount of installed RAM and set the memory usage limit.
420 // This is needed before parsing the command line arguments.
421 set_default_memlimit();
423 // Parse the command line options.
424 parse_options(argc, argv);
426 // The same lzma_stream is used for all files that we decode. This way
427 // we don't need to reallocate memory for every file if they use same
428 // compression settings.
429 lzma_stream strm = LZMA_STREAM_INIT;
431 // Some systems require setting stdin and stdout to binary mode.
433 setmode(fileno(stdin), O_BINARY);
434 setmode(fileno(stdout), O_BINARY);
437 if (optind == argc) {
438 // No filenames given, decode from stdin.
439 uncompress(&strm, stdin, "(stdin)");
441 // Loop through the filenames given on the command line.
443 // "-" indicates stdin.
444 if (strcmp(argv[optind], "-") == 0) {
445 uncompress(&strm, stdin, "(stdin)");
447 FILE *file = fopen(argv[optind], "rb");
449 my_errorf("%s: %s", argv[optind],
454 uncompress(&strm, file, argv[optind]);
457 } while (++optind < argc);
461 // Free the memory only when debugging. Freeing wastes some time,
462 // but allows detecting possible memory leaks with Valgrind.