1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Listing information about .xz 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 ///////////////////////////////////////////////////////////////////////////////
14 #include "tuklib_integer.h"
17 /// Information about a .xz file
19 /// Combined Index of all Streams in the file
22 /// Total amount of Stream Padding
23 uint64_t stream_padding;
25 /// Highest memory usage so far
26 uint64_t memusage_max;
28 /// True if all Blocks so far have Compressed Size and
29 /// Uncompressed Size fields
34 #define XZ_FILE_INFO_INIT { NULL, 0, 0, true }
37 /// Information about a .xz Block
39 /// Size of the Block Header
42 /// A few of the Block Flags as a string
45 /// Size of the Compressed Data field in the Block
46 lzma_vli compressed_size;
48 /// Decoder memory usage for this Block
51 /// The filter chain of this Block in human-readable form
52 const char *filter_chain;
57 /// Check ID to string mapping
58 static const char check_names[LZMA_CHECK_ID_MAX + 1][12] = {
78 /// Value of the Check field as hexadecimal string.
79 /// This is set by parse_check_value().
80 static char check_value[2 * LZMA_CHECK_SIZE_MAX + 1];
83 /// Totals that are displayed if there was more than one file.
84 /// The "files" counter is also used in print_info_adv() to show
90 uint64_t compressed_size;
91 uint64_t uncompressed_size;
92 uint64_t stream_padding;
93 uint64_t memusage_max;
96 } totals = { 0, 0, 0, 0, 0, 0, 0, 0, true };
99 /// \brief Parse the Index(es) from the given .xz file
101 /// \param xfi Pointer to structure where the decoded information
103 /// \param pair Input file
105 /// \return On success, false is returned. On error, true is returned.
107 // TODO: This function is pretty big. liblzma should have a function that
108 // takes a callback function to parse the Index(es) from a .xz file to make
109 // it easy for applications.
111 parse_indexes(xz_file_info *xfi, file_pair *pair)
113 if (pair->src_st.st_size <= 0) {
114 message_error(_("%s: File is empty"), pair->src_name);
118 if (pair->src_st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) {
119 message_error(_("%s: Too small to be a valid .xz file"),
125 lzma_stream_flags header_flags;
126 lzma_stream_flags footer_flags;
129 // lzma_stream for the Index decoder
130 lzma_stream strm = LZMA_STREAM_INIT;
132 // All Indexes decoded so far
133 lzma_index *combined_index = NULL;
135 // The Index currently being decoded
136 lzma_index *this_index = NULL;
138 // Current position in the file. We parse the file backwards so
139 // initialize it to point to the end of the file.
140 off_t pos = pair->src_st.st_size;
142 // Each loop iteration decodes one Index.
144 // Check that there is enough data left to contain at least
145 // the Stream Header and Stream Footer. This check cannot
146 // fail in the first pass of this loop.
147 if (pos < 2 * LZMA_STREAM_HEADER_SIZE) {
148 message_error("%s: %s", pair->src_name,
149 message_strm(LZMA_DATA_ERROR));
153 pos -= LZMA_STREAM_HEADER_SIZE;
154 lzma_vli stream_padding = 0;
156 // Locate the Stream Footer. There may be Stream Padding which
157 // we must skip when reading backwards.
159 if (pos < LZMA_STREAM_HEADER_SIZE) {
160 message_error("%s: %s", pair->src_name,
166 if (io_pread(pair, &buf,
167 LZMA_STREAM_HEADER_SIZE, pos))
170 // Stream Padding is always a multiple of four bytes.
175 // To avoid calling io_pread() for every four bytes
176 // of Stream Padding, take advantage that we read
177 // 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
178 // check them too before calling io_pread() again.
183 } while (i >= 0 && buf.u32[i] == 0);
186 // Decode the Stream Footer.
187 ret = lzma_stream_footer_decode(&footer_flags, buf.u8);
188 if (ret != LZMA_OK) {
189 message_error("%s: %s", pair->src_name,
194 // Check that the size of the Index field looks sane.
195 lzma_vli index_size = footer_flags.backward_size;
196 if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) {
197 message_error("%s: %s", pair->src_name,
198 message_strm(LZMA_DATA_ERROR));
202 // Set pos to the beginning of the Index.
205 // See how much memory we can use for decoding this Index.
206 uint64_t memlimit = hardware_memlimit_get(MODE_LIST);
207 uint64_t memused = 0;
208 if (combined_index != NULL) {
209 memused = lzma_index_memused(combined_index);
210 if (memused > memlimit)
217 ret = lzma_index_decoder(&strm, &this_index, memlimit);
218 if (ret != LZMA_OK) {
219 message_error("%s: %s", pair->src_name,
225 // Don't give the decoder more input than the
227 strm.avail_in = my_min(IO_BUFFER_SIZE, index_size);
228 if (io_pread(pair, &buf, strm.avail_in, pos))
231 pos += strm.avail_in;
232 index_size -= strm.avail_in;
234 strm.next_in = buf.u8;
235 ret = lzma_code(&strm, LZMA_RUN);
237 } while (ret == LZMA_OK);
239 // If the decoding seems to be successful, check also that
240 // the Index decoder consumed as much input as indicated
241 // by the Backward Size field.
242 if (ret == LZMA_STREAM_END)
243 if (index_size != 0 || strm.avail_in != 0)
244 ret = LZMA_DATA_ERROR;
246 if (ret != LZMA_STREAM_END) {
247 // LZMA_BUFFER_ERROR means that the Index decoder
248 // would have liked more input than what the Index
249 // size should be according to Stream Footer.
250 // The message for LZMA_DATA_ERROR makes more
251 // sense in that case.
252 if (ret == LZMA_BUF_ERROR)
253 ret = LZMA_DATA_ERROR;
255 message_error("%s: %s", pair->src_name,
258 // If the error was too low memory usage limit,
259 // show also how much memory would have been needed.
260 if (ret == LZMA_MEMLIMIT_ERROR) {
261 uint64_t needed = lzma_memusage(&strm);
262 if (UINT64_MAX - needed < memused)
267 message_mem_needed(V_ERROR, needed);
273 // Decode the Stream Header and check that its Stream Flags
274 // match the Stream Footer.
275 pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
276 if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) {
277 message_error("%s: %s", pair->src_name,
278 message_strm(LZMA_DATA_ERROR));
282 pos -= lzma_index_total_size(this_index);
283 if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos))
286 ret = lzma_stream_header_decode(&header_flags, buf.u8);
287 if (ret != LZMA_OK) {
288 message_error("%s: %s", pair->src_name,
293 ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
294 if (ret != LZMA_OK) {
295 message_error("%s: %s", pair->src_name,
300 // Store the decoded Stream Flags into this_index. This is
301 // needed so that we can print which Check is used in each
303 ret = lzma_index_stream_flags(this_index, &footer_flags);
307 // Store also the size of the Stream Padding field. It is
308 // needed to show the offsets of the Streams correctly.
309 ret = lzma_index_stream_padding(this_index, stream_padding);
313 if (combined_index != NULL) {
314 // Append the earlier decoded Indexes
316 ret = lzma_index_cat(
317 this_index, combined_index, NULL);
318 if (ret != LZMA_OK) {
319 message_error("%s: %s", pair->src_name,
325 combined_index = this_index;
328 xfi->stream_padding += stream_padding;
334 // All OK. Make combined_index available to the caller.
335 xfi->idx = combined_index;
339 // Something went wrong, free the allocated memory.
341 lzma_index_end(combined_index, NULL);
342 lzma_index_end(this_index, NULL);
347 /// \brief Parse the Block Header
349 /// The result is stored into *bhi. The caller takes care of initializing it.
351 /// \return False on success, true on error.
353 parse_block_header(file_pair *pair, const lzma_index_iter *iter,
354 block_header_info *bhi, xz_file_info *xfi)
356 #if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
357 # error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
360 // Get the whole Block Header with one read, but don't read past
361 // the end of the Block (or even its Check field).
362 const uint32_t size = my_min(iter->block.total_size
363 - lzma_check_size(iter->stream.flags->check),
364 LZMA_BLOCK_HEADER_SIZE_MAX);
366 if (io_pread(pair, &buf, size, iter->block.compressed_file_offset))
369 // Zero would mean Index Indicator and thus not a valid Block.
374 lzma_filter filters[LZMA_FILTERS_MAX + 1];
376 // Initialize the pointers so that they can be passed to free().
377 for (size_t i = 0; i < ARRAY_SIZE(filters); ++i)
378 filters[i].options = NULL;
380 // Initialize the block structure and decode Block Header Size.
382 block.check = iter->stream.flags->check;
383 block.filters = filters;
385 block.header_size = lzma_block_header_size_decode(buf.u8[0]);
386 if (block.header_size > size)
389 // Decode the Block Header.
390 switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
394 case LZMA_OPTIONS_ERROR:
395 message_error("%s: %s", pair->src_name,
396 message_strm(LZMA_OPTIONS_ERROR));
399 case LZMA_DATA_ERROR:
406 // Check the Block Flags. These must be done before calling
407 // lzma_block_compressed_size(), because it overwrites
408 // block.compressed_size.
409 bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
411 bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
413 bhi->flags[2] = '\0';
415 // Collect information if all Blocks have both Compressed Size
416 // and Uncompressed Size fields. They can be useful e.g. for
417 // multi-threaded decompression so it can be useful to know it.
418 xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
419 && block.uncompressed_size != LZMA_VLI_UNKNOWN;
421 // Validate or set block.compressed_size.
422 switch (lzma_block_compressed_size(&block,
423 iter->block.unpadded_size)) {
427 case LZMA_DATA_ERROR:
434 // Copy the known sizes.
435 bhi->header_size = block.header_size;
436 bhi->compressed_size = block.compressed_size;
438 // Calculate the decoder memory usage and update the maximum
439 // memory usage of this Block.
440 bhi->memusage = lzma_raw_decoder_memusage(filters);
441 if (xfi->memusage_max < bhi->memusage)
442 xfi->memusage_max = bhi->memusage;
444 // Convert the filter chain to human readable form.
445 bhi->filter_chain = message_filters_to_str(filters, false);
447 // Free the memory allocated by lzma_block_header_decode().
448 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
449 free(filters[i].options);
454 // Show the error message.
455 message_error("%s: %s", pair->src_name,
456 message_strm(LZMA_DATA_ERROR));
458 // Free the memory allocated by lzma_block_header_decode().
459 // This is truly needed only if we get here after a succcessful
460 // call to lzma_block_header_decode() but it doesn't hurt to
462 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
463 free(filters[i].options);
469 /// \brief Parse the Check field and put it into check_value[]
471 /// \return False on success, true on error.
473 parse_check_value(file_pair *pair, const lzma_index_iter *iter)
475 // Don't read anything from the file if there is no integrity Check.
476 if (iter->stream.flags->check == LZMA_CHECK_NONE) {
477 snprintf(check_value, sizeof(check_value), "---");
481 // Locate and read the Check field.
482 const uint32_t size = lzma_check_size(iter->stream.flags->check);
483 const off_t offset = iter->block.compressed_file_offset
484 + iter->block.total_size - size;
486 if (io_pread(pair, &buf, size, offset))
489 // CRC32 and CRC64 are in little endian. Guess that all the future
490 // 32-bit and 64-bit Check values are little endian too. It shouldn't
491 // be a too big problem if this guess is wrong.
493 snprintf(check_value, sizeof(check_value),
494 "%08" PRIx32, conv32le(buf.u32[0]));
496 snprintf(check_value, sizeof(check_value),
497 "%016" PRIx64, conv64le(buf.u64[0]));
499 for (size_t i = 0; i < size; ++i)
500 snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);
506 /// \brief Parse detailed information about a Block
508 /// Since this requires seek(s), listing information about all Blocks can
511 /// \param pair Input file
512 /// \param iter Location of the Block whose Check value should
514 /// \param bhi Pointer to structure where to store the information
515 /// about the Block Header field.
517 /// \return False on success, true on error. If an error occurs,
518 /// the error message is printed too so the caller doesn't
519 /// need to worry about that.
521 parse_details(file_pair *pair, const lzma_index_iter *iter,
522 block_header_info *bhi, xz_file_info *xfi)
524 if (parse_block_header(pair, iter, bhi, xfi))
527 if (parse_check_value(pair, iter))
534 /// \brief Get the compression ratio
536 /// This has slightly different format than that is used by in message.c.
538 get_ratio(uint64_t compressed_size, uint64_t uncompressed_size)
540 if (uncompressed_size == 0)
543 const double ratio = (double)(compressed_size)
544 / (double)(uncompressed_size);
549 snprintf(buf, sizeof(buf), "%.3f", ratio);
554 /// \brief Get a comma-separated list of Check names
556 /// \param checks Bit mask of Checks to print
557 /// \param space_after_comma
558 /// It's better to not use spaces in table-like listings,
559 /// but in more verbose formats a space after a comma
560 /// is good for readability.
562 get_check_names(uint32_t checks, bool space_after_comma)
566 static char buf[sizeof(check_names)];
568 size_t left = sizeof(buf);
570 const char *sep = space_after_comma ? ", " : ",";
573 for (size_t i = 0; i <= LZMA_CHECK_ID_MAX; ++i) {
574 if (checks & (UINT32_C(1) << i)) {
575 my_snprintf(&pos, &left, "%s%s",
576 comma ? sep : "", check_names[i]);
586 print_info_basic(const xz_file_info *xfi, file_pair *pair)
588 static bool headings_displayed = false;
589 if (!headings_displayed) {
590 headings_displayed = true;
591 // TRANSLATORS: These are column headings. From Strms (Streams)
592 // to Ratio, the columns are right aligned. Check and Filename
593 // are left aligned. If you need longer words, it's OK to
594 // use two lines here. Test with "xz -l foo.xz".
595 puts(_("Strms Blocks Compressed Uncompressed Ratio "
599 printf("%5s %7s %11s %11s %5s %-7s %s\n",
600 uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
601 uint64_to_str(lzma_index_block_count(xfi->idx), 1),
602 uint64_to_nicestr(lzma_index_file_size(xfi->idx),
603 NICESTR_B, NICESTR_TIB, false, 2),
605 lzma_index_uncompressed_size(xfi->idx),
606 NICESTR_B, NICESTR_TIB, false, 3),
607 get_ratio(lzma_index_file_size(xfi->idx),
608 lzma_index_uncompressed_size(xfi->idx)),
609 get_check_names(lzma_index_checks(xfi->idx), false),
617 print_adv_helper(uint64_t stream_count, uint64_t block_count,
618 uint64_t compressed_size, uint64_t uncompressed_size,
619 uint32_t checks, uint64_t stream_padding)
621 printf(_(" Streams: %s\n"),
622 uint64_to_str(stream_count, 0));
623 printf(_(" Blocks: %s\n"),
624 uint64_to_str(block_count, 0));
625 printf(_(" Compressed size: %s\n"),
626 uint64_to_nicestr(compressed_size,
627 NICESTR_B, NICESTR_TIB, true, 0));
628 printf(_(" Uncompressed size: %s\n"),
629 uint64_to_nicestr(uncompressed_size,
630 NICESTR_B, NICESTR_TIB, true, 0));
631 printf(_(" Ratio: %s\n"),
632 get_ratio(compressed_size, uncompressed_size));
633 printf(_(" Check: %s\n"),
634 get_check_names(checks, true));
635 printf(_(" Stream padding: %s\n"),
636 uint64_to_nicestr(stream_padding,
637 NICESTR_B, NICESTR_TIB, true, 0));
643 print_info_adv(xz_file_info *xfi, file_pair *pair)
645 // Print the overall information.
646 print_adv_helper(lzma_index_stream_count(xfi->idx),
647 lzma_index_block_count(xfi->idx),
648 lzma_index_file_size(xfi->idx),
649 lzma_index_uncompressed_size(xfi->idx),
650 lzma_index_checks(xfi->idx),
651 xfi->stream_padding);
653 // Size of the biggest Check. This is used to calculate the width
654 // of the CheckVal field. The table would get insanely wide if
655 // we always reserved space for 64-byte Check (128 chars as hex).
656 uint32_t check_max = 0;
658 // Print information about the Streams.
660 // TRANSLATORS: The second line is column headings. All except
661 // Check are right aligned; Check is left aligned. Test with
663 puts(_(" Streams:\n Stream Blocks"
664 " CompOffset UncompOffset"
665 " CompSize UncompSize Ratio"
668 lzma_index_iter iter;
669 lzma_index_iter_init(&iter, xfi->idx);
671 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
672 printf(" %6s %9s %15s %15s ",
673 uint64_to_str(iter.stream.number, 0),
674 uint64_to_str(iter.stream.block_count, 1),
676 iter.stream.compressed_offset, 2),
678 iter.stream.uncompressed_offset, 3));
679 printf("%15s %15s %5s %-10s %7s\n",
680 uint64_to_str(iter.stream.compressed_size, 0),
682 iter.stream.uncompressed_size, 1),
683 get_ratio(iter.stream.compressed_size,
684 iter.stream.uncompressed_size),
685 check_names[iter.stream.flags->check],
686 uint64_to_str(iter.stream.padding, 2));
688 // Update the maximum Check size.
689 if (lzma_check_size(iter.stream.flags->check) > check_max)
690 check_max = lzma_check_size(iter.stream.flags->check);
693 // Cache the verbosity level to a local variable.
694 const bool detailed = message_verbosity_get() >= V_DEBUG;
696 // Information collected from Block Headers
697 block_header_info bhi;
699 // Print information about the Blocks but only if there is
700 // at least one Block.
701 if (lzma_index_block_count(xfi->idx) > 0) {
702 // Calculate the width of the CheckVal field.
703 const int checkval_width = my_max(8, 2 * check_max);
705 // TRANSLATORS: The second line is column headings. All
706 // except Check are right aligned; Check is left aligned.
707 printf(_(" Blocks:\n Stream Block"
708 " CompOffset UncompOffset"
709 " TotalSize UncompSize Ratio Check"));
712 // TRANSLATORS: These are additional column headings
713 // for the most verbose listing mode. CheckVal
714 // (Check value), Flags, and Filters are left aligned.
715 // Header (Block Header Size), CompSize, and MemUsage
716 // are right aligned. %*s is replaced with 0-120
717 // spaces to make the CheckVal column wide enough.
718 // Test with "xz -lvv foo.xz".
719 printf(_(" CheckVal %*s Header Flags "
720 "CompSize MemUsage Filters"),
721 checkval_width - 8, "");
726 lzma_index_iter_init(&iter, xfi->idx);
728 // Iterate over the Blocks.
729 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
730 if (detailed && parse_details(pair, &iter, &bhi, xfi))
733 printf(" %6s %9s %15s %15s ",
734 uint64_to_str(iter.stream.number, 0),
736 iter.block.number_in_stream, 1),
738 iter.block.compressed_file_offset, 2),
740 iter.block.uncompressed_file_offset,
742 printf("%15s %15s %5s %-*s",
743 uint64_to_str(iter.block.total_size, 0),
744 uint64_to_str(iter.block.uncompressed_size,
746 get_ratio(iter.block.total_size,
747 iter.block.uncompressed_size),
749 check_names[iter.stream.flags->check]);
752 // Show MiB for memory usage, because it
753 // is the only size which is not in bytes.
754 const lzma_vli compressed_size
755 = iter.block.unpadded_size
758 iter.stream.flags->check);
759 printf("%-*s %6s %-5s %15s %7s MiB %s",
760 checkval_width, check_value,
761 uint64_to_str(bhi.header_size, 0),
763 uint64_to_str(compressed_size, 1),
765 round_up_to_mib(bhi.memusage),
775 printf(_(" Memory needed: %s MiB\n"), uint64_to_str(
776 round_up_to_mib(xfi->memusage_max), 0));
777 printf(_(" Sizes in headers: %s\n"),
778 xfi->all_have_sizes ? _("Yes") : _("No"));
786 print_info_robot(xz_file_info *xfi, file_pair *pair)
788 printf("name\t%s\n", pair->src_name);
790 printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
791 "\t%s\t%s\t%" PRIu64 "\n",
792 lzma_index_stream_count(xfi->idx),
793 lzma_index_block_count(xfi->idx),
794 lzma_index_file_size(xfi->idx),
795 lzma_index_uncompressed_size(xfi->idx),
796 get_ratio(lzma_index_file_size(xfi->idx),
797 lzma_index_uncompressed_size(xfi->idx)),
798 get_check_names(lzma_index_checks(xfi->idx), false),
799 xfi->stream_padding);
801 if (message_verbosity_get() >= V_VERBOSE) {
802 lzma_index_iter iter;
803 lzma_index_iter_init(&iter, xfi->idx);
805 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
806 printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
807 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
808 "\t%s\t%s\t%" PRIu64 "\n",
810 iter.stream.block_count,
811 iter.stream.compressed_offset,
812 iter.stream.uncompressed_offset,
813 iter.stream.compressed_size,
814 iter.stream.uncompressed_size,
815 get_ratio(iter.stream.compressed_size,
816 iter.stream.uncompressed_size),
817 check_names[iter.stream.flags->check],
818 iter.stream.padding);
820 lzma_index_iter_rewind(&iter);
821 block_header_info bhi;
823 while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
824 if (message_verbosity_get() >= V_DEBUG
826 pair, &iter, &bhi, xfi))
829 printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
830 "\t%" PRIu64 "\t%" PRIu64
831 "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
833 iter.block.number_in_stream,
834 iter.block.number_in_file,
835 iter.block.compressed_file_offset,
836 iter.block.uncompressed_file_offset,
837 iter.block.total_size,
838 iter.block.uncompressed_size,
839 get_ratio(iter.block.total_size,
840 iter.block.uncompressed_size),
841 check_names[iter.stream.flags->check]);
843 if (message_verbosity_get() >= V_DEBUG)
844 printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
857 if (message_verbosity_get() >= V_DEBUG)
858 printf("summary\t%" PRIu64 "\t%s\n",
860 xfi->all_have_sizes ? "yes" : "no");
867 update_totals(const xz_file_info *xfi)
869 // TODO: Integer overflow checks
871 totals.streams += lzma_index_stream_count(xfi->idx);
872 totals.blocks += lzma_index_block_count(xfi->idx);
873 totals.compressed_size += lzma_index_file_size(xfi->idx);
874 totals.uncompressed_size += lzma_index_uncompressed_size(xfi->idx);
875 totals.stream_padding += xfi->stream_padding;
876 totals.checks |= lzma_index_checks(xfi->idx);
878 if (totals.memusage_max < xfi->memusage_max)
879 totals.memusage_max = xfi->memusage_max;
881 totals.all_have_sizes &= xfi->all_have_sizes;
888 print_totals_basic(void)
890 // Print a separator line.
892 memset(line, '-', sizeof(line));
893 line[sizeof(line) - 1] = '\0';
896 // Print the totals except the file count, which needs
898 printf("%5s %7s %11s %11s %5s %-7s ",
899 uint64_to_str(totals.streams, 0),
900 uint64_to_str(totals.blocks, 1),
901 uint64_to_nicestr(totals.compressed_size,
902 NICESTR_B, NICESTR_TIB, false, 2),
903 uint64_to_nicestr(totals.uncompressed_size,
904 NICESTR_B, NICESTR_TIB, false, 3),
905 get_ratio(totals.compressed_size,
906 totals.uncompressed_size),
907 get_check_names(totals.checks, false));
909 // Since we print totals only when there are at least two files,
910 // the English message will always use "%s files". But some other
911 // languages need different forms for different plurals so we
912 // have to translate this with N_().
914 // TRANSLATORS: %s is an integer. Only the plural form of this
915 // message is used (e.g. "2 files"). Test with "xz -l foo.xz bar.xz".
916 printf(N_("%s file", "%s files\n",
917 totals.files <= ULONG_MAX ? totals.files
918 : (totals.files % 1000000) + 1000000),
919 uint64_to_str(totals.files, 0));
926 print_totals_adv(void)
930 printf(_(" Number of files: %s\n"),
931 uint64_to_str(totals.files, 0));
932 print_adv_helper(totals.streams, totals.blocks,
933 totals.compressed_size, totals.uncompressed_size,
934 totals.checks, totals.stream_padding);
936 if (message_verbosity_get() >= V_DEBUG) {
937 printf(_(" Memory needed: %s MiB\n"), uint64_to_str(
938 round_up_to_mib(totals.memusage_max), 0));
939 printf(_(" Sizes in headers: %s\n"),
940 totals.all_have_sizes ? _("Yes") : _("No"));
948 print_totals_robot(void)
950 printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
951 "\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
954 totals.compressed_size,
955 totals.uncompressed_size,
956 get_ratio(totals.compressed_size,
957 totals.uncompressed_size),
958 get_check_names(totals.checks, false),
959 totals.stream_padding,
962 if (message_verbosity_get() >= V_DEBUG)
963 printf("\t%" PRIu64 "\t%s",
965 totals.all_have_sizes ? "yes" : "no");
977 // Always print totals in --robot mode. It can be convenient
978 // in some cases and doesn't complicate usage of the
979 // single-file case much.
980 print_totals_robot();
982 } else if (totals.files > 1) {
983 // For non-robot mode, totals are printed only if there
984 // is more than one file.
985 if (message_verbosity_get() <= V_WARNING)
986 print_totals_basic();
996 list_file(const char *filename)
998 if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
999 message_fatal(_("--list works only on .xz files "
1000 "(--format=xz or --format=auto)"));
1002 message_filename(filename);
1004 if (filename == stdin_filename) {
1005 message_error(_("--list does not support reading from "
1010 // Unset opt_stdout so that io_open_src() won't accept special files.
1011 // Set opt_force so that io_open_src() will follow symlinks.
1014 file_pair *pair = io_open_src(filename);
1018 xz_file_info xfi = XZ_FILE_INFO_INIT;
1019 if (!parse_indexes(&xfi, pair)) {
1022 // We have three main modes:
1023 // - --robot, which has submodes if --verbose is specified
1025 // - Normal --list without --verbose
1026 // - --list with one or two --verbose
1028 fail = print_info_robot(&xfi, pair);
1029 else if (message_verbosity_get() <= V_WARNING)
1030 fail = print_info_basic(&xfi, pair);
1032 fail = print_info_adv(&xfi, pair);
1034 // Update the totals that are displayed after all
1035 // the individual files have been listed. Don't count
1038 update_totals(&xfi);
1040 lzma_index_end(xfi.idx, NULL);
1043 io_close(pair, false);