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 ///////////////////////////////////////////////////////////////////////////////
30 # define TOOL_FORMAT "lzma"
32 # define TOOL_FORMAT "xz"
36 /// Number of bytes to use memory at maximum
37 static uint64_t memlimit;
39 /// Program name to be shown in error messages
40 static const char *argv0;
43 static void lzma_attribute((noreturn))
46 int status = EXIT_SUCCESS;
48 // Close stdout. We don't care about stderr, because we write to it
49 // only when an error has already occurred.
50 const int ferror_err = ferror(stdout);
51 const int fclose_err = fclose(stdout);
53 if (ferror_err || fclose_err) {
54 // If it was fclose() that failed, we have the reason
55 // in errno. If only ferror() indicated an error,
56 // we have no idea what the reason was.
57 fprintf(stderr, "%s: Cannot write to standard output: %s\n",
59 ? strerror(errno) : "Unknown error");
60 status = EXIT_FAILURE;
67 static void lzma_attribute((noreturn))
71 "Usage: %s [OPTION]... [FILE]...\n"
72 "Uncompress files in the ." TOOL_FORMAT " format to the standard output.\n"
74 " -c, --stdout (ignored)\n"
75 " -d, --decompress (ignored)\n"
76 " -k, --keep (ignored)\n"
77 " -f, --force (ignored)\n"
78 " -M, --memory=NUM use NUM bytes of memory at maximum (0 means default);\n"
79 " the suffixes k, M, G, Ki, Mi, and Gi are supported.\n"
80 " -h, --help display this help and exit\n"
81 " -V, --version display version and license information and exit\n"
83 "With no FILE, or when FILE is -, read standard input.\n"
85 "On this configuration, the tool will use about %" PRIu64
86 " MiB of memory at maximum.\n"
88 "Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n",
89 argv0, memlimit / (1024 * 1024));
94 static void lzma_attribute((noreturn))
97 printf(TOOL_FORMAT "dec " LZMA_VERSION_STRING "\n"
98 "liblzma %s\n", lzma_version_string());
104 /// Finds out the amount of physical memory in the system, and sets
105 /// a default memory usage limit.
107 set_default_memlimit(void)
109 const uint64_t mem = physmem();
112 // Cannot autodetect, use 10 MiB as the default limit.
113 memlimit = (1U << 23) + (1U << 21);
115 // Limit is 33 % of RAM.
122 /// \brief Converts a string to uint64_t
124 /// This is rudely copied from src/xz/util.c and modified a little. :-(
127 str_to_uint64(const char *value)
131 // Accept special value "max".
132 if (strcmp(value, "max") == 0)
135 if (*value < '0' || *value > '9') {
136 fprintf(stderr, "%s: %s: Not a number\n", argv0, value);
142 if (result > (UINT64_MAX - 9) / 10)
146 result += *value - '0';
148 } while (*value >= '0' && *value <= '9');
150 if (*value != '\0') {
152 static const struct {
161 { "GB", 1000000000 },
166 { "Gi", 1073741824 },
167 { "GiB", 1073741824 }
170 uint32_t multiplier = 0;
171 for (size_t i = 0; i < ARRAY_SIZE(suffixes); ++i) {
172 if (strcmp(value, suffixes[i].name) == 0) {
173 multiplier = suffixes[i].multiplier;
178 if (multiplier == 0) {
179 fprintf(stderr, "%s: %s: Invalid suffix\n",
184 // Don't overflow here either.
185 if (result > UINT64_MAX / multiplier)
188 result *= multiplier;
195 /// Parses command line options.
197 parse_options(int argc, char **argv)
199 static const char short_opts[] = "cdkfM:hV";
200 static const struct option long_opts[] = {
201 { "stdout", no_argument, NULL, 'c' },
202 { "to-stdout", no_argument, NULL, 'c' },
203 { "decompress", no_argument, NULL, 'd' },
204 { "uncompress", no_argument, NULL, 'd' },
205 { "force", no_argument, NULL, 'f' },
206 { "keep", no_argument, NULL, 'k' },
207 { "memory", required_argument, NULL, 'M' },
208 { "help", no_argument, NULL, 'h' },
209 { "version", no_argument, NULL, 'V' },
215 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
225 memlimit = str_to_uint64(optarg);
227 set_default_memlimit();
247 uncompress(lzma_stream *strm, FILE *file, const char *filename)
251 // Initialize the decoder
253 ret = lzma_alone_decoder(strm, memlimit);
255 ret = lzma_stream_decoder(strm, memlimit, LZMA_CONCATENATED);
258 // The only reasonable error here is LZMA_MEM_ERROR.
259 // FIXME: Maybe also LZMA_MEMLIMIT_ERROR in future?
260 if (ret != LZMA_OK) {
261 fprintf(stderr, "%s: ", argv0);
263 if (ret == LZMA_MEM_ERROR)
264 fprintf(stderr, "%s\n", strerror(ENOMEM));
266 fprintf(stderr, "Internal program error (bug)\n");
271 // Input and output buffers
272 uint8_t in_buf[BUFSIZ];
273 uint8_t out_buf[BUFSIZ];
276 strm->next_out = out_buf;
277 strm->avail_out = BUFSIZ;
279 lzma_action action = LZMA_RUN;
282 if (strm->avail_in == 0) {
283 strm->next_in = in_buf;
284 strm->avail_in = fread(in_buf, 1, BUFSIZ, file);
287 // POSIX says that fread() sets errno if
288 // an error occurred. ferror() doesn't
290 fprintf(stderr, "%s: %s: Error reading "
298 // When using LZMA_CONCATENATED, we need to tell
299 // liblzma when it has got all the input.
301 action = LZMA_FINISH;
305 ret = lzma_code(strm, action);
307 // Write and check write error before checking decoder error.
308 // This way as much data as possible gets written to output
309 // even if decoder detected an error.
310 if (strm->avail_out == 0 || ret != LZMA_OK) {
311 const size_t write_size = BUFSIZ - strm->avail_out;
313 if (fwrite(out_buf, 1, write_size, stdout)
315 // Wouldn't be a surprise if writing to stderr
316 // would fail too but at least try to show an
318 fprintf(stderr, "%s: Cannot write to "
319 "standard output: %s\n", argv0,
324 strm->next_out = out_buf;
325 strm->avail_out = BUFSIZ;
328 if (ret != LZMA_OK) {
329 if (ret == LZMA_STREAM_END) {
331 // Check that there's no trailing garbage.
332 if (strm->avail_in != 0
333 || fread(in_buf, 1, 1, file)
336 ret = LZMA_DATA_ERROR;
340 // lzma_stream_decoder() already guarantees
341 // that there's no trailing garbage.
342 assert(strm->avail_in == 0);
343 assert(action == LZMA_FINISH);
352 msg = strerror(ENOMEM);
355 case LZMA_MEMLIMIT_ERROR:
356 msg = "Memory usage limit reached";
359 case LZMA_FORMAT_ERROR:
360 msg = "File format not recognized";
363 case LZMA_OPTIONS_ERROR:
364 // FIXME: Better message?
365 msg = "Unsupported compression options";
368 case LZMA_DATA_ERROR:
369 msg = "File is corrupt";
373 msg = "Unexpected end of input";
377 msg = "Internal program error (bug)";
381 fprintf(stderr, "%s: %s: %s\n", argv0, filename, msg);
390 main(int argc, char **argv)
392 // Set the argv0 global so that we can print the command name in
393 // error and help messages.
396 // Detect amount of installed RAM and set the memory usage limit.
397 // This is needed before parsing the command line arguments.
398 set_default_memlimit();
400 // Parse the command line options.
401 parse_options(argc, argv);
403 // The same lzma_stream is used for all files that we decode. This way
404 // we don't need to reallocate memory for every file if they use same
405 // compression settings.
406 lzma_stream strm = LZMA_STREAM_INIT;
408 // Some systems require setting stdin and stdout to binary mode.
410 setmode(fileno(stdin), O_BINARY);
411 setmode(fileno(stdout), O_BINARY);
414 if (optind == argc) {
415 // No filenames given, decode from stdin.
416 uncompress(&strm, stdin, "(stdin)");
418 // Loop through the filenames given on the command line.
420 // "-" indicates stdin.
421 if (strcmp(argv[optind], "-") == 0) {
422 uncompress(&strm, stdin, "(stdin)");
424 FILE *file = fopen(argv[optind], "rb");
426 fprintf(stderr, "%s: %s: %s\n",
432 uncompress(&strm, file, argv[optind]);
435 } while (++optind < argc);
439 // Free the memory only when debugging. Freeing wastes some time,
440 // but allows detecting possible memory leaks with Valgrind.