Lasse Collin [Thu, 14 Apr 2022 11:50:17 +0000 (14:50 +0300)]
xz: Change the cap of the default -T0 memlimit for 32-bit xz.
The SIZE_MAX / 3 was 1365 MiB. 1400 MiB gives little more room
and it looks like a round (artificial) number in --info-memory
once --info-memory is made to display it.
Also, using #if avoids useless code on 64-bit builds.
Lasse Collin [Thu, 14 Apr 2022 11:20:46 +0000 (14:20 +0300)]
xz: Add a default soft memory usage limit for --threads=0.
This is a soft limit in sense that it only affects the number of
threads. It never makes xz fail and it never makes xz change
settings that would affect the compressed output.
The idea is to make -T0 have more reasonable behavior when
the system has very many cores or when a memory-hungry
compression options are used. This also helps with 32-bit xz,
preventing it from running out of address space.
The downside of this commit is that now the number of threads
might become too low compared to what the user expected. I
hope this to be an acceptable compromise as the old behavior
has been a source of well-argued complaints for a long time.
Lasse Collin [Thu, 14 Apr 2022 09:59:09 +0000 (12:59 +0300)]
xz: Make -T0 use multithreaded mode on single-core systems.
The main problem withi the old behavior is that the compressed
output is different on single-core systems vs. multicore systems.
This commit fixes it by making -T0 one thread in multithreaded mode
on single-core systems.
The downside of this is that it uses more memory. However, if
--memlimit-compress is used, xz can (thanks to the previous commit)
drop to the single-threaded mode still.
Lasse Collin [Thu, 14 Apr 2022 09:38:00 +0000 (12:38 +0300)]
xz: Changes to --memlimit-compress and --no-adjust.
In single-threaded mode, --memlimit-compress can make xz scale down
the LZMA2 dictionary size to meet the memory usage limit. This
obviously affects the compressed output. However, if xz was in
threaded mode, --memlimit-compress could make xz reduce the number
of threads but it wouldn't make xz switch from multithreaded mode
to single-threaded mode or scale down the LZMA2 dictionary size.
This seemed illogical and there was even a "FIXME?" about it.
Now --memlimit-compress can make xz switch to single-threaded
mode if one thread in multithreaded mode uses too much memory.
If memory usage is still too high, then the LZMA2 dictionary
size can be scaled down too.
The option --no-adjust was also changed so that it no longer
prevents xz from scaling down the number of threads as that
doesn't affect compressed output (only performance). After
this commit --no-adjust only prevents adjustments that affect
compressed output, that is, with --no-adjust xz won't switch
from multithreaded mode to single-threaded mode and won't
scale down the LZMA2 dictionary size.
Lasse Collin [Mon, 11 Apr 2022 19:20:49 +0000 (22:20 +0300)]
xz: Add --memlimit-mt-decompress along with a default limit value.
--memlimit-mt-decompress allows specifying the limit for
multithreaded decompression. This matches memlimit_threading in
liblzma. This limit can only affect the number of threads being
used; it will never prevent xz from decompressing a file. The
old --memlimit-decompress option is still used at the same time.
If the value of --memlimit-decompress (the default value or
one specified by the user) is less than the value of
--memlimit-mt-decompress , then --memlimit-mt-decompress is
reduced to match --memlimit-decompress.
Lasse Collin [Wed, 6 Apr 2022 09:39:49 +0000 (12:39 +0300)]
liblzma: Add a new flag LZMA_FAIL_FAST for threaded decoder.
In most cases if the input file is corrupt the application won't
care about the uncompressed content at all. With this new flag
the threaded decoder will return an error as soon as any thread
has detected an error; it won't wait to copy out the data before
the location of the error.
I don't plan to use this in xz to keep the behavior consistent
between single-threaded and multi-threaded modes.
Lasse Collin [Sat, 2 Apr 2022 18:49:59 +0000 (21:49 +0300)]
liblzma: Threaded decoder: Support zpipe.c-style decoding loop.
This makes it possible to call lzma_code() in a loop that only
reads new input when lzma_code() didn't fill the output buffer
completely. That isn't the calling style suggested by the
liblzma example program 02_decompress.c so perhaps the usefulness
of this feature is limited.
Also, it is possible to write such a loop so that it works
with the single-threaded decoder but not with the threaded
decoder even after this commit, or so that it works only if
lzma_mt.timeout = 0.
The zlib tutorial <https://zlib.net/zlib_how.html> is a well-known
example of a loop where more input is read only when output isn't
full. Porting this as is to liblzma would work with the
single-threaded decoder (if LZMA_CONCATENATED isn't used) but it
wouldn't work with threaded decoder even after this commit because
the loop assumes that no more output is possible when it cannot
read more input ("if (strm.avail_in == 0) break;"). This cannot
be fixed at liblzma side; the loop has to be modified at least
a little.
I'm adding this in any case because the actual code is simple
and short and should have no harmful side-effects in other
situations.
Lasse Collin [Tue, 29 Mar 2022 16:19:12 +0000 (19:19 +0300)]
xzgrep: Fix escaping of malicious filenames (ZDI-CAN-16587).
Malicious filenames can make xzgrep to write to arbitrary files
or (with a GNU sed extension) lead to arbitrary code execution.
xzgrep from XZ Utils versions up to and including 5.2.5 are
affected. 5.3.1alpha and 5.3.2alpha are affected as well.
This patch works for all of them.
This bug was inherited from gzip's zgrep. gzip 1.12 includes
a fix for zgrep.
The issue with the old sed script is that with multiple newlines,
the N-command will read the second line of input, then the
s-commands will be skipped because it's not the end of the
file yet, then a new sed cycle starts and the pattern space
is printed and emptied. So only the last line or two get escaped.
One way to fix this would be to read all lines into the pattern
space first. However, the included fix is even simpler: All lines
except the last line get a backslash appended at the end. To ensure
that shell command substitution doesn't eat a possible trailing
newline, a colon is appended to the filename before escaping.
The colon is later used to separate the filename from the grep
output so it is fine to add it here instead of a few lines later.
The old code also wasn't POSIX compliant as it used \n in the
replacement section of the s-command. Using \<newline> is the
POSIX compatible method.
LC_ALL=C was added to the two critical sed commands. POSIX sed
manual recommends it when using sed to manipulate pathnames
because in other locales invalid multibyte sequences might
cause issues with some sed implementations. In case of GNU sed,
these particular sed scripts wouldn't have such problems but some
other scripts could have, see:
info '(sed)Locale Considerations'
This vulnerability was discovered by:
cleemy desu wayo working with Trend Micro Zero Day Initiative
Thanks to Jim Meyering and Paul Eggert discussing the different
ways to fix this and for coordinating the patch release schedule
with gzip.
Lasse Collin [Fri, 25 Mar 2022 23:02:44 +0000 (01:02 +0200)]
liblzma: Fix a deadlock in threaded decoder.
If a worker thread has consumed all input so far and it's
waiting on thr->cond and then the main thread enables
partial update for that thread, the code used to deadlock.
This commit allows one dummy decoding pass to occur in this
situation which then also does the partial update.
As part of the fix, this moves thr->progress_* updates to
avoid the second thr->mutex locking.
Thanks to Jia Tan for finding, debugging, and reporting the bug.
Lasse Collin [Sun, 6 Mar 2022 22:36:16 +0000 (00:36 +0200)]
xz: Add initial support for threaded decompression.
If threading support is enabled at build time, this will
use lzma_stream_decoder_mt() even for single-threaded mode.
With memlimit_threading=0 the behavior should be identical.
This needs some work like adding --memlimit-threading=LIMIT.
The original patch from Sebastian Andrzej Siewior included
a method to get currently available RAM on Linux. It might
be one way to go but as it is Linux-only, the available-RAM
approach needs work for portability or using a fallback method
on other OSes.
Lasse Collin [Sun, 6 Mar 2022 21:36:20 +0000 (23:36 +0200)]
liblzma: Add threaded .xz decompressor.
I realize that this is about a decade late.
Big thanks to Sebastian Andrzej Siewior for the original patch.
I made a bunch of smaller changes but after a while quite a few
things got rewritten. So any bugs in the commit were created by me.
Lasse Collin [Sun, 6 Mar 2022 14:41:19 +0000 (16:41 +0200)]
liblzma: Add new output queue (lzma_outq) features.
Add lzma_outq_clear_cache2() which may leave one buffer allocated
in the cache.
Add lzma_outq_outbuf_memusage() to get the memory needed for
a single lzma_outbuf. This is now used internally in outqueue.c too.
Track both the total amount of memory allocated and the amount of
memory that is in active use (not in cache).
In lzma_outbuf, allow storing the current input position that
matches the current output position. This way the main thread
can notice when no more output is possible without first providing
more input.
Allow specifying return code for lzma_outq_read() in a finished
lzma_outbuf.
Lasse Collin [Tue, 22 Feb 2022 00:04:18 +0000 (02:04 +0200)]
liblzma: Check the return value of lzma_index_append() in threaded encoder.
If lzma_index_append() failed (most likely memory allocation failure)
it could have gone unnoticed and the resulting .xz file would have
an incorrect Index. Decompressing such a file would produce the
correct uncompressed data but then an error would occur when
verifying the Index field.
Lasse Collin [Sun, 20 Feb 2022 18:36:27 +0000 (20:36 +0200)]
liblzma: Make Block decoder catch certain types of errors better.
Now it limits the input and output buffer sizes that are
passed to a raw decoder. This way there's no need to check
if the sizes can grow too big or overflow when updating
Compressed Size and Uncompressed Size counts. This also means
that a corrupt file cannot cause the raw decoder to process
useless extra input or output that would exceed the size info
in Block Header (and thus cause LZMA_DATA_ERROR anyway).
More importantly, now the size information is verified more
carefully in case raw decoder returns LZMA_OK. This doesn't
really matter with the current single-threaded .xz decoder
as the errors would be detected slightly later anyway. But
this helps avoiding corner cases in the upcoming threaded
decompressor, and it might help other Block decoder uses
outside liblzma too.
The test files bad-1-lzma2-{9,10,11}.xz test these conditions.
With the single-threaded .xz decoder the only difference is
that LZMA_DATA_ERROR is detected in a difference place now.
Lasse Collin [Sun, 6 Feb 2022 23:14:37 +0000 (01:14 +0200)]
Translations: Add French translation of man pages.
This matches xz-utils 5.2.5-2 in Debian.
The translation was done by "bubu", proofread by the debian-l10n-french
mailing list contributors, and submitted to me on the xz-devel mailing
list by Jean-Pierre Giraud. Thanks to everyone!
jiat75 [Fri, 28 Jan 2022 12:47:55 +0000 (20:47 +0800)]
liblzma: Add NULL checks to LZMA and LZMA2 properties encoders.
Previously lzma_lzma_props_encode() and lzma_lzma2_props_encode()
assumed that the options pointers must be non-NULL because the
with these filters the API says it must never be NULL. It is
good to do these checks anyway.
Ville Skyttä [Sat, 13 Nov 2021 08:11:57 +0000 (10:11 +0200)]
xzgrep: use `grep -E/-F` instead of `egrep` and `fgrep`
`egrep` and `fgrep` have been deprecated in GNU grep since 2007, and in
current post 3.7 Git they have been made to emit obsolescence warnings:
https://git.savannah.gnu.org/cgit/grep.git/commit/?id=a9515624709865d480e3142fd959bccd1c9372d1
Alexander Bluhm [Tue, 5 Oct 2021 21:33:16 +0000 (23:33 +0200)]
xz: Avoid fchown(2) failure.
OpenBSD does not allow to change the group of a file if the user
does not belong to this group. In contrast to Linux, OpenBSD also
fails if the new group is the same as the old one. Do not call
fchown(2) in this case, it would change nothing anyway.
This fixes an issue with Perl Alien::Build module.
https://github.com/PerlAlien/Alien-Build/issues/62
Lasse Collin [Thu, 9 Sep 2021 18:41:51 +0000 (21:41 +0300)]
liblzma: Use _MSVC_LANG to detect when "noexcept" can be used with MSVC.
By default, MSVC always sets __cplusplus to 199711L. The real
C++ standard version is available in _MSVC_LANG (or one could
use /Zc:__cplusplus to set __cplusplus correctly).
Lasse Collin [Fri, 4 Jun 2021 15:52:48 +0000 (18:52 +0300)]
xzless: Fix less(1) version detection when it contains a dot.
Sometimes the version number from "less -V" contains a dot,
sometimes not. xzless failed detect the version number when
it does contain a dot. This fixes it.
Thanks to nick87720z for reporting this. Apparently it had been
reported here <https://bugs.gentoo.org/489362> in 2013.
Due to architectural limitations, address space available to a single
userspace process on MIPS32 is limited to 2 GiB, not 4, even on systems
that have more physical RAM -- e.g. 64-bit systems with 32-bit
userspace, or systems that use XPA (an extension similar to x86's PAE).
So, for MIPS32, we have to impose stronger memory limits. I've chosen
2000MiB to give the process some headroom.
Lasse Collin [Sat, 30 Jan 2021 16:36:04 +0000 (18:36 +0200)]
CMake: Try to improve compatibility with the FindLibLZMA module.
The naming conflict with FindLibLZMA module gets worse.
Not avoiding it in the first place was stupid.
Normally find_package(LibLZMA) will use the module and
find_package(liblzma 5.2.5 REQUIRED CONFIG) will use the config
file even with a case insensitive file system. However, if
CMAKE_FIND_PACKAGE_PREFER_CONFIG is TRUE and the file system
is case insensitive, find_package(LibLZMA) will find our liblzma
config file instead of using FindLibLZMA module.
One big problem with this is that FindLibLZMA uses
LibLZMA::LibLZMA and we use liblzma::liblzma as the target
name. With target names CMake happens to be case sensitive.
To workaround this, this commit adds
add_library(LibLZMA::LibLZMA ALIAS liblzma::liblzma)
to the config file. Then both spellings work.
To make the behavior consistent between case sensitive and
insensitive file systems, the config and related files are
renamed from liblzmaConfig.cmake to liblzma-config.cmake style.
With this style CMake looks for lowercase version of the package
name so find_package(LiBLzmA 5.2.5 REQUIRED CONFIG) will work
to find our config file.
There are other differences between our config file and
FindLibLZMA so it's still possible that things break for
reasons other than the spelling of the target name. Hopefully
those situations aren't too common.
When the config file is available, it should always give as good or
better results as FindLibLZMA so this commit doesn't affect the
recommendation to use find_package(liblzma 5.2.5 REQUIRED CONFIG)
which explicitly avoids FindLibLZMA.
Lasse Collin [Sun, 17 Jan 2021 17:20:50 +0000 (19:20 +0200)]
liblzma: In EROFS LZMA decoder, verify that comp_size matches at the end.
When the uncompressed size is known to be exact, after decompressing
the stream exactly comp_size bytes of input must have been consumed.
This is a minor improvement to error detection.
Lasse Collin [Thu, 14 Jan 2021 18:07:01 +0000 (20:07 +0200)]
liblzma: Add EROFS LZMA encoder and decoder.
Right now this is just a planned extra-compact format for use
in the EROFS file system in Linux. At this point it's possible
that the format will either change or be abandoned and removed
completely.
The special thing about the encoder is that it uses the
output-size-limited encoding added in the previous commit.
EROFS uses fixed-sized blocks (e.g. 4 KiB) to hold compressed
data so the compressors must be able to create valid streams
that fill the given block size.
Lasse Collin [Wed, 13 Jan 2021 17:16:32 +0000 (19:16 +0200)]
liblzma: Add rough support for output-size-limited encoding in LZMA1.
With this it is possible to encode LZMA1 data without EOPM so that
the encoder will encode as much input as it can without exceeding
the specified output size limit. The resulting LZMA1 stream will
be a normal LZMA1 stream without EOPM. The actual uncompressed size
will be available to the caller via the uncomp_size pointer.
One missing thing is that the LZMA layer doesn't inform the LZ layer
when the encoding is finished and thus the LZ may read more input
when it won't be used. However, this doesn't matter if encoding is
done with a single call (which is the planned use case for now).
For proper multi-call encoding this should be improved.
This commit only adds the functionality for internal use.
Nothing uses it yet.
Lasse Collin [Mon, 11 Jan 2021 21:41:16 +0000 (23:41 +0200)]
xz: Make --keep accept symlinks, hardlinks, and setuid/setgid/sticky.
Previously this required using --force but that has other
effects too which might be undesirable. Changing the behavior
of --keep has a small risk of breaking existing scripts but
since this is a fairly special corner case I expect the
likehood of breakage to be low enough.
I think the new behavior is more logical. The only reason for
the old behavior was to be consistent with gzip and bzip2.
Thanks to Vincent Lefevre and Sebastian Andrzej Siewior.
Lasse Collin [Mon, 11 Jan 2021 21:28:52 +0000 (23:28 +0200)]
Scripts: Fix exit status of xzgrep.
Omit the -q option from xz, gzip, and bzip2. With xz this shouldn't
matter. With gzip it's important because -q makes gzip replace SIGPIPE
with exit status 2. With bzip2 it's important because with -q bzip2
is completely silent if input is corrupt while other decompressors
still give an error message.
Avoiding exit status 2 from gzip is important because bzip2 uses
exit status 2 to indicate corrupt input. Before this commit xzgrep
didn't recognize corrupt .bz2 files because xzgrep was treating
exit status 2 as SIGPIPE for gzip compatibility.
zstd still needs -q because otherwise it is noisy in normal
operation.
The code to detect real SIGPIPE didn't check if the exit status
was due to a signal (>= 128) and so could ignore some other exit
status too.
Lasse Collin [Mon, 11 Jan 2021 20:01:51 +0000 (22:01 +0200)]
Scripts: Fix exit status of xzdiff/xzcmp.
This is a minor fix since this affects only the situation when
the files differ and the exit status is something else than 0.
In such case there could be SIGPIPE from a decompression tool
and that would result in exit status of 2 from xzdiff/xzcmp
while the correct behavior would be to return 1 or whatever
else diff or cmp may have returned.
This commit omits the -q option from xz/gzip/bzip2/lzop arguments.
I'm not sure why the -q was used in the first place, perhaps it
hides warnings in some situation that I cannot see at the moment.
Hopefully the removal won't introduce a new bug.
With gzip the -q option was harmful because it made gzip return 2
instead of >= 128 with SIGPIPE. Ignoring exit status 2 (warning
from gzip) isn't practical because bzip2 uses exit status 2 to
indicate corrupt input file. It's better if SIGPIPE results in
exit status >= 128.
With bzip2 the removal of -q seems to be good because with -q
it prints nothing if input is corrupt. The other tools aren't
silent in this situation even with -q. On the other hand, if
zstd support is added, it will need -q since otherwise it's
noisy in normal situations.
Thanks to Étienne Mollier and Sebastian Andrzej Siewior.
Lasse Collin [Sat, 9 Jan 2021 19:14:36 +0000 (21:14 +0200)]
liblzma: Make lzma_outq usable for threaded decompression too.
Before this commit all output queue buffers were allocated as
a single big allocation. Now each buffer is allocated separately
when needed. Used buffers are cached to avoid reallocation
overhead but the cache will keep only one buffer size at a time.
This should make things work OK in the decompression where most
of the time the buffer sizes will be the same but with some less
common files the buffer sizes may vary.
While this should work fine, it's still a bit preliminary
and may even get reverted if it turns out to be useless for
decompression.
Lasse Collin [Tue, 17 Nov 2020 18:51:48 +0000 (20:51 +0200)]
CMake: Fix compatibility with CMake 3.13.
The syntax "if(DEFINED CACHE{FOO})" requires CMake 3.14.
In some other places the code treats the cache variables
like normal variables already (${FOO} or if(FOO) is used,
not ${CACHE{FOO}).
Lasse Collin [Sun, 1 Nov 2020 20:34:25 +0000 (22:34 +0200)]
xz: Avoid unneeded \f escapes on the man page.
I don't want to use \c in macro arguments but groff_man(7)
suggests that \f has better portability. \f would be needed
for the .TP strings for portability reasons anyway.
Lasse Collin [Sun, 1 Nov 2020 16:41:21 +0000 (18:41 +0200)]
xz: Avoid the abbreviation "e.g." on the man page.
A few are simply omitted, most are converted to "for example"
and surrounded with commas. Sounds like that this is better
style, for example, man-pages(7) recommends avoiding such
abbreviations except in parenthesis.
Lasse Collin [Sun, 12 Jul 2020 20:10:03 +0000 (23:10 +0300)]
xz man page: Change \- (minus) to \(en (en-dash) for a numeric range.
Docs of ancient troff/nroff mention \(em (em-dash) but not \(en
and \- was used for both minus and en-dash. I don't know how
portable \(en is nowadays but it can be changed back if someone
complains. At least GNU groff and OpenBSD's mandoc support it.
Output is from: test-groff -b -e -mandoc -T utf8 -rF0 -t -w w -z
[ "test-groff" is a developmental version of "groff" ]
Input file is ./src/scripts/xzgrep.1
<src/scripts/xzgrep.1>:20 (macro RB): only 1 argument, but more are expected
<src/scripts/xzgrep.1>:23 (macro RB): only 1 argument, but more are expected
<src/scripts/xzgrep.1>:26 (macro RB): only 1 argument, but more are expected
<src/scripts/xzgrep.1>:29 (macro RB): only 1 argument, but more are expected
<src/scripts/xzgrep.1>:32 (macro RB): only 1 argument, but more are expected
"abc..." does not mean the same as "abc ...".
The output from nroff and troff is unchanged except for the space
between "file" and "...".
Output is from: test-groff -b -e -mandoc -T utf8 -rF0 -t -w w -z
[ "test-groff" is a developmental version of "groff" ]
Input file is ./src/xz/xz.1
<src/xz/xz.1>:408 (macro BR): only 1 argument, but more are expected
<src/xz/xz.1>:1009 (macro BR): only 1 argument, but more are expected
<src/xz/xz.1>:1743 (macro BR): only 1 argument, but more are expected
<src/xz/xz.1>:1920 (macro BR): only 1 argument, but more are expected
<src/xz/xz.1>:2213 (macro BR): only 1 argument, but more are expected
Output from nroff and troff is unchanged, except for a font change of a
full stop (.).
Lasse Collin [Wed, 11 Mar 2020 19:15:35 +0000 (21:15 +0200)]
xz: Never use thousand separators in DJGPP builds.
DJGPP 2.05 added support for thousands separators but it's
broken at least under WinXP with Finnish locale that uses
a non-breaking space as the thousands separator. Workaround
by disabling thousands separators for DJGPP builds.
Lasse Collin [Mon, 2 Mar 2020 11:54:33 +0000 (13:54 +0200)]
liblzma: Fix a comment and RC_SYMBOLS_MAX.
The comment didn't match the value of RC_SYMBOLS_MAX and the value
itself was slightly larger than actually needed. The only harm
about this was that memory usage was a few bytes larger.
Lasse Collin [Thu, 27 Feb 2020 18:24:27 +0000 (20:24 +0200)]
Build: Add support for --no-po4a option to autogen.sh.
Normally, if po4a isn't available, autogen.sh will return
with non-zero exit status. The option --no-po4a can be useful
when one knows that po4a isn't available but wants autogen.sh
to still return with zero exit status.
Lasse Collin [Tue, 25 Feb 2020 18:42:31 +0000 (20:42 +0200)]
Build: Fix bugs in the CMake files.
Seems that the phrase "add more quotes" from sh/bash scripting
applies to CMake as well. E.g. passing an unquoted list ${FOO}
to a function that expects one argument results in only the
first element of the list being passed as an argument and
the rest get ignored. Adding quotes helps ("${FOO}").
list(INSERT ...) is weird. Inserting an empty string to an empty
variable results in empty list, but inserting it to a non-empty
variable does insert an empty element to the list.
Since INSERT requires at least one element,
"${CMAKE_THREAD_LIBS_INIT}" needs to be quoted in CMakeLists.txt.
It might result in an empty element in the list. It seems to not
matter as empty elements consistently get ignored in that variable.
In fact, calling cmake_check_push_state() and cmake_check_pop_state()
will strip the empty elements from CMAKE_REQUIRED_LIBRARIES!
In addition to quoting fixes, this fixes checks for the cache
variables in tuklib_cpucores.cmake and tuklib_physmem.cmake.
Thanks to Martin Matuška for testing and reporting the problems.
These fixes aren't tested yet but hopefully they soon will be.