Пример #1
0
static void
print_totals_robot(void)
{
	char checks[CHECKS_STR_SIZE];
	get_check_names(checks, totals.checks, false);

	printf("totals\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
			"\t%s\t%s\t%" PRIu64 "\t%" PRIu64,
			totals.streams,
			totals.blocks,
			totals.compressed_size,
			totals.uncompressed_size,
			get_ratio(totals.compressed_size,
				totals.uncompressed_size),
			checks,
			totals.stream_padding,
			totals.files);

	if (message_verbosity_get() >= V_DEBUG)
		printf("\t%" PRIu64 "\t%s\t%" PRIu32,
				totals.memusage_max,
				totals.all_have_sizes ? "yes" : "no",
				totals.min_version);

	putchar('\n');

	return;
}
Пример #2
0
extern void
list_file(const char *filename)
{
	if (opt_format != FORMAT_XZ && opt_format != FORMAT_AUTO)
		message_fatal(_("--list works only on .xz files "
				"(--format=xz or --format=auto)"));

	message_filename(filename);

	if (filename == stdin_filename) {
		message_error(_("--list does not support reading from "
				"standard input"));
		return;
	}

	// Unset opt_stdout so that io_open_src() won't accept special files.
	// Set opt_force so that io_open_src() will follow symlinks.
	opt_stdout = false;
	opt_force = true;
	file_pair *pair = io_open_src(filename);
	if (pair == NULL)
		return;

	xz_file_info xfi = XZ_FILE_INFO_INIT;
	if (!parse_indexes(&xfi, pair)) {
		bool fail;

		// We have three main modes:
		//  - --robot, which has submodes if --verbose is specified
		//    once or twice
		//  - Normal --list without --verbose
		//  - --list with one or two --verbose
		if (opt_robot)
			fail = print_info_robot(&xfi, pair);
		else if (message_verbosity_get() <= V_WARNING)
			fail = print_info_basic(&xfi, pair);
		else
			fail = print_info_adv(&xfi, pair);

		// Update the totals that are displayed after all
		// the individual files have been listed. Don't count
		// broken files.
		if (!fail)
			update_totals(&xfi);

		lzma_index_end(xfi.idx, NULL);
	}

	io_close(pair, false);
	return;
}
Пример #3
0
extern void
list_totals(void)
{
	if (opt_robot) {
		// Always print totals in --robot mode. It can be convenient
		// in some cases and doesn't complicate usage of the
		// single-file case much.
		print_totals_robot();

	} else if (totals.files > 1) {
		// For non-robot mode, totals are printed only if there
		// is more than one file.
		if (message_verbosity_get() <= V_WARNING)
			print_totals_basic();
		else
			print_totals_adv();
	}

	return;
}
Пример #4
0
static void
print_totals_adv(void)
{
	putchar('\n');
	puts(_("Totals:"));
	printf(_("  Number of files:    %s\n"),
			uint64_to_str(totals.files, 0));
	print_adv_helper(totals.streams, totals.blocks,
			totals.compressed_size, totals.uncompressed_size,
			totals.checks, totals.stream_padding);

	if (message_verbosity_get() >= V_DEBUG) {
		printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
				round_up_to_mib(totals.memusage_max), 0));
		printf(_("  Sizes in headers:   %s\n"),
				totals.all_have_sizes ? _("Yes") : _("No"));
	}

	return;
}
Пример #5
0
static bool
print_info_robot(xz_file_info *xfi, file_pair *pair)
{
	char checks[CHECKS_STR_SIZE];
	get_check_names(checks, lzma_index_checks(xfi->idx), false);

	printf("name\t%s\n", pair->src_name);

	printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
			"\t%s\t%s\t%" PRIu64 "\n",
			lzma_index_stream_count(xfi->idx),
			lzma_index_block_count(xfi->idx),
			lzma_index_file_size(xfi->idx),
			lzma_index_uncompressed_size(xfi->idx),
			get_ratio(lzma_index_file_size(xfi->idx),
				lzma_index_uncompressed_size(xfi->idx)),
			checks,
			xfi->stream_padding);

	if (message_verbosity_get() >= V_VERBOSE) {
		lzma_index_iter iter;
		lzma_index_iter_init(&iter, xfi->idx);

		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM))
			printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
				"\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
				"\t%s\t%s\t%" PRIu64 "\n",
				iter.stream.number,
				iter.stream.block_count,
				iter.stream.compressed_offset,
				iter.stream.uncompressed_offset,
				iter.stream.compressed_size,
				iter.stream.uncompressed_size,
				get_ratio(iter.stream.compressed_size,
					iter.stream.uncompressed_size),
				check_names[iter.stream.flags->check],
				iter.stream.padding);

		lzma_index_iter_rewind(&iter);
		block_header_info bhi;

		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
			if (message_verbosity_get() >= V_DEBUG
					&& parse_details(
						pair, &iter, &bhi, xfi))
				return true;

			printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
					"\t%" PRIu64 "\t%" PRIu64
					"\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s",
					iter.stream.number,
					iter.block.number_in_stream,
					iter.block.number_in_file,
					iter.block.compressed_file_offset,
					iter.block.uncompressed_file_offset,
					iter.block.total_size,
					iter.block.uncompressed_size,
					get_ratio(iter.block.total_size,
						iter.block.uncompressed_size),
					check_names[iter.stream.flags->check]);

			if (message_verbosity_get() >= V_DEBUG)
				printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64
						"\t%" PRIu64 "\t%s",
						check_value,
						bhi.header_size,
						bhi.flags,
						bhi.compressed_size,
						bhi.memusage,
						bhi.filter_chain);

			putchar('\n');
		}
	}

	if (message_verbosity_get() >= V_DEBUG)
		printf("summary\t%" PRIu64 "\t%s\t%" PRIu32 "\n",
				xfi->memusage_max,
				xfi->all_have_sizes ? "yes" : "no",
				xfi->min_version);

	return false;
}
Пример #6
0
static bool
print_info_adv(xz_file_info *xfi, file_pair *pair)
{
	// Print the overall information.
	print_adv_helper(lzma_index_stream_count(xfi->idx),
			lzma_index_block_count(xfi->idx),
			lzma_index_file_size(xfi->idx),
			lzma_index_uncompressed_size(xfi->idx),
			lzma_index_checks(xfi->idx),
			xfi->stream_padding);

	// Size of the biggest Check. This is used to calculate the width
	// of the CheckVal field. The table would get insanely wide if
	// we always reserved space for 64-byte Check (128 chars as hex).
	uint32_t check_max = 0;

	// Print information about the Streams.
	//
	// TRANSLATORS: The second line is column headings. All except
	// Check are right aligned; Check is left aligned. Test with
	// "xz -lv foo.xz".
	puts(_("  Streams:\n    Stream    Blocks"
			"      CompOffset    UncompOffset"
			"        CompSize      UncompSize  Ratio"
			"  Check      Padding"));

	lzma_index_iter iter;
	lzma_index_iter_init(&iter, xfi->idx);

	while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) {
		const char *cols1[4] = {
			uint64_to_str(iter.stream.number, 0),
			uint64_to_str(iter.stream.block_count, 1),
			uint64_to_str(iter.stream.compressed_offset, 2),
			uint64_to_str(iter.stream.uncompressed_offset, 3),
		};
		printf("    %*s %*s %*s %*s ",
				tuklib_mbstr_fw(cols1[0], 6), cols1[0],
				tuklib_mbstr_fw(cols1[1], 9), cols1[1],
				tuklib_mbstr_fw(cols1[2], 15), cols1[2],
				tuklib_mbstr_fw(cols1[3], 15), cols1[3]);

		const char *cols2[5] = {
			uint64_to_str(iter.stream.compressed_size, 0),
			uint64_to_str(iter.stream.uncompressed_size, 1),
			get_ratio(iter.stream.compressed_size,
				iter.stream.uncompressed_size),
			_(check_names[iter.stream.flags->check]),
			uint64_to_str(iter.stream.padding, 2),
		};
		printf("%*s %*s  %*s  %-*s %*s\n",
				tuklib_mbstr_fw(cols2[0], 15), cols2[0],
				tuklib_mbstr_fw(cols2[1], 15), cols2[1],
				tuklib_mbstr_fw(cols2[2], 5), cols2[2],
				tuklib_mbstr_fw(cols2[3], 10), cols2[3],
				tuklib_mbstr_fw(cols2[4], 7), cols2[4]);

		// Update the maximum Check size.
		if (lzma_check_size(iter.stream.flags->check) > check_max)
			check_max = lzma_check_size(iter.stream.flags->check);
	}

	// Cache the verbosity level to a local variable.
	const bool detailed = message_verbosity_get() >= V_DEBUG;

	// Information collected from Block Headers
	block_header_info bhi;

	// Print information about the Blocks but only if there is
	// at least one Block.
	if (lzma_index_block_count(xfi->idx) > 0) {
		// Calculate the width of the CheckVal field.
		const int checkval_width = my_max(8, 2 * check_max);

		// TRANSLATORS: The second line is column headings. All
		// except Check are right aligned; Check is left aligned.
		printf(_("  Blocks:\n    Stream     Block"
			"      CompOffset    UncompOffset"
			"       TotalSize      UncompSize  Ratio  Check"));

		if (detailed) {
			// TRANSLATORS: These are additional column headings
			// for the most verbose listing mode. CheckVal
			// (Check value), Flags, and Filters are left aligned.
			// Header (Block Header Size), CompSize, and MemUsage
			// are right aligned. %*s is replaced with 0-120
			// spaces to make the CheckVal column wide enough.
			// Test with "xz -lvv foo.xz".
			printf(_("      CheckVal %*s Header  Flags        "
					"CompSize    MemUsage  Filters"),
					checkval_width - 8, "");
		}

		putchar('\n');

		lzma_index_iter_init(&iter, xfi->idx);

		// Iterate over the Blocks.
		while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) {
			if (detailed && parse_details(pair, &iter, &bhi, xfi))
					return true;

			const char *cols1[4] = {
				uint64_to_str(iter.stream.number, 0),
				uint64_to_str(
					iter.block.number_in_stream, 1),
				uint64_to_str(
					iter.block.compressed_file_offset, 2),
				uint64_to_str(
					iter.block.uncompressed_file_offset, 3)
			};
			printf("    %*s %*s %*s %*s ",
				tuklib_mbstr_fw(cols1[0], 6), cols1[0],
				tuklib_mbstr_fw(cols1[1], 9), cols1[1],
				tuklib_mbstr_fw(cols1[2], 15), cols1[2],
				tuklib_mbstr_fw(cols1[3], 15), cols1[3]);

			const char *cols2[4] = {
				uint64_to_str(iter.block.total_size, 0),
				uint64_to_str(iter.block.uncompressed_size,
						1),
				get_ratio(iter.block.total_size,
					iter.block.uncompressed_size),
				_(check_names[iter.stream.flags->check])
			};
			printf("%*s %*s  %*s  %-*s",
				tuklib_mbstr_fw(cols2[0], 15), cols2[0],
				tuklib_mbstr_fw(cols2[1], 15), cols2[1],
				tuklib_mbstr_fw(cols2[2], 5), cols2[2],
				tuklib_mbstr_fw(cols2[3], detailed ? 11 : 1),
					cols2[3]);

			if (detailed) {
				const lzma_vli compressed_size
						= iter.block.unpadded_size
						- bhi.header_size
						- lzma_check_size(
						iter.stream.flags->check);

				const char *cols3[6] = {
					check_value,
					uint64_to_str(bhi.header_size, 0),
					bhi.flags,
					uint64_to_str(compressed_size, 1),
					uint64_to_str(
						round_up_to_mib(bhi.memusage),
						2),
					bhi.filter_chain
				};
				// Show MiB for memory usage, because it
				// is the only size which is not in bytes.
				printf("%-*s  %*s  %-5s %*s %*s MiB  %s",
					checkval_width, cols3[0],
					tuklib_mbstr_fw(cols3[1], 6), cols3[1],
					cols3[2],
					tuklib_mbstr_fw(cols3[3], 15),
						cols3[3],
					tuklib_mbstr_fw(cols3[4], 7), cols3[4],
					cols3[5]);
			}

			putchar('\n');
		}
	}

	if (detailed) {
		printf(_("  Memory needed:      %s MiB\n"), uint64_to_str(
				round_up_to_mib(xfi->memusage_max), 0));
		printf(_("  Sizes in headers:   %s\n"),
				xfi->all_have_sizes ? _("Yes") : _("No"));
		printf(_("  Minimum XZ Utils version: %s\n"),
				xz_ver_to_str(xfi->min_version));
	}

	return false;
}
Пример #7
0
Файл: main.c Проект: DrOpdRoP/xz
int
main(int argc, char **argv)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
	InitializeCriticalSection(&exit_status_cs);
#endif

	// Set up the progname variable.
	tuklib_progname_init(argv);

	// Initialize the file I/O. This makes sure that
	// stdin, stdout, and stderr are something valid.
	io_init();

	// Set up the locale and message translations.
	tuklib_gettext_init(PACKAGE, LOCALEDIR);

	// Initialize handling of error/warning/other messages.
	message_init();

	// Set hardware-dependent default values. These can be overriden
	// on the command line, thus this must be done before args_parse().
	hardware_init();

	// Parse the command line arguments and get an array of filenames.
	// This doesn't return if something is wrong with the command line
	// arguments. If there are no arguments, one filename ("-") is still
	// returned to indicate stdin.
	args_info args;
	args_parse(&args, argc, argv);

	if (opt_mode != MODE_LIST && opt_robot)
		message_fatal(_("Compression and decompression with --robot "
			"are not supported yet."));

	// Tell the message handling code how many input files there are if
	// we know it. This way the progress indicator can show it.
	if (args.files_name != NULL)
		message_set_files(0);
	else
		message_set_files(args.arg_count);

	// Refuse to write compressed data to standard output if it is
	// a terminal.
	if (opt_mode == MODE_COMPRESS) {
		if (opt_stdout || (args.arg_count == 1
				&& strcmp(args.arg_names[0], "-") == 0)) {
			if (is_tty_stdout()) {
				message_try_help();
				tuklib_exit(E_ERROR, E_ERROR, false);
			}
		}
	}

	// Set up the signal handlers. We don't need these before we
	// start the actual action and not in --list mode, so this is
	// done after parsing the command line arguments.
	//
	// It's good to keep signal handlers in normal compression and
	// decompression modes even when only writing to stdout, because
	// we might need to restore O_APPEND flag on stdout before exiting.
	// In --test mode, signal handlers aren't really needed, but let's
	// keep them there for consistency with normal decompression.
	if (opt_mode != MODE_LIST)
		signals_init();

	// coder_run() handles compression, decompression, and testing.
	// list_file() is for --list.
	void (*run)(const char *filename) = opt_mode == MODE_LIST
			 ? &list_file : &coder_run;

	// Process the files given on the command line. Note that if no names
	// were given, args_parse() gave us a fake "-" filename.
	for (size_t i = 0; i < args.arg_count && !user_abort; ++i) {
		if (strcmp("-", args.arg_names[i]) == 0) {
			// Processing from stdin to stdout. Check that we
			// aren't writing compressed data to a terminal or
			// reading it from a terminal.
			if (opt_mode == MODE_COMPRESS) {
				if (is_tty_stdout())
					continue;
			} else if (is_tty_stdin()) {
				continue;
			}

			// It doesn't make sense to compress data from stdin
			// if we are supposed to read filenames from stdin
			// too (enabled with --files or --files0).
			if (args.files_name == stdin_filename) {
				message_error(_("Cannot read data from "
						"standard input when "
						"reading filenames "
						"from standard input"));
				continue;
			}

			// Replace the "-" with a special pointer, which is
			// recognized by coder_run() and other things.
			// This way error messages get a proper filename
			// string and the code still knows that it is
			// handling the special case of stdin.
			args.arg_names[i] = (char *)stdin_filename;
		}

		// Do the actual compression or decompression.
		run(args.arg_names[i]);
	}

	// If --files or --files0 was used, process the filenames from the
	// given file or stdin. Note that here we don't consider "-" to
	// indicate stdin like we do with the command line arguments.
	if (args.files_name != NULL) {
		// read_name() checks for user_abort so we don't need to
		// check it as loop termination condition.
		while (true) {
			const char *name = read_name(&args);
			if (name == NULL)
				break;

			// read_name() doesn't return empty names.
			assert(name[0] != '\0');
			run(name);
		}

		if (args.files_name != stdin_filename)
			(void)fclose(args.files_file);
	}

	// All files have now been handled. If in --list mode, display
	// the totals before exiting. We don't have signal handlers
	// enabled in --list mode, so we don't need to check user_abort.
	if (opt_mode == MODE_LIST) {
		assert(!user_abort);
		list_totals();
	}

#ifndef NDEBUG
	coder_free();
#endif

	// If we have got a signal, raise it to kill the program instead
	// of calling tuklib_exit().
	signals_exit();

	// Make a local copy of exit_status to keep the Windows code
	// thread safe. At this point it is fine if we miss the user
	// pressing C-c and don't set the exit_status to E_ERROR on
	// Windows.
#if defined(_WIN32) && !defined(__CYGWIN__)
	EnterCriticalSection(&exit_status_cs);
#endif

	enum exit_status_type es = exit_status;

#if defined(_WIN32) && !defined(__CYGWIN__)
	LeaveCriticalSection(&exit_status_cs);
#endif

	// Suppress the exit status indicating a warning if --no-warn
	// was specified.
	if (es == E_WARNING && no_warn)
		es = E_SUCCESS;

	tuklib_exit(es, E_ERROR, message_verbosity_get() != V_SILENT);
}