[PATCH] tar: fix verbose output with extract-to-stdout

ThorstenB via busybox <[email protected]> Thu, 30 Jul 2026 20:03:15 +0200
Newsgroups gmane.linux.busybox
Message-ID <[email protected]>
Combining the verbose (-v) and extract-to-stdout (-O) options caused
verbose output and extracted file data to be interleaved unpredictably on
stdout. Verbose listing uses buffered stdio (printf()/puts()), while file
contents are written directly to the stdout file descriptor.

GNU tar also combines buffered verbose output with unbuffered writes for
"-vO", however, GNU tar writes verbose output to stderr, so the two streams
remain separate and consistent. BusyBox tar writes both to stdout, making
the interaction between buffered and unbuffered output visible.

Patch only affects the extract-to-stdout ("-O") path, and only when
combined with verbose output. It flushes stdout before writing file
contents so that, for each archive member, verbose output is emitted
before the corresponding file data.

Includes two test cases.

function                                             old     new   delta
data_extract_to_stdout                                19      36     +17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0)               Total: 17 bytes

Signed-off-by: ThorstenB <[email protected]>
---
 archival/libarchive/data_extract_to_stdout.c   |  3 +++
 .../tar/tar-verbose-extract-to-standard-output | 18 ++++++++++++++++++
 ...tar-very-verbose-extract-to-standard-output | 18 ++++++++++++++++++
 3 files changed, 39 insertions(+)
 create mode 100644 testsuite/tar/tar-verbose-extract-to-standard-output
 create mode 100644 testsuite/tar/tar-very-verbose-extract-to-standard-output

diff --git a/archival/libarchive/data_extract_to_stdout.c b/archival/libarchive/data_extract_to_stdout.c
index 520041329..167a15e7c 100644
--- a/archival/libarchive/data_extract_to_stdout.c
+++ b/archival/libarchive/data_extract_to_stdout.c
@@ -7,6 +7,9 @@
 
 void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
 {
+	// flush buffered stdout before writing directly to STDOUT_FILENO
+	fflush(stdout);
+
 	bb_copyfd_exact_size(archive_handle->src_fd,
 			STDOUT_FILENO,
 			archive_handle->file_header->size);
diff --git a/testsuite/tar/tar-verbose-extract-to-standard-output b/testsuite/tar/tar-verbose-extract-to-standard-output
new file mode 100644
index 000000000..702dac92e
--- /dev/null
+++ b/testsuite/tar/tar-verbose-extract-to-standard-output
@@ -0,0 +1,18 @@
+# FEATURE: CONFIG_FEATURE_TAR_CREATE
+echo "data 1" > file1.txt
+echo "data 2" > file2.txt
+echo "data 3" > file3.txt
+
+busybox tar cf test.tar file1.txt file2.txt file3.txt
+busybox tar xvOf test.tar > output.txt
+
+cat > expected.txt << 'EOF'
+file1.txt
+data 1
+file2.txt
+data 2
+file3.txt
+data 3
+EOF
+
+cmp expected.txt output.txt
diff --git a/testsuite/tar/tar-very-verbose-extract-to-standard-output b/testsuite/tar/tar-very-verbose-extract-to-standard-output
new file mode 100644
index 000000000..b743d3994
--- /dev/null
+++ b/testsuite/tar/tar-very-verbose-extract-to-standard-output
@@ -0,0 +1,18 @@
+# FEATURE: CONFIG_FEATURE_TAR_CREATE
+echo "data 1" > file1.txt
+echo "data 2" > file2.txt
+echo "data 3" > file3.txt
+
+busybox tar cf test.tar file1.txt file2.txt file3.txt
+busybox tar xvvOf test.tar > output.txt
+
+# create expected output
+busybox tar tvvf test.tar file1.txt > expected.txt
+cat file1.txt >> expected.txt
+busybox tar tvvf test.tar file2.txt >> expected.txt
+cat file2.txt >> expected.txt
+busybox tar tvvf test.tar file3.txt >> expected.txt
+cat file3.txt >> expected.txt
+
+cmp expected.txt output.txt
+
-- 
2.51.0