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

Guillermo Rodriguez Garcia via busybox <[email protected]> Fri, 31 Jul 2026 00:29:50 +0200
Newsgroups gmane.linux.busybox
Message-ID <CABDcavb+F6aavj4JVON+fo_6wNm1wCYBJi8W09qD-CVOwj8syA@mail.gmail.com>
--===============3375394289143833788==
Content-Type: multipart/alternative; boundary="000000000000efaf420657db9c4e"

--000000000000efaf420657db9c4e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Wouldn=E2=80=99t it make more sense to do as GNU tar and write verbose outp=
ut to
stderr instead when -O is used ?

Guillermo Rodriguez Garcia
[email protected]

El El jue, 30 jul 2026 a las 20:03, ThorstenB via busybox <
[email protected]> escribi=C3=B3:

> 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 strea=
ms
> 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
>
> _______________________________________________
> busybox mailing list
> [email protected]
> https://lists.busybox.net/mailman/listinfo/busybox
>

--000000000000efaf420657db9c4e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto">Wouldn=E2=80=99t it make more sense to do as GNU tar and =
write verbose output to stderr instead when -O is used ?</div><div><br clea=
r=3D"all"><div><div dir=3D"ltr" class=3D"gmail_signature" data-smartmail=3D=
"gmail_signature">Guillermo Rodriguez Garcia<br><a href=3D"mailto:guille.ro=
[email protected]" target=3D"_blank">[email protected]</a></div></=
div></div><div><br><div class=3D"gmail_quote gmail_quote_container"><div di=
r=3D"ltr" class=3D"gmail_attr">El El jue, 30 jul 2026 a las 20:03, Thorsten=
B via busybox &lt;<a href=3D"mailto:[email protected]">[email protected]=
t</a>&gt; escribi=C3=B3:<br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Combinin=
g the verbose (-v) and extract-to-stdout (-O) options caused<br>
verbose output and extracted file data to be interleaved unpredictably on<b=
r>
stdout. Verbose listing uses buffered stdio (printf()/puts()), while file<b=
r>
contents are written directly to the stdout file descriptor.<br>
<br>
GNU tar also combines buffered verbose output with unbuffered writes for<br=
>
&quot;-vO&quot;, however, GNU tar writes verbose output to stderr, so the t=
wo streams<br>
remain separate and consistent. BusyBox tar writes both to stdout, making<b=
r>
the interaction between buffered and unbuffered output visible.<br>
<br>
Patch only affects the extract-to-stdout (&quot;-O&quot;) path, and only wh=
en<br>
combined with verbose output. It flushes stdout before writing file<br>
contents so that, for each archive member, verbose output is emitted<br>
before the corresponding file data.<br>
<br>
Includes two test cases.<br>
<br>
function=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0old=C2=A0 =C2=A0 =C2=A0new=C2=A0 =C2=A0delta<br>
data_extract_to_stdout=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 19=C2=A0 =C2=A0=
 =C2=A0 36=C2=A0 =C2=A0 =C2=A0+17<br>
---------------------------------------------------------------------------=
---<br>
(add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0)=C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0Total: 17 bytes<br>
<br>
Signed-off-by: ThorstenB &lt;<a href=3D"mailto:[email protected]" target=3D"=
_blank">[email protected]</a>&gt;<br>
---<br>
=C2=A0archival/libarchive/data_extract_to_stdout.c=C2=A0 =C2=A0|=C2=A0 3 ++=
+<br>
=C2=A0.../tar/tar-verbose-extract-to-standard-output | 18 +++++++++++++++++=
+<br>
=C2=A0...tar-very-verbose-extract-to-standard-output | 18 +++++++++++++++++=
+<br>
=C2=A03 files changed, 39 insertions(+)<br>
=C2=A0create mode 100644 testsuite/tar/tar-verbose-extract-to-standard-outp=
ut<br>
=C2=A0create mode 100644 testsuite/tar/tar-very-verbose-extract-to-standard=
-output<br>
<br>
diff --git a/archival/libarchive/data_extract_to_stdout.c b/archival/libarc=
hive/data_extract_to_stdout.c<br>
index 520041329..167a15e7c 100644<br>
--- a/archival/libarchive/data_extract_to_stdout.c<br>
+++ b/archival/libarchive/data_extract_to_stdout.c<br>
@@ -7,6 +7,9 @@<br>
<br>
=C2=A0void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handl=
e)<br>
=C2=A0{<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0// flush buffered stdout before writing directl=
y to STDOUT_FILENO<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0fflush(stdout);<br>
+<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 bb_copyfd_exact_size(archive_handle-&gt;src_fd,=
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 STDOUT_FILENO,<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 archive_handle-&gt;file_header-&gt;size);<br>
diff --git a/testsuite/tar/tar-verbose-extract-to-standard-output b/testsui=
te/tar/tar-verbose-extract-to-standard-output<br>
new file mode 100644<br>
index 000000000..702dac92e<br>
--- /dev/null<br>
+++ b/testsuite/tar/tar-verbose-extract-to-standard-output<br>
@@ -0,0 +1,18 @@<br>
+# FEATURE: CONFIG_FEATURE_TAR_CREATE<br>
+echo &quot;data 1&quot; &gt; file1.txt<br>
+echo &quot;data 2&quot; &gt; file2.txt<br>
+echo &quot;data 3&quot; &gt; file3.txt<br>
+<br>
+busybox tar cf test.tar file1.txt file2.txt file3.txt<br>
+busybox tar xvOf test.tar &gt; output.txt<br>
+<br>
+cat &gt; expected.txt &lt;&lt; &#39;EOF&#39;<br>
+file1.txt<br>
+data 1<br>
+file2.txt<br>
+data 2<br>
+file3.txt<br>
+data 3<br>
+EOF<br>
+<br>
+cmp expected.txt output.txt<br>
diff --git a/testsuite/tar/tar-very-verbose-extract-to-standard-output b/te=
stsuite/tar/tar-very-verbose-extract-to-standard-output<br>
new file mode 100644<br>
index 000000000..b743d3994<br>
--- /dev/null<br>
+++ b/testsuite/tar/tar-very-verbose-extract-to-standard-output<br>
@@ -0,0 +1,18 @@<br>
+# FEATURE: CONFIG_FEATURE_TAR_CREATE<br>
+echo &quot;data 1&quot; &gt; file1.txt<br>
+echo &quot;data 2&quot; &gt; file2.txt<br>
+echo &quot;data 3&quot; &gt; file3.txt<br>
+<br>
+busybox tar cf test.tar file1.txt file2.txt file3.txt<br>
+busybox tar xvvOf test.tar &gt; output.txt<br>
+<br>
+# create expected output<br>
+busybox tar tvvf test.tar file1.txt &gt; expected.txt<br>
+cat file1.txt &gt;&gt; expected.txt<br>
+busybox tar tvvf test.tar file2.txt &gt;&gt; expected.txt<br>
+cat file2.txt &gt;&gt; expected.txt<br>
+busybox tar tvvf test.tar file3.txt &gt;&gt; expected.txt<br>
+cat file3.txt &gt;&gt; expected.txt<br>
+<br>
+cmp expected.txt output.txt<br>
+<br>
-- <br>
2.51.0<br>
<br>
_______________________________________________<br>
busybox mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">[email protected]=
t</a><br>
<a href=3D"https://lists.busybox.net/mailman/listinfo/busybox" rel=3D"noref=
errer" target=3D"_blank">https://lists.busybox.net/mailman/listinfo/busybox=
</a><br>
</blockquote></div></div>

--000000000000efaf420657db9c4e--

--===============3375394289143833788==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

--===============3375394289143833788==--