Compare commits

...
Author SHA1 Message Date
Colin Percival 8c9ce319fe Update in preparation for 14.3-RELEASE
- Bump BRANCH to RELEASE
- Add the anticipated RELEASE announcement date
- Set a static __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	Amazon
2025-06-06 00:00:00 +00:00
Tom Hukins ffacf114e1 Fix incorrect version introduced in manual pages
Several manual pages for releng/14.3 incorrectly claim that features
were first introduced in FreeBSD 15.0.

I discovered these by running:

  git checkout origin/releng/14.3
  git grep -F '.Fx 15.0'

Approved by:    re (cperciva)
MFC After: 3 days
Reviewed by: imp, ziaee
Pull Request: https://github.com/freebsd/freebsd-src/pull/1685

(cherry picked from commit 5b9660caff)
(cherry picked from commit ef4014882e)
2025-06-03 17:47:57 -06:00
Kenneth Raplee cd46420a61 ure.4: add a HARDWARE section + add RTL8156BG as a compatible controller
While here, rename all instances of "RealTek" to "Realtek" for
authenticity.

Approved by:	re (cperciva)
Reviewed by: imp, lwshu, zaiee
Pull Request: https://github.com/freebsd/freebsd-src/pull/1649

(cherry picked from commit 76ed6f2db3)
(cherry picked from commit f336a04960)
2025-06-03 11:35:21 -07:00
Alexander Ziaee 6fe425b4c4 ure.4: description consistencies + tag spdx
+ consistent document description languague with other USB-BaseT drivers
+ mention newly added adapters from 6ea4d9
+ attempt to mention rgephy(4) phys feed into ure interfaces

Approved by:	re (cperciva)
Fixes:		6ea4d9 (Move RTL8156 from cdce(4) to ure(4))
MFC after:	3 days

Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/1384

(cherry picked from commit 4c72525953)
(cherry picked from commit b529a06d1d)
2025-06-03 11:35:11 -07:00
Kenneth Raplee 9efdb081e8 puc.4: Add a HARDWARE section based off device data from pucdata.c
While here, change applicable uses of "ports" to "adapters" to be more
precise and improve searchability.

This is a 14.3 candate since it affects (positively) the release notes
generated from the hardware secionts.

Approved by:	re (cperciva)
MFC After: 3 days
Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/1663

(cherry picked from commit 794ee43e75)
(cherry picked from commit 827153d212)
2025-06-03 11:35:01 -07:00
Colin Percival a7a4742156 Reapply "14.3: Update to RC1"
Second attempt at making 14.3-RC1 happen, now that a critical
last-minute MFC has landed.

This reverts commit c5db8f6562.

Approved by:	re (cperciva)
2025-05-30 09:02:53 -07:00
Dag-Erling Smørgrav fb33dd91ae certctl: Split certificate bundles before processing.
This allows 'certctl rehash' to do the right thing when ca_root_nss is
installed, instead of linking the entire bundle to the hash of the
first certificate it contains.

MFC after:	3 days
Reviewed by:	allanjude
Differential Revision:	https://reviews.freebsd.org/D42087

(cherry picked from commit a401c8cb26)

certctl: Fix recent regressions.

- If an untrusted certificate is also found in the list of trusted
  certificate, issue a warning and skip it, but don't fail.
- Split on -+BEGIN CERTIFICATE-+ instead of "Certificate:" since
  that's what we're really looking for.

Also fix a long-standing bug: .crl files are not certificates, so we
should not include them when searching for certificates.

Reported by:	madpilot, netchild, tijl
Reviewed by:	netchild, allanjude
Differential Revision:	https://reviews.freebsd.org/D42276

(cherry picked from commit 87945a0829)

certctl: Convert line endings before inspecting files.

This ensures that certificate files or bundles with DOS or Mac line
endings are recognized as such and handled identically to those with
Unix line endings.

PR:		274952
Reviewed by:	allanjude
Differential Revision:	https://reviews.freebsd.org/D42490

(cherry picked from commit f7d16a627e)

certctl: Revert to symlinks.

Unfortunately tar will not be able to extract base.txz to a system where
/etc and /usr are not on the same filesystem if the certificates are
hard links.

PR:		277828
Reviewed by:	mp
Differential Revision:	https://reviews.freebsd.org/D44496

(cherry picked from commit 3fed4f0db5)
(cherry picked from commit 9c34a6876a)

Approved by:	re (cperciva)
2025-05-30 17:59:32 +02:00
Colin Percival c5db8f6562 Revert "14.3: Update to RC1"
Postponing RC1 slightly to allow one more critical bug fix.

This reverts commit 3383279318.

Approved by:	re (cperciva)
2025-05-30 08:53:21 -07:00
Colin Percival 3383279318 14.3: Update to RC1
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-29 15:54:06 -07:00
Christos Margiolis 99b8be414c sound: Terminate stream properly when closing vchans
When a channel is closed, dsp_close() either calls vchan_destroy() on vchans,
or chn_abort()/chn_flush() on primary channels. However, the problem with this
is that, when closing a vchan, we end up not terminating the stream properly.

The call sequence we are interested in is the following:

	vchan_destroy(vchan) -> chn_kill(vchan) -> chn_trigger(vchan) ->
	vchan_trigger(vchan) -> chn_notify(parent)

Even though chn_notify() contains codepaths which call chn_abort(parent),
apparently we do not execute any of those codepaths in this case, so the
DMA remains unterminated, hence why we keep seeing the primary
channel(s) being interrupted even once the application has exited:

root@freebsd:~ # sndctl interrupts
dsp0.play.0.interrupts=1139
dsp0.record.0.interrupts=0
root@freebsd:~ # sndctl interrupts
dsp0.play.0.interrupts=1277
dsp0.record.0.interrupts=0
root@freebsd:~ # sndctl interrupts
dsp0.play.0.interrupts=1394
dsp0.record.0.interrupts=0

The only applications that do not have this issue are those (e.g., mpv) that
manually call ioctls which end up calling chn_abort(), like SNDCTL_DSP_HALT, to
abort the channel(s) during shutdown. For all other applications that do not
manually abort the channel(s), we can confirm that chn_abort()/chn_flush(), or
even chn_trigger(PCMTRIG_ABORT) on the parent, doesn't happen during shutdown.

root@freebsd:~ # dtrace -n 'fbt::chn_abort:entry,fbt::chn_flush:entry { printf("%s", args[0]->name); stack(); }'
dtrace: description 'fbt::chn_abort:entry,fbt::chn_flush:entry ' matched 2 probes
dtrace: buffer size lowered to 1m
^C

[...]

root@freebsd:~ # dtrace -n 'fbt::chn_trigger:entry /args[1] == -1/ { printf("%s", args[0]->name); stack(); }'
dtrace: description 'fbt::chn_trigger:entry ' matched 1 probe
dtrace: buffer size lowered to 1m
CPU     ID                    FUNCTION:NAME
  0  68037                chn_trigger:entry dsp0.virtual_play.0
	      sound.ko`chn_kill+0x134
	      sound.ko`vchan_destroy+0x94
	      sound.ko`dsp_close+0x39b
	      kernel`devfs_destroy_cdevpriv+0xab
	      kernel`devfs_close_f+0x63
	      kernel`_fdrop+0x1a
	      kernel`closef+0x1e3
	      kernel`closefp_impl+0x76
	      kernel`amd64_syscall+0x151
	      kernel`0xffffffff8103841b1

To fix this, modify dsp_close() to execute the primary channel case on both
primary and virtual channels. While what we really care about are the
chn_abort()/chn_flush() calls, it shouldn't hurt to call the rest of the
functions on the vchans as well, to avoid complicating things; they get deleted
right below, anyway.

With the patch applied:

root@freebsd:~ # dtrace -n 'fbt::chn_trigger:entry /args[1] == -1/ { printf("%s", args[0]->name); stack(); }'
dtrace: description 'fbt::chn_trigger:entry ' matched 1 probe
dtrace: buffer size lowered to 1m
CPU     ID                    FUNCTION:NAME
  1  68037                chn_trigger:entry dsp0.virtual_play.0
              sound.ko`chn_flush+0x2a
              sound.ko`dsp_close+0x330
              kernel`devfs_destroy_cdevpriv+0xab
              kernel`devfs_close_f+0x63
              kernel`_fdrop+0x1a
              kernel`closef+0x1e3
              kernel`closefp_impl+0x76
              kernel`amd64_syscall+0x151
              kernel`0xffffffff8103841b

  0  68037                chn_trigger:entry dsp0.play.0
              sound.ko`chn_notify+0x4ce
              sound.ko`vchan_trigger+0x105
              sound.ko`chn_trigger+0xb4
              sound.ko`chn_flush+0x2a
              sound.ko`dsp_close+0x330
              kernel`devfs_destroy_cdevpriv+0xab
              kernel`devfs_close_f+0x63
              kernel`_fdrop+0x1a
              kernel`closef+0x1e3
              kernel`closefp_impl+0x76
              kernel`amd64_syscall+0x151
              kernel`0xffffffff8103841b

Above we can see a chn_trigger(PCMTRIG_ABORT) on the parent (dsp0.play.0),
which is coming from the chn_abort() (inlined) in chn_notify():

root@freebsd:~ # dtrace -n 'kinst::chn_abort:entry { stack(); }'
dtrace: description 'kinst::chn_abort:entry ' matched 5 probes
dtrace: buffer size lowered to 1m
CPU     ID                    FUNCTION:NAME
  1  72580                  chn_notify:1192
              sound.ko`0xffffffff8296cab4
              sound.ko`vchan_trigger+0x105
              sound.ko`chn_trigger+0xb4
              sound.ko`chn_flush+0x2a
              sound.ko`dsp_close+0x330
              kernel`devfs_destroy_cdevpriv+0xab
              kernel`devfs_close_f+0x63
              kernel`_fdrop+0x1a
              kernel`closef+0x1e3
              kernel`closefp_impl+0x76
              kernel`amd64_syscall+0x151
              kernel`0xffffffff8103841b

We can also confirm the primary channel(s) are not interrupted anymore:

root@freebsd:/mnt/src # sndctl interrupts
dsp0.play.0.interrupts=0
dsp0.record.0.interrupts=0

In collaboration with:	adrian
Tested by:		adrian, christos, thj
Sponsored by:		The FreeBSD Foundation
MFC after:		2 days
Reviewed by:		thj, adrian, emaste
Differential Revision:	https://reviews.freebsd.org/D50488

(cherry picked from commit f6430bc61d)
(cherry picked from commit 0c6aa445ec)

Approved by:		re (cperciva)
2025-05-30 00:51:30 +02:00
Colin Percival 85739bcbce 14.3: Switch from "quarterly" to "release" pkgs
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-29 15:18:34 -07:00
Colin Percival a47542f715 pkg.conf: Use kmod repositories
The kmod repositories were added shortly after 14.2-RELEASE.  Point at
them here so that users don't need to manually add the configuration
in order to get e.g. working graphics.

Approved by:	re (cperciva)
MFC after:	1 minute
Sponsored by:	Amazon
Differential Revision:	https://reviews.freebsd.org/D50583

(cherry picked from commit 29f076ae0c)
(cherry picked from commit 8a2ce9f9dd)
2025-05-29 12:58:46 -07:00
Jordan Gordeev a0d22d7934 libc++: fix compiling <locale> with -fmodules
In /usr/include/c++/v1/__locale_dir/locale_base_api.h, xlocale.h is
included without first including stdio.h and stdlib.h, which causes
functions like strtoll_l() or sscanf_l() to not be declared.

When compiling with -fmodules, locale_base_api.h is processed separately
due to a declaration in /usr/include/c++/v1/module.modulemap, and this
will cause errors due to the above undeclared symbols.

Meanwhile, upstream has substantially reorganized this part of libc++'s
headers, so apply a minimalistic workaround: specifically when compiling
with -fmodules, add includes of stdio.h and stdlib.h.

PR:		286342
Approved by:	re (cperciva)
MFC after:	1 week

(cherry picked from commit c809b0184d)
(cherry picked from commit cab029073d)
2025-05-28 18:26:27 +02:00
Alexander Motin 93839cddbd systat/top: Update ZFS sysctl names
Some of ARC statistic sysctls changed years ago, but those tools
are still using legacy shims, that are going to be removed.

Approved by:    re (cperciva)

(cherry picked from commit 8aad1e6148)
(cherry picked from commit f23326ff2c)
2025-05-27 22:20:01 -04:00
Bjoern A. Zeeb 4d66e0f884 LinuxKPI: 802.11: mark struct ieee80211_ht_cap __packed
In lkpi_sta_sync_ht_from_ni() we are casting the information element (IE)
data to this struct as net80211 does not save the mcs/rx_mask.
Not marking the structs packed results in the mcs information not being
copied correctly and rx_nss calculations possibly being off.  Even worse,
at a later stage iwlwifi mvm/rs.c would extract the mcs values from the
same field to pass to the firmware which will than crash in an assert
as we would want to do HT with an empty MCS set.

Sponsored by:	The FreeBSD Foundation
Discovered:	while testing other features on arm64.
Approved by:	re (cperciva)

(cherry picked from commit 6cbf8a04b1)
(cherry picked from commit 9ccf7aeaa5)
2025-05-27 22:44:20 +00:00
Olivier Certner adc6f56e81 MAC/do: Fix a too stringent debug assertion for a target of 'uid=*'
MDF_HAS_PRIMARY_CLAUSE only concerns groups, not users, and is thus not
set in the latter case.

This change only has an effect on INVARIANTS builds.

PR:             287057
MFC after:      10 minutes
Sponsored by:   The FreeBSD Foundation

(cherry picked from commit b5c9889e36)
(cherry picked from commit 30f092c40a)

Approved by:    re (cperciva)
2025-05-27 23:01:54 +02:00
Philip Paeps a48dc9b03b zoneinfo: don't install version
The commit teaching the build to install tzdata.zi for libcxx also
instals version.  It turns out this makes at least one piece of third
party software cry: rubygem-tzinfo expects any file in zoneinfo to be at
least 44 bytes long.  Clearly this is a bug in rubygem-tzinfo but since
nothing actually uses version, we may as well not install it ... as we
did previously.

Reported by:	delphij
Fixes:		91506dba7f zoneinfo: also install tzdata.zi and version
MFC after:	1 day
Approved by:	re (cperciva)

(cherry picked from commit 23a0c88b03)
(cherry picked from commit 16ad4d7712)
2025-05-24 11:33:02 +06:00
Colin Percival c4c9907816 14.3: Update to BETA4
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-22 17:04:19 -07:00
Lexi Winter 6e27b15e6a package: fix dependency generation
A bug in release/packages/generate-ucl.sh causes package dependencies
(other than shlib depends) to not be generated correctly, meaning
packages are missing their dependencies.

generate-ucl.sh creates the UCL file by:

1. copying ${uclsource} (template.ucl) to ${uclfile}
2. appending dependencies to ${uclfile}
3. calling generate-ucl.lua on ${uclsource} to create ${uclfile}

This breaks because the dependencies added in step 2 are overwritten in
step 3.

Fix this by calling generate-ucl.lua with ${uclfile} as both the input
and output file, so anything we added to ${uclfile} is preserved.

PR:	286551
Reviewed by:	des, imp
Approved by:	re (cperciva)
Approved by:	kevans (mentor, stable/14 mfc)
Pull Request:	https://github.com/freebsd/freebsd-src/pull/1203

(cherry picked from commit e05b6502f9)
(cherry picked from commit fb6b1a7973)
2025-05-22 17:04:12 -07:00
Alexander Ziaee 5af0942052 mtkswitch.4: Initial manual page
Add a stub manual only saying what it is, how to include it, what is
supported, and since when. This plugs the mtkswitch driver into the
manual subsystem and the release hardware notes.

MFC to:			14.3
MFC after:		3 days
Reviewed by:		adrian, carlavilla
Approved by:		carlavilla (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50412

(cherry picked from commit 37f00bc257)
(cherry picked from commit f31ac06711)
2025-05-21 23:01:36 -04:00
Alexander Ziaee dc8ade18cf ip17x.4: Initial manual page
Add a stub manual only saying what it is, how to include it, what is
supported, and since when. This plugs the ip17x driver into the manual
subsystem and the release hardware notes.

MFC to:			14.3
MFC after:		3 days
Reviewed by:		adrian, carlavilla
Approved by:		carlavilla (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50411

(cherry picked from commit f750a114d2)
(cherry picked from commit ded154a1df)
2025-05-21 23:01:22 -04:00
Alexander Ziaee 86b04d37f0 qat.4: Cleanup
+ copyright symbols do not belong in Nd's (apropos results)
+ move hardware to HARDWARE for inclusion in the hw release notes
+ improve sysctls
+ lines which say nothing removed
+ links moved to see also
+ spacing and markup corrections

MFC after:		3 days
Reviewed by:		markj, mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50381

(cherry picked from commit c1d9b2c9b0)
(cherry picked from commit 802edf2307)
2025-05-21 23:00:56 -04:00
Alexander Ziaee b7fc3fbe32 e6000sw.4: Add HISTORY
MFC after:		3 days
Reviewed by:		mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50358

(cherry picked from commit c808bee35b)
(cherry picked from commit 6426b01310)
2025-05-21 23:00:39 -04:00
Alexander Ziaee ee743b40ac e6060sw.4: Improve title and add HARDWARE
For visibility in apropos and inclusion in the hardware release notes.

MFC after:		3 days
Reviewed by:		adrian, mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50321

(cherry picked from commit bef89c155e)
(cherry picked from commit 5e0e046d95)
2025-05-21 23:00:26 -04:00
Alexander Ziaee fddd2c4d37 ar40xx.4: Initial manual page
For inclusion in apropos and the hardware release notes. While here,
add xrefs to this page and the previous e6000sw in etherswitch.4.

MFC after:		3 days (but adjusted for 14.3)
Reported by:		adrian
Reviewed by:		adrian, mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50324

(cherry picked from commit 91c9751c39)
(cherry picked from commit 17e9eb1e0e)
2025-05-21 23:00:12 -04:00
Alexander Ziaee 5dbcb9bfd0 arswitch.4: Improve title and add HARDWARE
For visibility in apropos and inclusion in the hardware release notes.

MFC after:		3 days
Reviewed by:		adrian (previous), mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50322

(cherry picked from commit 9692d5e15e)
(cherry picked from commit 1343a5b616)
2025-05-21 22:58:47 -04:00
Alexander Ziaee f50ca9a01b stand/lua manuals: Describe better
The lua boot loader module manuals were getting pulled into search
results for FreeBSD, but not for "boot" or "loader". Reword them to
increase clarity for boot or loader searches, as well as the FreeBSD
search term which we've been scoping to system topic overview manuals.

MFC after:	3 days
Reviewed by:	imp, mhorne
Approved by:	mhorne (mentor)
Approved by:	re (cperciva)
Pull Request:	https://github.com/freebsd/freebsd-src/pulls/1628

(cherry picked from commit 5d59c1b4f1)
(cherry picked from commit 651102873e)
2025-05-21 22:58:35 -04:00
Alexander Ziaee 5d9e62e1cd cdboot.8: Initial manual page
Add cdboot to the reference manual, fixing an undocumented bug where it
is undocumented. There's almost nothing here, but that's better than
"only imp and jhb know what this is".

MFC after:		3 days
Reported by:		jhb, imp
Reviewed by:		mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50274

(cherry picked from commit ecdb0b79bf)
(cherry picked from commit d659366cc6)
2025-05-21 22:58:21 -04:00
Alexander Ziaee 66a6607089 e6000sw.4: Initial manual page
For inclusion in the HW relnotes.

MFC after:		3 days, note removed entries which didn't mfc
Reviewed by:		adrian, ivy, mhorne
Approved by:		mhorne (mentor)
Approved by:		re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D50293

(cherry picked from commit 6da793a8ca)
(cherry picked from commit d0e29f92f7)
2025-05-21 22:56:59 -04:00
Tijl Coosemans adf77cb48e snd_hda: Add shutdown method
Power down the device on shutdown similar to what is done in the case
of suspend. The device may fail to attach on next boot without this.

PR:		286385
Reviewed by:	christos, adrian
Differential Revision:	https://reviews.freebsd.org/D50306

(cherry picked from commit d9900b9ea2)
(cherry picked from commit 77521692f4)

Approved by:    re (cperciva)
2025-05-22 01:21:42 +02:00
Dag-Erling Smørgrav 747efc2aee namei: Update documentation.
This should have been done 2+ years ago when the td argument was dropped
from NDINIT() and the NDFREE() macro and the SAVENAME and SAVESTART
flags were retired.

Approved by:	re (cperciva)
MFC after:	3 days
Fixes:		7e1d3eefd4 ("vfs: remove the unused thread argument from NDINIT*")
Fixes:		269c564b90 ("vfs: retire NDFREE")
Sponsored by:	NetApp, Inc.
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D50375

(cherry picked from commit ee84b4e2fd)
(cherry picked from commit 68bc635cc9)
2025-05-21 19:37:10 +02:00
Dag-Erling Smørgrav 84b971c918 man: Exit cleanly on SIGPIPE.
The first attempt at addressing this simply suppressed SIGPIPE, which
resulted in mandoc printing out error messages instead.  This was then
reverted, but the pipefail was (correctly) left in, so man still
returned a nonzero exit code if you quit a page before the end.

Approved by:	re (cperciva)
PR:		223516, 279542
Fixes:		14a5c1068d, a85d870007
MFC after:	1 week
Reviewed by:	ziaee, kevans
Differential Revision:	https://reviews.freebsd.org/D50302

(cherry picked from commit fbaba7aa43)
(cherry picked from commit 2f99190a92)
2025-05-21 19:36:41 +02:00
Olivier Certner 6b6d6448fe vfs: vntblinit(): Raise default 'kern.maxvnodes' higher than 'kern.maxfiles'
Having 'kern.maxvnodes' higher than 'kern.maxfiles' mitigates a scenario
where some processes can eat up all vnodes in the system, causing
a deadlock, as long as the kernel itself does not create too many vnodes
without creating some file descriptor in some process' FD table.  A very
small percentage (~0.6%) of excess vnodes at infinity, coupled with
a large difference near the origin, should cover basic cases more than
enough.  Note however that this measure can be defeated, e.g., by using
nullfs mounts with non-trivial file hierarchies.

MFC after:      5 days
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50314

(cherry picked from commit e9baf472a6)
(cherry picked from commit a6b05a35ce)

Approved by:    re (cperciva)
2025-05-21 12:07:52 +02:00
Olivier Certner 0b4d5c560a vfs: vntblinit(): Rework comments on the computation of 'kern.maxvnodes'
Remove the parts that describe what is already in the code formula.  Add
hints about which of 'physvnodes'/'virtvnodes' takes precedence, and
when 'desiredvnodes' becomes smaller than 'maxfiles'.  These were both
computed analytically and verified experimentally.

Reviewed by:    kib (older version)
MFC after:      3 days
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50310

(cherry picked from commit bf8890c84b)
(cherry picked from commit 5b07152f3e)

Approved by:    re (cperciva)
2025-05-21 12:07:45 +02:00
Olivier Certner fbc73f17ba Compute 'maxproc'/'maxfiles' from memory amount; Expand/fix comments
Change the formulae so that 'maxproc' and 'maxfiles' are computed based
on the physical memory amount, and not the corresponding number of
pages.  Make sure that the practical results are unchanged for all
architectures (which is possible since all have 4096 as their
PAGE_SIZE).  Despite this, we do this change to make it clearer how many
units of these values are computed per MB, which is easier on readers.

Change the comments accordingly and expand them to indicate which parts
of the computations are actually not used by default.  In passing, fix the
comments about default values and limits for 'maxfiles' (they were off).

No functional change (intended).

MFC after:      3 days
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50124

(cherry picked from commit 73f9251c0b)
(cherry picked from commit e7d4e52eaf)

Approved by:    re (cperciva)
2025-05-21 12:07:36 +02:00
Olivier Certner 7a9ea03e4b vfs: vn_alloc(): Stop always calling vn_alloc_hard() and direct reclaiming
Commit ab05a1cf32 intended to revert commit 8733bc277a
("vfs: don't provoke recycling non-free vnodes without a good reason"),
but due to intervening changes in commit 054f45e026 ("vfs: further
speed up continuous free vnode recycle"), it also had to revert part of
it.  In particular, while removing the whole 'if (vn_alloc_cyclecount !=
0)' block, it inadvertantly removed the code block resetting
'vn_alloc_cyclecount' to 0 and skipping direct vnode reclamation (done
further below through vnlru_free_locked_direct()), which had been
outside the 'if' before the intervening commit.

Removing this block instead of reinstating it in practice causes
'vn_alloc_cyclecount' to (almost) never be 0, making vn_alloc() always
call vn_alloc_hard(), which takes the 'vnode_list_mtx' mutex.  In other
words, this disables the fast path.  [The reverted commit, which
introduced the 'if (vn_alloc_cyclecount != 0)' guarding this block,
actually never executed it because it also had the bug that
'vn_alloc_cyclecount' would always stay at 0, hiding its usefulness.]

Additionally, not skipping direct vnode reclamation even when there are
less vnodes than 'kern.maxvnodes' not only causes unnecessary contention
but also plain livelocks as vnlru_free_locked_direct() does not itself
check whether there are actually "free" (not referenced) vnodes to be
deallocated, and will blindly browse all the vnode list until it finds
one (which it may not, or only a few ones at the end).  As the fast path
was disabled, all threads in the system would soon be competing for the
vnode list lock, outpacing the vnlru process that could never actually
recycle vnodes in a more agressive manner (i.e., even if they have
a non-zero hold count).  And we could more easily get into this
situation, as each vnode allocation was reducing the count of "free"
vnodes, even if entirely new vnodes could be allocated instead.  This
part was mitigated by the vnlru process (before the tipping point
described above), which explains why the mechanism would not always
livelock.

Not skipping direct vnode reclamation was arguably a bug introduced by
the intervening commit (054f45e026), but was mitigated by
vn_alloc_hard() not being called in the fast path.  The revert commit,
by disabling the fast path, made it significantly annoying (to the point
of getting a few livelocks a week in some of my workloads).

Restore the reset of 'vn_alloc_cyclecount' to 0 and skip direct
reclamation when the current number of vnodes is below the
'kern.maxvnodes' limit, indicating we can start allocating a new 'struct
vnode' right away.  While here, fix the comparison with the limit when
'bumped' is true.

Reviewed by:    kib (older version), avg
Tested by:      avg, olce
Fixes:          ab05a1cf32 (revert of "vfs: don't provoke recycling non-free vnodes without a good reason")
Fixes:          054f45e026 ("vfs: further speed up continuous free vnode recycle")
MFC after:      5 days
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50338

(cherry picked from commit d90c9c24e2)
(cherry picked from commit ce6b7a5919)

Approved by:    re (cperciva)
2025-05-21 12:07:15 +02:00
Bjoern A. Zeeb 361a8fdefa iwlwifi.4: Update modes for recent 802.11ac
By:			ziaee
Reported by:		Pat Maddox <[email protected]>
Reviewed by:		bz (previous version), emaste, mhorne
Differential Revision:	https://reviews.freebsd.org/D49937

iwlwifi: update man pages for generations, firmware. and 11n/11ac

Put Intel's iwlwifi better in context to iwm, iwx and iwn.
Document the important tunables so users know where to go.
Document the port/package for firmware where firmware is now
maintained.
Adjust wording and table for the firmware and a flavor column.
Update History sections for 11n/11ac support as well as firmware
module removal from base.

Sponsored by:	The FreeBSD Foundation
Reviewed by:	ziaee, emaste (comments)
Differential Revision: https://reviews.freebsd.org/D50319

Approved by:	re (cperciva)

(cherry picked from commit c33945a112)
(cherry picked from commit a7e183c0c9)
(cherry picked from commit 4ae64bd33f)
2025-05-19 19:28:40 +00:00
Roger Pau Monné a7277b98b8 xen: improve man (4) page
Update the xen(4) man page to reflect the current support status.

Approved by: re (cperciva)
Reported by: kevans
Reviewed by: bcr kevans imp
Differential revision: https://reviews.freebsd.org/D43373

(cherry picked from commit 82126ef92f)
(cherry picked from commit 7dc0a9fa76)
2025-05-19 10:01:30 -07:00
Colin Percival a2ebf641da 14.3: Update to BETA3
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-16 00:00:00 +00:00
Colin Percival 29d6968fd3 EC2: Remove old broken_txfifo workaround
Early versions of Xen, including those used in the early days of EC2,
had a bug in their UART emulation whereby the TX FIFO wouldn't send the
expected interrupt when emptying; as a result, FreeBSD would write 16
characters to the serial console and then stop because we thought the
FIFO was forever full.

In 2013 (1c60b24baa) I added a loader tunable "hw.broken_txfifo"
which spinwaits for the FIFO TX rather than relying on the interrupt,
and enabled this in loader.conf in EC2 images.

A decade later, this workaround is almost certainly no longer needed in
EC2 -- most instances don't run Xen, and the bug was long since fixed
in Xen anyway -- but we've been holding on to the workaround "just in
case".  Unfortunately, the spinwait behaviour is causing latency spikes
and triggering warnings from the ena(4) driver.

This commit removes the hw.broken_txfifo setting from loader.conf in
EC2 images, but leaves the loader tunable and associated code, since it
has been necessary in some other environments.  (It seems that the TX
FIFO missing-interrupts bug has been independently written at least
three times!)

Approved by:	re (cperciva)
MFC after:	1 minute
Sponsored by:	Amazon

(cherry picked from commit 9a685c09f0)
(cherry picked from commit eadda156a5)
2025-05-15 15:22:44 -07:00
Bjoern A. Zeeb 36174c38f9 LinuxKPI: 802.11: make sure AUTH frames are not being sent if BSS changed
iwlwifi keeps logging 'Invalid TXQ id' even after previous changes to
catch the BSS changed.  The reason for this is that we do not error in
the SCAN -> AUTH path as otherwise we would not have the state machine
get us back to SCAN to clear up firmware state before auth/assoc to the
new BSS.

If we are not in synch as net80211 just swapped the iv_bss from under us,
disable the TX queue for the (old) lsta to prevent the AUTH frame sent
from sta_newstate() reaching the driver.  After all we are not trying to
authenticate to that node (sta) anymore.

Sponsored by:	The FreeBSD Foundation
PR:		274382
Approved by:	re (cperciva)

(cherry picked from commit 16d987fe78)
(cherry picked from commit e0692e7bb6)
2025-05-15 19:13:58 +00:00
Justin Hibbits ac1943f97c powerpc: Always use BE tag in nexus_map_resource
7b5a5e4e replaced nexus_activate_resource() with the bus generic
equivalent, which uses bus_map_resource().  However, though not intended
to have a functional change, nexus_map_resource() uses the bus tag of
the build (BE vs LE), while nexus_activate_resource() always explicitly
set a big-endian tag, leading to failures on powerpc64le now.  Using BE
unless otherwise explicitly specified with the RF_LITTLEENDIAN fixes LE
on bare metal, and doesn't hurt in a VM, which nexus_map_resource() was
added for.

Reported by:	pkubaj
Tested by:	pkubaj
Fixes:		7b5a5e4e("powerpc nexus: Use bus_generic_rman_*")
MFC after:	1 day
Approved by:	re(cperciva)

(cherry picked from commit c4921a0faa)
(cherry picked from commit 45d585ab7f)
2025-05-15 09:06:51 -04:00
Dag-Erling Smørgrav 95223d920a bsdinstall: Use a login shell for final configuration.
If the user accepts our offer of a shell to perform final configuration
tasks before rebooting, start a login shell.  This ensures it will have
the correct PATH and be able to install packages without issues.

Approved by:	re (cperciva)
PR:		286722
MFC after:	3 days
Reviewed by:	jrtc27, allanjude, emaste
Differential Revision:	https://reviews.freebsd.org/D50297

(cherry picked from commit 5870d6a1ef)
(cherry picked from commit 242b52ba3c)
2025-05-14 20:08:15 +02:00
Christos Margiolis aff92a9f3c sound: Call PCM_RELEASE() if pcm_addchan() fails
Fixes:		fd906e47b1 ("sound: Simplify locking during device creation")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 day
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D50337

(cherry picked from commit dbfe79bbe5)
(cherry picked from commit 3de66f369c)

Approved by:    re (cperciva)
2025-05-14 16:23:53 +02:00
Olivier Certner 10944406be queue(3): Install *_SPLIT_AFTER() links to the main manual page
Completes commit "queue(3): New *_SPLIT_AFTER(), *_ASSERT_EMPTY(),
*_ASSERT_NONEMPTY()" (c028802339).

MFC after:      1 day
Sponsored by:   The FreeBSD Foundation

(cherry picked from commit c071616b06)
(cherry picked from commit eca0ce8afb)

Approved by:    re (cperciva)
2025-05-13 14:41:33 +02:00
Olivier Certner d156cabc0f sysctl.9: Constant integer example: Do not promote 'debug.sizeof'
Replace it with another one, selected from current in-tree uses.

MFC after:      1 day
Sponsored by:   The FreeBSD Foundation

(cherry picked from commit 129a6cf886)
(cherry picked from commit 1ca993dd45)

Approved by:    re (implicit)
2025-05-13 14:41:33 +02:00
Olivier Certner de6a4418ee sysctl(9): Ease exporting struct sizes; Discourage doing that
Introduce two helpers, the more general SYSCTL_SIZEOF() and
a struct-specific one SYSCTL_SIZEOF_STRUCT() which prepends 'struct' in
the description and in the use of sizeof() but uses the raw structure
name as the knob's name.  The size of the object/structure is exported
under 'debug.sizeof'.

Existing knobs under 'debug.sizeof' were all converted to use the
helpers.

Add a note before the helpers discouraging the introduction of new
leaves for ad-hoc reasons.  List alternative means for developers to
obtain the size of arbitrary kernel structures easily (thanks to markj@
for providing these).

No functional change (intended).

Reviewed by:    kib, markj
MFC after:      3 days
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50121

(cherry picked from commit 713abc9880)
(cherry picked from commit efce9f8a51)

Approved by:    re (cperciva)
2025-05-13 14:41:33 +02:00
Olivier Certner f7fa53cead stress2: exlock2.sh: Fix impact of previous '-U' removal
In commit "stress2: exlock2.sh: Preserve behavior after ps(1)'s '-U'
change" (1265d3b07e), I forgot that '-U' also has the side-effect of
implying '-x' by default.  Now that '-U' has been removed, make '-x'
explicit.

Fixes:          1265d3b07e ("stress2: exlock2.sh: Preserve behavior after ps(1)'s '-U' change")
MFC after:      1 hour
Sponsored by:   The FreeBSD Foundation

(cherry picked from commit f6e8268917)
(cherry picked from commit da6b04cd40)

Approved by:    re (implicit)
2025-05-13 14:41:33 +02:00
Olivier Certner 10e6bac460 stress2: exlock2.sh: Preserve behavior after ps(1)'s '-U' change
Remove '-Uroot', as now '-U' selects processes based on their real user
IDs, and since the program using them was launched as 'root', the
equivalent now is just to remove it, as now ps(1) by default selects
processes based on its effective UID (root) and their effective UIDs.

It seems that matching on effective or real UID does not really matter
in this test, but at least this change simplifies the command-line.

MFC after:      1 day
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50200

(cherry picked from commit 1265d3b07e)
(cherry picked from commit 5af18707c1)

Approved by:    re (cperciva)
2025-05-13 14:41:32 +02:00
Olivier Certner 2d5e13c86a rc/tests: Fix process flags checks using ps(1)
These checks use ps(1) with both the '-p' and '-a' flags, which worked
so far as ps(1)'s '-a' option was buggy.  Since the fix in commit
"ps(1): Make '-a' and '-A' always show all processes"
(93a94ce731), such a command-line always selects all processes,
making the specified '-p' useless and the test wrong.  Remove the
useless '-a'.

While here, remove the redundant '-x', as '-p' implies '-x' by default.

MFC after:      1 day
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50201

(cherry picked from commit 6463754087)
(cherry picked from commit a69fe62604)

Approved by:    re (cperciva)
2025-05-13 14:41:32 +02:00
Olivier Certner d5fff1aad5 ps.1: Remove ambiguity in description of option '-J'
As stated in the previous commit, option '-J' was introduced by commit
"Add -J to filter by matching jail IDs and names."
(13767130c7, r265229), which unfortunately talked about '-J'
being a filter while actually implementing it as a regular selection
option which adds to the processes to display.

The manual page's formulation hinted more at '-J' being a filter, which
it is not, or could be just considered ambiguous, because of the
presence of the "only" word.  Consequently, remove it and reformulate.

Reviewed by:    ziaee, dch
MFC after:      1 day
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50194

(cherry picked from commit cbda1aea65)
(cherry picked from commit 1586fd84fb)

Approved by:    re (cperciva)
2025-05-13 14:41:32 +02:00
Olivier Certner eed005b578 RELNOTES: ps(1): Document change in behavior for '-a'/'-A'
Document the practical consequence of change "ps(1): Make '-a' and '-A'
always show all processes" (93a94ce731) that specifying '-a'/'-A'
leads to printing all processes regardless of the presence of other
process selection options (except for '-x'/'-X', which command
a filter).

While here, mention a possible practical issue with '-J', as reported by
dch@.  This option was introduced by commit "Add -J to filter by
matching jail IDs and names." (13767130c7, r265229), which
unfortunately talked about '-J' being a filter while actually
implementing it as a regular selection option which adds to the
processes to display.

Reviewed by:    dch
MFC after:      1 day
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D50193

(cherry picked from commit 428200d2f0)

Commit hash edited on MFC.

(cherry picked from commit f18a49a747)

Approved by:    re (cperciva)
2025-05-13 14:41:26 +02:00
Warner Losh e79a3515c2 mpi3mr: Remove -g
This -g was introduce when I didn't review all the cahnges to mpi3mr I
was MFCing. Remove it. This is a direct commit.

PR: 249068
Fixes: 80b069913d
Sponsored by:		Netflix
Approved by:  re (cperciva)
(cherry picked from commit 22ebbdea3f)
2025-05-12 16:45:35 -06:00
Colin Percival 0e771ca261 release: Don't put drm-kmod package onto DVD
The X.Y-RELEASE DVDs use a quarterly package set which was built on
X.(Y-1)-RELEASE, and those kernel modules are never going to be
useful.

Approved by:	re (cperciva)
MFC after:	30 seconds
Sponsored by:	Amazon

(cherry picked from commit 94e44a074e)
(cherry picked from commit 1ecfdc0091)
2025-05-11 15:23:21 -07:00
Colin Percival a1874e9adf pkg-stage.sh: kde5 -> kde
The "kde5" package no longer exists; KDE goes to 6.

Note: Depending on the size of 13.5-BETA3 DVD images, KDE might end
up being removed from this list in the near future.

Approved by:	re (cperciva)
With hat:	re@
MFC after:	30 seconds
Sponsored by:	Amazon

(cherry picked from commit 0d7b98c06c)
(cherry picked from commit 1c2e947d27)
2025-05-11 15:23:14 -07:00
Colin Percival 0e80651662 14.3: Update to BETA2
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-09 00:00:00 +00:00
Bjoern A. Zeeb 8d6b758199 net80211: fix a race between ieee80211_sta_join and scan entries
We were seeing panics during ieee80211_sta_join() which seemed that
the ni->ni_chan was not valid anymore, which was true.
We also saw errors indicating data put into ni_ies became inalid.

The problem was that the ieee80211_scan_entry passed into
ieee80211_sta_join() (in the observed case from setmlme_assoc_sta())
became invalid during ieee80211_alloc_node().
As a result for the ni_chan case the the rateset and len in rates[1]
became invalid.  Similarly for the IEs.

Make a (deep)copy of the scan entry in setmlme_assoc_sta() and return
the copy as once we leave ieee80211_scan_iterate() we can no longer
rely on the scan entry to be valid.

Sponsored by:	The FreeBSD Foundation
Reported by:	rm, ziaee, bz
Tested by:	rm, ziaee, bz
PR:		286063
Approved by:	re (cperciva)
Reviewed by:	adrian (,emaste)
Differential Revision: https://reviews.freebsd.org/D49865

(cherry picked from commit aff56b4f0b)
(cherry picked from commit 34cd369186)
2025-05-08 21:22:59 +00:00
Bjoern A. Zeeb 873c0ea648 LinuxKPI: 802.11: header updates for mt76
Add more structs, fields, flags, defines.

Sponsored by:	The FreeBSD Foundation
Approved by:	re (cperciva)

(cherry picked from commit 675e6b1c68)
(cherry picked from commit 6a0dbc0a12)
2025-05-08 21:22:53 +00:00
Bjoern A. Zeeb 71946313d4 LinuxKPI: 802.11: fix wiphy_info[_once]
The dev field in wiphy is a pointer already; no need for &.

Sponsored by:	The FreeBSD Foundation
Fixes:		ac1d519c01
Approved by:	re (cperciva)

(cherry picked from commit 845b81cf90)
(cherry picked from commit a21addc7a0)
2025-05-08 21:22:35 +00:00
Xin LI 9679eedea9 MFV: xz 5.8.1.
PR:		bin/286252
Approved by:	re (cperciva)

(cherry picked from commit 128836d304)
(cherry picked from commit 5cf27a49a2)
2025-05-08 09:24:51 -07:00
Baptiste Daroussin b64d3fc884 nuageinit: implement chpasswd
Add support for chpasswd, with all possible syntaxes, including
deprecated one: chpasswd.list as a list or as a multiline string
as some providers are still only providing this deprecated form

Approved by:	 re (cperciva)
Sponsored by:	OVHCloud
MFC After:	1 week
Reviewed by:	kevans, jlduran
Differential Revision: 	https://reviews.freebsd.org/D50021

(cherry picked from commit c201a1198a)
(cherry picked from commit 6c91247003)
2025-05-08 15:08:55 +02:00
Mark Johnston f30669ba97 bpf: Make bpf.h self-contained
PR:		286539
MFC after:	3 days
Approved by:	re (cperciva)

(cherry picked from commit 981af1192c)
(cherry picked from commit 48881a2680)
2025-05-07 12:05:08 +00:00
Mark Johnston 399bc0c182 netinet: Make in_systm.h self-contained
PR:		286539
MFC after:	3 days
Approved by:	re (cperciva)

(cherry picked from commit 75d173a848)
(cherry picked from commit 02dde7c43f)
2025-05-07 12:04:59 +00:00
Michael Tuexen 976aa65e3e tcp: improve KASSERT in limited retransmit
When doing a limited retransmit, allow up to 2 * MSS - 1 if the
Nagle algorithm has been disabled.

PR:			282605
Approved by:		re (cperciva)
Reviewed by:		cc, Peter Lei
Sponsored by:		Netflix, Inc.
Differential Revision:	https://reviews.freebsd.org/D49922

(cherry picked from commit 934caaec3a)
(cherry picked from commit 0906658c34)
2025-05-06 21:18:24 +02:00
Michal Meloun c3ecee5b38 arm: remove accidentally added -Map switch to linker
Approved by:	re (cperciva)
Fixes:	ba045ba49d

(cherry picked from commit 0283eebb4a)
(cherry picked from commit 0aca1d4e7c)
2025-05-05 00:02:29 -07:00
Michal Meloun 95d87d5f56 arm: Improve the creation of kernel.bin
Instead of relinking the kernel without elf headers, replace them with
a binary blob of the same length starting with a jump to the kernel's start
address. This ensures that all symbols stay at the same offsets as in
the original kernel, so kernel.debug remains valid also for kernel.bin.

Also ensure that the awk script used runs with  the neutral locale defined.
Awk 'write' is a locale compilant, and  script is used to write binary data
to a file, so it needs to ensure that  bytes > 127 are written unchanged.

While I'm on, set the neutral locale also for arm64, where the same script is
used to generate the kernel booti image.

Reviewed by:	emaste, imp
Approved by:	re (cperciva)
Differential Revision:	https://reviews.freebsd.org/D47488

(cherry picked from commit ba045ba49d)
(cherry picked from commit bec5167645)
2025-05-05 00:01:44 -07:00
Rick Macklem 2773c07181 mountd: Fix updating the network/host(s) for an exports line
Mountd reloads the exports(5) file(s) when it receives a SIGHUP
and then compares the old and new exports, updating any ones that
have changed in the kernel.

Without this patch, mountd failed to recognize that a network/host(s)
had changed, if there was no other change to the exports line.
As such, the change of network/hosts(s) did not take effect until
the mountd daemon was (re)started.

This patch fixes the code so that it checks for changes in
the network/host(s) list for an exports line.

PR:	286260
Approved by:	re (cperciva)

(cherry picked from commit 68daa781c1)
(cherry picked from commit 37abcf06f2)
2025-05-04 12:13:49 -07:00
Mark Johnston 97a057f168 vm_pageout: Disallow invalid values for act_scan_laundry_weight
PR:		234167
MFC after:	2 weeks
Approved by:	re (cperciva)

(cherry picked from commit d8b03c5904)
(cherry picked from commit 098e4ecd65)
2025-05-03 20:22:08 +00:00
Colin Percival 3ce28e0624 14.3: create releng/14.3 branch
Update from PRERELEASE to BETA1
Switch pkg(8) configuration to use the quarterly repository
Bump __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	Amazon
2025-05-02 00:00:00 +00:00
178 changed files with 10426 additions and 3698 deletions

No files matched your search

+6
View File
@@ -51,6 +51,12 @@
# xargs -n1 | sort | uniq -d;
# done
# 20250524: don't install zoneinfo version
OLD_FILES+=usr/share/zoneinfo/version
# 20250521: NDFREE(9) -> NDFREE_PNBUF(9)
OLD_FILES+=usr/share/man/man9/NDFREE.9.gz
# 20250419: removal of iwlwifi firmware files
OLD_FILES+=usr/share/doc/legal/intel_iwlwifi_firmware.LICENCE
+17
View File
@@ -10,6 +10,23 @@ newline. Entries should be separated by a newline.
Changes to this file should not be MFCed.
1ee62f354ab0:
ps(1)'s options '-a' and '-A', when combined with any other one
affecting the selection of processes except for '-X' and '-x', would
have no effect, in contradiction with the rule that one process is
listed as soon as any of the specified options selects it (inclusive
OR), which is both mandated by POSIX and arguably a natural expectation.
This bug has been fixed.
As a practical consequence, specifying '-a'/'-A' now causes all
processes to be listed regardless of other selection options (except for
'-X' and '-x', which still apply). In particular, to list only
processes from specific jails, one must not use '-a' with '-J'. Option
'-J', contrary to its apparent initial intent, never worked as a filter
in practice (except by accident with '-a' due to the bug), but instead
as any other selection options (e.g., '-U', '-p', '-G', etc.) subject to
the "inclusive OR" rule.
a2132d91739d:
ps(1)'s '-U' option has been changed to select processes by their real
user IDs instead of their effective one, in accordance with POSIX and
+3
View File
@@ -12,6 +12,9 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
20250610:
14.3-RELEASE.
20250419:
LinuxKPI alloc routines were changed to return physically contiguous
memory where expected. These changes may require out-of-tree drivers
+2 -2
View File
@@ -35,7 +35,7 @@
.\"
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
.\"
.Dd April 28, 2025
.Dd May 06, 2025
.Dt PS 1
.Os
.Sh NAME
@@ -285,7 +285,7 @@ of the jail.
Use
.Fl J
.Sy 0
to display only host processes.
to request display of host processes.
Implies
.Fl x
by default.
@@ -25,7 +25,13 @@
# include <__locale_dir/locale_base_api/fuchsia.h>
#elif defined(__wasi__) || defined(_LIBCPP_HAS_MUSL_LIBC)
# include <__locale_dir/locale_base_api/musl.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#elif defined(__APPLE__)
# include <xlocale.h>
#elif defined(__FreeBSD__)
# if __has_feature(modules)
# include <stdio.h>
# include <stdlib.h>
# endif
# include <xlocale.h>
#endif
+1 -1
View File
@@ -24,7 +24,7 @@ Authors of XZ Utils
by Michał Górny.
Architecture-specific CRC optimizations were contributed by
Ilya Kurdyukov, Hans Jansen, and Chenxi Mao.
Ilya Kurdyukov, Chenxi Mao, and Xi Ruoyao.
Other authors:
- Jonathan Nieder
+6 -19
View File
@@ -40,6 +40,12 @@ XZ Utils Licensing
free software licenses. These aren't built or installed as
part of XZ Utils.
The following command may be helpful in finding per-file license
information. It works on xz.git and on a clean file tree extracted
from a release tarball.
sh build-aux/license-check.sh -v
For the files under the BSD Zero Clause License (0BSD), if
a copyright notice is needed, the following is sufficient:
@@ -59,25 +65,6 @@ XZ Utils Licensing
- COPYING.GPLv2: GNU General Public License version 2
- COPYING.GPLv3: GNU General Public License version 3
A note about old XZ Utils releases:
XZ Utils releases 5.4.6 and older and 5.5.1alpha have a
significant amount of code put into the public domain and
that obviously remains so. The switch from public domain to
0BSD for newer releases was made in Febrary 2024 because
public domain has (real or perceived) legal ambiguities in
some jurisdictions.
There is very little *practical* difference between public
domain and 0BSD. The main difference likely is that one
shouldn't claim that 0BSD-licensed code is in the public
domain; 0BSD-licensed code is copyrighted but available under
an extremely permissive license. Neither 0BSD nor public domain
require retaining or reproducing author, copyright holder, or
license notices when distributing the software. (Compare to,
for example, BSD 2-Clause "Simplified" License which does have
such requirements.)
If you have questions, don't hesitate to ask for more information.
The contact information is in the README file.
+4402 -921
View File
File diff suppressed because it is too large. Load diff
+37 -66
View File
@@ -10,6 +10,7 @@ XZ Utils
2. Version numbering
3. Reporting bugs
4. Translations
4.1. Testing translations
5. Other implementations of the .xz format
6. Contact information
@@ -203,77 +204,47 @@ XZ Utils
https://translationproject.org/html/translators.html
Below are notes and testing instructions specific to xz
translations.
Updates to translations won't be accepted by methods that bypass
the Translation Project because there is a risk of duplicate work:
translation updates made in the xz repository aren't seen by the
translators in the Translation Project. If you have found bugs in
a translation, please report them to the Language-Team address
which can be found near the beginning of the PO file.
Testing can be done by installing xz into a temporary directory:
If you find language problems in the original English strings,
feel free to suggest improvements. Ask if something is unclear.
4.1. Testing translations
Testing can be done by installing xz into a temporary directory.
If building from Git repository (not tarball), generate the
Autotools files:
./autogen.sh
Create a subdirectory for the build files. The tmp-build directory
can be deleted after testing.
mkdir tmp-build
cd tmp-build
../configure --disable-shared --enable-debug --prefix=$PWD/inst
Edit the .po file in the po directory. Then build and install to
the "tmp-build/inst" directory, and use translations.bash to see
how some of the messages look. Repeat these steps if needed:
./configure --disable-shared --prefix=/tmp/xz-test
# <Edit the .po file in the po directory.>
make -C po update-po
make install
bash debug/translation.bash | less
bash debug/translation.bash | less -S # For --list outputs
make -j"$(nproc)" install
bash ../debug/translation.bash | less
bash ../debug/translation.bash | less -S # For --list outputs
Repeat the above as needed (no need to re-run configure though).
To test other languages, set the LANGUAGE environment variable
before running translations.bash. The value should match the PO file
name without the .po suffix. Example:
Note especially the following:
- The output of --help and --long-help must look nice on
an 80-column terminal. It's OK to add extra lines if needed.
- In contrast, don't add extra lines to error messages and such.
They are often preceded with e.g. a filename on the same line,
so you have no way to predict where to put a \n. Let the terminal
do the wrapping even if it looks ugly. Adding new lines will be
even uglier in the generic case even if it looks nice in a few
limited examples.
- Be careful with column alignment in tables and table-like output
(--list, --list --verbose --verbose, --info-memory, --help, and
--long-help):
* All descriptions of options in --help should start in the
same column (but it doesn't need to be the same column as
in the English messages; just be consistent if you change it).
Check that both --help and --long-help look OK, since they
share several strings.
* --list --verbose and --info-memory print lines that have
the format "Description: %s". If you need a longer
description, you can put extra space between the colon
and %s. Then you may need to add extra space to other
strings too so that the result as a whole looks good (all
values start at the same column).
* The columns of the actual tables in --list --verbose --verbose
should be aligned properly. Abbreviate if necessary. It might
be good to keep at least 2 or 3 spaces between column headings
and avoid spaces in the headings so that the columns stand out
better, but this is a matter of opinion. Do what you think
looks best.
- Be careful to put a period at the end of a sentence when the
original version has it, and don't put it when the original
doesn't have it. Similarly, be careful with \n characters
at the beginning and end of the strings.
- Read the TRANSLATORS comments that have been extracted from the
source code and included in xz.pot. Some comments suggest
testing with a specific command which needs an .xz file. You
may use e.g. any tests/files/good-*.xz. However, these test
commands are included in translations.bash output, so reading
translations.bash output carefully can be enough.
- If you find language problems in the original English strings,
feel free to suggest improvements. Ask if something is unclear.
- The translated messages should be understandable (sometimes this
may be a problem with the original English messages too). Don't
make a direct word-by-word translation from English especially if
the result doesn't sound good in your language.
Thanks for your help!
export LANGUAGE=fi
5. Other implementations of the .xz format
+37
View File
@@ -20,6 +20,7 @@ has been important. :-) In alphabetical order:
- Jakub Bogusz
- Adam Borowski
- Maarten Bosmans
- Roel Bouckaert
- Lukas Braune
- Benjamin Buch
- Trent W. Buck
@@ -29,26 +30,35 @@ has been important. :-) In alphabetical order:
- Frank Busse
- Daniel Mealha Cabrita
- Milo Casagrande
- Cristiano Ceglia
- Marek Černocký
- Tomer Chachamu
- Vitaly Chikunov
- Antoine Cœur
- Elijah Almeida Coimbra
- Felix Collin
- Ryan Colyer
- Marcus Comstedt
- Vincent Cruz
- Gabi Davar
- Ron Desmond
- İhsan Doğan
- Chris Donawa
- Andrew Dudman
- Markus Duft
- İsmail Dönmez
- Dexter Castor Döpping
- Paul Eggert
- Robert Elz
- Gilles Espinasse
- Denis Excoffier
- Vincent Fazio
- Michael Felt
- Sean Fenian
- Michael Fox
- Andres Freund
- Mike Frysinger
- Collin Funk
- Daniel Richard G.
- Tomasz Gajc
- Bjarni Ingi Gislason
@@ -57,10 +67,14 @@ has been important. :-) In alphabetical order:
- Matthew Good
- Michał Górny
- Jason Gorski
- Alexander M. Greenham
- Juan Manuel Guerrero
- Gabriela Gutierrez
- Diederik de Haas
- Jan Terje Hansen
- Tobias Lahrmann Hansen
- Joachim Henke
- Lizandro Heredia
- Christian Hesse
- Vincenzo Innocente
- Peter Ivanov
@@ -76,9 +90,11 @@ has been important. :-) In alphabetical order:
- Per Øyvind Karlsen
- Firas Khalil Khana
- Iouri Kharon
- Kim Jinyeong
- Thomas Klausner
- Richard Koch
- Anton Kochkov
- Harri K. Koskinen
- Ville Koskinen
- Sergey Kosukhin
- Marcin Kowalczyk
@@ -103,14 +119,20 @@ has been important. :-) In alphabetical order:
- Chenxi Mao
- Gregory Margo
- Julien Marrec
- Pierre-Yves Martin
- Ed Maste
- Martin Matuška
- Scott McAllister
- Chris McCrohan
- Derwin McGeary
- Ivan A. Melnikov
- Jim Meyering
- Arkadiusz Miskiewicz
- Nathan Moinvaziri
- Étienne Mollier
- Conley Moorhous
- Dirk Müller
- Rainer Müller
- Andrew Murray
- Rafał Mużyło
- Adrien Nader
@@ -118,28 +140,34 @@ has been important. :-) In alphabetical order:
- Alexander Neumann
- Hongbo Ni
- Jonathan Nieder
- Asgeir Storesund Nilsen
- Andre Noll
- Ruarí Ødegaard
- Peter O'Gorman
- Dimitri Papadopoulos Orfanos
- Daniel Packard
- Filip Palian
- Peter Pallinger
- Kai Pastor
- Keith Patton
- Rui Paulo
- Igor Pavlov
- Diego Elio Pettenò
- Elbert Pol
- Guiorgy Potskhishvili
- Mikko Pouru
- Frank Prochnow
- Rich Prohaska
- Trần Ngọc Quân
- Pavel Raiskup
- Matthieu Rakotojaona
- Ole André Vadla Ravnås
- Eric S. Raymond
- Robert Readman
- Bernhard Reutner-Fischer
- Markus Rickert
- Cristian Rodríguez
- Jeroen Roovers
- Christian von Roques
- Boud Roukema
- Torsten Rupp
@@ -156,6 +184,7 @@ has been important. :-) In alphabetical order:
- Dan Shechter
- Stuart Shelton
- Sebastian Andrzej Siewior
- Andrej Skenderija
- Ville Skyttä
- Brad Smith
- Bruce Stark
@@ -181,20 +210,28 @@ has been important. :-) In alphabetical order:
- Christian Weisgerber
- Dan Weiss
- Bert Wesarg
- Mark Wielaard
- Fredrik Wikstrom
- Jim Wilcoxson
- Ralf Wildenhues
- Charles Wilson
- Lars Wirzenius
- Vincent Wixsom
- Pilorz Wojciech
- Chien Wong
- Xi Ruoyao
- Ryan Young
- Andreas Zieringer
- 榆柳松 (ZhengSen Wang)
Companies:
- Google
- Sandfly Security
Other credits:
- cleemy desu wayo working with Trend Micro Zero Day Initiative
- Orange Tsai and splitline from DEVCORE Research Team
Also thanks to all the people who have participated in the Tukaani project.
I have probably forgot to add some names to the above list. Sorry about
+4 -21
View File
@@ -5,12 +5,7 @@ XZ Utils To-Do List
Known bugs
----------
The test suite is too incomplete.
If the memory usage limit is less than about 13 MiB, xz is unable to
automatically scale down the compression settings enough even though
it would be possible by switching from BT2/BT3/BT4 match finder to
HC3/HC4.
The test suite is incomplete.
XZ Utils compress some files significantly worse than LZMA Utils.
This is due to faster compression presets used by XZ Utils, and
@@ -19,9 +14,6 @@ Known bugs
compress extremely well, so going from compression ratio of 0.003
to 0.004 means big relative increase in the compressed file size.
xz doesn't quote unprintable characters when it displays file names
given on the command line.
tuklib_exit() doesn't block signals => EINTR is possible.
If liblzma has created threads and fork() gets called, liblzma
@@ -41,9 +33,6 @@ Missing features
be mostly useful when using a preset dictionary in LZMA2, but
it may have other uses too. Compare to deflateCopy() in zlib.
Support LZMA_FINISH in raw decoder to indicate end of LZMA1 and
other streams that don't have an end of payload marker.
Adjust dictionary size when the input file size is known.
Maybe do this only if an option is given.
@@ -67,9 +56,9 @@ Missing features
Support LZMA_FULL_FLUSH for lzma_stream_decoder() to stop at
Block and Stream boundaries.
lzma_strerror() to convert lzma_ret to human readable form?
This is tricky, because the same error codes are used with
slightly different meanings, and this cannot be fixed anymore.
Error codes from lzma_code() aren't very specific. A more detailed
error message (string) could be provided too. It could be returned
by a new function or use a currently-reserved member of lzma_stream.
Make it possible to adjust LZMA2 options in the middle of a Block
so that the encoding speed vs. compression ratio can be optimized
@@ -97,9 +86,3 @@ Documentation
Document the LZMA1 and LZMA2 algorithms.
Miscellaneous
------------
Try to get the media type for .xz registered at IANA.
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file my_landlock.h
/// \brief Linux Landlock sandbox helper functions
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#ifndef MY_LANDLOCK_H
#define MY_LANDLOCK_H
#include "sysdefs.h"
#include <linux/landlock.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
/// \brief Initialize Landlock ruleset attributes to forbid everything
///
/// The supported Landlock ABI is checked at runtime and only the supported
/// actions are forbidden in the attributes. Thus, if the attributes are
/// used with my_landlock_create_ruleset(), it shouldn't fail.
///
/// \return On success, the Landlock ABI version is returned (a positive
/// integer). If Landlock isn't supported, -1 is returned.
static int
my_landlock_ruleset_attr_forbid_all(struct landlock_ruleset_attr *attr)
{
memzero(attr, sizeof(*attr));
const int abi_version = syscall(SYS_landlock_create_ruleset,
(void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi_version <= 0)
return -1;
// ABI 1 except the few at the end
attr->handled_access_fs
= LANDLOCK_ACCESS_FS_EXECUTE
| LANDLOCK_ACCESS_FS_WRITE_FILE
| LANDLOCK_ACCESS_FS_READ_FILE
| LANDLOCK_ACCESS_FS_READ_DIR
| LANDLOCK_ACCESS_FS_REMOVE_DIR
| LANDLOCK_ACCESS_FS_REMOVE_FILE
| LANDLOCK_ACCESS_FS_MAKE_CHAR
| LANDLOCK_ACCESS_FS_MAKE_DIR
| LANDLOCK_ACCESS_FS_MAKE_REG
| LANDLOCK_ACCESS_FS_MAKE_SOCK
| LANDLOCK_ACCESS_FS_MAKE_FIFO
| LANDLOCK_ACCESS_FS_MAKE_BLOCK
| LANDLOCK_ACCESS_FS_MAKE_SYM
#ifdef LANDLOCK_ACCESS_FS_REFER
| LANDLOCK_ACCESS_FS_REFER // ABI 2
#endif
#ifdef LANDLOCK_ACCESS_FS_TRUNCATE
| LANDLOCK_ACCESS_FS_TRUNCATE // ABI 3
#endif
#ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV
| LANDLOCK_ACCESS_FS_IOCTL_DEV // ABI 5
#endif
;
#ifdef LANDLOCK_ACCESS_NET_BIND_TCP
// ABI 4
attr->handled_access_net
= LANDLOCK_ACCESS_NET_BIND_TCP
| LANDLOCK_ACCESS_NET_CONNECT_TCP;
#endif
#ifdef LANDLOCK_SCOPE_SIGNAL
// ABI 6
attr->scoped
= LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
| LANDLOCK_SCOPE_SIGNAL;
#endif
// Disable flags that require a new ABI version.
switch (abi_version) {
case 1:
#ifdef LANDLOCK_ACCESS_FS_REFER
attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
#endif
FALLTHROUGH;
case 2:
#ifdef LANDLOCK_ACCESS_FS_TRUNCATE
attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
#endif
FALLTHROUGH;
case 3:
#ifdef LANDLOCK_ACCESS_NET_BIND_TCP
attr->handled_access_net = 0;
#endif
FALLTHROUGH;
case 4:
#ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV
attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
#endif
FALLTHROUGH;
case 5:
#ifdef LANDLOCK_SCOPE_SIGNAL
attr->scoped = 0;
#endif
FALLTHROUGH;
default:
// We only know about the features of the ABIs 1-6.
break;
}
return abi_version;
}
/// \brief Wrapper for the landlock_create_ruleset(2) syscall
///
/// Syscall wrappers provide argument type checking.
///
/// \note Remember to call `prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)` too!
static inline int
my_landlock_create_ruleset(const struct landlock_ruleset_attr *attr,
size_t size, uint32_t flags)
{
return syscall(SYS_landlock_create_ruleset, attr, size, flags);
}
/// \brief Wrapper for the landlock_restrict_self(2) syscall
static inline int
my_landlock_restrict_self(int ruleset_fd, uint32_t flags)
{
return syscall(SYS_landlock_restrict_self, ruleset_fd, flags);
}
#endif
+44 -14
View File
@@ -23,17 +23,29 @@
# include <config.h>
#endif
// This #define ensures that C99 and POSIX compliant stdio functions are
// available with MinGW-w64 (both 32-bit and 64-bit). Modern MinGW-w64 adds
// this automatically, for example, when the compiler is in C99 (or later)
// mode when building against msvcrt.dll. It still doesn't hurt to be explicit
// that we always want this and #define this unconditionally.
// Choose if MinGW-w64's stdio replacement functions should be used.
// The default has varied slightly in the past so it's clearest to always
// set it explicitly.
//
// With Universal CRT (UCRT) this is less important because UCRT contains
// C99-compatible stdio functions. It's still nice to #define this as UCRT
// doesn't support the POSIX thousand separator flag in printf (like "%'u").
#ifdef __MINGW32__
// Modern MinGW-w64 enables the replacement functions even with UCRT
// when _GNU_SOURCE is defined. That's good because UCRT doesn't support
// the POSIX thousand separator flag in printf (like "%'u"). Otherwise
// XZ Utils works with the UCRT stdio functions.
//
// The replacement functions add over 20 KiB to each executable. For
// size-optimized builds (HAVE_SMALL), disable the replacements.
// Then thousand separators aren't shown in xz's messages but this is
// a minor downside compare to the slower speed of the HAVE_SMALL builds.
//
// The legacy MSVCRT is pre-C99 and it's best to always use the stdio
// replacements functions from MinGW-w64.
#if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
# define __USE_MINGW_ANSI_STDIO 1
# include <_mingw.h>
# if defined(_UCRT) && defined(HAVE_SMALL)
# undef __USE_MINGW_ANSI_STDIO
# define __USE_MINGW_ANSI_STDIO 0
# endif
#endif
// size_t and NULL
@@ -156,17 +168,26 @@ typedef unsigned char _Bool;
# define __bool_true_false_are_defined 1
#endif
// We may need alignas from C11/C17/C23.
#if __STDC_VERSION__ >= 202311
// alignas is a keyword in C23. Do nothing.
#elif __STDC_VERSION__ >= 201112
// Oracle Developer Studio 12.6 lacks <stdalign.h>.
// For simplicity, avoid the header with all C11/C17 compilers.
# define alignas _Alignas
#elif defined(__GNUC__) || defined(__clang__)
# define alignas(n) __attribute__((__aligned__(n)))
#else
# define alignas(n)
#endif
#include <string.h>
// Visual Studio 2013 update 2 supports only __inline, not inline.
// MSVC v19.0 / VS 2015 and newer support both.
// MSVC v19.00 (VS 2015 version 14.0) and later should work.
//
// MSVC v19.27 (VS 2019 version 16.7) added support for restrict.
// Older ones support only __restrict.
#ifdef _MSC_VER
# if _MSC_VER < 1900 && !defined(inline)
# define inline __inline
# endif
# if _MSC_VER < 1927 && !defined(restrict)
# define restrict __restrict
# endif
@@ -196,4 +217,13 @@ typedef unsigned char _Bool;
# define lzma_attr_alloc_size(x)
#endif
#if __STDC_VERSION__ >= 202311
# define FALLTHROUGH [[__fallthrough__]]
#elif (defined(__GNUC__) && __GNUC__ >= 7) \
|| (defined(__clang_major__) && __clang_major__ >= 10)
# define FALLTHROUGH __attribute__((__fallthrough__))
#else
# define FALLTHROUGH ((void)0)
#endif
#endif
+8 -3
View File
@@ -56,6 +56,13 @@
# define TUKLIB_GNUC_REQ(major, minor) 0
#endif
#if defined(__GNUC__) || defined(__clang__)
# define tuklib_attr_format_printf(fmt_index, args_index) \
__attribute__((__format__(__printf__, fmt_index, args_index)))
#else
# define tuklib_attr_format_printf(fmt_index, args_index)
#endif
// tuklib_attr_noreturn attribute is used to mark functions as non-returning.
// We cannot use "noreturn" as the macro name because then C23 code that
// uses [[noreturn]] would break as it would expand to [[ [[noreturn]] ]].
@@ -68,9 +75,7 @@
// __attribute__((nonnull(1)))
// extern void foo(const char *s);
//
// FIXME: Update __STDC_VERSION__ for the final C23 version. 202000 is used
// by GCC 13 and Clang 15 with -std=c2x.
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311
# define tuklib_attr_noreturn [[noreturn]]
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112
# define tuklib_attr_noreturn _Noreturn
+11
View File
@@ -40,4 +40,15 @@
#endif
#define N_(msgid) msgid
// Optional: Strings that are word wrapped using tuklib_mbstr_wrap may be
// marked with W_("foo) in the source code. xgettext can then add a comment
// to all such strings to inform translators. The following option needs to
// be added to XGETTEXT_OPTIONS in po/Makevars or in an equivalent place:
//
// '--keyword=W_:1,"This is word wrapped at spaces. The Unicode character U+00A0 works as a non-breaking space. Tab (\t) is interpret as a zero-width space (the tab itself is not displayed); U+200B is NOT supported. Manual word wrapping with \n is supported but requires care."'
//
// NOTE: The double-quotes in the --keyword argument above must be passed to
// xgettext as is, thus one needs the single-quotes in Makevars.
#define W_(msgid) _(msgid)
#endif
+19 -6
View File
@@ -27,10 +27,7 @@ extern size_t tuklib_mbstr_width(const char *str, size_t *bytes);
///
/// This is somewhat similar to wcswidth() but works on multibyte strings.
///
/// \param str String whose width is to be calculated. If the
/// current locale uses a multibyte character set
/// that has shift states, the string must begin
/// and end in the initial shift state.
/// \param str String whose width is to be calculated.
/// \param bytes If this is not NULL, *bytes is set to the
/// value returned by strlen(str) (even if an
/// error occurs when calculating the width).
@@ -38,8 +35,24 @@ extern size_t tuklib_mbstr_width(const char *str, size_t *bytes);
/// \return On success, the number of columns needed to display the
/// string e.g. in a terminal emulator is returned. On error,
/// (size_t)-1 is returned. Possible errors include invalid,
/// partial, or non-printable multibyte character in str, or
/// that str doesn't end in the initial shift state.
/// partial, or non-printable multibyte character in str.
#define tuklib_mbstr_width_mem TUKLIB_SYMBOL(tuklib_mbstr_width_mem)
extern size_t tuklib_mbstr_width_mem(const char *str, size_t len);
///<
/// \brief Get the number of columns needed for the multibyte buffer
///
/// This is like tuklib_mbstr_width() except that this takes the buffer
/// length in bytes as the second argument. This allows using the function
/// for buffers that aren't terminated with '\0'.
///
/// \param str String whose width is to be calculated.
/// \param len Number of bytes to read from str.
///
/// \return On success, the number of columns needed to display the
/// string e.g. in a terminal emulator is returned. On error,
/// (size_t)-1 is returned. Possible errors include invalid,
/// partial, or non-printable multibyte character in str.
#define tuklib_mbstr_fw TUKLIB_SYMBOL(tuklib_mbstr_fw)
extern int tuklib_mbstr_fw(const char *str, int columns_min);
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file tuklib_mbstr_nonprint.c
/// \brief Find and replace non-printable characters with question marks
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include "tuklib_mbstr_nonprint.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_MBRTOWC
# include <wchar.h>
# include <wctype.h>
#else
# include <ctype.h>
#endif
static bool
is_next_printable(const char *str, size_t len, size_t *next_len)
{
#ifdef HAVE_MBRTOWC
// This assumes that character sets with locking shift states aren't
// used, and thus mbsinit() is never needed.
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
wchar_t wc;
*next_len = mbrtowc(&wc, str, len, &ps);
if (*next_len == (size_t)-2) {
// Incomplete multibyte sequence: Treat the whole sequence
// as a single non-printable multibyte character that ends
// the string.
*next_len = len;
return false;
}
// Check more broadly than just ret == (size_t)-1 to be safe
// in case mbrtowc() returns something weird. This check
// covers (size_t)-1 (that is, SIZE_MAX) too because len is from
// strlen() and the terminating '\0' isn't part of the length.
if (*next_len < 1 || *next_len > len) {
// Invalid multibyte sequence: Treat the first byte as
// a non-printable single-byte character. Decoding will
// be restarted from the next byte on the next call to
// this function.
*next_len = 1;
return false;
}
# if defined(_WIN32) && !defined(__CYGWIN__)
// On Windows, wchar_t stores UTF-16 code units, thus characters
// outside the Basic Multilingual Plane (BMP) don't fit into
// a single wchar_t. In an UTF-8 locale, UCRT's mbrtowc() returns
// successfully when the input is a non-BMP character but the
// output is the replacement character U+FFFD.
//
// iswprint() returns 0 for U+FFFD on Windows for some reason. Treat
// U+FFFD as printable and thus also all non-BMP chars as printable.
if (wc == 0xFFFD)
return true;
# endif
return iswprint((wint_t)wc) != 0;
#else
(void)len;
*next_len = 1;
return isprint((unsigned char)str[0]) != 0;
#endif
}
static bool
has_nonprint(const char *str, size_t len)
{
for (size_t i = 0; i < len; ) {
size_t next_len;
if (!is_next_printable(str + i, len - i, &next_len))
return true;
i += next_len;
}
return false;
}
extern bool
tuklib_has_nonprint(const char *str)
{
const int saved_errno = errno;
const bool ret = has_nonprint(str, strlen(str));
errno = saved_errno;
return ret;
}
extern const char *
tuklib_mask_nonprint_r(const char *str, char **mem)
{
const int saved_errno = errno;
// Free the old string, if any.
free(*mem);
*mem = NULL;
// If the whole input string contains only printable characters,
// return the input string.
const size_t len = strlen(str);
if (!has_nonprint(str, len)) {
errno = saved_errno;
return str;
}
// Allocate memory for the masked string. Since we use the single-byte
// character '?' to mask non-printable characters, it's possible that
// a few bytes less memory would be needed in reality if multibyte
// characters are masked.
//
// If allocation fails, return "???" because it should be safer than
// returning the unmasked string.
*mem = malloc(len + 1);
if (*mem == NULL) {
errno = saved_errno;
return "???";
}
// Replace all non-printable characters with '?'.
char *dest = *mem;
for (size_t i = 0; i < len; ) {
size_t next_len;
if (is_next_printable(str + i, len - i, &next_len)) {
memcpy(dest, str + i, next_len);
dest += next_len;
} else {
*dest++ = '?';
}
i += next_len;
}
*dest = '\0';
errno = saved_errno;
return *mem;
}
extern const char *
tuklib_mask_nonprint(const char *str)
{
static char *mem = NULL;
return tuklib_mask_nonprint_r(str, &mem);
}
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file tuklib_mbstr_nonprint.h
/// \brief Find and replace non-printable characters with question marks
///
/// If mbrtowc(3) is available, it and iswprint(3) is used to check if all
/// characters are printable. Otherwise single-byte character set is assumed
/// and isprint(3) is used.
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#ifndef TUKLIB_MBSTR_NONPRINT_H
#define TUKLIB_MBSTR_NONPRINT_H
#include "tuklib_common.h"
TUKLIB_DECLS_BEGIN
#define tuklib_has_nonprint TUKLIB_SYMBOL(tuklib_has_nonprint)
extern bool tuklib_has_nonprint(const char *str);
///<
/// \brief Check if a string contains any non-printable characters
///
/// \return false if str contains only valid multibyte characters and
/// iswprint(3) returns non-zero for all of them; true otherwise.
/// The value of errno is preserved.
///
/// \note In case mbrtowc(3) isn't available, single-byte character set
/// is assumed and isprint(3) is used instead of iswprint(3).
#define tuklib_mask_nonprint_r TUKLIB_SYMBOL(tuklib_mask_nonprint_r)
extern const char *tuklib_mask_nonprint_r(const char *str, char **mem);
///<
/// \brief Replace non-printable characters with question marks
///
/// \param str Untrusted string, for example, a filename
/// \param mem This function always calls free(*mem) to free the old
/// allocation and then sets *mem = NULL. Before the first
/// call, *mem should be initialized to NULL. If this
/// function needs to allocate memory for a modified
/// string, a pointer to the allocated memory will be
/// stored to *mem. Otherwise *mem will remain NULL.
///
/// \return If tuklib_has_nonprint(str) returns false, this function
/// returns str. Otherwise memory is allocated to hold a modified
/// string and a pointer to that is returned. The pointer to the
/// allocated memory is also stored to *mem. A modified string
/// has the problematic characters replaced by '?'. If memory
/// allocation fails, "???" is returned and *mem is NULL.
/// The value of errno is preserved.
#define tuklib_mask_nonprint TUKLIB_SYMBOL(tuklib_mask_nonprint)
extern const char *tuklib_mask_nonprint(const char *str);
///<
/// \brief Replace non-printable characters with question marks
///
/// This is a convenience function for single-threaded use. This calls
/// tuklib_mask_nonprint_r() using an internal static variable to hold
/// the possible allocation.
///
/// \param str Untrusted string, for example, a filename
///
/// \return See tuklib_mask_nonprint_r().
///
/// \note This function is not thread safe!
TUKLIB_DECLS_END
#endif
+28 -6
View File
@@ -12,7 +12,7 @@
#include "tuklib_mbstr.h"
#include <string.h>
#if defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
#ifdef HAVE_MBRTOWC
# include <wchar.h>
#endif
@@ -24,9 +24,17 @@ tuklib_mbstr_width(const char *str, size_t *bytes)
if (bytes != NULL)
*bytes = len;
#if !(defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH))
return tuklib_mbstr_width_mem(str, len);
}
extern size_t
tuklib_mbstr_width_mem(const char *str, size_t len)
{
#ifndef HAVE_MBRTOWC
// In single-byte mode, the width of the string is the same
// as its length.
(void)str;
return len;
#else
@@ -41,21 +49,35 @@ tuklib_mbstr_width(const char *str, size_t *bytes)
while (i < len) {
wchar_t wc;
const size_t ret = mbrtowc(&wc, str + i, len - i, &state);
if (ret < 1 || ret > len)
if (ret < 1 || ret > len - i)
return (size_t)-1;
i += ret;
#ifdef HAVE_WCWIDTH
const int wc_width = wcwidth(wc);
if (wc_width < 0)
return (size_t)-1;
width += (size_t)wc_width;
#else
// Without wcwidth() (like in a native Windows build),
// assume that one multibyte char == one column. With
// UTF-8, this is less bad than one byte == one column.
// This way quite a few languages will be handled correctly
// in practice; CJK chars will be very wrong though.
++width;
#endif
}
// Require that the string ends in the initial shift state.
// This way the caller can be combine the string with other
// strings without needing to worry about the shift states.
// It's good to check that the string ended in the initial state.
// However, in practice this is redundant:
//
// - No one will use this code with character sets that have
// locking shift states.
//
// - We already checked that mbrtowc() didn't return (size_t)-2
// which would indicate a partial multibyte character.
if (!mbsinit(&state))
return (size_t)-1;
+294
View File
@@ -0,0 +1,294 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file tuklib_mbstr_wrap.c
/// \brief Word wraps a string and prints it to a FILE stream
///
/// This depends on tuklib_mbstr_width.c.
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include "tuklib_mbstr.h"
#include "tuklib_mbstr_wrap.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern int
tuklib_wraps(FILE *outfile, const struct tuklib_wrap_opt *opt, const char *str)
{
// left_cont may be less than left_margin. In that case, if the first
// word is extremely long, it will stay on the first line even if
// the line then gets overlong.
//
// On the other hand, left2_cont < left2_margin isn't allowed because
// it could result in inconsistent behavior when a very long word
// comes right after a \v.
//
// It is fine to have left2_margin < left_margin although it would be
// an odd use case.
if (!(opt->left_margin < opt->right_margin
&& opt->left_cont < opt->right_margin
&& opt->left2_margin <= opt->left2_cont
&& opt->left2_cont < opt->right_margin))
return TUKLIB_WRAP_ERR_OPT;
// This is set to TUKLIB_WRAP_WARN_OVERLONG if one or more
// output lines extend past opt->right_margin columns.
int warn_overlong = 0;
// Indentation of the first output line after \n or \r.
// \v sets this to opt->left2_margin.
// \r resets this back to the original value.
size_t first_indent = opt->left_margin;
// Indentation of the output lines that occur due to word wrapping.
// \v sets this to opt->left2_cont and \r back to the original value.
size_t cont_indent = opt->left_cont;
// If word wrapping occurs, the newline isn't printed unless more
// text would be put on the continuation line. This is also used
// when \v needs to start on a new line.
bool pending_newline = false;
// Spaces are printed only when there is something else to put
// after the spaces on the line. This avoids unwanted empty lines
// in the output and makes it possible to ignore possible spaces
// before a \v character.
size_t pending_spaces = first_indent;
// Current output column. When cur_col == pending_spaces, nothing
// has been actually printed to the current output line.
size_t cur_col = pending_spaces;
while (true) {
// Number of bytes until the *next* line-break opportunity.
size_t len = 0;
// Number of columns until the *next* line-break opportunity.
size_t width = 0;
// Text between a pair of \b characters is treated as
// an unbreakable block even if it contains spaces.
// It must not contain any control characters before
// the closing \b.
bool unbreakable = false;
while (true) {
// Find the next character that we handle specially.
// In an unbreakable block, search only for the
// closing \b; if missing, the unbreakable block
// extends to the end of the string.
const size_t n = strcspn(str + len,
unbreakable ? "\b" : " \t\n\r\v\b");
// Calculate how many columns the characters need.
const size_t w = tuklib_mbstr_width_mem(str + len, n);
if (w == (size_t)-1)
return TUKLIB_WRAP_ERR_STR;
width += w;
len += n;
// \b isn't a line-break opportunity so it has to
// be handled here. For simplicity, empty blocks
// are treated as zero-width characters.
if (str[len] == '\b') {
++len;
unbreakable = !unbreakable;
continue;
}
break;
}
// Determine if adding this chunk of text would make the
// current output line exceed opt->right_margin columns.
const bool too_long = cur_col + width > opt->right_margin;
// Wrap the line if needed. However:
//
// - Don't wrap if the current column is less than where
// the continuation line would begin. In that case
// the chunk wouldn't fit on the next line either so
// we just have to produce an overlong line.
//
// - Don't wrap if so far the line only contains spaces.
// Wrapping in that case would leave a weird empty line.
// NOTE: This "only contains spaces" condition is the
// reason why left2_margin > left2_cont isn't allowed.
if (too_long && cur_col > cont_indent
&& cur_col > pending_spaces) {
// There might be trailing spaces or zero-width spaces
// which need to be ignored to keep the output pretty.
//
// Spaces need to be ignored because in some
// writing styles there are two spaces after
// a full stop. Example string:
//
// "Foo bar. Abc def."
// ^
// If the first space after the first full stop
// triggers word wrapping, both spaces must be
// ignored. Otherwise the next line would be
// indented too much.
//
// Zero-width spaces are ignored the same way
// because they are meaningless if an adjacent
// character is a space.
while (*str == ' ' || *str == '\t')
++str;
// Don't print the newline here; only mark it as
// pending. This avoids an unwanted empty line if
// there is a \n or \r or \0 after the spaces have
// been ignored.
pending_newline = true;
pending_spaces = cont_indent;
cur_col = pending_spaces;
// Since str may have been incremented due to the
// ignored spaces, the loop needs to be restarted.
continue;
}
// Print the current chunk of text before the next
// line-break opportunity. If the chunk was empty,
// don't print anything so that the pending newline
// and pending spaces aren't printed on their own.
if (len > 0) {
if (pending_newline) {
pending_newline = false;
if (putc('\n', outfile) == EOF)
return TUKLIB_WRAP_ERR_IO;
}
while (pending_spaces > 0) {
if (putc(' ', outfile) == EOF)
return TUKLIB_WRAP_ERR_IO;
--pending_spaces;
}
for (size_t i = 0; i < len; ++i) {
// Ignore unbreakable block characters (\b).
const int c = (unsigned char)str[i];
if (c != '\b' && putc(c, outfile) == EOF)
return TUKLIB_WRAP_ERR_IO;
}
str += len;
cur_col += width;
// Remember if the line got overlong. If no other
// errors occur, we return warn_overlong. It might
// help in catching problematic strings.
if (too_long)
warn_overlong = TUKLIB_WRAP_WARN_OVERLONG;
}
// Handle the special character after the chunk of text.
switch (*str) {
case ' ':
// Regular space.
++cur_col;
++pending_spaces;
break;
case '\v':
// Set the alternative indentation settings.
first_indent = opt->left2_margin;
cont_indent = opt->left2_cont;
if (first_indent > cur_col) {
// Add one or more spaces to reach
// the column specified in first_indent.
pending_spaces += first_indent - cur_col;
} else {
// There is no room to add even one space
// before reaching the column first_indent.
pending_newline = true;
pending_spaces = first_indent;
}
cur_col = first_indent;
break;
case '\0': // Implicit newline at the end of the string.
case '\r': // Newline that also resets the effect of \v.
case '\n': // Newline without resetting the indentation mode.
if (putc('\n', outfile) == EOF)
return TUKLIB_WRAP_ERR_IO;
if (*str == '\0')
return warn_overlong;
if (*str == '\r') {
first_indent = opt->left_margin;
cont_indent = opt->left_cont;
}
pending_newline = false;
pending_spaces = first_indent;
cur_col = first_indent;
break;
}
// Skip the specially-handled character.
++str;
}
}
extern int
tuklib_wrapf(FILE *stream, const struct tuklib_wrap_opt *opt,
const char *fmt, ...)
{
va_list ap;
char *buf;
#ifdef HAVE_VASPRINTF
va_start(ap, fmt);
#ifdef __clang__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
const int n = vasprintf(&buf, fmt, ap);
#ifdef __clang__
# pragma GCC diagnostic pop
#endif
va_end(ap);
if (n == -1)
return TUKLIB_WRAP_ERR_FORMAT;
#else
// Fixed buffer size is dumb but in practice one shouldn't need
// huge strings for *formatted* output. This simple method is safe
// with pre-C99 vsnprintf() implementations too which don't return
// the required buffer size (they return -1 or buf_size - 1) or
// which might not null-terminate the buffer in case it's too small.
const size_t buf_size = 128 * 1024;
buf = malloc(buf_size);
if (buf == NULL)
return TUKLIB_WRAP_ERR_FORMAT;
va_start(ap, fmt);
const int n = vsnprintf(buf, buf_size, fmt, ap);
va_end(ap);
if (n <= 0 || n >= (int)(buf_size - 1)) {
free(buf);
return TUKLIB_WRAP_ERR_FORMAT;
}
#endif
const int ret = tuklib_wraps(stream, opt, buf);
free(buf);
return ret;
}
+204
View File
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file tuklib_mbstr_wrap.h
/// \brief Word wrapping for multibyte strings
///
/// The word wrapping functions are intended to be usable, for example,
/// for printing --help text in command line tools. While manually-wrapped
/// --help text allows precise formatting, such freedom requires translators
/// to count spaces and determine where line breaks should occur. It's
/// tedious and error prone, and experience has shown that only some
/// translators do it well. Automatic word wrapping is less flexible but
/// results in polished-enough look with less effort from everyone.
/// Right-to-left languages and languages that don't use spaces between
/// words will still need extra effort though.
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#ifndef TUKLIB_MBSTR_WRAP_H
#define TUKLIB_MBSTR_WRAP_H
#include "tuklib_common.h"
#include <stdio.h>
TUKLIB_DECLS_BEGIN
/// One or more output lines exceeded right_margin.
/// This only a warning; everything was still printed successfully.
#define TUKLIB_WRAP_WARN_OVERLONG 0x01
/// Error writing to to the output FILE. The error flag in the FILE
/// should have been set as well.
#define TUKLIB_WRAP_ERR_IO 0x02
/// Invalid options in struct tuklib_wrap_opt.
/// Nothing was printed.
#define TUKLIB_WRAP_ERR_OPT 0x04
/// Invalid or unsupported multibyte character in the input string:
/// either mbrtowc() failed or wcwidth() returned a negative value.
#define TUKLIB_WRAP_ERR_STR 0x08
/// Only tuklib_wrapf(): Error in converting the format string.
/// It's either a memory allocation failure or something bad with the
/// format string or arguments.
#define TUKLIB_WRAP_ERR_FORMAT 0x10
/// Options for tuklib_wraps() and tuklib_wrapf()
struct tuklib_wrap_opt {
/// Indentation of the first output line after `\n` or `\r`.
/// This can be anything less than right_margin.
unsigned short left_margin;
/// Column where word-wrapped continuation lines start.
/// This can be anything less than right_margin.
unsigned short left_cont;
/// Column where the text after `\v` will start, either on the current
/// line (when there is room to add at least one space) or on a new
/// empty line.
unsigned short left2_margin;
/// Like left_cont but for text after a `\v`. However, this must
/// be greater than or equal to left2_margin in addition to being
/// less than right_margin.
unsigned short left2_cont;
/// For 80-column terminals, it is recommended to use 79 here for
/// maximum portability. 80 will work most of the time but it will
/// result in unwanted empty lines in the rare case where a terminal
/// moves the cursor to the beginning of the next line immediately
/// when the last column has been used.
unsigned short right_margin;
};
#define tuklib_wraps TUKLIB_SYMBOL(tuklib_wraps)
extern int tuklib_wraps(FILE *stream, const struct tuklib_wrap_opt *opt,
const char *str);
///<
/// \brief Word wrap a multibyte string and write it to a FILE
///
/// Word wrapping is done only at spaces and at the special control characters
/// described below. Multiple consecutive spaces are handled properly: strings
/// that have two (or more) spaces after a full sentence will look good even
/// when the spaces occur at a word wrapping boundary. Trailing spaces are
/// ignored at the end of a line or at the end of a string.
///
/// The following control characters have been repurposed:
///
/// - `\t` = Zero-width space allows a line break without producing any
/// output by itself. This can be useful after hard hyphens as
/// hyphens aren't otherwise used for line breaking. This can also
/// be useful in languages that don't use spaces between words.
/// (The Unicode character U+200B isn't supported.)
/// - `\b` = Text between a pair of `\b` characters is treated as an
/// unbreakable block (not wrapped even if there are spaces).
/// For example, a non-breaking space can be done like
/// in `"123\b \bMiB"`. Control characters (like `\n` or `\t`)
/// aren't allowed before the closing `\b`. If closing `\b` is
/// missing, the block extends to the end of the string. Empty
/// blocks are treated as zero-width characters. If line breaks
/// are possible around an empty block (like in `"foo \b\b bar"`
/// or `"foo \b"`), it can result in weird output.
/// - `\v` = Change to alternative indentation (left2_margin).
/// - `\r` = Reset back to the initial indentation and add a newline.
/// The next line will be indented by left_margin.
/// - `\n` = Add a newline without resetting the effect of `\v`. The
/// next line will be indented by left_margin or left2_margin
/// (not left_cont or left2_cont).
///
/// Only `\n` should appear in translatable strings. `\t` works too but
/// even that might confuse some translators even if there is a TRANSLATORS
/// comment explaining its meaning.
///
/// To use the other control characters in messages, one should use
/// tuklib_wrapf() with appropriate printf format string to combine
/// translatable strings with non-translatable portions. For example:
///
/// \code{.c}
/// static const struct tuklib_wrap_opt wrap2 = { 2, 2, 22, 22, 79 };
/// int e = 0;
/// ...
/// e |= tuklib_wrapf(stdout, &wrap2,
/// "-h, --help\v%s\r"
/// " --version\v%s",
/// W_("display this help and exit"),
/// W_("display version information and exit"));
/// ...
/// if (e != 0) {
/// // Handle warning or error.
/// ...
/// }
/// \endcode
///
/// Control characters other than `\n` and `\t` are unusable in
/// translatable strings:
///
/// - Gettext tools show annoying warnings if C escape sequences other
/// than `\n` or `\t` are seen. (Otherwise they still work perfectly
/// fine though.)
///
/// - While at least Poedit and Lokalize support all escapes, some
/// editors only support `\n` and `\t`.
///
/// - They could confuse some translators, resulting in broken
/// translations.
///
/// Using non-control characters would solve some issues but it wouldn't
/// help with the unfortunate real-world issue that some translators would
/// likely have trouble understanding a new syntax. The Gettext manual
/// specifically warns about this, see the subheading "No unusual markup"
/// in `info (gettext)Preparing Strings`. (While using `\t` for zero-width
/// space is such custom markup, most translators will never need it.)
///
/// Translators can use the Unicode character U+00A0 (or U+202F) if they
/// need a non-breaking space. For example, in French a non-breaking space
/// may be needed before colons and question marks (U+00A0 is common in
/// real-world French PO files).
///
/// Using a non-ASCII char in a string in the C code (like `"123\u00A0MiB"`)
/// can work if one tells xgettext that input encoding is UTF-8, one
/// ensures that the C compiler uses UTF-8 as the input charset, and one
/// is certain that the program is *always* run under an UTF-8 locale.
/// Unfortunately a portable program cannot make this kind of assumptions,
/// which means that there is no pretty way to have a non-breaking space in
/// a translatable string.
///
/// Optional: To tell translators which strings are automatically word
/// wrapped, see the macro `W_` in tuklib_gettext.h.
///
/// \param stream Output FILE stream. For decent performance, it
/// should be in buffered mode because this function
/// writes the output one byte at a time with fputc().
/// \param opt Word wrapping options.
/// \param str Null-terminated multibyte string that is in
/// the encoding used by the current locale.
///
/// \return Returns 0 on success. If an error or warning occurs, one of
/// TUKLIB_WRAP_* codes is returned. Those codes are powers
/// of two. When warning/error detection can be delayed, the
/// return values can be accumulated from multiple calls using
/// bitwise-or into a single variable which can be checked after
/// all strings have (hopefully) been printed.
#define tuklib_wrapf TUKLIB_SYMBOL(tuklib_wrapf)
tuklib_attr_format_printf(3, 4)
extern int tuklib_wrapf(FILE *stream, const struct tuklib_wrap_opt *opt,
const char *fmt, ...);
///<
/// \brief Format and word-wrap a multibyte string and write it to a FILE
///
/// This is like tuklib_wraps() except that this takes a printf
/// format string.
///
/// \note On platforms that lack vasprintf(), the intermediate
/// result from vsnprintf() must fit into a 128 KiB buffer.
/// TUKLIB_WRAP_ERR_FORMAT is returned if it doesn't but
/// only on platforms that lack vasprintf().
TUKLIB_DECLS_END
#endif
+2 -9
View File
@@ -91,18 +91,11 @@ tuklib_physmem(void)
// supports reporting values greater than 4 GiB. To keep the
// code working also on older Windows versions, use
// GlobalMemoryStatusEx() conditionally.
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
if (kernel32 != NULL) {
typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX);
#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
gmse_type gmse = (gmse_type)GetProcAddress(
kernel32, "GlobalMemoryStatusEx");
#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
# pragma GCC diagnostic pop
#endif
if (gmse != NULL) {
MEMORYSTATUSEX meminfo;
meminfo.dwLength = sizeof(meminfo);
@@ -155,7 +148,7 @@ tuklib_physmem(void)
ret += entries[i].end - entries[i].start + 1;
#elif defined(TUKLIB_PHYSMEM_AIX)
ret = _system_configuration.physmem;
ret = (uint64_t)_system_configuration.physmem;
#elif defined(TUKLIB_PHYSMEM_SYSCONF)
const long pagesize = sysconf(_SC_PAGESIZE);
+97
View File
@@ -96,3 +96,100 @@ typedef struct {
uint32_t start_offset;
} lzma_options_bcj;
/**
* \brief Raw ARM64 BCJ encoder
*
* This is for special use cases only.
*
* \param start_offset The lowest 32 bits of the offset in the
* executable being filtered. For the ARM64
* filter, this must be a multiple of four.
* For the very best results, this should also
* be in sync with 4096-byte page boundaries
* in the executable due to how ARM64's ADRP
* instruction works.
* \param buf Buffer to be filtered in place
* \param size Size of the buffer
*
* \return Number of bytes that were processed in `buf`. This is at most
* `size`. With the ARM64 filter, the return value is always
* a multiple of 4, and at most 3 bytes are left unfiltered.
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_arm64_encode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
/**
* \brief Raw ARM64 BCJ decoder
*
* See lzma_bcj_arm64_encode().
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_arm64_decode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
/**
* \brief Raw RISC-V BCJ encoder
*
* This is for special use cases only.
*
* \param start_offset The lowest 32 bits of the offset in the
* executable being filtered. For the RISC-V
* filter, this must be a multiple of 2.
* \param buf Buffer to be filtered in place
* \param size Size of the buffer
*
* \return Number of bytes that were processed in `buf`. This is at most
* `size`. With the RISC-V filter, the return value is always
* a multiple of 2, and at most 7 bytes are left unfiltered.
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_riscv_encode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
/**
* \brief Raw RISC-V BCJ decoder
*
* See lzma_bcj_riscv_encode().
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_riscv_decode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
/**
* \brief Raw x86 BCJ encoder
*
* This is for special use cases only.
*
* \param start_offset The lowest 32 bits of the offset in the
* executable being filtered. For the x86
* filter, all values are valid.
* \param buf Buffer to be filtered in place
* \param size Size of the buffer
*
* \return Number of bytes that were processed in `buf`. This is at most
* `size`. For the x86 filter, the return value is always
* a multiple of 1, and at most 4 bytes are left unfiltered.
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_x86_encode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
/**
* \brief Raw x86 BCJ decoder
*
* See lzma_bcj_x86_encode().
*
* \since 5.7.1alpha
*/
extern LZMA_API(size_t) lzma_bcj_x86_decode(
uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
+1 -1
View File
@@ -573,7 +573,7 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
* The action argument must be LZMA_FINISH and the return value will never be
* LZMA_OK. Thus the encoding is always done with a single lzma_code() after
* the initialization. The benefit of the combination of initialization
* function and lzma_code() is that memory allocations can be re-used for
* function and lzma_code() is that memory allocations can be reused for
* better performance.
*
* lzma_code() will try to encode as much input as is possible to fit into
+1 -1
View File
@@ -461,7 +461,7 @@ typedef struct {
*
* ext_size_low holds the least significant 32 bits of the
* uncompressed size. The most significant 32 bits must be set
* in ext_size_high. The macro lzma_ext_size_set(opt_lzma, u64size)
* in ext_size_high. The macro lzma_set_ext_size(opt_lzma, u64size)
* can be used to set these members.
*
* The 64-bit uncompressed size is split into two uint32_t variables
+2 -2
View File
@@ -19,10 +19,10 @@
#define LZMA_VERSION_MAJOR 5
/** \brief Minor version number of the liblzma release. */
#define LZMA_VERSION_MINOR 6
#define LZMA_VERSION_MINOR 8
/** \brief Patch version number of the liblzma release. */
#define LZMA_VERSION_PATCH 3
#define LZMA_VERSION_PATCH 1
/**
* \brief Version stability marker
-18
View File
@@ -95,24 +95,6 @@ typedef struct {
} lzma_check_state;
/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep
/// the array two-dimensional.
#ifdef HAVE_SMALL
lzma_attr_visibility_hidden
extern uint32_t lzma_crc32_table[1][256];
extern void lzma_crc32_init(void);
#else
lzma_attr_visibility_hidden
extern const uint32_t lzma_crc32_table[8][256];
lzma_attr_visibility_hidden
extern const uint64_t lzma_crc64_table[4][256];
#endif
/// \brief Initialize *check depending on type
extern void lzma_check_init(lzma_check_state *check, lzma_check type);
+40 -15
View File
@@ -7,7 +7,7 @@
//
// Authors: Chenxi Mao
// Jia Tan
// Hans Jansen
// Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
@@ -49,25 +49,50 @@ crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
{
crc = ~crc;
// Align the input buffer because this was shown to be
// significantly faster than unaligned accesses.
const size_t align_amount = my_min(size, (0U - (uintptr_t)buf) & 7);
if (size >= 8) {
// Align the input buffer because this was shown to be
// significantly faster than unaligned accesses.
const size_t align = (0 - (uintptr_t)buf) & 7;
for (const uint8_t *limit = buf + align_amount; buf < limit; ++buf)
crc = __crc32b(crc, *buf);
if (align & 1)
crc = __crc32b(crc, *buf++);
size -= align_amount;
if (align & 2) {
crc = __crc32h(crc, aligned_read16le(buf));
buf += 2;
}
// Process 8 bytes at a time. The end point is determined by
// ignoring the least significant three bits of size to ensure
// we do not process past the bounds of the buffer. This guarantees
// that limit is a multiple of 8 and is strictly less than size.
for (const uint8_t *limit = buf + (size & ~(size_t)7);
buf < limit; buf += 8)
crc = __crc32d(crc, aligned_read64le(buf));
if (align & 4) {
crc = __crc32w(crc, aligned_read32le(buf));
buf += 4;
}
size -= align;
// Process 8 bytes at a time. The end point is determined by
// ignoring the least significant three bits of size to
// ensure we do not process past the bounds of the buffer.
// This guarantees that limit is a multiple of 8 and is
// strictly less than size.
for (const uint8_t *limit = buf + (size & ~(size_t)7);
buf < limit; buf += 8)
crc = __crc32d(crc, aligned_read64le(buf));
size &= 7;
}
// Process the remaining bytes that are not 8 byte aligned.
for (const uint8_t *limit = buf + (size & 7); buf < limit; ++buf)
if (size & 4) {
crc = __crc32w(crc, aligned_read32le(buf));
buf += 4;
}
if (size & 2) {
crc = __crc32h(crc, aligned_read16le(buf));
buf += 2;
}
if (size & 1)
crc = __crc32b(crc, *buf);
return ~crc;
+19 -27
View File
@@ -7,7 +7,6 @@
//
// Authors: Lasse Collin
// Ilya Kurdyukov
// Hans Jansen
//
///////////////////////////////////////////////////////////////////////////////
@@ -15,10 +14,12 @@
#include "crc_common.h"
#if defined(CRC_X86_CLMUL)
# define BUILDING_CRC32_CLMUL
# define BUILDING_CRC_CLMUL 32
# include "crc_x86_clmul.h"
#elif defined(CRC32_ARM64)
# include "crc32_arm64.h"
#elif defined(CRC32_LOONGARCH)
# include "crc32_loongarch.h"
#endif
@@ -28,8 +29,19 @@
// Generic CRC32 //
///////////////////
#ifdef WORDS_BIGENDIAN
# include "crc32_table_be.h"
#else
# include "crc32_table_le.h"
#endif
#ifdef HAVE_CRC_X86_ASM
extern uint32_t lzma_crc32_generic(
const uint8_t *buf, size_t size, uint32_t crc);
#else
static uint32_t
crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
lzma_crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
{
crc = ~crc;
@@ -85,7 +97,8 @@ crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
return ~crc;
}
#endif
#endif // HAVE_CRC_X86_ASM
#endif // CRC32_GENERIC
#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
@@ -119,7 +132,7 @@ static crc32_func_type
crc32_resolve(void)
{
return is_arch_extension_supported()
? &crc32_arch_optimized : &crc32_generic;
? &crc32_arch_optimized : &lzma_crc32_generic;
}
@@ -164,27 +177,6 @@ extern LZMA_API(uint32_t)
lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
{
#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
// On x86-64, if CLMUL is available, it is the best for non-tiny
// inputs, being over twice as fast as the generic slice-by-four
// version. However, for size <= 16 it's different. In the extreme
// case of size == 1 the generic version can be five times faster.
// At size >= 8 the CLMUL starts to become reasonable. It
// varies depending on the alignment of buf too.
//
// The above doesn't include the overhead of mythread_once().
// At least on x86-64 GNU/Linux, pthread_once() is very fast but
// it still makes lzma_crc32(buf, 1, crc) 50-100 % slower. When
// size reaches 12-16 bytes the overhead becomes negligible.
//
// So using the generic version for size <= 16 may give better
// performance with tiny inputs but if such inputs happen rarely
// it's not so obvious because then the lookup table of the
// generic version may not be in the processor cache.
#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
if (size <= 16)
return crc32_generic(buf, size, crc);
#endif
/*
#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
// See crc32_dispatch(). This would be the alternative which uses
@@ -199,6 +191,6 @@ lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
return crc32_arch_optimized(buf, size, crc);
#else
return crc32_generic(buf, size, crc);
return lzma_crc32_generic(buf, size, crc);
#endif
}
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file crc32_loongarch.h
/// \brief CRC32 calculation with LoongArch optimization
//
// Authors: Xi Ruoyao
// Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_CRC32_LOONGARCH_H
#define LZMA_CRC32_LOONGARCH_H
#include <larchintrin.h>
static uint32_t
crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc_unsigned)
{
int32_t crc = (int32_t)~crc_unsigned;
if (size >= 8) {
const size_t align = (0 - (uintptr_t)buf) & 7;
if (align & 1)
crc = __crc_w_b_w((int8_t)*buf++, crc);
if (align & 2) {
crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);
buf += 2;
}
if (align & 4) {
crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);
buf += 4;
}
size -= align;
for (const uint8_t *limit = buf + (size & ~(size_t)7);
buf < limit; buf += 8)
crc = __crc_w_d_w((int64_t)aligned_read64le(buf), crc);
size &= 7;
}
if (size & 4) {
crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);
buf += 4;
}
if (size & 2) {
crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);
buf += 2;
}
if (size & 1)
crc = __crc_w_b_w((int8_t)*buf, crc);
return (uint32_t)~crc;
}
#endif // LZMA_CRC32_LOONGARCH_H
@@ -10,8 +10,11 @@
///////////////////////////////////////////////////////////////////////////////
#include "check.h"
#include "crc_common.h"
// The table is used by the LZ encoder too, thus it's not static like
// in crc64_small.c.
uint32_t lzma_crc32_table[1][256];
@@ -1,42 +0,0 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file crc32_table.c
/// \brief Precalculated CRC32 table with correct endianness
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
// so that in 32-bit builds crc32_x86.S won't break due to a missing table.
#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
|| (defined(__e2k__) && __iset__ >= 6))
# define NO_CRC32_TABLE
#elif defined(HAVE_ARM64_CRC32) \
&& !defined(WORDS_BIGENDIAN) \
&& defined(__ARM_FEATURE_CRC32)
# define NO_CRC32_TABLE
#endif
#if !defined(HAVE_ENCODERS) && defined(NO_CRC32_TABLE)
// No table needed. Use a typedef to avoid an empty translation unit.
typedef void lzma_crc32_dummy;
#else
// Having the declaration here silences clang -Wmissing-variable-declarations.
extern const uint32_t lzma_crc32_table[8][256];
# ifdef WORDS_BIGENDIAN
# include "crc32_table_be.h"
# else
# include "crc32_table_le.h"
# endif
#endif
+5 -9
View File
@@ -67,7 +67,7 @@ init_table(void)
#endif
#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
#define LZMA_CRC32 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32)
#define LZMA_CRC32 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32_generic)
#define LZMA_CRC32_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32_table)
/*
@@ -82,6 +82,9 @@ init_table(void)
.text
.globl LZMA_CRC32
#ifdef __ELF__
.hidden LZMA_CRC32
#endif
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
&& !defined(__MSDOS__)
@@ -290,14 +293,7 @@ LZMA_CRC32:
.indirect_symbol LZMA_CRC32_TABLE
.long 0
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifdef DLL_EXPORT
/* This is equivalent of __declspec(dllexport). */
.section .drectve
.ascii " -export:lzma_crc32"
# endif
#elif !defined(__MSDOS__)
#elif !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSDOS__)
/* ELF */
.size LZMA_CRC32, .-LZMA_CRC32
#endif
+26 -13
View File
@@ -14,7 +14,7 @@
#include "crc_common.h"
#if defined(CRC_X86_CLMUL)
# define BUILDING_CRC64_CLMUL
# define BUILDING_CRC_CLMUL 64
# include "crc_x86_clmul.h"
#endif
@@ -25,6 +25,18 @@
// Generic slice-by-four CRC64 //
/////////////////////////////////
#if defined(WORDS_BIGENDIAN)
# include "crc64_table_be.h"
#else
# include "crc64_table_le.h"
#endif
#ifdef HAVE_CRC_X86_ASM
extern uint64_t lzma_crc64_generic(
const uint8_t *buf, size_t size, uint64_t crc);
#else
#ifdef WORDS_BIGENDIAN
# define A1(x) ((x) >> 56)
#else
@@ -34,7 +46,7 @@
// See the comments in crc32_fast.c. They aren't duplicated here.
static uint64_t
crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
lzma_crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
{
crc = ~crc;
@@ -78,7 +90,8 @@ crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
return ~crc;
}
#endif
#endif // HAVE_CRC_X86_ASM
#endif // CRC64_GENERIC
#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
@@ -97,7 +110,7 @@ static crc64_func_type
crc64_resolve(void)
{
return is_arch_extension_supported()
? &crc64_arch_optimized : &crc64_generic;
? &crc64_arch_optimized : &lzma_crc64_generic;
}
#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
@@ -133,24 +146,24 @@ crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
extern LZMA_API(uint64_t)
lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
{
#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
if (size <= 16)
return crc64_generic(buf, size, crc);
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
&& defined(_M_IX86) && defined(CRC64_ARCH_OPTIMIZED)
// VS2015-2022 might corrupt the ebx register on 32-bit x86 when
// the CLMUL code is enabled. This hack forces MSVC to store and
// restore ebx. This is only needed here, not in lzma_crc32().
__asm mov ebx, ebx
#endif
#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
return crc64_func(buf, size, crc);
#elif defined(CRC64_ARCH_OPTIMIZED)
// If arch-optimized version is used unconditionally without runtime
// CPU detection then omitting the generic version and its 8 KiB
// lookup table makes the library smaller.
//
// FIXME: Lookup table isn't currently omitted on 32-bit x86,
// see crc64_table.c.
return crc64_arch_optimized(buf, size, crc);
#else
return crc64_generic(buf, size, crc);
return lzma_crc64_generic(buf, size, crc);
#endif
}
@@ -1,37 +0,0 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file crc64_table.c
/// \brief Precalculated CRC64 table with correct endianness
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
// so that in 32-bit builds crc64_x86.S won't break due to a missing table.
#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
|| (defined(__e2k__) && __iset__ >= 6))
# define NO_CRC64_TABLE
#endif
#ifdef NO_CRC64_TABLE
// No table needed. Use a typedef to avoid an empty translation unit.
typedef void lzma_crc64_dummy;
#else
// Having the declaration here silences clang -Wmissing-variable-declarations.
extern const uint64_t lzma_crc64_table[4][256];
# if defined(WORDS_BIGENDIAN)
# include "crc64_table_be.h"
# else
# include "crc64_table_le.h"
# endif
#endif
+5 -9
View File
@@ -57,7 +57,7 @@ init_table(void)
#endif
#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
#define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64)
#define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_generic)
#define LZMA_CRC64_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_table)
/*
@@ -72,6 +72,9 @@ init_table(void)
.text
.globl LZMA_CRC64
#ifdef __ELF__
.hidden LZMA_CRC64
#endif
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
&& !defined(__MSDOS__)
@@ -273,14 +276,7 @@ LZMA_CRC64:
.indirect_symbol LZMA_CRC64_TABLE
.long 0
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifdef DLL_EXPORT
/* This is equivalent of __declspec(dllexport). */
.section .drectve
.ascii " -export:lzma_crc64"
# endif
#elif !defined(__MSDOS__)
#elif !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSDOS__)
/* ELF */
.size LZMA_CRC64, .-LZMA_CRC64
#endif
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: 0BSD
///////////////////////////////////////////////////////////////////////////////
//
/// \file crc_clmul_consts_gen.c
/// \brief Generate constants for CLMUL CRC code
///
/// Compiling: gcc -std=c99 -o crc_clmul_consts_gen crc_clmul_consts_gen.c
///
/// This is for CRCs that use reversed bit order (bit reflection).
/// The same CLMUL CRC code can be used with CRC64 and smaller ones like
/// CRC32 apart from one special case: CRC64 needs an extra step in the
/// Barrett reduction to handle the 65th bit; the smaller ones don't.
/// Otherwise it's enough to just change the polynomial and the derived
/// constants and use the same code.
///
/// See the Intel white paper "Fast CRC Computation for Generic Polynomials
/// Using PCLMULQDQ Instruction" from 2009.
//
// Author: Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#include <inttypes.h>
#include <stdio.h>
/// CRC32 (Ethernet) polynomial in reversed representation
static const uint64_t p32 = 0xedb88320;
// CRC64 (ECMA-182) polynomial in reversed representation
static const uint64_t p64 = 0xc96c5795d7870f42;
/// Calculates floor(x^128 / p) where p is a CRC64 polynomial in
/// reversed representation. The result is in reversed representation too.
static uint64_t
calc_cldiv(uint64_t p)
{
// Quotient
uint64_t q = 0;
// Align the x^64 term with the x^128 (the implied high bits of the
// divisor and the dividend) and do the first step of polynomial long
// division, calculating the first remainder. The variable q remains
// zero because the highest bit of the quotient is an implied bit 1
// (we kind of set q = 1 << -1).
uint64_t r = p;
// Then process the remaining 64 terms. Note that r has no implied
// high bit, only q and p do. (And remember that a high bit in the
// polynomial is stored at a low bit in the variable due to the
// reversed bit order.)
for (unsigned i = 0; i < 64; ++i) {
q |= (r & 1) << i;
r = (r >> 1) ^ (r & 1 ? p : 0);
}
return q;
}
/// Calculate the remainder of carryless division:
///
/// x^(bits + n - 1) % p, where n=64 (for CRC64)
///
/// p must be in reversed representation which omits the bit of
/// the highest term of the polynomial. Instead, it is an implied bit
/// at kind of like "1 << -1" position, as if it had just been shifted out.
///
/// The return value is in the reversed bit order. (There are no implied bits.)
static uint64_t
calc_clrem(uint64_t p, unsigned bits)
{
// Do the first step of polynomial long division.
uint64_t r = p;
// Then process the remaining terms. Start with i = 1 instead of i = 0
// to account for the -1 in x^(bits + n - 1). This -1 is convenient
// with the reversed bit order. See the "Bit-Reflection" section in
// the Intel white paper.
for (unsigned i = 1; i < bits; ++i)
r = (r >> 1) ^ (r & 1 ? p : 0);
return r;
}
extern int
main(void)
{
puts("// CRC64");
// The order of the two 64-bit constants in a vector don't matter.
// It feels logical to put them in this order as it matches the
// order in which the input bytes are read.
printf("const __m128i fold512 = _mm_set_epi64x("
"0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",
calc_clrem(p64, 4 * 128 - 64),
calc_clrem(p64, 4 * 128));
printf("const __m128i fold128 = _mm_set_epi64x("
"0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",
calc_clrem(p64, 128 - 64),
calc_clrem(p64, 128));
// When we multiply by mu, we care about the high bits of the result
// (in reversed bit order!). It doesn't matter that the low bit gets
// shifted out because the affected output bits will be ignored.
// Below we add the implied high bit with "| 1" after the shifting
// so that the high bits of the multiplication will be correct.
//
// p64 is shifted left by one so that the final multiplication
// in Barrett reduction won't be misaligned by one bit. We could
// use "(p64 << 1) | 1" instead of "p64 << 1" too but it makes
// no difference as that bit won't affect the relevant output bits
// (we only care about the lowest 64 bits of the result, that is,
// lowest in the reversed bit order).
//
// NOTE: The 65rd bit of p64 gets shifted out. It needs to be
// compensated with 64-bit shift and xor in the CRC64 code.
printf("const __m128i mu_p = _mm_set_epi64x("
"0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",
(calc_cldiv(p64) << 1) | 1,
p64 << 1);
puts("");
puts("// CRC32");
printf("const __m128i fold512 = _mm_set_epi64x("
"0x%08" PRIx64 ", 0x%08" PRIx64 ");\n",
calc_clrem(p32, 4 * 128 - 64),
calc_clrem(p32, 4 * 128));
printf("const __m128i fold128 = _mm_set_epi64x("
"0x%08" PRIx64 ", 0x%08" PRIx64 ");\n",
calc_clrem(p32, 128 - 64),
calc_clrem(p32, 128));
// CRC32 calculation is done by modulus scaling it to a CRC64.
// Since the CRC is in reversed representation, only the mu
// constant changes with the modulus scaling. This method avoids
// one additional constant and one additional clmul in the final
// reduction steps, making the code both simpler and faster.
//
// p32 is shifted left by one so that the final multiplication
// in Barrett reduction won't be misaligned by one bit. We could
// use "(p32 << 1) | 1" instead of "p32 << 1" too but it makes
// no difference as that bit won't affect the relevant output bits.
//
// NOTE: The 33-bit value fits in 64 bits so, unlike with CRC64,
// there is no need to compensate for any missing bits in the code.
printf("const __m128i mu_p = _mm_set_epi64x("
"0x%016" PRIx64 ", 0x%" PRIx64 ");\n",
(calc_cldiv(p32) << 1) | 1,
p32 << 1);
return 0;
}
+72 -39
View File
@@ -3,11 +3,10 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file crc_common.h
/// \brief Some functions and macros for CRC32 and CRC64
/// \brief Macros and declarations for CRC32 and CRC64
//
// Authors: Lasse Collin
// Ilya Kurdyukov
// Hans Jansen
// Jia Tan
//
///////////////////////////////////////////////////////////////////////////////
@@ -18,6 +17,10 @@
#include "common.h"
/////////////
// Generic //
/////////////
#ifdef WORDS_BIGENDIAN
# define A(x) ((x) >> 24)
# define B(x) (((x) >> 16) & 0xFF)
@@ -38,43 +41,63 @@
#endif
// CRC CLMUL code needs this because accessing input buffers that aren't
// aligned to the vector size will inherently trip the address sanitizer.
#if lzma_has_attribute(__no_sanitize_address__)
# define crc_attr_no_sanitize_address \
__attribute__((__no_sanitize_address__))
/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep
/// the array two-dimensional.
#ifdef HAVE_SMALL
lzma_attr_visibility_hidden
extern uint32_t lzma_crc32_table[1][256];
extern void lzma_crc32_init(void);
#else
# define crc_attr_no_sanitize_address
#endif
// Keep this in sync with changes to crc32_arm64.h
#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \
|| defined(HAVE_ELF_AUX_INFO) \
|| (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME))
# define ARM64_RUNTIME_DETECTION 1
lzma_attr_visibility_hidden
extern const uint32_t lzma_crc32_table[8][256];
lzma_attr_visibility_hidden
extern const uint64_t lzma_crc64_table[4][256];
#endif
///////////////////
// Configuration //
///////////////////
// NOTE: This config isn't used if HAVE_SMALL is defined!
// These are defined if the generic slicing-by-n implementations and their
// lookup tables are built.
#undef CRC32_GENERIC
#undef CRC64_GENERIC
// These are defined if an arch-specific version is built. If both this
// and matching _GENERIC is defined then runtime detection must be used.
#undef CRC32_ARCH_OPTIMIZED
#undef CRC64_ARCH_OPTIMIZED
// The x86 CLMUL is used for both CRC32 and CRC64.
#undef CRC_X86_CLMUL
// Many ARM64 processor have CRC32 instructions.
// CRC64 could be done with CLMUL but it's not implemented yet.
#undef CRC32_ARM64
#undef CRC64_ARM64_CLMUL
#undef CRC_USE_GENERIC_FOR_SMALL_INPUTS
// 64-bit LoongArch has CRC32 instructions.
#undef CRC32_LOONGARCH
// ARM64
//
// Keep this in sync with changes to crc32_arm64.h
#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \
|| defined(HAVE_ELF_AUX_INFO) \
|| (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME))
# define CRC_ARM64_RUNTIME_DETECTION 1
#endif
// ARM64 CRC32 instruction is only useful for CRC32. Currently, only
// little endian is supported since we were unable to test on a big
// endian machine.
//
// NOTE: Keep this and the next check in sync with the macro
// NO_CRC32_TABLE in crc32_table.c
#if defined(HAVE_ARM64_CRC32) && !defined(WORDS_BIGENDIAN)
// Allow ARM64 CRC32 instruction without a runtime check if
// __ARM_FEATURE_CRC32 is defined. GCC and Clang only define
@@ -82,21 +105,40 @@
# if defined(__ARM_FEATURE_CRC32)
# define CRC32_ARCH_OPTIMIZED 1
# define CRC32_ARM64 1
# elif defined(ARM64_RUNTIME_DETECTION)
# elif defined(CRC_ARM64_RUNTIME_DETECTION)
# define CRC32_ARCH_OPTIMIZED 1
# define CRC32_ARM64 1
# define CRC32_GENERIC 1
# endif
#endif
#if defined(HAVE_USABLE_CLMUL)
// If CLMUL is allowed unconditionally in the compiler options then the
// generic version can be omitted. Note that this doesn't work with MSVC
// as I don't know how to detect the features here.
// LoongArch
//
// NOTE: Keep this in sync with the NO_CRC32_TABLE macro in crc32_table.c
// and NO_CRC64_TABLE in crc64_table.c.
# if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__)) \
// Only 64-bit LoongArch is supported for now. No runtime detection
// is needed because the LoongArch specification says that the CRC32
// instructions are a part of the Basic Integer Instructions and
// they shall be implemented by 64-bit LoongArch implementations.
#ifdef HAVE_LOONGARCH_CRC32
# define CRC32_ARCH_OPTIMIZED 1
# define CRC32_LOONGARCH 1
#endif
// x86 and E2K
#if defined(HAVE_USABLE_CLMUL)
// If CLMUL is allowed unconditionally in the compiler options then
// the generic version and the tables can be omitted. Exceptions:
//
// - If 32-bit x86 assembly files are enabled then those are always
// built and runtime detection is used even if compiler flags
// were set to allow CLMUL unconditionally.
//
// - This doesn't work with MSVC as I don't know how to detect
// the features here.
//
# if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__) \
&& !defined(HAVE_CRC_X86_ASM)) \
|| (defined(__e2k__) && __iset__ >= 6)
# define CRC32_ARCH_OPTIMIZED 1
# define CRC64_ARCH_OPTIMIZED 1
@@ -107,21 +149,12 @@
# define CRC32_ARCH_OPTIMIZED 1
# define CRC64_ARCH_OPTIMIZED 1
# define CRC_X86_CLMUL 1
/*
// The generic code is much faster with 1-8-byte inputs and
// has similar performance up to 16 bytes at least in
// microbenchmarks (it depends on input buffer alignment
// too). If both versions are built, this #define will use
// the generic version for inputs up to 16 bytes and CLMUL
// for bigger inputs. It saves a little in code size since
// the special cases for 0-16-byte inputs will be omitted
// from the CLMUL code.
# define CRC_USE_GENERIC_FOR_SMALL_INPUTS 1
*/
# endif
#endif
// Fallback configuration
//
// For CRC32 use the generic slice-by-eight implementation if no optimized
// version is available.
#if !defined(CRC32_ARCH_OPTIMIZED) && !defined(CRC32_GENERIC)
+247 -302
View File
@@ -8,26 +8,20 @@
/// The CRC32 and CRC64 implementations use 32/64-bit x86 SSSE3, SSE4.1, and
/// CLMUL instructions. This is compatible with Elbrus 2000 (E2K) too.
///
/// They were derived from
/// See the Intel white paper "Fast CRC Computation for Generic Polynomials
/// Using PCLMULQDQ Instruction" from 2009. The original file seems to be
/// gone from Intel's website but a version is available here:
/// https://www.researchgate.net/publication/263424619_Fast_CRC_computation
/// and the public domain code from https://github.com/rawrunprotected/crc
/// (URLs were checked on 2023-10-14).
/// (The link was checked on 2024-06-11.)
///
/// While this file has both CRC32 and CRC64 implementations, only one
/// should be built at a time to ensure that crc_simd_body() is inlined
/// even with compilers with which lzma_always_inline expands to plain inline.
/// The version to build is selected by defining BUILDING_CRC32_CLMUL or
/// BUILDING_CRC64_CLMUL before including this file.
/// can be built at a time. The version to build is selected by defining
/// BUILDING_CRC_CLMUL to 32 or 64 before including this file.
///
/// FIXME: Builds for 32-bit x86 use the assembly .S files by default
/// unless configured with --disable-assembler. Even then the lookup table
/// isn't omitted in crc64_table.c since it doesn't know that assembly
/// code has been disabled.
/// NOTE: The x86 CLMUL CRC implementation was rewritten for XZ Utils 5.8.0.
//
// Authors: Ilya Kurdyukov
// Hans Jansen
// Lasse Collin
// Jia Tan
// Authors: Lasse Collin
// Ilya Kurdyukov
//
///////////////////////////////////////////////////////////////////////////////
@@ -37,6 +31,10 @@
#endif
#define LZMA_CRC_X86_CLMUL_H
#if BUILDING_CRC_CLMUL != 32 && BUILDING_CRC_CLMUL != 64
# error BUILDING_CRC_CLMUL is undefined or has an invalid value
#endif
#include <immintrin.h>
#if defined(_MSC_VER)
@@ -59,330 +57,277 @@
#endif
#define MASK_L(in, mask, r) r = _mm_shuffle_epi8(in, mask)
#define MASK_H(in, mask, r) \
r = _mm_shuffle_epi8(in, _mm_xor_si128(mask, vsign))
#define MASK_LH(in, mask, low, high) \
MASK_L(in, mask, low); \
MASK_H(in, mask, high)
crc_attr_target
crc_attr_no_sanitize_address
static lzma_always_inline void
crc_simd_body(const uint8_t *buf, const size_t size, __m128i *v0, __m128i *v1,
const __m128i vfold16, const __m128i initial_crc)
{
// Create a vector with 8-bit values 0 to 15. This is used to
// construct control masks for _mm_blendv_epi8 and _mm_shuffle_epi8.
const __m128i vramp = _mm_setr_epi32(
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c);
// This is used to inverse the control mask of _mm_shuffle_epi8
// so that bytes that wouldn't be picked with the original mask
// will be picked and vice versa.
const __m128i vsign = _mm_set1_epi8(-0x80);
// Memory addresses A to D and the distances between them:
//
// A B C D
// [skip_start][size][skip_end]
// [ size2 ]
//
// A and D are 16-byte aligned. B and C are 1-byte aligned.
// skip_start and skip_end are 0-15 bytes. size is at least 1 byte.
//
// A = aligned_buf will initially point to this address.
// B = The address pointed by the caller-supplied buf.
// C = buf + size == aligned_buf + size2
// D = buf + size + skip_end == aligned_buf + size2 + skip_end
const size_t skip_start = (size_t)((uintptr_t)buf & 15);
const size_t skip_end = (size_t)((0U - (uintptr_t)(buf + size)) & 15);
const __m128i *aligned_buf = (const __m128i *)(
(uintptr_t)buf & ~(uintptr_t)15);
// If size2 <= 16 then the whole input fits into a single 16-byte
// vector. If size2 > 16 then at least two 16-byte vectors must
// be processed. If size2 > 16 && size <= 16 then there is only
// one 16-byte vector's worth of input but it is unaligned in memory.
//
// NOTE: There is no integer overflow here if the arguments
// are valid. If this overflowed, buf + size would too.
const size_t size2 = skip_start + size;
// Masks to be used with _mm_blendv_epi8 and _mm_shuffle_epi8:
// The first skip_start or skip_end bytes in the vectors will have
// the high bit (0x80) set. _mm_blendv_epi8 and _mm_shuffle_epi8
// will produce zeros for these positions. (Bitwise-xor of these
// masks with vsign will produce the opposite behavior.)
const __m128i mask_start
= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_start));
const __m128i mask_end
= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_end));
// Get the first 1-16 bytes into data0. If loading less than 16
// bytes, the bytes are loaded to the high bits of the vector and
// the least significant positions are filled with zeros.
const __m128i data0 = _mm_blendv_epi8(_mm_load_si128(aligned_buf),
_mm_setzero_si128(), mask_start);
aligned_buf++;
__m128i v2, v3;
#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
if (size <= 16) {
// Right-shift initial_crc by 1-16 bytes based on "size"
// and store the result in v1 (high bytes) and v0 (low bytes).
//
// NOTE: The highest 8 bytes of initial_crc are zeros so
// v1 will be filled with zeros if size >= 8. The highest
// 8 bytes of v1 will always become zeros.
//
// [ v1 ][ v0 ]
// [ initial_crc ] size == 1
// [ initial_crc ] size == 2
// [ initial_crc ] size == 15
// [ initial_crc ] size == 16 (all in v0)
const __m128i mask_low = _mm_add_epi8(
vramp, _mm_set1_epi8((char)(size - 16)));
MASK_LH(initial_crc, mask_low, *v0, *v1);
if (size2 <= 16) {
// There are 1-16 bytes of input and it is all
// in data0. Copy the input bytes to v3. If there
// are fewer than 16 bytes, the low bytes in v3
// will be filled with zeros. That is, the input
// bytes are stored to the same position as
// (part of) initial_crc is in v0.
MASK_L(data0, mask_end, v3);
} else {
// There are 2-16 bytes of input but not all bytes
// are in data0.
const __m128i data1 = _mm_load_si128(aligned_buf);
// Collect the 2-16 input bytes from data0 and data1
// to v2 and v3, and bitwise-xor them with the
// low bits of initial_crc in v0. Note that the
// the second xor is below this else-block as it
// is shared with the other branch.
MASK_H(data0, mask_end, v2);
MASK_L(data1, mask_end, v3);
*v0 = _mm_xor_si128(*v0, v2);
}
*v0 = _mm_xor_si128(*v0, v3);
*v1 = _mm_alignr_epi8(*v1, *v0, 8);
} else
// GCC and Clang would produce good code with _mm_set_epi64x
// but MSVC needs _mm_cvtsi64_si128 on x86-64.
#if defined(__i386__) || defined(_M_IX86)
# define my_set_low64(a) _mm_set_epi64x(0, (a))
#else
# define my_set_low64(a) _mm_cvtsi64_si128(a)
#endif
{
// There is more than 16 bytes of input.
const __m128i data1 = _mm_load_si128(aligned_buf);
const __m128i *end = (const __m128i*)(
(const char *)aligned_buf - 16 + size2);
aligned_buf++;
MASK_LH(initial_crc, mask_start, *v0, *v1);
*v0 = _mm_xor_si128(*v0, data0);
*v1 = _mm_xor_si128(*v1, data1);
while (aligned_buf < end) {
*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
*v0, vfold16, 0x00));
*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
*v0, vfold16, 0x11));
*v1 = _mm_load_si128(aligned_buf++);
}
if (aligned_buf != end) {
MASK_H(*v0, mask_end, v2);
MASK_L(*v0, mask_end, *v0);
MASK_L(*v1, mask_end, v3);
*v1 = _mm_or_si128(v2, v3);
}
*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
*v0, vfold16, 0x00));
*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
*v0, vfold16, 0x11));
*v1 = _mm_srli_si128(*v0, 8);
}
}
/////////////////////
// x86 CLMUL CRC32 //
/////////////////////
// Align it so that the whole array is within the same cache line.
// More than one unaligned load can be done from this during the
// same CRC function call.
//
// The bytes [0] to [31] are used with AND to clear the low bytes. (With ANDN
// those could be used to clear the high bytes too but it's not needed here.)
//
// The bytes [16] to [47] are for left shifts.
// The bytes [32] to [63] are for right shifts.
alignas(64)
static uint8_t vmasks[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
/*
// These functions were used to generate the constants
// at the top of crc32_arch_optimized().
static uint64_t
calc_lo(uint64_t p, uint64_t a, int n)
// *Unaligned* 128-bit load
crc_attr_target
static inline __m128i
my_load128(const uint8_t *p)
{
uint64_t b = 0; int i;
for (i = 0; i < n; i++) {
b = b >> 1 | (a & 1) << (n - 1);
a = (a >> 1) ^ ((0 - (a & 1)) & p);
}
return b;
return _mm_loadu_si128((const __m128i *)p);
}
// same as ~crc(&a, sizeof(a), ~0)
static uint64_t
calc_hi(uint64_t p, uint64_t a, int n)
// Keep the highest "count" bytes as is and clear the remaining low bytes.
crc_attr_target
static inline __m128i
keep_high_bytes(__m128i v, size_t count)
{
int i;
for (i = 0; i < n; i++)
a = (a >> 1) ^ ((0 - (a & 1)) & p);
return a;
return _mm_and_si128(my_load128((vmasks + count)), v);
}
// Shift the 128-bit value left by "amount" bytes (not bits).
crc_attr_target
static inline __m128i
shift_left(__m128i v, size_t amount)
{
return _mm_shuffle_epi8(v, my_load128((vmasks + 32 - amount)));
}
// Shift the 128-bit value right by "amount" bytes (not bits).
crc_attr_target
static inline __m128i
shift_right(__m128i v, size_t amount)
{
return _mm_shuffle_epi8(v, my_load128((vmasks + 32 + amount)));
}
*/
#ifdef BUILDING_CRC32_CLMUL
crc_attr_target
crc_attr_no_sanitize_address
static inline __m128i
fold(__m128i v, __m128i k)
{
__m128i a = _mm_clmulepi64_si128(v, k, 0x00);
__m128i b = _mm_clmulepi64_si128(v, k, 0x11);
return _mm_xor_si128(a, b);
}
crc_attr_target
static inline __m128i
fold_xor(__m128i v, __m128i k, const uint8_t *buf)
{
return _mm_xor_si128(my_load128(buf), fold(v, k));
}
#if BUILDING_CRC_CLMUL == 32
crc_attr_target
static uint32_t
crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
{
#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
// The code assumes that there is at least one byte of input.
if (size == 0)
return crc;
#endif
// uint32_t poly = 0xedb88320;
const int64_t p = 0x1db710640; // p << 1
const int64_t mu = 0x1f7011641; // calc_lo(p, p, 32) << 1 | 1
const int64_t k5 = 0x163cd6124; // calc_hi(p, p, 32) << 1
const int64_t k4 = 0x0ccaa009e; // calc_hi(p, p, 64) << 1
const int64_t k3 = 0x1751997d0; // calc_hi(p, p, 128) << 1
const __m128i vfold4 = _mm_set_epi64x(mu, p);
const __m128i vfold8 = _mm_set_epi64x(0, k5);
const __m128i vfold16 = _mm_set_epi64x(k4, k3);
__m128i v0, v1, v2;
crc_simd_body(buf, size, &v0, &v1, vfold16,
_mm_cvtsi32_si128((int32_t)~crc));
v1 = _mm_xor_si128(
_mm_clmulepi64_si128(v0, vfold16, 0x10), v1); // xxx0
v2 = _mm_shuffle_epi32(v1, 0xe7); // 0xx0
v0 = _mm_slli_epi64(v1, 32); // [0]
v0 = _mm_clmulepi64_si128(v0, vfold8, 0x00);
v0 = _mm_xor_si128(v0, v2); // [1] [2]
v2 = _mm_clmulepi64_si128(v0, vfold4, 0x10);
v2 = _mm_clmulepi64_si128(v2, vfold4, 0x00);
v0 = _mm_xor_si128(v0, v2); // [2]
return ~(uint32_t)_mm_extract_epi32(v0, 2);
}
#endif // BUILDING_CRC32_CLMUL
/////////////////////
// x86 CLMUL CRC64 //
/////////////////////
/*
// These functions were used to generate the constants
// at the top of crc64_arch_optimized().
static uint64_t
calc_lo(uint64_t poly)
{
uint64_t a = poly;
uint64_t b = 0;
for (unsigned i = 0; i < 64; ++i) {
b = (b >> 1) | (a << 63);
a = (a >> 1) ^ (a & 1 ? poly : 0);
}
return b;
}
static uint64_t
calc_hi(uint64_t poly, uint64_t a)
{
for (unsigned i = 0; i < 64; ++i)
a = (a >> 1) ^ (a & 1 ? poly : 0);
return a;
}
*/
#ifdef BUILDING_CRC64_CLMUL
// MSVC (VS2015 - VS2022) produces bad 32-bit x86 code from the CLMUL CRC
// code when optimizations are enabled (release build). According to the bug
// report, the ebx register is corrupted and the calculated result is wrong.
// Trying to workaround the problem with "__asm mov ebx, ebx" didn't help.
// The following pragma works and performance is still good. x86-64 builds
// and CRC32 CLMUL aren't affected by this problem. The problem does not
// happen in crc_simd_body() either (which is shared with CRC32 CLMUL anyway).
//
// NOTE: Another pragma after crc64_arch_optimized() restores
// the optimizations. If the #if condition here is updated,
// the other one must be updated too.
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
&& defined(_M_IX86)
# pragma optimize("g", off)
#endif
#else
crc_attr_target
crc_attr_no_sanitize_address
static uint64_t
crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc)
#endif
{
#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
// The code assumes that there is at least one byte of input.
// We will assume that there is at least one byte of input.
if (size == 0)
return crc;
// See crc_clmul_consts_gen.c.
#if BUILDING_CRC_CLMUL == 32
const __m128i fold512 = _mm_set_epi64x(0x1d9513d7, 0x8f352d95);
const __m128i fold128 = _mm_set_epi64x(0xccaa009e, 0xae689191);
const __m128i mu_p = _mm_set_epi64x(
(int64_t)0xb4e5b025f7011641, 0x1db710640);
#else
const __m128i fold512 = _mm_set_epi64x(
(int64_t)0x081f6054a7842df4, (int64_t)0x6ae3efbb9dd441f3);
const __m128i fold128 = _mm_set_epi64x(
(int64_t)0xdabe95afc7875f40, (int64_t)0xe05dd497ca393ae4);
const __m128i mu_p = _mm_set_epi64x(
(int64_t)0x9c3e466c172963d5, (int64_t)0x92d8af2baf0e1e84);
#endif
// const uint64_t poly = 0xc96c5795d7870f42; // CRC polynomial
const uint64_t p = 0x92d8af2baf0e1e85; // (poly << 1) | 1
const uint64_t mu = 0x9c3e466c172963d5; // (calc_lo(poly) << 1) | 1
const uint64_t k2 = 0xdabe95afc7875f40; // calc_hi(poly, 1)
const uint64_t k1 = 0xe05dd497ca393ae4; // calc_hi(poly, k2)
__m128i v0, v1, v2, v3;
const __m128i vfold8 = _mm_set_epi64x((int64_t)p, (int64_t)mu);
const __m128i vfold16 = _mm_set_epi64x((int64_t)k2, (int64_t)k1);
crc = ~crc;
__m128i v0, v1, v2;
if (size < 8) {
uint64_t x = crc;
size_t i = 0;
// Checking the bit instead of comparing the size means
// that we don't need to update the size between the steps.
if (size & 4) {
x ^= read32le(buf);
buf += 4;
i = 32;
}
if (size & 2) {
x ^= (uint64_t)read16le(buf) << i;
buf += 2;
i += 16;
}
if (size & 1)
x ^= (uint64_t)*buf << i;
v0 = my_set_low64((int64_t)x);
v0 = shift_left(v0, 8 - size);
} else if (size < 16) {
v0 = my_set_low64((int64_t)(crc ^ read64le(buf)));
// NOTE: buf is intentionally left 8 bytes behind so that
// we can read the last 1-7 bytes with read64le(buf + size).
size -= 8;
// Handling 8-byte input specially is a speed optimization
// as the clmul can be skipped. A branch is also needed to
// avoid a too high shift amount.
if (size > 0) {
const size_t padding = 8 - size;
uint64_t high = read64le(buf + size) >> (padding * 8);
#if defined(__i386__) || defined(_M_IX86)
crc_simd_body(buf, size, &v0, &v1, vfold16,
_mm_set_epi64x(0, (int64_t)~crc));
// Simple but likely not the best code for 32-bit x86.
v0 = _mm_insert_epi32(v0, (int32_t)high, 2);
v0 = _mm_insert_epi32(v0, (int32_t)(high >> 32), 3);
#else
// GCC and Clang would produce good code with _mm_set_epi64x
// but MSVC needs _mm_cvtsi64_si128 on x86-64.
crc_simd_body(buf, size, &v0, &v1, vfold16,
_mm_cvtsi64_si128((int64_t)~crc));
v0 = _mm_insert_epi64(v0, (int64_t)high, 1);
#endif
v1 = _mm_xor_si128(_mm_clmulepi64_si128(v0, vfold16, 0x10), v1);
v0 = _mm_clmulepi64_si128(v1, vfold8, 0x00);
v2 = _mm_clmulepi64_si128(v0, vfold8, 0x10);
v0 = _mm_xor_si128(_mm_xor_si128(v1, _mm_slli_si128(v0, 8)), v2);
v0 = shift_left(v0, padding);
v1 = _mm_srli_si128(v0, 8);
v0 = _mm_clmulepi64_si128(v0, fold128, 0x10);
v0 = _mm_xor_si128(v0, v1);
}
} else {
v0 = my_set_low64((int64_t)crc);
// To align or not to align the buf pointer? If the end of
// the buffer isn't aligned, aligning the pointer here would
// make us do an extra folding step with the associated byte
// shuffling overhead. The cost of that would need to be
// lower than the benefit of aligned reads. Testing on an old
// Intel Ivy Bridge processor suggested that aligning isn't
// worth the cost but it likely depends on the processor and
// buffer size. Unaligned loads (MOVDQU) should be fast on
// x86 processors that support PCLMULQDQ, so we don't align
// the buf pointer here.
// Read the first (and possibly the only) full 16 bytes.
v0 = _mm_xor_si128(v0, my_load128(buf));
buf += 16;
size -= 16;
if (size >= 48) {
v1 = my_load128(buf);
v2 = my_load128(buf + 16);
v3 = my_load128(buf + 32);
buf += 48;
size -= 48;
while (size >= 64) {
v0 = fold_xor(v0, fold512, buf);
v1 = fold_xor(v1, fold512, buf + 16);
v2 = fold_xor(v2, fold512, buf + 32);
v3 = fold_xor(v3, fold512, buf + 48);
buf += 64;
size -= 64;
}
v0 = _mm_xor_si128(v1, fold(v0, fold128));
v0 = _mm_xor_si128(v2, fold(v0, fold128));
v0 = _mm_xor_si128(v3, fold(v0, fold128));
}
while (size >= 16) {
v0 = fold_xor(v0, fold128, buf);
buf += 16;
size -= 16;
}
if (size > 0) {
// We want the last "size" number of input bytes to
// be at the high bits of v1. First do a full 16-byte
// load and then mask the low bytes to zeros.
v1 = my_load128(buf + size - 16);
v1 = keep_high_bytes(v1, size);
// Shift high bytes from v0 to the low bytes of v1.
//
// Alternatively we could replace the combination
// keep_high_bytes + shift_right + _mm_or_si128 with
// _mm_shuffle_epi8 + _mm_blendv_epi8 but that would
// require larger tables for the masks. Now there are
// three loads (instead of two) from the mask tables
// but they all are from the same cache line.
v1 = _mm_or_si128(v1, shift_right(v0, size));
// Shift high bytes of v0 away, padding the
// low bytes with zeros.
v0 = shift_left(v0, 16 - size);
v0 = _mm_xor_si128(v1, fold(v0, fold128));
}
v1 = _mm_srli_si128(v0, 8);
v0 = _mm_clmulepi64_si128(v0, fold128, 0x10);
v0 = _mm_xor_si128(v0, v1);
}
// Barrett reduction
#if BUILDING_CRC_CLMUL == 32
v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu
v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p
v0 = _mm_xor_si128(v0, v1);
return ~(uint32_t)_mm_extract_epi32(v0, 2);
#else
// Because p is 65 bits but one bit doesn't fit into the 64-bit
// half of __m128i, finish the second clmul by shifting v1 left
// by 64 bits and xorring it to the final result.
v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu
v2 = _mm_slli_si128(v1, 8);
v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p
v0 = _mm_xor_si128(v0, v2);
v0 = _mm_xor_si128(v0, v1);
#if defined(__i386__) || defined(_M_IX86)
return ~(((uint64_t)(uint32_t)_mm_extract_epi32(v0, 3) << 32) |
(uint64_t)(uint32_t)_mm_extract_epi32(v0, 2));
#else
return ~(uint64_t)_mm_extract_epi64(v0, 1);
#endif
}
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
&& defined(_M_IX86)
# pragma optimize("", on)
#endif
#endif // BUILDING_CRC64_CLMUL
}
// Even though this is an inline function, compile it only when needed.
@@ -134,8 +134,7 @@ alone_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->pos = 0;
coder->sequence = SEQ_CODER_INIT;
// Fall through
FALLTHROUGH;
case SEQ_CODER_INIT: {
if (coder->memusage > coder->memlimit)
+2 -3
View File
@@ -79,7 +79,7 @@ auto_decode(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_GET_CHECK;
}
// Fall through
FALLTHROUGH;
case SEQ_CODE: {
const lzma_ret ret = coder->next.code(
@@ -91,10 +91,9 @@ auto_decode(void *coder_ptr, const lzma_allocator *allocator,
return ret;
coder->sequence = SEQ_FINISH;
FALLTHROUGH;
}
// Fall through
case SEQ_FINISH:
// When LZMA_CONCATENATED was used and we were decoding
// a LZMA_Alone file, we need to check that there is no
@@ -146,10 +146,9 @@ block_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->block->uncompressed_size = coder->uncompressed_size;
coder->sequence = SEQ_PADDING;
FALLTHROUGH;
}
// Fall through
case SEQ_PADDING:
// Compressed Data is padded to a multiple of four bytes.
while (coder->compressed_size & 3) {
@@ -173,8 +172,7 @@ block_decode(void *coder_ptr, const lzma_allocator *allocator,
lzma_check_finish(&coder->check, coder->block->check);
coder->sequence = SEQ_CHECK;
// Fall through
FALLTHROUGH;
case SEQ_CHECK: {
const size_t check_size = lzma_check_size(coder->block->check);
@@ -94,10 +94,9 @@ block_encode(void *coder_ptr, const lzma_allocator *allocator,
coder->block->uncompressed_size = coder->uncompressed_size;
coder->sequence = SEQ_PADDING;
FALLTHROUGH;
}
// Fall through
case SEQ_PADDING:
// Pad Compressed Data to a multiple of four bytes. We can
// use coder->compressed_size for this since we don't need
@@ -117,8 +116,7 @@ block_encode(void *coder_ptr, const lzma_allocator *allocator,
lzma_check_finish(&coder->check, coder->block->check);
coder->sequence = SEQ_CHECK;
// Fall through
FALLTHROUGH;
case SEQ_CHECK: {
const size_t check_size = lzma_check_size(coder->block->check);
+7 -1
View File
@@ -96,6 +96,12 @@ lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size)
{
assert(in != NULL || *in_pos == in_size);
assert(out != NULL || *out_pos == out_size);
assert(*in_pos <= in_size);
assert(*out_pos <= out_size);
const size_t in_avail = in_size - *in_pos;
const size_t out_avail = out_size - *out_pos;
const size_t copy_size = my_min(in_avail, out_avail);
@@ -348,7 +354,7 @@ lzma_code(lzma_stream *strm, lzma_action action)
else
strm->internal->sequence = ISEQ_END;
// Fall through
FALLTHROUGH;
case LZMA_NO_CHECK:
case LZMA_UNSUPPORTED_CHECK:
+9 -13
View File
@@ -298,15 +298,13 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
// Start looking for Stream Padding and Stream Footer
// at the end of the file.
coder->file_target_pos = coder->file_size;
// Fall through
FALLTHROUGH;
case SEQ_PADDING_SEEK:
coder->sequence = SEQ_PADDING_DECODE;
return_if_error(reverse_seek(
coder, in_start, in_pos, in_size));
// Fall through
FALLTHROUGH;
case SEQ_PADDING_DECODE: {
// Copy to coder->temp first. This keeps the code simpler if
@@ -356,9 +354,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
if (coder->temp_size < LZMA_STREAM_HEADER_SIZE)
return_if_error(reverse_seek(
coder, in_start, in_pos, in_size));
}
// Fall through
FALLTHROUGH;
}
case SEQ_FOOTER:
// Copy the Stream Footer field into coder->temp.
@@ -414,7 +412,7 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_SEEK_NEEDED;
}
// Fall through
FALLTHROUGH;
case SEQ_INDEX_INIT: {
// Calculate the amount of memory already used by the earlier
@@ -444,10 +442,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->index_remaining = coder->footer_flags.backward_size;
coder->sequence = SEQ_INDEX_DECODE;
FALLTHROUGH;
}
// Fall through
case SEQ_INDEX_DECODE: {
// Decode (a part of) the Index. If the whole Index is already
// in coder->temp, read it from there. Otherwise read from
@@ -574,9 +571,9 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
return_if_error(reverse_seek(coder,
in_start, in_pos, in_size));
}
}
// Fall through
FALLTHROUGH;
}
case SEQ_HEADER_DECODE:
// Copy the Stream Header field into coder->temp.
@@ -596,8 +593,7 @@ file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->temp + coder->temp_size)));
coder->sequence = SEQ_HEADER_COMPARE;
// Fall through
FALLTHROUGH;
case SEQ_HEADER_COMPARE:
// Compare Stream Header against Stream Footer. They must
@@ -93,8 +93,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->pos = 0;
coder->sequence = SEQ_MEMUSAGE;
// Fall through
FALLTHROUGH;
case SEQ_MEMUSAGE:
if (lzma_index_memusage(1, coder->count) > coder->memlimit) {
@@ -153,8 +152,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator,
case SEQ_PADDING_INIT:
coder->pos = lzma_index_padding_size(coder->index);
coder->sequence = SEQ_PADDING;
// Fall through
FALLTHROUGH;
case SEQ_PADDING:
if (coder->pos > 0) {
@@ -170,8 +168,7 @@ index_decode(void *coder_ptr, const lzma_allocator *allocator,
*in_pos - in_start, coder->crc32);
coder->sequence = SEQ_CRC32;
// Fall through
FALLTHROUGH;
case SEQ_CRC32:
do {
@@ -93,8 +93,7 @@ index_encode(void *coder_ptr,
}
coder->sequence = SEQ_UNPADDED;
// Fall through
FALLTHROUGH;
case SEQ_UNPADDED:
case SEQ_UNCOMPRESSED: {
@@ -127,8 +126,7 @@ index_encode(void *coder_ptr,
*out_pos - out_start, coder->crc32);
coder->sequence = SEQ_CRC32;
// Fall through
FALLTHROUGH;
case SEQ_CRC32:
// We don't use the main loop, because we don't want
+3 -4
View File
@@ -267,9 +267,9 @@ lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in,
index_hash->pos = (LZMA_VLI_C(4) - index_size_unpadded(
index_hash->records.count,
index_hash->records.index_list_size)) & 3;
index_hash->sequence = SEQ_PADDING;
// Fall through
index_hash->sequence = SEQ_PADDING;
FALLTHROUGH;
case SEQ_PADDING:
if (index_hash->pos > 0) {
@@ -302,8 +302,7 @@ lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in,
*in_pos - in_start, index_hash->crc32);
index_hash->sequence = SEQ_CRC32;
// Fall through
FALLTHROUGH;
case SEQ_CRC32:
do {
+5 -9
View File
@@ -150,10 +150,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->member_size = sizeof(lzip_id_string);
coder->sequence = SEQ_VERSION;
FALLTHROUGH;
}
// Fall through
case SEQ_VERSION:
if (*in_pos >= in_size)
return LZMA_OK;
@@ -173,7 +172,7 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
if (coder->tell_any_check)
return LZMA_GET_CHECK;
// Fall through
FALLTHROUGH;
case SEQ_DICT_SIZE: {
if (*in_pos >= in_size)
@@ -220,10 +219,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
// LZMA_MEMLIMIT_ERROR we need to be able to restart after
// the memlimit has been increased.
coder->sequence = SEQ_CODER_INIT;
FALLTHROUGH;
}
// Fall through
case SEQ_CODER_INIT: {
if (coder->memusage > coder->memlimit)
return LZMA_MEMLIMIT_ERROR;
@@ -243,10 +241,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->crc32 = 0;
coder->sequence = SEQ_LZMA_STREAM;
FALLTHROUGH;
}
// Fall through
case SEQ_LZMA_STREAM: {
const size_t in_start = *in_pos;
const size_t out_start = *out_pos;
@@ -273,10 +270,9 @@ lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
return ret;
coder->sequence = SEQ_MEMBER_FOOTER;
FALLTHROUGH;
}
// Fall through
case SEQ_MEMBER_FOOTER: {
// The footer of .lz version 0 lacks the Member size field.
// This is the only difference between version 0 and
+8 -4
View File
@@ -58,15 +58,13 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
&& (((TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) \
&& (defined(__x86_64__) \
|| defined(__aarch64__))) \
&& SIZE_MAX == UINT64_MAX) \
|| (defined(__INTEL_COMPILER) && defined(__x86_64__)) \
|| (defined(__INTEL_COMPILER) && defined(_M_X64)) \
|| (defined(_MSC_VER) && (defined(_M_X64) \
|| defined(_M_ARM64) || defined(_M_ARM64EC))))
// This is only for x86-64 and ARM64 for now. This might be fine on
// other 64-bit processors too. On big endian one should use xor
// instead of subtraction and switch to __builtin_clzll().
// other 64-bit processors too.
//
// Reasons to use subtraction instead of xor:
//
@@ -82,7 +80,11 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
// version 2023-05-26. https://www.agner.org/optimize/
#define LZMA_MEMCMPLEN_EXTRA 8
while (len < limit) {
# ifdef WORDS_BIGENDIAN
const uint64_t x = read64ne(buf1 + len) ^ read64ne(buf2 + len);
# else
const uint64_t x = read64ne(buf1 + len) - read64ne(buf2 + len);
# endif
if (x != 0) {
// MSVC or Intel C compiler on Windows
# if defined(_MSC_VER) || defined(__INTEL_COMPILER)
@@ -90,6 +92,8 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
_BitScanForward64(&tmp, x);
len += (uint32_t)tmp >> 3;
// GCC, Clang, or Intel C compiler
# elif defined(WORDS_BIGENDIAN)
len += (uint32_t)__builtin_clzll(x) >> 3;
# else
len += (uint32_t)__builtin_ctzll(x) >> 3;
# endif
+6 -10
View File
@@ -154,9 +154,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator,
if (coder->tell_any_check)
return LZMA_GET_CHECK;
}
// Fall through
FALLTHROUGH;
}
case SEQ_BLOCK_HEADER: {
if (*in_pos >= in_size)
@@ -187,10 +187,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator,
coder->pos = 0;
coder->sequence = SEQ_BLOCK_INIT;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_INIT: {
// Checking memusage and doing the initialization needs
// its own sequence point because we need to be able to
@@ -252,10 +251,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator,
return ret;
coder->sequence = SEQ_BLOCK_RUN;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_RUN: {
const lzma_ret ret = coder->block_decoder.code(
coder->block_decoder.coder, allocator,
@@ -291,10 +289,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator,
return ret;
coder->sequence = SEQ_STREAM_FOOTER;
FALLTHROUGH;
}
// Fall through
case SEQ_STREAM_FOOTER: {
// Copy the Stream Footer to the internal buffer.
lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
@@ -331,10 +328,9 @@ stream_decode(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_STREAM_END;
coder->sequence = SEQ_STREAM_PADDING;
FALLTHROUGH;
}
// Fall through
case SEQ_STREAM_PADDING:
assert(coder->concatenated);
@@ -23,15 +23,10 @@ typedef enum {
THR_IDLE,
/// Decoding is in progress.
/// Main thread may change this to THR_STOP or THR_EXIT.
/// Main thread may change this to THR_IDLE or THR_EXIT.
/// The worker thread may change this to THR_IDLE.
THR_RUN,
/// The main thread wants the thread to stop whatever it was doing
/// but not exit. Main thread may change this to THR_EXIT.
/// The worker thread may change this to THR_IDLE.
THR_STOP,
/// The main thread wants the thread to exit.
THR_EXIT,
@@ -346,27 +341,6 @@ worker_enable_partial_update(void *thr_ptr)
}
/// Things do to at THR_STOP or when finishing a Block.
/// This is called with thr->mutex locked.
static void
worker_stop(struct worker_thread *thr)
{
// Update memory usage counters.
thr->coder->mem_in_use -= thr->in_size;
thr->in_size = 0; // thr->in was freed above.
thr->coder->mem_in_use -= thr->mem_filters;
thr->coder->mem_cached += thr->mem_filters;
// Put this thread to the stack of free threads.
thr->next = thr->coder->threads_free;
thr->coder->threads_free = thr;
mythread_cond_signal(&thr->coder->cond);
return;
}
static MYTHREAD_RET_TYPE
worker_decoder(void *thr_ptr)
{
@@ -397,17 +371,6 @@ next_loop_unlocked:
return MYTHREAD_RET_VALUE;
}
if (thr->state == THR_STOP) {
thr->state = THR_IDLE;
mythread_mutex_unlock(&thr->mutex);
mythread_sync(thr->coder->mutex) {
worker_stop(thr);
}
goto next_loop_lock;
}
assert(thr->state == THR_RUN);
// Update progress info for get_progress().
@@ -472,8 +435,7 @@ next_loop_unlocked:
}
// Either we finished successfully (LZMA_STREAM_END) or an error
// occurred. Both cases are handled almost identically. The error
// case requires updating thr->coder->thread_error.
// occurred.
//
// The sizes are in the Block Header and the Block decoder
// checks that they match, thus we know these:
@@ -481,16 +443,30 @@ next_loop_unlocked:
assert(ret != LZMA_STREAM_END
|| thr->out_pos == thr->block_options.uncompressed_size);
// Free the input buffer. Don't update in_size as we need
// it later to update thr->coder->mem_in_use.
lzma_free(thr->in, thr->allocator);
thr->in = NULL;
mythread_sync(thr->mutex) {
// Block decoder ensures this, but do a sanity check anyway
// because thr->in_filled < thr->in_size means that the main
// thread is still writing to thr->in.
if (ret == LZMA_STREAM_END && thr->in_filled != thr->in_size) {
assert(0);
ret = LZMA_PROG_ERROR;
}
if (thr->state != THR_EXIT)
thr->state = THR_IDLE;
}
// Free the input buffer. Don't update in_size as we need
// it later to update thr->coder->mem_in_use.
//
// This step is skipped if an error occurred because the main thread
// might still be writing to thr->in. The memory will be freed after
// threads_end() sets thr->state = THR_EXIT.
if (ret == LZMA_STREAM_END) {
lzma_free(thr->in, thr->allocator);
thr->in = NULL;
}
mythread_sync(thr->coder->mutex) {
// Move our progress info to the main thread.
thr->coder->progress_in += thr->in_pos;
@@ -510,7 +486,20 @@ next_loop_unlocked:
&& thr->coder->thread_error == LZMA_OK)
thr->coder->thread_error = ret;
worker_stop(thr);
// Return the worker thread to the stack of available
// threads only if no errors occurred.
if (ret == LZMA_STREAM_END) {
// Update memory usage counters.
thr->coder->mem_in_use -= thr->in_size;
thr->coder->mem_in_use -= thr->mem_filters;
thr->coder->mem_cached += thr->mem_filters;
// Put this thread to the stack of free threads.
thr->next = thr->coder->threads_free;
thr->coder->threads_free = thr;
}
mythread_cond_signal(&thr->coder->cond);
}
goto next_loop_lock;
@@ -544,17 +533,22 @@ threads_end(struct lzma_stream_coder *coder, const lzma_allocator *allocator)
}
/// Tell worker threads to stop without doing any cleaning up.
/// The clean up will be done when threads_exit() is called;
/// it's not possible to reuse the threads after threads_stop().
///
/// This is called before returning an unrecoverable error code
/// to the application. It would be waste of processor time
/// to keep the threads running in such a situation.
static void
threads_stop(struct lzma_stream_coder *coder)
{
for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
// The threads that are in the THR_RUN state will stop
// when they check the state the next time. There's no
// need to signal coder->threads[i].cond.
mythread_sync(coder->threads[i].mutex) {
// The state must be changed conditionally because
// THR_IDLE -> THR_STOP is not a valid state change.
if (coder->threads[i].state != THR_IDLE) {
coder->threads[i].state = THR_STOP;
mythread_cond_signal(&coder->threads[i].cond);
}
coder->threads[i].state = THR_IDLE;
}
}
@@ -1077,9 +1071,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
if (coder->tell_any_check)
return LZMA_GET_CHECK;
}
// Fall through
FALLTHROUGH;
}
case SEQ_BLOCK_HEADER: {
const size_t in_old = *in_pos;
@@ -1214,10 +1208,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
}
coder->sequence = SEQ_BLOCK_INIT;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_INIT: {
// Check if decoding is possible at all with the current
// memlimit_stop which we must never exceed.
@@ -1303,10 +1296,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
}
coder->sequence = SEQ_BLOCK_THR_INIT;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_THR_INIT: {
// We need to wait for a multiple conditions to become true
// until we can initialize the Block decoder and let a worker
@@ -1508,10 +1500,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
}
coder->sequence = SEQ_BLOCK_THR_RUN;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_THR_RUN: {
if (action == LZMA_FINISH && coder->fail_fast) {
// We know that we won't get more input and that
@@ -1549,10 +1540,17 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
// Read output from the output queue. Just like in
// SEQ_BLOCK_HEADER, we wait to fill the output buffer
// only if waiting_allowed was set to true in the beginning
// of this function (see the comment there).
// of this function (see the comment there) and there is
// no input available. In SEQ_BLOCK_HEADER, there is never
// input available when read_output_and_wait() is called,
// but here there can be when LZMA_FINISH is used, thus we
// need to check if *in_pos == in_size. Otherwise we would
// wait here instead of using the available input to start
// a new thread.
return_if_error(read_output_and_wait(coder, allocator,
out, out_pos, out_size,
NULL, waiting_allowed,
NULL,
waiting_allowed && *in_pos == in_size,
&wait_abs, &has_blocked));
if (coder->pending_error != LZMA_OK) {
@@ -1561,6 +1559,10 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
}
// Return if the input didn't contain the whole Block.
//
// NOTE: When we updated coder->thr->in_filled a few lines
// above, the worker thread might by now have finished its
// work and returned itself back to the stack of free threads.
if (coder->thr->in_filled < coder->thr->in_size) {
assert(*in_pos == in_size);
return LZMA_OK;
@@ -1613,10 +1615,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
coder->mem_direct_mode = coder->mem_next_filters;
coder->sequence = SEQ_BLOCK_DIRECT_RUN;
FALLTHROUGH;
}
// Fall through
case SEQ_BLOCK_DIRECT_RUN: {
const size_t in_old = *in_pos;
const size_t out_old = *out_pos;
@@ -1652,8 +1653,7 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_OK;
coder->sequence = SEQ_INDEX_DECODE;
// Fall through
FALLTHROUGH;
case SEQ_INDEX_DECODE: {
// If we don't have any input, don't call
@@ -1672,10 +1672,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
return ret;
coder->sequence = SEQ_STREAM_FOOTER;
FALLTHROUGH;
}
// Fall through
case SEQ_STREAM_FOOTER: {
// Copy the Stream Footer to the internal buffer.
const size_t in_old = *in_pos;
@@ -1714,10 +1713,9 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_STREAM_END;
coder->sequence = SEQ_STREAM_PADDING;
FALLTHROUGH;
}
// Fall through
case SEQ_STREAM_PADDING:
assert(coder->concatenated);
@@ -1948,7 +1946,7 @@ stream_decoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
// accounting from scratch, too. Changes in filter and block sizes may
// affect number of threads.
//
// FIXME? Reusing should be easy but unlike the single-threaded
// Reusing threads doesn't seem worth it. Unlike the single-threaded
// decoder, with some types of input file combinations reusing
// could leave quite a lot of memory allocated but unused (first
// file could allocate a lot, the next files could use fewer
@@ -731,8 +731,7 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator,
coder->header_pos = 0;
coder->sequence = SEQ_BLOCK;
// Fall through
FALLTHROUGH;
case SEQ_BLOCK: {
// Initialized to silence warnings.
@@ -851,9 +850,9 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator,
// to be ready to be copied out.
coder->progress_out += lzma_index_size(coder->index)
+ LZMA_STREAM_HEADER_SIZE;
}
// Fall through
FALLTHROUGH;
}
case SEQ_INDEX: {
// Call the Index encoder. It doesn't take any input, so
@@ -873,10 +872,9 @@ stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator,
return LZMA_PROG_ERROR;
coder->sequence = SEQ_STREAM_FOOTER;
FALLTHROUGH;
}
// Fall through
case SEQ_STREAM_FOOTER:
lzma_bufcpy(coder->header, &coder->header_pos,
sizeof(coder->header),
@@ -12,6 +12,11 @@
#include "filter_common.h"
// liblzma itself doesn't use gettext to translate messages.
// Mark the strings still so that xz can translate them.
#define N_(msgid) msgid
/////////////////////
// String building //
/////////////////////
@@ -317,6 +322,10 @@ parse_lzma12_preset(const char **const str, const char *str_end,
uint32_t *preset)
{
assert(*str < str_end);
if (!(**str >= '0' && **str <= '9'))
return N_("Unsupported preset");
*preset = (uint32_t)(**str - '0');
// NOTE: Remember to update LZMA12_PRESET_STR if this is modified!
@@ -327,7 +336,7 @@ parse_lzma12_preset(const char **const str, const char *str_end,
break;
default:
return "Unsupported preset flag";
return N_("Unsupported flag in the preset");
}
}
@@ -346,7 +355,7 @@ set_lzma12_preset(const char **const str, const char *str_end,
lzma_options_lzma *opts = filter_options;
if (lzma_lzma_preset(opts, preset))
return "Unsupported preset";
return N_("Unsupported preset");
return NULL;
}
@@ -438,7 +447,7 @@ parse_lzma12(const char **const str, const char *str_end, void *filter_options)
return errmsg;
if (opts->lc + opts->lp > LZMA_LCLP_MAX)
return "The sum of lc and lp must not exceed 4";
return N_("The sum of lc and lp must not exceed 4");
return NULL;
}
@@ -574,21 +583,21 @@ parse_options(const char **const str, const char *str_end,
// Fail if the '=' wasn't found or the option name is missing
// (the first char is '=').
if (equals_sign == NULL || **str == '=')
return "Options must be 'name=value' pairs separated "
"with commas";
return N_("Options must be 'name=value' pairs "
"separated with commas");
// Reject a too long option name so that the memcmp()
// in the loop below won't read past the end of the
// string in optmap[i].name.
const size_t name_len = (size_t)(equals_sign - *str);
if (name_len > NAME_LEN_MAX)
return "Unknown option name";
return N_("Unknown option name");
// Find the option name from optmap[].
size_t i = 0;
while (true) {
if (i == optmap_size)
return "Unknown option name";
return N_("Unknown option name");
if (memcmp(*str, optmap[i].name, name_len) == 0
&& optmap[i].name[name_len] == '\0')
@@ -605,7 +614,7 @@ parse_options(const char **const str, const char *str_end,
// string so check it here.
const size_t value_len = (size_t)(name_eq_value_end - *str);
if (value_len == 0)
return "Option value cannot be empty";
return N_("Option value cannot be empty");
// LZMA1/2 preset has its own parsing function.
if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) {
@@ -626,14 +635,14 @@ parse_options(const char **const str, const char *str_end,
// in the loop below won't read past the end of the
// string in optmap[i].u.map[j].name.
if (value_len > NAME_LEN_MAX)
return "Invalid option value";
return N_("Invalid option value");
const name_value_map *map = optmap[i].u.map;
size_t j = 0;
while (true) {
// The array is terminated with an empty name.
if (map[j].name[0] == '\0')
return "Invalid option value";
return N_("Invalid option value");
if (memcmp(*str, map[j].name, value_len) == 0
&& map[j].name[value_len]
@@ -647,7 +656,8 @@ parse_options(const char **const str, const char *str_end,
} else if (**str < '0' || **str > '9') {
// Note that "max" isn't supported while it is
// supported in xz. It's not useful here.
return "Value is not a non-negative decimal integer";
return N_("Value is not a non-negative "
"decimal integer");
} else {
// strtoul() has locale-specific behavior so it cannot
// be relied on to get reproducible results since we
@@ -661,13 +671,13 @@ parse_options(const char **const str, const char *str_end,
v = 0;
do {
if (v > UINT32_MAX / 10)
return "Value out of range";
return N_("Value out of range");
v *= 10;
const uint32_t add = (uint32_t)(*p - '0');
if (UINT32_MAX - add < v)
return "Value out of range";
return N_("Value out of range");
v += add;
++p;
@@ -692,8 +702,9 @@ parse_options(const char **const str, const char *str_end,
if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX)
== 0) {
*str = multiplier_start;
return "This option does not support "
"any integer suffixes";
return N_("This option does not "
"support any multiplier "
"suffixes");
}
uint32_t shift;
@@ -716,8 +727,13 @@ parse_options(const char **const str, const char *str_end,
default:
*str = multiplier_start;
return "Invalid multiplier suffix "
"(KiB, MiB, or GiB)";
// TRANSLATORS: Don't translate the
// suffixes "KiB", "MiB", or "GiB"
// because a user can only specify
// untranslated suffixes.
return N_("Invalid multiplier suffix "
"(KiB, MiB, or GiB)");
}
++p;
@@ -736,19 +752,19 @@ parse_options(const char **const str, const char *str_end,
// Now we must have no chars remaining.
if (p < name_eq_value_end) {
*str = multiplier_start;
return "Invalid multiplier suffix "
"(KiB, MiB, or GiB)";
return N_("Invalid multiplier suffix "
"(KiB, MiB, or GiB)");
}
if (v > (UINT32_MAX >> shift))
return "Value out of range";
return N_("Value out of range");
v <<= shift;
}
if (v < optmap[i].u.range.min
|| v > optmap[i].u.range.max)
return "Value out of range";
return N_("Value out of range");
}
// Set the value in filter_options. Enums are handled
@@ -810,15 +826,15 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
// string in filter_name_map[i].name.
const size_t name_len = (size_t)(name_end - *str);
if (name_len > NAME_LEN_MAX)
return "Unknown filter name";
return N_("Unknown filter name");
for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
if (memcmp(*str, filter_name_map[i].name, name_len) == 0
&& filter_name_map[i].name[name_len] == '\0') {
if (only_xz && filter_name_map[i].id
>= LZMA_FILTER_RESERVED_START)
return "This filter cannot be used in "
"the .xz format";
return N_("This filter cannot be used in "
"the .xz format");
// Allocate the filter-specific options and
// initialize the memory with zeros.
@@ -826,7 +842,7 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
filter_name_map[i].opts_size,
allocator);
if (options == NULL)
return "Memory allocation failed";
return N_("Memory allocation failed");
// Filter name was found so the input string is good
// at least this far.
@@ -846,7 +862,7 @@ parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
}
}
return "Unknown filter name";
return N_("Unknown filter name");
}
@@ -865,8 +881,8 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
++*str;
if (**str == '\0')
return "Empty string is not allowed, "
"try \"6\" if a default value is needed";
return N_("Empty string is not allowed, "
"try '6' if a default value is needed");
// Detect the type of the string.
//
@@ -889,7 +905,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
// there are no chars other than spaces.
for (size_t i = 1; str_end[i] != '\0'; ++i)
if (str_end[i] != ' ')
return "Unsupported preset";
return N_("Unsupported preset");
} else {
// There are no trailing spaces. Use the whole string.
str_end = *str + str_len;
@@ -902,11 +918,11 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator);
if (opts == NULL)
return "Memory allocation failed";
return N_("Memory allocation failed");
if (lzma_lzma_preset(opts, preset)) {
lzma_free(opts, allocator);
return "Unsupported preset";
return N_("Unsupported preset");
}
filters[0].id = LZMA_FILTER_LZMA2;
@@ -930,7 +946,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
size_t i = 0;
do {
if (i == LZMA_FILTERS_MAX) {
errmsg = "The maximum number of filters is four";
errmsg = N_("The maximum number of filters is four");
goto error;
}
@@ -952,7 +968,7 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
// Inputs that have "--" at the end or "-- " in the middle
// will result in an empty filter name.
if (filter_end == *str) {
errmsg = "Filter name is missing";
errmsg = N_("Filter name is missing");
goto error;
}
@@ -979,8 +995,8 @@ str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
const lzma_ret ret = lzma_validate_chain(temp_filters, &dummy);
assert(ret == LZMA_OK || ret == LZMA_OPTIONS_ERROR);
if (ret != LZMA_OK) {
errmsg = "Invalid filter chain "
"('lzma2' missing at the end?)";
errmsg = N_("Invalid filter chain "
"('lzma2' missing at the end?)");
goto error;
}
}
@@ -1008,17 +1024,26 @@ lzma_str_to_filters(const char *str, int *error_pos, lzma_filter *filters,
if (error_pos != NULL)
*error_pos = 0;
if (str == NULL || filters == NULL)
if (str == NULL || filters == NULL) {
// Don't translate this because it's only shown in case of
// a programming error.
return "Unexpected NULL pointer argument(s) "
"to lzma_str_to_filters()";
}
// Validate the flags.
const uint32_t supported_flags
= LZMA_STR_ALL_FILTERS
| LZMA_STR_NO_VALIDATION;
if (flags & ~supported_flags)
if (flags & ~supported_flags) {
// This message is possible only if the caller uses flags
// that are only supported in a newer liblzma version (or
// the flags are simply buggy). Don't translate this at least
// when liblzma itself doesn't use gettext; xz and liblzma
// are usually upgraded at the same time.
return "Unsupported flags to lzma_str_to_filters()";
}
const char *used = str;
const char *errmsg = str_to_filters(&used, filters, flags, allocator);
@@ -126,3 +126,13 @@ XZ_5.6.0 {
global:
lzma_mt_block_size;
} XZ_5.4;
XZ_5.8 {
global:
lzma_bcj_arm64_encode;
lzma_bcj_arm64_decode;
lzma_bcj_riscv_encode;
lzma_bcj_riscv_decode;
lzma_bcj_x86_encode;
lzma_bcj_x86_decode;
} XZ_5.6.0;
+10
View File
@@ -141,3 +141,13 @@ XZ_5.6.0 {
global:
lzma_mt_block_size;
} XZ_5.4;
XZ_5.8 {
global:
lzma_bcj_arm64_encode;
lzma_bcj_arm64_decode;
lzma_bcj_riscv_encode;
lzma_bcj_riscv_decode;
lzma_bcj_x86_encode;
lzma_bcj_x86_decode;
} XZ_5.6.0;
+15 -6
View File
@@ -53,9 +53,9 @@ typedef struct {
static void
lz_decoder_reset(lzma_coder *coder)
{
coder->dict.pos = 2 * LZ_DICT_REPEAT_MAX;
coder->dict.pos = LZ_DICT_INIT_POS;
coder->dict.full = 0;
coder->dict.buf[2 * LZ_DICT_REPEAT_MAX - 1] = '\0';
coder->dict.buf[LZ_DICT_INIT_POS - 1] = '\0';
coder->dict.has_wrapped = false;
coder->dict.need_reset = false;
return;
@@ -261,10 +261,12 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
// recommended to give aligned buffers to liblzma.
//
// Reserve 2 * LZ_DICT_REPEAT_MAX bytes of extra space which is
// needed for alloc_size.
// needed for alloc_size. Reserve also LZ_DICT_EXTRA bytes of extra
// space which is *not* counted in alloc_size or coder->dict.size.
//
// Avoid integer overflow.
if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX)
if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX
- LZ_DICT_EXTRA)
return LZMA_MEM_ERROR;
lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));
@@ -277,7 +279,13 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
// Allocate and initialize the dictionary.
if (coder->dict.size != alloc_size) {
lzma_free(coder->dict.buf, allocator);
coder->dict.buf = lzma_alloc(alloc_size, allocator);
// The LZ_DICT_EXTRA bytes at the end of the buffer aren't
// included in alloc_size. These extra bytes allow
// dict_repeat() to read and write more data than requested.
// Otherwise this extra space is ignored.
coder->dict.buf = lzma_alloc(alloc_size + LZ_DICT_EXTRA,
allocator);
if (coder->dict.buf == NULL)
return LZMA_MEM_ERROR;
@@ -320,5 +328,6 @@ lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
extern uint64_t
lzma_lz_decoder_memusage(size_t dictionary_size)
{
return sizeof(lzma_coder) + (uint64_t)(dictionary_size);
return sizeof(lzma_coder) + (uint64_t)(dictionary_size)
+ 2 * LZ_DICT_REPEAT_MAX + LZ_DICT_EXTRA;
}
+89 -14
View File
@@ -15,10 +15,40 @@
#include "common.h"
#ifdef HAVE_IMMINTRIN_H
# include <immintrin.h>
#endif
/// Maximum length of a match rounded up to a nice power of 2 which is
/// a good size for aligned memcpy(). The allocated dictionary buffer will
/// be 2 * LZ_DICT_REPEAT_MAX bytes larger than the actual dictionary size:
// dict_repeat() implementation variant:
// 0 = Byte-by-byte copying only.
// 1 = Use memcpy() for non-overlapping copies.
// 2 = Use x86 SSE2 for non-overlapping copies.
#ifndef LZMA_LZ_DECODER_CONFIG
# if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
&& defined(HAVE_IMMINTRIN_H) \
&& (defined(__SSE2__) || defined(_M_X64) \
|| (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
# define LZMA_LZ_DECODER_CONFIG 2
# else
# define LZMA_LZ_DECODER_CONFIG 1
# endif
#endif
/// Byte-by-byte and memcpy() copy exactly the amount needed. Other methods
/// can copy up to LZ_DICT_EXTRA bytes more than requested, and this amount
/// of extra space is needed at the end of the allocated dictionary buffer.
///
/// NOTE: If this is increased, update LZMA_DICT_REPEAT_MAX too.
#if LZMA_LZ_DECODER_CONFIG >= 2
# define LZ_DICT_EXTRA 32
#else
# define LZ_DICT_EXTRA 0
#endif
/// Maximum number of bytes that dict_repeat() may copy. The allocated
/// dictionary buffer will be 2 * LZ_DICT_REPEAT_MAX + LZMA_DICT_EXTRA bytes
/// larger than the actual dictionary size:
///
/// (1) Every time the decoder reaches the end of the dictionary buffer,
/// the last LZ_DICT_REPEAT_MAX bytes will be copied to the beginning.
@@ -27,14 +57,26 @@
///
/// (2) The other LZ_DICT_REPEAT_MAX bytes is kept as a buffer between
/// the oldest byte still in the dictionary and the current write
/// position. This way dict_repeat(dict, dict->size - 1, &len)
/// position. This way dict_repeat() with the maximum valid distance
/// won't need memmove() as the copying cannot overlap.
///
/// (3) LZ_DICT_EXTRA bytes are required at the end of the dictionary buffer
/// so that extra copying done by dict_repeat() won't write or read past
/// the end of the allocated buffer. This amount is *not* counted as part
/// of lzma_dict.size.
///
/// Note that memcpy() still cannot be used if distance < len.
///
/// LZMA's longest match length is 273 so pick a multiple of 16 above that.
/// LZMA's longest match length is 273 bytes. The LZMA decoder looks at
/// the lowest four bits of the dictionary position, thus 273 must be
/// rounded up to the next multiple of 16 (288). In addition, optimized
/// dict_repeat() copies 32 bytes at a time, thus this must also be
/// a multiple of 32.
#define LZ_DICT_REPEAT_MAX 288
/// Initial position in lzma_dict.buf when the dictionary is empty.
#define LZ_DICT_INIT_POS (2 * LZ_DICT_REPEAT_MAX)
typedef struct {
/// Pointer to the dictionary buffer.
@@ -158,7 +200,8 @@ dict_is_distance_valid(const lzma_dict *const dict, const size_t distance)
/// Repeat *len bytes at distance.
static inline bool
dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
dict_repeat(lzma_dict *restrict dict,
uint32_t distance, uint32_t *restrict len)
{
// Don't write past the end of the dictionary.
const size_t dict_avail = dict->limit - dict->pos;
@@ -169,9 +212,17 @@ dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
if (distance >= dict->pos)
back += dict->size - LZ_DICT_REPEAT_MAX;
// Repeat a block of data from the history. Because memcpy() is faster
// than copying byte by byte in a loop, the copying process gets split
// into two cases.
#if LZMA_LZ_DECODER_CONFIG == 0
// Minimal byte-by-byte method. This might be the least bad choice
// if memcpy() isn't fast and there's no replacement for it below.
while (left-- > 0) {
dict->buf[dict->pos++] = dict->buf[back++];
}
#else
// Because memcpy() or a similar method can be faster than copying
// byte by byte in a loop, the copying process is split into
// two cases.
if (distance < left) {
// Source and target areas overlap, thus we can't use
// memcpy() nor even memmove() safely.
@@ -179,32 +230,56 @@ dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
dict->buf[dict->pos++] = dict->buf[back++];
} while (--left > 0);
} else {
# if LZMA_LZ_DECODER_CONFIG == 1
memcpy(dict->buf + dict->pos, dict->buf + back, left);
dict->pos += left;
# elif LZMA_LZ_DECODER_CONFIG == 2
// This can copy up to 32 bytes more than required.
// (If left == 0, we still copy 32 bytes.)
size_t pos = dict->pos;
dict->pos += left;
do {
const __m128i x0 = _mm_loadu_si128(
(__m128i *)(dict->buf + back));
const __m128i x1 = _mm_loadu_si128(
(__m128i *)(dict->buf + back + 16));
back += 32;
_mm_storeu_si128(
(__m128i *)(dict->buf + pos), x0);
_mm_storeu_si128(
(__m128i *)(dict->buf + pos + 16), x1);
pos += 32;
} while (pos < dict->pos);
# else
# error "Invalid LZMA_LZ_DECODER_CONFIG value"
# endif
}
#endif
// Update how full the dictionary is.
if (!dict->has_wrapped)
dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
dict->full = dict->pos - LZ_DICT_INIT_POS;
return *len != 0;
}
static inline void
dict_put(lzma_dict *dict, uint8_t byte)
dict_put(lzma_dict *restrict dict, uint8_t byte)
{
dict->buf[dict->pos++] = byte;
if (!dict->has_wrapped)
dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
dict->full = dict->pos - LZ_DICT_INIT_POS;
}
/// Puts one byte into the dictionary. Returns true if the dictionary was
/// already full and the byte couldn't be added.
static inline bool
dict_put_safe(lzma_dict *dict, uint8_t byte)
dict_put_safe(lzma_dict *restrict dict, uint8_t byte)
{
if (unlikely(dict->pos == dict->limit))
return true;
@@ -234,7 +309,7 @@ dict_write(lzma_dict *restrict dict, const uint8_t *restrict in,
dict->buf, &dict->pos, dict->limit);
if (!dict->has_wrapped)
dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
dict->full = dict->pos - LZ_DICT_INIT_POS;
return;
}
+1 -1
View File
@@ -15,7 +15,7 @@
// See lz_encoder_hash.h. This is a bit hackish but avoids making
// endianness a conditional in makefiles.
#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
#ifdef LZMA_LZ_HASH_TABLE_IS_NEEDED
# include "lz_encoder_hash_table.h"
#endif
+22 -8
View File
@@ -5,23 +5,37 @@
/// \file lz_encoder_hash.h
/// \brief Hash macros for match finders
//
// Author: Igor Pavlov
// Authors: Igor Pavlov
// Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_LZ_ENCODER_HASH_H
#define LZMA_LZ_ENCODER_HASH_H
#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
// This is to make liblzma produce the same output on big endian
// systems that it does on little endian systems. lz_encoder.c
// takes care of including the actual table.
// We need to know if CRC32_GENERIC is defined and we may need the declaration
// of lzma_crc32_table[][].
#include "crc_common.h"
// If HAVE_SMALL is defined, then lzma_crc32_table[][] exists and
// it's little endian even on big endian systems.
//
// If HAVE_SMALL isn't defined, lzma_crc32_table[][] is in native endian
// but we want a little endian one so that the compressed output won't
// depend on the processor endianness. Big endian systems are less common
// so those get the burden of an extra 1 KiB table.
//
// If HAVE_SMALL isn't defined and CRC32_GENERIC isn't defined either,
// then lzma_crc32_table[][] doesn't exist.
#if defined(HAVE_SMALL) \
|| (defined(CRC32_GENERIC) && !defined(WORDS_BIGENDIAN))
# define hash_table lzma_crc32_table[0]
#else
// lz_encoder.c takes care of including the actual table.
lzma_attr_visibility_hidden
extern const uint32_t lzma_lz_hash_table[256];
# define hash_table lzma_lz_hash_table
#else
# include "check.h"
# define hash_table lzma_crc32_table[0]
# define LZMA_LZ_HASH_TABLE_IS_NEEDED 1
#endif
#define HASH_2_SIZE (UINT32_C(1) << 10)
+3 -6
View File
@@ -159,8 +159,7 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
coder->uncompressed_size = 0;
coder->compressed_size = 0;
coder->sequence = SEQ_LZMA_ENCODE;
// Fall through
FALLTHROUGH;
case SEQ_LZMA_ENCODE: {
// Calculate how much more uncompressed data this chunk
@@ -219,10 +218,9 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
lzma2_header_lzma(coder);
coder->sequence = SEQ_LZMA_COPY;
FALLTHROUGH;
}
// Fall through
case SEQ_LZMA_COPY:
// Copy the compressed chunk along its headers to the
// output buffer.
@@ -244,8 +242,7 @@ lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
return LZMA_OK;
coder->sequence = SEQ_UNCOMPRESSED_COPY;
// Fall through
FALLTHROUGH;
case SEQ_UNCOMPRESSED_COPY:
// Copy the uncompressed data as is from the dictionary
+1 -1
View File
@@ -18,7 +18,7 @@
// The macros unroll loops with switch statements.
// Silence warnings about missing fall-through comments.
#if TUKLIB_GNUC_REQ(7, 0)
#if TUKLIB_GNUC_REQ(7, 0) || defined(__clang__)
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
+3 -1
View File
@@ -18,8 +18,10 @@ arm_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
size &= ~(size_t)3;
size_t i;
for (i = 0; i + 4 <= size; i += 4) {
for (i = 0; i < size; i += 4) {
if (buffer[i + 3] == 0xEB) {
uint32_t src = ((uint32_t)(buffer[i + 2]) << 16)
| ((uint32_t)(buffer[i + 1]) << 8)
+21 -1
View File
@@ -28,6 +28,8 @@ arm64_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
size &= ~(size_t)3;
size_t i;
// Clang 14.0.6 on x86-64 makes this four times bigger and 40 % slower
@@ -37,7 +39,7 @@ arm64_code(void *simple lzma_attribute((__unused__)),
#ifdef __clang__
# pragma clang loop vectorize(disable)
#endif
for (i = 0; i + 4 <= size; i += 4) {
for (i = 0; i < size; i += 4) {
uint32_t pc = (uint32_t)(now_pos + i);
uint32_t instr = read32le(buffer + i);
@@ -122,6 +124,15 @@ lzma_simple_arm64_encoder_init(lzma_next_coder *next,
{
return arm64_coder_init(next, allocator, filters, true);
}
extern LZMA_API(size_t)
lzma_bcj_arm64_encode(uint32_t start_offset, uint8_t *buf, size_t size)
{
// start_offset must be a multiple of four.
start_offset &= ~UINT32_C(3);
return arm64_code(NULL, start_offset, true, buf, size);
}
#endif
@@ -133,4 +144,13 @@ lzma_simple_arm64_decoder_init(lzma_next_coder *next,
{
return arm64_coder_init(next, allocator, filters, false);
}
extern LZMA_API(size_t)
lzma_bcj_arm64_decode(uint32_t start_offset, uint8_t *buf, size_t size)
{
// start_offset must be a multiple of four.
start_offset &= ~UINT32_C(3);
return arm64_code(NULL, start_offset, false, buf, size);
}
#endif
+6 -1
View File
@@ -18,8 +18,13 @@ armthumb_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
if (size < 4)
return 0;
size -= 4;
size_t i;
for (i = 0; i + 4 <= size; i += 2) {
for (i = 0; i <= size; i += 2) {
if ((buffer[i + 1] & 0xF8) == 0xF0
&& (buffer[i + 3] & 0xF8) == 0xF8) {
uint32_t src = (((uint32_t)(buffer[i + 1]) & 7) << 19)
+3 -1
View File
@@ -25,8 +25,10 @@ ia64_code(void *simple lzma_attribute((__unused__)),
4, 4, 0, 0, 4, 4, 0, 0
};
size &= ~(size_t)15;
size_t i;
for (i = 0; i + 16 <= size; i += 16) {
for (i = 0; i < size; i += 16) {
const uint32_t instr_template = buffer[i] & 0x1F;
const uint32_t mask = BRANCH_TABLE[instr_template];
uint32_t bit_pos = 5;
+3 -1
View File
@@ -18,8 +18,10 @@ powerpc_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
size &= ~(size_t)3;
size_t i;
for (i = 0; i + 4 <= size; i += 4) {
for (i = 0; i < size; i += 4) {
// PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
if ((buffer[i] >> 2) == 0x12
&& ((buffer[i + 3] & 3) == 1)) {
+18
View File
@@ -617,6 +617,15 @@ lzma_simple_riscv_encoder_init(lzma_next_coder *next,
return lzma_simple_coder_init(next, allocator, filters,
&riscv_encode, 0, 8, 2, true);
}
extern LZMA_API(size_t)
lzma_bcj_riscv_encode(uint32_t start_offset, uint8_t *buf, size_t size)
{
// start_offset must be a multiple of two.
start_offset &= ~UINT32_C(1);
return riscv_encode(NULL, start_offset, true, buf, size);
}
#endif
@@ -752,4 +761,13 @@ lzma_simple_riscv_decoder_init(lzma_next_coder *next,
return lzma_simple_coder_init(next, allocator, filters,
&riscv_decode, 0, 8, 2, false);
}
extern LZMA_API(size_t)
lzma_bcj_riscv_decode(uint32_t start_offset, uint8_t *buf, size_t size)
{
// start_offset must be a multiple of two.
start_offset &= ~UINT32_C(1);
return riscv_decode(NULL, start_offset, false, buf, size);
}
#endif
+3 -2
View File
@@ -18,9 +18,10 @@ sparc_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
size_t i;
for (i = 0; i + 4 <= size; i += 4) {
size &= ~(size_t)3;
size_t i;
for (i = 0; i < size; i += 4) {
if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00)
|| (buffer[i] == 0x7F
&& (buffer[i + 1] & 0xC0) == 0xC0)) {
+24
View File
@@ -143,6 +143,18 @@ lzma_simple_x86_encoder_init(lzma_next_coder *next,
{
return x86_coder_init(next, allocator, filters, true);
}
extern LZMA_API(size_t)
lzma_bcj_x86_encode(uint32_t start_offset, uint8_t *buf, size_t size)
{
lzma_simple_x86 simple = {
.prev_mask = 0,
.prev_pos = (uint32_t)(-5),
};
return x86_code(&simple, start_offset, true, buf, size);
}
#endif
@@ -154,4 +166,16 @@ lzma_simple_x86_decoder_init(lzma_next_coder *next,
{
return x86_coder_init(next, allocator, filters, false);
}
extern LZMA_API(size_t)
lzma_bcj_x86_decode(uint32_t start_offset, uint8_t *buf, size_t size)
{
lzma_simple_x86 simple = {
.prev_mask = 0,
.prev_pos = (uint32_t)(-5),
};
return x86_code(&simple, start_offset, false, buf, size);
}
#endif
+38 -14
View File
@@ -17,6 +17,8 @@
#include "getopt.h"
#include "tuklib_gettext.h"
#include "tuklib_progname.h"
#include "tuklib_mbstr_nonprint.h"
#include "tuklib_mbstr_wrap.h"
#include "tuklib_exit.h"
#ifdef TUKLIB_DOSLIKE
@@ -29,17 +31,36 @@ tuklib_attr_noreturn
static void
help(void)
{
printf(
_("Usage: %s [--help] [--version] [FILE]...\n"
"Show information stored in the .lzma file header"), progname);
// A few languages use so long strings that we need automatic
// wrapping. A few strings are the same as in xz/message.c and
// should be kept in sync.
static const struct tuklib_wrap_opt wrap0 = { 0, 0, 0, 0, 79 };
int e = 0;
printf(_(
"\nWith no FILE, or when FILE is -, read standard input.\n"));
printf("\n");
printf(_("Usage: %s [--help] [--version] [FILE]...\n"), progname);
printf(_("Report bugs to <%s> (in English or Finnish).\n"),
e |= tuklib_wraps(stdout, &wrap0,
W_("Show information stored in the .lzma file header."));
e |= tuklib_wraps(stdout, &wrap0,
W_("With no FILE, or when FILE is -, read standard input."));
putchar('\n');
e |= tuklib_wrapf(stdout, &wrap0,
W_("Report bugs to <%s> (in English or Finnish)."),
PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
e |= tuklib_wrapf(stdout, &wrap0,
W_("%s home page: <%s>"), PACKAGE_NAME, PACKAGE_URL);
if (e != 0) {
// Avoid new translatable strings by printing the message
// in pieces.
fprintf(stderr, _("%s: "), progname);
fprintf(stderr, _("Error printing the help text "
"(error code %d)"), e);
fprintf(stderr, "\n");
}
tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
}
@@ -104,7 +125,8 @@ lzmainfo(const char *name, FILE *f)
uint8_t buf[13];
const size_t size = fread(buf, 1, sizeof(buf), f);
if (size != 13) {
fprintf(stderr, "%s: %s: %s\n", progname, name,
fprintf(stderr, "%s: %s: %s\n", progname,
tuklib_mask_nonprint(name),
ferror(f) ? strerror(errno)
: _("File is too small to be a .lzma file"));
return true;
@@ -118,7 +140,8 @@ lzmainfo(const char *name, FILE *f)
break;
case LZMA_OPTIONS_ERROR:
fprintf(stderr, "%s: %s: %s\n", progname, name,
fprintf(stderr, "%s: %s: %s\n", progname,
tuklib_mask_nonprint(name),
_("Not a .lzma file"));
return true;
@@ -142,7 +165,7 @@ lzmainfo(const char *name, FILE *f)
// this output and we don't want to break that when people move
// from LZMA Utils to XZ Utils.
if (f != stdin)
printf("%s\n", name);
printf("%s\n", tuklib_mask_nonprint(name));
printf("Uncompressed size: ");
if (uncompressed_size == UINT64_MAX)
@@ -200,9 +223,10 @@ main(int argc, char **argv)
if (f == NULL) {
ret = EXIT_FAILURE;
fprintf(stderr, "%s: %s: %s\n",
progname,
argv[optind],
strerror(errno));
progname,
tuklib_mask_nonprint(
argv[optind]),
strerror(errno));
continue;
}
+29 -12
View File
@@ -21,6 +21,7 @@
bool opt_stdout = false;
bool opt_force = false;
bool opt_keep_original = false;
bool opt_synchronous = true;
bool opt_robot = false;
bool opt_ignore_check = false;
@@ -217,6 +218,7 @@ parse_real(args_info *args, int argc, char **argv)
OPT_LZMA1,
OPT_LZMA2,
OPT_NO_SYNC,
OPT_SINGLE_STREAM,
OPT_NO_SPARSE,
OPT_FILES,
@@ -249,6 +251,7 @@ parse_real(args_info *args, int argc, char **argv)
{ "force", no_argument, NULL, 'f' },
{ "stdout", no_argument, NULL, 'c' },
{ "to-stdout", no_argument, NULL, 'c' },
{ "no-sync", no_argument, NULL, OPT_NO_SYNC },
{ "single-stream", no_argument, NULL, OPT_SINGLE_STREAM },
{ "no-sparse", no_argument, NULL, OPT_NO_SPARSE },
{ "suffix", required_argument, NULL, 'S' },
@@ -275,17 +278,17 @@ parse_real(args_info *args, int argc, char **argv)
{ "best", no_argument, NULL, '9' },
// Filters
{ "filters", optional_argument, NULL, OPT_FILTERS},
{ "filters1", optional_argument, NULL, OPT_FILTERS1},
{ "filters2", optional_argument, NULL, OPT_FILTERS2},
{ "filters3", optional_argument, NULL, OPT_FILTERS3},
{ "filters4", optional_argument, NULL, OPT_FILTERS4},
{ "filters5", optional_argument, NULL, OPT_FILTERS5},
{ "filters6", optional_argument, NULL, OPT_FILTERS6},
{ "filters7", optional_argument, NULL, OPT_FILTERS7},
{ "filters8", optional_argument, NULL, OPT_FILTERS8},
{ "filters9", optional_argument, NULL, OPT_FILTERS9},
{ "filters-help", optional_argument, NULL, OPT_FILTERS_HELP},
{ "filters", required_argument, NULL, OPT_FILTERS},
{ "filters1", required_argument, NULL, OPT_FILTERS1},
{ "filters2", required_argument, NULL, OPT_FILTERS2},
{ "filters3", required_argument, NULL, OPT_FILTERS3},
{ "filters4", required_argument, NULL, OPT_FILTERS4},
{ "filters5", required_argument, NULL, OPT_FILTERS5},
{ "filters6", required_argument, NULL, OPT_FILTERS6},
{ "filters7", required_argument, NULL, OPT_FILTERS7},
{ "filters8", required_argument, NULL, OPT_FILTERS8},
{ "filters9", required_argument, NULL, OPT_FILTERS9},
{ "filters-help", no_argument, NULL, OPT_FILTERS_HELP},
{ "lzma1", optional_argument, NULL, OPT_LZMA1 },
{ "lzma2", optional_argument, NULL, OPT_LZMA2 },
@@ -612,6 +615,9 @@ parse_real(args_info *args, int argc, char **argv)
case OPT_SINGLE_STREAM:
opt_single_stream = true;
// Since 5.7.1alpha --single-stream implies --keep.
opt_keep_original = true;
break;
case OPT_NO_SPARSE:
@@ -621,7 +627,7 @@ parse_real(args_info *args, int argc, char **argv)
case OPT_FILES:
args->files_delim = '\n';
// Fall through
FALLTHROUGH;
case OPT_FILES0:
if (args->files_name != NULL)
@@ -655,6 +661,10 @@ parse_real(args_info *args, int argc, char **argv)
optarg, 0, UINT64_MAX);
break;
case OPT_NO_SYNC:
opt_synchronous = false;
break;
default:
message_try_help();
tuklib_exit(E_ERROR, E_ERROR, false);
@@ -823,6 +833,13 @@ args_parse(args_info *args, int argc, char **argv)
opt_stdout = true;
}
// Don't use fsync() if --keep is specified or implied.
// However, don't document this as "--keep implies --no-sync"
// because if syncing support was added to --flush-timeout,
// it would sync even if --keep was specified.
if (opt_keep_original)
opt_synchronous = false;
// When compressing, if no --format flag was used, or it
// was --format=auto, we compress to the .xz format.
if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_AUTO)
+1 -1
View File
@@ -34,7 +34,7 @@ typedef struct {
extern bool opt_stdout;
extern bool opt_force;
extern bool opt_keep_original;
// extern bool opt_recursive;
extern bool opt_synchronous;
extern bool opt_robot;
extern bool opt_ignore_check;
+15 -13
View File
@@ -168,16 +168,13 @@ str_to_filters(const char *str, uint32_t index, uint32_t flags)
if (index > 0)
filter_num[0] = '0' + index;
// FIXME? The message in err isn't translated.
// Including the translations in the xz translations is
// slightly ugly but possible. Creating a new domain for
// liblzma might not be worth it especially since on some
// OSes it adds extra dependencies to translation libraries.
// liblzma doesn't translate the error messages but
// the messages are included in xz's translations.
message(V_ERROR, _("Error in --filters%s=FILTERS option:"),
filter_num);
message(V_ERROR, "%s", str);
message(V_ERROR, "%*s^", error_pos, "");
message_fatal("%s", err);
message_fatal("%s", _(err));
}
}
@@ -1003,8 +1000,9 @@ coder_init(file_pair *pair)
strm.avail_out = 0;
while ((ret = lzma_code(&strm, LZMA_RUN))
== LZMA_UNSUPPORTED_CHECK)
message_warning(_("%s: %s"), pair->src_name,
message_strm(ret));
message_warning(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
// With --single-stream lzma_code won't wait for
// LZMA_FINISH and thus it can return LZMA_STREAM_END
@@ -1019,7 +1017,9 @@ coder_init(file_pair *pair)
}
if (ret != LZMA_OK) {
message_error(_("%s: %s"), pair->src_name, message_strm(ret));
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
if (ret == LZMA_MEMLIMIT_ERROR)
message_mem_needed(V_ERROR, lzma_memusage(&strm));
@@ -1320,11 +1320,13 @@ coder_normal(file_pair *pair)
// wrong and we print an error. Otherwise it's just
// a warning and coding can continue.
if (stop) {
message_error(_("%s: %s"), pair->src_name,
message_strm(ret));
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
} else {
message_warning(_("%s: %s"), pair->src_name,
message_strm(ret));
message_warning(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
// When compressing, all possible errors set
// stop to true.
+213 -47
View File
@@ -17,6 +17,7 @@
# include <io.h>
#else
# include <poll.h>
# include <libgen.h>
static bool warn_fchown;
#endif
@@ -56,6 +57,10 @@ static bool warn_fchown;
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
# define fsync _commit
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
@@ -64,6 +69,25 @@ static bool warn_fchown;
# define O_NOCTTY 0
#endif
// In musl 1.2.5, O_SEARCH is defined to O_PATH. As of Linux 6.12,
// a file descriptor from open("dir", O_SEARCH | O_DIRECTORY) cannot be
// used with fsync() (fails with EBADF). musl 1.2.5 doesn't emulate it
// using /proc/self/fd. Even if it did, it might need to do it with
// fd = open("/proc/...", O_RDONLY); fsync(fd); which fails if the
// directory lacks read permission. Since we need a working fsync(),
// O_RDONLY imitates O_SEARCH better than O_PATH.
#if defined(O_SEARCH) && defined(O_PATH) && O_SEARCH == O_PATH
# undef O_SEARCH
#endif
#ifndef O_SEARCH
# define O_SEARCH O_RDONLY
#endif
#ifndef O_DIRECTORY
# define O_DIRECTORY 0
#endif
// Using this macro to silence a warning from gcc -Wlogical-op.
#if EAGAIN == EWOULDBLOCK
# define IS_EAGAIN_OR_EWOULDBLOCK(e) ((e) == EAGAIN)
@@ -205,8 +229,9 @@ io_wait(file_pair *pair, int timeout, bool is_reading)
continue;
message_error(_("%s: poll() failed: %s"),
is_reading ? pair->src_name
: pair->dest_name,
tuklib_mask_nonprint(is_reading
? pair->src_name
: pair->dest_name),
strerror(errno));
return IO_WAIT_ERROR;
}
@@ -272,14 +297,15 @@ io_unlink(const char *name, const struct stat *known_st)
// of the original file, and in that case it obviously
// shouldn't be removed.
message_warning(_("%s: File seems to have been moved, "
"not removing"), name);
"not removing"), tuklib_mask_nonprint(name));
else
#endif
// There's a race condition between lstat() and unlink()
// but at least we have tried to avoid removing wrong file.
if (unlink(name))
message_warning(_("%s: Cannot remove: %s"),
name, strerror(errno));
tuklib_mask_nonprint(name),
strerror(errno));
return;
}
@@ -305,7 +331,8 @@ io_copy_attrs(const file_pair *pair)
if (fchown(pair->dest_fd, pair->src_st.st_uid, (gid_t)(-1))
&& warn_fchown)
message_warning(_("%s: Cannot set the file owner: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
mode_t mode;
@@ -318,7 +345,8 @@ io_copy_attrs(const file_pair *pair)
&& fchown(pair->dest_fd, (uid_t)(-1),
pair->src_st.st_gid)) {
message_warning(_("%s: Cannot set the file group: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
// We can still safely copy some additional permissions:
// 'group' must be at least as strict as 'other' and
// also vice versa.
@@ -337,7 +365,8 @@ io_copy_attrs(const file_pair *pair)
if (fchmod(pair->dest_fd, mode))
message_warning(_("%s: Cannot set the file permissions: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
#endif
// Copy the timestamps. We have several possible ways to do this, of
@@ -445,6 +474,39 @@ io_copy_attrs(const file_pair *pair)
}
/// \brief Synchronizes the destination file to permanent storage
///
/// \param pair File pair having the destination file open for writing
///
/// \return On success, false is returned. On error, error message
/// is printed and true is returned.
static bool
io_sync_dest(file_pair *pair)
{
assert(pair->dest_fd != -1);
assert(pair->dest_fd != STDOUT_FILENO);
if (fsync(pair->dest_fd)) {
message_error(_("%s: Synchronizing the file failed: %s"),
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
return true;
}
#ifndef TUKLIB_DOSLIKE
if (fsync(pair->dir_fd)) {
message_error(_("%s: Synchronizing the directory of "
"the file failed: %s"),
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
return true;
}
#endif
return false;
}
/// Opens the source file. Returns false on success, true on error.
static bool
io_open_src_real(file_pair *pair)
@@ -515,13 +577,15 @@ io_open_src_real(file_pair *pair)
if (!follow_symlinks) {
struct stat st;
if (lstat(pair->src_name, &st)) {
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
strerror(errno));
return true;
} else if (S_ISLNK(st.st_mode)) {
message_warning(_("%s: Is a symbolic link, "
"skipping"), pair->src_name);
"skipping"),
tuklib_mask_nonprint(pair->src_name));
return true;
}
}
@@ -583,13 +647,15 @@ io_open_src_real(file_pair *pair)
if (was_symlink)
message_warning(_("%s: Is a symbolic link, "
"skipping"), pair->src_name);
"skipping"),
tuklib_mask_nonprint(pair->src_name));
else
#endif
// Something else than O_NOFOLLOW failing
// (assuming that the race conditions didn't
// confuse us).
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
strerror(errno));
return true;
@@ -612,13 +678,13 @@ io_open_src_real(file_pair *pair)
if (S_ISDIR(pair->src_st.st_mode)) {
message_warning(_("%s: Is a directory, skipping"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
goto error;
}
if (reg_files_only && !S_ISREG(pair->src_st.st_mode)) {
message_warning(_("%s: Not a regular file, skipping"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
goto error;
}
@@ -636,21 +702,21 @@ io_open_src_real(file_pair *pair)
// explicitly in io_copy_attr().
message_warning(_("%s: File has setuid or "
"setgid bit set, skipping"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
goto error;
}
if (pair->src_st.st_mode & S_ISVTX) {
message_warning(_("%s: File has sticky bit "
"set, skipping"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
goto error;
}
if (pair->src_st.st_nlink > 1) {
message_warning(_("%s: Input file has more "
"than one hard link, "
"skipping"), pair->src_name);
"than one hard link, skipping"),
tuklib_mask_nonprint(pair->src_name));
goto error;
}
}
@@ -679,7 +745,8 @@ io_open_src_real(file_pair *pair)
return false;
error_msg:
message_error(_("%s: %s"), pair->src_name, strerror(errno));
message_error(_("%s: %s"), tuklib_mask_nonprint(pair->src_name),
strerror(errno));
error:
(void)close(pair->src_fd);
return true;
@@ -707,6 +774,9 @@ io_open_src(const char *src_name)
.dest_name = NULL,
.src_fd = -1,
.dest_fd = -1,
#ifndef TUKLIB_DOSLIKE
.dir_fd = -1,
#endif
.src_eof = false,
.src_has_seen_input = false,
.flush_needed = false,
@@ -809,6 +879,56 @@ io_open_dest_real(file_pair *pair)
if (pair->dest_name == NULL)
return true;
#ifndef TUKLIB_DOSLIKE
if (opt_synchronous) {
// Open the directory where the destination file will
// be created (the file descriptor is needed for
// fsync()). Do this before creating the destination
// file:
//
// - We currently have no files to clean up if
// opening the directory fails. (We aren't
// reading from stdin so there are no stdin_flags
// to restore either.)
//
// - Allocating memory with xstrdup() is safe only
// when we have nothing to clean up.
char *buf = xstrdup(pair->dest_name);
const char *dir_name = dirname(buf);
// O_NOCTTY and O_NONBLOCK are there in case
// O_DIRECTORY is 0 and dir_name doesn't refer
// to a directory. (We opened the source file
// already but directories might have been renamed
// after the source file was opened.)
pair->dir_fd = open(dir_name, O_SEARCH | O_DIRECTORY
| O_NOCTTY | O_NONBLOCK);
if (pair->dir_fd == -1) {
// Since we did open the source file
// successfully, we should rarely get here.
// Perhaps something has been renamed or
// had its permissions changed.
//
// In an odd case, the directory has write
// and search permissions but not read
// permission (d-wx------), and O_SEARCH is
// actually O_RDONLY. Then we would be able
// to create a new file and only the directory
// syncing would be impossible. But let's be
// strict about syncing and require users to
// explicitly disable it if they don't want it.
message_error(_("%s: Opening the directory "
"failed: %s"),
tuklib_mask_nonprint(dir_name),
strerror(errno));
free(buf);
goto error;
}
free(buf);
}
#endif
#ifdef __DJGPP__
struct stat st;
if (stat(pair->dest_name, &st) == 0) {
@@ -816,9 +936,9 @@ io_open_dest_real(file_pair *pair)
if (st.st_dev == -1) {
message_error("%s: Refusing to write to "
"a DOS special file",
pair->dest_name);
free(pair->dest_name);
return true;
tuklib_mask_nonprint(
pair->dest_name));
goto error;
}
// Check that we aren't overwriting the source file.
@@ -826,9 +946,9 @@ io_open_dest_real(file_pair *pair)
&& st.st_ino == pair->src_st.st_ino) {
message_error("%s: Output file is the same "
"as the input file",
pair->dest_name);
free(pair->dest_name);
return true;
tuklib_mask_nonprint(
pair->dest_name));
goto error;
}
}
#endif
@@ -836,9 +956,9 @@ io_open_dest_real(file_pair *pair)
// If --force was used, unlink the target file first.
if (opt_force && unlink(pair->dest_name) && errno != ENOENT) {
message_error(_("%s: Cannot remove: %s"),
pair->dest_name, strerror(errno));
free(pair->dest_name);
return true;
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
goto error;
}
// Open the file.
@@ -851,11 +971,15 @@ io_open_dest_real(file_pair *pair)
pair->dest_fd = open(pair->dest_name, flags, mode);
if (pair->dest_fd == -1) {
message_error(_("%s: %s"), pair->dest_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
free(pair->dest_name);
return true;
goto error;
}
// We could sync dir_fd now and close it. However, performance
// can be better if this is delayed until dest_fd has been
// synced in io_sync_dest().
}
if (fstat(pair->dest_fd, &pair->dest_st)) {
@@ -881,15 +1005,13 @@ io_open_dest_real(file_pair *pair)
// With fstat()/_fstat64() it works.
else if (pair->dest_fd != STDOUT_FILENO
&& !S_ISREG(pair->dest_st.st_mode)) {
message_error("%s: Destination is not a regular file",
pair->dest_name);
message_error(_("%s: Destination is not a regular file"),
tuklib_mask_nonprint(pair->dest_name));
// dest_fd needs to be reset to -1 to keep io_close() working.
(void)close(pair->dest_fd);
pair->dest_fd = -1;
free(pair->dest_name);
return true;
goto error;
}
#elif !defined(TUKLIB_DOSLIKE)
else if (try_sparse && opt_mode == MODE_DECOMPRESS) {
@@ -961,6 +1083,18 @@ io_open_dest_real(file_pair *pair)
#endif
return false;
error:
#ifndef TUKLIB_DOSLIKE
// io_close() closes pair->dir_fd but let's do it here anyway.
if (pair->dir_fd != -1) {
(void)close(pair->dir_fd);
pair->dir_fd = -1;
}
#endif
free(pair->dest_name);
return true;
}
@@ -979,8 +1113,8 @@ io_open_dest(file_pair *pair)
/// \param pair File whose dest_fd should be closed
/// \param success If false, the file will be removed from the disk.
///
/// \return Zero if closing succeeds. On error, -1 is returned and
/// error message printed.
/// \return If closing succeeds, false is returned. On error, an error
/// message is printed and true is returned.
static bool
io_close_dest(file_pair *pair, bool success)
{
@@ -1003,9 +1137,17 @@ io_close_dest(file_pair *pair, bool success)
if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO)
return false;
#ifndef TUKLIB_DOSLIKE
// dir_fd was only used for syncing the directory.
// Error checking was done when syncing.
if (pair->dir_fd != -1)
(void)close(pair->dir_fd);
#endif
if (close(pair->dest_fd)) {
message_error(_("%s: Closing the file failed: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
// Closing destination file failed, so we cannot trust its
// contents. Get rid of junk:
@@ -1042,7 +1184,8 @@ io_close(file_pair *pair, bool success)
SEEK_CUR) == -1) {
message_error(_("%s: Seeking failed when trying "
"to create a sparse file: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
success = false;
} else {
const uint8_t zero[1] = { '\0' };
@@ -1053,11 +1196,16 @@ io_close(file_pair *pair, bool success)
signals_block();
// Copy the file attributes. We need to skip this if destination
// file isn't open or it is standard output.
if (success && pair->dest_fd != -1 && pair->dest_fd != STDOUT_FILENO)
if (success && pair->dest_fd != -1 && pair->dest_fd != STDOUT_FILENO) {
// Copy the file attributes. This may produce warnings but
// not errors so "success" isn't affected.
io_copy_attrs(pair);
// Synchronize the file and its directory if needed.
if (opt_synchronous)
success = !io_sync_dest(pair);
}
// Close the destination first. If it fails, we must not remove
// the source file!
if (io_close_dest(pair, success))
@@ -1141,7 +1289,8 @@ io_read(file_pair *pair, io_buf *buf, size_t size)
#endif
message_error(_("%s: Read error: %s"),
pair->src_name, strerror(errno));
tuklib_mask_nonprint(pair->src_name),
strerror(errno));
return SIZE_MAX;
}
@@ -1171,7 +1320,8 @@ io_seek_src(file_pair *pair, uint64_t pos)
if (lseek(pair->src_fd, (off_t)(pos), SEEK_SET) == -1) {
message_error(_("%s: Error seeking the file: %s"),
pair->src_name, strerror(errno));
tuklib_mask_nonprint(pair->src_name),
strerror(errno));
return true;
}
@@ -1195,7 +1345,7 @@ io_pread(file_pair *pair, io_buf *buf, size_t size, uint64_t pos)
if (amount != size) {
message_error(_("%s: Unexpected end of file"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
return true;
}
@@ -1240,6 +1390,19 @@ io_write_buf(file_pair *pair, const uint8_t *buf, size_t size)
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
// On native Windows, broken pipe is reported as
// EINVAL. Don't show an error message in this case.
// Try: xz -dc bigfile.xz | head -n1
if (errno == EINVAL
&& pair->dest_fd == STDOUT_FILENO) {
// Emulate SIGPIPE by setting user_abort here.
user_abort = true;
set_exit_status(E_ERROR);
return true;
}
#endif
// Handle broken pipe specially. gzip and bzip2
// don't print anything on SIGPIPE. In addition,
// gzip --quiet uses exit status 2 (warning) on
@@ -1254,7 +1417,8 @@ io_write_buf(file_pair *pair, const uint8_t *buf, size_t size)
// user_abort, and get EPIPE here.
if (errno != EPIPE)
message_error(_("%s: Write error: %s"),
pair->dest_name, strerror(errno));
tuklib_mask_nonprint(pair->dest_name),
strerror(errno));
return true;
}
@@ -1304,7 +1468,9 @@ io_write(file_pair *pair, const io_buf *buf, size_t size)
SEEK_CUR) == -1) {
message_error(_("%s: Seeking failed when "
"trying to create a sparse "
"file: %s"), pair->dest_name,
"file: %s"),
tuklib_mask_nonprint(
pair->dest_name),
strerror(errno));
return true;
}
+8 -2
View File
@@ -55,6 +55,12 @@ typedef struct {
/// File descriptor of the target file
int dest_fd;
#ifndef TUKLIB_DOSLIKE
/// File descriptor of the directory of the target file (which is
/// also the directory of the source file)
int dir_fd;
#endif
/// True once end of the source file has been detected.
bool src_eof;
@@ -177,6 +183,6 @@ extern bool io_pread(file_pair *pair, io_buf *buf, size_t size, uint64_t pos);
/// \param buf Buffer containing the data to be written
/// \param size Size of the buffer; must be at most IO_BUFFER_SIZE
///
/// \return On success, zero is returned. On error, -1 is returned
/// and error message printed.
/// \return On success, false is returned. On error, error message
/// is printed and true is returned.
extern bool io_write(file_pair *pair, const io_buf *buf, size_t size);
+24 -15
View File
@@ -347,13 +347,14 @@ static bool
parse_indexes(xz_file_info *xfi, file_pair *pair)
{
if (pair->src_st.st_size <= 0) {
message_error(_("%s: File is empty"), pair->src_name);
message_error(_("%s: File is empty"),
tuklib_mask_nonprint(pair->src_name));
return true;
}
if (pair->src_st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) {
message_error(_("%s: Too small to be a valid .xz file"),
pair->src_name);
tuklib_mask_nonprint(pair->src_name));
return true;
}
@@ -365,7 +366,9 @@ parse_indexes(xz_file_info *xfi, file_pair *pair)
hardware_memlimit_get(MODE_LIST),
(uint64_t)(pair->src_st.st_size));
if (ret != LZMA_OK) {
message_error(_("%s: %s"), pair->src_name, message_strm(ret));
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
return true;
}
@@ -411,7 +414,8 @@ parse_indexes(xz_file_info *xfi, file_pair *pair)
}
default:
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(ret));
// If the error was too low memory usage limit,
@@ -473,7 +477,8 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter,
break;
case LZMA_OPTIONS_ERROR:
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(LZMA_OPTIONS_ERROR));
return true;
@@ -520,8 +525,7 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter,
// If the above fails, the file is corrupt so
// LZMA_DATA_ERROR is a good error code.
// Fall through
FALLTHROUGH;
case LZMA_DATA_ERROR:
// Free the memory allocated by lzma_block_header_decode().
@@ -587,7 +591,8 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter,
// Check if the stringification succeeded.
if (str_ret != LZMA_OK) {
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(str_ret));
return true;
}
@@ -596,7 +601,8 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter,
data_error:
// Show the error message.
message_error(_("%s: %s"), pair->src_name,
message_error(_("%s: %s"),
tuklib_mask_nonprint(pair->src_name),
message_strm(LZMA_DATA_ERROR));
return true;
}
@@ -744,7 +750,7 @@ print_info_basic(const xz_file_info *xfi, file_pair *pair)
char checks[CHECKS_STR_SIZE];
get_check_names(checks, lzma_index_checks(xfi->idx), false);
const char *cols[7] = {
const char *cols[6] = {
uint64_to_str(lzma_index_stream_count(xfi->idx), 0),
uint64_to_str(lzma_index_block_count(xfi->idx), 1),
uint64_to_nicestr(lzma_index_file_size(xfi->idx),
@@ -754,7 +760,6 @@ print_info_basic(const xz_file_info *xfi, file_pair *pair)
get_ratio(lzma_index_file_size(xfi->idx),
lzma_index_uncompressed_size(xfi->idx)),
checks,
pair->src_name,
};
printf("%*s %*s %*s %*s %*s %-*s %s\n",
tuklib_mbstr_fw(cols[0], 5), cols[0],
@@ -763,7 +768,7 @@ print_info_basic(const xz_file_info *xfi, file_pair *pair)
tuklib_mbstr_fw(cols[3], 11), cols[3],
tuklib_mbstr_fw(cols[4], 5), cols[4],
tuklib_mbstr_fw(cols[5], 7), cols[5],
cols[6]);
tuklib_mask_nonprint(pair->src_name));
return false;
}
@@ -1034,7 +1039,7 @@ print_info_adv(xz_file_info *xfi, file_pair *pair)
printf(" %-*s %s\n", COLON_STR(COLON_STR_SIZES_IN_HEADERS),
xfi->all_have_sizes ? _("Yes") : _("No"));
//printf(" %-*s %s\n", COLON_STR(COLON_STR_MINIMUM_XZ_VERSION),
printf(_(" Minimum XZ Utils version: %s\n"),
printf(" %s %s\n", _("Minimum XZ Utils version:"),
xz_ver_to_str(xfi->min_version));
}
@@ -1048,7 +1053,11 @@ 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);
// Robot mode has to mask at least some control chars to prevent
// the output from getting out of sync if filename is malicious.
// Masking all non-printable chars is more than we need but
// perhaps this is good enough in practice.
printf("name\t%s\n", tuklib_mask_nonprint(pair->src_name));
printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64
"\t%s\t%s\t%" PRIu64 "\n",
@@ -1219,7 +1228,7 @@ print_totals_adv(void)
printf(" %-*s %s\n", COLON_STR(COLON_STR_SIZES_IN_HEADERS),
totals.all_have_sizes ? _("Yes") : _("No"));
//printf(" %-*s %s\n", COLON_STR(COLON_STR_MINIMUM_XZ_VERSION),
printf(_(" Minimum XZ Utils version: %s\n"),
printf(" %s %s\n", _("Minimum XZ Utils version:"),
xz_ver_to_str(totals.min_version));
}
+7 -3
View File
@@ -87,7 +87,8 @@ read_name(const args_info *args)
continue;
message_error(_("%s: Error reading filenames: %s"),
args->files_name, strerror(errno));
tuklib_mask_nonprint(args->files_name),
strerror(errno));
return NULL;
}
@@ -95,7 +96,8 @@ read_name(const args_info *args)
if (pos != 0)
message_error(_("%s: Unexpected end of input "
"when reading filenames"),
args->files_name);
tuklib_mask_nonprint(
args->files_name));
return NULL;
}
@@ -120,7 +122,9 @@ read_name(const args_info *args)
message_error(_("%s: Null character found when "
"reading filenames; maybe you meant "
"to use '--files0' instead "
"of '--files'?"), args->files_name);
"of '--files'?"),
tuklib_mask_nonprint(
args->files_name));
return NULL;
}
+334 -180
View File
@@ -11,7 +11,7 @@
///////////////////////////////////////////////////////////////////////////////
#include "private.h"
#include "tuklib_mbstr_wrap.h"
#include <stdarg.h>
@@ -196,10 +196,12 @@ print_filename(void)
// If we don't know how many files there will be due
// to usage of --files or --files0.
if (files_total == 0)
fprintf(file, "%s (%u)\n", filename,
fprintf(file, "%s (%u)\n",
tuklib_mask_nonprint(filename),
files_pos);
else
fprintf(file, "%s (%u/%u)\n", filename,
fprintf(file, "%s (%u/%u)\n",
tuklib_mask_nonprint(filename),
files_pos, files_total);
signals_unblock();
@@ -648,7 +650,7 @@ progress_flush(bool finished)
cols[4]);
} else {
// The filename is always printed.
fprintf(stderr, _("%s: "), filename);
fprintf(stderr, _("%s: "), tuklib_mask_nonprint(filename));
// Percentage is printed only if we didn't finish yet.
if (!finished) {
@@ -936,213 +938,360 @@ message_version(void)
}
static void
detect_wrapping_errors(int error_mask)
{
#ifndef NDEBUG
// This might help in catching problematic strings in translations.
// It's a debug message so don't translate this.
if (error_mask & TUKLIB_WRAP_WARN_OVERLONG)
message_fatal("The help text contains overlong lines");
#endif
if (error_mask & ~TUKLIB_WRAP_WARN_OVERLONG)
message_fatal(_("Error printing the help text "
"(error code %d)"), error_mask);
return;
}
extern void
message_help(bool long_help)
{
printf(_("Usage: %s [OPTION]... [FILE]...\n"
"Compress or decompress FILEs in the .xz format.\n\n"),
progname);
static const struct tuklib_wrap_opt wrap0 = { 0, 0, 0, 0, 79 };
static const struct tuklib_wrap_opt wrap1 = { 1, 1, 1, 1, 79 };
static const struct tuklib_wrap_opt wrap2 = { 2, 2, 22, 22, 79 };
static const struct tuklib_wrap_opt wrap3 = { 24, 24, 36, 36, 79 };
// NOTE: The short help doesn't currently have options that
// take arguments.
if (long_help)
puts(_("Mandatory arguments to long options are mandatory "
"for short options too.\n"));
// Accumulated error codes from tuklib_wraps() and tuklib_wrapf()
int e = 0;
if (long_help)
puts(_(" Operation mode:\n"));
printf(_("Usage: %s [OPTION]... [FILE]...\n"), progname);
e |= tuklib_wraps(stdout, &wrap0,
W_("Compress or decompress FILEs in the .xz format."));
putchar('\n');
puts(_(
" -z, --compress force compression\n"
" -d, --decompress force decompression\n"
" -t, --test test compressed file integrity\n"
" -l, --list list information about .xz files"));
e |= tuklib_wraps(stdout, &wrap0,
W_("Mandatory arguments to long options are "
"mandatory for short options too."));
putchar('\n');
if (long_help)
puts(_("\n Operation modifiers:\n"));
if (long_help) {
e |= tuklib_wraps(stdout, &wrap1, W_("Operation mode:"));
putchar('\n');
}
puts(_(
" -k, --keep keep (don't delete) input files\n"
" -f, --force force overwrite of output file and (de)compress links\n"
" -c, --stdout write to standard output and don't delete input files"));
e |= tuklib_wrapf(stdout, &wrap2,
"-z, --compress\v%s\r"
"-d, --decompress\v%s\r"
"-t, --test\v%s\r"
"-l, --list\v%s",
W_("force compression"),
W_("force decompression"),
W_("test compressed file integrity"),
W_("list information about .xz files"));
if (long_help) {
putchar('\n');
e |= tuklib_wraps(stdout, &wrap1, W_("Operation modifiers:"));
putchar('\n');
}
e |= tuklib_wrapf(stdout, &wrap2,
"-k, --keep\v%s\r"
"-f, --force\v%s\r"
"-c, --stdout\v%s",
W_("keep (don't delete) input files"),
W_("force overwrite of output file and (de)compress links"),
W_("write to standard output and don't delete input files"));
// NOTE: --to-stdout isn't included above because it's not
// the recommended spelling. It was copied from gzip but other
// compressors with gzip-like syntax don't support it.
if (long_help) {
puts(_(
" --single-stream decompress only the first stream, and silently\n"
" ignore possible remaining input data"));
puts(_(
" --no-sparse do not create sparse files when decompressing\n"
" -S, --suffix=.SUF use the suffix '.SUF' on compressed files\n"
" --files[=FILE] read filenames to process from FILE; if FILE is\n"
" omitted, filenames are read from the standard input;\n"
" filenames must be terminated with the newline character\n"
" --files0[=FILE] like --files but use the null character as terminator"));
e |= tuklib_wrapf(stdout, &wrap2,
" --no-sync\v%s\r"
" --single-stream\v%s\r"
" --no-sparse\v%s\r"
"-S, --suffix=%s\v%s\r"
" --files[=%s]\v%s\r"
" --files0[=%s]\v%s\r",
W_("don't synchronize the output file to the storage "
"device before removing the input file"),
W_("decompress only the first stream, and silently "
"ignore possible remaining input data"),
W_("do not create sparse files when decompressing"),
_(".SUF"),
W_("use the suffix '.SUF' on compressed files"),
_("FILE"),
W_("read filenames to process from FILE; "
"if FILE is omitted, "
"filenames are read from the standard input; "
"filenames must be terminated with "
"the newline character"),
_("FILE"),
W_("like --files but use the null character as "
"terminator"));
e |= tuklib_wraps(stdout, &wrap1,
W_("Basic file format and compression options:"));
e |= tuklib_wrapf(stdout, &wrap2,
"\n"
"-F, --format=%s\v%s\r"
"-C, --check=%s\v%s\r"
" --ignore-check\v%s",
_("FORMAT"),
W_("file format to encode or decode; possible values "
"are 'auto' (default), 'xz', 'lzma', 'lzip', "
"and 'raw'"),
_("NAME"),
W_("integrity check type: 'none' (use with caution), "
"'crc32', 'crc64' (default), or 'sha256'"),
W_("don't verify the integrity check when "
"decompressing"));
}
e |= tuklib_wrapf(stdout, &wrap2,
"-0 ... -9\v%s\r"
"-e, --extreme\v%s\r"
"-T, --threads=%s\v%s",
W_("compression preset; default is 6; take compressor *and* "
"decompressor memory usage into account before "
"using 7-9!"),
W_("try to improve compression ratio by using more CPU time; "
"does not affect decompressor memory requirements"),
// TRANSLATORS: Short for NUMBER. A longer string is fine but
// wider than 5 columns makes --long-help a few lines longer.
_("NUM"),
W_("use at most NUM threads; the default is 0 which uses "
"as many threads as there are processor cores"));
if (long_help) {
e |= tuklib_wrapf(stdout, &wrap2,
" --block-size=%s\v%s\r"
" --block-list=%s\v%s\r"
" --flush-timeout=%s\v%s",
_("SIZE"),
W_("start a new .xz block after every SIZE bytes "
"of input; use this to set the block size "
"for threaded compression"),
_("BLOCKS"),
W_("start a new .xz block after the given "
"comma-separated intervals of uncompressed "
"data; optionally, specify a "
"filter chain number (0-9) followed by "
"a ':' before the uncompressed data size"),
_("NUM"),
W_("when compressing, if more than NUM "
"milliseconds has passed since the previous "
"flush and reading more input would block, "
"all pending data is flushed out"));
e |= tuklib_wrapf(stdout, &wrap2,
" --memlimit-compress=%s\n"
" --memlimit-decompress=%s\n"
" --memlimit-mt-decompress=%s\n"
"-M, --memlimit=%s\v%s\r"
" --no-adjust\v%s",
_("LIMIT"),
_("LIMIT"),
_("LIMIT"),
_("LIMIT"),
// xgettext:no-c-format
W_("set memory usage limit for compression, "
"decompression, threaded decompression, "
"or all of these; LIMIT is in "
"bytes, % of RAM, or 0 for defaults"),
W_("if compression settings exceed the "
"memory usage limit, "
"give an error instead of adjusting "
"the settings downwards"));
}
if (long_help) {
puts(_("\n Basic file format and compression options:\n"));
puts(_(
" -F, --format=FMT file format to encode or decode; possible values are\n"
" 'auto' (default), 'xz', 'lzma', 'lzip', and 'raw'\n"
" -C, --check=CHECK integrity check type: 'none' (use with caution),\n"
" 'crc32', 'crc64' (default), or 'sha256'"));
puts(_(
" --ignore-check don't verify the integrity check when decompressing"));
}
putchar('\n');
puts(_(
" -0 ... -9 compression preset; default is 6; take compressor *and*\n"
" decompressor memory usage into account before using 7-9!"));
e |= tuklib_wraps(stdout, &wrap1,
W_("Custom filter chain for compression "
"(an alternative to using presets):"));
puts(_(
" -e, --extreme try to improve compression ratio by using more CPU time;\n"
" does not affect decompressor memory requirements"));
puts(_(
" -T, --threads=NUM use at most NUM threads; the default is 0 which uses\n"
" as many threads as there are processor cores"));
if (long_help) {
puts(_(
" --block-size=SIZE\n"
" start a new .xz block after every SIZE bytes of input;\n"
" use this to set the block size for threaded compression"));
puts(_(
" --block-list=BLOCKS\n"
" start a new .xz block after the given comma-separated\n"
" intervals of uncompressed data; optionally, specify a\n"
" filter chain number (0-9) followed by a ':' before the\n"
" uncompressed data size"));
puts(_(
" --flush-timeout=TIMEOUT\n"
" when compressing, if more than TIMEOUT milliseconds has\n"
" passed since the previous flush and reading more input\n"
" would block, all pending data is flushed out"
));
puts(_( // xgettext:no-c-format
" --memlimit-compress=LIMIT\n"
" --memlimit-decompress=LIMIT\n"
" --memlimit-mt-decompress=LIMIT\n"
" -M, --memlimit=LIMIT\n"
" set memory usage limit for compression, decompression,\n"
" threaded decompression, or all of these; LIMIT is in\n"
" bytes, % of RAM, or 0 for defaults"));
puts(_(
" --no-adjust if compression settings exceed the memory usage limit,\n"
" give an error instead of adjusting the settings downwards"));
}
if (long_help) {
puts(_(
"\n Custom filter chain for compression (alternative for using presets):"));
puts(_(
"\n"
" --filters=FILTERS set the filter chain using the liblzma filter string\n"
" syntax; use --filters-help for more information"
));
puts(_(
" --filters1=FILTERS ... --filters9=FILTERS\n"
" set additional filter chains using the liblzma filter\n"
" string syntax to use with --block-list"
));
puts(_(
" --filters-help display more information about the liblzma filter string\n"
" syntax and exit."
));
e |= tuklib_wrapf(stdout, &wrap2,
"\n"
"--filters=%s\v%s\r"
"--filters1=%s ... --filters9=%s\v%s\r"
"--filters-help\v%s",
_("FILTERS"),
W_("set the filter chain using the "
"liblzma filter string syntax; "
"use --filters-help for more information"),
_("FILTERS"),
_("FILTERS"),
W_("set additional filter chains using the "
"liblzma filter string syntax to use "
"with --block-list"),
W_("display more information about the "
"liblzma filter string syntax and exit"));
#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1) \
|| defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
// TRANSLATORS: The word "literal" in "literal context bits"
// means how many "context bits" to use when encoding
// literals. A literal is a single 8-bit byte. It doesn't
// mean "literally" here.
puts(_(
"\n"
" --lzma1[=OPTS] LZMA1 or LZMA2; OPTS is a comma-separated list of zero or\n"
" --lzma2[=OPTS] more of the following options (valid values; default):\n"
" preset=PRE reset options to a preset (0-9[e])\n"
" dict=NUM dictionary size (4KiB - 1536MiB; 8MiB)\n"
" lc=NUM number of literal context bits (0-4; 3)\n"
" lp=NUM number of literal position bits (0-4; 0)\n"
" pb=NUM number of position bits (0-4; 2)\n"
" mode=MODE compression mode (fast, normal; normal)\n"
" nice=NUM nice length of a match (2-273; 64)\n"
" mf=NAME match finder (hc3, hc4, bt2, bt3, bt4; bt4)\n"
" depth=NUM maximum search depth; 0=automatic (default)"));
e |= tuklib_wrapf(stdout, &wrap2,
"\n"
"--lzma1[=%s]\n"
"--lzma2[=%s]\v%s",
// TRANSLATORS: Short for OPTIONS.
_("OPTS"),
_("OPTS"),
// TRANSLATORS: Use semicolon (or its fullwidth form)
// in "(valid values; default)" even if it is weird in
// your language. There are non-translatable strings
// that look like "(foo, bar, baz; foo)" which list
// the supported values and the default value.
W_("LZMA1 or LZMA2; OPTS is a comma-separated list "
"of zero or more of the following options "
"(valid values; default):"));
e |= tuklib_wrapf(stdout, &wrap3,
"preset=%s\v%s (0-9[e])\r"
"dict=%s\v%s \b(4KiB - 1536MiB; 8MiB)\b\r"
"lc=%s\v%s \b(0-4; 3)\b\r"
"lp=%s\v%s \b(0-4; 0)\b\r"
"pb=%s\v%s \b(0-4; 2)\b\r"
"mode=%s\v%s (fast, normal; normal)\r"
"nice=%s\v%s \b(2-273; 64)\b\r"
"mf=%s\v%s (hc3, hc4, bt2, bt3, bt4; bt4)\r"
"depth=%s\v%s",
// TRANSLATORS: Short for PRESET. A longer string is
// fine but wider than 4 columns makes --long-help
// one line longer.
_("PRE"),
W_("reset options to a preset"),
_("NUM"), W_("dictionary size"),
_("NUM"),
// TRANSLATORS: The word "literal" in "literal context
// bits" means how many "context bits" to use when
// encoding literals. A literal is a single 8-bit
// byte. It doesn't mean "literally" here.
W_("number of literal context bits"),
_("NUM"), W_("number of literal position bits"),
_("NUM"), W_("number of position bits"),
_("MODE"), W_("compression mode"),
_("NUM"), W_("nice length of a match"),
_("NAME"), W_("match finder"),
_("NUM"), W_("maximum search depth; "
"0=automatic (default)"));
#endif
puts(_(
"\n"
" --x86[=OPTS] x86 BCJ filter (32-bit and 64-bit)\n"
" --arm[=OPTS] ARM BCJ filter\n"
" --armthumb[=OPTS] ARM-Thumb BCJ filter\n"
" --arm64[=OPTS] ARM64 BCJ filter\n"
" --powerpc[=OPTS] PowerPC BCJ filter (big endian only)\n"
" --ia64[=OPTS] IA-64 (Itanium) BCJ filter\n"
" --sparc[=OPTS] SPARC BCJ filter\n"
" --riscv[=OPTS] RISC-V BCJ filter\n"
" Valid OPTS for all BCJ filters:\n"
" start=NUM start offset for conversions (default=0)"));
e |= tuklib_wrapf(stdout, &wrap2,
"\n"
"--x86[=%s]\v%s\r"
"--arm[=%s]\v%s\r"
"--armthumb[=%s]\v%s\r"
"--arm64[=%s]\v%s\r"
"--powerpc[=%s]\v%s\r"
"--ia64[=%s]\v%s\r"
"--sparc[=%s]\v%s\r"
"--riscv[=%s]\v%s\r"
"\v%s",
_("OPTS"),
W_("x86 BCJ filter (32-bit and 64-bit)"),
_("OPTS"),
W_("ARM BCJ filter"),
_("OPTS"),
W_("ARM-Thumb BCJ filter"),
_("OPTS"),
W_("ARM64 BCJ filter"),
_("OPTS"),
W_("PowerPC BCJ filter (big endian only)"),
_("OPTS"),
W_("IA-64 (Itanium) BCJ filter"),
_("OPTS"),
W_("SPARC BCJ filter"),
_("OPTS"),
W_("RISC-V BCJ filter"),
W_("Valid OPTS for all BCJ filters:"));
e |= tuklib_wrapf(stdout, &wrap3,
"start=%s\v%s",
_("NUM"),
W_("start offset for conversions (default=0)"));
#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
puts(_(
"\n"
" --delta[=OPTS] Delta filter; valid OPTS (valid values; default):\n"
" dist=NUM distance between bytes being subtracted\n"
" from each other (1-256; 1)"));
e |= tuklib_wrapf(stdout, &wrap2,
"\n"
"--delta[=%s]\v%s",
_("OPTS"),
W_("Delta filter; valid OPTS "
"(valid values; default):"));
e |= tuklib_wrapf(stdout, &wrap3,
"dist=%s\v%s \b(1-256; 1)\b",
_("NUM"),
W_("distance between bytes being subtracted "
"from each other"));
#endif
}
if (long_help)
puts(_("\n Other options:\n"));
puts(_(
" -q, --quiet suppress warnings; specify twice to suppress errors too\n"
" -v, --verbose be verbose; specify twice for even more verbose"));
if (long_help) {
puts(_(
" -Q, --no-warn make warnings not affect the exit status"));
puts(_(
" --robot use machine-parsable messages (useful for scripts)"));
puts("");
puts(_(
" --info-memory display the total amount of RAM and the currently active\n"
" memory usage limits, and exit"));
puts(_(
" -h, --help display the short help (lists only the basic options)\n"
" -H, --long-help display this long help and exit"));
} else {
puts(_(
" -h, --help display this short help and exit\n"
" -H, --long-help display the long help (lists also the advanced options)"));
putchar('\n');
e |= tuklib_wraps(stdout, &wrap1, W_("Other options:"));
putchar('\n');
}
puts(_(
" -V, --version display the version number and exit"));
e |= tuklib_wrapf(stdout, &wrap2,
"-q, --quiet\v%s\r"
"-v, --verbose\v%s",
W_("suppress warnings; specify twice to suppress errors too"),
W_("be verbose; specify twice for even more verbose"));
puts(_("\nWith no FILE, or when FILE is -, read standard input.\n"));
if (long_help) {
e |= tuklib_wrapf(stdout, &wrap2,
"-Q, --no-warn\v%s\r"
" --robot\v%s\r"
"\n"
" --info-memory\v%s\r"
"-h, --help\v%s\r"
"-H, --long-help\v%s",
W_("make warnings not affect the exit status"),
W_("use machine-parsable messages (useful for scripts)"),
W_("display the total amount of RAM and the currently active "
"memory usage limits, and exit"),
W_("display the short help (lists only the basic options)"),
W_("display this long help and exit"));
} else {
e |= tuklib_wrapf(stdout, &wrap2,
"-h, --help\v%s\r"
"-H, --long-help\v%s",
W_("display this short help and exit"),
W_("display the long help (lists also the advanced options)"));
}
// TRANSLATORS: This message indicates the bug reporting address
// for this package. Please add _another line_ saying
// "Report translation bugs to <...>\n" with the email or WWW
// address for translation bugs. Thanks.
printf(_("Report bugs to <%s> (in English or Finnish).\n"),
PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
e |= tuklib_wrapf(stdout, &wrap2, "-V, --version\v%s",
W_("display the version number and exit"));
putchar('\n');
e |= tuklib_wraps(stdout, &wrap0,
W_("With no FILE, or when FILE is -, read standard input."));
putchar('\n');
e |= tuklib_wrapf(stdout, &wrap0,
// TRANSLATORS: This message indicates the bug reporting
// address for this package. Please add another line saying
// "\nReport translation bugs to <...>." with the email or WWW
// address for translation bugs. Thanks!
W_("Report bugs to <%s> (in English or Finnish)."),
PACKAGE_BUGREPORT);
e |= tuklib_wrapf(stdout, &wrap0,
// TRANSLATORS: The first %s is the name of this software.
// The second <%s> is an URL.
W_("%s home page: <%s>"), PACKAGE_NAME, PACKAGE_URL);
#if LZMA_VERSION_STABILITY != LZMA_VERSION_STABILITY_STABLE
puts(_(
e |= tuklib_wraps(stdout, &wrap0, W_(
"THIS IS A DEVELOPMENT VERSION NOT INTENDED FOR PRODUCTION USE."));
#endif
detect_wrapping_errors(e);
tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT);
}
@@ -1150,20 +1299,25 @@ message_help(bool long_help)
extern void
message_filters_help(void)
{
static const struct tuklib_wrap_opt wrap = { .right_margin = 76 };
char *encoder_options;
if (lzma_str_list_filters(&encoder_options, LZMA_VLI_UNKNOWN,
LZMA_STR_ENCODER, NULL) != LZMA_OK)
message_bug();
if (!opt_robot) {
puts(_(
"Filter chains are set using the --filters=FILTERS or\n"
"--filters1=FILTERS ... --filters9=FILTERS options. Each filter in the chain\n"
"can be separated by spaces or '--'. Alternatively a preset <0-9>[e] can be\n"
"specified instead of a filter chain.\n"
));
int e = tuklib_wrapf(stdout, &wrap,
W_("Filter chains are set using the --filters=FILTERS or "
"--filters1=FILTERS ... --filters9=FILTERS options. "
"Each filter in the chain can be separated by spaces or '--'. "
"Alternatively a preset %s can be specified instead of a filter chain."),
"<0-9>[e]");
putchar('\n');
e |= tuklib_wraps(stdout, &wrap,
W_("The supported filters and their options are:"));
puts(_("The supported filters and their options are:"));
detect_wrapping_errors(e);
}
puts(encoder_options);
+9 -6
View File
@@ -82,15 +82,16 @@ parse_options(const char *str, const option_map *opts,
*value++ = '\0';
if (value == NULL || value[0] == '\0')
message_fatal(_("%s: Options must be 'name=value' "
"pairs separated with commas"), str);
message_fatal(_("%s: %s"), tuklib_mask_nonprint(str),
_("Options must be 'name=value' "
"pairs separated with commas"));
// Look for the option name from the option map.
unsigned i = 0;
while (true) {
if (opts[i].name == NULL)
message_fatal(_("%s: Invalid option name"),
name);
tuklib_mask_nonprint(name));
if (strcmp(name, opts[i].name) == 0)
break;
@@ -109,8 +110,9 @@ parse_options(const char *str, const option_map *opts,
}
if (opts[i].map[j].name == NULL)
message_fatal(_("%s: Invalid option value"),
value);
message_fatal(_("%s: %s"),
tuklib_mask_nonprint(value),
_("Invalid option value"));
set(filter_options, i, opts[i].map[j].id, value);
@@ -244,7 +246,8 @@ tuklib_attr_noreturn
static void
error_lzma_preset(const char *valuestr)
{
message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"), valuestr);
message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"),
tuklib_mask_nonprint(valuestr));
}
+1
View File
@@ -28,6 +28,7 @@
#include "tuklib_gettext.h"
#include "tuklib_progname.h"
#include "tuklib_exit.h"
#include "tuklib_mbstr_nonprint.h"
#include "tuklib_mbstr.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
+17 -61
View File
@@ -115,26 +115,7 @@ sandbox_enable_strict_if_allowed(int src_fd lzma_attribute((__unused__)),
// Landlock //
//////////////
#include <linux/landlock.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
// Highest Landlock ABI version supported by this file:
// - For ABI versions 1-3 we don't need anything from <linux/landlock.h>
// that isn't part of version 1.
// - For ABI version 4 we need the larger struct landlock_ruleset_attr
// with the handled_access_net member. That is bundled with the macros
// LANDLOCK_ACCESS_NET_BIND_TCP and LANDLOCK_ACCESS_NET_CONNECT_TCP.
#ifdef LANDLOCK_ACCESS_NET_BIND_TCP
# define LANDLOCK_ABI_MAX 4
#else
# define LANDLOCK_ABI_MAX 3
#endif
/// Landlock ABI version supported by the kernel
static int landlock_abi;
#include "my_landlock.h"
// The required_rights should have those bits set that must not be restricted.
@@ -144,40 +125,19 @@ static int landlock_abi;
static void
enable_landlock(uint64_t required_rights)
{
assert(landlock_abi <= LANDLOCK_ABI_MAX);
if (landlock_abi <= 0)
// Initialize the ruleset to forbid all actions that the available
// Landlock ABI version supports. Return if Landlock isn't supported
// at all.
struct landlock_ruleset_attr attr;
if (my_landlock_ruleset_attr_forbid_all(&attr) == -1)
return;
// We want to set all supported flags in handled_access_fs.
// This way the ruleset will initially forbid access to all
// actions that the available Landlock ABI version supports.
// Exceptions can be added using landlock_add_rule(2) to
// allow certain actions on certain files or directories.
//
// The same flag values are used on all archs. ABI v2 and v3
// both add one new flag.
//
// First in ABI v1: LANDLOCK_ACCESS_FS_EXECUTE = 1ULL << 0
// Last in ABI v1: LANDLOCK_ACCESS_FS_MAKE_SYM = 1ULL << 12
// Last in ABI v2: LANDLOCK_ACCESS_FS_REFER = 1ULL << 13
// Last in ABI v3: LANDLOCK_ACCESS_FS_TRUNCATE = 1ULL << 14
//
// This makes it simple to set the mask based on the ABI
// version and we don't need to care which flags are #defined
// in the installed <linux/landlock.h> for ABI versions 1-3.
const struct landlock_ruleset_attr attr = {
.handled_access_fs = ~required_rights
& ((1ULL << (12 + my_min(3, landlock_abi))) - 1),
#if LANDLOCK_ABI_MAX >= 4
.handled_access_net = landlock_abi < 4 ? 0 :
(LANDLOCK_ACCESS_NET_BIND_TCP
| LANDLOCK_ACCESS_NET_CONNECT_TCP),
#endif
};
// Allow the required rights.
attr.handled_access_fs &= ~required_rights;
const int ruleset_fd = syscall(SYS_landlock_create_ruleset,
&attr, sizeof(attr), 0U);
// Create the ruleset in the kernel. This shouldn't fail.
const int ruleset_fd = my_landlock_create_ruleset(
&attr, sizeof(attr), 0);
if (ruleset_fd < 0)
message_fatal(_("Failed to enable the sandbox"));
@@ -193,9 +153,10 @@ enable_landlock(uint64_t required_rights)
//
// prctl(PR_SET_NO_NEW_PRIVS, ...) was already called in
// sandbox_init() so we don't do it here again.
if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0U) != 0)
if (my_landlock_restrict_self(ruleset_fd, 0) != 0)
message_fatal(_("Failed to enable the sandbox"));
(void)close(ruleset_fd);
return;
}
@@ -213,19 +174,14 @@ sandbox_init(void)
// fails here the error will still be detected when it matters.
(void)prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
// Get the highest Landlock ABI version supported by the kernel.
landlock_abi = syscall(SYS_landlock_create_ruleset,
(void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
// The kernel might support a newer ABI than this file.
if (landlock_abi > LANDLOCK_ABI_MAX)
landlock_abi = LANDLOCK_ABI_MAX;
// These are all in ABI version 1 already. We don't need truncate
// rights because files are created with open() using O_EXCL and
// without O_TRUNC.
//
// LANDLOCK_ACCESS_FS_READ_DIR is included here to get a clear error
// LANDLOCK_ACCESS_FS_READ_DIR is required to synchronize the
// directory before removing the source file.
//
// LANDLOCK_ACCESS_FS_READ_DIR is also helpful to show a clear error
// message if xz is given a directory name. Without this permission
// the message would be "Permission denied" but with this permission
// it's "Is a directory, skipping". It could be worked around with
+7 -5
View File
@@ -163,7 +163,7 @@ uncompressed_name(const char *src_name, const size_t src_len)
if (new_len == 0) {
message_warning(_("%s: Filename has an unknown suffix, "
"skipping"), src_name);
"skipping"), tuklib_mask_nonprint(src_name));
return NULL;
}
@@ -178,13 +178,14 @@ uncompressed_name(const char *src_name, const size_t src_len)
}
/// This message is needed in multiple places in compressed_name(),
/// so the message has been put into its own function.
static void
msg_suffix(const char *src_name, const char *suffix)
{
char *mem = NULL;
message_warning(_("%s: File already has '%s' suffix, skipping"),
src_name, suffix);
tuklib_mask_nonprint(src_name),
tuklib_mask_nonprint_r(suffix, &mem));
free(mem);
return;
}
@@ -390,7 +391,8 @@ suffix_set(const char *suffix)
// Empty suffix and suffixes having a directory separator are
// rejected. Such suffixes would break things later.
if (suffix[0] == '\0' || has_dir_sep(suffix))
message_fatal(_("%s: Invalid filename suffix"), suffix);
message_fatal(_("%s: Invalid filename suffix"),
tuklib_mask_nonprint(suffix));
// Replace the old custom_suffix (if any) with the new suffix.
free(custom_suffix);
+7 -3
View File
@@ -25,7 +25,11 @@ static char bufs[4][128];
// for DJGPP builds.
//
// MSVC doesn't support thousand separators.
#if defined(__DJGPP__) || defined(_MSC_VER)
//
// MinGW-w64 supports thousand separators only with its own stdio functions
// which our sysdefs.h disables when _UCRT && HAVE_SMALL.
#if defined(__DJGPP__) || defined(_MSC_VER) \
|| (defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO == 0)
# define FORMAT_THOUSAND_SEP(prefix, suffix) prefix suffix
# define check_thousand_sep(slot) do { } while (0)
#else
@@ -103,8 +107,8 @@ str_to_uint64(const char *name, const char *value, uint64_t min, uint64_t max)
return max;
if (*value < '0' || *value > '9')
message_fatal(_("%s: Value is not a non-negative "
"decimal integer"), value);
message_fatal(_("%s: %s"), value,
_("Value is not a non-negative decimal integer"));
do {
// Don't overflow.
+91 -3
View File
@@ -4,7 +4,7 @@
.\" Authors: Lasse Collin
.\" Jia Tan
.\"
.TH XZ 1 "2024-04-08" "Tukaani" "XZ Utils"
.TH XZ 1 "2025-03-08" "Tukaani" "XZ Utils"
.
.SH NAME
xz, unxz, xzcat, lzma, unlzma, lzcat \- Compress or decompress .xz and .lzma files
@@ -237,6 +237,8 @@ The memory usage limiter can be enabled with
the command line option \fB\-\-memlimit=\fIlimit\fR.
Often it is more convenient to enable the limiter
by default by setting the environment variable
.\" TRANSLATORS: Don't translate the uppercase XZ_DEFAULTS.
.\" It's a name of an environment variable.
.BR XZ_DEFAULTS ,
for example,
.BR XZ_DEFAULTS=\-\-memlimit=150MiB .
@@ -351,9 +353,24 @@ the command name (for example,
.B unxz
implies
.BR \-\-decompress ).
.IP ""
.\" The DESCRIPTION section already says this but it's good to repeat it
.\" here because the default behavior is a bit dangerous and new users
.\" in a hurry may skip reading the DESCRIPTION section.
After successful compression, the source file is removed
unless writing to standard output or
.B \-\-keep
was specified.
.TP
.BR \-d ", " \-\-decompress ", " \-\-uncompress
Decompress.
.\" The DESCRIPTION section already says this but it's good to repeat it
.\" here because the default behavior is a bit dangerous and new users
.\" in a hurry may skip reading the DESCRIPTION section.
After successful decompression, the source file is removed
unless writing to standard output or
.B \-\-keep
was specified.
.TP
.BR \-t ", " \-\-test
Test the integrity of compressed
@@ -482,6 +499,13 @@ This option has no effect if the operation mode is not
.B \-\-decompress
or
.BR \-\-test .
.IP ""
Since
.B xz
5.7.1alpha,
.B \-\-single\-stream
implies
.BR \-\-keep .
.TP
.B \-\-no\-sparse
Disable creation of sparse files.
@@ -553,6 +577,7 @@ Specify the file
to compress or decompress:
.RS
.TP
.\" TRANSLATORS: Don't translate bold string B<auto>.
.B auto
This is the default.
When compressing,
@@ -639,6 +664,9 @@ Supported
types:
.RS
.TP
.\" TRANSLATORS: Don't translate the bold strings B<none>, B<crc32>,
.\" B<crc64>, and B<sha256>. The command line option --check accepts
.\" only the untranslated strings.
.B none
Don't calculate an integrity check at all.
This is usually a bad idea.
@@ -1039,6 +1067,28 @@ is unsuitable for decompressing the stream in real time due to how
.B xz
does buffering.
.TP
.B \-\-no\-sync
Do not synchronize the target file and its directory
to the storage device before removing the source file.
This can improve performance if compressing or decompressing
many small files.
However, if the system crashes soon after the deletion,
it is possible that the target file was not written
to the storage device but the delete operation was.
In that case neither the original source file
nor the target file is available.
.IP ""
This option has an effect only when
.B xz
is going to remove the source file.
In other cases synchronization is never done.
.IP ""
The synchronization and
.B \-\-no\-sync
were added in
.B xz
5.7.1alpha.
.TP
.BI \-\-memlimit\-compress= limit
Set a memory usage limit for compression.
If this option is specified multiple times,
@@ -1453,6 +1503,11 @@ LZMA1 and LZMA2 share the same set of
.IR options :
.RS
.TP
.\" TRANSLATORS: Don't translate bold strings like B<preset>, B<dict>,
.\" B<mode>, B<nice>, B<fast>, or B<normal> because those are command line
.\" options. On the other hand, do translate the italic strings like
.\" I<preset>, I<size>, and I<mode>, because such italic strings are
.\" placeholders which a user replaces with an actual value.
.BI preset= preset
Reset all LZMA1 or LZMA2
.I options
@@ -2103,6 +2158,11 @@ uses tab-separated output.
The first column of every line has a string
that indicates the type of the information found on that line:
.TP
.\" TRANSLATORS: The bold strings B<name>, B<file>, B<stream>, B<block>,
.\" B<summary>, and B<totals> are produced by the xz tool for scripts to
.\" parse, thus the untranslated strings must be included in the translated
.\" man page. It may be useful to provide a translated string in parenthesis
.\" without bold, for example: "B<name> (nimi)"
.B name
This is always the first line when starting to list a file.
The second column on the line is the filename.
@@ -2181,6 +2241,9 @@ are displayed instead of the ratio.
.IP 7. 4
Comma-separated list of integrity check names.
The following strings are used for the known check types:
.\" TRANSLATORS: Don't translate the bold strings B<None>, B<CRC32>,
.\" B<CRC64>, B<SHA-256>, or B<Unknown-> here. In robot mode, xz produces
.\" them in untranslated form for scripts to parse.
.BR None ,
.BR CRC32 ,
.BR CRC64 ,
@@ -2467,6 +2530,7 @@ prints the version number of
.B xz
and liblzma in the following format:
.PP
.\" TRANSLATORS: Don't translate the uppercase XZ_VERSION or LIBLZMA_VERSION.
.BI XZ_VERSION= XYYYZZZS
.br
.BI LIBLZMA_VERSION= XYYYZZZS
@@ -2521,6 +2585,8 @@ don't affect the exit status.
.B xz
parses space-separated lists of options
from the environment variables
.\" TRANSLATORS: Don't translate the uppercase XZ_DEFAULTS or XZ_OPT.
.\" They are names of environment variables.
.B XZ_DEFAULTS
and
.BR XZ_OPT ,
@@ -2530,14 +2596,36 @@ all non-options are silently ignored.
Parsing is done with
.BR getopt_long (3)
which is used also for the command line arguments.
.PP
.B Warning:
By setting these environment variables,
one is effectively modifying programs and scripts that run
.BR xz .
Most of the time it is safe to set memory usage limits, number of threads,
and compression options via the environment variables.
However, some options can break scripts.
An obvious example is
.B \-\-help
which makes
.B xz
show the help text instead of compressing or decompressing a file.
More subtle examples are
.B \-\-quiet
and
.BR \-\-verbose .
In many cases it works well to enable the progress indicator using
.BR \-\-verbose ,
but in some situations the extra messages create problems.
The verbosity level also affects the behavior of
.BR \-\-list .
.TP
.B XZ_DEFAULTS
User-specific or system-wide default options.
Typically this is set in a shell initialization script to enable
.BR xz 's
memory usage limiter by default.
memory usage limiter by default or set the default number of threads.
Excluding shell initialization scripts
and similar special cases, scripts must never set or unset
and similar special cases, scripts should never set or unset
.BR XZ_DEFAULTS .
.TP
.B XZ_OPT
+40 -35
View File
@@ -14,6 +14,7 @@
#include <stdarg.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#ifndef _MSC_VER
@@ -25,14 +26,7 @@
#endif
#ifdef HAVE_LINUX_LANDLOCK
# include <linux/landlock.h>
# include <sys/prctl.h>
# include <sys/syscall.h>
# ifdef LANDLOCK_ACCESS_NET_BIND_TCP
# define LANDLOCK_ABI_MAX 4
# else
# define LANDLOCK_ABI_MAX 3
# endif
# include "my_landlock.h"
#endif
#if defined(HAVE_CAP_RIGHTS_LIMIT) || defined(HAVE_PLEDGE) \
@@ -42,6 +36,7 @@
#include "getopt.h"
#include "tuklib_progname.h"
#include "tuklib_mbstr_nonprint.h"
#include "tuklib_exit.h"
#ifdef TUKLIB_DOSLIKE
@@ -209,7 +204,8 @@ uncompress(lzma_stream *strm, FILE *file, const char *filename)
// an error occurred. ferror() doesn't
// touch errno.
my_errorf("%s: Error reading input file: %s",
filename, strerror(errno));
tuklib_mask_nonprint(filename),
strerror(errno));
exit(EXIT_FAILURE);
}
@@ -234,8 +230,17 @@ uncompress(lzma_stream *strm, FILE *file, const char *filename)
// Wouldn't be a surprise if writing to stderr
// would fail too but at least try to show an
// error message.
my_errorf("Cannot write to standard output: "
#if defined(_WIN32) && !defined(__CYGWIN__)
// On native Windows, broken pipe is reported
// as EINVAL. Don't show an error message
// in this case.
if (errno != EINVAL)
#endif
{
my_errorf("Cannot write to "
"standard output: "
"%s", strerror(errno));
}
exit(EXIT_FAILURE);
}
@@ -292,7 +297,8 @@ uncompress(lzma_stream *strm, FILE *file, const char *filename)
break;
}
my_errorf("%s: %s", filename, msg);
my_errorf("%s: %s", tuklib_mask_nonprint(filename),
msg);
exit(EXIT_FAILURE);
}
}
@@ -334,33 +340,20 @@ sandbox_enter(int src_fd)
(void)src_fd;
#elif defined(HAVE_LINUX_LANDLOCK)
int landlock_abi = syscall(SYS_landlock_create_ruleset,
(void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (landlock_abi > 0) {
if (landlock_abi > LANDLOCK_ABI_MAX)
landlock_abi = LANDLOCK_ABI_MAX;
const struct landlock_ruleset_attr attr = {
.handled_access_fs = (1ULL
<< (12 + my_min(3, landlock_abi))) - 1,
# if LANDLOCK_ABI_MAX >= 4
.handled_access_net = landlock_abi < 4 ? 0 :
(LANDLOCK_ACCESS_NET_BIND_TCP
| LANDLOCK_ACCESS_NET_CONNECT_TCP),
# endif
};
const int ruleset_fd = syscall(SYS_landlock_create_ruleset,
&attr, sizeof(attr), 0U);
struct landlock_ruleset_attr attr;
if (my_landlock_ruleset_attr_forbid_all(&attr) > 0) {
const int ruleset_fd = my_landlock_create_ruleset(
&attr, sizeof(attr), 0);
if (ruleset_fd < 0)
goto error;
// All files we need should have already been opened. Thus,
// we don't need to add any rules using landlock_add_rule(2)
// before activating the sandbox.
if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0U) != 0)
if (my_landlock_restrict_self(ruleset_fd, 0) != 0)
goto error;
(void)close(ruleset_fd);
}
(void)src_fd;
@@ -391,6 +384,9 @@ error:
int
main(int argc, char **argv)
{
// Initialize progname which will be used in error messages.
tuklib_progname_init(argv);
#ifdef HAVE_PLEDGE
// OpenBSD's pledge(2) sandbox.
// Initially enable the sandbox slightly more relaxed so that
@@ -416,8 +412,15 @@ main(int argc, char **argv)
(void)prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
#endif
// Initialize progname which we will be used in error messages.
tuklib_progname_init(argv);
// We need to set the locale even though we don't have any
// translated messages:
//
// - tuklib_mask_nonprint() has locale-specific behavior (LC_CTYPE).
//
// - This is needed on Windows to make non-ASCII filenames display
// properly when the active code page has been set to UTF-8
// in the application manifest.
setlocale(LC_ALL, "");
// Parse the command line options.
parse_options(argc, argv);
@@ -453,8 +456,10 @@ main(int argc, char **argv)
src_name = argv[optind];
src_file = fopen(src_name, "rb");
if (src_file == NULL) {
my_errorf("%s: %s", src_name,
strerror(errno));
my_errorf("%s: %s",
tuklib_mask_nonprint(
src_name),
strerror(errno));
exit(EXIT_FAILURE);
}
}
+1 -1
View File
@@ -43,7 +43,7 @@
.4byte NT_FREEBSD_ABI_TAG
1: .asciz NOTE_FREEBSD_VENDOR
2: .p2align 2
3: .4byte __FreeBSD_version
3: .4byte 1403000
4:
.section .note.GNU-stack,"",%progbits
+1 -1
View File
@@ -122,7 +122,7 @@ function appeared in
The
.Fn psiginfo
function appeared in
.Fx 15.0 ,
.Fx 14.3 ,
.Nx 6.0 ,
and
.Dx 4.1 .
+1 -1
View File
@@ -103,4 +103,4 @@ is unknown.
The
.Nm
function first appeared in
.Fx 15.0 .
.Fx 14.3 .
+1 -1
View File
@@ -676,7 +676,7 @@ The
option originated in
.Ox 4.9
and first appeared in
.Fx 15.0 .
.Fx 14.3 .
The
.Fx
implementation aims to be source-compatible.
+1 -1
View File
@@ -248,7 +248,7 @@ does not.
The
.Fn setcred
system call appeared in
.Fx 15.0 .
.Fx 14.3 .
.Pp
Traditionally in UNIX, all credential changes beyond shuffles of effective, real
and saved IDs have been done by setuid binaries that successively call multiple
+3 -6
View File
@@ -81,16 +81,13 @@ SRCS+= common.c \
.PATH: ${LZMADIR}/check
SRCS+= check.c \
crc32_table.c \
crc64_table.c
SRCS+= check.c \
crc32_fast.c \
crc64_fast.c
.if defined(MACHINE_ARCH) && ${MACHINE_ARCH} == "i386"
SRCS+= crc32_x86.S \
crc64_x86.S
ACFLAGS+= -Wa,--noexecstack
.else
SRCS+= crc32_fast.c \
crc64_fast.c
.endif
.PATH: ${LZMADIR}/lz
+9
View File
@@ -118,6 +118,15 @@ XZ_5.6 {
lzma_mt_block_size;
};
XZ_5.8 {
lzma_bcj_arm64_encode;
lzma_bcj_arm64_decode;
lzma_bcj_riscv_encode;
lzma_bcj_riscv_decode;
lzma_bcj_x86_encode;
lzma_bcj_x86_decode;
};
XZprivate_1.0 {
lzma_alloc;
lzma_alloc_zero;
+4 -1
View File
@@ -11,6 +11,9 @@ XZ_5.4 {
XZ_5.6 {
} XZ_5.4;
XZprivate_1.0 {
XZ_5.8 {
} XZ_5.6;
XZprivate_1.0 {
} XZ_5.8;
+15 -3
View File
@@ -68,6 +68,12 @@
/* Define to 1 if you have the <cpuid.h> header file. */
#define HAVE_CPUID_H 1
/* Define to 1 if the 32-bit x86 CRC assembly files are used. */
/* FreeBSD - only enabled for i386 */
#if defined(__FreeBSD__) && defined(__i386__)
#define HAVE_CRC_X86_ASM 1
#endif
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
/* FreeBSD - disabled intentionally */
@@ -193,6 +199,9 @@
*/
/* #undef HAVE_LINUX_LANDLOCK */
/* Define to 1 if 64-bit LoongArch CRC32 instructions are supported. */
/* #undef HAVE_LOONGARCH_CRC32 */
/* Define to 1 if .lz (lzip) decompression support is enabled. */
#define HAVE_LZIP_DECODER 1
@@ -335,6 +344,9 @@
/* Define to 1 if you have the 'utimes' function. */
/* #undef HAVE_UTIMES */
/* Define to 1 if you have the 'vasprintf' function. */
#define HAVE_VASPRINTF 1
/* Define to 1 or 0, depending whether the compiler supports simple visibility
declarations. */
#define HAVE_VISIBILITY 1
@@ -391,7 +403,7 @@
#define PACKAGE_NAME "XZ Utils"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "XZ Utils 5.6.3"
#define PACKAGE_STRING "XZ Utils 5.8.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "xz"
@@ -400,7 +412,7 @@
#define PACKAGE_URL "https://tukaani.org/xz/"
/* Define to the version of this package. */
#define PACKAGE_VERSION "5.6.3"
#define PACKAGE_VERSION "5.8.1"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
@@ -565,7 +577,7 @@
/* Version number of package */
#define VERSION "5.6.3"
#define VERSION "5.8.1"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
+103 -2
View File
@@ -1,7 +1,7 @@
---
-- SPDX-License-Identifier: BSD-2-Clause
--
-- Copyright(c) 2022 Baptiste Daroussin <[email protected]>
-- Copyright(c) 2022-2025 Baptiste Daroussin <[email protected]>
local unistd = require("posix.unistd")
local sys_stat = require("posix.sys.stat")
@@ -261,6 +261,106 @@ local function update_sshd_config(key, value)
os.rename(sshd_config .. ".nuageinit", sshd_config)
end
local function exec_change_password(user, password, type, expire)
local root = os.getenv("NUAGE_FAKE_ROOTDIR")
local cmd = "pw "
if root then
cmd = cmd .. "-R " .. root .. " "
end
local postcmd = " -H 0"
local input = password
if type ~= nil and type == "text" then
postcmd = " -h 0"
else
if password == "RANDOM" then
input = nil
postcmd = " -w random"
end
end
cmd = cmd .. "usermod " .. user .. postcmd
if expire then
cmd = cmd .. " -p 1"
else
cmd = cmd .. " -p 0"
end
local f = io.popen(cmd .. " >/dev/null", "w")
if input then
f:write(input)
end
-- ignore stdout to avoid printing the password in case of random password
local r = f:close(cmd)
if not r then
warnmsg("fail to change user password ".. user)
warnmsg(cmd)
end
end
local function change_password_from_line(line, expire)
local user, password = line:match("%s*(%w+):(%S+)%s*")
local type = nil
if user and password then
if password == "R" then
password = "RANDOM"
end
if not password:match("^%$%d+%$%w+%$") then
if password ~= "RANDOM" then
type = "text"
end
end
exec_change_password(user, password, type, expire)
end
end
local function chpasswd(obj)
if type(obj) ~= "table" then
warnmsg("Invalid chpasswd entry, expecting an object")
return
end
local expire = false
if obj.expire ~= nil then
if type(obj.expire) == "boolean" then
expire = obj.expire
else
warnmsg("Invalid type for chpasswd.expire, expecting a boolean, got a ".. type(obj.expire))
end
end
if obj.users ~= nil then
if type(obj.users) ~= "table" then
warnmsg("Invalid type for chpasswd.users, expecting a list, got a ".. type(obj.users))
goto list
end
for _, u in ipairs(obj.users) do
if type(u) ~= "table" then
warnmsg("Invalid chpasswd.users entry, expecting an object, got a " .. type(u))
goto next
end
if not u.name then
warnmsg("Invalid entry for chpasswd.users: missing 'name'")
goto next
end
if not u.password then
warnmsg("Invalid entry for chpasswd.users: missing 'password'")
goto next
end
exec_change_password(u.name, u.password, u.type, expire)
::next::
end
end
::list::
if obj.list ~= nil then
warnmsg("chpasswd.list is deprecated consider using chpasswd.users")
if type(obj.list) == "string" then
for line in obj.list:gmatch("[^\n]+") do
change_password_from_line(line, expire)
end
elseif type(obj.list) == "table" then
for _, u in ipairs(obj.list) do
change_password_from_line(u, expire)
end
end
end
end
local n = {
warn = warnmsg,
err = errmsg,
@@ -270,7 +370,8 @@ local n = {
adduser = adduser,
addgroup = addgroup,
addsshkey = addsshkey,
update_sshd_config = update_sshd_config
update_sshd_config = update_sshd_config,
chpasswd = chpasswd
}
return n
+5 -1
View File
@@ -2,7 +2,7 @@
---
-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
--
-- Copyright(c) 2022 Baptiste Daroussin <[email protected]>
-- Copyright(c) 2022-2025 Baptiste Daroussin <[email protected]>
local nuage = require("nuage")
local ucl = require("ucl")
@@ -359,6 +359,10 @@ if line == "#cloud-config" then
end
nuage.update_sshd_config("PasswordAuthentication", value)
end
if obj.chpasswd ~= nil then
nuage.chpasswd(obj.chpasswd)
end
else
local res, err = os.execute(path .. "/" .. ud)
if not res then
+175
View File
@@ -20,6 +20,9 @@ atf_test_case config2_network
atf_test_case config2_network_static_v4
atf_test_case config2_ssh_keys
atf_test_case nocloud_userdata_cloudconfig_ssh_pwauth
atf_test_case nocloud_userdata_cloudconfig_chpasswd
atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_string
atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_list
args_body()
{
@@ -512,6 +515,175 @@ EOF
atf_check -o inline:"PasswordAuthentication no\n" cat etc/ssh/sshd_config
}
nocloud_userdata_cloudconfig_chpasswd_head()
{
atf_set "require.user" root
}
nocloud_userdata_cloudconfig_chpasswd_body()
{
mkdir -p etc
cat > etc/master.passwd << EOF
root:*:0:0::0:0:Charlie &:/root:/bin/sh
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
EOF
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
cat > etc/group << EOF
wheel:*:0:root
users:*:1:
EOF
mkdir -p media/nuageinit
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
users:
- { user: "sys", password: RANDOM }
EOF
atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'name'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
# nothing modified
atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
users:
- { name: "sys", pwd: RANDOM }
EOF
atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'password'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
# nothing modified
atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: false
users:
- { name: "sys", password: RANDOM }
EOF
# not empty because the password is printed to stdout
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
users:
- { name: "sys", password: RANDOM }
EOF
# not empty because the password is printed to stdout
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
users:
- { name: "user", password: "$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/" }
EOF
# not empty because the password is printed to stdout
atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::1:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
}
nocloud_userdata_cloudconfig_chpasswd_list_string_head()
{
atf_set "require.user" root
}
nocloud_userdata_cloudconfig_chpasswd_list_string_body()
{
mkdir -p etc
cat > etc/master.passwd << EOF
root:*:0:0::0:0:Charlie &:/root:/bin/sh
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
EOF
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
cat > etc/group << EOF
wheel:*:0:root
users:*:1:
EOF
mkdir -p media/nuageinit
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
list: |
sys:RANDOM
EOF
atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: false
list: |
sys:plop
user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
root:R
EOF
atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root
}
nocloud_userdata_cloudconfig_chpasswd_list_list_head()
{
atf_set "require.user" root
}
nocloud_userdata_cloudconfig_chpasswd_list_list_body()
{
mkdir -p etc
cat > etc/master.passwd << EOF
root:*:0:0::0:0:Charlie &:/root:/bin/sh
sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
user:*:1:0::0:0:Sys:/home/sys:/bin/sh
EOF
pwd_mkdb -d etc "${PWD}"/etc/master.passwd
cat > etc/group << EOF
wheel:*:0:root
users:*:1:
EOF
mkdir -p media/nuageinit
printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: true
list:
- sys:RANDOM
EOF
atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
cat > media/nuageinit/user-data << 'EOF'
#cloud-config
chpasswd:
expire: false
list:
- sys:plop
- user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
- root:R
EOF
atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys
atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user
atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root
}
atf_init_test_cases()
{
atf_add_test_case args
@@ -528,4 +700,7 @@ atf_init_test_cases()
atf_add_test_case config2_network_static_v4
atf_add_test_case config2_ssh_keys
atf_add_test_case nocloud_userdata_cloudconfig_ssh_pwauth
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_string
atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_list
}
+2 -2
View File
@@ -59,9 +59,9 @@ oomprotect_all_body()
atf_check -s exit:0 -o inline:"Starting ${__name}.\n" -e empty \
/bin/sh "$__script" "$__name" "$__pidfile" "$__childpidfile" onestart
atf_check -s exit:0 -o match:'^..1..... .......1$' -e empty \
ps -p "$(cat "$__pidfile")" -ax -o flags,flags2
ps -p "$(cat "$__pidfile")" -o flags,flags2
atf_check -s exit:0 -o match:'^..1..... .......1$' -e empty \
ps -p "$(cat "$__childpidfile")" -ax -o flags,flags2
ps -p "$(cat "$__childpidfile")" -o flags,flags2
atf_check -s exit:0 -o ignore -e empty \
/bin/sh "$__script" "$__name" "$__pidfile" "$__childpidfile" onestop
}
+1 -1
View File
@@ -153,7 +153,7 @@ EOF
PKG_WWW "${PKG_WWW}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
UCLFILES "${srctree}/release/packages/" \
${uclsource} ${uclfile}
${uclfile} ${uclfile}
return 0
}
Loaded 100 of 178 files, more files were not shown because too many files have changed in this diff. Show more