Улучшения сборки, небольшие изменения в коде
This commit is contained in:
parent
8535d05433
commit
4248bf4f5b
63
busybox-1_37_0/.gitignore
vendored
Normal file
63
busybox-1_37_0/.gitignore
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# Kbuild ignores
|
||||
#
|
||||
.*
|
||||
*.o
|
||||
*.o.*
|
||||
*.a
|
||||
*.s
|
||||
Kbuild
|
||||
Config.in
|
||||
|
||||
#
|
||||
# Never ignore these
|
||||
#
|
||||
!.gitignore
|
||||
|
||||
#
|
||||
# Normal output
|
||||
#
|
||||
/busybox
|
||||
/busybox_old
|
||||
/busybox_unstripped*
|
||||
|
||||
#
|
||||
# Backups / patches
|
||||
#
|
||||
*~
|
||||
*.orig
|
||||
*.rej
|
||||
/*.patch
|
||||
|
||||
#
|
||||
# debugging stuff
|
||||
#
|
||||
core
|
||||
.gdb_history
|
||||
.gdbinit
|
||||
|
||||
#
|
||||
# testing output
|
||||
#
|
||||
/busybox.links
|
||||
/runtest-tempdir-links
|
||||
/testsuite/echo-ne
|
||||
|
||||
#
|
||||
# cscope output
|
||||
#
|
||||
cscope.files
|
||||
cscope.in.out
|
||||
cscope.out
|
||||
cscope.po.out
|
||||
|
||||
#
|
||||
# ctags output
|
||||
#
|
||||
tags
|
||||
TAGS
|
||||
|
||||
#
|
||||
# user-supplied scripts
|
||||
#
|
||||
/embed
|
186
busybox-1_37_0/AUTHORS
Normal file
186
busybox-1_37_0/AUTHORS
Normal file
@ -0,0 +1,186 @@
|
||||
List of the authors of code contained in BusyBox.
|
||||
|
||||
If you have code in BusyBox, you should be listed here. If you should be
|
||||
listed, or the description of what you have done needs more detail, or is
|
||||
incorrect, _please_ let me know.
|
||||
|
||||
-Erik
|
||||
|
||||
-----------
|
||||
|
||||
Peter Willis <psyphreak@phreaker.net>
|
||||
eject
|
||||
|
||||
Emanuele Aina <emanuele.aina@tiscali.it>
|
||||
run-parts
|
||||
|
||||
Erik Andersen <andersen@codepoet.org>
|
||||
Tons of new stuff, major rewrite of most of the
|
||||
core apps, tons of new apps as noted in header files.
|
||||
Lots of tedious effort writing these boring docs that
|
||||
nobody is going to actually read.
|
||||
|
||||
Laurence Anderson <l.d.anderson@warwick.ac.uk>
|
||||
rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm
|
||||
|
||||
Jeff Angielski <jeff@theptrgroup.com>
|
||||
ftpput, ftpget
|
||||
|
||||
Enrik Berkhan <Enrik.Berkhan@inka.de>
|
||||
setconsole
|
||||
|
||||
Jim Bauer <jfbauer@nfr.com>
|
||||
modprobe shell dependency
|
||||
|
||||
Edward Betts <edward@debian.org>
|
||||
expr, hostid, logname, whoami
|
||||
|
||||
John Beppu <beppu@codepoet.org>
|
||||
du, nslookup, sort
|
||||
|
||||
David Brownell <dbrownell@users.sourceforge.net>
|
||||
zcip
|
||||
|
||||
Brian Candler <B.Candler@pobox.com>
|
||||
tiny-ls(ls)
|
||||
|
||||
Randolph Chung <tausq@debian.org>
|
||||
fbset, ping, hostname
|
||||
|
||||
Dave Cinege <dcinege@psychosis.com>
|
||||
more(v2), makedevs, dutmp, modularization, auto links file,
|
||||
various fixes, Linux Router Project maintenance
|
||||
|
||||
Jordan Crouse <jordan@cosmicpenguin.net>
|
||||
ipcalc
|
||||
|
||||
Magnus Damm <damm@opensource.se>
|
||||
tftp client
|
||||
insmod powerpc support
|
||||
|
||||
Larry Doolittle <ldoolitt@recycle.lbl.gov>
|
||||
pristine source directory compilation, lots of patches and fixes.
|
||||
|
||||
Glenn Engel <glenne@engel.org>
|
||||
httpd
|
||||
|
||||
Gennady Feldman <gfeldman@gena01.com>
|
||||
Sysklogd (single threaded syslogd, IPC Circular buffer support,
|
||||
logread), various fixes.
|
||||
|
||||
Robert Griebl <sandman@handhelds.org>
|
||||
modprobe, hwclock, suid/sgid handling, tinylogin integration
|
||||
many bugfixes and enhancements
|
||||
|
||||
Karl M. Hegbloom <karlheg@debian.org>
|
||||
cp_mv.c, the test suite, various fixes to utility.c, &c.
|
||||
|
||||
Daniel Jacobowitz <dan@debian.org>
|
||||
mktemp.c
|
||||
|
||||
Matt Kraai <kraai@alumni.cmu.edu>
|
||||
documentation, bugfixes, test suite
|
||||
|
||||
Rob Landley <rob@landley.net>
|
||||
Became busybox maintainer in 2006.
|
||||
|
||||
sed (major rewrite in 2003, and I now maintain the thing)
|
||||
bunzip2 (complete from-scratch rewrite, then mjn3 optimized the result)
|
||||
sort (more or less from scratch rewrite in 2004, I now maintain it)
|
||||
mount (rewrite in 2005, I maintain the new one)
|
||||
|
||||
Stephan Linz <linz@li-pro.net>
|
||||
ipcalc, Red Hat equivalence
|
||||
|
||||
John Lombardo <john@deltanet.com>
|
||||
tr
|
||||
|
||||
Glenn McGrath <glenn.l.mcgrath@gmail.com>
|
||||
Common unarchiving code and unarchiving applets, ifupdown, ftpgetput,
|
||||
nameif, sed, patch, fold, install, uudecode.
|
||||
Various bugfixes, review and apply numerous patches.
|
||||
|
||||
Manuel Novoa III <mjn3@codepoet.org>
|
||||
cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes,
|
||||
mesg, vconfig, nice, renice,
|
||||
make_directory, parse_mode, dirname, mode_string,
|
||||
get_last_path_component, simplify_path, and a number trivial libbb routines
|
||||
|
||||
also bug fixes, partial rewrites, and size optimizations in
|
||||
ash, basename, cal, cmp, cp, df, du, echo, env, ln, logname, md5sum, mkdir,
|
||||
mv, realpath, rm, sort, tail, touch, uname, watch, arith, human_readable,
|
||||
interface, dutmp, ifconfig, route
|
||||
|
||||
Vladimir Oleynik <dzo@simtreas.ru>
|
||||
cmdedit; bb_mkdep, xargs(current), httpd(current);
|
||||
ports: ash, crond, fdisk (initial, unmaintained now), inetd, stty, traceroute,
|
||||
top;
|
||||
locale, various fixes
|
||||
and irreconcilable critic of everything not perfect.
|
||||
|
||||
Bruce Perens <bruce@pixar.com>
|
||||
Original author of BusyBox in 1995, 1996. Some of his code can
|
||||
still be found hiding here and there...
|
||||
|
||||
Rodney Radford <rradford@mindspring.com>
|
||||
ipcs, ipcrm
|
||||
|
||||
Tim Riker <Tim@Rikers.org>
|
||||
bug fixes, member of fan club
|
||||
|
||||
Kent Robotti <robotti@metconnect.com>
|
||||
reset, tons and tons of bug reports and patches.
|
||||
|
||||
Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
|
||||
wget - Contributed by permission of Covad Communications
|
||||
|
||||
Pavel Roskin <proski@gnu.org>
|
||||
Lots of bugs fixes and patches.
|
||||
|
||||
Gyepi Sam <gyepi@praxis-sw.com>
|
||||
Remote logging feature for syslogd
|
||||
|
||||
Rob Sullivan <cogito.ergo.cogito@gmail.com>
|
||||
comm
|
||||
|
||||
Linus Torvalds
|
||||
mkswap, fsck.minix, mkfs.minix
|
||||
|
||||
Linus Walleij
|
||||
fbset and fbsplash config RGBA parsing
|
||||
rewrite of mdev helper to create devices from /sys/dev
|
||||
|
||||
Mark Whitley <markw@codepoet.org>
|
||||
grep, sed, cut, xargs(previous),
|
||||
style-guide, new-applet-HOWTO, bug fixes, etc.
|
||||
|
||||
Charles P. Wright <cpwright@villagenet.com>
|
||||
gzip, mini-netcat(nc)
|
||||
|
||||
Enrique Zanardi <ezanardi@ull.es>
|
||||
tarcat (since removed), loadkmap, various fixes, Debian maintenance
|
||||
|
||||
Tito Ragusa <farmatito@tiscali.it>
|
||||
devfsd and size optimizations in strings, openvt, chvt, deallocvt, hdparm,
|
||||
fdformat, lsattr, chattr, id and eject.
|
||||
|
||||
Paul Fox <pgf@foxharp.boston.ma.us>
|
||||
vi editing mode for ash, various other patches/fixes
|
||||
|
||||
Roberto A. Foglietta <me@roberto.foglietta.name>
|
||||
port: dnsd
|
||||
|
||||
Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
|
||||
misc
|
||||
|
||||
Mike Frysinger <vapier@gentoo.org>
|
||||
initial e2fsprogs, printenv, setarch, sum, misc
|
||||
|
||||
Jie Zhang <jie.zhang@analog.com>
|
||||
fixed two bugs in msh and hush (exitcode of killed processes)
|
||||
|
||||
Maxime Coste <mawww@kakoune.org>
|
||||
paste implementation
|
||||
|
||||
Roger Knecht <rknecht@pm.me>
|
||||
tree
|
142
busybox-1_37_0/INSTALL
Normal file
142
busybox-1_37_0/INSTALL
Normal file
@ -0,0 +1,142 @@
|
||||
Building:
|
||||
=========
|
||||
|
||||
The BusyBox build process is similar to the Linux kernel build:
|
||||
|
||||
make menuconfig # This creates a file called ".config"
|
||||
make # This creates the "busybox" executable
|
||||
make install # or make CONFIG_PREFIX=/path/from/root install
|
||||
|
||||
The full list of configuration and install options is available by typing:
|
||||
|
||||
make help
|
||||
|
||||
Quick Start:
|
||||
============
|
||||
|
||||
The easy way to try out BusyBox for the first time, without having to install
|
||||
it, is to enable all features and then use "standalone shell" mode with a
|
||||
blank command $PATH.
|
||||
|
||||
To enable all features, use "make defconfig", which produces the largest
|
||||
general-purpose configuration. It's allyesconfig minus debugging options,
|
||||
optional packaging choices, and a few special-purpose features requiring
|
||||
extra configuration to use. Then enable "standalone shell" feature:
|
||||
|
||||
make defconfig
|
||||
make menuconfig
|
||||
# select Busybox Settings
|
||||
# then General Configuration
|
||||
# then exec prefers applets
|
||||
# exit back to top level menu
|
||||
# select Shells
|
||||
# then Standalone shell
|
||||
# exit back to top level menu
|
||||
# exit and save new configuration
|
||||
# OR
|
||||
# use these commands to modify .config directly:
|
||||
sed -e 's/.*FEATURE_PREFER_APPLETS.*/CONFIG_FEATURE_PREFER_APPLETS=y/' -i .config
|
||||
sed -e 's/.*FEATURE_SH_STANDALONE.*/CONFIG_FEATURE_SH_STANDALONE=y/' -i .config
|
||||
make
|
||||
PATH= ./busybox ash
|
||||
|
||||
Standalone shell mode causes busybox's built-in command shell to run
|
||||
any built-in busybox applets directly, without looking for external
|
||||
programs by that name. Supplying an empty command path (as above) means
|
||||
the only commands busybox can find are the built-in ones.
|
||||
|
||||
Note that the standalone shell requires CONFIG_BUSYBOX_EXEC_PATH
|
||||
to be set appropriately, depending on whether or not /proc/self/exe is
|
||||
available. If you do not have /proc, then point that config option
|
||||
to the location of your busybox binary, usually /bin/busybox.
|
||||
Another solution is to patch the kernel (see
|
||||
examples/linux-*_proc_self_exe.patch) to make exec("/proc/self/exe")
|
||||
always work.
|
||||
|
||||
Configuring Busybox:
|
||||
====================
|
||||
|
||||
Busybox is optimized for size, but enabling the full set of functionality
|
||||
still results in a fairly large executable -- more than 1 megabyte when
|
||||
statically linked. To save space, busybox can be configured with only the
|
||||
set of applets needed for each environment. The minimal configuration, with
|
||||
all applets disabled, produces a 4k executable. (It's useless, but very small.)
|
||||
|
||||
The manual configurator "make menuconfig" modifies the existing configuration.
|
||||
(For systems without ncurses, try "make config" instead.) The two most
|
||||
interesting starting configurations are "make allnoconfig" (to start with
|
||||
everything disabled and add just what you need), and "make defconfig" (to
|
||||
start with everything enabled and remove what you don't need). If menuconfig
|
||||
is run without an existing configuration, make defconfig will run first to
|
||||
create a known starting point.
|
||||
|
||||
Other starting configurations (mostly used for testing purposes) include
|
||||
"make allbareconfig" (enables all applets but disables all optional features),
|
||||
"make allyesconfig" (enables absolutely everything including debug features),
|
||||
and "make randconfig" (produce a random configuration). The configs/ directory
|
||||
contains a number of additional configuration files ending in _defconfig which
|
||||
are useful in specific cases. "make help" will list them.
|
||||
|
||||
Configuring BusyBox produces a file ".config", which can be saved for future
|
||||
use. Run "make oldconfig" to bring a .config file from an older version of
|
||||
busybox up to date.
|
||||
|
||||
Installing Busybox:
|
||||
===================
|
||||
|
||||
Busybox is a single executable that can behave like many different commands,
|
||||
and BusyBox uses the name it was invoked under to determine the desired
|
||||
behavior. (Try "mv busybox ls" and then "./ls -l".)
|
||||
|
||||
Installing busybox consists of creating symlinks (or hardlinks) to the busybox
|
||||
binary for each applet enabled in busybox, and making sure these symlinks are
|
||||
in the shell's command $PATH. Running "make install" creates these symlinks,
|
||||
or "make install-hardlinks" creates hardlinks instead (useful on systems with
|
||||
a limited number of inodes). This install process uses the file
|
||||
"busybox.links" (created by make), which contains the list of enabled applets
|
||||
and the path at which to install them.
|
||||
|
||||
Installing links to busybox is not always necessary. The special applet name
|
||||
"busybox" (or with any optional suffix, such as "busybox-static") uses the
|
||||
first argument to determine which applet to behave as, for example
|
||||
"./busybox cat LICENSE". (Running the busybox applet with no arguments gives
|
||||
a list of all enabled applets.) The standalone shell can also call busybox
|
||||
applets without links to busybox under other names in the filesystem. You can
|
||||
also configure a standalone install capability into the busybox base applet,
|
||||
and then install such links at runtime with one of "busybox --install" (for
|
||||
hardlinks) or "busybox --install -s" (for symlinks).
|
||||
|
||||
If you enabled the busybox shared library feature (libbusybox.so) and want
|
||||
to run tests without installing, set your LD_LIBRARY_PATH accordingly when
|
||||
running the executable:
|
||||
|
||||
LD_LIBRARY_PATH=`pwd` ./busybox
|
||||
|
||||
Building out-of-tree:
|
||||
=====================
|
||||
|
||||
By default, the BusyBox build puts its temporary files in the source tree.
|
||||
Building from a read-only source tree, or building multiple configurations from
|
||||
the same source directory, requires the ability to put the temporary files
|
||||
somewhere else.
|
||||
|
||||
To build out of tree, cd to an empty directory and configure busybox from there:
|
||||
|
||||
make KBUILD_SRC=/path/to/source -f /path/to/source/Makefile defconfig
|
||||
make
|
||||
make install
|
||||
|
||||
Alternately, use the O=$BUILDPATH option (with an absolute path) during the
|
||||
configuration step, as in:
|
||||
|
||||
make O=/some/empty/directory allyesconfig
|
||||
cd /some/empty/directory
|
||||
make
|
||||
make CONFIG_PREFIX=. install
|
||||
|
||||
More Information:
|
||||
=================
|
||||
|
||||
Se also the busybox FAQ, under the questions "How can I get started using
|
||||
BusyBox" and "How do I build a BusyBox-based system?" The BusyBox FAQ is
|
||||
available from http://www.busybox.net/FAQ.html
|
348
busybox-1_37_0/LICENSE
Normal file
348
busybox-1_37_0/LICENSE
Normal file
@ -0,0 +1,348 @@
|
||||
--- A note on GPL versions
|
||||
|
||||
BusyBox is distributed under version 2 of the General Public License (included
|
||||
in its entirety, below). Version 2 is the only version of this license which
|
||||
this version of BusyBox (or modified versions derived from this one) may be
|
||||
distributed under.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
1329
busybox-1_37_0/Makefile
Normal file
1329
busybox-1_37_0/Makefile
Normal file
File diff suppressed because it is too large
Load Diff
201
busybox-1_37_0/Makefile.custom
Normal file
201
busybox-1_37_0/Makefile.custom
Normal file
@ -0,0 +1,201 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h include/applets.h
|
||||
$(Q)-$(SHELL) $^ > $@
|
||||
|
||||
busybox.cfg.suid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h
|
||||
$(Q)-SUID="yes" $(SHELL) $^ > $@
|
||||
busybox.cfg.nosuid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h
|
||||
$(Q)-SUID="DROP" $(SHELL) $^ > $@
|
||||
|
||||
.PHONY: install
|
||||
ifeq ($(CONFIG_INSTALL_APPLET_DONT),y)
|
||||
INSTALL_OPTS:= --none
|
||||
endif
|
||||
ifeq ($(CONFIG_INSTALL_APPLET_SYMLINKS),y)
|
||||
INSTALL_OPTS:= --symlinks
|
||||
endif
|
||||
ifeq ($(CONFIG_INSTALL_APPLET_HARDLINKS),y)
|
||||
INSTALL_OPTS:= --hardlinks
|
||||
endif
|
||||
ifeq ($(CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS),y)
|
||||
ifeq ($(CONFIG_INSTALL_SH_APPLET_SYMLINK),y)
|
||||
INSTALL_OPTS:= --sw-sh-sym
|
||||
endif
|
||||
ifeq ($(CONFIG_INSTALL_SH_APPLET_HARDLINK),y)
|
||||
INSTALL_OPTS:= --sw-sh-hard
|
||||
endif
|
||||
ifeq ($(CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER),y)
|
||||
INSTALL_OPTS:= --scriptwrapper
|
||||
endif
|
||||
endif
|
||||
ifeq ($(CONFIG_FEATURE_INDIVIDUAL),y)
|
||||
INSTALL_OPTS:= --binaries
|
||||
LIBBUSYBOX_SONAME:= 0_lib/libbusybox.so.$(BB_VER)
|
||||
endif
|
||||
install: $(srctree)/applets/install.sh busybox busybox.links
|
||||
$(Q)DO_INSTALL_LIBS="$(strip $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS))" \
|
||||
$(SHELL) $< $(CONFIG_PREFIX) $(INSTALL_OPTS)
|
||||
ifeq ($(strip $(CONFIG_FEATURE_SUID)),y)
|
||||
@echo
|
||||
@echo
|
||||
@echo --------------------------------------------------
|
||||
@echo You will probably need to make your busybox binary
|
||||
@echo setuid root to ensure all configured applets will
|
||||
@echo work properly.
|
||||
@echo --------------------------------------------------
|
||||
@echo
|
||||
endif
|
||||
|
||||
install-noclobber: INSTALL_OPTS+=--noclobber
|
||||
install-noclobber: install
|
||||
|
||||
uninstall: busybox.links
|
||||
rm -f $(CONFIG_PREFIX)/bin/busybox
|
||||
for i in `cat busybox.links` ; do rm -f $(CONFIG_PREFIX)$$i; done
|
||||
ifneq ($(strip $(DO_INSTALL_LIBS)),n)
|
||||
for i in $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS); do \
|
||||
rm -f $(CONFIG_PREFIX)$$i; \
|
||||
done
|
||||
endif
|
||||
|
||||
# Not very elegant: copies testsuite to objdir...
|
||||
# (cp -pPR is POSIX-compliant (cp -dpR or cp -a would not be))
|
||||
.PHONY: check
|
||||
.PHONY: test
|
||||
ifeq ($(CONFIG_UNIT_TEST),y)
|
||||
UNIT_CMD = ./busybox unit
|
||||
endif
|
||||
check test: busybox busybox.links
|
||||
$(UNIT_CMD)
|
||||
test -d $(objtree)/testsuite || cp -pPR $(srctree)/testsuite $(objtree)
|
||||
bindir=$(objtree) srcdir=$(srctree)/testsuite \
|
||||
$(SHELL) -c "cd $(objtree)/testsuite && $(srctree)/testsuite/runtest $(if $(KBUILD_VERBOSE:0=),-v)"
|
||||
|
||||
.PHONY: release
|
||||
release: distclean
|
||||
cd ..; \
|
||||
rm -r -f busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION); \
|
||||
cp -pPR busybox busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) && { \
|
||||
find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type d \
|
||||
-name .svn \
|
||||
-print \
|
||||
-exec rm -r -f {} \; ; \
|
||||
find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type d \
|
||||
-name .git \
|
||||
-print \
|
||||
-exec rm -r -f {} \; ; \
|
||||
find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \
|
||||
-name .gitignore \
|
||||
-print \
|
||||
-exec rm -f {} \; ; \
|
||||
find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \
|
||||
-name .\#* \
|
||||
-print \
|
||||
-exec rm -f {} \; ; \
|
||||
tar -czf busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION).tar.gz \
|
||||
busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ ; }
|
||||
|
||||
.PHONY: checkhelp
|
||||
checkhelp:
|
||||
$(Q)$(srctree)/scripts/checkhelp.awk \
|
||||
$(patsubst %,$(srctree)/%,$(wildcard $(patsubst %,%/Config.in,$(busybox-dirs) ./)))
|
||||
|
||||
.PHONY: sizes
|
||||
sizes: busybox_unstripped
|
||||
$(NM) --size-sort $(<)
|
||||
|
||||
.PHONY: bloatcheck
|
||||
bloatcheck: busybox_old busybox_unstripped
|
||||
@$(srctree)/scripts/bloat-o-meter busybox_old busybox_unstripped
|
||||
@$(CROSS_COMPILE)size busybox_old busybox_unstripped
|
||||
|
||||
.PHONY: baseline
|
||||
baseline: busybox_unstripped
|
||||
@mv busybox_unstripped busybox_old
|
||||
|
||||
.PHONY: objsizes
|
||||
objsizes: busybox_unstripped
|
||||
$(srctree)/scripts/objsizes
|
||||
|
||||
.PHONY: stksizes
|
||||
stksizes: busybox_unstripped
|
||||
$(CROSS_COMPILE)objdump -d busybox_unstripped | $(srctree)/scripts/checkstack.pl $(ARCH) | uniq
|
||||
|
||||
.PHONY: bigdata
|
||||
bigdata: busybox_unstripped
|
||||
$(CROSS_COMPILE)nm --size-sort busybox_unstripped | grep -vi ' [trw] '
|
||||
|
||||
# Documentation Targets
|
||||
.PHONY: doc
|
||||
doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html
|
||||
|
||||
# FIXME: Doesn't belong here
|
||||
cmd_doc =
|
||||
quiet_cmd_doc = $(Q)echo " DOC $(@F)"
|
||||
silent_cmd_doc =
|
||||
disp_doc = $($(quiet)cmd_doc)
|
||||
|
||||
# sed adds newlines after "Options:" etc,
|
||||
# this is needed in order to get good BusyBox.{1,txt,html}
|
||||
docs/busybox.pod: $(srctree)/docs/busybox_header.pod \
|
||||
include/usage.h \
|
||||
$(srctree)/docs/busybox_footer.pod \
|
||||
applets/usage_pod
|
||||
$(disp_doc)
|
||||
$(Q)-mkdir -p docs
|
||||
$(Q)-( \
|
||||
cat $(srctree)/docs/busybox_header.pod; \
|
||||
echo; \
|
||||
applets/usage_pod | sed 's/^[A-Za-z][A-Za-z ]*[a-z]:$$/&\n/'; \
|
||||
cat $(srctree)/docs/busybox_footer.pod; \
|
||||
) > docs/busybox.pod
|
||||
|
||||
docs/BusyBox.txt: docs/busybox.pod
|
||||
$(disp_doc)
|
||||
$(Q)-mkdir -p docs
|
||||
$(Q)-pod2text $< > $@
|
||||
|
||||
docs/busybox.1: docs/busybox.pod
|
||||
$(disp_doc)
|
||||
$(Q)-mkdir -p docs
|
||||
$(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@
|
||||
|
||||
docs/BusyBox.html: docs/busybox.net/BusyBox.html
|
||||
$(disp_doc)
|
||||
$(Q)-mkdir -p docs
|
||||
$(Q)-rm -f docs/BusyBox.html
|
||||
$(Q)-cp docs/busybox.net/BusyBox.html docs/BusyBox.html
|
||||
|
||||
docs/busybox.net/BusyBox.html: docs/busybox.pod
|
||||
$(Q)-mkdir -p docs/busybox.net
|
||||
$(Q)-pod2html --noindex $< > $@
|
||||
$(Q)-rm -f pod2htm*
|
||||
|
||||
# documentation, cross-reference
|
||||
# Modern distributions already ship synopsis packages (e.g. debian)
|
||||
# If you have an old distribution go to http://synopsis.fresco.org/
|
||||
syn_tgt = $(wildcard $(patsubst %,%/*.c,$(busybox-alldirs)))
|
||||
syn = $(patsubst %.c, %.syn, $(syn_tgt))
|
||||
|
||||
comma:= ,
|
||||
brace_open:= (
|
||||
brace_close:= )
|
||||
|
||||
SYN_CPPFLAGS := $(strip $(CPPFLAGS) $(EXTRA_CPPFLAGS))
|
||||
SYN_CPPFLAGS := $(subst $(brace_open),\$(brace_open),$(SYN_CPPFLAGS))
|
||||
SYN_CPPFLAGS := $(subst $(brace_close),\$(brace_close),$(SYN_CPPFLAGS))
|
||||
#SYN_CPPFLAGS := $(subst ",\",$(SYN_CPPFLAGS))
|
||||
#")
|
||||
#SYN_CPPFLAGS := [$(patsubst %,'%'$(comma),$(SYN_CPPFLAGS))'']
|
||||
|
||||
%.syn: %.c
|
||||
synopsis -p C -l Comments.SSDFilter,Comments.Previous -Wp,preprocess=True,cppflags="'$(SYN_CPPFLAGS)'" -o $@ $<
|
||||
|
||||
.PHONY: html
|
||||
html: $(syn)
|
||||
synopsis -f HTML -Wf,title="'BusyBox Documentation'" -o $@ $^
|
||||
|
||||
-include $(srctree)/Makefile.local
|
223
busybox-1_37_0/Makefile.flags
Normal file
223
busybox-1_37_0/Makefile.flags
Normal file
@ -0,0 +1,223 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
|
||||
export BB_VER
|
||||
SKIP_STRIP ?= n
|
||||
|
||||
# -std=gnu99 needed for [U]LLONG_MAX on some systems
|
||||
CPPFLAGS += $(call cc-option,-std=gnu99,)
|
||||
|
||||
CPPFLAGS += \
|
||||
-Iinclude -Ilibbb \
|
||||
$(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include -I$(srctree)/libbb) \
|
||||
-include include/autoconf.h \
|
||||
-D_GNU_SOURCE -DNDEBUG \
|
||||
$(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \
|
||||
$(if $(CONFIG_TIME64),-D_TIME_BITS=64) \
|
||||
-DBB_VER=$(squote)$(quote)$(BB_VER)$(quote)$(squote)
|
||||
|
||||
CFLAGS += $(call cc-option,-Wall,)
|
||||
CFLAGS += $(call cc-option,-Wshadow,)
|
||||
CFLAGS += $(call cc-option,-Wwrite-strings,)
|
||||
CFLAGS += $(call cc-option,-Wundef,)
|
||||
CFLAGS += $(call cc-option,-Wstrict-prototypes,)
|
||||
CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,)
|
||||
CFLAGS += $(call cc-option,-Wunused-function -Wunused-value,)
|
||||
CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,)
|
||||
CFLAGS += $(call cc-option,-Wno-format-security,)
|
||||
# warn about C99 declaration after statement
|
||||
CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
|
||||
# If you want to add more -Wsomething above, make sure that it is
|
||||
# still possible to build bbox without warnings.
|
||||
|
||||
ifeq ($(CONFIG_WERROR),y)
|
||||
CFLAGS += $(call cc-option,-Werror,)
|
||||
## TODO:
|
||||
## gcc version 4.4.0 20090506 (Red Hat 4.4.0-4) (GCC) is a PITA:
|
||||
## const char *ptr; ... off_t v = *(off_t*)ptr; -> BOOM
|
||||
## and no easy way to convince it to shut the hell up.
|
||||
## We have a lot of such things all over the place.
|
||||
## Classic *(off_t*)(void*)ptr does not work,
|
||||
## and I am unwilling to do crazy gcc specific ({ void *ppp = ...; })
|
||||
## stuff in macros. This would obfuscate the code too much.
|
||||
## Maybe try __attribute__((__may_alias__))?
|
||||
#CFLAGS += $(call cc-ifversion, -eq, 0404, -fno-strict-aliasing)
|
||||
endif
|
||||
# gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action()
|
||||
CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition)
|
||||
|
||||
ifneq ($(lastword $(subst -, ,$(CC))),clang)
|
||||
# "clang-9: warning: optimization flag '-finline-limit=0' is not supported
|
||||
CFLAGS += $(call cc-option,-finline-limit=0,)
|
||||
endif
|
||||
|
||||
CFLAGS += $(call cc-option,-fno-builtin-strlen -fomit-frame-pointer -ffunction-sections -fdata-sections,)
|
||||
# -fno-guess-branch-probability: prohibit pseudo-random guessing
|
||||
# of branch probabilities (hopefully makes bloatcheck more stable):
|
||||
CFLAGS += $(call cc-option,-fno-guess-branch-probability,)
|
||||
CFLAGS += $(call cc-option,-funsigned-char,)
|
||||
|
||||
ifeq ($(CONFIG_STATIC_LIBGCC),y)
|
||||
# Disable it, for example, if you get
|
||||
# "clang-9: warning: argument unused during compilation: '-static-libgcc'"
|
||||
CFLAGS += $(call cc-option,-static-libgcc,)
|
||||
endif
|
||||
|
||||
CFLAGS += $(call cc-option,-falign-functions=1,)
|
||||
ifneq ($(lastword $(subst -, ,$(CC))),clang)
|
||||
# "clang-9: warning: optimization flag '-falign-jumps=1' is not supported" (and same for other two)
|
||||
CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,)
|
||||
endif
|
||||
|
||||
# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary):
|
||||
CFLAGS += $(call cc-option,-fno-unwind-tables,)
|
||||
CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
|
||||
# No automatic printf->puts,putchar conversions
|
||||
# (try disabling this and comparing assembly, it's instructive)
|
||||
CFLAGS += $(call cc-option,-fno-builtin-printf,)
|
||||
|
||||
# clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs
|
||||
ifeq ($(lastword $(subst -, ,$(CC))),clang)
|
||||
CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand)
|
||||
endif
|
||||
|
||||
# FIXME: These warnings are at least partially to be concerned about and should
|
||||
# be fixed..
|
||||
#CFLAGS += $(call cc-option,-Wconversion,)
|
||||
|
||||
ifneq ($(CONFIG_DEBUG),y)
|
||||
CFLAGS += $(call cc-option,-Oz,$(call cc-option,-Os,$(call cc-option,-O2,)))
|
||||
else
|
||||
CFLAGS += $(call cc-option,-g,)
|
||||
#CFLAGS += "-D_FORTIFY_SOURCE=2"
|
||||
ifeq ($(CONFIG_DEBUG_PESSIMIZE),y)
|
||||
CFLAGS += $(call cc-option,-O0,)
|
||||
else
|
||||
CFLAGS += $(call cc-option,-Oz,$(call cc-option,-Os,$(call cc-option,-O2,)))
|
||||
endif
|
||||
endif
|
||||
ifeq ($(CONFIG_DEBUG_SANITIZE),y)
|
||||
CFLAGS += $(call cc-option,-fsanitize=address,)
|
||||
CFLAGS += $(call cc-option,-fsanitize=leak,)
|
||||
CFLAGS += $(call cc-option,-fsanitize=undefined,)
|
||||
endif
|
||||
|
||||
# If arch/$(ARCH)/Makefile did not override it (with, say, -fPIC)...
|
||||
ARCH_FPIC ?= -fpic
|
||||
ARCH_FPIE ?= -fpie
|
||||
ARCH_PIE ?= -pie
|
||||
|
||||
# Usage: $(eval $(call pkg_check_modules,VARIABLE-PREFIX,MODULES))
|
||||
define pkg_check_modules
|
||||
$(1)_CFLAGS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --cflags $(2))
|
||||
$(1)_LIBS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --libs $(2))
|
||||
endef
|
||||
|
||||
ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y)
|
||||
# on i386: 14% smaller libbusybox.so
|
||||
# (code itself is 9% bigger, we save on relocs/PLT/GOT)
|
||||
CFLAGS += $(ARCH_FPIC)
|
||||
# and another 4% reduction of libbusybox.so:
|
||||
# (external entry points must be marked EXTERNALLY_VISIBLE)
|
||||
CFLAGS += $(call cc-option,-fvisibility=hidden)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STATIC),y)
|
||||
CFLAGS_busybox += -static
|
||||
PKG_CONFIG_FLAGS += --static
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PIE),y)
|
||||
CFLAGS_busybox += $(ARCH_PIE)
|
||||
CFLAGS += $(ARCH_FPIE)
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_EXTRA_CFLAGS),)
|
||||
CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS)))
|
||||
#"))
|
||||
endif
|
||||
|
||||
# Note: both "" (string consisting of two quote chars) and empty string
|
||||
# are possible, and should be skipped below.
|
||||
ifneq ($(subst "",,$(CONFIG_SYSROOT)),)
|
||||
CFLAGS += --sysroot=$(CONFIG_SYSROOT)
|
||||
export SYSROOT=$(CONFIG_SYSROOT)
|
||||
endif
|
||||
|
||||
# libm may be needed for dc, awk, ntpd
|
||||
LDLIBS += m
|
||||
# Android has no separate crypt library
|
||||
# gcc-4.2.1 fails if we try to feed C source on stdin:
|
||||
# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc -
|
||||
# fall back to using a temp file:
|
||||
CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) $(CFLAGS_busybox) -lcrypt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c)
|
||||
RT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) $(CFLAGS_busybox) -lrt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c)
|
||||
ifeq ($(CRYPT_AVAILABLE),y)
|
||||
LDLIBS += crypt
|
||||
endif
|
||||
# librt may be needed for clock_gettime()
|
||||
ifeq ($(RT_AVAILABLE),y)
|
||||
LDLIBS += rt
|
||||
endif
|
||||
|
||||
# libpam may use libpthread, libdl and/or libaudit.
|
||||
# On some platforms that requires an explicit -lpthread, -ldl, -laudit.
|
||||
# However, on *other platforms* it fails when some of those flags
|
||||
# given needlessly. On some systems, crypt needs pthread.
|
||||
#
|
||||
# I even had a system where a runtime test for pthread
|
||||
# (similar to CRYPT_AVAILABLE test above) was not reliable.
|
||||
#
|
||||
# Do not propagate this mess by adding libraries to CONFIG_PAM/CRYPT_AVAILABLE blocks.
|
||||
# Add libraries you need to CONFIG_EXTRA_LDLIBS instead.
|
||||
|
||||
ifeq ($(CONFIG_PAM),y)
|
||||
LDLIBS += pam pam_misc
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SELINUX),y)
|
||||
SELINUX_PC_MODULES = libselinux libsepol
|
||||
$(eval $(call pkg_check_modules,SELINUX,$(SELINUX_PC_MODULES)))
|
||||
CPPFLAGS += $(SELINUX_CFLAGS)
|
||||
LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=%))
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y)
|
||||
ifneq (,$(findstring linux,$(shell $(CC) $(CFLAGS) -dumpmachine)))
|
||||
LDLIBS += resolv
|
||||
endif
|
||||
ifneq (,$(findstring gnu,$(shell $(CC) $(CFLAGS) -dumpmachine)))
|
||||
LDLIBS += resolv
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_EFENCE),y)
|
||||
LDLIBS += efence
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DMALLOC),y)
|
||||
LDLIBS += dmalloc
|
||||
endif
|
||||
|
||||
# If a flat binary should be built, CFLAGS_busybox="-elf2flt"
|
||||
# env var should be set for make invocation.
|
||||
# Here we check whether CFLAGS_busybox indeed contains that flag.
|
||||
# (For historical reasons, we also check LDFLAGS, which doesn't
|
||||
# seem to be entirely correct variable to put "-elf2flt" into).
|
||||
W_ELF2FLT = -elf2flt
|
||||
ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox)))
|
||||
SKIP_STRIP = y
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_EXTRA_LDFLAGS),)
|
||||
LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS)))
|
||||
#"))
|
||||
endif
|
||||
|
||||
# Busybox is a stack-fatty so make sure we increase default size
|
||||
# TODO: use "make stksizes" to find & fix big stack users
|
||||
# (we stole scripts/checkstack.pl from the kernel... thanks guys!)
|
||||
# Reduced from 20k to 16k in 1.9.0.
|
||||
FLTFLAGS += -s 16000
|
44
busybox-1_37_0/Makefile.help
Normal file
44
busybox-1_37_0/Makefile.help
Normal file
@ -0,0 +1,44 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
help:
|
||||
@echo 'Cleaning:'
|
||||
@echo ' clean - delete temporary files created by build'
|
||||
@echo ' distclean - delete all non-source files (including .config)'
|
||||
@echo ' doc-clean - delete all generated documentation'
|
||||
@echo
|
||||
@echo 'Build:'
|
||||
@echo ' all - Executable and documentation'
|
||||
@echo ' busybox - the swiss-army executable'
|
||||
@echo ' doc - docs/BusyBox.{txt,html,1}'
|
||||
@echo ' html - create html-based cross-reference'
|
||||
@echo
|
||||
@echo 'Configuration:'
|
||||
@echo ' allnoconfig - disable all symbols in .config'
|
||||
@echo ' allyesconfig - enable all symbols in .config (see defconfig)'
|
||||
@echo ' config - text based configurator (of last resort)'
|
||||
@echo ' defconfig - set .config to largest generic configuration'
|
||||
@echo ' menuconfig - interactive curses-based configurator'
|
||||
@echo ' oldconfig - resolve any unresolved symbols in .config'
|
||||
@$(if $(boards), \
|
||||
$(foreach b, $(boards), \
|
||||
printf " %-21s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
|
||||
echo '')
|
||||
@echo
|
||||
@echo 'Installation:'
|
||||
@echo ' install - install busybox into CONFIG_PREFIX'
|
||||
@echo ' uninstall'
|
||||
@echo
|
||||
@echo 'Development:'
|
||||
@echo ' baseline - create busybox_old for bloatcheck.'
|
||||
@echo ' bloatcheck - show size difference between old and new versions'
|
||||
@echo ' check - run the test suite for all applets'
|
||||
@echo ' checkhelp - check for missing help-entries in Config.in'
|
||||
@echo ' randconfig - generate a random configuration'
|
||||
@echo ' release - create a distribution tarball'
|
||||
@echo ' sizes - show size of all enabled busybox symbols'
|
||||
@echo ' objsizes - show size of each .o object built'
|
||||
@echo ' bigdata - show data objects, biggest first'
|
||||
@echo ' stksizes - show stack users, biggest first'
|
||||
@echo
|
437
busybox-1_37_0/NOFORK_NOEXEC.lst
Normal file
437
busybox-1_37_0/NOFORK_NOEXEC.lst
Normal file
@ -0,0 +1,437 @@
|
||||
Why an applet can't be NOFORK or NOEXEC?
|
||||
|
||||
Why can't be NOFORK:
|
||||
interactive: may wait for user input, ^C has to work
|
||||
spawner: "tool PROG ARGS" which changes program state and execs - must fork
|
||||
changes state: e.g. environment, signal handlers
|
||||
leaks: does not free allocated memory or opened fds
|
||||
alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies
|
||||
open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies
|
||||
talks to network/serial/etc: it's not known how long the delay can be,
|
||||
it's reasonable to expect it might be many seconds
|
||||
(even if usually it is not), so ^C has to work
|
||||
runner: sometimes may run for long(ish) time, and/or works with network:
|
||||
^C has to work (cat BIGFILE, chmod -R, ftpget, nc)
|
||||
|
||||
"runners" can become eligible after shell is taught ^C to interrupt NOFORKs,
|
||||
need to be inspected that they do not fall into alloc+xfunc, open+xfunc,
|
||||
leak categories.
|
||||
|
||||
Why can't be NOEXEC:
|
||||
suid: runs under different uid - must fork+exec
|
||||
if it's important that /proc/PID/cmdline and comm are correct.
|
||||
("pkill sh" killing itself before it kills real "sh" is no fun)
|
||||
|
||||
Why shouldn't be NOFORK/NOEXEC:
|
||||
rare: not started often enough to bother optimizing (example: poweroff)
|
||||
daemon: runs indefinitely; these are also always fit "rare" category
|
||||
longterm: often runs for a long time (many seconds), execing makes
|
||||
memory footprint smaller
|
||||
complex: no immediately obvious reason why NOFORK wouldn't work,
|
||||
but does some non-obvoius operations (example: fuser, lsof, losetup);
|
||||
detailed audit often turns out that it's a leaker
|
||||
hardware: performs unusual hardware ops which may take long,
|
||||
or even hang due to hardware or firmware bugs
|
||||
|
||||
Interesting example of "interactive" applet which is nevertheless can be
|
||||
(and is) NOEXEC is "rm". Yes, "rm -i" is interactive - but it's not that typical
|
||||
for users to keep it waiting for many minutes, whereas running "rm" in shell
|
||||
is very typical, and speeding up this common use via NOEXEC is useful.
|
||||
IOW: rm is "interactive", but not "longterm".
|
||||
|
||||
Interesting example of an applet which can be NOFORK but if not,
|
||||
then should not be NOEXEC, is "usleep". As NOFORK, it amount to simply
|
||||
nanosleep()ing in the calling program (usually shell). No memory wasted.
|
||||
But if ran as NOEXEC, it would create a potentially long-term process,
|
||||
which would be taking more memory because it did not exec
|
||||
and did not free much of the copied memory of the parent
|
||||
(COW helps with this only as long as parent doesn't modify its memory).
|
||||
|
||||
|
||||
[ - NOFORK
|
||||
[[ - NOFORK
|
||||
acpid - daemon
|
||||
add-shell - noexec. leaks: open+xfunc
|
||||
addgroup - noexec. leaks
|
||||
adduser - noexec. leaks
|
||||
adjtimex - NOFORK
|
||||
ar - runner
|
||||
arch - NOFORK
|
||||
arp - talks to network: arp -n queries DNS
|
||||
arping - longterm
|
||||
ash - interactive, longterm
|
||||
awk - noexec. runner
|
||||
base64 - runner
|
||||
basename - NOFORK
|
||||
beep - longterm: beep -r 999999999
|
||||
blkdiscard - noexec. leaks: open+xioctl
|
||||
blkid - noexec
|
||||
blockdev - noexec. leaks fd
|
||||
bootchartd - daemon
|
||||
brctl - noexec
|
||||
bunzip2 - runner
|
||||
bzcat - runner
|
||||
bzip2 - runner
|
||||
cal - noexec. can be runner: cal -n9999
|
||||
cat - runner: cat HUGEFILE
|
||||
chat - longterm (when used as intended - talking to modem over stdin/out)
|
||||
chattr - noexec. runner
|
||||
chgrp - noexec. runner
|
||||
chmod - noexec. runner
|
||||
chown - noexec. runner
|
||||
chpasswd - longterm? (list of "user:password"s from stdin)
|
||||
chpst - noexec. spawner
|
||||
chroot - noexec. spawner
|
||||
chrt - noexec. spawner
|
||||
chvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
|
||||
cksum - noexec. runner
|
||||
clear - NOFORK
|
||||
cmp - runner
|
||||
comm - runner
|
||||
conspy - interactive, longterm
|
||||
cp - noexec. sometimes runner
|
||||
cpio - runner
|
||||
crond - daemon
|
||||
crontab - longterm (runs $EDITOR), leaks: open+xasprintf
|
||||
cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin
|
||||
cttyhack - noexec. spawner
|
||||
cut - noexec. runner
|
||||
date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf)
|
||||
dc - longterm (eats stdin if no params)
|
||||
dd - noexec. runner
|
||||
deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
|
||||
delgroup - noexec. leaks
|
||||
deluser - noexec. leaks
|
||||
depmod - longterm(ish)
|
||||
devmem - hardware (access to device memory may hang)
|
||||
df - noexec. leaks: nested allocs
|
||||
dhcprelay - daemon
|
||||
diff - runner
|
||||
dirname - NOFORK
|
||||
dmesg - runner
|
||||
dnsd - daemon
|
||||
dnsdomainname - noexec. talks to network (may query DNS)
|
||||
dos2unix - noexec. runner
|
||||
dpkg - runner
|
||||
du - runner
|
||||
dumpkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
|
||||
dumpleases - noexec. leaks: open+xread
|
||||
echo - NOFORK
|
||||
ed - interactive, longterm
|
||||
egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory)
|
||||
eject - hardware, leaks: open+ioctl_or_perror_and_die, changes state (moves fds)
|
||||
env - noexec. spawner, changes state (env)
|
||||
envdir - noexec. spawner
|
||||
envuidgid - noexec. spawner
|
||||
expand - runner
|
||||
expr - noexec. leaks: nested allocs
|
||||
factor - longterm (eats stdin if no params)
|
||||
fakeidentd - daemon
|
||||
false - NOFORK
|
||||
fatattr - noexec. leaks: open+xioctl, complex
|
||||
fbset - hardware, leaks: open+xfunc
|
||||
fbsplash - runner, longterm
|
||||
fdflush - hardware, leaks: open+ioctl_or_perror_and_die
|
||||
fdformat - hardware, longterm
|
||||
fdisk - interactive, longterm
|
||||
fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
|
||||
fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory)
|
||||
find - noexec. runner
|
||||
findfs - suid
|
||||
flash_eraseall - hardware
|
||||
flash_lock - hardware
|
||||
flash_unlock - hardware
|
||||
flashcp - hardware
|
||||
flock - spawner, changes state (file locks), let's play safe and not be noexec
|
||||
fold - noexec. runner
|
||||
free - NOFORK
|
||||
freeramdisk - noexec. leaks: open+ioctl_or_perror_and_die
|
||||
fsck - interactive, longterm
|
||||
fsck.minix - needs ^C
|
||||
fsfreeze - noexec. leaks: open+xioctl
|
||||
fstrim - noexec. leaks: open+xioctl, find_block_device -> readdir+xstrdup
|
||||
fsync - NOFORK
|
||||
ftpd - daemon
|
||||
ftpget - runner
|
||||
ftpput - runner
|
||||
fuser - complex
|
||||
getopt - noexec. leaks: many allocs
|
||||
getty - interactive, longterm
|
||||
grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory)
|
||||
groups - noexec
|
||||
gunzip - runner
|
||||
gzip - runner
|
||||
halt - rare
|
||||
hd - noexec. runner
|
||||
hdparm - hardware
|
||||
head - noexec. runner
|
||||
hexdump - noexec. runner
|
||||
hexedit - interactive, longterm
|
||||
hostid - NOFORK
|
||||
hostname - noexec. talks to network (hostname -d may query DNS)
|
||||
httpd - daemon
|
||||
hush - interactive, longterm
|
||||
hwclock - hardware (xioctl(RTC_RD_TIME))
|
||||
i2cdetect - hardware
|
||||
i2cdump - hardware
|
||||
i2cget - hardware
|
||||
i2cset - hardware
|
||||
id - noexec
|
||||
ifconfig - hardware? (mem_start NN io_addr NN irq NN), leaks: xsocket+ioctl_or_perror_and_die
|
||||
ifenslave - noexec. leaks: xsocket+bb_perror_msg_and_die
|
||||
ifplugd - daemon
|
||||
inetd - daemon
|
||||
init - daemon
|
||||
inotifyd - daemon
|
||||
insmod - noexec
|
||||
install - runner
|
||||
ionice - noexec. spawner
|
||||
iostat - longterm: "iostat 1" runs indefinitely
|
||||
ip - noexec
|
||||
ipaddr - noexec
|
||||
ipcalc - noexec. ipcalc -h talks to network
|
||||
ipcrm - noexec
|
||||
ipcs - noexec
|
||||
iplink - noexec
|
||||
ipneigh - noexec
|
||||
iproute - noexec
|
||||
iprule - noexec
|
||||
iptunnel - noexec
|
||||
kbd_mode - noexec. leaks: xopen_nonblocking+xioctl
|
||||
kill - NOFORK
|
||||
killall - NOFORK
|
||||
killall5 - NOFORK
|
||||
klogd - daemon
|
||||
last - runner (I've got 1300 lines of output when tried it)
|
||||
less - interactive, longterm
|
||||
link - NOFORK
|
||||
linux32 - noexec. spawner
|
||||
linux64 - noexec. spawner
|
||||
linuxrc - daemon
|
||||
ln - noexec
|
||||
loadfont - noexec. leaks: config_open+bb_error_msg_and_die("map format")
|
||||
loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds
|
||||
logger - runner
|
||||
login - suid, interactive, longterm
|
||||
logname - NOFORK
|
||||
losetup - noexec. complex
|
||||
lpd - daemon
|
||||
lpq - runner
|
||||
lpr - runner
|
||||
ls - noexec. runner
|
||||
lsattr - noexec. runner
|
||||
lsmod - noexec
|
||||
lsof - complex
|
||||
lspci - noexec. too rare to bother for nofork
|
||||
lsscsi - noexec. too rare to bother for nofork
|
||||
lsusb - noexec. too rare to bother for nofork
|
||||
lzcat - runner
|
||||
lzma - runner
|
||||
lzop - runner
|
||||
lzopcat - runner
|
||||
makedevs - noexec
|
||||
makemime - runner
|
||||
man - spawner, interactive, longterm
|
||||
md5sum - noexec. runner
|
||||
mdev - daemon
|
||||
mesg - NOFORK
|
||||
microcom - interactive, longterm
|
||||
minips - noexec
|
||||
mkdir - NOFORK
|
||||
mkdosfs - needs ^C
|
||||
mke2fs - needs ^C
|
||||
mkfifo - noexec
|
||||
mkfs.ext2 - needs ^C
|
||||
mkfs.minix - needs ^C
|
||||
mkfs.vfat - needs ^C
|
||||
mknod - noexec
|
||||
mkpasswd - noexec. changes state: with --password-fd=N, moves N to stdin
|
||||
mkswap - needs ^C
|
||||
mktemp - noexec. leaks: xstrdup+concat_path_file
|
||||
modinfo - noexec
|
||||
modprobe - noexec
|
||||
more - interactive, longterm
|
||||
mount - suid
|
||||
mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup
|
||||
mpstat - longterm: "mpstat 1" runs indefinitely
|
||||
mt - hardware
|
||||
mv - noexec. sometimes runner
|
||||
nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die
|
||||
nbd-client - noexec
|
||||
nc - runner
|
||||
netstat - longterm with -c (continuous listing)
|
||||
nice - noexec. spawner
|
||||
nl - runner
|
||||
nmeter - longterm
|
||||
nohup - noexec. spawner
|
||||
nproc - NOFORK
|
||||
ntpd - daemon
|
||||
nuke - noexec
|
||||
od - runner
|
||||
openvt - longterm: spawns a child and waits for it
|
||||
partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART)
|
||||
passwd - suid
|
||||
paste - noexec. runner
|
||||
patch - needs ^C
|
||||
pgrep - must fork+exec to get correct /proc/PID/cmdline and comm field
|
||||
pidof - must fork+exec to get correct /proc/PID/cmdline and comm field
|
||||
ping - suid, longterm
|
||||
ping6 - suid, longterm
|
||||
pipe_progress - longterm
|
||||
pivot_root - NOFORK
|
||||
pkill - must fork+exec to get correct /proc/PID/cmdline and comm field
|
||||
pmap - noexec candidate, leaks: open+xstrdup
|
||||
popmaildir - runner
|
||||
poweroff - rare
|
||||
powertop - interactive, longterm
|
||||
printenv - NOFORK
|
||||
printf - NOFORK
|
||||
ps - noexec
|
||||
pscan - talks to network
|
||||
pstree - noexec
|
||||
pwd - NOFORK
|
||||
pwdx - NOFORK
|
||||
raidautorun - noexec. very simple. leaks: open+xioctl
|
||||
rdate - talks to network
|
||||
rdev - noexec. leaks: find_block_device -> readdir+xstrdup
|
||||
readlink - NOFORK
|
||||
readprofile - reads /boot/System.map and /proc/profile, better to free more memory by execing?
|
||||
realpath - NOFORK
|
||||
reboot - rare
|
||||
reformime - runner
|
||||
remove-shell - noexec. leaks: open+xfunc
|
||||
renice - noexec. nofork candidate(uses getpwnam, is that ok?)
|
||||
reset - noexec. spawner (execs "stty")
|
||||
resize - noexec. changes state (signal handlers)
|
||||
resume - noexec
|
||||
rev - runner
|
||||
rm - noexec. rm -i interactive
|
||||
rmdir - NOFORK
|
||||
rmmod - noexec
|
||||
route - talks to network (may query DNS to convert IPs to names)
|
||||
rpm - runner
|
||||
rpm2cpio - runner
|
||||
rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless
|
||||
run-init - spawner, rare, changes state (oh yes), execing may be important to free binary's inode
|
||||
run-parts - longterm
|
||||
runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother?
|
||||
runsv - daemon
|
||||
runsvdir - daemon
|
||||
rx - runner
|
||||
script - longterm: pumps script output from slave pty
|
||||
scriptreplay - longterm: plays back "script" saved output, sleeping as necessary.
|
||||
sed - runner
|
||||
sendmail - runner
|
||||
seq - noexec. runner
|
||||
setarch - noexec. spawner
|
||||
setconsole - noexec
|
||||
setfattr - noexec
|
||||
setfont - noexec. leaks a lot of stuff
|
||||
setkeycodes - noexec
|
||||
setlogcons - noexec
|
||||
setpriv - spawner, changes state, let's play safe and not be noexec
|
||||
setserial - noexec
|
||||
setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec
|
||||
setuidgid - noexec. spawner
|
||||
sha1sum - noexec. runner
|
||||
sha256sum - noexec. runner
|
||||
sha3sum - noexec. runner
|
||||
sha512sum - noexec. runner
|
||||
showkey - interactive, longterm
|
||||
shred - runner
|
||||
shuf - noexec. runner
|
||||
slattach - longterm (may sleep forever), uses bb_common_bufsiz1
|
||||
sleep - longterm. Could be nofork, if not the problem of "killall sleep" not killing it.
|
||||
smemcap - runner
|
||||
softlimit - noexec. spawner
|
||||
sort - noexec. runner
|
||||
split - runner
|
||||
ssl_client - longterm
|
||||
start-stop-daemon - not noexec: uses bb_common_bufsiz1
|
||||
stat - noexec. nofork candidate(needs fewer allocs)
|
||||
strings - runner
|
||||
stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd
|
||||
su - suid, spawner
|
||||
sulogin - noexec. spawner
|
||||
sum - runner
|
||||
sv - noexec. needs ^C (uses usleep(420000))
|
||||
svc - noexec. needs ^C (uses usleep(420000))
|
||||
svlogd - daemon
|
||||
swapoff - longterm: may cause memory pressure, execing is beneficial
|
||||
swapon - rare
|
||||
switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode
|
||||
sync - NOFORK
|
||||
sysctl - noexec. leaks: xstrdup+xmalloc_read
|
||||
syslogd - daemon
|
||||
tac - noexec. runner
|
||||
tail - runner
|
||||
tar - runner
|
||||
taskset - noexec. spawner
|
||||
tcpsvd - daemon
|
||||
tee - runner
|
||||
telnet - interactive, longterm
|
||||
telnetd - daemon
|
||||
test - NOFORK
|
||||
tftp - runner
|
||||
tftpd - daemon
|
||||
time - spawner, longterm, changes state (signals)
|
||||
timeout - spawner, longterm, changes state (signals)
|
||||
top - interactive, longterm
|
||||
touch - NOFORK
|
||||
tr - runner
|
||||
traceroute - suid, longterm
|
||||
traceroute6 - suid, longterm
|
||||
true - NOFORK
|
||||
truncate - NOFORK
|
||||
tty - NOFORK
|
||||
ttysize - NOFORK
|
||||
tunctl - noexec
|
||||
tune2fs - noexec. leaks: open+xfunc
|
||||
ubiattach - hardware
|
||||
ubidetach - hardware
|
||||
ubimkvol - hardware
|
||||
ubirename - hardware
|
||||
ubirmvol - hardware
|
||||
ubirsvol - hardware
|
||||
ubiupdatevol - hardware
|
||||
udhcpc - daemon
|
||||
udhcpd - daemon
|
||||
udpsvd - daemon
|
||||
uevent - daemon
|
||||
umount - noexec. leaks: nested xmalloc
|
||||
uname - NOFORK
|
||||
uncompress - runner
|
||||
unexpand - runner
|
||||
uniq - runner
|
||||
unix2dos - noexec. runner
|
||||
unlink - NOFORK
|
||||
unlzma - runner
|
||||
unlzop - runner
|
||||
unxz - runner
|
||||
unzip - runner
|
||||
uptime - noexec. nofork candidate(is getutxent ok?)
|
||||
users - noexec. nofork candidate(is getutxent ok?)
|
||||
usleep - NOFORK. But what about "killall usleep"?
|
||||
uudecode - runner
|
||||
uuencode - runner
|
||||
vconfig - noexec. leaks: xsocket+ioctl_or_perror_and_die
|
||||
vi - interactive, longterm
|
||||
vlock - suid
|
||||
volname - hardware (reads CDROM, this can take long-ish if need to spin up)
|
||||
w - noexec. nofork candidate(is getutxent ok?)
|
||||
wall - suid
|
||||
watch - longterm
|
||||
watchdog - daemon
|
||||
wc - runner
|
||||
wget - longterm
|
||||
which - NOFORK
|
||||
who - noexec. nofork candidate(is getutxent ok?)
|
||||
whoami - NOFORK
|
||||
whois - talks to network
|
||||
xargs - noexec. spawner
|
||||
xxd - noexec. runner
|
||||
xz - runner
|
||||
xzcat - runner
|
||||
yes - noexec. runner
|
||||
zcat - runner
|
||||
zcip - daemon
|
34
busybox-1_37_0/NOFORK_NOEXEC.sh
Executable file
34
busybox-1_37_0/NOFORK_NOEXEC.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec >NOFORK_NOEXEC.lst1
|
||||
|
||||
false && grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \
|
||||
| grep -v 'noexec.' | grep -v 'noexec$' \
|
||||
| grep -v ' suid' \
|
||||
| grep -v ' daemon' \
|
||||
| grep -v ' longterm' \
|
||||
| grep rare
|
||||
|
||||
echo === nofork candidate
|
||||
grep -F 'nofork candidate' NOFORK_NOEXEC.lst \
|
||||
|
||||
echo === noexec candidate
|
||||
grep -F 'noexec candidate' NOFORK_NOEXEC.lst \
|
||||
|
||||
echo === ^C
|
||||
grep -F '^C' NOFORK_NOEXEC.lst \
|
||||
| grep -F ' - ' \
|
||||
|
||||
echo === talks
|
||||
grep -F 'talks' NOFORK_NOEXEC.lst \
|
||||
| grep -F ' - ' \
|
||||
|
||||
echo ===
|
||||
grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \
|
||||
| grep '^[^ ][^ ]* - ' \
|
||||
| grep -v 'noexec.' | grep -v ' - noexec$' \
|
||||
| grep -v ' suid' \
|
||||
| grep -v ' daemon' \
|
||||
| grep -v 'longterm' \
|
||||
| grep -v 'interactive' \
|
||||
| grep -v 'hardware' \
|
204
busybox-1_37_0/README
Normal file
204
busybox-1_37_0/README
Normal file
@ -0,0 +1,204 @@
|
||||
Please see the LICENSE file for details on copying and usage.
|
||||
Please refer to the INSTALL file for instructions on how to build.
|
||||
|
||||
What is busybox:
|
||||
|
||||
BusyBox combines tiny versions of many common UNIX utilities into a single
|
||||
small executable. It provides minimalist replacements for most of the
|
||||
utilities you usually find in bzip2, coreutils, dhcp, diffutils, e2fsprogs,
|
||||
file, findutils, gawk, grep, inetutils, less, modutils, net-tools, procps,
|
||||
sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The utilities
|
||||
in BusyBox often have fewer options than their full-featured cousins;
|
||||
however, the options that are included provide the expected functionality
|
||||
and behave very much like their larger counterparts.
|
||||
|
||||
BusyBox has been written with size-optimization and limited resources in
|
||||
mind, both to produce small binaries and to reduce run-time memory usage.
|
||||
Busybox is also extremely modular so you can easily include or exclude
|
||||
commands (or features) at compile time. This makes it easy to customize
|
||||
embedded systems; to create a working system, just add /dev, /etc, and a
|
||||
Linux kernel. Busybox (usually together with uClibc) has also been used as
|
||||
a component of "thin client" desktop systems, live-CD distributions, rescue
|
||||
disks, installers, and so on.
|
||||
|
||||
BusyBox provides a fairly complete POSIX environment for any small system,
|
||||
both embedded environments and more full featured systems concerned about
|
||||
space. Busybox is slowly working towards implementing the full Single Unix
|
||||
Specification V3 (http://www.opengroup.org/onlinepubs/009695399/), but isn't
|
||||
there yet (and for size reasons will probably support at most UTF-8 for
|
||||
internationalization). We are also interested in passing the Linux Test
|
||||
Project (http://ltp.sourceforge.net).
|
||||
|
||||
----------------
|
||||
|
||||
Using busybox:
|
||||
|
||||
BusyBox is extremely configurable. This allows you to include only the
|
||||
components and options you need, thereby reducing binary size. Run 'make
|
||||
config' or 'make menuconfig' to select the functionality that you wish to
|
||||
enable. (See 'make help' for more commands.)
|
||||
|
||||
The behavior of busybox is determined by the name it's called under: as
|
||||
"cp" it behaves like cp, as "sed" it behaves like sed, and so on. Called
|
||||
as "busybox" it takes the second argument as the name of the applet to
|
||||
run (I.E. "./busybox ls -l /proc").
|
||||
|
||||
The "standalone shell" mode is an easy way to try out busybox; this is a
|
||||
command shell that calls the built-in applets without needing them to be
|
||||
installed in the path. (Note that this requires /proc to be mounted, if
|
||||
testing from a boot floppy or in a chroot environment.)
|
||||
|
||||
The build automatically generates a file "busybox.links", which is used by
|
||||
'make install' to create symlinks to the BusyBox binary for all compiled in
|
||||
commands. This uses the CONFIG_PREFIX environment variable to specify
|
||||
where to install, and installs hardlinks or symlinks depending
|
||||
on the configuration preferences. (You can also manually run
|
||||
the install script at "applets/install.sh").
|
||||
|
||||
----------------
|
||||
|
||||
Downloading the current source code:
|
||||
|
||||
Source for the latest released version, as well as daily snapshots, can always
|
||||
be downloaded from
|
||||
|
||||
http://busybox.net/downloads/
|
||||
|
||||
You can browse the up to the minute source code and change history online.
|
||||
|
||||
http://git.busybox.net/busybox/
|
||||
|
||||
Anonymous GIT access is available. For instructions, check out:
|
||||
|
||||
http://www.busybox.net/source.html
|
||||
|
||||
For those that are actively contributing and would like to check files in,
|
||||
see:
|
||||
|
||||
http://busybox.net/developer.html
|
||||
|
||||
The developers also have a bug and patch tracking system
|
||||
(https://bugs.busybox.net) although posting a bug/patch to the mailing list
|
||||
is generally a faster way of getting it fixed, and the complete archive of
|
||||
what happened is the git changelog.
|
||||
|
||||
Note: if you want to compile busybox in a busybox environment you must
|
||||
select CONFIG_DESKTOP.
|
||||
|
||||
----------------
|
||||
|
||||
Getting help:
|
||||
|
||||
when you find you need help, you can check out the busybox mailing list
|
||||
archives at http://busybox.net/lists/busybox/ or even join
|
||||
the mailing list if you are interested.
|
||||
|
||||
----------------
|
||||
|
||||
Bugs:
|
||||
|
||||
if you find bugs, please submit a detailed bug report to the busybox mailing
|
||||
list at busybox@busybox.net. a well-written bug report should include a
|
||||
transcript of a shell session that demonstrates the bad behavior and enables
|
||||
anyone else to duplicate the bug on their own machine. the following is such
|
||||
an example:
|
||||
|
||||
to: busybox@busybox.net
|
||||
from: diligent@testing.linux.org
|
||||
subject: /bin/date doesn't work
|
||||
|
||||
package: busybox
|
||||
version: 1.00
|
||||
|
||||
when i execute busybox 'date' it produces unexpected results.
|
||||
with gnu date i get the following output:
|
||||
|
||||
$ date
|
||||
fri oct 8 14:19:41 mdt 2004
|
||||
|
||||
but when i use busybox date i get this instead:
|
||||
|
||||
$ date
|
||||
illegal instruction
|
||||
|
||||
i am using debian unstable, kernel version 2.4.25-vrs2 on a netwinder,
|
||||
and the latest uclibc from cvs.
|
||||
|
||||
-diligent
|
||||
|
||||
note the careful description and use of examples showing not only what
|
||||
busybox does, but also a counter example showing what an equivalent app
|
||||
does (or pointing to the text of a relevant standard). Bug reports lacking
|
||||
such detail may never be fixed... Thanks for understanding.
|
||||
|
||||
----------------
|
||||
|
||||
Portability:
|
||||
|
||||
Busybox is developed and tested on Linux 2.4 and 2.6 kernels, compiled
|
||||
with gcc (the unit-at-a-time optimizations in version 3.4 and later are
|
||||
worth upgrading to get, but older versions should work), and linked against
|
||||
uClibc (0.9.27 or greater) or glibc (2.2 or greater). In such an
|
||||
environment, the full set of busybox features should work, and if
|
||||
anything doesn't we want to know about it so we can fix it.
|
||||
|
||||
There are many other environments out there, in which busybox may build
|
||||
and run just fine. We just don't test them. Since busybox consists of a
|
||||
large number of more or less independent applets, portability is a question
|
||||
of which features work where. Some busybox applets (such as cat and rm) are
|
||||
highly portable and likely to work just about anywhere, while others (such as
|
||||
insmod and losetup) require recent Linux kernels with recent C libraries.
|
||||
|
||||
Earlier versions of Linux and glibc may or may not work, for any given
|
||||
configuration. Linux 2.2 or earlier should mostly work (there's still
|
||||
some support code in things like mount.c) but this is no longer regularly
|
||||
tested, and inherently won't support certain features (such as long files
|
||||
and --bind mounts). The same is true for glibc 2.0 and 2.1: expect a higher
|
||||
testing and debugging burden using such old infrastructure. (The busybox
|
||||
developers are not very interested in supporting these older versions, but
|
||||
will probably accept small self-contained patches to fix simple problems.)
|
||||
|
||||
Some environments are not recommended. Early versions of uClibc were buggy
|
||||
and missing many features: upgrade. Linking against libc5 or dietlibc is
|
||||
not supported and not interesting to the busybox developers. (The first is
|
||||
obsolete and has no known size or feature advantages over uClibc, the second
|
||||
has known bugs that its developers have actively refused to fix.) Ancient
|
||||
Linux kernels (2.0.x and earlier) are similarly uninteresting.
|
||||
|
||||
In theory it's possible to use Busybox under other operating systems (such as
|
||||
MacOS X, Solaris, Cygwin, or the BSD Fork Du Jour). This generally involves
|
||||
a different kernel and a different C library at the same time. While it
|
||||
should be possible to port the majority of the code to work in one of
|
||||
these environments, don't be surprised if it doesn't work out of the box. If
|
||||
you're into that sort of thing, start small (selecting just a few applets)
|
||||
and work your way up.
|
||||
|
||||
In 2005 Shaun Jackman has ported busybox to a combination of newlib
|
||||
and libgloss, and some of his patches have been integrated.
|
||||
|
||||
Supported hardware:
|
||||
|
||||
BusyBox in general will build on any architecture supported by gcc. We
|
||||
support both 32 and 64 bit platforms, and both big and little endian
|
||||
systems.
|
||||
|
||||
Under 2.4 Linux kernels, kernel module loading was implemented in a
|
||||
platform-specific manner. Busybox's insmod utility has been reported to
|
||||
work under ARM, CRIS, H8/300, x86, ia64, x86_64, m68k, MIPS, PowerPC, S390,
|
||||
SH3/4/5, Sparc, and v850e. Anything else probably won't work.
|
||||
|
||||
The module loading mechanism for the 2.6 kernel is much more generic, and
|
||||
we believe 2.6.x kernel module loading support should work on all
|
||||
architectures supported by the kernel.
|
||||
|
||||
----------------
|
||||
|
||||
Please feed suggestions, bug reports, insults, and bribes back to the busybox
|
||||
mailing list:
|
||||
|
||||
busybox@busybox.net
|
||||
|
||||
and/or maintainer:
|
||||
|
||||
Denys Vlasenko
|
||||
<vda.linux@googlemail.com>
|
256
busybox-1_37_0/TODO
Normal file
256
busybox-1_37_0/TODO
Normal file
@ -0,0 +1,256 @@
|
||||
Busybox TODO
|
||||
|
||||
Harvest patches from
|
||||
http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/
|
||||
https://dev.openwrt.org/browser/trunk/package/busybox/patches/
|
||||
|
||||
|
||||
Stuff that needs to be done. This is organized by who plans to get around to
|
||||
doing it eventually, but that doesn't mean they "own" the item. If you want to
|
||||
do one of these bounce an email off the person it's listed under to see if they
|
||||
have any suggestions how they plan to go about it, and to minimize conflicts
|
||||
between your work and theirs. But otherwise, all of these are fair game.
|
||||
|
||||
Rob Landley suggested this:
|
||||
Implement bb_realpath() that can handle NULL on non-glibc.
|
||||
|
||||
sh
|
||||
The command shell situation is a mess. We have two different
|
||||
shells that don't really share any code, and the "standalone shell" doesn't
|
||||
work all that well (especially not in a chroot environment), due to apps not
|
||||
being reentrant.
|
||||
|
||||
Do a SUSv3 audit
|
||||
Look at the full Single Unix Specification version 3 (available online at
|
||||
"http://www.opengroup.org/onlinepubs/009695399/nfindex.html") and
|
||||
figure out which of our apps are compliant, and what we're missing that
|
||||
we might actually care about.
|
||||
|
||||
Even better would be some kind of automated compliance test harness that
|
||||
exercises each command line option and the various corner cases.
|
||||
|
||||
Internationalization
|
||||
How much internationalization should we do?
|
||||
|
||||
The low hanging fruit is UTF-8 character set support. We should do this.
|
||||
See TODO_unicode file.
|
||||
|
||||
We also have lots of hardwired english text messages. Consolidating this
|
||||
into some kind of message table not only makes translation easier, but
|
||||
also allows us to consolidate redundant (or close) strings.
|
||||
|
||||
We probably don't want to be bloated with locale support. (Not unless we
|
||||
can cleanly export it from our underlying C library without having to
|
||||
concern ourselves with it directly. Perhaps a few specific things like a
|
||||
config option for "date" are low hanging fruit here?)
|
||||
|
||||
What level should things happen at? How much do we care about
|
||||
internationalizing the text console when X11 and xterms are so much better
|
||||
at it? (There's some infrastructure here we don't implement: The
|
||||
"unicode_start" and "unicode_stop" shell scripts need "vt-is-UTF8" and a
|
||||
--unicode option to loadkeys. That implies a real loadkeys/dumpkeys
|
||||
implementation to replace loadkmap/dumpkmap. Plus messing with console font
|
||||
loading. Is it worth it, or do we just say "use X"?)
|
||||
|
||||
Individual compilation of applets.
|
||||
It would be nice if busybox had the option to compile to individual applets,
|
||||
for people who want an alternate implementation less bloated than the gnu
|
||||
utils (or simply with less political baggage), but without it being one big
|
||||
executable.
|
||||
|
||||
Turning libbb into a real dll is another possibility, especially if libbb
|
||||
could export some of the other library interfaces we've already more or less
|
||||
got the code for (like zlib).
|
||||
|
||||
buildroot - Make a "dogfood" option
|
||||
Busybox 1.1 will be capable of replacing most gnu packages for real world
|
||||
use, such as developing software or in a live CD. It needs wider testing.
|
||||
|
||||
Busybox should now be able to replace bzip2, coreutils, e2fsprogs, file,
|
||||
findutils, gawk, grep, inetutils, less, modutils, net-tools, patch, procps,
|
||||
sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The resulting
|
||||
system should be self-hosting (I.E. able to rebuild itself from source
|
||||
code). This means it would need (at least) binutils, gcc, and make, or
|
||||
equivalents.
|
||||
|
||||
It would be a good "eating our own dogfood" test if buildroot had the option
|
||||
of using a "make allyesconfig" busybox instead of the all of the above
|
||||
packages. Anything that's wrong with the resulting system, we can fix. (It
|
||||
would be nice to be able to upgrade busybox to be able to replace bash and
|
||||
diffutils as well, but we're not there yet.)
|
||||
|
||||
One example of an existing system that does this already is Firmware Linux:
|
||||
http://www.landley.net/code/firmware
|
||||
|
||||
initramfs
|
||||
Busybox should have a sample initramfs build script. This depends on
|
||||
shell, mdev, and switch_root.
|
||||
|
||||
mkdep
|
||||
Write a mkdep that doesn't segfault if there's a directory it doesn't
|
||||
have permission to read, isn't based on manually editing the output of
|
||||
lexx and yacc, doesn't make such a mess under include/config, etc.
|
||||
|
||||
Group globals into unions of structures.
|
||||
Go through and turn all the global and static variables into structures,
|
||||
and have all those structures be in a big union shared between processes,
|
||||
so busybox uses less bss. (This is a big win on nommu machines.) See
|
||||
sed.c and mdev.c for examples.
|
||||
|
||||
Go through bugs.busybox.net and close out all of that somehow.
|
||||
This one's open to everybody, but I'll wind up doing it...
|
||||
|
||||
Bernhard Reutner-Fischer <busybox@busybox.net> suggests to look at these:
|
||||
New debug options:
|
||||
-Wlarger-than-127
|
||||
Cleanup any big users
|
||||
Collate BUFSIZ IOBUF_SIZE MY_BUF_SIZE PIPE_PROGRESS_SIZE BUFSIZE PIPESIZE
|
||||
make bb_common_bufsiz1 configurable, size wise.
|
||||
make pipesize configurable, size wise.
|
||||
Use bb_common_bufsiz1 throughout applets!
|
||||
|
||||
As yet unclaimed:
|
||||
|
||||
----
|
||||
diff
|
||||
Make sure we handle empty files properly:
|
||||
From the patch man page:
|
||||
|
||||
you can remove a file by sending out a context diff that compares
|
||||
the file to be deleted with an empty file dated the Epoch. The
|
||||
file will be removed unless patch is conforming to POSIX and the
|
||||
-E or --remove-empty-files option is not given.
|
||||
---
|
||||
patch
|
||||
Should have simple fuzz factor support to apply patches at an offset which
|
||||
shouldn't take up too much space.
|
||||
|
||||
And while we're at it, a new patch filename quoting format is apparently
|
||||
coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
|
||||
|
||||
Architectural issues:
|
||||
|
||||
bb_close() with fsync()
|
||||
We should have a bb_close() in place of normal close, with a CONFIG_ option
|
||||
to not just check the return value of close() for an error, but fsync().
|
||||
Close can't reliably report anything useful because if write() accepted the
|
||||
data then it either went out to the network or it's in cache or a pipe
|
||||
buffer. Either way, there's no guarantee it'll make it to its final
|
||||
destination before close() gets called, so there's no guarantee that any
|
||||
error will be reported.
|
||||
|
||||
You need to call fsync() if you care about errors that occur after write(),
|
||||
but that can have a big performance impact. So make it a config option.
|
||||
---
|
||||
Unify archivers
|
||||
Lots of archivers have the same general infrastructure. The directory
|
||||
traversal code should be factored out, and the guts of each archiver could
|
||||
be some setup code and a series of callbacks for "add this file",
|
||||
"add this directory", "add this symlink" and so on.
|
||||
|
||||
This could clean up tar and zip, and make it cheaper to add cpio and ar
|
||||
write support, and possibly even cheaply add things like mkisofs or
|
||||
mksquashfs someday, if they become relevant.
|
||||
---
|
||||
Text buffer support.
|
||||
Several existing applets (sort, vi, less...) read
|
||||
a whole file into memory and act on it. Use open_read_close().
|
||||
---
|
||||
Memory Allocation
|
||||
We have a CONFIG_BUFFER mechanism that lets us select whether to do memory
|
||||
allocation on the stack or the heap. Unfortunately, we're not using it much.
|
||||
We need to audit our memory allocations and turn a lot of malloc/free calls
|
||||
into RESERVE_CONFIG_BUFFER/RELEASE_CONFIG_BUFFER.
|
||||
For a start, see e.g. make EXTRA_CFLAGS=-Wlarger-than-64
|
||||
|
||||
And while we're at it, many of the CONFIG_FEATURE_CLEAN_UP #ifdefs will be
|
||||
optimized out by the compiler in the stack allocation case (since there's no
|
||||
free for an alloca()), and this means that various cleanup loops that just
|
||||
call free might also be optimized out by the compiler if written right, so
|
||||
we can yank those #ifdefs too, and generally clean up the code.
|
||||
---
|
||||
FEATURE_CLEAN_UP
|
||||
This is more an unresolved issue than a to-do item. More thought is needed.
|
||||
|
||||
Normally we rely on exit() to free memory, close files and unmap segments
|
||||
for us. This makes most calls to free(), close(), and unmap() optional in
|
||||
busybox applets that don't intend to run for very long, and optional stuff
|
||||
can be omitted to save size.
|
||||
|
||||
The idea was raised that we could simulate fork/exit with setjmp/longjmp
|
||||
for _really_ brainless embedded systems, or speed up the standalone shell
|
||||
by not forking. Doing so would require a reliable FEATURE_CLEAN_UP.
|
||||
Unfortunately, this isn't as easy as it sounds.
|
||||
|
||||
The problem is, lots of things exit(), sometimes unexpectedly (xmalloc())
|
||||
and sometimes reliably (bb_perror_msg_and_die() or show_usage()). This
|
||||
jumps out of the normal flow control and bypasses any cleanup code we
|
||||
put at the end of our applets.
|
||||
|
||||
It's possible to add hooks to libbb functions like xmalloc() and xopen()
|
||||
to add their entries to a linked list, which could be traversed and
|
||||
freed/closed automatically. (This would need to be able to free just the
|
||||
entries after a checkpoint to be usable for a forkless standalone shell.
|
||||
You don't want to free the shell's own resources.)
|
||||
|
||||
Right now, FEATURE_CLEAN_UP is more or less a debugging aid, to make things
|
||||
like valgrind happy. It's also documentation of _what_ we're trusting
|
||||
exit() to clean up for us. But new infrastructure to auto-free stuff would
|
||||
render the existing FEATURE_CLEAN_UP code redundant.
|
||||
|
||||
For right now, exit() handles it just fine.
|
||||
|
||||
|
||||
Minor stuff:
|
||||
watchdog.c could autodetect the timer duration via:
|
||||
if(!ioctl (fd, WDIOC_GETTIMEOUT, &tmo)) timer_duration = 1 + (tmo / 2);
|
||||
Unfortunately, that needs linux/watchdog.h and that contains unfiltered
|
||||
kernel types on some distros, which breaks the build.
|
||||
---
|
||||
use bb_error_msg where appropriate: See
|
||||
egrep "(printf.*\([[:space:]]*(stderr|2)|[^_]write.*\([[:space:]]*(stderr|2))"
|
||||
---
|
||||
use bb_perror_msg where appropriate: See
|
||||
egrep "[^_]perror"
|
||||
---
|
||||
possible code duplication ingroup() and is_a_group_member()
|
||||
---
|
||||
Move __get_hz() to a better place and (re)use it in route.c, ash.c
|
||||
---
|
||||
See grep -r strtod
|
||||
Alot of duplication that wants cleanup.
|
||||
---
|
||||
unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles.
|
||||
---
|
||||
|
||||
(TODO list after discussion 11.05.2009)
|
||||
|
||||
* shrink tc/brctl/ip
|
||||
tc/brctl seem like fairly large things to try and tackle in your timeframe,
|
||||
and i think people have posted attempts in the past. Adding additional
|
||||
options to ip though seems reasonable.
|
||||
|
||||
* add tests for some applets
|
||||
|
||||
* implement POSIX utilities and audit them for POSIX conformance. then
|
||||
audit them for GNU conformance. then document all your findings in a new
|
||||
doc/conformance.txt file while perhaps implementing some of the missing
|
||||
features.
|
||||
you can find the latest POSIX documentation (1003.1-2008) here:
|
||||
http://www.opengroup.org/onlinepubs/9699919799/
|
||||
and the complete list of all utilities that POSIX covers:
|
||||
http://www.opengroup.org/onlinepubs/9699919799/idx/utilities.html
|
||||
The first step would to generate a file/matrix what is already archived
|
||||
(also IPV6)
|
||||
|
||||
* implement 'at'
|
||||
|
||||
* rpcbind (former portmap) or equivalent
|
||||
so that we don't have to use -o nolock on nfs mounts
|
||||
|
||||
* check IPV6 compliance
|
||||
|
||||
* generate a mini example using kernel+busybox only (+libc) for example
|
||||
|
||||
* more support for advanced linux 2.6.x features, see: iotop
|
||||
most likely there is more
|
45
busybox-1_37_0/TODO_unicode
Normal file
45
busybox-1_37_0/TODO_unicode
Normal file
@ -0,0 +1,45 @@
|
||||
Already fixed applets:
|
||||
cal
|
||||
lsmod
|
||||
df
|
||||
dumpleases
|
||||
|
||||
Applets which may need unicode handling (more extensive than sanitizing
|
||||
of filenames in error messages):
|
||||
|
||||
ls - work in progress
|
||||
expand, unexpand - uses unicode_strlen, not scrlen
|
||||
ash, hush through lineedit - uses unicode_strlen, not scrlen
|
||||
top - need to sanitize process args
|
||||
ps - need to sanitize process args
|
||||
less
|
||||
more
|
||||
vi
|
||||
ed
|
||||
cut
|
||||
awk
|
||||
sed
|
||||
tr
|
||||
grep egrep fgrep
|
||||
fold
|
||||
sort
|
||||
head, tail
|
||||
catv - "display nonprinting chars" - what this could mean for unicode?
|
||||
wc
|
||||
chat
|
||||
dumpkmap
|
||||
last - just line up columns
|
||||
man
|
||||
microcom
|
||||
strings
|
||||
watch
|
||||
|
||||
Unsure, may need fixing:
|
||||
|
||||
hostname - do we really want to protect against bad chars in it?
|
||||
patch
|
||||
addgroup, adduser, delgroup, deluser
|
||||
telnet
|
||||
telnetd
|
||||
od
|
||||
printf
|
3
busybox-1_37_0/applets/.gitignore
vendored
Normal file
3
busybox-1_37_0/applets/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/applet_tables
|
||||
/usage
|
||||
/usage_pod
|
57
busybox-1_37_0/applets/Kbuild.src
Normal file
57
busybox-1_37_0/applets/Kbuild.src
Normal file
@ -0,0 +1,57 @@
|
||||
# Makefile for busybox
|
||||
#
|
||||
# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
|
||||
#
|
||||
# Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
|
||||
obj-y :=
|
||||
obj-y += applets.o
|
||||
|
||||
hostprogs-y:=
|
||||
hostprogs-y += usage usage_pod applet_tables
|
||||
|
||||
always:= $(hostprogs-y)
|
||||
|
||||
# Generated files need additional love
|
||||
|
||||
# This trick decreases amount of rebuilds
|
||||
# if tree is merely renamed/copied
|
||||
ifeq ($(srctree),$(objtree))
|
||||
srctree_slash =
|
||||
else
|
||||
srctree_slash = $(srctree)/
|
||||
endif
|
||||
|
||||
HOSTCFLAGS_usage.o = -I$(srctree_slash)include -Iinclude
|
||||
HOSTCFLAGS_usage_pod.o = -I$(srctree_slash)include -Iinclude
|
||||
|
||||
applets/applets.o: include/usage_compressed.h include/applet_tables.h
|
||||
|
||||
applets/applet_tables: .config include/applets.h
|
||||
applets/usage: .config include/applets.h
|
||||
applets/usage_pod: .config include/applets.h include/applet_tables.h
|
||||
|
||||
quiet_cmd_gen_usage_compressed = GEN include/usage_compressed.h
|
||||
cmd_gen_usage_compressed = $(srctree_slash)applets/usage_compressed include/usage_compressed.h applets
|
||||
|
||||
include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compressed
|
||||
$(call cmd,gen_usage_compressed)
|
||||
|
||||
quiet_cmd_gen_applet_tables = GEN include/applet_tables.h include/NUM_APPLETS.h
|
||||
cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h
|
||||
|
||||
include/NUM_APPLETS.h: applets/applet_tables
|
||||
$(call cmd,gen_applet_tables)
|
||||
|
||||
# In fact, include/applet_tables.h depends only on applets/applet_tables,
|
||||
# and is generated by it. But specifying only it can run
|
||||
# applets/applet_tables twice, possibly in parallel.
|
||||
# We say that it also needs NUM_APPLETS.h
|
||||
#
|
||||
# Unfortunately, we need to list the same command,
|
||||
# and it can be executed twice (sequentially).
|
||||
# The alternative is to not list any command,
|
||||
# and then if include/applet_tables.h is deleted, it won't be rebuilt.
|
||||
#
|
||||
include/applet_tables.h: include/NUM_APPLETS.h applets/applet_tables
|
||||
$(call cmd,gen_applet_tables)
|
244
busybox-1_37_0/applets/applet_tables.c
Normal file
244
busybox-1_37_0/applets/applet_tables.c
Normal file
@ -0,0 +1,244 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Applet table generator.
|
||||
* Runs on host and produces include/applet_tables.h
|
||||
*
|
||||
* Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#undef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#include "../include/autoconf.h"
|
||||
#include "../include/applet_metadata.h"
|
||||
|
||||
struct bb_applet {
|
||||
const char *name;
|
||||
const char *main;
|
||||
enum bb_install_loc_t install_loc;
|
||||
enum bb_suid_t need_suid;
|
||||
/* true if instead of fork(); exec("applet"); waitpid();
|
||||
* one can do fork(); exit(applet_main(argc,argv)); waitpid(); */
|
||||
unsigned char noexec;
|
||||
/* Even nicer */
|
||||
/* true if instead of fork(); exec("applet"); waitpid();
|
||||
* one can simply call applet_main(argc,argv); */
|
||||
unsigned char nofork;
|
||||
};
|
||||
|
||||
/* Define struct bb_applet applets[] */
|
||||
#include "../include/applets.h"
|
||||
|
||||
enum { NUM_APPLETS = ARRAY_SIZE(applets) };
|
||||
|
||||
static int cmp_name(const void *a, const void *b)
|
||||
{
|
||||
const struct bb_applet *aa = a;
|
||||
const struct bb_applet *bb = b;
|
||||
return strcmp(aa->name, bb->name);
|
||||
}
|
||||
|
||||
static int str_isalnum_(const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (!isalnum((unsigned char)*s) && *s != '_')
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
char tmp1[PATH_MAX], tmp2[PATH_MAX];
|
||||
|
||||
// In find_applet_by_name(), before linear search, narrow it down
|
||||
// by looking at N "equidistant" names. With ~350 applets:
|
||||
// KNOWN_APPNAME_OFFSETS cycles
|
||||
// 0 9057
|
||||
// 2 4604 + ~100 bytes of code
|
||||
// 4 2407 + 4 bytes
|
||||
// 8 1342 + 8 bytes
|
||||
// 16 908 + 16 bytes
|
||||
// 32 884 + 32 bytes
|
||||
// With 8, int16_t applet_nameofs[] table has 7 elements.
|
||||
int KNOWN_APPNAME_OFFSETS = 8;
|
||||
// With 128 applets we do two linear searches, with 1..7 strcmp's in the first one
|
||||
// and 1..16 strcmp's in the second. With 256 apps, second search does 1..32 strcmp's.
|
||||
if (NUM_APPLETS < 128)
|
||||
KNOWN_APPNAME_OFFSETS = 4;
|
||||
if (NUM_APPLETS < 32)
|
||||
KNOWN_APPNAME_OFFSETS = 0;
|
||||
|
||||
qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name);
|
||||
|
||||
for (i = j = 0; i < NUM_APPLETS-1; ++i) {
|
||||
if (cmp_name(applets+i, applets+i+1) == 0) {
|
||||
fprintf(stderr, "%s: duplicate applet name '%s'\n", argv[0],
|
||||
applets[i].name);
|
||||
j = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (j != 0 || !argv[1])
|
||||
return 1;
|
||||
snprintf(tmp1, PATH_MAX, "%s.%u.new", argv[1], (int) getpid());
|
||||
i = open(tmp1, O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
if (i < 0)
|
||||
return 1;
|
||||
dup2(i, 1);
|
||||
|
||||
/* Keep in sync with include/busybox.h! */
|
||||
|
||||
printf("/* This is a generated file, don't edit */\n\n");
|
||||
|
||||
printf("#define NUM_APPLETS %u\n", NUM_APPLETS);
|
||||
if (NUM_APPLETS == 1) {
|
||||
printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name);
|
||||
printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main);
|
||||
}
|
||||
|
||||
printf("#define KNOWN_APPNAME_OFFSETS %u\n\n", KNOWN_APPNAME_OFFSETS);
|
||||
if (KNOWN_APPNAME_OFFSETS > 0) {
|
||||
int ofs, offset[KNOWN_APPNAME_OFFSETS], index[KNOWN_APPNAME_OFFSETS];
|
||||
for (i = 0; i < KNOWN_APPNAME_OFFSETS; i++)
|
||||
index[i] = i * NUM_APPLETS / KNOWN_APPNAME_OFFSETS;
|
||||
ofs = 0;
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
for (j = 0; j < KNOWN_APPNAME_OFFSETS; j++)
|
||||
if (i == index[j])
|
||||
offset[j] = ofs;
|
||||
ofs += strlen(applets[i].name) + 1;
|
||||
}
|
||||
/* If the list of names is too long refuse to proceed */
|
||||
if (ofs > 0xffff)
|
||||
return 1;
|
||||
printf("const uint16_t applet_nameofs[] ALIGN2 = {\n");
|
||||
for (i = 1; i < KNOWN_APPNAME_OFFSETS; i++)
|
||||
printf("%d,\n", offset[i]);
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
//printf("#ifndef SKIP_definitions\n");
|
||||
printf("const char applet_names[] ALIGN1 = \"\"\n");
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
printf("\"%s\" \"\\0\"\n", applets[i].name);
|
||||
// if (MAX_APPLET_NAME_LEN < strlen(applets[i].name))
|
||||
// MAX_APPLET_NAME_LEN = strlen(applets[i].name);
|
||||
}
|
||||
printf(";\n\n");
|
||||
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
if (str_isalnum_(applets[i].name))
|
||||
printf("#define APPLET_NO_%s %d\n", applets[i].name, i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("#ifndef SKIP_applet_main\n");
|
||||
printf("int (*const applet_main[])(int argc, char **argv) = {\n");
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
printf("%s_main,\n", applets[i].main);
|
||||
}
|
||||
printf("};\n");
|
||||
printf("#endif\n\n");
|
||||
|
||||
#if ENABLE_FEATURE_PREFER_APPLETS \
|
||||
|| ENABLE_FEATURE_SH_STANDALONE \
|
||||
|| ENABLE_FEATURE_SH_NOFORK
|
||||
printf("const uint8_t applet_flags[] ALIGN1 = {\n");
|
||||
i = 0;
|
||||
while (i < NUM_APPLETS) {
|
||||
int v = applets[i].nofork + (applets[i].noexec << 1);
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= (applets[i].nofork + (applets[i].noexec << 1)) << 2;
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= (applets[i].nofork + (applets[i].noexec << 1)) << 4;
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= (applets[i].nofork + (applets[i].noexec << 1)) << 6;
|
||||
printf("0x%02x,\n", v);
|
||||
i++;
|
||||
}
|
||||
printf("};\n\n");
|
||||
#endif
|
||||
|
||||
#if ENABLE_FEATURE_SUID
|
||||
printf("const uint8_t applet_suid[] ALIGN1 = {\n");
|
||||
i = 0;
|
||||
while (i < NUM_APPLETS) {
|
||||
int v = applets[i].need_suid; /* 2 bits */
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= applets[i].need_suid << 2;
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= applets[i].need_suid << 4;
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= applets[i].need_suid << 6;
|
||||
printf("0x%02x,\n", v);
|
||||
i++;
|
||||
}
|
||||
printf("};\n\n");
|
||||
#endif
|
||||
|
||||
#if ENABLE_FEATURE_INSTALLER
|
||||
printf("const uint8_t applet_install_loc[] ALIGN1 = {\n");
|
||||
i = 0;
|
||||
while (i < NUM_APPLETS) {
|
||||
int v = applets[i].install_loc; /* 3 bits */
|
||||
if (++i < NUM_APPLETS)
|
||||
v |= applets[i].install_loc << 4; /* 3 bits */
|
||||
printf("0x%02x,\n", v);
|
||||
i++;
|
||||
}
|
||||
printf("};\n");
|
||||
#endif
|
||||
//printf("#endif /* SKIP_definitions */\n");
|
||||
|
||||
// printf("\n");
|
||||
// printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
|
||||
|
||||
if (argv[2]) {
|
||||
FILE *fp;
|
||||
char line_new[80];
|
||||
// char line_old[80];
|
||||
|
||||
sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS);
|
||||
// line_old[0] = 0;
|
||||
// fp = fopen(argv[2], "r");
|
||||
// if (fp) {
|
||||
// fgets(line_old, sizeof(line_old), fp);
|
||||
// fclose(fp);
|
||||
// }
|
||||
// if (strcmp(line_old, line_new) != 0) {
|
||||
snprintf(tmp2, PATH_MAX, "%s.%u.new", argv[2], (int) getpid());
|
||||
fp = fopen(tmp2, "w");
|
||||
if (!fp)
|
||||
return 1;
|
||||
fputs(line_new, fp);
|
||||
if (fclose(fp))
|
||||
return 1;
|
||||
// }
|
||||
}
|
||||
|
||||
if (fclose(stdout))
|
||||
return 1;
|
||||
if (rename(tmp1, argv[1]))
|
||||
return 1;
|
||||
if (rename(tmp2, argv[2]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
16
busybox-1_37_0/applets/applets.c
Normal file
16
busybox-1_37_0/applets/applets.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Stub for linking busybox binary against libbusybox.
|
||||
*
|
||||
* Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "busybox.h"
|
||||
|
||||
#if ENABLE_BUILD_LIBBUSYBOX
|
||||
int main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
return lbb_main(argv);
|
||||
}
|
||||
#endif
|
24
busybox-1_37_0/applets/busybox.mkll
Executable file
24
busybox-1_37_0/applets/busybox.mkll
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
# Make busybox links list file.
|
||||
|
||||
# input $1: full path to Config.h
|
||||
# input $2: full path to applets.h
|
||||
# output (stdout): list of pathnames that should be linked to busybox
|
||||
|
||||
# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
|
||||
|
||||
export LC_ALL=POSIX
|
||||
export LC_CTYPE=POSIX
|
||||
|
||||
CONFIG_H=${1:-include/autoconf.h}
|
||||
APPLETS_H=${2:-include/applets.h}
|
||||
$HOSTCC -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
|
||||
awk '/^[ \t]*LINK/{
|
||||
dir=substr($2,7)
|
||||
gsub("_","/",dir)
|
||||
if(dir=="/ROOT") dir=""
|
||||
file=$3
|
||||
gsub("\"","",file)
|
||||
if (file=="busybox") next
|
||||
print tolower(dir) "/" file
|
||||
}'
|
16
busybox-1_37_0/applets/busybox.mkscripts
Executable file
16
busybox-1_37_0/applets/busybox.mkscripts
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
# Make busybox scripted applet list file.
|
||||
|
||||
# input $1: full path to Config.h
|
||||
# input $2: full path to applets.h
|
||||
# output (stdout): list of pathnames that should be linked to busybox
|
||||
|
||||
export LC_ALL=POSIX
|
||||
export LC_CTYPE=POSIX
|
||||
|
||||
CONFIG_H=${1:-include/autoconf.h}
|
||||
APPLETS_H=${2:-include/applets.h}
|
||||
$HOSTCC -E -DMAKE_SCRIPTS -include $CONFIG_H $APPLETS_H |
|
||||
awk '/^[ \t]*SCRIPT/{
|
||||
print $2
|
||||
}'
|
54
busybox-1_37_0/applets/busybox.mksuid
Executable file
54
busybox-1_37_0/applets/busybox.mksuid
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
# Make list of configuration variables regarding suid handling
|
||||
|
||||
# input $1: full path to autoconf.h
|
||||
# input $2: full path to applets.h
|
||||
# input $3: full path to .config
|
||||
# output (stdout): list of CONFIG_ that do or may require suid
|
||||
|
||||
# If the environment variable SUID is not set or set to DROP,
|
||||
# lists all config options that do not require suid permissions.
|
||||
# Otherwise, lists all config options for applets that DO or MAY require
|
||||
# suid permissions.
|
||||
|
||||
# Maintainer: Bernhard Reutner-Fischer
|
||||
|
||||
export LC_ALL=POSIX
|
||||
export LC_CTYPE=POSIX
|
||||
|
||||
CONFIG_H=${1:-include/autoconf.h}
|
||||
APPLETS_H=${2:-include/applets.h}
|
||||
DOT_CONFIG=${3:-.config}
|
||||
|
||||
case ${SUID:-DROP} in
|
||||
[dD][rR][oO][pP]) USE="DROP" ;;
|
||||
*) USE="suid" ;;
|
||||
esac
|
||||
|
||||
$HOSTCC -E -DMAKE_SUID -include $CONFIG_H $APPLETS_H |
|
||||
awk -v USE=${USE} '
|
||||
/^SUID[ \t]/{
|
||||
if (USE == "DROP") {
|
||||
if ($2 != "BB_SUID_DROP") next
|
||||
} else {
|
||||
if ($2 == "BB_SUID_DROP") next
|
||||
}
|
||||
cfg = $NF
|
||||
gsub("\"", "", cfg)
|
||||
cfg = substr(cfg, 8)
|
||||
s[i++] = "CONFIG_" cfg
|
||||
s[i++] = "CONFIG_FEATURE_" cfg "_.*"
|
||||
}
|
||||
END{
|
||||
while (getline < ARGV[2]) {
|
||||
for (j in s) {
|
||||
if ($0 ~ "^" s[j] "=y$") {
|
||||
sub(/=.*/, "")
|
||||
print
|
||||
if (s[j] !~ /\*$/) delete s[j] # can drop this applet now
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
' - $DOT_CONFIG
|
||||
|
24
busybox-1_37_0/applets/individual.c
Normal file
24
busybox-1_37_0/applets/individual.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* Minimal wrapper to build an individual busybox applet.
|
||||
*
|
||||
* Copyright 2005 Rob Landley <rob@landley.net
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
const char *applet_name;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "usage.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
applet_name = argv[0];
|
||||
return APPLET_main(argc, argv);
|
||||
}
|
||||
|
||||
void bb_show_usage(void)
|
||||
{
|
||||
fputs_stdout(APPLET_full_usage "\n");
|
||||
exit_FAILURE();
|
||||
}
|
137
busybox-1_37_0/applets/install.sh
Executable file
137
busybox-1_37_0/applets/install.sh
Executable file
@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LC_ALL=POSIX
|
||||
export LC_CTYPE=POSIX
|
||||
|
||||
prefix=$1
|
||||
if [ -z "$prefix" ]; then
|
||||
echo "usage: applets/install.sh DESTINATION TYPE [OPTS ...]"
|
||||
echo " TYPE is one of: --symlinks --hardlinks --binaries --scriptwrapper --none"
|
||||
echo " OPTS is one or more of: --cleanup --noclobber"
|
||||
exit 1
|
||||
fi
|
||||
shift # Keep only remaining options
|
||||
|
||||
# Source the configuration
|
||||
. ./.config
|
||||
|
||||
h=`sort busybox.links | uniq`
|
||||
|
||||
sharedlib_dir="0_lib"
|
||||
|
||||
linkopts=""
|
||||
scriptwrapper="n"
|
||||
binaries="n"
|
||||
cleanup="0"
|
||||
noclobber="0"
|
||||
while [ ${#} -gt 0 ]; do
|
||||
case "$1" in
|
||||
--hardlinks) linkopts="-f";;
|
||||
--symlinks) linkopts="-fs";;
|
||||
--binaries) binaries="y";;
|
||||
--scriptwrapper) scriptwrapper="y"; swrapall="y";;
|
||||
--sw-sh-hard) scriptwrapper="y"; linkopts="-f";;
|
||||
--sw-sh-sym) scriptwrapper="y"; linkopts="-fs";;
|
||||
--cleanup) cleanup="1";;
|
||||
--noclobber) noclobber="1";;
|
||||
--none) h="";;
|
||||
*) echo "Unknown install option: $1"; exit 1;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -n "$DO_INSTALL_LIBS" ] && [ x"$DO_INSTALL_LIBS" != x"n" ]; then
|
||||
# get the target dir for the libs
|
||||
# assume it starts with lib
|
||||
libdir=$($CC -print-file-name=libc.so | \
|
||||
sed -n 's%^.*\(/lib[^\/]*\)/libc.so%\1%p')
|
||||
if test -z "$libdir"; then
|
||||
libdir=/lib
|
||||
fi
|
||||
|
||||
mkdir -p "$prefix/$libdir" || exit 1
|
||||
for i in $DO_INSTALL_LIBS; do
|
||||
rm -f "$prefix/$libdir/$i" || exit 1
|
||||
if [ -f "$i" ]; then
|
||||
echo " Installing $i to the target at $prefix/$libdir/"
|
||||
cp -pPR "$i" "$prefix/$libdir/" || exit 1
|
||||
chmod 0644 "$prefix/$libdir/`basename $i`" || exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$cleanup" = x"1" ] && [ -e "$prefix/bin/busybox" ]; then
|
||||
inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'`
|
||||
sub_shell_it=`
|
||||
cd "$prefix"
|
||||
for d in usr/sbin usr/bin sbin bin; do
|
||||
pd=$PWD
|
||||
if [ -d "$d" ]; then
|
||||
cd "$d"
|
||||
ls -iL . | grep "^ *$inode" | awk '{print $2}' | env -i xargs rm -f
|
||||
fi
|
||||
cd "$pd"
|
||||
done
|
||||
`
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f "$prefix/bin/busybox" || exit 1
|
||||
mkdir -p "$prefix/bin" || exit 1
|
||||
install -m 755 busybox "$prefix/bin/busybox" || exit 1
|
||||
|
||||
for i in $h; do
|
||||
appdir=`dirname "$i"`
|
||||
app=`basename "$i"`
|
||||
if [ x"$noclobber" = x"1" ] && ([ -e "$prefix/$i" ] || [ -h "$prefix/$i" ]); then
|
||||
echo " $prefix/$i already exists"
|
||||
continue
|
||||
fi
|
||||
mkdir -p "$prefix/$appdir" || exit 1
|
||||
if [ x"$scriptwrapper" = x"y" ]; then
|
||||
if [ x"$swrapall" != x"y" ] && [ x"$i" = x"/bin/sh" ]; then
|
||||
ln $linkopts busybox "$prefix/$i" || exit 1
|
||||
else
|
||||
rm -f "$prefix/$i"
|
||||
echo "#!/bin/busybox" >"$prefix/$i"
|
||||
chmod +x "$prefix/$i"
|
||||
fi
|
||||
echo " $prefix/$i"
|
||||
elif [ x"$binaries" = x"y" ]; then
|
||||
# Copy the binary over rather
|
||||
if [ -e "$sharedlib_dir/$app" ]; then
|
||||
echo " Copying $sharedlib_dir/$app to $prefix/$i"
|
||||
cp -pPR "$sharedlib_dir/$app" "$prefix/$i" || exit 1
|
||||
else
|
||||
echo "Error: Could not find $sharedlib_dir/$app"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [ x"$linkopts" = x"-f" ]; then
|
||||
bb_path="$prefix/bin/busybox"
|
||||
else
|
||||
case "$appdir" in
|
||||
/)
|
||||
bb_path="bin/busybox"
|
||||
;;
|
||||
/bin)
|
||||
bb_path="busybox"
|
||||
;;
|
||||
/sbin)
|
||||
bb_path="../bin/busybox"
|
||||
;;
|
||||
/usr/bin | /usr/sbin)
|
||||
bb_path="../../bin/busybox"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown installation directory: $appdir"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo " $prefix/$i -> $bb_path"
|
||||
ln $linkopts "$bb_path" "$prefix/$i" || exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
55
busybox-1_37_0/applets/usage.c
Normal file
55
busybox-1_37_0/applets/usage.c
Normal file
@ -0,0 +1,55 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2008 Denys Vlasenko.
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "autoconf.h"
|
||||
|
||||
/* Since we can't use platform.h, have to do this again by hand: */
|
||||
#if ENABLE_NOMMU
|
||||
# define BB_MMU 0
|
||||
# define USE_FOR_NOMMU(...) __VA_ARGS__
|
||||
# define USE_FOR_MMU(...)
|
||||
#else
|
||||
# define BB_MMU 1
|
||||
# define USE_FOR_NOMMU(...)
|
||||
# define USE_FOR_MMU(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#include "usage.h"
|
||||
#define MAKE_USAGE(aname, usage) { aname, usage },
|
||||
static struct usage_data {
|
||||
const char *aname;
|
||||
const char *usage;
|
||||
} usage_array[] = {
|
||||
#include "applets.h"
|
||||
};
|
||||
|
||||
static int compare_func(const void *a, const void *b)
|
||||
{
|
||||
const struct usage_data *ua = a;
|
||||
const struct usage_data *ub = b;
|
||||
return strcmp(ua->aname, ub->aname);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
int num_messages = sizeof(usage_array) / sizeof(usage_array[0]);
|
||||
|
||||
if (num_messages == 0)
|
||||
return 0;
|
||||
|
||||
qsort(usage_array,
|
||||
num_messages, sizeof(usage_array[0]),
|
||||
compare_func);
|
||||
for (i = 0; i < num_messages; i++)
|
||||
write(STDOUT_FILENO, usage_array[i].usage, strlen(usage_array[i].usage) + 1);
|
||||
|
||||
return 0;
|
||||
}
|
62
busybox-1_37_0/applets/usage_compressed
Executable file
62
busybox-1_37_0/applets/usage_compressed
Executable file
@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
|
||||
target="$1"
|
||||
loc="$2"
|
||||
|
||||
test "$target" || exit 1
|
||||
test "$loc" || loc=.
|
||||
test -x "$loc/usage" || exit 1
|
||||
test "$SED" || SED=sed
|
||||
test "$DD" || DD=dd
|
||||
|
||||
# Some people were bitten by their system lacking a (proper) od
|
||||
od -v -b </dev/null >/dev/null
|
||||
if test $? != 0; then
|
||||
echo 'od tool is not installed or cannot accept "-v -b" options'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec >"$target.$$"
|
||||
|
||||
echo '#define UNPACKED_USAGE "" \'
|
||||
"$loc/usage" | od -v -b \
|
||||
| grep -v '^ ' \
|
||||
| $SED -e 's/^[^ ]*//' \
|
||||
-e 's/ //g' \
|
||||
-e '/^$/d' \
|
||||
-e 's/\(...\)/\\\1/g' \
|
||||
-e 's/^/"/' \
|
||||
-e 's/$/" \\/'
|
||||
echo ''
|
||||
# "grep -v '^ '" is for toybox's od bug: od -b prints some extra lines:
|
||||
#0000000 010 000 010 000 133 055 144 146 135 040 133 055 143 040 103 117
|
||||
# 000010 000010 026533 063144 020135 026533 020143 047503
|
||||
#0000020 116 106 104 111 122 135 040 133 055 154 040 114 117 107 106 111
|
||||
# 043116 044504 056522 055440 066055 046040 043517 044506
|
||||
#0000040 114 105 135 040 133 055 141 040 101 103 124 111 117 116 106 111
|
||||
# 042514 020135 026533 020141 041501 044524 047117 044506
|
||||
|
||||
echo "#define UNPACKED_USAGE_LENGTH `$loc/usage | wc -c`"
|
||||
echo
|
||||
|
||||
echo '#define PACKED_USAGE \'
|
||||
## Breaks on big-endian systems!
|
||||
## # Extra effort to avoid using "od -t x1": -t is not available
|
||||
## # in non-CONFIG_DESKTOPed busybox od
|
||||
##
|
||||
## "$loc/usage" | bzip2 -1 | od -v -x \
|
||||
## | $SED -e 's/^[^ ]*//' \
|
||||
## -e 's/ //g' \
|
||||
## -e '/^$/d' \
|
||||
## -e 's/\(..\)\(..\)/0x\2,0x\1,/g'
|
||||
## -e 's/$/ \\/'
|
||||
"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \
|
||||
| grep -v '^ ' \
|
||||
| $SED -e 's/^[^ ]*//' \
|
||||
-e 's/ //g' \
|
||||
-e '/^$/d' \
|
||||
-e 's/\(...\)/0\1,/g' \
|
||||
-e 's/$/ \\/'
|
||||
echo ''
|
||||
|
||||
mv -- "$target.$$" "$target"
|
113
busybox-1_37_0/applets/usage_pod.c
Normal file
113
busybox-1_37_0/applets/usage_pod.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2009 Denys Vlasenko.
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "autoconf.h"
|
||||
|
||||
#define SKIP_applet_main
|
||||
#define ALIGN1 /* nothing, just to placate applet_tables.h */
|
||||
#define ALIGN2 /* nothing, just to placate applet_tables.h */
|
||||
#include "applet_tables.h"
|
||||
|
||||
/* Since we can't use platform.h, have to do this again by hand: */
|
||||
#if ENABLE_NOMMU
|
||||
# define BB_MMU 0
|
||||
# define USE_FOR_NOMMU(...) __VA_ARGS__
|
||||
# define USE_FOR_MMU(...)
|
||||
#else
|
||||
# define BB_MMU 1
|
||||
# define USE_FOR_NOMMU(...)
|
||||
# define USE_FOR_MMU(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#include "usage.h"
|
||||
#define MAKE_USAGE(aname, usage) { aname, usage },
|
||||
static struct usage_data {
|
||||
const char *aname;
|
||||
const char *usage;
|
||||
} usage_array[] = {
|
||||
#include "applets.h"
|
||||
};
|
||||
|
||||
static int compare_func(const void *a, const void *b)
|
||||
{
|
||||
const struct usage_data *ua = a;
|
||||
const struct usage_data *ub = b;
|
||||
return strcmp(ua->aname, ub->aname);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int col, len2;
|
||||
|
||||
int i;
|
||||
int num_messages = sizeof(usage_array) / sizeof(usage_array[0]);
|
||||
|
||||
if (num_messages == 0)
|
||||
return 0;
|
||||
|
||||
qsort(usage_array,
|
||||
num_messages, sizeof(usage_array[0]),
|
||||
compare_func);
|
||||
|
||||
col = 0;
|
||||
for (i = 0; i < num_messages; i++) {
|
||||
len2 = strlen(usage_array[i].aname) + 2;
|
||||
if (col >= 76 - len2) {
|
||||
printf(",\n");
|
||||
col = 0;
|
||||
}
|
||||
if (col == 0) {
|
||||
col = 6;
|
||||
printf("\t");
|
||||
} else {
|
||||
printf(", ");
|
||||
}
|
||||
printf("%s", usage_array[i].aname);
|
||||
col += len2;
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("=head1 COMMAND DESCRIPTIONS\n\n");
|
||||
printf("=over 4\n\n");
|
||||
|
||||
for (i = 0; i < num_messages; i++) {
|
||||
if (usage_array[i].aname[0] >= 'a' && usage_array[i].aname[0] <= 'z'
|
||||
&& usage_array[i].usage[0] != NOUSAGE_STR[0]
|
||||
) {
|
||||
printf("=item B<%s>\n\n", usage_array[i].aname);
|
||||
if (usage_array[i].usage[0])
|
||||
printf("%s %s\n\n", usage_array[i].aname, usage_array[i].usage);
|
||||
else
|
||||
printf("%s\n\n", usage_array[i].aname);
|
||||
}
|
||||
}
|
||||
printf("=back\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: we used to make options bold with B<> and output an example too:
|
||||
|
||||
=item B<cat>
|
||||
|
||||
cat [B<-u>] [FILE]...
|
||||
|
||||
Concatenate FILE(s) and print them to stdout
|
||||
|
||||
Options:
|
||||
-u Use unbuffered i/o (ignored)
|
||||
|
||||
Example:
|
||||
$ cat /proc/uptime
|
||||
110716.72 17.67
|
||||
|
||||
*/
|
39
busybox-1_37_0/applets_sh/mim
Executable file
39
busybox-1_37_0/applets_sh/mim
Executable file
@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
MIMFILE="Mimfile"
|
||||
if [ $# -ge 2 ] && [ "$1" = "-f" ]
|
||||
then
|
||||
MIMFILE="$2"
|
||||
shift 2
|
||||
fi
|
||||
exec <"$MIMFILE" || exit 1
|
||||
{
|
||||
INCASE=false
|
||||
while read -r REPLY
|
||||
do
|
||||
case $REPLY in
|
||||
*:)
|
||||
if ! $INCASE
|
||||
then
|
||||
printf '[ $# -eq 0 ] && set -- "%s"
|
||||
TARGET="$1"
|
||||
shift
|
||||
case "$TARGET" in
|
||||
' "${REPLY%:}"
|
||||
else
|
||||
printf ';;\n'
|
||||
fi
|
||||
printf '%s)\n' "${REPLY%:}"
|
||||
INCASE=true
|
||||
;;
|
||||
"") ;;
|
||||
*) printf '%s\n' "${REPLY##[ ]}";;
|
||||
esac
|
||||
done
|
||||
$INCASE && printf ';;\n'
|
||||
printf '*)
|
||||
echo "Unknown command $TARGET"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'
|
||||
} | sh -s "$@"
|
3
busybox-1_37_0/applets_sh/nologin
Executable file
3
busybox-1_37_0/applets_sh/nologin
Executable file
@ -0,0 +1,3 @@
|
||||
cat /etc/nologin.txt 2>/dev/null || echo This account is not available
|
||||
sleep 5
|
||||
exit 1
|
21
busybox-1_37_0/arch/i386/Makefile
Normal file
21
busybox-1_37_0/arch/i386/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
# Allow i486 insns (basically, bswap insn)
|
||||
# Do not try to tune for 486+ (might add padding)
|
||||
CFLAGS += $(call cc-option,-march=i486 -mtune=i386,)
|
||||
|
||||
ifeq ($(CONFIG_STACK_OPTIMIZATION_386),y)
|
||||
# -mpreferred-stack-boundary=2 is essential in preventing gcc 4.2.x
|
||||
# from aligning stack to 16 bytes. (Which is gcc's way of supporting SSE).
|
||||
CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2,)
|
||||
endif
|
||||
|
||||
# "Control how GCC aligns variables.
|
||||
# Supported values for type are compat uses increased alignment value
|
||||
# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI,
|
||||
# and cacheline uses increased alignment value to match the cache line size.
|
||||
# compat is the default."
|
||||
# "abi" seems to be somewhat successful in preventing oversealous data alignment.
|
||||
CFLAGS += $(call cc-option,-malign-data=abi,)
|
11
busybox-1_37_0/arch/sparc/Makefile
Normal file
11
busybox-1_37_0/arch/sparc/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# When building a library, even intra-library references,
|
||||
# such as from find_applet_by_name() to applet_names[],
|
||||
# don't work with -fpic on sparc, needs -fPIC.
|
||||
# Don't know why it fails in this case but works when
|
||||
# a binary is being built.
|
||||
#
|
||||
# (if is superfluous, ARCH_FPIC is only used by library build, but it
|
||||
# demonstrates the point: non-pic binary does not need it)
|
||||
ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y)
|
||||
ARCH_FPIC = -fPIC
|
||||
endif
|
11
busybox-1_37_0/arch/sparc64/Makefile
Normal file
11
busybox-1_37_0/arch/sparc64/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# When building a library, even intra-library references,
|
||||
# such as from find_applet_by_name() to applet_names[],
|
||||
# don't work with -fpic on sparc, needs -fPIC.
|
||||
# Don't know why it fails in this case but works when
|
||||
# a binary is being built.
|
||||
#
|
||||
# (if is superfluous, ARCH_FPIC is only used by library build, but it
|
||||
# demonstrates the point: non-pic binary does not need it)
|
||||
ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y)
|
||||
ARCH_FPIC = -fPIC
|
||||
endif
|
11
busybox-1_37_0/arch/x86_64/Makefile
Normal file
11
busybox-1_37_0/arch/x86_64/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
# "Control how GCC aligns variables.
|
||||
# Supported values for type are compat uses increased alignment value
|
||||
# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI,
|
||||
# and cacheline uses increased alignment value to match the cache line size.
|
||||
# compat is the default."
|
||||
# "abi" seems to be somewhat successful in preventing oversealous data alignment.
|
||||
CFLAGS += $(call cc-option,-malign-data=abi,)
|
38
busybox-1_37_0/archival/Config.src
Normal file
38
busybox-1_37_0/archival/Config.src
Normal file
@ -0,0 +1,38 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see docs/Kconfig-language.txt.
|
||||
#
|
||||
|
||||
menu "Archival Utilities"
|
||||
|
||||
config FEATURE_SEAMLESS_XZ
|
||||
bool "Make tar, rpm, modprobe etc understand .xz data"
|
||||
default y
|
||||
|
||||
config FEATURE_SEAMLESS_LZMA
|
||||
bool "Make tar, rpm, modprobe etc understand .lzma data"
|
||||
default y
|
||||
|
||||
config FEATURE_SEAMLESS_BZ2
|
||||
bool "Make tar, rpm, modprobe etc understand .bz2 data"
|
||||
default y
|
||||
|
||||
config FEATURE_SEAMLESS_GZ
|
||||
bool "Make tar, rpm, modprobe etc understand .gz data"
|
||||
default y
|
||||
|
||||
config FEATURE_SEAMLESS_Z
|
||||
bool "Make tar, rpm, modprobe etc understand .Z data"
|
||||
default n # it is ancient
|
||||
|
||||
INSERT
|
||||
|
||||
config FEATURE_LZMA_FAST
|
||||
bool "Optimize lzma for speed"
|
||||
default n
|
||||
depends on UNLZMA || LZCAT || LZMA || FEATURE_SEAMLESS_LZMA
|
||||
help
|
||||
This option reduces decompression time by about 25% at the cost of
|
||||
a 1K bigger binary.
|
||||
|
||||
endmenu
|
11
busybox-1_37_0/archival/Kbuild.src
Normal file
11
busybox-1_37_0/archival/Kbuild.src
Normal file
@ -0,0 +1,11 @@
|
||||
# Makefile for busybox
|
||||
#
|
||||
# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
|
||||
#
|
||||
# Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
|
||||
libs-y += libarchive/
|
||||
|
||||
lib-y:=
|
||||
|
||||
INSERT
|
301
busybox-1_37_0/archival/ar.c
Normal file
301
busybox-1_37_0/archival/ar.c
Normal file
@ -0,0 +1,301 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Mini ar implementation for busybox
|
||||
*
|
||||
* Copyright (C) 2000 by Glenn McGrath
|
||||
*
|
||||
* Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*
|
||||
* Archive creation support:
|
||||
* Copyright (C) 2010 Nokia Corporation. All rights reserved.
|
||||
* Written by Alexander Shishkin.
|
||||
*
|
||||
* There is no single standard to adhere to so ar may not portable
|
||||
* between different systems
|
||||
* http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html
|
||||
*/
|
||||
//config:config AR
|
||||
//config: bool "ar (9.5 kb)"
|
||||
//config: default n # needs to be improved to be able to replace binutils ar
|
||||
//config: help
|
||||
//config: ar is an archival utility program used to create, modify, and
|
||||
//config: extract contents from archives. In practice, it is used exclusively
|
||||
//config: for object module archives used by compilers.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires ar, you should
|
||||
//config: probably say N here: most compilers come with their own ar utility.
|
||||
//config:
|
||||
//config:config FEATURE_AR_LONG_FILENAMES
|
||||
//config: bool "Support long filenames (not needed for debs)"
|
||||
//config: default y
|
||||
//config: depends on AR
|
||||
//config: help
|
||||
//config: By default the ar format can only store the first 15 characters
|
||||
//config: of the filename, this option removes that limitation.
|
||||
//config: It supports the GNU ar long filename method which moves multiple long
|
||||
//config: filenames into a the data section of a new ar entry.
|
||||
//config:
|
||||
//config:config FEATURE_AR_CREATE
|
||||
//config: bool "Support archive creation"
|
||||
//config: default y
|
||||
//config: depends on AR
|
||||
//config: help
|
||||
//config: This enables archive creation (-c and -r) with busybox ar.
|
||||
|
||||
//applet:IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
|
||||
//kbuild:lib-$(CONFIG_AR) += ar.o
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
#include "ar_.h"
|
||||
|
||||
#if ENABLE_FEATURE_AR_CREATE
|
||||
/* filter out entries with same names as specified on the command line */
|
||||
static char FAST_FUNC filter_replaceable(archive_handle_t *handle)
|
||||
{
|
||||
if (find_list_entry(handle->accept, handle->file_header->name))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void output_ar_header(archive_handle_t *handle)
|
||||
{
|
||||
/* GNU ar 2.19.51.0.14 creates malformed archives
|
||||
* if input files are >10G. It also truncates files >4GB
|
||||
* (uses "size mod 4G"). We abort in this case:
|
||||
* We could add support for up to 10G files, but this is unlikely to be useful.
|
||||
* Note that unpacking side limits all fields to "unsigned int" data type,
|
||||
* and treats "all ones" as an error indicator. Thus max we allow here is UINT_MAX-1.
|
||||
*/
|
||||
enum {
|
||||
/* for 2nd field: mtime */
|
||||
MAX11CHARS = UINT_MAX > 0xffffffff ? (unsigned)99999999999 : UINT_MAX-1,
|
||||
/* for last field: filesize */
|
||||
MAX10CHARS = UINT_MAX > 0xffffffff ? (unsigned)9999999999 : UINT_MAX-1,
|
||||
};
|
||||
|
||||
struct file_header_t *fh = handle->file_header;
|
||||
|
||||
if (handle->offset & 1) {
|
||||
xwrite(handle->src_fd, "\n", 1);
|
||||
handle->offset++;
|
||||
}
|
||||
|
||||
/* Careful! The widths should be exact. Fields must be separated */
|
||||
if (sizeof(off_t) > 4 && fh->size > (off_t)MAX10CHARS) {
|
||||
bb_error_msg_and_die("'%s' is bigger than ar can handle", fh->name);
|
||||
}
|
||||
fdprintf(handle->src_fd, "%-16.16s%-12lu%-6u%-6u%-8o%-10"OFF_FMT"u`\n",
|
||||
fh->name,
|
||||
(sizeof(time_t) > 4 && fh->mtime > MAX11CHARS) ? (long)0 : (long)fh->mtime,
|
||||
fh->uid > 99999 ? 0 : (int)fh->uid,
|
||||
fh->gid > 99999 ? 0 : (int)fh->gid,
|
||||
(int)fh->mode & 07777777,
|
||||
fh->size
|
||||
);
|
||||
|
||||
handle->offset += AR_HEADER_LEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* when replacing files in an existing archive, copy from the
|
||||
* original archive those files that are to be left intact
|
||||
*/
|
||||
static void FAST_FUNC copy_data(archive_handle_t *handle)
|
||||
{
|
||||
archive_handle_t *out_handle = handle->ar__out;
|
||||
struct file_header_t *fh = handle->file_header;
|
||||
|
||||
out_handle->file_header = fh;
|
||||
output_ar_header(out_handle);
|
||||
|
||||
bb_copyfd_exact_size(handle->src_fd, out_handle->src_fd, fh->size);
|
||||
out_handle->offset += fh->size;
|
||||
}
|
||||
|
||||
static int write_ar_header(archive_handle_t *handle)
|
||||
{
|
||||
char *fn;
|
||||
char fn_h[17]; /* 15 + "/" + NUL */
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
fn = llist_pop(&handle->accept);
|
||||
if (!fn)
|
||||
return -1;
|
||||
|
||||
xstat(fn, &st);
|
||||
|
||||
handle->file_header->mtime = st.st_mtime;
|
||||
handle->file_header->uid = st.st_uid;
|
||||
handle->file_header->gid = st.st_gid;
|
||||
handle->file_header->mode = st.st_mode;
|
||||
handle->file_header->size = st.st_size;
|
||||
handle->file_header->name = fn_h;
|
||||
//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES...
|
||||
sprintf(fn_h, "%.15s/", bb_basename(fn));
|
||||
|
||||
output_ar_header(handle);
|
||||
|
||||
fd = xopen(fn, O_RDONLY);
|
||||
bb_copyfd_exact_size(fd, handle->src_fd, st.st_size);
|
||||
close(fd);
|
||||
handle->offset += st.st_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_ar_archive(archive_handle_t *handle)
|
||||
{
|
||||
struct stat st;
|
||||
archive_handle_t *out_handle;
|
||||
|
||||
xfstat(handle->src_fd, &st, handle->ar__name);
|
||||
|
||||
/* if archive exists, create a new handle for output.
|
||||
* we create it in place of the old one.
|
||||
*/
|
||||
if (st.st_size != 0) {
|
||||
out_handle = init_handle();
|
||||
xunlink(handle->ar__name);
|
||||
out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
out_handle->accept = handle->accept;
|
||||
} else {
|
||||
out_handle = handle;
|
||||
}
|
||||
|
||||
handle->ar__out = out_handle;
|
||||
|
||||
xwrite(out_handle->src_fd, AR_MAGIC "\n", AR_MAGIC_LEN + 1);
|
||||
out_handle->offset += AR_MAGIC_LEN + 1;
|
||||
|
||||
/* skip to the end of the archive if we have to append stuff */
|
||||
if (st.st_size != 0) {
|
||||
handle->filter = filter_replaceable;
|
||||
handle->action_data = copy_data;
|
||||
unpack_ar_archive(handle);
|
||||
}
|
||||
|
||||
while (write_ar_header(out_handle) == 0)
|
||||
continue;
|
||||
|
||||
/* optional, since we exit right after we return */
|
||||
if (ENABLE_FEATURE_CLEAN_UP) {
|
||||
close(handle->src_fd);
|
||||
if (out_handle->src_fd != handle->src_fd)
|
||||
close(out_handle->src_fd);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif /* FEATURE_AR_CREATE */
|
||||
|
||||
static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
|
||||
{
|
||||
char mode[12];
|
||||
char *mtime;
|
||||
|
||||
bb_mode_string(mode, file_header->mode);
|
||||
mtime = ctime(&file_header->mtime);
|
||||
mtime[16] = ' ';
|
||||
memmove(&mtime[17], &mtime[20], 4);
|
||||
mtime[21] = '\0';
|
||||
printf("%s %u/%u%7"OFF_FMT"u %s %s\n", &mode[1],
|
||||
(int)file_header->uid, (int)file_header->gid,
|
||||
file_header->size,
|
||||
&mtime[4], file_header->name
|
||||
);
|
||||
}
|
||||
|
||||
//usage:#define ar_trivial_usage
|
||||
//usage: "x|p|t"IF_FEATURE_AR_CREATE("|r")" [-ov] ARCHIVE [FILE]..."
|
||||
//usage:#define ar_full_usage "\n\n"
|
||||
//usage: "Extract or list FILEs from an ar archive"IF_FEATURE_AR_CREATE(", or create it")"\n"
|
||||
//usage: "\n x Extract"
|
||||
//usage: "\n p Extract to stdout"
|
||||
//usage: "\n t List"
|
||||
//usage: IF_FEATURE_AR_CREATE(
|
||||
//usage: "\n r Create"
|
||||
//usage: )
|
||||
//usage: "\n -o Restore mtime"
|
||||
//usage: "\n -v Verbose"
|
||||
|
||||
int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int ar_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
archive_handle_t *archive_handle;
|
||||
unsigned opt, t;
|
||||
enum {
|
||||
OPT_VERBOSE = (1 << 0),
|
||||
OPT_PRESERVE_DATE = (1 << 1),
|
||||
/* "ar r" implies create, but warns about it. c suppresses warning.
|
||||
* bbox accepts but ignores it: */
|
||||
OPT_CREATE = (1 << 2),
|
||||
CMD_PRINT = (1 << 3),
|
||||
FIRST_CMD = CMD_PRINT,
|
||||
CMD_LIST = (1 << 4),
|
||||
CMD_EXTRACT = (1 << 5),
|
||||
CMD_INSERT = ((1 << 6) * ENABLE_FEATURE_AR_CREATE),
|
||||
};
|
||||
|
||||
archive_handle = init_handle();
|
||||
|
||||
/* prepend '-' to the first argument if required */
|
||||
if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0')
|
||||
argv[1] = xasprintf("-%s", argv[1]);
|
||||
opt = getopt32(argv, "^"
|
||||
"voc""ptx"IF_FEATURE_AR_CREATE("r")
|
||||
"\0"
|
||||
/* -1: at least one arg is reqd */
|
||||
/* one of p,t,x[,r] is required */
|
||||
"-1:p:t:x"IF_FEATURE_AR_CREATE(":r")
|
||||
);
|
||||
argv += optind;
|
||||
|
||||
t = opt / FIRST_CMD;
|
||||
if (t & (t-1)) /* more than one of p,t,x[,r] are specified */
|
||||
bb_show_usage();
|
||||
|
||||
if (opt & CMD_PRINT) {
|
||||
archive_handle->action_data = data_extract_to_stdout;
|
||||
}
|
||||
if (opt & CMD_LIST) {
|
||||
archive_handle->action_header = header_list;
|
||||
}
|
||||
if (opt & CMD_EXTRACT) {
|
||||
archive_handle->action_data = data_extract_all;
|
||||
}
|
||||
if (opt & OPT_PRESERVE_DATE) {
|
||||
archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
|
||||
}
|
||||
if (opt & OPT_VERBOSE) {
|
||||
archive_handle->action_header = header_verbose_list_ar;
|
||||
}
|
||||
#if ENABLE_FEATURE_AR_CREATE
|
||||
archive_handle->ar__name = *argv;
|
||||
#endif
|
||||
archive_handle->src_fd = xopen(*argv++,
|
||||
(opt & CMD_INSERT)
|
||||
? O_RDWR | O_CREAT
|
||||
: O_RDONLY
|
||||
);
|
||||
|
||||
if (*argv)
|
||||
archive_handle->filter = filter_accept_list;
|
||||
while (*argv) {
|
||||
llist_add_to_end(&archive_handle->accept, *argv++);
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_AR_CREATE
|
||||
if (opt & CMD_INSERT)
|
||||
return write_ar_archive(archive_handle);
|
||||
#endif
|
||||
|
||||
unpack_ar_archive(archive_handle);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
603
busybox-1_37_0/archival/bbunzip.c
Normal file
603
busybox-1_37_0/archival/bbunzip.c
Normal file
@ -0,0 +1,603 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Common code for gunzip-like applets
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
//kbuild:lib-$(CONFIG_ZCAT) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_BZCAT) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o
|
||||
|
||||
/* lzop_main() uses bbunpack(), need this: */
|
||||
//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_LZOPCAT) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_UNLZOP) += bbunzip.o
|
||||
/* bzip2_main() too: */
|
||||
//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o
|
||||
/* gzip_main() too: */
|
||||
//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
static
|
||||
int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
|
||||
{
|
||||
int fd = open3_or_warn(filename, flags, mode);
|
||||
if (fd < 0) {
|
||||
return 1;
|
||||
}
|
||||
xmove_fd(fd, to_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
|
||||
{
|
||||
return xasprintf("%s.%s", filename, expected_ext);
|
||||
}
|
||||
|
||||
int FAST_FUNC bbunpack(char **argv,
|
||||
IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate),
|
||||
char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
|
||||
const char *expected_ext
|
||||
)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
IF_DESKTOP(long long) int status = 0;
|
||||
char *filename, *new_name;
|
||||
smallint exitcode = 0;
|
||||
transformer_state_t xstate;
|
||||
|
||||
do {
|
||||
/* NB: new_name is *maybe* malloc'ed! */
|
||||
new_name = NULL;
|
||||
filename = *argv; /* can be NULL - 'streaming' bunzip2 */
|
||||
|
||||
if (filename && LONE_DASH(filename))
|
||||
filename = NULL;
|
||||
|
||||
/* Open src */
|
||||
if (filename) {
|
||||
if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
|
||||
if (stat(filename, &stat_buf) != 0) {
|
||||
err_name:
|
||||
bb_simple_perror_msg(filename);
|
||||
err:
|
||||
exitcode = 1;
|
||||
goto free_name;
|
||||
}
|
||||
if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
|
||||
goto err;
|
||||
} else {
|
||||
/* "clever zcat" with FILE */
|
||||
/* fail_if_not_compressed because zcat refuses uncompressed input */
|
||||
int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1);
|
||||
if (fd < 0)
|
||||
goto err_name;
|
||||
xmove_fd(fd, STDIN_FILENO);
|
||||
}
|
||||
} else
|
||||
if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) {
|
||||
/* "clever zcat" on stdin */
|
||||
if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Special cases: test, stdout */
|
||||
if (option_mask32 & (BBUNPK_OPT_STDOUT|BBUNPK_OPT_TEST)) {
|
||||
if (option_mask32 & BBUNPK_OPT_TEST)
|
||||
if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
|
||||
xfunc_die();
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
/* Open dst if we are going to unpack to file */
|
||||
if (filename) {
|
||||
new_name = make_new_name(filename, expected_ext);
|
||||
if (!new_name) {
|
||||
bb_error_msg("%s: unknown suffix - ignored", filename);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* -f: overwrite existing output files */
|
||||
if (option_mask32 & BBUNPK_OPT_FORCE) {
|
||||
unlink(new_name);
|
||||
}
|
||||
|
||||
/* O_EXCL: "real" bunzip2 doesn't overwrite files */
|
||||
/* GNU gunzip does not bail out, but goes to next file */
|
||||
if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
|
||||
stat_buf.st_mode))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check that the input is sane */
|
||||
if (!(option_mask32 & BBUNPK_OPT_FORCE) && isatty(STDIN_FILENO)) {
|
||||
bb_simple_error_msg_and_die("compressed data not read from terminal, "
|
||||
"use -f to force it");
|
||||
}
|
||||
|
||||
if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
|
||||
init_transformer_state(&xstate);
|
||||
/*xstate.signature_skipped = 0; - already is */
|
||||
/*xstate.src_fd = STDIN_FILENO; - already is */
|
||||
xstate.dst_fd = STDOUT_FILENO;
|
||||
status = unpacker(&xstate);
|
||||
if (status < 0)
|
||||
exitcode = 1;
|
||||
} else {
|
||||
if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0)
|
||||
/* Disk full, tty closed, etc. No point in continuing */
|
||||
xfunc_die();
|
||||
}
|
||||
|
||||
if (!(option_mask32 & BBUNPK_OPT_STDOUT))
|
||||
xclose(STDOUT_FILENO); /* with error check! */
|
||||
|
||||
if (filename) {
|
||||
char *del = new_name;
|
||||
|
||||
if (status >= 0) {
|
||||
unsigned new_name_len;
|
||||
|
||||
/* TODO: restore other things? */
|
||||
if (xstate.mtime != 0) {
|
||||
struct timeval times[2];
|
||||
|
||||
times[1].tv_sec = times[0].tv_sec = xstate.mtime;
|
||||
times[1].tv_usec = times[0].tv_usec = 0;
|
||||
/* Note: we closed it first.
|
||||
* On some systems calling utimes
|
||||
* then closing resets the mtime
|
||||
* back to current time. */
|
||||
utimes(new_name, times); /* ignoring errors */
|
||||
}
|
||||
|
||||
if (ENABLE_DESKTOP)
|
||||
new_name_len = strlen(new_name);
|
||||
/* Restore source filename (unless tgz -> tar case) */
|
||||
if (new_name == filename) {
|
||||
new_name_len = strlen(filename);
|
||||
filename[new_name_len] = '.';
|
||||
}
|
||||
/* Extreme bloat for gunzip compat */
|
||||
/* Some users do want this info... */
|
||||
if (ENABLE_DESKTOP && (option_mask32 & BBUNPK_OPT_VERBOSE)) {
|
||||
unsigned percent = status
|
||||
? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status)
|
||||
: 0;
|
||||
fprintf(stderr, "%s: %u%% - replaced with %.*s\n",
|
||||
filename,
|
||||
100u - percent,
|
||||
new_name_len, new_name
|
||||
);
|
||||
}
|
||||
/* Delete _source_ file */
|
||||
del = filename;
|
||||
if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */
|
||||
del = NULL;
|
||||
}
|
||||
if (del)
|
||||
xunlink(del);
|
||||
free_name:
|
||||
if (new_name != filename)
|
||||
free(new_name);
|
||||
}
|
||||
} while (*argv && *++argv);
|
||||
|
||||
if (option_mask32 & BBUNPK_OPT_STDOUT)
|
||||
xclose(STDOUT_FILENO); /* with error check! */
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
#if ENABLE_UNCOMPRESS \
|
||||
|| ENABLE_FEATURE_BZIP2_DECOMPRESS \
|
||||
|| ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA \
|
||||
|| ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ
|
||||
static
|
||||
char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
|
||||
{
|
||||
char *extension = strrchr(filename, '.');
|
||||
if (!extension || strcmp(extension + 1, expected_ext) != 0) {
|
||||
/* Mimic GNU gunzip - "real" bunzip2 tries to */
|
||||
/* unpack file anyway, to file.out */
|
||||
return NULL;
|
||||
}
|
||||
*extension = '\0';
|
||||
return filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Uncompress applet for busybox (c) 2002 Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
//usage:#define uncompress_trivial_usage
|
||||
//usage: "[-cf] [FILE]..."
|
||||
//usage:#define uncompress_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Overwrite"
|
||||
|
||||
//config:config UNCOMPRESS
|
||||
//config: bool "uncompress (7.1 kb)"
|
||||
//config: default n # ancient
|
||||
//config: help
|
||||
//config: uncompress is used to decompress archives created by compress.
|
||||
//config: Not much used anymore, replaced by gzip/gunzip.
|
||||
|
||||
//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP))
|
||||
//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
|
||||
#if ENABLE_UNCOMPRESS
|
||||
int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int uncompress_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
// (N)compress 4.2.4.4:
|
||||
// -d If given, decompression is done instead
|
||||
// -c Write output on stdout, don't remove original
|
||||
// -b Parameter limits the max number of bits/code
|
||||
// -f Forces output file to be generated
|
||||
// -v Write compression statistics
|
||||
// -V Output vesion and compile options
|
||||
// -r Recursive. If a filename is a directory, descend into it and compress everything
|
||||
getopt32(argv, "cf");
|
||||
|
||||
argv += optind;
|
||||
|
||||
return bbunpack(argv, unpack_Z_stream, make_new_name_generic, "Z");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Gzip implementation for busybox
|
||||
*
|
||||
* Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
|
||||
*
|
||||
* Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
|
||||
* based on gzip sources
|
||||
*
|
||||
* Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
|
||||
* well as stdin/stdout, and to generally behave itself wrt command line
|
||||
* handling.
|
||||
*
|
||||
* General cleanup to better adhere to the style guide and make use of standard
|
||||
* busybox functions by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*
|
||||
* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
|
||||
* Copyright (C) 1992-1993 Jean-loup Gailly
|
||||
* The unzip code was written and put in the public domain by Mark Adler.
|
||||
* Portions of the lzw code are derived from the public domain 'compress'
|
||||
* written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
|
||||
* Ken Turkowski, Dave Mack and Peter Jannesen.
|
||||
*/
|
||||
//usage:#define gunzip_trivial_usage
|
||||
//usage: "[-cfkt] [FILE]..."
|
||||
//usage:#define gunzip_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define gunzip_example_usage
|
||||
//usage: "$ ls -la /tmp/BusyBox*\n"
|
||||
//usage: "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n"
|
||||
//usage: "$ gunzip /tmp/BusyBox-0.43.tar.gz\n"
|
||||
//usage: "$ ls -la /tmp/BusyBox*\n"
|
||||
//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
|
||||
//usage:
|
||||
//usage:#define zcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define zcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config GUNZIP
|
||||
//config: bool "gunzip (11 kb)"
|
||||
//config: default y
|
||||
//config: select FEATURE_GZIP_DECOMPRESS
|
||||
//config: help
|
||||
//config: gunzip is used to decompress archives created by gzip.
|
||||
//config: You can use the '-t' option to test the integrity of
|
||||
//config: an archive, without decompressing it.
|
||||
//config:
|
||||
//config:config ZCAT
|
||||
//config: bool "zcat (24 kb)"
|
||||
//config: default y
|
||||
//config: select FEATURE_GZIP_DECOMPRESS
|
||||
//config: help
|
||||
//config: Alias to "gunzip -c".
|
||||
//config:
|
||||
//config:config FEATURE_GUNZIP_LONG_OPTIONS
|
||||
//config: bool "Enable long options"
|
||||
//config: default y
|
||||
//config: depends on (GUNZIP || ZCAT) && LONG_OPTS
|
||||
|
||||
//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
|
||||
// APPLET_ODDNAME:name main location suid_type help
|
||||
//applet:IF_ZCAT(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
|
||||
#if ENABLE_FEATURE_GZIP_DECOMPRESS
|
||||
static
|
||||
char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
|
||||
{
|
||||
char *extension = strrchr(filename, '.');
|
||||
|
||||
if (!extension)
|
||||
return NULL;
|
||||
|
||||
extension++;
|
||||
if (strcmp(extension, "tgz" + 1) == 0
|
||||
#if ENABLE_FEATURE_SEAMLESS_Z
|
||||
|| (extension[0] == 'Z' && extension[1] == '\0')
|
||||
#endif
|
||||
) {
|
||||
extension[-1] = '\0';
|
||||
} else if (strcmp(extension, "tgz") == 0) {
|
||||
filename = xstrdup(filename);
|
||||
extension = strrchr(filename, '.');
|
||||
extension[2] = 'a';
|
||||
extension[3] = 'r';
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
|
||||
static const char gunzip_longopts[] ALIGN1 =
|
||||
"stdout\0" No_argument "c"
|
||||
"to-stdout\0" No_argument "c"
|
||||
"force\0" No_argument "f"
|
||||
"test\0" No_argument "t"
|
||||
"no-name\0" No_argument "n"
|
||||
;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Linux kernel build uses gzip -d -n. We accept and ignore it.
|
||||
* Man page says:
|
||||
* -n --no-name
|
||||
* gzip: do not save the original file name and time stamp.
|
||||
* (The original name is always saved if the name had to be truncated.)
|
||||
* gunzip: do not restore the original file name/time even if present
|
||||
* (remove only the gzip suffix from the compressed file name).
|
||||
* This option is the default when decompressing.
|
||||
* -N --name
|
||||
* gzip: always save the original file name and time stamp (this is the default)
|
||||
* gunzip: restore the original file name and time stamp if present.
|
||||
*/
|
||||
int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int gunzip_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
|
||||
getopt32long(argv, BBUNPK_OPTSTR "dtn", gunzip_longopts);
|
||||
#else
|
||||
getopt32(argv, BBUNPK_OPTSTR "dtn");
|
||||
#endif
|
||||
argv += optind;
|
||||
|
||||
/* If called as zcat...
|
||||
* Normally, "zcat" is just "gunzip -c".
|
||||
* But if seamless magic is enabled, then we are much more clever.
|
||||
*/
|
||||
if (ENABLE_ZCAT && applet_name[1] == 'c')
|
||||
option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC;
|
||||
|
||||
return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
|
||||
}
|
||||
#endif /* FEATURE_GZIP_DECOMPRESS */
|
||||
|
||||
|
||||
/*
|
||||
* Modified for busybox by Glenn McGrath
|
||||
* Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
//usage:#define bunzip2_trivial_usage
|
||||
//usage: "[-cfk] [FILE]..."
|
||||
//usage:#define bunzip2_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define bzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define bzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config BUNZIP2
|
||||
//config: bool "bunzip2 (9.1 kb)"
|
||||
//config: default y
|
||||
//config: select FEATURE_BZIP2_DECOMPRESS
|
||||
//config: help
|
||||
//config: bunzip2 is a compression utility using the Burrows-Wheeler block
|
||||
//config: sorting text compression algorithm, and Huffman coding. Compression
|
||||
//config: is generally considerably better than that achieved by more
|
||||
//config: conventional LZ77/LZ78-based compressors, and approaches the
|
||||
//config: performance of the PPM family of statistical compressors.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires bunzip2, you
|
||||
//config: should probably say N here.
|
||||
//config:
|
||||
//config:config BZCAT
|
||||
//config: bool "bzcat (9 kb)"
|
||||
//config: default y
|
||||
//config: select FEATURE_BZIP2_DECOMPRESS
|
||||
//config: help
|
||||
//config: Alias to "bunzip2 -c".
|
||||
|
||||
//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
// APPLET_ODDNAME:name main location suid_type help
|
||||
//applet:IF_BZCAT(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
|
||||
#if ENABLE_FEATURE_BZIP2_DECOMPRESS || ENABLE_BUNZIP2 || ENABLE_BZCAT
|
||||
int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int bunzip2_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
getopt32(argv, BBUNPK_OPTSTR "dt");
|
||||
argv += optind;
|
||||
if (ENABLE_BZCAT && (!ENABLE_BUNZIP2 || applet_name[2] == 'c')) /* bzcat */
|
||||
option_mask32 |= BBUNPK_OPT_STDOUT;
|
||||
|
||||
return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Small lzma deflate implementation.
|
||||
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* Based on bunzip.c from busybox
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
//usage:#define unlzma_trivial_usage
|
||||
//usage: "[-cfk] [FILE]..."
|
||||
//usage:#define unlzma_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define lzma_trivial_usage
|
||||
//usage: "-d [-cfk] [FILE]..."
|
||||
//usage:#define lzma_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define lzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define lzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config UNLZMA
|
||||
//config: bool "unlzma (7.8 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: unlzma is a compression utility using the Lempel-Ziv-Markov chain
|
||||
//config: compression algorithm, and range coding. Compression
|
||||
//config: is generally considerably better than that achieved by the bzip2
|
||||
//config: compressors.
|
||||
//config:
|
||||
//config:config LZCAT
|
||||
//config: bool "lzcat (7.8 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Alias to "unlzma -c".
|
||||
//config:
|
||||
//config:config LZMA
|
||||
//config: bool "lzma -d"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Enable this option if you want commands like "lzma -d" to work.
|
||||
//config: IOW: you'll get lzma applet, but it will always require -d option.
|
||||
|
||||
//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
// APPLET_ODDNAME:name main location suid_type help
|
||||
//applet:IF_LZCAT(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat))
|
||||
//applet:IF_LZMA( APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
|
||||
//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_LZCAT) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_LZMA) += bbunzip.o
|
||||
#if ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA
|
||||
int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int unlzma_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
IF_LZMA(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
|
||||
# if ENABLE_LZMA
|
||||
/* lzma without -d or -t? */
|
||||
if (applet_name[2] == 'm' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
|
||||
bb_show_usage();
|
||||
# endif
|
||||
/* lzcat? */
|
||||
if (ENABLE_LZCAT && applet_name[2] == 'c')
|
||||
option_mask32 |= BBUNPK_OPT_STDOUT;
|
||||
|
||||
argv += optind;
|
||||
return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//usage:#define unxz_trivial_usage
|
||||
//usage: "[-cfk] [FILE]..."
|
||||
//usage:#define unxz_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define xz_trivial_usage
|
||||
//usage: "-d [-cfk] [FILE]..."
|
||||
//usage:#define xz_full_usage "\n\n"
|
||||
//usage: "Decompress FILEs (or stdin)\n"
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage:
|
||||
//usage:#define xzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define xzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config UNXZ
|
||||
//config: bool "unxz (13 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: unxz is a unlzma successor.
|
||||
//config:
|
||||
//config:config XZCAT
|
||||
//config: bool "xzcat (13 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Alias to "unxz -c".
|
||||
//config:
|
||||
//config:config XZ
|
||||
//config: bool "xz -d"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Enable this option if you want commands like "xz -d" to work.
|
||||
//config: IOW: you'll get xz applet, but it will always require -d option.
|
||||
|
||||
//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
// APPLET_ODDNAME:name main location suid_type help
|
||||
//applet:IF_XZCAT(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat))
|
||||
//applet:IF_XZ( APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
|
||||
//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_XZCAT) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_XZ) += bbunzip.o
|
||||
#if ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ
|
||||
int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int unxz_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
IF_XZ(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
|
||||
# if ENABLE_XZ
|
||||
/* xz without -d or -t? */
|
||||
if (applet_name[2] == '\0' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
|
||||
bb_show_usage();
|
||||
# endif
|
||||
/* xzcat? */
|
||||
if (ENABLE_XZCAT && applet_name[2] == 'c')
|
||||
option_mask32 |= BBUNPK_OPT_STDOUT;
|
||||
|
||||
argv += optind;
|
||||
return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz");
|
||||
}
|
||||
#endif
|
61
busybox-1_37_0/archival/bbunzip_test.sh
Normal file
61
busybox-1_37_0/archival/bbunzip_test.sh
Normal file
@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
# Test that concatenated gz files are unpacking correctly.
|
||||
# It also tests that unpacking in general is working right.
|
||||
# Since zip code has many corner cases, run it for a few hours
|
||||
# to get a decent coverage (200000 tests or more).
|
||||
|
||||
gzip="gzip"
|
||||
gunzip="../busybox gunzip"
|
||||
# Or the other way around:
|
||||
#gzip="../busybox gzip"
|
||||
#gunzip="gunzip"
|
||||
|
||||
c=0
|
||||
i=$PID
|
||||
while true; do
|
||||
c=$((c+1))
|
||||
|
||||
# RANDOM is not very random on some shells. Spice it up.
|
||||
# 100003 is prime
|
||||
len1=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
|
||||
i=$((i * 1664525 + 1013904223))
|
||||
len2=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
|
||||
|
||||
# Just using urandom will make gzip use method 0 (store) -
|
||||
# not good for test coverage!
|
||||
cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
|
||||
| dd bs=$len1 count=1 >z1 2>/dev/null
|
||||
cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \
|
||||
| dd bs=$len2 count=1 >z2 2>/dev/null
|
||||
|
||||
$gzip <z1 >zz.gz
|
||||
$gzip <z2 >>zz.gz
|
||||
$gunzip -c zz.gz >z9 || {
|
||||
echo "Exitcode $?"
|
||||
exit
|
||||
}
|
||||
sum=`cat z1 z2 | md5sum`
|
||||
sum9=`md5sum <z9`
|
||||
test "$sum" == "$sum9" || {
|
||||
echo "md5sums don't match"
|
||||
exit
|
||||
}
|
||||
echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum"
|
||||
|
||||
sum=`cat z1 z2 z1 z2 | md5sum`
|
||||
rm z1.gz z2.gz 2>/dev/null
|
||||
$gzip z1
|
||||
$gzip z2
|
||||
cat z1.gz z2.gz z1.gz z2.gz >zz.gz
|
||||
$gunzip -c zz.gz >z9 || {
|
||||
echo "Exitcode $? (2)"
|
||||
exit
|
||||
}
|
||||
sum9=`md5sum <z9`
|
||||
test "$sum" == "$sum9" || {
|
||||
echo "md5sums don't match (1)"
|
||||
exit
|
||||
}
|
||||
|
||||
echo "Test $c ok: len1=$len1 len2=$len2 sum=$sum (2)"
|
||||
done
|
10
busybox-1_37_0/archival/bbunzip_test2.sh
Normal file
10
busybox-1_37_0/archival/bbunzip_test2.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
# Leak test for gunzip. Watch top for growing process size.
|
||||
|
||||
# Just using urandom will make gzip use method 0 (store) -
|
||||
# not good for test coverage!
|
||||
|
||||
cat /dev/urandom \
|
||||
| while true; do read junk; echo "junk $RANDOM $junk"; done \
|
||||
| ../busybox gzip \
|
||||
| ../busybox gunzip -c >/dev/null
|
23
busybox-1_37_0/archival/bbunzip_test3.sh
Normal file
23
busybox-1_37_0/archival/bbunzip_test3.sh
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
# Leak test for gunzip. Watch top for growing process size.
|
||||
# In this case we look for leaks in "concatenated .gz" code -
|
||||
# we feed gunzip with a stream of .gz files.
|
||||
|
||||
i=$PID
|
||||
c=0
|
||||
while true; do
|
||||
c=$((c + 1))
|
||||
echo "Block# $c" >&2
|
||||
# RANDOM is not very random on some shells. Spice it up.
|
||||
i=$((i * 1664525 + 1013904223))
|
||||
# 100003 is prime
|
||||
len=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 ))
|
||||
|
||||
# Just using urandom will make gzip use method 0 (store) -
|
||||
# not good for test coverage!
|
||||
cat /dev/urandom \
|
||||
| while true; do read junk; echo "junk $c $i $junk"; done \
|
||||
| dd bs=$len count=1 2>/dev/null \
|
||||
| gzip >xxx.gz
|
||||
cat xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz
|
||||
done | ../busybox gunzip -c >/dev/null
|
247
busybox-1_37_0/archival/bzip2.c
Normal file
247
busybox-1_37_0/archival/bzip2.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
|
||||
*
|
||||
* This file uses bzip2 library code which is written
|
||||
* by Julian Seward <jseward@bzip.org>.
|
||||
* See README and LICENSE files in bz/ directory for more information
|
||||
* about bzip2 library code.
|
||||
*/
|
||||
//config:config BZIP2
|
||||
//config: bool "bzip2 (16 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: bzip2 is a compression utility using the Burrows-Wheeler block
|
||||
//config: sorting text compression algorithm, and Huffman coding. Compression
|
||||
//config: is generally considerably better than that achieved by more
|
||||
//config: conventional LZ77/LZ78-based compressors, and approaches the
|
||||
//config: performance of the PPM family of statistical compressors.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires bzip2, you
|
||||
//config: should probably say N here.
|
||||
//config:
|
||||
//config:config BZIP2_SMALL
|
||||
//config: int "Trade bytes for speed (0:fast, 9:small)"
|
||||
//config: default 8 # all "fast or small" options default to small
|
||||
//config: range 0 9
|
||||
//config: depends on BZIP2
|
||||
//config: help
|
||||
//config: Trade code size versus speed.
|
||||
//config: Approximate values with gcc-6.3.0 "bzip -9" compressing
|
||||
//config: linux-4.15.tar were:
|
||||
//config: value time (sec) code size (386)
|
||||
//config: 9 (smallest) 70.11 7687
|
||||
//config: 8 67.93 8091
|
||||
//config: 7 67.88 8405
|
||||
//config: 6 67.78 8624
|
||||
//config: 5 67.05 9427
|
||||
//config: 4-0 (fastest) 64.14 12083
|
||||
//config:
|
||||
//config:config FEATURE_BZIP2_DECOMPRESS
|
||||
//config: bool "Enable decompression"
|
||||
//config: default y
|
||||
//config: depends on BZIP2 || BUNZIP2 || BZCAT
|
||||
//config: help
|
||||
//config: Enable -d (--decompress) and -t (--test) options for bzip2.
|
||||
//config: This will be automatically selected if bunzip2 or bzcat is
|
||||
//config: enabled.
|
||||
|
||||
//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
|
||||
//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o
|
||||
|
||||
//usage:#define bzip2_trivial_usage
|
||||
//usage: "[-cfk" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789] [FILE]..."
|
||||
//usage:#define bzip2_full_usage "\n\n"
|
||||
//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n"
|
||||
//usage: "\n -1..9 Compression level"
|
||||
//usage: IF_FEATURE_BZIP2_DECOMPRESS(
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: )
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage: "\n -k Keep input files"
|
||||
//usage: IF_FEATURE_BZIP2_DECOMPRESS(
|
||||
//usage: "\n -t Test integrity"
|
||||
//usage: )
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#if CONFIG_BZIP2_SMALL >= 4
|
||||
#define BZIP2_SPEED (9 - CONFIG_BZIP2_SMALL)
|
||||
#else
|
||||
#define BZIP2_SPEED 5
|
||||
#endif
|
||||
|
||||
/* Speed test:
|
||||
* Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache).
|
||||
* Stock bzip2 is 26.4% slower than bbox bzip2 at SPEED 1
|
||||
* (time to compress gcc-4.2.1.tar is 126.4% compared to bbox).
|
||||
* At SPEED 5 difference is 32.7%.
|
||||
*
|
||||
* Test run of all BZIP2_SPEED values on a 11Mb text file:
|
||||
* Size Time (3 runs)
|
||||
* 0: 10828 4.145 4.146 4.148
|
||||
* 1: 11097 3.845 3.860 3.861
|
||||
* 2: 11392 3.763 3.767 3.768
|
||||
* 3: 11892 3.722 3.724 3.727
|
||||
* 4: 12740 3.637 3.640 3.644
|
||||
* 5: 17273 3.497 3.509 3.509
|
||||
*/
|
||||
|
||||
|
||||
#define BZ_DEBUG 0
|
||||
/* Takes ~300 bytes, detects corruption caused by bad RAM etc */
|
||||
#define BZ_LIGHT_DEBUG 0
|
||||
|
||||
#include "libarchive/bz/bzlib.h"
|
||||
|
||||
#include "libarchive/bz/bzlib_private.h"
|
||||
|
||||
#include "libarchive/bz/blocksort.c"
|
||||
#include "libarchive/bz/bzlib.c"
|
||||
#include "libarchive/bz/compress.c"
|
||||
#include "libarchive/bz/huffman.c"
|
||||
|
||||
/* No point in being shy and having very small buffer here.
|
||||
* bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
|
||||
* If iobuf is several pages long, malloc() may use mmap,
|
||||
* making iobuf page aligned and thus (maybe) have one memcpy less
|
||||
* if kernel is clever enough.
|
||||
*/
|
||||
enum {
|
||||
IOBUF_SIZE = 8 * 1024
|
||||
};
|
||||
|
||||
/* NB: compressStream() has to return -1 on errors, not die.
|
||||
* bbunpack() will correctly clean up in this case
|
||||
* (delete incomplete .bz2 file)
|
||||
*/
|
||||
|
||||
/* Returns:
|
||||
* -1 on errors
|
||||
* total written bytes so far otherwise
|
||||
*/
|
||||
static
|
||||
IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
|
||||
{
|
||||
int n, n2, ret;
|
||||
|
||||
strm->avail_in = rlen;
|
||||
strm->next_in = rbuf;
|
||||
while (1) {
|
||||
strm->avail_out = IOBUF_SIZE;
|
||||
strm->next_out = wbuf;
|
||||
|
||||
ret = BZ2_bzCompress(strm, rlen ? BZ_RUN : BZ_FINISH);
|
||||
if (ret != BZ_RUN_OK /* BZ_RUNning */
|
||||
&& ret != BZ_FINISH_OK /* BZ_FINISHing, but not done yet */
|
||||
&& ret != BZ_STREAM_END /* BZ_FINISHed */
|
||||
) {
|
||||
bb_error_msg_and_die("internal error %d", ret);
|
||||
}
|
||||
|
||||
n = IOBUF_SIZE - strm->avail_out;
|
||||
if (n) {
|
||||
n2 = full_write(STDOUT_FILENO, wbuf, n);
|
||||
if (n2 != n) {
|
||||
if (n2 >= 0)
|
||||
errno = 0; /* prevent bogus error message */
|
||||
bb_simple_perror_msg(n2 >= 0 ? "short write" : bb_msg_write_error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == BZ_STREAM_END)
|
||||
break;
|
||||
if (rlen && strm->avail_in == 0)
|
||||
break;
|
||||
}
|
||||
return 0 IF_DESKTOP( + strm->total_out );
|
||||
}
|
||||
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM)
|
||||
{
|
||||
IF_DESKTOP(long long) int total;
|
||||
unsigned opt, level;
|
||||
ssize_t count;
|
||||
bz_stream bzs; /* it's small */
|
||||
#define strm (&bzs)
|
||||
char *iobuf;
|
||||
#define rbuf iobuf
|
||||
#define wbuf (iobuf + IOBUF_SIZE)
|
||||
|
||||
iobuf = xmalloc(2 * IOBUF_SIZE);
|
||||
|
||||
opt = option_mask32 >> (BBUNPK_OPTSTRLEN IF_FEATURE_BZIP2_DECOMPRESS(+ 2) + 2);
|
||||
/* skipped BBUNPK_OPTSTR, "dt" and "zs" bits */
|
||||
opt |= 0x100; /* if nothing else, assume -9 */
|
||||
level = 0;
|
||||
for (;;) {
|
||||
level++;
|
||||
if (opt & 1) break;
|
||||
opt >>= 1;
|
||||
}
|
||||
|
||||
BZ2_bzCompressInit(strm, level);
|
||||
|
||||
while (1) {
|
||||
count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE);
|
||||
if (count < 0) {
|
||||
bb_simple_perror_msg(bb_msg_read_error);
|
||||
total = -1;
|
||||
break;
|
||||
}
|
||||
/* if count == 0, bz_write finalizes compression */
|
||||
total = bz_write(strm, rbuf, count, wbuf);
|
||||
if (count == 0 || total < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Can't be conditional on ENABLE_FEATURE_CLEAN_UP -
|
||||
* we are called repeatedly
|
||||
*/
|
||||
BZ2_bzCompressEnd(strm);
|
||||
free(iobuf);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int bzip2_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
unsigned opt;
|
||||
|
||||
/* standard bzip2 flags
|
||||
* -d --decompress force decompression
|
||||
* -z --compress force compression
|
||||
* -k --keep keep (don't delete) input files
|
||||
* -f --force overwrite existing output files
|
||||
* -t --test test compressed file integrity
|
||||
* -c --stdout output to standard out
|
||||
* -q --quiet suppress noncritical error messages
|
||||
* -v --verbose be verbose (a 2nd -v gives more)
|
||||
* -s --small use less memory (at most 2500k)
|
||||
* -1 .. -9 set block size to 100k .. 900k
|
||||
* --fast alias for -1
|
||||
* --best alias for -9
|
||||
*/
|
||||
|
||||
opt = getopt32(argv, "^"
|
||||
/* Must match BBUNPK_foo constants! */
|
||||
BBUNPK_OPTSTR IF_FEATURE_BZIP2_DECOMPRESS("dt") "zs123456789"
|
||||
"\0" "s2" /* -s means -2 (compatibility) */
|
||||
);
|
||||
#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */
|
||||
if (opt & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)) /* -d and/or -t */
|
||||
return bunzip2_main(argc, argv);
|
||||
#else
|
||||
/* clear "decompress" and "test" bits (or bbunpack() can get confused) */
|
||||
/* in !BZIP2_DECOMPRESS config, these bits are -zs and are unused */
|
||||
option_mask32 = opt & ~(BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST);
|
||||
#endif
|
||||
|
||||
argv += optind;
|
||||
return bbunpack(argv, compressStream, append_ext, "bz2");
|
||||
}
|
35
busybox-1_37_0/archival/chksum_and_xwrite_tar_header.c
Normal file
35
busybox-1_37_0/archival/chksum_and_xwrite_tar_header.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Denys Vlasenko <vda.linux@googlemail.com>
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
//kbuild:lib-$(CONFIG_FEATURE_TAR_CREATE) += chksum_and_xwrite_tar_header.o
|
||||
//kbuild:lib-$(CONFIG_SMEMCAP) += chksum_and_xwrite_tar_header.o
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC chksum_and_xwrite_tar_header(int fd, struct tar_header_t *hp)
|
||||
{
|
||||
/* POSIX says that checksum is done on unsigned bytes
|
||||
* (Sun and HP-UX gets it wrong... more details in
|
||||
* GNU tar source) */
|
||||
const unsigned char *cp;
|
||||
unsigned int chksum, size;
|
||||
|
||||
strcpy(hp->magic, "ustar ");
|
||||
|
||||
/* Calculate and store the checksum (the sum of all of the bytes of
|
||||
* the header). The checksum field must be filled with blanks for the
|
||||
* calculation. The checksum field is formatted differently from the
|
||||
* other fields: it has 6 digits, a NUL, then a space -- rather than
|
||||
* digits, followed by a NUL like the other fields... */
|
||||
memset(hp->chksum, ' ', sizeof(hp->chksum));
|
||||
cp = (const unsigned char *) hp;
|
||||
chksum = 0;
|
||||
size = sizeof(*hp);
|
||||
do { chksum += *cp++; } while (--size);
|
||||
sprintf(hp->chksum, "%06o", chksum);
|
||||
|
||||
xwrite(fd, hp, sizeof(*hp));
|
||||
}
|
581
busybox-1_37_0/archival/cpio.c
Normal file
581
busybox-1_37_0/archival/cpio.c
Normal file
@ -0,0 +1,581 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Mini cpio implementation for busybox
|
||||
*
|
||||
* Copyright (C) 2001 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*
|
||||
* Limitations:
|
||||
* Doesn't check CRC's
|
||||
* Only supports new ASCII and CRC formats
|
||||
*/
|
||||
//config:config CPIO
|
||||
//config: bool "cpio (15 kb)"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: cpio is an archival utility program used to create, modify, and
|
||||
//config: extract contents from archives.
|
||||
//config: cpio has 110 bytes of overheads for every stored file.
|
||||
//config:
|
||||
//config: This implementation of cpio can extract cpio archives created in the
|
||||
//config: "newc" or "crc" format.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires cpio, you
|
||||
//config: should probably say N here.
|
||||
//config:
|
||||
//config:config FEATURE_CPIO_O
|
||||
//config: bool "Support archive creation"
|
||||
//config: default y
|
||||
//config: depends on CPIO
|
||||
//config: help
|
||||
//config: This implementation of cpio can create cpio archives in the "newc"
|
||||
//config: format only.
|
||||
//config:
|
||||
//config:config FEATURE_CPIO_P
|
||||
//config: bool "Support passthrough mode"
|
||||
//config: default y
|
||||
//config: depends on FEATURE_CPIO_O
|
||||
//config: help
|
||||
//config: Passthrough mode. Rarely used.
|
||||
//config:
|
||||
//config:config FEATURE_CPIO_IGNORE_DEVNO
|
||||
//config: bool "Support --ignore-devno like GNU cpio"
|
||||
//config: default y
|
||||
//config: depends on FEATURE_CPIO_O && LONG_OPTS
|
||||
//config: help
|
||||
//config: Optionally ignore device numbers when creating archives.
|
||||
//config:
|
||||
//config:config FEATURE_CPIO_RENUMBER_INODES
|
||||
//config: bool "Support --renumber-inodes like GNU cpio"
|
||||
//config: default y
|
||||
//config: depends on FEATURE_CPIO_O && LONG_OPTS
|
||||
//config: help
|
||||
//config: Optionally renumber inodes when creating archives.
|
||||
|
||||
//applet:IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP))
|
||||
|
||||
//kbuild:lib-$(CONFIG_CPIO) += cpio.o
|
||||
|
||||
//usage:#define cpio_trivial_usage
|
||||
//usage: "[-dmvu] [-F FILE] [-R USER[:GRP]]" IF_FEATURE_CPIO_O(" [-H newc]")
|
||||
//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
|
||||
//usage: " [EXTR_FILE]..."
|
||||
//usage:#define cpio_full_usage "\n\n"
|
||||
//usage: "Extract (-i) or list (-t) files from a cpio archive on stdin"
|
||||
//usage: IF_FEATURE_CPIO_O(", or"
|
||||
//usage: "\ntake file list from stdin and create an archive (-o)"
|
||||
//usage: IF_FEATURE_CPIO_P(" or copy files (-p)")
|
||||
//usage: )
|
||||
//usage: "\n"
|
||||
//usage: "\nMain operation mode:"
|
||||
//usage: "\n -t List"
|
||||
//usage: "\n -i Extract EXTR_FILEs (or all)"
|
||||
//usage: IF_FEATURE_CPIO_O(
|
||||
//usage: "\n -o Create (requires -H newc)"
|
||||
//usage: )
|
||||
//usage: IF_FEATURE_CPIO_P(
|
||||
//usage: "\n -p DIR Copy files to DIR"
|
||||
//usage: )
|
||||
//usage: "\nOptions:"
|
||||
//usage: IF_FEATURE_CPIO_O(
|
||||
//usage: "\n -H newc Archive format"
|
||||
//usage: )
|
||||
//usage: "\n -d Make leading directories"
|
||||
//usage: "\n -m Restore mtime"
|
||||
//usage: "\n -v Verbose"
|
||||
//usage: "\n -u Overwrite"
|
||||
//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
|
||||
//usage: "\n -R USER[:GRP] Set owner of created files"
|
||||
//usage: "\n -L Dereference symlinks"
|
||||
//usage: "\n -0 NUL terminated input"
|
||||
//usage: IF_FEATURE_CPIO_IGNORE_DEVNO(
|
||||
//usage: "\n --ignore-devno"
|
||||
//usage: )
|
||||
//usage: IF_FEATURE_CPIO_RENUMBER_INODES(
|
||||
//usage: "\n --renumber-inodes"
|
||||
//usage: )
|
||||
|
||||
/* GNU cpio 2.9 --help (abridged):
|
||||
|
||||
Modes:
|
||||
-t, --list List the archive
|
||||
-i, --extract Extract files from an archive
|
||||
-o, --create Create the archive
|
||||
-p, --pass-through Copy-pass mode
|
||||
|
||||
Options valid in any mode:
|
||||
--block-size=SIZE I/O block size = SIZE * 512 bytes
|
||||
-B I/O block size = 5120 bytes
|
||||
-c Use the old portable (ASCII) archive format
|
||||
-C, --io-size=NUMBER I/O block size in bytes
|
||||
-f, --nonmatching Only copy files that do not match given pattern
|
||||
-F, --file=FILE Use FILE instead of standard input or output
|
||||
-H, --format=FORMAT Use given archive FORMAT
|
||||
-M, --message=STRING Print STRING when the end of a volume of the
|
||||
backup media is reached
|
||||
-n, --numeric-uid-gid If -v, show numeric UID and GID
|
||||
--quiet Do not print the number of blocks copied
|
||||
--rsh-command=COMMAND Use remote COMMAND instead of rsh
|
||||
-v, --verbose Verbosely list the files processed
|
||||
-V, --dot Print a "." for each file processed
|
||||
-W, --warning=FLAG Control warning display: 'none','truncate','all';
|
||||
multiple options accumulate
|
||||
|
||||
Options valid only in --extract mode:
|
||||
-b, --swap Swap both halfwords of words and bytes of
|
||||
halfwords in the data (equivalent to -sS)
|
||||
-r, --rename Interactively rename files
|
||||
-s, --swap-bytes Swap the bytes of each halfword in the files
|
||||
-S, --swap-halfwords Swap the halfwords of each word (4 bytes)
|
||||
--to-stdout Extract files to standard output
|
||||
-E, --pattern-file=FILE Read additional patterns specifying filenames to
|
||||
extract or list from FILE
|
||||
--only-verify-crc Verify CRC's, don't actually extract the files
|
||||
|
||||
Options valid only in --create mode:
|
||||
-A, --append Append to an existing archive
|
||||
-O FILE File to use instead of standard output
|
||||
|
||||
Options valid only in --pass-through mode:
|
||||
-l, --link Link files instead of copying them, when possible
|
||||
|
||||
Options valid in --extract and --create modes:
|
||||
--absolute-filenames Do not strip file system prefix components from
|
||||
the file names
|
||||
--no-absolute-filenames Create all files relative to the current dir
|
||||
|
||||
Options valid in --create and --pass-through modes:
|
||||
-0, --null A list of filenames is terminated by a NUL
|
||||
-a, --reset-access-time Reset the access times of files after reading them
|
||||
-I FILE File to use instead of standard input
|
||||
-L, --dereference Dereference symbolic links (copy the files
|
||||
that they point to instead of copying the links)
|
||||
-R, --owner=[USER][:.][GRP] Set owner of created files
|
||||
|
||||
Options valid in --extract and --pass-through modes:
|
||||
-d, --make-directories Create leading directories where needed
|
||||
-m, --preserve-modification-time Retain mtime when creating files
|
||||
--no-preserve-owner Do not change the ownership of the files
|
||||
--sparse Write files with blocks of zeros as sparse files
|
||||
-u, --unconditional Replace all files unconditionally
|
||||
*/
|
||||
|
||||
#include "libbb.h"
|
||||
#include "common_bufsiz.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
enum {
|
||||
OPT_EXTRACT = (1 << 0),
|
||||
OPT_TEST = (1 << 1),
|
||||
OPT_NUL_TERMINATED = (1 << 2),
|
||||
OPT_UNCONDITIONAL = (1 << 3),
|
||||
OPT_VERBOSE = (1 << 4),
|
||||
OPT_CREATE_LEADING_DIR = (1 << 5),
|
||||
OPT_PRESERVE_MTIME = (1 << 6),
|
||||
OPT_DEREF = (1 << 7),
|
||||
OPT_FILE = (1 << 8),
|
||||
OPT_OWNER = (1 << 9),
|
||||
OPTBIT_OWNER = 9,
|
||||
IF_FEATURE_CPIO_O(OPTBIT_CREATE ,)
|
||||
IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,)
|
||||
IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
|
||||
IF_LONG_OPTS( OPTBIT_QUIET ,)
|
||||
IF_LONG_OPTS( OPTBIT_2STDOUT ,)
|
||||
IF_FEATURE_CPIO_IGNORE_DEVNO(OPTBIT_IGNORE_DEVNO,)
|
||||
IF_FEATURE_CPIO_RENUMBER_INODES(OPTBIT_RENUMBER_INODES,)
|
||||
OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0,
|
||||
OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0,
|
||||
OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
|
||||
OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0,
|
||||
OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0,
|
||||
OPT_IGNORE_DEVNO = IF_FEATURE_CPIO_IGNORE_DEVNO((1 << OPTBIT_IGNORE_DEVNO)) + 0,
|
||||
OPT_RENUMBER_INODES = IF_FEATURE_CPIO_RENUMBER_INODES((1 << OPTBIT_RENUMBER_INODES)) + 0,
|
||||
};
|
||||
|
||||
#define OPTION_STR "it0uvdmLF:R:"
|
||||
|
||||
struct globals {
|
||||
struct bb_uidgid_t owner_ugid;
|
||||
ino_t next_inode;
|
||||
} FIX_ALIASING;
|
||||
#define G (*(struct globals*)bb_common_bufsiz1)
|
||||
void BUG_cpio_globals_too_big(void);
|
||||
#define INIT_G() do { \
|
||||
setup_common_bufsiz(); \
|
||||
G.owner_ugid.uid = -1L; \
|
||||
G.owner_ugid.gid = -1L; \
|
||||
} while (0)
|
||||
|
||||
#if ENABLE_FEATURE_CPIO_O
|
||||
static off_t cpio_pad4(off_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = (- size) & 3;
|
||||
size += i;
|
||||
while (--i >= 0)
|
||||
bb_putchar('\0');
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Return value will become exit code.
|
||||
* It's ok to exit instead of return. */
|
||||
static NOINLINE int cpio_o(void)
|
||||
{
|
||||
struct name_s {
|
||||
struct name_s *next;
|
||||
char name[1];
|
||||
};
|
||||
struct inodes_s {
|
||||
struct inodes_s *next;
|
||||
struct name_s *names;
|
||||
struct stat st;
|
||||
#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
|
||||
ino_t mapped_inode;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct inodes_s *links = NULL;
|
||||
off_t bytes = 0; /* output bytes count */
|
||||
|
||||
while (1) {
|
||||
const char *name;
|
||||
char *line;
|
||||
struct stat st;
|
||||
|
||||
line = (option_mask32 & OPT_NUL_TERMINATED)
|
||||
? bb_get_chunk_from_file(stdin, NULL)
|
||||
: xmalloc_fgetline(stdin);
|
||||
|
||||
if (line) {
|
||||
/* Strip leading "./[./]..." from the filename */
|
||||
name = line;
|
||||
while (name[0] == '.' && name[1] == '/') {
|
||||
while (*++name == '/')
|
||||
continue;
|
||||
}
|
||||
if (!*name) { /* line is empty */
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
if ((option_mask32 & OPT_DEREF)
|
||||
? stat(name, &st)
|
||||
: lstat(name, &st)
|
||||
) {
|
||||
abort_cpio_o:
|
||||
bb_simple_perror_msg_and_die(name);
|
||||
}
|
||||
|
||||
if (G.owner_ugid.uid != (uid_t)-1L)
|
||||
st.st_uid = G.owner_ugid.uid;
|
||||
if (G.owner_ugid.gid != (gid_t)-1L)
|
||||
st.st_gid = G.owner_ugid.gid;
|
||||
|
||||
if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
|
||||
st.st_size = 0; /* paranoia */
|
||||
|
||||
/* Store hardlinks for later processing, dont output them */
|
||||
if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
|
||||
struct name_s *n;
|
||||
struct inodes_s *l;
|
||||
|
||||
/* Do we have this hardlink remembered? */
|
||||
l = links;
|
||||
while (1) {
|
||||
if (l == NULL) {
|
||||
/* Not found: add new item to "links" list */
|
||||
l = xzalloc(sizeof(*l));
|
||||
l->st = st;
|
||||
l->next = links;
|
||||
#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
|
||||
if (option_mask32 & OPT_RENUMBER_INODES)
|
||||
l->mapped_inode = ++G.next_inode;
|
||||
#endif
|
||||
links = l;
|
||||
break;
|
||||
}
|
||||
if (l->st.st_ino == st.st_ino) {
|
||||
/* found */
|
||||
break;
|
||||
}
|
||||
l = l->next;
|
||||
}
|
||||
/* Add new name to "l->names" list */
|
||||
n = xmalloc(sizeof(*n) + strlen(name));
|
||||
strcpy(n->name, name);
|
||||
n->next = l->names;
|
||||
l->names = n;
|
||||
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
|
||||
else if (option_mask32 & OPT_RENUMBER_INODES) {
|
||||
st.st_ino = ++G.next_inode;
|
||||
}
|
||||
#endif
|
||||
} else { /* line == NULL: EOF */
|
||||
next_link:
|
||||
if (links) {
|
||||
/* Output hardlink's data */
|
||||
st = links->st;
|
||||
name = links->names->name;
|
||||
links->names = links->names->next;
|
||||
#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
|
||||
if (links->mapped_inode)
|
||||
st.st_ino = links->mapped_inode;
|
||||
#endif
|
||||
/* GNU cpio is reported to emit file data
|
||||
* only for the last instance. Mimic that. */
|
||||
if (links->names == NULL)
|
||||
links = links->next;
|
||||
else
|
||||
st.st_size = 0;
|
||||
/* NB: we leak links->names and/or links,
|
||||
* this is intended (we exit soon anyway) */
|
||||
} else {
|
||||
/* If no (more) hardlinks to output,
|
||||
* output "trailer" entry */
|
||||
name = cpio_TRAILER;
|
||||
/* st.st_size == 0 is a must, but for uniformity
|
||||
* in the output, we zero out everything */
|
||||
memset(&st, 0, sizeof(st));
|
||||
/* st.st_nlink = 1; - GNU cpio does this */
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
|
||||
if (option_mask32 & OPT_IGNORE_DEVNO)
|
||||
st.st_dev = st.st_rdev = 0;
|
||||
#endif
|
||||
|
||||
bytes += printf("070701"
|
||||
"%08X%08X%08X%08X%08X%08X%08X"
|
||||
"%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
|
||||
/* strlen+1: */ "%08X"
|
||||
/* chksum: */ "00000000" /* (only for "070702" files) */
|
||||
/* name,NUL: */ "%s%c",
|
||||
(unsigned)(uint32_t) st.st_ino,
|
||||
(unsigned)(uint32_t) st.st_mode,
|
||||
(unsigned)(uint32_t) st.st_uid,
|
||||
(unsigned)(uint32_t) st.st_gid,
|
||||
(unsigned)(uint32_t) st.st_nlink,
|
||||
(unsigned)(uint32_t) st.st_mtime,
|
||||
(unsigned)(uint32_t) st.st_size,
|
||||
(unsigned)(uint32_t) major(st.st_dev),
|
||||
(unsigned)(uint32_t) minor(st.st_dev),
|
||||
(unsigned)(uint32_t) major(st.st_rdev),
|
||||
(unsigned)(uint32_t) minor(st.st_rdev),
|
||||
(unsigned)(strlen(name) + 1),
|
||||
name, '\0');
|
||||
bytes = cpio_pad4(bytes);
|
||||
|
||||
if (st.st_size) {
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
char *lpath = xmalloc_readlink_or_warn(name);
|
||||
if (!lpath)
|
||||
goto abort_cpio_o;
|
||||
bytes += printf("%s", lpath);
|
||||
free(lpath);
|
||||
} else { /* S_ISREG */
|
||||
int fd = xopen(name, O_RDONLY);
|
||||
fflush_all();
|
||||
/* We must abort if file got shorter too! */
|
||||
bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
|
||||
bytes += st.st_size;
|
||||
close(fd);
|
||||
}
|
||||
bytes = cpio_pad4(bytes);
|
||||
}
|
||||
|
||||
if (!line) {
|
||||
if (name != cpio_TRAILER)
|
||||
goto next_link;
|
||||
/* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
free(line);
|
||||
} /* end of "while (1)" */
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int cpio_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
archive_handle_t *archive_handle;
|
||||
char *cpio_filename;
|
||||
char *cpio_owner;
|
||||
IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
|
||||
unsigned opt;
|
||||
#if ENABLE_LONG_OPTS
|
||||
const char *long_opts =
|
||||
"extract\0" No_argument "i"
|
||||
"list\0" No_argument "t"
|
||||
#if ENABLE_FEATURE_CPIO_O
|
||||
"create\0" No_argument "o"
|
||||
"format\0" Required_argument "H"
|
||||
#if ENABLE_FEATURE_CPIO_P
|
||||
"pass-through\0" No_argument "p"
|
||||
#endif
|
||||
#endif
|
||||
"owner\0" Required_argument "R"
|
||||
"verbose\0" No_argument "v"
|
||||
"null\0" No_argument "0"
|
||||
"quiet\0" No_argument "\xff"
|
||||
"to-stdout\0" No_argument "\xfe"
|
||||
#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
|
||||
"ignore-devno\0" No_argument "\xfd"
|
||||
#endif
|
||||
#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
|
||||
"renumber-inodes\0" No_argument "\xfc"
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
|
||||
INIT_G();
|
||||
archive_handle = init_handle();
|
||||
/* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
|
||||
archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
|
||||
|
||||
/* As of now we do not enforce this: */
|
||||
/* -i,-t,-o,-p are mutually exclusive */
|
||||
/* -u,-d,-m make sense only with -i or -p */
|
||||
/* -L makes sense only with -o or -p */
|
||||
|
||||
#if !ENABLE_FEATURE_CPIO_O
|
||||
opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner);
|
||||
#else
|
||||
opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts,
|
||||
&cpio_filename, &cpio_owner, &cpio_fmt);
|
||||
#endif
|
||||
argv += optind;
|
||||
if (opt & OPT_OWNER) { /* -R */
|
||||
parse_chown_usergroup_or_die(&G.owner_ugid, cpio_owner);
|
||||
archive_handle->cpio__owner = G.owner_ugid;
|
||||
}
|
||||
#if !ENABLE_FEATURE_CPIO_O
|
||||
if (opt & OPT_FILE) { /* -F */
|
||||
xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
|
||||
}
|
||||
#else
|
||||
if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */
|
||||
xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
|
||||
}
|
||||
if (opt & OPT_PASSTHROUGH) {
|
||||
pid_t pid;
|
||||
struct fd_pair pp;
|
||||
|
||||
if (argv[0] == NULL)
|
||||
bb_show_usage();
|
||||
if (opt & OPT_CREATE_LEADING_DIR)
|
||||
/* GNU cpio 2.13: "cpio -d -p a/b/c" works */
|
||||
bb_make_directory(argv[0], -1, FILEUTILS_RECUR);
|
||||
/* Crude existence check:
|
||||
* close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
|
||||
* We can also xopen, fstat, IS_DIR, later fchdir.
|
||||
* This would check for existence earlier and cleaner.
|
||||
* As it stands now, if we fail xchdir later,
|
||||
* child dies on EPIPE, unless it caught
|
||||
* a diffrerent problem earlier.
|
||||
* This is good enough for now.
|
||||
*/
|
||||
//FIXME: GNU cpio -d -p DIR does not immediately create DIR -
|
||||
//it just prepends "DIR/" to the names of files to be created.
|
||||
//The first file (fails to) be copied, and then the -d logic
|
||||
//triggers and creates all necessary directories.
|
||||
//IOW: bare "cpio -d -p DIR" + ^C shouldn't create anything.
|
||||
#if !BB_MMU
|
||||
pp.rd = 3;
|
||||
pp.wr = 4;
|
||||
if (!re_execed) {
|
||||
close(3);
|
||||
close(4);
|
||||
xpiped_pair(pp);
|
||||
}
|
||||
#else
|
||||
xpiped_pair(pp);
|
||||
#endif
|
||||
pid = fork_or_rexec(argv - optind);
|
||||
if (pid == 0) { /* child */
|
||||
close(pp.rd);
|
||||
xmove_fd(pp.wr, STDOUT_FILENO);
|
||||
goto dump;
|
||||
}
|
||||
/* parent */
|
||||
xchdir(*argv++);
|
||||
close(pp.wr);
|
||||
xmove_fd(pp.rd, STDIN_FILENO);
|
||||
//opt &= ~OPT_PASSTHROUGH;
|
||||
opt |= OPT_EXTRACT;
|
||||
goto skip;
|
||||
}
|
||||
/* -o */
|
||||
if (opt & OPT_CREATE) {
|
||||
if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
|
||||
bb_show_usage();
|
||||
if (opt & OPT_FILE) {
|
||||
xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
|
||||
}
|
||||
dump:
|
||||
return cpio_o();
|
||||
}
|
||||
skip:
|
||||
#endif
|
||||
|
||||
/* One of either extract or test options must be given */
|
||||
if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
|
||||
bb_show_usage();
|
||||
}
|
||||
|
||||
if (opt & OPT_TEST) {
|
||||
/* if both extract and test options are given, ignore extract option */
|
||||
opt &= ~OPT_EXTRACT;
|
||||
archive_handle->action_header = header_list;
|
||||
}
|
||||
if (opt & OPT_EXTRACT) {
|
||||
archive_handle->action_data = data_extract_all;
|
||||
if (opt & OPT_2STDOUT)
|
||||
archive_handle->action_data = data_extract_to_stdout;
|
||||
}
|
||||
if (opt & OPT_UNCONDITIONAL) {
|
||||
archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
|
||||
archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
|
||||
}
|
||||
if (opt & OPT_VERBOSE) {
|
||||
if (archive_handle->action_header == header_list) {
|
||||
archive_handle->action_header = header_verbose_list;
|
||||
} else {
|
||||
archive_handle->action_header = header_list;
|
||||
}
|
||||
}
|
||||
if (opt & OPT_CREATE_LEADING_DIR) {
|
||||
archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
|
||||
}
|
||||
if (opt & OPT_PRESERVE_MTIME) {
|
||||
archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
|
||||
}
|
||||
|
||||
while (*argv) {
|
||||
archive_handle->filter = filter_accept_list;
|
||||
llist_add_to(&archive_handle->accept, *argv);
|
||||
argv++;
|
||||
}
|
||||
|
||||
/* see get_header_cpio */
|
||||
archive_handle->cpio__blocks = (off_t)-1;
|
||||
while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
create_links_from_list(archive_handle->link_placeholders);
|
||||
|
||||
if (archive_handle->cpio__blocks != (off_t)-1
|
||||
&& !(opt & OPT_QUIET)
|
||||
) {
|
||||
fflush_all();
|
||||
fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1966
busybox-1_37_0/archival/dpkg.c
Normal file
1966
busybox-1_37_0/archival/dpkg.c
Normal file
File diff suppressed because it is too large
Load Diff
134
busybox-1_37_0/archival/dpkg_deb.c
Normal file
134
busybox-1_37_0/archival/dpkg_deb.c
Normal file
@ -0,0 +1,134 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* dpkg-deb packs, unpacks and provides information about Debian archives.
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
//config:config DPKG_DEB
|
||||
//config: bool "dpkg-deb (29 kb)"
|
||||
//config: default y
|
||||
//config: select FEATURE_SEAMLESS_GZ
|
||||
//config: help
|
||||
//config: dpkg-deb unpacks and provides information about Debian archives.
|
||||
//config:
|
||||
//config: This implementation of dpkg-deb cannot pack archives.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires dpkg-deb,
|
||||
//config: say N here.
|
||||
|
||||
//applet:IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, BB_DIR_USR_BIN, BB_SUID_DROP, dpkg_deb))
|
||||
|
||||
//kbuild:lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
|
||||
|
||||
//usage:#define dpkg_deb_trivial_usage
|
||||
//usage: "[-cefxX] FILE [DIR]"
|
||||
//usage:#define dpkg_deb_full_usage "\n\n"
|
||||
//usage: "Perform actions on Debian packages (.deb)\n"
|
||||
//usage: "\n -c List files"
|
||||
//usage: "\n -f Print control fields"
|
||||
//usage: "\n -e Extract control files to DIR (default: ./DEBIAN)"
|
||||
//usage: "\n -x Extract files to DIR (no default)"
|
||||
//usage: "\n -X Verbose extract"
|
||||
//usage:
|
||||
//usage:#define dpkg_deb_example_usage
|
||||
//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#define DPKG_DEB_OPT_CONTENTS 1
|
||||
#define DPKG_DEB_OPT_CONTROL 2
|
||||
#define DPKG_DEB_OPT_FIELD 4
|
||||
#define DPKG_DEB_OPT_EXTRACT_VERBOSE 8
|
||||
#define DPKG_DEB_OPT_EXTRACT 16
|
||||
|
||||
int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int dpkg_deb_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
archive_handle_t *ar_archive;
|
||||
archive_handle_t *tar_archive;
|
||||
llist_t *control_tar_llist = NULL;
|
||||
unsigned opt;
|
||||
const char *extract_dir;
|
||||
|
||||
/* Setup the tar archive handle */
|
||||
tar_archive = init_handle();
|
||||
|
||||
/* Setup an ar archive handle that refers to the gzip sub archive */
|
||||
ar_archive = init_handle();
|
||||
ar_archive->dpkg__sub_archive = tar_archive;
|
||||
ar_archive->filter = filter_accept_list_reassign;
|
||||
|
||||
llist_add_to(&ar_archive->accept, (char*)"data.tar");
|
||||
llist_add_to(&control_tar_llist, (char*)"control.tar");
|
||||
#if ENABLE_FEATURE_SEAMLESS_GZ
|
||||
llist_add_to(&ar_archive->accept, (char*)"data.tar.gz");
|
||||
llist_add_to(&control_tar_llist, (char*)"control.tar.gz");
|
||||
#endif
|
||||
#if ENABLE_FEATURE_SEAMLESS_BZ2
|
||||
llist_add_to(&ar_archive->accept, (char*)"data.tar.bz2");
|
||||
llist_add_to(&control_tar_llist, (char*)"control.tar.bz2");
|
||||
#endif
|
||||
#if ENABLE_FEATURE_SEAMLESS_LZMA
|
||||
llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma");
|
||||
llist_add_to(&control_tar_llist, (char*)"control.tar.lzma");
|
||||
#endif
|
||||
#if ENABLE_FEATURE_SEAMLESS_XZ
|
||||
llist_add_to(&ar_archive->accept, (char*)"data.tar.xz");
|
||||
llist_add_to(&control_tar_llist, (char*)"control.tar.xz");
|
||||
#endif
|
||||
|
||||
/* Must have 1 or 2 args */
|
||||
opt = getopt32(argv, "^" "cefXx"
|
||||
"\0" "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX"
|
||||
);
|
||||
argv += optind;
|
||||
//argc -= optind;
|
||||
|
||||
extract_dir = argv[1];
|
||||
if (opt & DPKG_DEB_OPT_CONTENTS) { // -c
|
||||
tar_archive->action_header = header_verbose_list;
|
||||
if (extract_dir)
|
||||
bb_show_usage();
|
||||
}
|
||||
if (opt & DPKG_DEB_OPT_FIELD) { // -f
|
||||
/* Print the entire control file */
|
||||
//TODO: standard tool accepts an optional list of fields to print
|
||||
ar_archive->accept = control_tar_llist;
|
||||
llist_add_to(&(tar_archive->accept), (char*)"./control");
|
||||
tar_archive->filter = filter_accept_list;
|
||||
tar_archive->action_data = data_extract_to_stdout;
|
||||
if (extract_dir)
|
||||
bb_show_usage();
|
||||
}
|
||||
if (opt & DPKG_DEB_OPT_CONTROL) { // -e
|
||||
ar_archive->accept = control_tar_llist;
|
||||
tar_archive->action_data = data_extract_all;
|
||||
if (!extract_dir)
|
||||
extract_dir = "./DEBIAN";
|
||||
}
|
||||
if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) { // -Xx
|
||||
if (opt & DPKG_DEB_OPT_EXTRACT_VERBOSE)
|
||||
tar_archive->action_header = header_list;
|
||||
tar_archive->action_data = data_extract_all;
|
||||
if (!extract_dir)
|
||||
bb_show_usage();
|
||||
}
|
||||
|
||||
/* Standard tool supports "-" */
|
||||
tar_archive->src_fd = ar_archive->src_fd = xopen_stdin(argv[0]);
|
||||
|
||||
if (extract_dir) {
|
||||
mkdir(extract_dir, 0777); /* bb_make_directory(extract_dir, 0777, 0) */
|
||||
xchdir(extract_dir);
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
unpack_ar_archive(ar_archive);
|
||||
|
||||
/* Cleanup */
|
||||
if (ENABLE_FEATURE_CLEAN_UP)
|
||||
close(ar_archive->src_fd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
2258
busybox-1_37_0/archival/gzip.c
Normal file
2258
busybox-1_37_0/archival/gzip.c
Normal file
File diff suppressed because it is too large
Load Diff
98
busybox-1_37_0/archival/libarchive/Kbuild.src
Normal file
98
busybox-1_37_0/archival/libarchive/Kbuild.src
Normal file
@ -0,0 +1,98 @@
|
||||
# Makefile for busybox
|
||||
#
|
||||
# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
|
||||
#
|
||||
# Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
|
||||
lib-y:= common.o
|
||||
|
||||
COMMON_FILES:= \
|
||||
\
|
||||
data_skip.o \
|
||||
data_extract_all.o \
|
||||
data_extract_to_stdout.o \
|
||||
\
|
||||
unsafe_symlink_target.o \
|
||||
\
|
||||
filter_accept_all.o \
|
||||
filter_accept_list.o \
|
||||
filter_accept_reject_list.o \
|
||||
\
|
||||
header_skip.o \
|
||||
header_list.o \
|
||||
header_verbose_list.o \
|
||||
\
|
||||
seek_by_read.o \
|
||||
seek_by_jump.o \
|
||||
\
|
||||
data_align.o \
|
||||
find_list_entry.o \
|
||||
init_handle.o
|
||||
|
||||
DPKG_FILES:= \
|
||||
unpack_ar_archive.o \
|
||||
filter_accept_list_reassign.o \
|
||||
unsafe_prefix.o \
|
||||
get_header_ar.o \
|
||||
get_header_tar.o \
|
||||
get_header_tar_gz.o \
|
||||
get_header_tar_bz2.o \
|
||||
get_header_tar_lzma.o \
|
||||
get_header_tar_xz.o \
|
||||
|
||||
INSERT
|
||||
|
||||
lib-$(CONFIG_DPKG) += $(DPKG_FILES)
|
||||
lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
|
||||
|
||||
lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
|
||||
lib-$(CONFIG_CPIO) += get_header_cpio.o
|
||||
lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o
|
||||
lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
|
||||
lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
|
||||
lib-$(CONFIG_UNLZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
|
||||
lib-$(CONFIG_LZOPCAT) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
|
||||
lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
|
||||
# 'bzip2 -d', bunzip2 or bzcat selects FEATURE_BZIP2_DECOMPRESS
|
||||
lib-$(CONFIG_FEATURE_BZIP2_DECOMPRESS) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_FEATURE_UNZIP_BZIP2) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_LZCAT) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_LZMA) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_FEATURE_UNZIP_LZMA) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o
|
||||
lib-$(CONFIG_XZCAT) += open_transformer.o decompress_unxz.o
|
||||
lib-$(CONFIG_XZ) += open_transformer.o decompress_unxz.o
|
||||
lib-$(CONFIG_FEATURE_UNZIP_XZ) += open_transformer.o decompress_unxz.o
|
||||
# 'gzip -d', gunzip or zcat selects FEATURE_GZIP_DECOMPRESS
|
||||
lib-$(CONFIG_FEATURE_GZIP_DECOMPRESS) += open_transformer.o decompress_gunzip.o
|
||||
lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o
|
||||
lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.o unsafe_prefix.o
|
||||
lib-$(CONFIG_RPM2CPIO) += open_transformer.o decompress_gunzip.o get_header_cpio.o
|
||||
lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o
|
||||
lib-$(CONFIG_GZIP) += open_transformer.o
|
||||
lib-$(CONFIG_BZIP2) += open_transformer.o
|
||||
lib-$(CONFIG_LZOP) += open_transformer.o
|
||||
lib-$(CONFIG_MAN) += open_transformer.o
|
||||
lib-$(CONFIG_SETFONT) += open_transformer.o
|
||||
lib-$(CONFIG_FEATURE_2_4_MODULES) += open_transformer.o
|
||||
lib-$(CONFIG_MODINFO) += open_transformer.o
|
||||
lib-$(CONFIG_INSMOD) += open_transformer.o
|
||||
lib-$(CONFIG_DEPMOD) += open_transformer.o
|
||||
lib-$(CONFIG_RMMOD) += open_transformer.o
|
||||
lib-$(CONFIG_LSMOD) += open_transformer.o
|
||||
lib-$(CONFIG_MODPROBE) += open_transformer.o
|
||||
lib-$(CONFIG_MODPROBE_SMALL) += open_transformer.o
|
||||
|
||||
lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o
|
||||
lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o
|
||||
lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
|
||||
lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o
|
||||
|
||||
ifneq ($(lib-y),)
|
||||
lib-y += $(COMMON_FILES)
|
||||
endif
|
44
busybox-1_37_0/archival/libarchive/bz/LICENSE
Normal file
44
busybox-1_37_0/archival/libarchive/bz/LICENSE
Normal file
@ -0,0 +1,44 @@
|
||||
bzip2 applet in busybox is based on lightly-modified source
|
||||
of bzip2 version 1.0.4. bzip2 source is distributed
|
||||
under the following conditions (copied verbatim from LICENSE file)
|
||||
===========================================================
|
||||
|
||||
|
||||
This program, "bzip2", the associated library "libbzip2", and all
|
||||
documentation, are copyright (C) 1996-2006 Julian R Seward. All
|
||||
rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, Cambridge, UK.
|
||||
jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
90
busybox-1_37_0/archival/libarchive/bz/README
Normal file
90
busybox-1_37_0/archival/libarchive/bz/README
Normal file
@ -0,0 +1,90 @@
|
||||
This file is an abridged version of README from bzip2 1.0.4
|
||||
Build instructions (which are not relevant to busyboxed bzip2)
|
||||
are removed.
|
||||
===========================================================
|
||||
|
||||
|
||||
This is the README for bzip2/libzip2.
|
||||
This version is fully compatible with the previous public releases.
|
||||
|
||||
------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in this file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------
|
||||
|
||||
Please read and be aware of the following:
|
||||
|
||||
|
||||
WARNING:
|
||||
|
||||
This program and library (attempts to) compress data by
|
||||
performing several non-trivial transformations on it.
|
||||
Unless you are 100% familiar with *all* the algorithms
|
||||
contained herein, and with the consequences of modifying them,
|
||||
you should NOT meddle with the compression or decompression
|
||||
machinery. Incorrect changes can and very likely *will*
|
||||
lead to disastrous loss of data.
|
||||
|
||||
|
||||
DISCLAIMER:
|
||||
|
||||
I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
|
||||
USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED.
|
||||
|
||||
Every compression of a file implies an assumption that the
|
||||
compressed file can be decompressed to reproduce the original.
|
||||
Great efforts in design, coding and testing have been made to
|
||||
ensure that this program works correctly. However, the complexity
|
||||
of the algorithms, and, in particular, the presence of various
|
||||
special cases in the code which occur with very low but non-zero
|
||||
probability make it impossible to rule out the possibility of bugs
|
||||
remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS
|
||||
PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER
|
||||
SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
|
||||
|
||||
That is not to say this program is inherently unreliable.
|
||||
Indeed, I very much hope the opposite is true. bzip2/libbzip2
|
||||
has been carefully constructed and extensively tested.
|
||||
|
||||
|
||||
PATENTS:
|
||||
|
||||
To the best of my knowledge, bzip2/libbzip2 does not use any
|
||||
patented algorithms. However, I do not have the resources
|
||||
to carry out a patent search. Therefore I cannot give any
|
||||
guarantee of the above statement.
|
||||
|
||||
|
||||
I hope you find bzip2 useful. Feel free to contact me at
|
||||
jseward@bzip.org
|
||||
if you have any suggestions or queries. Many people mailed me with
|
||||
comments, suggestions and patches after the releases of bzip-0.15,
|
||||
bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1,
|
||||
1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this
|
||||
feedback. I thank you for your comments.
|
||||
|
||||
bzip2's "home" is http://www.bzip.org/
|
||||
|
||||
Julian Seward
|
||||
jseward@bzip.org
|
||||
Cambridge, UK.
|
||||
|
||||
18 July 1996 (version 0.15)
|
||||
25 August 1996 (version 0.21)
|
||||
7 August 1997 (bzip2, version 0.1)
|
||||
29 August 1997 (bzip2, version 0.1pl2)
|
||||
23 August 1998 (bzip2, version 0.9.0)
|
||||
8 June 1999 (bzip2, version 0.9.5)
|
||||
4 Sept 1999 (bzip2, version 0.9.5d)
|
||||
5 May 2000 (bzip2, version 1.0pre8)
|
||||
30 December 2001 (bzip2, version 1.0.2pre1)
|
||||
15 February 2005 (bzip2, version 1.0.3)
|
||||
20 December 2006 (bzip2, version 1.0.4)
|
1079
busybox-1_37_0/archival/libarchive/bz/blocksort.c
Normal file
1079
busybox-1_37_0/archival/libarchive/bz/blocksort.c
Normal file
File diff suppressed because it is too large
Load Diff
428
busybox-1_37_0/archival/libarchive/bz/bzlib.c
Normal file
428
busybox-1_37_0/archival/libarchive/bz/bzlib.c
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* bzip2 is written by Julian Seward <jseward@bzip.org>.
|
||||
* Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
||||
* See README and LICENSE files in this directory for more information.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Library top-level functions. ---*/
|
||||
/*--- bzlib.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
/* CHANGES
|
||||
* 0.9.0 -- original version.
|
||||
* 0.9.0a/b -- no changes in this file.
|
||||
* 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
|
||||
* fixed bzWrite/bzRead to ignore zero-length requests.
|
||||
* fixed bzread to correctly handle read requests after EOF.
|
||||
* wrong parameter order in call to bzDecompressInit in
|
||||
* bzBuffToBuffDecompress. Fixed.
|
||||
*/
|
||||
|
||||
/* #include "bzlib_private.h" */
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Compression stuff ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#if BZ_LIGHT_DEBUG
|
||||
static
|
||||
void bz_assert_fail(int errcode)
|
||||
{
|
||||
/* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
|
||||
bb_error_msg_and_die("internal error %d", errcode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void prepare_new_block(EState* s)
|
||||
{
|
||||
int i;
|
||||
s->nblock = 0;
|
||||
//indexes into s->zbits[], initialzation moved to init of s->zbits
|
||||
//s->posZ = s->zbits; // was: s->numZ = 0;
|
||||
//s->state_out_pos = s->zbits;
|
||||
BZ_INITIALISE_CRC(s->blockCRC);
|
||||
/* inlined memset would be nice to have here */
|
||||
for (i = 0; i < 256; i++)
|
||||
s->inUse[i] = 0;
|
||||
s->blockNo++;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
ALWAYS_INLINE
|
||||
void init_RL(EState* s)
|
||||
{
|
||||
s->state_in_ch = 256;
|
||||
s->state_in_len = 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int isempty_RL(EState* s)
|
||||
{
|
||||
return (s->state_in_ch >= 256 || s->state_in_len <= 0);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
|
||||
{
|
||||
unsigned n;
|
||||
EState* s;
|
||||
|
||||
s = xzalloc(sizeof(EState));
|
||||
s->strm = strm;
|
||||
|
||||
n = 100000 * blockSize100k;
|
||||
s->arr1 = xmalloc(n * sizeof(uint32_t));
|
||||
s->mtfv = (uint16_t*)s->arr1;
|
||||
s->ptr = (uint32_t*)s->arr1;
|
||||
s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t));
|
||||
s->block = (uint8_t*)s->arr2;
|
||||
|
||||
crc32_filltable(s->crc32table, 1);
|
||||
|
||||
s->state = BZ_S_INPUT;
|
||||
s->mode = BZ_M_RUNNING;
|
||||
s->blockSize100k = blockSize100k;
|
||||
s->nblockMAX = n - 19;
|
||||
|
||||
strm->state = s;
|
||||
/*strm->total_in = 0;*/
|
||||
strm->total_out = 0;
|
||||
init_RL(s);
|
||||
prepare_new_block(s);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void add_pair_to_block(EState* s)
|
||||
{
|
||||
int32_t i;
|
||||
uint8_t ch = (uint8_t)(s->state_in_ch);
|
||||
for (i = 0; i < s->state_in_len; i++) {
|
||||
BZ_UPDATE_CRC(s, s->blockCRC, ch);
|
||||
}
|
||||
s->inUse[s->state_in_ch] = 1;
|
||||
switch (s->state_in_len) {
|
||||
case 3:
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
/* fall through */
|
||||
case 2:
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
/* fall through */
|
||||
case 1:
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
break;
|
||||
default:
|
||||
s->inUse[s->state_in_len - 4] = 1;
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
||||
s->block[s->nblock] = (uint8_t)(s->state_in_len - 4);
|
||||
s->nblock++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void flush_RL(EState* s)
|
||||
{
|
||||
if (s->state_in_ch < 256) add_pair_to_block(s);
|
||||
init_RL(s);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define ADD_CHAR_TO_BLOCK(zs, zchh0) \
|
||||
{ \
|
||||
uint32_t zchh = (uint32_t)(zchh0); \
|
||||
/*-- fast track the common case --*/ \
|
||||
if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
|
||||
uint8_t ch = (uint8_t)(zs->state_in_ch); \
|
||||
BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
|
||||
zs->inUse[zs->state_in_ch] = 1; \
|
||||
zs->block[zs->nblock] = (uint8_t)ch; \
|
||||
zs->nblock++; \
|
||||
zs->state_in_ch = zchh; \
|
||||
} \
|
||||
else \
|
||||
/*-- general, uncommon cases --*/ \
|
||||
if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
|
||||
if (zs->state_in_ch < 256) \
|
||||
add_pair_to_block(zs); \
|
||||
zs->state_in_ch = zchh; \
|
||||
zs->state_in_len = 1; \
|
||||
} else { \
|
||||
zs->state_in_len++; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void /*Bool*/ copy_input_until_stop(EState* s)
|
||||
{
|
||||
/*Bool progress_in = False;*/
|
||||
|
||||
#ifdef SAME_CODE_AS_BELOW
|
||||
if (s->mode == BZ_M_RUNNING) {
|
||||
/*-- fast track the common case --*/
|
||||
while (1) {
|
||||
/*-- no input? --*/
|
||||
if (s->strm->avail_in == 0) break;
|
||||
/*-- block full? --*/
|
||||
if (s->nblock >= s->nblockMAX) break;
|
||||
/*progress_in = True;*/
|
||||
ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in)));
|
||||
s->strm->next_in++;
|
||||
s->strm->avail_in--;
|
||||
/*s->strm->total_in++;*/
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*-- general, uncommon case --*/
|
||||
while (1) {
|
||||
/*-- no input? --*/
|
||||
if (s->strm->avail_in == 0) break;
|
||||
/*-- block full? --*/
|
||||
if (s->nblock >= s->nblockMAX) break;
|
||||
//# /*-- flush/finish end? --*/
|
||||
//# if (s->avail_in_expect == 0) break;
|
||||
/*progress_in = True;*/
|
||||
ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in));
|
||||
s->strm->next_in++;
|
||||
s->strm->avail_in--;
|
||||
/*s->strm->total_in++;*/
|
||||
//# s->avail_in_expect--;
|
||||
}
|
||||
}
|
||||
/*return progress_in;*/
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void /*Bool*/ copy_output_until_stop(EState* s)
|
||||
{
|
||||
/*Bool progress_out = False;*/
|
||||
|
||||
while (1) {
|
||||
/*-- no output space? --*/
|
||||
if (s->strm->avail_out == 0) break;
|
||||
|
||||
/*-- block done? --*/
|
||||
if (s->state_out_pos >= s->posZ) break;
|
||||
|
||||
/*progress_out = True;*/
|
||||
*(s->strm->next_out) = *s->state_out_pos++;
|
||||
s->strm->avail_out--;
|
||||
s->strm->next_out++;
|
||||
s->strm->total_out++;
|
||||
}
|
||||
/*return progress_out;*/
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void /*Bool*/ handle_compress(bz_stream *strm)
|
||||
{
|
||||
/*Bool progress_in = False;*/
|
||||
/*Bool progress_out = False;*/
|
||||
EState* s = strm->state;
|
||||
|
||||
while (1) {
|
||||
if (s->state == BZ_S_OUTPUT) {
|
||||
/*progress_out |=*/ copy_output_until_stop(s);
|
||||
if (s->state_out_pos < s->posZ) break;
|
||||
if (s->mode == BZ_M_FINISHING
|
||||
//# && s->avail_in_expect == 0
|
||||
&& s->strm->avail_in == 0
|
||||
&& isempty_RL(s))
|
||||
break;
|
||||
prepare_new_block(s);
|
||||
s->state = BZ_S_INPUT;
|
||||
#ifdef FLUSH_IS_UNUSED
|
||||
if (s->mode == BZ_M_FLUSHING
|
||||
&& s->avail_in_expect == 0
|
||||
&& isempty_RL(s))
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->state == BZ_S_INPUT) {
|
||||
/*progress_in |=*/ copy_input_until_stop(s);
|
||||
//#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
|
||||
if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) {
|
||||
flush_RL(s);
|
||||
BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING));
|
||||
s->state = BZ_S_OUTPUT;
|
||||
} else
|
||||
if (s->nblock >= s->nblockMAX) {
|
||||
BZ2_compressBlock(s, 0);
|
||||
s->state = BZ_S_OUTPUT;
|
||||
} else
|
||||
if (s->strm->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*return progress_in || progress_out;*/
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
int BZ2_bzCompress(bz_stream *strm, int action)
|
||||
{
|
||||
/*Bool progress;*/
|
||||
EState* s;
|
||||
|
||||
s = strm->state;
|
||||
|
||||
switch (s->mode) {
|
||||
case BZ_M_RUNNING:
|
||||
if (action == BZ_RUN) {
|
||||
/*progress =*/ handle_compress(strm);
|
||||
/*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
|
||||
return BZ_RUN_OK;
|
||||
}
|
||||
#ifdef FLUSH_IS_UNUSED
|
||||
else
|
||||
if (action == BZ_FLUSH) {
|
||||
//#s->avail_in_expect = strm->avail_in;
|
||||
s->mode = BZ_M_FLUSHING;
|
||||
goto case_BZ_M_FLUSHING;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
/*if (action == BZ_FINISH)*/ {
|
||||
//#s->avail_in_expect = strm->avail_in;
|
||||
s->mode = BZ_M_FINISHING;
|
||||
goto case_BZ_M_FINISHING;
|
||||
}
|
||||
|
||||
#ifdef FLUSH_IS_UNUSED
|
||||
case_BZ_M_FLUSHING:
|
||||
case BZ_M_FLUSHING:
|
||||
/*if (s->avail_in_expect != s->strm->avail_in)
|
||||
return BZ_SEQUENCE_ERROR;*/
|
||||
/*progress =*/ handle_compress(strm);
|
||||
if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
|
||||
return BZ_FLUSH_OK;
|
||||
s->mode = BZ_M_RUNNING;
|
||||
return BZ_RUN_OK;
|
||||
#endif
|
||||
|
||||
case_BZ_M_FINISHING:
|
||||
/*case BZ_M_FINISHING:*/
|
||||
default:
|
||||
/*if (s->avail_in_expect != s->strm->avail_in)
|
||||
return BZ_SEQUENCE_ERROR;*/
|
||||
/*progress =*/ handle_compress(strm);
|
||||
/*if (!progress) return BZ_SEQUENCE_ERROR;*/
|
||||
//#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
|
||||
//# return BZ_FINISH_OK;
|
||||
if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ)
|
||||
return BZ_FINISH_OK;
|
||||
/*s->mode = BZ_M_IDLE;*/
|
||||
return BZ_STREAM_END;
|
||||
}
|
||||
/* return BZ_OK; --not reached--*/
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_bzCompressEnd(bz_stream *strm)
|
||||
{
|
||||
EState* s;
|
||||
|
||||
s = strm->state;
|
||||
free(s->arr1);
|
||||
free(s->arr2);
|
||||
//free(s->ftab); // made it array member of s
|
||||
//free(s->crc32table); // ditto
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Misc convenience stuff ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
|
||||
static
|
||||
int BZ2_bzBuffToBuffCompress(char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int blockSize100k)
|
||||
{
|
||||
bz_stream strm;
|
||||
int ret;
|
||||
|
||||
if (dest == NULL || destLen == NULL
|
||||
|| source == NULL
|
||||
|| blockSize100k < 1 || blockSize100k > 9
|
||||
) {
|
||||
return BZ_PARAM_ERROR;
|
||||
}
|
||||
|
||||
BZ2_bzCompressInit(&strm, blockSize100k);
|
||||
|
||||
strm.next_in = source;
|
||||
strm.next_out = dest;
|
||||
strm.avail_in = sourceLen;
|
||||
strm.avail_out = *destLen;
|
||||
|
||||
ret = BZ2_bzCompress(&strm, BZ_FINISH);
|
||||
if (ret == BZ_FINISH_OK) goto output_overflow;
|
||||
if (ret != BZ_STREAM_END) goto errhandler;
|
||||
|
||||
/* normal termination */
|
||||
*destLen -= strm.avail_out;
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
return BZ_OK;
|
||||
|
||||
output_overflow:
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
return BZ_OUTBUFF_FULL;
|
||||
|
||||
errhandler:
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
65
busybox-1_37_0/archival/libarchive/bz/bzlib.h
Normal file
65
busybox-1_37_0/archival/libarchive/bz/bzlib.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* bzip2 is written by Julian Seward <jseward@bzip.org>.
|
||||
* Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
||||
* See README and LICENSE files in this directory for more information.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Public header file for the library. ---*/
|
||||
/*--- bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
#define BZ_RUN 0
|
||||
#define BZ_FLUSH 1
|
||||
#define BZ_FINISH 2
|
||||
|
||||
#define BZ_OK 0
|
||||
#define BZ_RUN_OK 1
|
||||
#define BZ_FLUSH_OK 2
|
||||
#define BZ_FINISH_OK 3
|
||||
#define BZ_STREAM_END 4
|
||||
#define BZ_SEQUENCE_ERROR (-1)
|
||||
#define BZ_PARAM_ERROR (-2)
|
||||
#define BZ_MEM_ERROR (-3)
|
||||
#define BZ_DATA_ERROR (-4)
|
||||
#define BZ_DATA_ERROR_MAGIC (-5)
|
||||
#define BZ_IO_ERROR (-6)
|
||||
#define BZ_UNEXPECTED_EOF (-7)
|
||||
#define BZ_OUTBUFF_FULL (-8)
|
||||
#define BZ_CONFIG_ERROR (-9)
|
||||
|
||||
typedef struct bz_stream {
|
||||
void *state;
|
||||
char *next_in;
|
||||
char *next_out;
|
||||
unsigned avail_in;
|
||||
unsigned avail_out;
|
||||
/*unsigned long long total_in;*/
|
||||
unsigned long long total_out;
|
||||
} bz_stream;
|
||||
|
||||
/*-- Core (low-level) library functions --*/
|
||||
|
||||
static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k);
|
||||
static int BZ2_bzCompress(bz_stream *strm, int action);
|
||||
#if ENABLE_FEATURE_CLEAN_UP
|
||||
static void BZ2_bzCompressEnd(bz_stream *strm);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
226
busybox-1_37_0/archival/libarchive/bz/bzlib_private.h
Normal file
226
busybox-1_37_0/archival/libarchive/bz/bzlib_private.h
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* bzip2 is written by Julian Seward <jseward@bzip.org>.
|
||||
* Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
||||
* See README and LICENSE files in this directory for more information.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Private header file for the library. ---*/
|
||||
/*--- bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
/* #include "bzlib.h" */
|
||||
|
||||
/*-- General stuff. --*/
|
||||
|
||||
typedef unsigned char Bool;
|
||||
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
#if BZ_LIGHT_DEBUG
|
||||
static void bz_assert_fail(int errcode) NORETURN;
|
||||
#define AssertH(cond, errcode) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
bz_assert_fail(errcode); \
|
||||
} while (0)
|
||||
#else
|
||||
#define AssertH(cond, msg) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if BZ_DEBUG
|
||||
#define AssertD(cond, msg) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
bb_error_msg_and_die("(debug build): internal error %s", msg); \
|
||||
} while (0)
|
||||
#else
|
||||
#define AssertD(cond, msg) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Header bytes. --*/
|
||||
|
||||
#define BZ_HDR_B 0x42 /* 'B' */
|
||||
#define BZ_HDR_Z 0x5a /* 'Z' */
|
||||
#define BZ_HDR_h 0x68 /* 'h' */
|
||||
#define BZ_HDR_0 0x30 /* '0' */
|
||||
|
||||
#define BZ_HDR_BZh0 0x425a6830
|
||||
|
||||
/*-- Constants for the back end. --*/
|
||||
|
||||
#define BZ_MAX_ALPHA_SIZE 258
|
||||
#define BZ_MAX_CODE_LEN 23
|
||||
|
||||
#define BZ_RUNA 0
|
||||
#define BZ_RUNB 1
|
||||
|
||||
#define BZ_N_GROUPS 6
|
||||
#define BZ_G_SIZE 50
|
||||
#define BZ_N_ITERS 4
|
||||
|
||||
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
|
||||
|
||||
|
||||
/*-- Stuff for doing CRCs. --*/
|
||||
|
||||
#define BZ_INITIALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = 0xffffffffL; \
|
||||
}
|
||||
|
||||
#define BZ_FINALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = ~(crcVar); \
|
||||
}
|
||||
|
||||
#define BZ_UPDATE_CRC(s, crcVar, cha) \
|
||||
{ \
|
||||
crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \
|
||||
}
|
||||
|
||||
|
||||
/*-- States and modes for compression. --*/
|
||||
|
||||
#define BZ_M_IDLE 1
|
||||
#define BZ_M_RUNNING 2
|
||||
#define BZ_M_FLUSHING 3
|
||||
#define BZ_M_FINISHING 4
|
||||
|
||||
#define BZ_S_OUTPUT 1
|
||||
#define BZ_S_INPUT 2
|
||||
|
||||
#define BZ_N_RADIX 2
|
||||
#define BZ_N_QSORT 12
|
||||
#define BZ_N_SHELL 18
|
||||
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
|
||||
|
||||
|
||||
/*-- Structure holding all the compression-side stuff. --*/
|
||||
|
||||
typedef struct EState {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream *strm;
|
||||
|
||||
/* mode this stream is in, and whether inputting */
|
||||
/* or outputting data */
|
||||
uint8_t mode;
|
||||
uint8_t state;
|
||||
|
||||
/* misc administratium */
|
||||
uint8_t blockSize100k;
|
||||
|
||||
/* remembers avail_in when flush/finish requested */
|
||||
/* bbox: not needed, strm->avail_in always has the same value */
|
||||
/* commented out with '//#' throughout the code */
|
||||
/* uint32_t avail_in_expect; */
|
||||
|
||||
/* for doing the block sorting */
|
||||
uint32_t *arr1;
|
||||
uint32_t *arr2;
|
||||
//uint32_t *ftab; //moved into this struct, see below
|
||||
|
||||
uint16_t *quadrant;
|
||||
int32_t budget;
|
||||
|
||||
/* aliases for arr1 and arr2 */
|
||||
uint32_t *ptr;
|
||||
uint8_t *block;
|
||||
uint16_t *mtfv;
|
||||
uint8_t *zbits;
|
||||
|
||||
/* run-length-encoding of the input */
|
||||
uint32_t state_in_ch;
|
||||
int32_t state_in_len;
|
||||
|
||||
/* input and output limits and current posns */
|
||||
int32_t nblock;
|
||||
int32_t nblockMAX;
|
||||
//int32_t numZ; // index into s->zbits[], replaced by pointer:
|
||||
uint8_t *posZ;
|
||||
uint8_t *state_out_pos;
|
||||
|
||||
/* the buffer for bit stream creation */
|
||||
uint32_t bsBuff;
|
||||
int32_t bsLive;
|
||||
|
||||
/* block and combined CRCs */
|
||||
uint32_t blockCRC;
|
||||
uint32_t combinedCRC;
|
||||
|
||||
/* misc administratium */
|
||||
int32_t blockNo;
|
||||
|
||||
/* stuff for coding the MTF values */
|
||||
int32_t nMTF;
|
||||
|
||||
/* map of bytes used in block */
|
||||
int32_t nInUse;
|
||||
Bool inUse[256] ALIGNED(sizeof(long));
|
||||
uint8_t unseqToSeq[256];
|
||||
|
||||
/* stuff for coding the MTF values */
|
||||
int32_t mtfFreq [BZ_MAX_ALPHA_SIZE];
|
||||
uint8_t selector [BZ_MAX_SELECTORS];
|
||||
uint8_t selectorMtf[BZ_MAX_SELECTORS];
|
||||
|
||||
uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
|
||||
/* guess what */
|
||||
uint32_t crc32table[256];
|
||||
|
||||
/* for doing the block sorting */
|
||||
uint32_t ftab[65537];
|
||||
|
||||
/* stack-saving measures: these can be local, but they are too big */
|
||||
int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
#if BZIP2_SPEED >= 5
|
||||
/* second dimension: only 3 needed; 4 makes index calculations faster */
|
||||
uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4];
|
||||
#endif
|
||||
int32_t BZ2_hbMakeCodeLengths__heap [BZ_MAX_ALPHA_SIZE + 2];
|
||||
int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2];
|
||||
int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2];
|
||||
|
||||
int32_t mainSort__copyStart[256];
|
||||
int32_t mainSort__copyEnd[256];
|
||||
} EState;
|
||||
|
||||
|
||||
/*-- compression. --*/
|
||||
|
||||
static int32_t
|
||||
BZ2_blockSort(EState*);
|
||||
|
||||
static void
|
||||
BZ2_compressBlock(EState*, int);
|
||||
|
||||
static void
|
||||
BZ2_bsInitWrite(EState*);
|
||||
|
||||
static void
|
||||
BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t);
|
||||
|
||||
static void
|
||||
BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t);
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
752
busybox-1_37_0/archival/libarchive/bz/compress.c
Normal file
752
busybox-1_37_0/archival/libarchive/bz/compress.c
Normal file
@ -0,0 +1,752 @@
|
||||
/*
|
||||
* bzip2 is written by Julian Seward <jseward@bzip.org>.
|
||||
* Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
||||
* See README and LICENSE files in this directory for more information.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Compression machinery (not incl block sorting) ---*/
|
||||
/*--- compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
/* CHANGES
|
||||
* 0.9.0 -- original version.
|
||||
* 0.9.0a/b -- no changes in this file.
|
||||
* 0.9.0c -- changed setting of nGroups in sendMTFValues()
|
||||
* so as to do a bit better on small files
|
||||
*/
|
||||
|
||||
/* #include "bzlib_private.h" */
|
||||
|
||||
#if BZIP2_SPEED >= 5
|
||||
# define ALWAYS_INLINE_5 ALWAYS_INLINE
|
||||
#else
|
||||
# define ALWAYS_INLINE_5 /*nothing*/
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Bit stream I/O ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_bsInitWrite(EState* s)
|
||||
{
|
||||
s->bsLive = 0;
|
||||
s->bsBuff = 0;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static NOINLINE
|
||||
void bsFinishWrite(EState* s)
|
||||
{
|
||||
while (s->bsLive > 0) {
|
||||
*s->posZ++ = (uint8_t)(s->bsBuff >> 24);
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
/* Helps only on level 5, on other levels hurts. ? */
|
||||
ALWAYS_INLINE_5
|
||||
void bsW(EState* s, int32_t n, uint32_t v)
|
||||
{
|
||||
while (s->bsLive >= 8) {
|
||||
*s->posZ++ = (uint8_t)(s->bsBuff >> 24);
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
s->bsBuff |= (v << (32 - s->bsLive - n));
|
||||
s->bsLive += n;
|
||||
}
|
||||
/* Same with n == 16: */
|
||||
static
|
||||
ALWAYS_INLINE_5
|
||||
void bsW16(EState* s, uint32_t v)
|
||||
{
|
||||
while (s->bsLive >= 8) {
|
||||
*s->posZ++ = (uint8_t)(s->bsBuff >> 24);
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
s->bsBuff |= (v << (16 - s->bsLive));
|
||||
s->bsLive += 16;
|
||||
}
|
||||
/* Same with n == 1: */
|
||||
static
|
||||
ALWAYS_INLINE /* one callsite */
|
||||
void bsW1_1(EState* s)
|
||||
{
|
||||
/* need space for only 1 bit, no need for loop freeing > 8 bits */
|
||||
if (s->bsLive >= 8) {
|
||||
*s->posZ++ = (uint8_t)(s->bsBuff >> 24);
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
s->bsBuff |= (1 << (31 - s->bsLive));
|
||||
s->bsLive += 1;
|
||||
}
|
||||
static
|
||||
ALWAYS_INLINE_5
|
||||
void bsW1_0(EState* s)
|
||||
{
|
||||
/* need space for only 1 bit, no need for loop freeing > 8 bits */
|
||||
if (s->bsLive >= 8) {
|
||||
*s->posZ++ = (uint8_t)(s->bsBuff >> 24);
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
//s->bsBuff |= (0 << (31 - s->bsLive));
|
||||
s->bsLive += 1;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static ALWAYS_INLINE
|
||||
void bsPutU16(EState* s, unsigned u)
|
||||
{
|
||||
bsW16(s, u);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutU32(EState* s, unsigned u)
|
||||
{
|
||||
//bsW(s, 32, u); // can't use: may try "uint32 << -n"
|
||||
bsW16(s, (u >> 16) & 0xffff);
|
||||
bsW16(s, u & 0xffff);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- The back end proper ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_e(EState* s)
|
||||
{
|
||||
int i;
|
||||
unsigned cnt = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (s->inUse[i]) {
|
||||
s->unseqToSeq[i] = cnt;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
s->nInUse = cnt;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*
|
||||
* This bit of code is performance-critical.
|
||||
* On 32bit x86, gcc-6.3.0 was observed to spill ryy_j to stack,
|
||||
* resulting in abysmal performance (x3 slowdown).
|
||||
* Forcing it into a separate function alleviates register pressure,
|
||||
* and spillage no longer happens.
|
||||
* Other versions of gcc do not exhibit this problem, but out-of-line code
|
||||
* seems to be helping them too (code is both smaller and faster).
|
||||
* Therefore NOINLINE is enabled for the entire 32bit x86 arch for now,
|
||||
* without a check for gcc version.
|
||||
*/
|
||||
static
|
||||
#if defined __i386__
|
||||
NOINLINE
|
||||
#endif
|
||||
int inner_loop(uint8_t *yy, uint8_t ll_i)
|
||||
{
|
||||
register uint8_t rtmp;
|
||||
register uint8_t* ryy_j;
|
||||
rtmp = yy[1];
|
||||
yy[1] = yy[0];
|
||||
ryy_j = &(yy[1]);
|
||||
while (ll_i != rtmp) {
|
||||
register uint8_t rtmp2;
|
||||
ryy_j++;
|
||||
rtmp2 = rtmp;
|
||||
rtmp = *ryy_j;
|
||||
*ryy_j = rtmp2;
|
||||
}
|
||||
yy[0] = rtmp;
|
||||
return ryy_j - &(yy[0]);
|
||||
}
|
||||
static NOINLINE
|
||||
void generateMTFValues(EState* s)
|
||||
{
|
||||
uint8_t yy[256];
|
||||
int i;
|
||||
int zPend;
|
||||
int32_t wr;
|
||||
|
||||
/*
|
||||
* After sorting (eg, here),
|
||||
* s->arr1[0 .. s->nblock-1] holds sorted order,
|
||||
* and
|
||||
* ((uint8_t*)s->arr2)[0 .. s->nblock-1]
|
||||
* holds the original block data.
|
||||
*
|
||||
* The first thing to do is generate the MTF values,
|
||||
* and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1].
|
||||
*
|
||||
* Because there are strictly fewer or equal MTF values
|
||||
* than block values, ptr values in this area are overwritten
|
||||
* with MTF values only when they are no longer needed.
|
||||
*
|
||||
* The final compressed bitstream is generated into the
|
||||
* area starting at &((uint8_t*)s->arr2)[s->nblock]
|
||||
*
|
||||
* These storage aliases are set up in bzCompressInit(),
|
||||
* except for the last one, which is arranged in
|
||||
* compressBlock().
|
||||
*/
|
||||
uint32_t* ptr = s->ptr;
|
||||
|
||||
makeMaps_e(s);
|
||||
|
||||
wr = 0;
|
||||
zPend = 0;
|
||||
for (i = 0; i <= s->nInUse+1; i++)
|
||||
s->mtfFreq[i] = 0;
|
||||
|
||||
for (i = 0; i < s->nInUse; i++)
|
||||
yy[i] = (uint8_t) i;
|
||||
|
||||
for (i = 0; i < s->nblock; i++) {
|
||||
uint8_t ll_i = ll_i; /* gcc 4.3.1 thinks it may be used w/o init */
|
||||
int32_t j;
|
||||
|
||||
AssertD(wr <= i, "generateMTFValues(1)");
|
||||
j = ptr[i] - 1;
|
||||
if (j < 0)
|
||||
j += s->nblock;
|
||||
ll_i = s->unseqToSeq[s->block[j]];
|
||||
AssertD(ll_i < s->nInUse, "generateMTFValues(2a)");
|
||||
|
||||
if (yy[0] == ll_i) {
|
||||
zPend++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zPend > 0) {
|
||||
process_zPend:
|
||||
zPend--;
|
||||
while (1) {
|
||||
#if 0
|
||||
if (zPend & 1) {
|
||||
s->mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
s->mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
#else /* same as above, since BZ_RUNA is 0 and BZ_RUNB is 1 */
|
||||
unsigned run = zPend & 1;
|
||||
s->mtfv[wr] = run;
|
||||
wr++;
|
||||
s->mtfFreq[run]++;
|
||||
#endif
|
||||
zPend -= 2;
|
||||
if (zPend < 0)
|
||||
break;
|
||||
zPend = (unsigned)zPend / 2;
|
||||
/* bbox: unsigned div is easier */
|
||||
}
|
||||
if (i < 0) /* came via "goto process_zPend"? exit */
|
||||
goto end;
|
||||
zPend = 0;
|
||||
}
|
||||
j = inner_loop(yy, ll_i);
|
||||
s->mtfv[wr] = j+1;
|
||||
wr++;
|
||||
s->mtfFreq[j+1]++;
|
||||
}
|
||||
|
||||
i = -1;
|
||||
if (zPend > 0)
|
||||
goto process_zPend; /* "process it and come back here" */
|
||||
end:
|
||||
s->mtfv[wr] = s->nInUse+1;
|
||||
wr++;
|
||||
s->mtfFreq[s->nInUse+1]++;
|
||||
|
||||
s->nMTF = wr;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define BZ_LESSER_ICOST 0
|
||||
#define BZ_GREATER_ICOST 15
|
||||
|
||||
static NOINLINE
|
||||
void sendMTFValues(EState* s)
|
||||
{
|
||||
int32_t t, i;
|
||||
unsigned iter;
|
||||
unsigned gs;
|
||||
int32_t alphaSize;
|
||||
unsigned nSelectors, selCtr;
|
||||
int32_t nGroups;
|
||||
|
||||
/*
|
||||
* uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
* is a global since the decoder also needs it.
|
||||
*
|
||||
* int32_t code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
* int32_t rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
* are also globals only used in this proc.
|
||||
* Made global to keep stack frame size small.
|
||||
*/
|
||||
#define code sendMTFValues__code
|
||||
#define rfreq sendMTFValues__rfreq
|
||||
#define len_pack sendMTFValues__len_pack
|
||||
|
||||
unsigned /*uint16_t*/ cost[BZ_N_GROUPS];
|
||||
|
||||
uint16_t* mtfv = s->mtfv;
|
||||
|
||||
alphaSize = s->nInUse + 2;
|
||||
for (t = 0; t < BZ_N_GROUPS; t++) {
|
||||
unsigned v;
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->len[t][v] = BZ_GREATER_ICOST;
|
||||
}
|
||||
|
||||
/*--- Decide how many coding tables to use ---*/
|
||||
AssertH(s->nMTF > 0, 3001);
|
||||
// 1..199 = 2
|
||||
// 200..599 = 3
|
||||
// 600..1199 = 4
|
||||
// 1200..2399 = 5
|
||||
// 2400..99999 = 6
|
||||
nGroups = 2;
|
||||
nGroups += (s->nMTF >= 200);
|
||||
nGroups += (s->nMTF >= 600);
|
||||
nGroups += (s->nMTF >= 1200);
|
||||
nGroups += (s->nMTF >= 2400);
|
||||
|
||||
/*--- Generate an initial set of coding tables ---*/
|
||||
{
|
||||
unsigned nPart, remF;
|
||||
|
||||
nPart = nGroups;
|
||||
remF = s->nMTF;
|
||||
gs = 0;
|
||||
while (nPart > 0) {
|
||||
unsigned v;
|
||||
unsigned ge;
|
||||
unsigned tFreq, aFreq;
|
||||
|
||||
tFreq = remF / nPart;
|
||||
ge = gs;
|
||||
aFreq = 0;
|
||||
while (aFreq < tFreq && ge < alphaSize) {
|
||||
aFreq += s->mtfFreq[ge++];
|
||||
}
|
||||
ge--;
|
||||
|
||||
if (ge > gs
|
||||
&& nPart != nGroups && nPart != 1
|
||||
&& ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */
|
||||
) {
|
||||
aFreq -= s->mtfFreq[ge];
|
||||
ge--;
|
||||
}
|
||||
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
if (v >= gs && v <= ge)
|
||||
s->len[nPart-1][v] = BZ_LESSER_ICOST;
|
||||
else
|
||||
s->len[nPart-1][v] = BZ_GREATER_ICOST;
|
||||
|
||||
nPart--;
|
||||
gs = ge + 1;
|
||||
remF -= aFreq;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate up to BZ_N_ITERS times to improve the tables.
|
||||
*/
|
||||
for (iter = 0; iter < BZ_N_ITERS; iter++) {
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
unsigned v;
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->rfreq[t][v] = 0;
|
||||
}
|
||||
|
||||
#if BZIP2_SPEED >= 5
|
||||
/*
|
||||
* Set up an auxiliary length table which is used to fast-track
|
||||
* the common case (nGroups == 6).
|
||||
*/
|
||||
if (nGroups == 6) {
|
||||
unsigned v;
|
||||
for (v = 0; v < alphaSize; v++) {
|
||||
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
|
||||
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
|
||||
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nSelectors = 0;
|
||||
gs = 0;
|
||||
while (1) {
|
||||
unsigned ge;
|
||||
unsigned bt, bc;
|
||||
|
||||
/*--- Set group start & end marks. --*/
|
||||
if (gs >= s->nMTF)
|
||||
break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF)
|
||||
ge = s->nMTF-1;
|
||||
|
||||
/*
|
||||
* Calculate the cost of this group as coded
|
||||
* by each of the coding tables.
|
||||
*/
|
||||
for (t = 0; t < nGroups; t++)
|
||||
cost[t] = 0;
|
||||
#if BZIP2_SPEED >= 5
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
register uint32_t cost01, cost23, cost45;
|
||||
register uint16_t icv;
|
||||
cost01 = cost23 = cost45 = 0;
|
||||
#define BZ_ITER(nn) \
|
||||
icv = mtfv[gs+(nn)]; \
|
||||
cost01 += s->len_pack[icv][0]; \
|
||||
cost23 += s->len_pack[icv][1]; \
|
||||
cost45 += s->len_pack[icv][2];
|
||||
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
|
||||
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
|
||||
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
|
||||
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
|
||||
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
|
||||
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
|
||||
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
|
||||
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
|
||||
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
|
||||
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
|
||||
#undef BZ_ITER
|
||||
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
|
||||
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
|
||||
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
unsigned /*uint16_t*/ icv = mtfv[i];
|
||||
for (t = 0; t < nGroups; t++)
|
||||
cost[t] += s->len[t][icv];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find the coding table which is best for this group,
|
||||
* and record its identity in the selector table.
|
||||
*/
|
||||
/*bc = 999999999;*/
|
||||
/*bt = -1;*/
|
||||
bc = cost[0];
|
||||
bt = 0;
|
||||
for (t = 1 /*0*/; t < nGroups; t++) {
|
||||
if (cost[t] < bc) {
|
||||
bc = cost[t];
|
||||
bt = t;
|
||||
}
|
||||
}
|
||||
s->selector[nSelectors] = bt;
|
||||
nSelectors++;
|
||||
|
||||
/*
|
||||
* Increment the symbol frequencies for the selected table.
|
||||
*/
|
||||
/* 1% faster compress. +800 bytes */
|
||||
#if BZIP2_SPEED >= 4
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++
|
||||
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
|
||||
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
|
||||
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
|
||||
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
|
||||
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
|
||||
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
|
||||
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
|
||||
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
|
||||
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
|
||||
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
|
||||
#undef BZ_ITUR
|
||||
gs = ge + 1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
while (gs <= ge) {
|
||||
s->rfreq[bt][mtfv[gs]]++;
|
||||
gs++;
|
||||
}
|
||||
/* already is: gs = ge + 1; */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recompute the tables based on the accumulated frequencies.
|
||||
*/
|
||||
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
|
||||
* comment in huffman.c for details. */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/);
|
||||
}
|
||||
|
||||
AssertH(nGroups < 8, 3002);
|
||||
AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003);
|
||||
|
||||
/*--- Compute MTF values for the selectors. ---*/
|
||||
{
|
||||
uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
|
||||
|
||||
for (i = 0; i < nGroups; i++)
|
||||
pos[i] = i;
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
unsigned j;
|
||||
ll_i = s->selector[i];
|
||||
j = 0;
|
||||
tmp = pos[j];
|
||||
while (ll_i != tmp) {
|
||||
j++;
|
||||
tmp2 = tmp;
|
||||
tmp = pos[j];
|
||||
pos[j] = tmp2;
|
||||
}
|
||||
pos[0] = tmp;
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Assign actual codes for the tables. --*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
unsigned minLen = 32; //todo: s->len[t][0];
|
||||
unsigned maxLen = 0; //todo: s->len[t][0];
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
AssertH(!(maxLen > 17 /*20*/), 3004);
|
||||
AssertH(!(minLen < 1), 3005);
|
||||
BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize);
|
||||
}
|
||||
|
||||
/*--- Transmit the mapping table. ---*/
|
||||
{
|
||||
/* bbox: optimized a bit more than in bzip2 */
|
||||
int inUse16 = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (sizeof(long) <= 4) {
|
||||
inUse16 = inUse16*2 +
|
||||
((*(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 0])
|
||||
| *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 4])
|
||||
| *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 8])
|
||||
| *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 12])) != 0);
|
||||
} else { /* Our CPU can do better */
|
||||
inUse16 = inUse16*2 +
|
||||
((*(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 0])
|
||||
| *(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 8])) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
bsW16(s, inUse16);
|
||||
|
||||
inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (inUse16 < 0) {
|
||||
unsigned v16 = 0;
|
||||
unsigned j;
|
||||
for (j = 0; j < 16; j++)
|
||||
v16 = v16*2 + s->inUse[i * 16 + j];
|
||||
bsW16(s, v16);
|
||||
}
|
||||
inUse16 <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Now the selectors. ---*/
|
||||
bsW(s, 3, nGroups);
|
||||
bsW(s, 15, nSelectors);
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
unsigned j;
|
||||
for (j = 0; j < s->selectorMtf[i]; j++)
|
||||
bsW1_1(s);
|
||||
bsW1_0(s);
|
||||
}
|
||||
|
||||
/*--- Now the coding tables. ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
unsigned curr = s->len[t][0];
|
||||
bsW(s, 5, curr);
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ }
|
||||
while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ }
|
||||
bsW1_0(s);
|
||||
}
|
||||
}
|
||||
|
||||
/*--- And finally, the block data proper ---*/
|
||||
selCtr = 0;
|
||||
gs = 0;
|
||||
while (1) {
|
||||
unsigned ge;
|
||||
|
||||
if (gs >= s->nMTF)
|
||||
break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF)
|
||||
ge = s->nMTF-1;
|
||||
AssertH(s->selector[selCtr] < nGroups, 3006);
|
||||
|
||||
/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */
|
||||
#if 0
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
uint16_t mtfv_i;
|
||||
uint8_t* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]);
|
||||
int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
|
||||
#define BZ_ITAH(nn) \
|
||||
mtfv_i = mtfv[gs+(nn)]; \
|
||||
bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i])
|
||||
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
|
||||
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
|
||||
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
|
||||
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
|
||||
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
|
||||
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
|
||||
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
|
||||
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
|
||||
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
|
||||
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
|
||||
#undef BZ_ITAH
|
||||
gs = ge+1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
/* code is bit bigger, but moves multiply out of the loop */
|
||||
uint8_t* s_len_sel_selCtr = &(s->len [s->selector[selCtr]][0]);
|
||||
int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]);
|
||||
while (gs <= ge) {
|
||||
bsW(s,
|
||||
s_len_sel_selCtr[mtfv[gs]],
|
||||
s_code_sel_selCtr[mtfv[gs]]
|
||||
);
|
||||
gs++;
|
||||
}
|
||||
/* already is: gs = ge+1; */
|
||||
}
|
||||
selCtr++;
|
||||
}
|
||||
AssertH(selCtr == nSelectors, 3007);
|
||||
#undef code
|
||||
#undef rfreq
|
||||
#undef len_pack
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_compressBlock(EState* s, int is_last_block)
|
||||
{
|
||||
int32_t origPtr = origPtr;
|
||||
|
||||
if (s->nblock > 0) {
|
||||
BZ_FINALISE_CRC(s->blockCRC);
|
||||
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
|
||||
s->combinedCRC ^= s->blockCRC;
|
||||
if (s->blockNo > 1)
|
||||
s->posZ = s->zbits; // was: s->numZ = 0;
|
||||
|
||||
origPtr = BZ2_blockSort(s);
|
||||
}
|
||||
|
||||
s->zbits = &((uint8_t*)s->arr2)[s->nblock];
|
||||
s->posZ = s->zbits;
|
||||
s->state_out_pos = s->zbits;
|
||||
|
||||
/*-- If this is the first block, create the stream header. --*/
|
||||
if (s->blockNo == 1) {
|
||||
BZ2_bsInitWrite(s);
|
||||
/*bsPutU8(s, BZ_HDR_B);*/
|
||||
/*bsPutU8(s, BZ_HDR_Z);*/
|
||||
/*bsPutU8(s, BZ_HDR_h);*/
|
||||
/*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/
|
||||
bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k);
|
||||
}
|
||||
|
||||
if (s->nblock > 0) {
|
||||
/*bsPutU8(s, 0x31);*/
|
||||
/*bsPutU8(s, 0x41);*/
|
||||
/*bsPutU8(s, 0x59);*/
|
||||
/*bsPutU8(s, 0x26);*/
|
||||
bsPutU32(s, 0x31415926);
|
||||
/*bsPutU8(s, 0x53);*/
|
||||
/*bsPutU8(s, 0x59);*/
|
||||
bsPutU16(s, 0x5359);
|
||||
|
||||
/*-- Now the block's CRC, so it is in a known place. --*/
|
||||
bsPutU32(s, s->blockCRC);
|
||||
|
||||
/*
|
||||
* Now a single bit indicating (non-)randomisation.
|
||||
* As of version 0.9.5, we use a better sorting algorithm
|
||||
* which makes randomisation unnecessary. So always set
|
||||
* the randomised bit to 'no'. Of course, the decoder
|
||||
* still needs to be able to handle randomised blocks
|
||||
* so as to maintain backwards compatibility with
|
||||
* older versions of bzip2.
|
||||
*/
|
||||
bsW1_0(s);
|
||||
|
||||
bsW(s, 24, origPtr);
|
||||
generateMTFValues(s);
|
||||
sendMTFValues(s);
|
||||
}
|
||||
|
||||
/*-- If this is the last block, add the stream trailer. --*/
|
||||
if (is_last_block) {
|
||||
/*bsPutU8(s, 0x17);*/
|
||||
/*bsPutU8(s, 0x72);*/
|
||||
/*bsPutU8(s, 0x45);*/
|
||||
/*bsPutU8(s, 0x38);*/
|
||||
bsPutU32(s, 0x17724538);
|
||||
/*bsPutU8(s, 0x50);*/
|
||||
/*bsPutU8(s, 0x90);*/
|
||||
bsPutU16(s, 0x5090);
|
||||
bsPutU32(s, s->combinedCRC);
|
||||
bsFinishWrite(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
229
busybox-1_37_0/archival/libarchive/bz/huffman.c
Normal file
229
busybox-1_37_0/archival/libarchive/bz/huffman.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* bzip2 is written by Julian Seward <jseward@bzip.org>.
|
||||
* Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
||||
* See README and LICENSE files in this directory for more information.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Huffman coding low-level stuff ---*/
|
||||
/*--- huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
||||
Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
/* #include "bzlib_private.h" */
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
|
||||
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
|
||||
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
|
||||
|
||||
#define ADDWEIGHTS(zw1,zw2) \
|
||||
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
|
||||
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
|
||||
|
||||
#define UPHEAP(z) \
|
||||
{ \
|
||||
int32_t zz, tmp; \
|
||||
zz = z; \
|
||||
tmp = heap[zz]; \
|
||||
while (weight[tmp] < weight[heap[zz >> 1]]) { \
|
||||
heap[zz] = heap[zz >> 1]; \
|
||||
zz >>= 1; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
|
||||
/* 90 bytes, 0.3% of overall compress speed */
|
||||
#if BZIP2_SPEED >= 1
|
||||
|
||||
/* macro works better than inline (gcc 4.2.1) */
|
||||
#define DOWNHEAP1(heap, weight, Heap) \
|
||||
{ \
|
||||
int32_t zz, yy, tmp; \
|
||||
zz = 1; \
|
||||
tmp = heap[zz]; \
|
||||
while (1) { \
|
||||
yy = zz << 1; \
|
||||
if (yy > nHeap) \
|
||||
break; \
|
||||
if (yy < nHeap \
|
||||
&& weight[heap[yy+1]] < weight[heap[yy]]) \
|
||||
yy++; \
|
||||
if (weight[tmp] < weight[heap[yy]]) \
|
||||
break; \
|
||||
heap[zz] = heap[yy]; \
|
||||
zz = yy; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static
|
||||
void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap)
|
||||
{
|
||||
int32_t zz, yy, tmp;
|
||||
zz = 1;
|
||||
tmp = heap[zz];
|
||||
while (1) {
|
||||
yy = zz << 1;
|
||||
if (yy > nHeap)
|
||||
break;
|
||||
if (yy < nHeap
|
||||
&& weight[heap[yy + 1]] < weight[heap[yy]])
|
||||
yy++;
|
||||
if (weight[tmp] < weight[heap[yy]])
|
||||
break;
|
||||
heap[zz] = heap[yy];
|
||||
zz = yy;
|
||||
}
|
||||
heap[zz] = tmp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_hbMakeCodeLengths(EState *s,
|
||||
uint8_t *len,
|
||||
int32_t *freq,
|
||||
int32_t alphaSize,
|
||||
int32_t maxLen)
|
||||
{
|
||||
/*
|
||||
* Nodes and heap entries run from 1. Entry 0
|
||||
* for both the heap and nodes is a sentinel.
|
||||
*/
|
||||
int32_t nNodes, nHeap, n1, n2, i, j, k;
|
||||
Bool tooLong;
|
||||
|
||||
/* bbox: moved to EState to save stack
|
||||
int32_t heap [BZ_MAX_ALPHA_SIZE + 2];
|
||||
int32_t weight[BZ_MAX_ALPHA_SIZE * 2];
|
||||
int32_t parent[BZ_MAX_ALPHA_SIZE * 2];
|
||||
*/
|
||||
#define heap (s->BZ2_hbMakeCodeLengths__heap)
|
||||
#define weight (s->BZ2_hbMakeCodeLengths__weight)
|
||||
#define parent (s->BZ2_hbMakeCodeLengths__parent)
|
||||
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
|
||||
|
||||
while (1) {
|
||||
nNodes = alphaSize;
|
||||
nHeap = 0;
|
||||
|
||||
heap[0] = 0;
|
||||
weight[0] = 0;
|
||||
parent[0] = -2;
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
parent[i] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = i;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001);
|
||||
|
||||
while (nHeap > 1) {
|
||||
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
|
||||
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap);
|
||||
nNodes++;
|
||||
parent[n1] = parent[n2] = nNodes;
|
||||
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
|
||||
parent[nNodes] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = nNodes;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002);
|
||||
|
||||
tooLong = False;
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = 0;
|
||||
k = i;
|
||||
while (parent[k] >= 0) {
|
||||
k = parent[k];
|
||||
j++;
|
||||
}
|
||||
len[i-1] = j;
|
||||
if (j > maxLen)
|
||||
tooLong = True;
|
||||
}
|
||||
|
||||
if (!tooLong)
|
||||
break;
|
||||
|
||||
/* 17 Oct 04: keep-going condition for the following loop used
|
||||
to be 'i < alphaSize', which missed the last element,
|
||||
theoretically leading to the possibility of the compressor
|
||||
looping. However, this count-scaling step is only needed if
|
||||
one of the generated Huffman code words is longer than
|
||||
maxLen, which up to and including version 1.0.2 was 20 bits,
|
||||
which is extremely unlikely. In version 1.0.3 maxLen was
|
||||
changed to 17 bits, which has minimal effect on compression
|
||||
ratio, but does mean this scaling step is used from time to
|
||||
time, enough to verify that it works.
|
||||
|
||||
This means that bzip2-1.0.3 and later will only produce
|
||||
Huffman codes with a maximum length of 17 bits. However, in
|
||||
order to preserve backwards compatibility with bitstreams
|
||||
produced by versions pre-1.0.3, the decompressor must still
|
||||
handle lengths of up to 20. */
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = weight[i] >> 8;
|
||||
/* bbox: yes, it is a signed division.
|
||||
* don't replace with shift! */
|
||||
j = 1 + (j / 2);
|
||||
weight[i] = j << 8;
|
||||
}
|
||||
}
|
||||
#undef heap
|
||||
#undef weight
|
||||
#undef parent
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void BZ2_hbAssignCodes(int32_t *code,
|
||||
uint8_t *length,
|
||||
int32_t minLen,
|
||||
int32_t maxLen,
|
||||
int32_t alphaSize)
|
||||
{
|
||||
int32_t n, vec, i;
|
||||
|
||||
vec = 0;
|
||||
for (n = minLen; n <= maxLen; n++) {
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (length[i] == n) {
|
||||
code[i] = vec;
|
||||
vec++;
|
||||
}
|
||||
}
|
||||
vec <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
8
busybox-1_37_0/archival/libarchive/common.c
Normal file
8
busybox-1_37_0/archival/libarchive/common.c
Normal file
@ -0,0 +1,8 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
const char cpio_TRAILER[] ALIGN1 = "TRAILER!!!";
|
14
busybox-1_37_0/archival/libarchive/data_align.c
Normal file
14
busybox-1_37_0/archival/libarchive/data_align.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary)
|
||||
{
|
||||
unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary;
|
||||
|
||||
archive_handle->seek(archive_handle->src_fd, skip_amount);
|
||||
archive_handle->offset += skip_amount;
|
||||
}
|
259
busybox-1_37_0/archival/libarchive/data_extract_all.c
Normal file
259
busybox-1_37_0/archival/libarchive/data_extract_all.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
|
||||
{
|
||||
file_header_t *file_header = archive_handle->file_header;
|
||||
int dst_fd;
|
||||
int res;
|
||||
char *hard_link;
|
||||
#if ENABLE_FEATURE_TAR_LONG_OPTIONS
|
||||
char *dst_name;
|
||||
#else
|
||||
# define dst_name (file_header->name)
|
||||
#endif
|
||||
|
||||
#if ENABLE_FEATURE_TAR_SELINUX
|
||||
char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
|
||||
if (!sctx)
|
||||
sctx = archive_handle->tar__sctx[PAX_GLOBAL];
|
||||
if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
|
||||
setfscreatecon(sctx);
|
||||
free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
|
||||
archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Hard links are encoded as regular files of size 0
|
||||
* with a nonempty link field */
|
||||
hard_link = NULL;
|
||||
if (S_ISREG(file_header->mode) && file_header->size == 0)
|
||||
hard_link = file_header->link_target;
|
||||
|
||||
#if ENABLE_FEATURE_TAR_LONG_OPTIONS
|
||||
dst_name = file_header->name;
|
||||
if (archive_handle->tar__strip_components) {
|
||||
unsigned n = archive_handle->tar__strip_components;
|
||||
do {
|
||||
dst_name = strchr(dst_name, '/');
|
||||
if (!dst_name || dst_name[1] == '\0') {
|
||||
data_skip(archive_handle);
|
||||
goto ret;
|
||||
}
|
||||
dst_name++;
|
||||
/*
|
||||
* Link target is shortened only for hardlinks:
|
||||
* softlinks restored unchanged.
|
||||
*/
|
||||
if (hard_link) {
|
||||
// GNU tar 1.26 does not check that we reached end of link name:
|
||||
// if "dir/hardlink" is hardlinked to "file",
|
||||
// tar xvf a.tar --strip-components=1 says:
|
||||
// tar: hardlink: Cannot hard link to '': No such file or directory
|
||||
// and continues processing. We silently skip such entries.
|
||||
hard_link = strchr(hard_link, '/');
|
||||
if (!hard_link || hard_link[1] == '\0') {
|
||||
data_skip(archive_handle);
|
||||
goto ret;
|
||||
}
|
||||
hard_link++;
|
||||
}
|
||||
} while (--n != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
|
||||
char *slash = strrchr(dst_name, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
bb_make_directory(dst_name, -1, FILEUTILS_RECUR);
|
||||
*slash = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
|
||||
/* Remove the entry if it exists */
|
||||
if (!S_ISDIR(file_header->mode)) {
|
||||
if (hard_link) {
|
||||
/* Ugly special case:
|
||||
* tar cf t.tar hardlink1 hardlink2 hardlink1
|
||||
* results in this tarball structure:
|
||||
* hardlink1
|
||||
* hardlink2 -> hardlink1
|
||||
* hardlink1 -> hardlink1 <== !!!
|
||||
*/
|
||||
if (strcmp(hard_link, dst_name) == 0)
|
||||
goto ret;
|
||||
}
|
||||
/* Proceed with deleting */
|
||||
if (unlink(dst_name) == -1
|
||||
&& errno != ENOENT
|
||||
) {
|
||||
bb_perror_msg_and_die("can't remove old file %s",
|
||||
dst_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
|
||||
/* Remove the existing entry if its older than the extracted entry */
|
||||
struct stat existing_sb;
|
||||
if (lstat(dst_name, &existing_sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
bb_simple_perror_msg_and_die("can't stat old file");
|
||||
}
|
||||
}
|
||||
else if (existing_sb.st_mtime >= file_header->mtime) {
|
||||
if (!S_ISDIR(file_header->mode)) {
|
||||
bb_error_msg("%s not created: newer or "
|
||||
"same age file exists", dst_name);
|
||||
}
|
||||
data_skip(archive_handle);
|
||||
goto ret;
|
||||
}
|
||||
else if ((unlink(dst_name) == -1) && (errno != EISDIR)) {
|
||||
bb_perror_msg_and_die("can't remove old file %s",
|
||||
dst_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle hard links separately */
|
||||
if (hard_link) {
|
||||
create_or_remember_link(&archive_handle->link_placeholders,
|
||||
hard_link,
|
||||
dst_name,
|
||||
1);
|
||||
/* Hardlinks have no separate mode/ownership, skip chown/chmod */
|
||||
goto ret;
|
||||
}
|
||||
|
||||
/* Create the filesystem entry */
|
||||
switch (file_header->mode & S_IFMT) {
|
||||
case S_IFREG: {
|
||||
/* Regular file */
|
||||
char *dst_nameN;
|
||||
int flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||
if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
dst_nameN = dst_name;
|
||||
#ifdef ARCHIVE_REPLACE_VIA_RENAME
|
||||
if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME)
|
||||
/* rpm-style temp file name */
|
||||
dst_nameN = xasprintf("%s;%x", dst_name, (int)getpid());
|
||||
#endif
|
||||
dst_fd = xopen3(dst_nameN,
|
||||
flags,
|
||||
file_header->mode
|
||||
);
|
||||
bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
|
||||
close(dst_fd);
|
||||
#ifdef ARCHIVE_REPLACE_VIA_RENAME
|
||||
if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) {
|
||||
xrename(dst_nameN, dst_name);
|
||||
free(dst_nameN);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case S_IFDIR:
|
||||
//TODO: this causes problems if tarball contains a r-xr-xr-x directory:
|
||||
// we create this directory, and then fail to create files inside it
|
||||
// (if tar xf isn't run as root).
|
||||
// GNU tar works around this by chmod-ing directories *after* all files are extracted.
|
||||
res = mkdir(dst_name, file_header->mode);
|
||||
if ((res != 0)
|
||||
&& (errno != EISDIR) /* btw, Linux doesn't return this */
|
||||
&& (errno != EEXIST)
|
||||
) {
|
||||
bb_perror_msg("can't make dir %s", dst_name);
|
||||
}
|
||||
break;
|
||||
case S_IFLNK:
|
||||
/* Symlink */
|
||||
//TODO: what if file_header->link_target == NULL (say, corrupted tarball?)
|
||||
|
||||
/* To avoid a directory traversal attack via symlinks,
|
||||
* do not restore symlinks with ".." components
|
||||
* or symlinks starting with "/", unless a magic
|
||||
* envvar is set.
|
||||
*
|
||||
* For example, consider a .tar created via:
|
||||
* $ tar cvf bug.tar anything.txt
|
||||
* $ ln -s /tmp symlink
|
||||
* $ tar --append -f bug.tar symlink
|
||||
* $ rm symlink
|
||||
* $ mkdir symlink
|
||||
* $ tar --append -f bug.tar symlink/evil.py
|
||||
*
|
||||
* This will result in an archive that contains:
|
||||
* $ tar --list -f bug.tar
|
||||
* anything.txt
|
||||
* symlink [-> /tmp]
|
||||
* symlink/evil.py
|
||||
*
|
||||
* Untarring bug.tar would otherwise place evil.py in '/tmp'.
|
||||
*/
|
||||
create_or_remember_link(&archive_handle->link_placeholders,
|
||||
file_header->link_target,
|
||||
dst_name,
|
||||
0);
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
case S_IFIFO:
|
||||
res = mknod(dst_name, file_header->mode, file_header->device);
|
||||
if (res != 0) {
|
||||
bb_perror_msg("can't create node %s", dst_name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bb_simple_error_msg_and_die("unrecognized file type");
|
||||
}
|
||||
|
||||
if (!S_ISLNK(file_header->mode)) {
|
||||
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) {
|
||||
uid_t uid = file_header->uid;
|
||||
gid_t gid = file_header->gid;
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) {
|
||||
if (file_header->tar__uname) {
|
||||
//TODO: cache last name/id pair?
|
||||
struct passwd *pwd = getpwnam(file_header->tar__uname);
|
||||
if (pwd) uid = pwd->pw_uid;
|
||||
}
|
||||
if (file_header->tar__gname) {
|
||||
struct group *grp = getgrnam(file_header->tar__gname);
|
||||
if (grp) gid = grp->gr_gid;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* GNU tar 1.15.1 uses chown, not lchown */
|
||||
chown(dst_name, uid, gid);
|
||||
}
|
||||
/* uclibc has no lchmod, glibc is even stranger -
|
||||
* it has lchmod which seems to do nothing!
|
||||
* so we use chmod... */
|
||||
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) {
|
||||
chmod(dst_name, file_header->mode);
|
||||
}
|
||||
if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) {
|
||||
struct timeval t[2];
|
||||
|
||||
t[1].tv_sec = t[0].tv_sec = file_header->mtime;
|
||||
t[1].tv_usec = t[0].tv_usec = 0;
|
||||
utimes(dst_name, t);
|
||||
}
|
||||
}
|
||||
|
||||
ret: ;
|
||||
#if ENABLE_FEATURE_TAR_SELINUX
|
||||
if (sctx) {
|
||||
/* reset the context after creating an entry */
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
136
busybox-1_37_0/archival/libarchive/data_extract_to_command.c
Normal file
136
busybox-1_37_0/archival/libarchive/data_extract_to_command.c
Normal file
@ -0,0 +1,136 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
enum {
|
||||
//TAR_FILETYPE,
|
||||
TAR_MODE,
|
||||
TAR_FILENAME,
|
||||
TAR_REALNAME,
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
TAR_UNAME,
|
||||
TAR_GNAME,
|
||||
#endif
|
||||
TAR_SIZE,
|
||||
TAR_UID,
|
||||
TAR_GID,
|
||||
TAR_MAX,
|
||||
};
|
||||
|
||||
static const char *const tar_var[] ALIGN_PTR = {
|
||||
// "FILETYPE",
|
||||
"MODE",
|
||||
"FILENAME",
|
||||
"REALNAME",
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
"UNAME",
|
||||
"GNAME",
|
||||
#endif
|
||||
"SIZE",
|
||||
"UID",
|
||||
"GID",
|
||||
};
|
||||
|
||||
static void xputenv(char *str)
|
||||
{
|
||||
if (putenv(str))
|
||||
bb_die_memory_exhausted();
|
||||
}
|
||||
|
||||
static void str2env(char *env[], int idx, const char *str)
|
||||
{
|
||||
env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str);
|
||||
xputenv(env[idx]);
|
||||
}
|
||||
|
||||
static void dec2env(char *env[], int idx, unsigned long long val)
|
||||
{
|
||||
env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val);
|
||||
xputenv(env[idx]);
|
||||
}
|
||||
|
||||
static void oct2env(char *env[], int idx, unsigned long val)
|
||||
{
|
||||
env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val);
|
||||
xputenv(env[idx]);
|
||||
}
|
||||
|
||||
void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
|
||||
{
|
||||
file_header_t *file_header = archive_handle->file_header;
|
||||
|
||||
#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
|
||||
char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
|
||||
if (!sctx)
|
||||
sctx = archive_handle->tar__sctx[PAX_GLOBAL];
|
||||
if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
|
||||
setfscreatecon(sctx);
|
||||
free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
|
||||
archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((file_header->mode & S_IFMT) == S_IFREG) {
|
||||
pid_t pid;
|
||||
int p[2], status;
|
||||
char *tar_env[TAR_MAX];
|
||||
|
||||
memset(tar_env, 0, sizeof(tar_env));
|
||||
|
||||
xpipe(p);
|
||||
pid = BB_MMU ? xfork() : xvfork();
|
||||
if (pid == 0) {
|
||||
/* Child */
|
||||
/* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */
|
||||
oct2env(tar_env, TAR_MODE, file_header->mode);
|
||||
str2env(tar_env, TAR_FILENAME, file_header->name);
|
||||
str2env(tar_env, TAR_REALNAME, file_header->name);
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
str2env(tar_env, TAR_UNAME, file_header->tar__uname);
|
||||
str2env(tar_env, TAR_GNAME, file_header->tar__gname);
|
||||
#endif
|
||||
dec2env(tar_env, TAR_SIZE, file_header->size);
|
||||
dec2env(tar_env, TAR_UID, file_header->uid);
|
||||
dec2env(tar_env, TAR_GID, file_header->gid);
|
||||
close(p[1]);
|
||||
xdup2(p[0], STDIN_FILENO);
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
execl(archive_handle->tar__to_command_shell,
|
||||
archive_handle->tar__to_command_shell,
|
||||
"-c",
|
||||
archive_handle->tar__to_command,
|
||||
(char *)0);
|
||||
bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
|
||||
}
|
||||
close(p[0]);
|
||||
/* Our caller is expected to do signal(SIGPIPE, SIG_IGN)
|
||||
* so that we don't die if child don't read all the input: */
|
||||
bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size);
|
||||
close(p[1]);
|
||||
|
||||
status = wait_for_exitstatus(pid);
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status))
|
||||
bb_error_msg_and_die("'%s' returned status %d",
|
||||
archive_handle->tar__to_command, WEXITSTATUS(status));
|
||||
if (WIFSIGNALED(status))
|
||||
bb_error_msg_and_die("'%s' terminated by signal %d",
|
||||
archive_handle->tar__to_command, WTERMSIG(status));
|
||||
|
||||
if (!BB_MMU) {
|
||||
int i;
|
||||
for (i = 0; i < TAR_MAX; i++) {
|
||||
if (tar_env[i])
|
||||
bb_unsetenv_and_free(tar_env[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* ENABLE_FEATURE_TAR_SELINUX */
|
||||
if (sctx)
|
||||
/* reset the context after creating an entry */
|
||||
setfscreatecon(NULL);
|
||||
#endif
|
||||
}
|
13
busybox-1_37_0/archival/libarchive/data_extract_to_stdout.c
Normal file
13
busybox-1_37_0/archival/libarchive/data_extract_to_stdout.c
Normal file
@ -0,0 +1,13 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
|
||||
{
|
||||
bb_copyfd_exact_size(archive_handle->src_fd,
|
||||
STDOUT_FILENO,
|
||||
archive_handle->file_header->size);
|
||||
}
|
11
busybox-1_37_0/archival/libarchive/data_skip.c
Normal file
11
busybox-1_37_0/archival/libarchive/data_skip.c
Normal file
@ -0,0 +1,11 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC data_skip(archive_handle_t *archive_handle)
|
||||
{
|
||||
archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size);
|
||||
}
|
900
busybox-1_37_0/archival/libarchive/decompress_bunzip2.c
Normal file
900
busybox-1_37_0/archival/libarchive/decompress_bunzip2.c
Normal file
@ -0,0 +1,900 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
|
||||
*
|
||||
* Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
|
||||
* which also acknowledges contributions by Mike Burrows, David Wheeler,
|
||||
* Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
|
||||
* Robert Sedgewick, and Jon L. Bentley.
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
/*
|
||||
Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org).
|
||||
|
||||
More efficient reading of Huffman codes, a streamlined read_bunzip()
|
||||
function, and various other tweaks. In (limited) tests, approximately
|
||||
20% faster than bzcat on x86 and about 10% faster on arm.
|
||||
|
||||
Note that about 2/3 of the time is spent in read_bunzip() reversing
|
||||
the Burrows-Wheeler transformation. Much of that time is delay
|
||||
resulting from cache misses.
|
||||
|
||||
(2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null"
|
||||
on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip:
|
||||
%time seconds calls function
|
||||
71.01 12.69 444 get_next_block
|
||||
28.65 5.12 93065 read_bunzip
|
||||
00.22 0.04 7736490 get_bits
|
||||
00.11 0.02 47 dealloc_bunzip
|
||||
00.00 0.00 93018 full_write
|
||||
...)
|
||||
|
||||
|
||||
I would ask that anyone benefiting from this work, especially those
|
||||
using it in commercial products, consider making a donation to my local
|
||||
non-profit hospice organization (www.hospiceacadiana.com) in the name of
|
||||
the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
|
||||
|
||||
Manuel
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#if 0
|
||||
# define dbg(...) bb_error_msg(__VA_ARGS__)
|
||||
#else
|
||||
# define dbg(...) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Constants for Huffman coding */
|
||||
#define MAX_GROUPS 6
|
||||
#define GROUP_SIZE 50 /* 64 would have been more efficient */
|
||||
#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */
|
||||
#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
|
||||
#define SYMBOL_RUNA 0
|
||||
#define SYMBOL_RUNB 1
|
||||
|
||||
/* Status return values */
|
||||
#define RETVAL_OK 0
|
||||
#define RETVAL_LAST_BLOCK (dbg("%d", __LINE__), -1)
|
||||
#define RETVAL_NOT_BZIP_DATA (dbg("%d", __LINE__), -2)
|
||||
#define RETVAL_UNEXPECTED_INPUT_EOF (dbg("%d", __LINE__), -3)
|
||||
#define RETVAL_SHORT_WRITE (dbg("%d", __LINE__), -4)
|
||||
#define RETVAL_DATA_ERROR (dbg("%d", __LINE__), -5)
|
||||
#define RETVAL_OUT_OF_MEMORY (dbg("%d", __LINE__), -6)
|
||||
#define RETVAL_OBSOLETE_INPUT (dbg("%d", __LINE__), -7)
|
||||
|
||||
/* Other housekeeping constants */
|
||||
#define IOBUF_SIZE 4096
|
||||
|
||||
/* This is what we know about each Huffman coding group */
|
||||
struct group_data {
|
||||
/* We have an extra slot at the end of limit[] for a sentinel value. */
|
||||
int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
|
||||
int minLen, maxLen;
|
||||
};
|
||||
|
||||
/* Structure holding all the housekeeping data, including IO buffers and
|
||||
* memory that persists between calls to bunzip
|
||||
* Found the most used member:
|
||||
* cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \
|
||||
* | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER
|
||||
* and moved it (inbufBitCount) to offset 0.
|
||||
*/
|
||||
struct bunzip_data {
|
||||
/* I/O tracking data (file handles, buffers, positions, etc.) */
|
||||
unsigned inbufBitCount, inbufBits;
|
||||
int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
|
||||
uint8_t *inbuf /*,*outbuf*/;
|
||||
|
||||
/* State for interrupting output loop */
|
||||
int writeCopies, writePos, writeRunCountdown, writeCount;
|
||||
int writeCurrent; /* actually a uint8_t */
|
||||
|
||||
/* The CRC values stored in the block header and calculated from the data */
|
||||
uint32_t headerCRC, totalCRC, writeCRC;
|
||||
|
||||
/* Intermediate buffer and its size (in bytes) */
|
||||
uint32_t *dbuf;
|
||||
unsigned dbufSize;
|
||||
|
||||
/* For I/O error handling */
|
||||
jmp_buf *jmpbuf;
|
||||
|
||||
/* Big things go last (register-relative addressing can be larger for big offsets) */
|
||||
uint32_t crc32Table[256];
|
||||
uint8_t selectors[32768]; /* nSelectors=15 bits */
|
||||
struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */
|
||||
};
|
||||
typedef struct bunzip_data bunzip_data;
|
||||
|
||||
|
||||
/* Return the next nnn bits of input. All reads from the compressed input
|
||||
are done through this function. All reads are big endian */
|
||||
static unsigned get_bits(bunzip_data *bd, int bits_wanted)
|
||||
{
|
||||
unsigned bits = 0;
|
||||
/* Cache bd->inbufBitCount in a CPU register (hopefully): */
|
||||
int bit_count = bd->inbufBitCount;
|
||||
|
||||
/* If we need to get more data from the byte buffer, do so. (Loop getting
|
||||
one byte at a time to enforce endianness and avoid unaligned access.) */
|
||||
while (bit_count < bits_wanted) {
|
||||
|
||||
/* If we need to read more data from file into byte buffer, do so */
|
||||
if (bd->inbufPos == bd->inbufCount) {
|
||||
/* if "no input fd" case: in_fd == -1, read fails, we jump */
|
||||
bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
|
||||
if (bd->inbufCount <= 0)
|
||||
longjmp(*bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
|
||||
bd->inbufPos = 0;
|
||||
}
|
||||
|
||||
/* Avoid 32-bit overflow (dump bit buffer to top of output) */
|
||||
if (bit_count >= 24) {
|
||||
bits = bd->inbufBits & ((1U << bit_count) - 1);
|
||||
bits_wanted -= bit_count;
|
||||
bits <<= bits_wanted;
|
||||
bit_count = 0;
|
||||
}
|
||||
|
||||
/* Grab next 8 bits of input from buffer. */
|
||||
bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
|
||||
bit_count += 8;
|
||||
}
|
||||
|
||||
/* Calculate result */
|
||||
bit_count -= bits_wanted;
|
||||
bd->inbufBitCount = bit_count;
|
||||
bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1);
|
||||
|
||||
return bits;
|
||||
}
|
||||
//#define get_bits(bd, n) (dbg("%d:get_bits()", __LINE__), get_bits(bd, n))
|
||||
|
||||
/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */
|
||||
static int get_next_block(bunzip_data *bd)
|
||||
{
|
||||
int groupCount, selector,
|
||||
i, j, symCount, symTotal, nSelectors, byteCount[256];
|
||||
uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
|
||||
uint32_t *dbuf;
|
||||
unsigned origPtr, t;
|
||||
unsigned dbufCount, runPos;
|
||||
unsigned runCnt = runCnt; /* for compiler */
|
||||
|
||||
dbuf = bd->dbuf;
|
||||
selectors = bd->selectors;
|
||||
|
||||
/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */
|
||||
#if 0
|
||||
/* Reset longjmp I/O error handling */
|
||||
i = setjmp(bd->jmpbuf);
|
||||
if (i) return i;
|
||||
#endif
|
||||
|
||||
/* Read in header signature and CRC, then validate signature.
|
||||
(last block signature means CRC is for whole file, return now) */
|
||||
i = get_bits(bd, 24);
|
||||
j = get_bits(bd, 24);
|
||||
bd->headerCRC = get_bits(bd, 32);
|
||||
if ((i == 0x177245) && (j == 0x385090))
|
||||
return RETVAL_LAST_BLOCK;
|
||||
if ((i != 0x314159) || (j != 0x265359))
|
||||
return RETVAL_NOT_BZIP_DATA;
|
||||
|
||||
/* We can add support for blockRandomised if anybody complains. There was
|
||||
some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
|
||||
it didn't actually work. */
|
||||
if (get_bits(bd, 1))
|
||||
return RETVAL_OBSOLETE_INPUT;
|
||||
origPtr = get_bits(bd, 24);
|
||||
if (origPtr > bd->dbufSize)
|
||||
return RETVAL_DATA_ERROR;
|
||||
|
||||
/* mapping table: if some byte values are never used (encoding things
|
||||
like ascii text), the compression code removes the gaps to have fewer
|
||||
symbols to deal with, and writes a sparse bitfield indicating which
|
||||
values were present. We make a translation table to convert the symbols
|
||||
back to the corresponding bytes. */
|
||||
symTotal = 0;
|
||||
i = 0;
|
||||
t = get_bits(bd, 16);
|
||||
do {
|
||||
if (t & (1 << 15)) {
|
||||
unsigned inner_map = get_bits(bd, 16);
|
||||
do {
|
||||
if (inner_map & (1 << 15))
|
||||
symToByte[symTotal++] = i;
|
||||
inner_map <<= 1;
|
||||
i++;
|
||||
} while (i & 15);
|
||||
i -= 16;
|
||||
}
|
||||
t <<= 1;
|
||||
i += 16;
|
||||
} while (i < 256);
|
||||
|
||||
/* How many different Huffman coding groups does this block use? */
|
||||
groupCount = get_bits(bd, 3);
|
||||
if (groupCount < 2 || groupCount > MAX_GROUPS)
|
||||
return RETVAL_DATA_ERROR;
|
||||
|
||||
/* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding
|
||||
group. Read in the group selector list, which is stored as MTF encoded
|
||||
bit runs. (MTF=Move To Front, as each value is used it's moved to the
|
||||
start of the list.) */
|
||||
for (i = 0; i < groupCount; i++)
|
||||
mtfSymbol[i] = i;
|
||||
nSelectors = get_bits(bd, 15);
|
||||
if (!nSelectors)
|
||||
return RETVAL_DATA_ERROR;
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
uint8_t tmp_byte;
|
||||
/* Get next value */
|
||||
int n = 0;
|
||||
while (get_bits(bd, 1)) {
|
||||
n++;
|
||||
if (n >= groupCount)
|
||||
return RETVAL_DATA_ERROR;
|
||||
}
|
||||
/* Decode MTF to get the next selector */
|
||||
tmp_byte = mtfSymbol[n];
|
||||
while (--n >= 0)
|
||||
mtfSymbol[n + 1] = mtfSymbol[n];
|
||||
//We catch it later, in the second loop where we use selectors[i].
|
||||
//Maybe this is a better place, though?
|
||||
// if (tmp_byte >= groupCount) {
|
||||
// dbg("%d: selectors[%d]:%d groupCount:%d",
|
||||
// __LINE__, i, tmp_byte, groupCount);
|
||||
// return RETVAL_DATA_ERROR;
|
||||
// }
|
||||
mtfSymbol[0] = selectors[i] = tmp_byte;
|
||||
}
|
||||
|
||||
/* Read the Huffman coding tables for each group, which code for symTotal
|
||||
literal symbols, plus two run symbols (RUNA, RUNB) */
|
||||
symCount = symTotal + 2;
|
||||
for (j = 0; j < groupCount; j++) {
|
||||
uint8_t length[MAX_SYMBOLS];
|
||||
/* 8 bits is ALMOST enough for temp[], see below */
|
||||
unsigned temp[MAX_HUFCODE_BITS+1];
|
||||
struct group_data *hufGroup;
|
||||
int *base, *limit;
|
||||
int minLen, maxLen, pp, len_m1;
|
||||
|
||||
/* Read Huffman code lengths for each symbol. They're stored in
|
||||
a way similar to mtf; record a starting value for the first symbol,
|
||||
and an offset from the previous value for every symbol after that.
|
||||
(Subtracting 1 before the loop and then adding it back at the end is
|
||||
an optimization that makes the test inside the loop simpler: symbol
|
||||
length 0 becomes negative, so an unsigned inequality catches it.) */
|
||||
len_m1 = get_bits(bd, 5) - 1;
|
||||
for (i = 0; i < symCount; i++) {
|
||||
for (;;) {
|
||||
int two_bits;
|
||||
if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1))
|
||||
return RETVAL_DATA_ERROR;
|
||||
|
||||
/* If first bit is 0, stop. Else second bit indicates whether
|
||||
to increment or decrement the value. Optimization: grab 2
|
||||
bits and unget the second if the first was 0. */
|
||||
two_bits = get_bits(bd, 2);
|
||||
if (two_bits < 2) {
|
||||
bd->inbufBitCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add one if second bit 1, else subtract 1. Avoids if/else */
|
||||
len_m1 += (((two_bits+1) & 2) - 1);
|
||||
}
|
||||
|
||||
/* Correct for the initial -1, to get the final symbol length */
|
||||
length[i] = len_m1 + 1;
|
||||
}
|
||||
|
||||
/* Find largest and smallest lengths in this group */
|
||||
minLen = maxLen = length[0];
|
||||
for (i = 1; i < symCount; i++) {
|
||||
if (length[i] > maxLen)
|
||||
maxLen = length[i];
|
||||
else if (length[i] < minLen)
|
||||
minLen = length[i];
|
||||
}
|
||||
|
||||
/* Calculate permute[], base[], and limit[] tables from length[].
|
||||
*
|
||||
* permute[] is the lookup table for converting Huffman coded symbols
|
||||
* into decoded symbols. base[] is the amount to subtract from the
|
||||
* value of a Huffman symbol of a given length when using permute[].
|
||||
*
|
||||
* limit[] indicates the largest numerical value a symbol with a given
|
||||
* number of bits can have. This is how the Huffman codes can vary in
|
||||
* length: each code with a value>limit[length] needs another bit.
|
||||
*/
|
||||
hufGroup = bd->groups + j;
|
||||
hufGroup->minLen = minLen;
|
||||
hufGroup->maxLen = maxLen;
|
||||
|
||||
/* Note that minLen can't be smaller than 1, so we adjust the base
|
||||
and limit array pointers so we're not always wasting the first
|
||||
entry. We do this again when using them (during symbol decoding). */
|
||||
base = hufGroup->base - 1;
|
||||
limit = hufGroup->limit - 1;
|
||||
|
||||
/* Calculate permute[]. Concurrently, initialize temp[] and limit[]. */
|
||||
pp = 0;
|
||||
for (i = minLen; i <= maxLen; i++) {
|
||||
int k;
|
||||
temp[i] = limit[i] = 0;
|
||||
for (k = 0; k < symCount; k++)
|
||||
if (length[k] == i)
|
||||
hufGroup->permute[pp++] = k;
|
||||
}
|
||||
|
||||
/* Count symbols coded for at each bit length */
|
||||
/* NB: in pathological cases, temp[8] can end ip being 256.
|
||||
* That's why uint8_t is too small for temp[]. */
|
||||
for (i = 0; i < symCount; i++)
|
||||
temp[length[i]]++;
|
||||
|
||||
/* Calculate limit[] (the largest symbol-coding value at each bit
|
||||
* length, which is (previous limit<<1)+symbols at this level), and
|
||||
* base[] (number of symbols to ignore at each bit length, which is
|
||||
* limit minus the cumulative count of symbols coded for already). */
|
||||
pp = t = 0;
|
||||
for (i = minLen; i < maxLen;) {
|
||||
unsigned temp_i = temp[i];
|
||||
|
||||
pp += temp_i;
|
||||
|
||||
/* We read the largest possible symbol size and then unget bits
|
||||
after determining how many we need, and those extra bits could
|
||||
be set to anything. (They're noise from future symbols.) At
|
||||
each level we're really only interested in the first few bits,
|
||||
so here we set all the trailing to-be-ignored bits to 1 so they
|
||||
don't affect the value>limit[length] comparison. */
|
||||
limit[i] = (pp << (maxLen - i)) - 1;
|
||||
pp <<= 1;
|
||||
t += temp_i;
|
||||
base[++i] = pp - t;
|
||||
}
|
||||
limit[maxLen] = pp + temp[maxLen] - 1;
|
||||
limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
|
||||
base[minLen] = 0;
|
||||
}
|
||||
|
||||
/* We've finished reading and digesting the block header. Now read this
|
||||
block's Huffman coded symbols from the file and undo the Huffman coding
|
||||
and run length encoding, saving the result into dbuf[dbufCount++] = uc */
|
||||
|
||||
/* Initialize symbol occurrence counters and symbol Move To Front table */
|
||||
/*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */
|
||||
for (i = 0; i < 256; i++) {
|
||||
byteCount[i] = 0;
|
||||
mtfSymbol[i] = (uint8_t)i;
|
||||
}
|
||||
|
||||
/* Loop through compressed symbols. */
|
||||
|
||||
runPos = dbufCount = selector = 0;
|
||||
for (;;) {
|
||||
struct group_data *hufGroup;
|
||||
int *base, *limit;
|
||||
int nextSym;
|
||||
uint8_t ngrp;
|
||||
|
||||
/* Fetch next Huffman coding group from list. */
|
||||
symCount = GROUP_SIZE - 1;
|
||||
if (selector >= nSelectors)
|
||||
return RETVAL_DATA_ERROR;
|
||||
ngrp = selectors[selector++];
|
||||
if (ngrp >= groupCount) {
|
||||
dbg("%d selectors[%d]:%d groupCount:%d",
|
||||
__LINE__, selector-1, ngrp, groupCount);
|
||||
return RETVAL_DATA_ERROR;
|
||||
}
|
||||
hufGroup = bd->groups + ngrp;
|
||||
base = hufGroup->base - 1;
|
||||
limit = hufGroup->limit - 1;
|
||||
|
||||
continue_this_group:
|
||||
/* Read next Huffman-coded symbol. */
|
||||
|
||||
/* Note: It is far cheaper to read maxLen bits and back up than it is
|
||||
to read minLen bits and then add additional bit at a time, testing
|
||||
as we go. Because there is a trailing last block (with file CRC),
|
||||
there is no danger of the overread causing an unexpected EOF for a
|
||||
valid compressed file.
|
||||
*/
|
||||
if (1) {
|
||||
/* As a further optimization, we do the read inline
|
||||
(falling back to a call to get_bits if the buffer runs dry).
|
||||
*/
|
||||
int new_cnt;
|
||||
while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) {
|
||||
/* bd->inbufBitCount < hufGroup->maxLen */
|
||||
if (bd->inbufPos == bd->inbufCount) {
|
||||
nextSym = get_bits(bd, hufGroup->maxLen);
|
||||
goto got_huff_bits;
|
||||
}
|
||||
bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
|
||||
bd->inbufBitCount += 8;
|
||||
};
|
||||
bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */
|
||||
nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1);
|
||||
got_huff_bits: ;
|
||||
} else { /* unoptimized equivalent */
|
||||
nextSym = get_bits(bd, hufGroup->maxLen);
|
||||
}
|
||||
/* Figure how many bits are in next symbol and unget extras */
|
||||
i = hufGroup->minLen;
|
||||
while (nextSym > limit[i])
|
||||
++i;
|
||||
j = hufGroup->maxLen - i;
|
||||
if (j < 0)
|
||||
return RETVAL_DATA_ERROR;
|
||||
bd->inbufBitCount += j;
|
||||
|
||||
/* Huffman decode value to get nextSym (with bounds checking) */
|
||||
nextSym = (nextSym >> j) - base[i];
|
||||
if ((unsigned)nextSym >= MAX_SYMBOLS)
|
||||
return RETVAL_DATA_ERROR;
|
||||
nextSym = hufGroup->permute[nextSym];
|
||||
|
||||
/* We have now decoded the symbol, which indicates either a new literal
|
||||
byte, or a repeated run of the most recent literal byte. First,
|
||||
check if nextSym indicates a repeated run, and if so loop collecting
|
||||
how many times to repeat the last literal. */
|
||||
if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */
|
||||
|
||||
/* If this is the start of a new run, zero out counter */
|
||||
if (runPos == 0) {
|
||||
runPos = 1;
|
||||
runCnt = 0;
|
||||
}
|
||||
|
||||
/* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
|
||||
each bit position, add 1 or 2 instead. For example,
|
||||
1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
|
||||
You can make any bit pattern that way using 1 less symbol than
|
||||
the basic or 0/1 method (except all bits 0, which would use no
|
||||
symbols, but a run of length 0 doesn't mean anything in this
|
||||
context). Thus space is saved. */
|
||||
runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
|
||||
//The 32-bit overflow of runCnt wasn't yet seen, but probably can happen.
|
||||
//This would be the fix (catches too large count way before it can overflow):
|
||||
// if (runCnt > bd->dbufSize) {
|
||||
// dbg("runCnt:%u > dbufSize:%u RETVAL_DATA_ERROR",
|
||||
// runCnt, bd->dbufSize);
|
||||
// return RETVAL_DATA_ERROR;
|
||||
// }
|
||||
if (runPos < bd->dbufSize) runPos <<= 1;
|
||||
goto end_of_huffman_loop;
|
||||
}
|
||||
|
||||
/* When we hit the first non-run symbol after a run, we now know
|
||||
how many times to repeat the last literal, so append that many
|
||||
copies to our buffer of decoded symbols (dbuf) now. (The last
|
||||
literal used is the one at the head of the mtfSymbol array.) */
|
||||
if (runPos != 0) {
|
||||
uint8_t tmp_byte;
|
||||
if (dbufCount + runCnt > bd->dbufSize) {
|
||||
dbg("dbufCount:%u+runCnt:%u %u > dbufSize:%u RETVAL_DATA_ERROR",
|
||||
dbufCount, runCnt, dbufCount + runCnt, bd->dbufSize);
|
||||
return RETVAL_DATA_ERROR;
|
||||
}
|
||||
tmp_byte = symToByte[mtfSymbol[0]];
|
||||
byteCount[tmp_byte] += runCnt;
|
||||
while ((int)--runCnt >= 0)
|
||||
dbuf[dbufCount++] = (uint32_t)tmp_byte;
|
||||
runPos = 0;
|
||||
}
|
||||
|
||||
/* Is this the terminating symbol? */
|
||||
if (nextSym > symTotal) break;
|
||||
|
||||
/* At this point, nextSym indicates a new literal character. Subtract
|
||||
one to get the position in the MTF array at which this literal is
|
||||
currently to be found. (Note that the result can't be -1 or 0,
|
||||
because 0 and 1 are RUNA and RUNB. But another instance of the
|
||||
first symbol in the mtf array, position 0, would have been handled
|
||||
as part of a run above. Therefore 1 unused mtf position minus
|
||||
2 non-literal nextSym values equals -1.) */
|
||||
if (dbufCount >= bd->dbufSize) return RETVAL_DATA_ERROR;
|
||||
i = nextSym - 1;
|
||||
uc = mtfSymbol[i];
|
||||
|
||||
/* Adjust the MTF array. Since we typically expect to move only a
|
||||
* small number of symbols, and are bound by 256 in any case, using
|
||||
* memmove here would typically be bigger and slower due to function
|
||||
* call overhead and other assorted setup costs. */
|
||||
do {
|
||||
mtfSymbol[i] = mtfSymbol[i-1];
|
||||
} while (--i);
|
||||
mtfSymbol[0] = uc;
|
||||
uc = symToByte[uc];
|
||||
|
||||
/* We have our literal byte. Save it into dbuf. */
|
||||
byteCount[uc]++;
|
||||
dbuf[dbufCount++] = (uint32_t)uc;
|
||||
|
||||
/* Skip group initialization if we're not done with this group. Done
|
||||
* this way to avoid compiler warning. */
|
||||
end_of_huffman_loop:
|
||||
if (--symCount >= 0) goto continue_this_group;
|
||||
}
|
||||
|
||||
/* At this point, we've read all the Huffman-coded symbols (and repeated
|
||||
runs) for this block from the input stream, and decoded them into the
|
||||
intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
|
||||
Now undo the Burrows-Wheeler transform on dbuf.
|
||||
See http://dogma.net/markn/articles/bwt/bwt.htm
|
||||
*/
|
||||
|
||||
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
|
||||
j = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
int tmp_count = j + byteCount[i];
|
||||
byteCount[i] = j;
|
||||
j = tmp_count;
|
||||
}
|
||||
|
||||
/* Figure out what order dbuf would be in if we sorted it. */
|
||||
for (i = 0; i < dbufCount; i++) {
|
||||
uint8_t tmp_byte = (uint8_t)dbuf[i];
|
||||
int tmp_count = byteCount[tmp_byte];
|
||||
dbuf[tmp_count] |= (i << 8);
|
||||
byteCount[tmp_byte] = tmp_count + 1;
|
||||
}
|
||||
|
||||
/* Decode first byte by hand to initialize "previous" byte. Note that it
|
||||
doesn't get output, and if the first three characters are identical
|
||||
it doesn't qualify as a run (hence writeRunCountdown=5). */
|
||||
if (dbufCount) {
|
||||
uint32_t tmp;
|
||||
if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR;
|
||||
tmp = dbuf[origPtr];
|
||||
bd->writeCurrent = (uint8_t)tmp;
|
||||
bd->writePos = (tmp >> 8);
|
||||
bd->writeRunCountdown = 5;
|
||||
}
|
||||
bd->writeCount = dbufCount;
|
||||
|
||||
return RETVAL_OK;
|
||||
}
|
||||
|
||||
/* Undo Burrows-Wheeler transform on intermediate buffer to produce output.
|
||||
If start_bunzip was initialized with out_fd=-1, then up to len bytes of
|
||||
data are written to outbuf. Return value is number of bytes written or
|
||||
error (all errors are negative numbers). If out_fd!=-1, outbuf and len
|
||||
are ignored, data is written to out_fd and return is RETVAL_OK or error.
|
||||
|
||||
NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
|
||||
in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0.
|
||||
(Why? This allows to get rid of one local variable)
|
||||
*/
|
||||
static int read_bunzip(bunzip_data *bd, char *outbuf, int len)
|
||||
{
|
||||
const uint32_t *dbuf;
|
||||
int pos, current, previous;
|
||||
uint32_t CRC;
|
||||
|
||||
/* If we already have error/end indicator, return it */
|
||||
if (bd->writeCount < 0)
|
||||
return bd->writeCount;
|
||||
|
||||
dbuf = bd->dbuf;
|
||||
|
||||
/* Register-cached state (hopefully): */
|
||||
pos = bd->writePos;
|
||||
current = bd->writeCurrent;
|
||||
CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */
|
||||
|
||||
/* We will always have pending decoded data to write into the output
|
||||
buffer unless this is the very first call (in which case we haven't
|
||||
Huffman-decoded a block into the intermediate buffer yet). */
|
||||
if (bd->writeCopies) {
|
||||
|
||||
dec_writeCopies:
|
||||
/* Inside the loop, writeCopies means extra copies (beyond 1) */
|
||||
--bd->writeCopies;
|
||||
|
||||
/* Loop outputting bytes */
|
||||
for (;;) {
|
||||
|
||||
/* If the output buffer is full, save cached state and return */
|
||||
if (--len < 0) {
|
||||
/* Unlikely branch.
|
||||
* Use of "goto" instead of keeping code here
|
||||
* helps compiler to realize this. */
|
||||
goto outbuf_full;
|
||||
}
|
||||
|
||||
/* Write next byte into output buffer, updating CRC */
|
||||
*outbuf++ = current;
|
||||
CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current];
|
||||
|
||||
/* Loop now if we're outputting multiple copies of this byte */
|
||||
if (bd->writeCopies) {
|
||||
/* Unlikely branch */
|
||||
/*--bd->writeCopies;*/
|
||||
/*continue;*/
|
||||
/* Same, but (ab)using other existing --writeCopies operation
|
||||
* (and this if() compiles into just test+branch pair): */
|
||||
goto dec_writeCopies;
|
||||
}
|
||||
decode_next_byte:
|
||||
if (--bd->writeCount < 0)
|
||||
break; /* input block is fully consumed, need next one */
|
||||
|
||||
/* Follow sequence vector to undo Burrows-Wheeler transform */
|
||||
previous = current;
|
||||
pos = dbuf[pos];
|
||||
current = (uint8_t)pos;
|
||||
pos >>= 8;
|
||||
|
||||
/* After 3 consecutive copies of the same byte, the 4th
|
||||
* is a repeat count. We count down from 4 instead
|
||||
* of counting up because testing for non-zero is faster */
|
||||
if (--bd->writeRunCountdown != 0) {
|
||||
if (current != previous)
|
||||
bd->writeRunCountdown = 4;
|
||||
} else {
|
||||
/* Unlikely branch */
|
||||
/* We have a repeated run, this byte indicates the count */
|
||||
bd->writeCopies = current;
|
||||
current = previous;
|
||||
bd->writeRunCountdown = 5;
|
||||
|
||||
/* Sometimes there are just 3 bytes (run length 0) */
|
||||
if (!bd->writeCopies) goto decode_next_byte;
|
||||
|
||||
/* Subtract the 1 copy we'd output anyway to get extras */
|
||||
--bd->writeCopies;
|
||||
}
|
||||
} /* for (;;) */
|
||||
|
||||
/* Decompression of this input block completed successfully */
|
||||
bd->writeCRC = CRC = ~CRC;
|
||||
bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC;
|
||||
|
||||
/* If this block had a CRC error, force file level CRC error */
|
||||
if (CRC != bd->headerCRC) {
|
||||
bd->totalCRC = bd->headerCRC + 1;
|
||||
return RETVAL_LAST_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Refill the intermediate buffer by Huffman-decoding next block of input */
|
||||
{
|
||||
int r = get_next_block(bd);
|
||||
if (r) { /* error/end */
|
||||
bd->writeCount = r;
|
||||
return (r != RETVAL_LAST_BLOCK) ? r : len;
|
||||
}
|
||||
}
|
||||
|
||||
CRC = ~0;
|
||||
pos = bd->writePos;
|
||||
current = bd->writeCurrent;
|
||||
goto decode_next_byte;
|
||||
|
||||
outbuf_full:
|
||||
/* Output buffer is full, save cached state and return */
|
||||
bd->writePos = pos;
|
||||
bd->writeCurrent = current;
|
||||
bd->writeCRC = CRC;
|
||||
|
||||
bd->writeCopies++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain
|
||||
a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are
|
||||
ignored, and data is read from file handle into temporary buffer. */
|
||||
|
||||
/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
|
||||
should work for NOFORK applets too, we must be extremely careful to not leak
|
||||
any allocations! */
|
||||
static int FAST_FUNC start_bunzip(
|
||||
void *jmpbuf,
|
||||
bunzip_data **bdp,
|
||||
int in_fd,
|
||||
const void *inbuf, int len)
|
||||
{
|
||||
bunzip_data *bd;
|
||||
unsigned i;
|
||||
enum {
|
||||
BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0',
|
||||
h0 = ('h' << 8) + '0',
|
||||
};
|
||||
|
||||
/* Figure out how much data to allocate */
|
||||
i = sizeof(bunzip_data);
|
||||
if (in_fd != -1)
|
||||
i += IOBUF_SIZE;
|
||||
|
||||
/* Allocate bunzip_data. Most fields initialize to zero. */
|
||||
bd = *bdp = xzalloc(i);
|
||||
|
||||
bd->jmpbuf = jmpbuf;
|
||||
|
||||
/* Setup input buffer */
|
||||
bd->in_fd = in_fd;
|
||||
if (-1 == in_fd) {
|
||||
/* in this case, bd->inbuf is read-only */
|
||||
bd->inbuf = (void*)inbuf; /* cast away const-ness */
|
||||
} else {
|
||||
bd->inbuf = (uint8_t*)(bd + 1);
|
||||
memcpy(bd->inbuf, inbuf, len);
|
||||
}
|
||||
bd->inbufCount = len;
|
||||
|
||||
/* Init the CRC32 table (big endian) */
|
||||
crc32_filltable(bd->crc32Table, 1);
|
||||
|
||||
/* Ensure that file starts with "BZh['1'-'9']." */
|
||||
/* Update: now caller verifies 1st two bytes, makes .gz/.bz2
|
||||
* integration easier */
|
||||
/* was: */
|
||||
/* i = get_bits(bd, 32); */
|
||||
/* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */
|
||||
i = get_bits(bd, 16);
|
||||
if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;
|
||||
|
||||
/* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of
|
||||
uncompressed data. Allocate intermediate buffer for block. */
|
||||
/* bd->dbufSize = 100000 * (i - BZh0); */
|
||||
bd->dbufSize = 100000 * (i - h0);
|
||||
|
||||
/* Cannot use xmalloc - may leak bd in NOFORK case! */
|
||||
bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0]));
|
||||
if (!bd->dbuf) {
|
||||
free(bd);
|
||||
xfunc_die();
|
||||
}
|
||||
return RETVAL_OK;
|
||||
}
|
||||
|
||||
static void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
|
||||
{
|
||||
free(bd->dbuf);
|
||||
free(bd);
|
||||
}
|
||||
|
||||
|
||||
/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
|
||||
IF_DESKTOP(long long) int FAST_FUNC
|
||||
unpack_bz2_stream(transformer_state_t *xstate)
|
||||
{
|
||||
IF_DESKTOP(long long total_written = 0;)
|
||||
bunzip_data *bd;
|
||||
char *outbuf;
|
||||
int i;
|
||||
unsigned len;
|
||||
|
||||
if (check_signature16(xstate, BZIP2_MAGIC))
|
||||
return -1;
|
||||
|
||||
outbuf = xmalloc(IOBUF_SIZE);
|
||||
len = 0;
|
||||
while (1) { /* "Process one BZ... stream" loop */
|
||||
jmp_buf jmpbuf;
|
||||
|
||||
/* Setup for I/O error handling via longjmp */
|
||||
i = setjmp(jmpbuf);
|
||||
if (i == 0)
|
||||
i = start_bunzip(&jmpbuf, &bd, xstate->src_fd, outbuf + 2, len);
|
||||
|
||||
if (i == 0) {
|
||||
while (1) { /* "Produce some output bytes" loop */
|
||||
i = read_bunzip(bd, outbuf, IOBUF_SIZE);
|
||||
if (i < 0) /* error? */
|
||||
break;
|
||||
i = IOBUF_SIZE - i; /* number of bytes produced */
|
||||
if (i == 0) /* EOF? */
|
||||
break;
|
||||
if (i != transformer_write(xstate, outbuf, i)) {
|
||||
i = RETVAL_SHORT_WRITE;
|
||||
goto release_mem;
|
||||
}
|
||||
IF_DESKTOP(total_written += i;)
|
||||
}
|
||||
}
|
||||
|
||||
if (i != RETVAL_LAST_BLOCK
|
||||
/* Observed case when i == RETVAL_OK:
|
||||
* "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file
|
||||
* (to be exact, z.bz2 is exactly these 14 bytes:
|
||||
* 42 5a 68 39 17 72 45 38 50 90 00 00 00 00).
|
||||
*/
|
||||
&& i != RETVAL_OK
|
||||
) {
|
||||
bb_error_msg("bunzip error %d", i);
|
||||
break;
|
||||
}
|
||||
if (bd->headerCRC != bd->totalCRC) {
|
||||
bb_simple_error_msg("CRC error");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Successfully unpacked one BZ stream */
|
||||
i = RETVAL_OK;
|
||||
|
||||
/* Do we have "BZ..." after last processed byte?
|
||||
* pbzip2 (parallelized bzip2) produces such files.
|
||||
*/
|
||||
len = bd->inbufCount - bd->inbufPos;
|
||||
memcpy(outbuf, &bd->inbuf[bd->inbufPos], len);
|
||||
if (len < 2) {
|
||||
if (safe_read(xstate->src_fd, outbuf + len, 2 - len) != 2 - len)
|
||||
break;
|
||||
len = 2;
|
||||
}
|
||||
if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */
|
||||
break;
|
||||
dealloc_bunzip(bd);
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
release_mem:
|
||||
dealloc_bunzip(bd);
|
||||
free(outbuf);
|
||||
|
||||
return i ? i : IF_DESKTOP(total_written) + 0;
|
||||
}
|
||||
|
||||
char* FAST_FUNC
|
||||
unpack_bz2_data(const char *packed, int packed_len, int unpacked_len)
|
||||
{
|
||||
char *outbuf = NULL;
|
||||
bunzip_data *bd;
|
||||
int i;
|
||||
jmp_buf jmpbuf;
|
||||
|
||||
/* Setup for I/O error handling via longjmp */
|
||||
i = setjmp(jmpbuf);
|
||||
if (i == 0) {
|
||||
i = start_bunzip(&jmpbuf,
|
||||
&bd,
|
||||
/* src_fd: */ -1,
|
||||
/* inbuf: */ packed,
|
||||
/* len: */ packed_len
|
||||
);
|
||||
}
|
||||
/* read_bunzip can longjmp and end up here with i != 0
|
||||
* on read data errors! Not trivial */
|
||||
if (i == 0) {
|
||||
/* Cannot use xmalloc: will leak bd in NOFORK case! */
|
||||
outbuf = malloc_or_warn(unpacked_len);
|
||||
if (outbuf)
|
||||
read_bunzip(bd, outbuf, unpacked_len);
|
||||
}
|
||||
dealloc_bunzip(bd);
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
static char *const bunzip_errors[] = {
|
||||
NULL, "Bad file checksum", "Not bzip data",
|
||||
"Unexpected input EOF", "Unexpected output EOF", "Data error",
|
||||
"Out of memory", "Obsolete (pre 0.9.5) bzip format not supported"
|
||||
};
|
||||
|
||||
/* Dumb little test thing, decompress stdin to stdout */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
|
||||
int i = unpack_bz2_stream(0, 1);
|
||||
if (i < 0)
|
||||
fprintf(stderr, "%s\n", bunzip_errors[-i]);
|
||||
else if (read(STDIN_FILENO, &c, 1))
|
||||
fprintf(stderr, "Trailing garbage ignored\n");
|
||||
return -i;
|
||||
}
|
||||
#endif
|
1299
busybox-1_37_0/archival/libarchive/decompress_gunzip.c
Normal file
1299
busybox-1_37_0/archival/libarchive/decompress_gunzip.c
Normal file
File diff suppressed because it is too large
Load Diff
312
busybox-1_37_0/archival/libarchive/decompress_uncompress.c
Normal file
312
busybox-1_37_0/archival/libarchive/decompress_uncompress.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* uncompress for busybox -- (c) 2002 Robert Griebl
|
||||
*
|
||||
* based on the original compress42.c source
|
||||
* (see disclaimer below)
|
||||
*/
|
||||
/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
|
||||
*
|
||||
* Authors:
|
||||
* Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
|
||||
* Jim McKie (decvax!mcvax!jim)
|
||||
* Steve Davies (decvax!vax135!petsd!peora!srd)
|
||||
* Ken Turkowski (decvax!decwrl!turtlevax!ken)
|
||||
* James A. Woods (decvax!ihnp4!ames!jaw)
|
||||
* Joe Orost (decvax!vax135!petsd!joe)
|
||||
* Dave Mack (csu@alembic.acs.com)
|
||||
* Peter Jannesen, Network Communication Systems
|
||||
* (peter@ncs.nl)
|
||||
*
|
||||
* marc@suse.de : a small security fix for a buffer overflow
|
||||
*
|
||||
* [... History snipped ...]
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
|
||||
/* Default input buffer size */
|
||||
#define IBUFSIZ 2048
|
||||
|
||||
/* Default output buffer size */
|
||||
#define OBUFSIZ 2048
|
||||
|
||||
/* Defines for third byte of header */
|
||||
#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */
|
||||
/* Masks 0x20 and 0x40 are free. */
|
||||
/* I think 0x20 should mean that there is */
|
||||
/* a fourth header byte (for expansion). */
|
||||
#define BLOCK_MODE 0x80 /* Block compression if table is full and */
|
||||
/* compression rate is dropping flush tables */
|
||||
/* the next two codes should not be changed lightly, as they must not */
|
||||
/* lie within the contiguous general code space. */
|
||||
#define FIRST 257 /* first free entry */
|
||||
#define CLEAR 256 /* table clear output code */
|
||||
|
||||
#define INIT_BITS 9 /* initial number of bits/code */
|
||||
|
||||
|
||||
/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */
|
||||
#define HBITS 17 /* 50% occupancy */
|
||||
#define HSIZE (1<<HBITS)
|
||||
#define HMASK (HSIZE-1) /* unused */
|
||||
#define HPRIME 9941 /* unused */
|
||||
#define BITS 16
|
||||
#define BITS_STR "16"
|
||||
#undef MAXSEG_64K /* unused */
|
||||
#define MAXCODE(n) (1L << (n))
|
||||
|
||||
#define htabof(i) htab[i]
|
||||
#define codetabof(i) codetab[i]
|
||||
#define tab_prefixof(i) codetabof(i)
|
||||
#define tab_suffixof(i) ((unsigned char *)(htab))[i]
|
||||
#define de_stack ((unsigned char *)&(htab[HSIZE-1]))
|
||||
#define clear_tab_prefixof() memset(codetab, 0, 256)
|
||||
|
||||
/*
|
||||
* Decompress stdin to stdout. This routine adapts to the codes in the
|
||||
* file building the "string" table on-the-fly; requiring no table to
|
||||
* be stored in the compressed file.
|
||||
*/
|
||||
|
||||
IF_DESKTOP(long long) int FAST_FUNC
|
||||
unpack_Z_stream(transformer_state_t *xstate)
|
||||
{
|
||||
IF_DESKTOP(long long total_written = 0;)
|
||||
IF_DESKTOP(long long) int retval = -1;
|
||||
unsigned char *stackp;
|
||||
int finchar;
|
||||
long oldcode;
|
||||
long incode;
|
||||
int inbits;
|
||||
int posbits;
|
||||
int outpos;
|
||||
int insize;
|
||||
int bitmask;
|
||||
long free_ent;
|
||||
long maxcode;
|
||||
long maxmaxcode;
|
||||
int n_bits;
|
||||
int rsize = 0;
|
||||
unsigned char *inbuf; /* were eating insane amounts of stack - */
|
||||
unsigned char *outbuf; /* bad for some embedded targets */
|
||||
unsigned char *htab;
|
||||
unsigned short *codetab;
|
||||
|
||||
/* Hmm, these were statics - why?! */
|
||||
/* user settable max # bits/code */
|
||||
int maxbits; /* = BITS; */
|
||||
/* block compress mode -C compatible with 2.0 */
|
||||
int block_mode; /* = BLOCK_MODE; */
|
||||
|
||||
if (check_signature16(xstate, COMPRESS_MAGIC))
|
||||
return -1;
|
||||
|
||||
inbuf = xzalloc(IBUFSIZ + 64);
|
||||
outbuf = xzalloc(OBUFSIZ + 2048);
|
||||
htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */
|
||||
codetab = xzalloc(HSIZE * sizeof(codetab[0]));
|
||||
|
||||
insize = 0;
|
||||
|
||||
/* xread isn't good here, we have to return - caller may want
|
||||
* to do some cleanup (e.g. delete incomplete unpacked file etc) */
|
||||
if (full_read(xstate->src_fd, inbuf, 1) != 1) {
|
||||
bb_simple_error_msg("short read");
|
||||
goto err;
|
||||
}
|
||||
|
||||
maxbits = inbuf[0] & BIT_MASK;
|
||||
block_mode = inbuf[0] & BLOCK_MODE;
|
||||
maxmaxcode = MAXCODE(maxbits);
|
||||
|
||||
if (maxbits > BITS) {
|
||||
bb_error_msg("compressed with %d bits, can only handle "
|
||||
BITS_STR" bits", maxbits);
|
||||
goto err;
|
||||
}
|
||||
|
||||
n_bits = INIT_BITS;
|
||||
maxcode = MAXCODE(INIT_BITS) - 1;
|
||||
bitmask = (1 << INIT_BITS) - 1;
|
||||
oldcode = -1;
|
||||
finchar = 0;
|
||||
outpos = 0;
|
||||
posbits = 0 << 3;
|
||||
|
||||
free_ent = ((block_mode) ? FIRST : 256);
|
||||
|
||||
/* As above, initialize the first 256 entries in the table. */
|
||||
/*clear_tab_prefixof(); - done by xzalloc */
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i = 255; i >= 0; --i)
|
||||
tab_suffixof(i) = (unsigned char) i;
|
||||
}
|
||||
|
||||
do {
|
||||
resetbuf:
|
||||
{
|
||||
int i;
|
||||
int e;
|
||||
int o;
|
||||
|
||||
o = posbits >> 3;
|
||||
e = insize - o;
|
||||
|
||||
for (i = 0; i < e; ++i)
|
||||
inbuf[i] = inbuf[i + o];
|
||||
|
||||
insize = e;
|
||||
posbits = 0;
|
||||
}
|
||||
|
||||
if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
|
||||
rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ);
|
||||
if (rsize < 0)
|
||||
bb_simple_error_msg_and_die(bb_msg_read_error);
|
||||
insize += rsize;
|
||||
}
|
||||
|
||||
inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 :
|
||||
(insize << 3) - (n_bits - 1));
|
||||
|
||||
while (inbits > posbits) {
|
||||
long code;
|
||||
|
||||
if (free_ent > maxcode) {
|
||||
posbits =
|
||||
((posbits - 1) +
|
||||
((n_bits << 3) -
|
||||
(posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
|
||||
++n_bits;
|
||||
if (n_bits == maxbits) {
|
||||
maxcode = maxmaxcode;
|
||||
} else {
|
||||
maxcode = MAXCODE(n_bits) - 1;
|
||||
}
|
||||
bitmask = (1 << n_bits) - 1;
|
||||
goto resetbuf;
|
||||
}
|
||||
{
|
||||
unsigned char *p = &inbuf[posbits >> 3];
|
||||
code = ((p[0]
|
||||
| ((long) (p[1]) << 8)
|
||||
| ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
|
||||
}
|
||||
posbits += n_bits;
|
||||
|
||||
if (oldcode == -1) {
|
||||
if (code >= 256)
|
||||
bb_simple_error_msg_and_die("corrupted data"); /* %ld", code); */
|
||||
oldcode = code;
|
||||
finchar = (int) oldcode;
|
||||
outbuf[outpos++] = (unsigned char) finchar;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code == CLEAR && block_mode) {
|
||||
clear_tab_prefixof();
|
||||
free_ent = FIRST - 1;
|
||||
posbits =
|
||||
((posbits - 1) +
|
||||
((n_bits << 3) -
|
||||
(posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
|
||||
n_bits = INIT_BITS;
|
||||
maxcode = MAXCODE(INIT_BITS) - 1;
|
||||
bitmask = (1 << INIT_BITS) - 1;
|
||||
goto resetbuf;
|
||||
}
|
||||
|
||||
incode = code;
|
||||
stackp = de_stack;
|
||||
|
||||
/* Special case for KwKwK string. */
|
||||
if (code >= free_ent) {
|
||||
if (code > free_ent) {
|
||||
/*
|
||||
unsigned char *p;
|
||||
|
||||
posbits -= n_bits;
|
||||
p = &inbuf[posbits >> 3];
|
||||
bb_error_msg
|
||||
("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
|
||||
insize, posbits, p[-1], p[0], p[1], p[2], p[3],
|
||||
(posbits & 07));
|
||||
*/
|
||||
bb_simple_error_msg("corrupted data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
*--stackp = (unsigned char) finchar;
|
||||
code = oldcode;
|
||||
}
|
||||
|
||||
/* Generate output characters in reverse order */
|
||||
while (code >= 256) {
|
||||
if (stackp <= &htabof(0))
|
||||
bb_simple_error_msg_and_die("corrupted data");
|
||||
*--stackp = tab_suffixof(code);
|
||||
code = tab_prefixof(code);
|
||||
}
|
||||
|
||||
finchar = tab_suffixof(code);
|
||||
*--stackp = (unsigned char) finchar;
|
||||
|
||||
/* And put them out in forward order */
|
||||
{
|
||||
int i;
|
||||
|
||||
i = de_stack - stackp;
|
||||
if (outpos + i >= OBUFSIZ) {
|
||||
do {
|
||||
if (i > OBUFSIZ - outpos) {
|
||||
i = OBUFSIZ - outpos;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
memcpy(outbuf + outpos, stackp, i);
|
||||
outpos += i;
|
||||
}
|
||||
|
||||
if (outpos >= OBUFSIZ) {
|
||||
xtransformer_write(xstate, outbuf, outpos);
|
||||
IF_DESKTOP(total_written += outpos;)
|
||||
outpos = 0;
|
||||
}
|
||||
stackp += i;
|
||||
i = de_stack - stackp;
|
||||
} while (i > 0);
|
||||
} else {
|
||||
memcpy(outbuf + outpos, stackp, i);
|
||||
outpos += i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the new entry. */
|
||||
if (free_ent < maxmaxcode) {
|
||||
tab_prefixof(free_ent) = (unsigned short) oldcode;
|
||||
tab_suffixof(free_ent) = (unsigned char) finchar;
|
||||
free_ent++;
|
||||
}
|
||||
|
||||
/* Remember previous code. */
|
||||
oldcode = incode;
|
||||
}
|
||||
} while (rsize > 0);
|
||||
|
||||
if (outpos > 0) {
|
||||
xtransformer_write(xstate, outbuf, outpos);
|
||||
IF_DESKTOP(total_written += outpos;)
|
||||
}
|
||||
|
||||
retval = IF_DESKTOP(total_written) + 0;
|
||||
err:
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
free(htab);
|
||||
free(codetab);
|
||||
return retval;
|
||||
}
|
527
busybox-1_37_0/archival/libarchive/decompress_unlzma.c
Normal file
527
busybox-1_37_0/archival/libarchive/decompress_unlzma.c
Normal file
@ -0,0 +1,527 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Small lzma deflate implementation.
|
||||
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
|
||||
* Copyright (C) 1999-2005 Igor Pavlov
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#if 0
|
||||
# define dbg(...) bb_error_msg(__VA_ARGS__)
|
||||
#else
|
||||
# define dbg(...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
#if ENABLE_FEATURE_LZMA_FAST
|
||||
# define speed_inline ALWAYS_INLINE
|
||||
# define size_inline
|
||||
#else
|
||||
# define speed_inline
|
||||
# define size_inline ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
uint8_t *ptr;
|
||||
|
||||
/* Was keeping rc on stack in unlzma and separately allocating buffer,
|
||||
* but with "buffer 'attached to' allocated rc" code is smaller: */
|
||||
/* uint8_t *buffer; */
|
||||
#define RC_BUFFER ((uint8_t*)(rc+1))
|
||||
|
||||
uint8_t *buffer_end;
|
||||
|
||||
/* Had provisions for variable buffer, but we don't need it here */
|
||||
/* int buffer_size; */
|
||||
#define RC_BUFFER_SIZE 0x10000
|
||||
|
||||
uint32_t code;
|
||||
uint32_t range;
|
||||
uint32_t bound;
|
||||
} rc_t;
|
||||
|
||||
#define RC_TOP_BITS 24
|
||||
#define RC_MOVE_BITS 5
|
||||
#define RC_MODEL_TOTAL_BITS 11
|
||||
|
||||
|
||||
/* Called once in rc_do_normalize() */
|
||||
static void rc_read(rc_t *rc)
|
||||
{
|
||||
int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
|
||||
//TODO: return -1 instead
|
||||
//This will make unlzma delete broken unpacked file on unpack errors
|
||||
if (buffer_size <= 0)
|
||||
bb_simple_error_msg_and_die("unexpected EOF");
|
||||
rc->buffer_end = RC_BUFFER + buffer_size;
|
||||
rc->ptr = RC_BUFFER;
|
||||
}
|
||||
|
||||
/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */
|
||||
static void rc_do_normalize(rc_t *rc)
|
||||
{
|
||||
if (rc->ptr >= rc->buffer_end)
|
||||
rc_read(rc);
|
||||
rc->range <<= 8;
|
||||
rc->code = (rc->code << 8) | *rc->ptr++;
|
||||
}
|
||||
static ALWAYS_INLINE void rc_normalize(rc_t *rc)
|
||||
{
|
||||
if (rc->range < (1 << RC_TOP_BITS)) {
|
||||
rc_do_normalize(rc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called once */
|
||||
static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */
|
||||
{
|
||||
int i;
|
||||
rc_t *rc;
|
||||
|
||||
rc = xzalloc(sizeof(*rc) + RC_BUFFER_SIZE);
|
||||
|
||||
rc->fd = fd;
|
||||
/* rc->ptr = rc->buffer_end; */
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
rc_do_normalize(rc);
|
||||
}
|
||||
rc->range = 0xffffffff;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Called once */
|
||||
static ALWAYS_INLINE void rc_free(rc_t *rc)
|
||||
{
|
||||
free(rc);
|
||||
}
|
||||
|
||||
/* rc_is_bit_1 is called 9 times */
|
||||
static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p)
|
||||
{
|
||||
rc_normalize(rc);
|
||||
rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
|
||||
if (rc->code < rc->bound) {
|
||||
rc->range = rc->bound;
|
||||
*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
|
||||
return 0;
|
||||
}
|
||||
rc->range -= rc->bound;
|
||||
rc->code -= rc->bound;
|
||||
*p -= *p >> RC_MOVE_BITS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called 4 times in unlzma loop */
|
||||
static ALWAYS_INLINE int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
|
||||
{
|
||||
int ret = rc_is_bit_1(rc, p);
|
||||
*symbol = *symbol * 2 + ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Called once */
|
||||
static ALWAYS_INLINE int rc_direct_bit(rc_t *rc)
|
||||
{
|
||||
rc_normalize(rc);
|
||||
rc->range >>= 1;
|
||||
if (rc->code >= rc->range) {
|
||||
rc->code -= rc->range;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called twice */
|
||||
static speed_inline void
|
||||
rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol)
|
||||
{
|
||||
int i = num_levels;
|
||||
|
||||
*symbol = 1;
|
||||
while (i--)
|
||||
rc_get_bit(rc, p + *symbol, symbol);
|
||||
*symbol -= 1 << num_levels;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t pos;
|
||||
uint32_t dict_size;
|
||||
uint64_t dst_size;
|
||||
} PACKED lzma_header_t;
|
||||
|
||||
|
||||
/* #defines will force compiler to compute/optimize each one with each usage.
|
||||
* Have heart and use enum instead. */
|
||||
enum {
|
||||
LZMA_BASE_SIZE = 1846,
|
||||
LZMA_LIT_SIZE = 768,
|
||||
|
||||
LZMA_NUM_POS_BITS_MAX = 4,
|
||||
|
||||
LZMA_LEN_NUM_LOW_BITS = 3,
|
||||
LZMA_LEN_NUM_MID_BITS = 3,
|
||||
LZMA_LEN_NUM_HIGH_BITS = 8,
|
||||
|
||||
LZMA_LEN_CHOICE = 0,
|
||||
LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1),
|
||||
LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1),
|
||||
LZMA_LEN_MID = (LZMA_LEN_LOW \
|
||||
+ (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))),
|
||||
LZMA_LEN_HIGH = (LZMA_LEN_MID \
|
||||
+ (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))),
|
||||
LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)),
|
||||
|
||||
LZMA_NUM_STATES = 12,
|
||||
LZMA_NUM_LIT_STATES = 7,
|
||||
|
||||
LZMA_START_POS_MODEL_INDEX = 4,
|
||||
LZMA_END_POS_MODEL_INDEX = 14,
|
||||
LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)),
|
||||
|
||||
LZMA_NUM_POS_SLOT_BITS = 6,
|
||||
LZMA_NUM_LEN_TO_POS_STATES = 4,
|
||||
|
||||
LZMA_NUM_ALIGN_BITS = 4,
|
||||
|
||||
LZMA_MATCH_MIN_LEN = 2,
|
||||
|
||||
LZMA_IS_MATCH = 0,
|
||||
LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
|
||||
LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES),
|
||||
LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES),
|
||||
LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES),
|
||||
LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES),
|
||||
LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \
|
||||
+ (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
|
||||
LZMA_SPEC_POS = (LZMA_POS_SLOT \
|
||||
+ (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)),
|
||||
LZMA_ALIGN = (LZMA_SPEC_POS \
|
||||
+ LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX),
|
||||
LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)),
|
||||
LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS),
|
||||
LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS),
|
||||
};
|
||||
|
||||
|
||||
IF_DESKTOP(long long) int FAST_FUNC
|
||||
unpack_lzma_stream(transformer_state_t *xstate)
|
||||
{
|
||||
IF_DESKTOP(long long total_written = 0;)
|
||||
lzma_header_t header;
|
||||
int lc, pb, lp;
|
||||
uint32_t pos_state_mask;
|
||||
uint32_t literal_pos_mask;
|
||||
uint16_t *p;
|
||||
rc_t *rc;
|
||||
int i;
|
||||
uint8_t *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint8_t previous_byte = 0;
|
||||
size_t buffer_pos = 0, global_pos = 0;
|
||||
int len = 0;
|
||||
int state = 0;
|
||||
uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
|
||||
|
||||
if (full_read(xstate->src_fd, &header, sizeof(header)) != sizeof(header)
|
||||
|| header.pos >= (9 * 5 * 5)
|
||||
) {
|
||||
bb_simple_error_msg("bad lzma header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = header.pos / 9;
|
||||
lc = header.pos % 9;
|
||||
pb = i / 5;
|
||||
lp = i % 5;
|
||||
pos_state_mask = (1 << pb) - 1;
|
||||
literal_pos_mask = (1 << lp) - 1;
|
||||
|
||||
/* Example values from linux-3.3.4.tar.lzma:
|
||||
* dict_size: 64M, dst_size: 2^64-1
|
||||
*/
|
||||
header.dict_size = SWAP_LE32(header.dict_size);
|
||||
header.dst_size = SWAP_LE64(header.dst_size);
|
||||
|
||||
if (header.dict_size == 0)
|
||||
header.dict_size++;
|
||||
|
||||
buffer_size = MIN(header.dst_size, header.dict_size);
|
||||
buffer = xmalloc(buffer_size);
|
||||
|
||||
{
|
||||
int num_probs;
|
||||
|
||||
num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
|
||||
p = xmalloc(num_probs * sizeof(*p));
|
||||
num_probs += LZMA_LITERAL - LZMA_BASE_SIZE;
|
||||
for (i = 0; i < num_probs; i++)
|
||||
p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
|
||||
}
|
||||
|
||||
rc = rc_init(xstate->src_fd); /*, RC_BUFFER_SIZE); */
|
||||
|
||||
while (global_pos + buffer_pos < header.dst_size) {
|
||||
int pos_state = (buffer_pos + global_pos) & pos_state_mask;
|
||||
uint16_t *prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
|
||||
|
||||
if (!rc_is_bit_1(rc, prob)) {
|
||||
static const char next_state[LZMA_NUM_STATES] =
|
||||
{ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
int mi = 1;
|
||||
|
||||
prob = (p + LZMA_LITERAL
|
||||
+ (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
|
||||
+ (previous_byte >> (8 - lc))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (state >= LZMA_NUM_LIT_STATES) {
|
||||
int match_byte;
|
||||
uint32_t pos;
|
||||
|
||||
pos = buffer_pos - rep0;
|
||||
if ((int32_t)pos < 0) {
|
||||
pos += header.dict_size;
|
||||
if ((int32_t)pos < 0)
|
||||
goto bad;
|
||||
}
|
||||
match_byte = buffer[pos];
|
||||
do {
|
||||
int bit;
|
||||
|
||||
match_byte <<= 1;
|
||||
bit = match_byte & 0x100;
|
||||
bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */
|
||||
if (bit)
|
||||
break;
|
||||
} while (mi < 0x100);
|
||||
}
|
||||
while (mi < 0x100) {
|
||||
rc_get_bit(rc, prob + mi, &mi);
|
||||
}
|
||||
|
||||
state = next_state[state];
|
||||
|
||||
previous_byte = (uint8_t) mi;
|
||||
#if ENABLE_FEATURE_LZMA_FAST
|
||||
one_byte1:
|
||||
buffer[buffer_pos++] = previous_byte;
|
||||
if (buffer_pos == header.dict_size) {
|
||||
buffer_pos = 0;
|
||||
global_pos += header.dict_size;
|
||||
if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size)
|
||||
goto bad;
|
||||
IF_DESKTOP(total_written += header.dict_size;)
|
||||
}
|
||||
#else
|
||||
len = 1;
|
||||
goto one_byte2;
|
||||
#endif
|
||||
} else {
|
||||
int num_bits;
|
||||
int offset;
|
||||
uint16_t *prob2;
|
||||
#define prob_len prob2
|
||||
|
||||
prob2 = p + LZMA_IS_REP + state;
|
||||
if (!rc_is_bit_1(rc, prob2)) {
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
|
||||
prob2 = p + LZMA_LEN_CODER;
|
||||
} else {
|
||||
prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP;
|
||||
if (!rc_is_bit_1(rc, prob2)) {
|
||||
prob2 = (p + LZMA_IS_REP_0_LONG
|
||||
+ (state << LZMA_NUM_POS_BITS_MAX)
|
||||
+ pos_state
|
||||
);
|
||||
if (!rc_is_bit_1(rc, prob2)) {
|
||||
#if ENABLE_FEATURE_LZMA_FAST
|
||||
uint32_t pos;
|
||||
state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
|
||||
|
||||
pos = buffer_pos - rep0;
|
||||
if ((int32_t)pos < 0) {
|
||||
pos += header.dict_size;
|
||||
/* see unzip_bad_lzma_2.zip: */
|
||||
if (pos >= buffer_size) {
|
||||
dbg("%d pos:%d buffer_size:%d", __LINE__, pos, buffer_size);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
previous_byte = buffer[pos];
|
||||
goto one_byte1;
|
||||
#else
|
||||
state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
|
||||
len = 1;
|
||||
goto string;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
uint32_t distance;
|
||||
|
||||
prob2 += LZMA_IS_REP_G1 - LZMA_IS_REP_G0;
|
||||
distance = rep1;
|
||||
if (rc_is_bit_1(rc, prob2)) {
|
||||
prob2 += LZMA_IS_REP_G2 - LZMA_IS_REP_G1;
|
||||
distance = rep2;
|
||||
if (rc_is_bit_1(rc, prob2)) {
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
|
||||
prob2 = p + LZMA_REP_LEN_CODER;
|
||||
}
|
||||
|
||||
prob_len = prob2 + LZMA_LEN_CHOICE;
|
||||
num_bits = LZMA_LEN_NUM_LOW_BITS;
|
||||
if (!rc_is_bit_1(rc, prob_len)) {
|
||||
prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE
|
||||
+ (pos_state << LZMA_LEN_NUM_LOW_BITS);
|
||||
offset = 0;
|
||||
} else {
|
||||
prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE;
|
||||
if (!rc_is_bit_1(rc, prob_len)) {
|
||||
prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2
|
||||
+ (pos_state << LZMA_LEN_NUM_MID_BITS);
|
||||
offset = 1 << LZMA_LEN_NUM_LOW_BITS;
|
||||
num_bits += LZMA_LEN_NUM_MID_BITS - LZMA_LEN_NUM_LOW_BITS;
|
||||
} else {
|
||||
prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2;
|
||||
offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
|
||||
+ (1 << LZMA_LEN_NUM_MID_BITS));
|
||||
num_bits += LZMA_LEN_NUM_HIGH_BITS - LZMA_LEN_NUM_LOW_BITS;
|
||||
}
|
||||
}
|
||||
rc_bit_tree_decode(rc, prob_len, num_bits, &len);
|
||||
len += offset;
|
||||
|
||||
if (state < 4) {
|
||||
int pos_slot;
|
||||
uint16_t *prob3;
|
||||
|
||||
state += LZMA_NUM_LIT_STATES;
|
||||
prob3 = p + LZMA_POS_SLOT +
|
||||
((len < LZMA_NUM_LEN_TO_POS_STATES ? len :
|
||||
LZMA_NUM_LEN_TO_POS_STATES - 1)
|
||||
<< LZMA_NUM_POS_SLOT_BITS);
|
||||
rc_bit_tree_decode(rc, prob3,
|
||||
LZMA_NUM_POS_SLOT_BITS, &pos_slot);
|
||||
rep0 = pos_slot;
|
||||
if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
|
||||
int i2, mi2, num_bits2 = (pos_slot >> 1) - 1;
|
||||
rep0 = 2 | (pos_slot & 1);
|
||||
if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
|
||||
rep0 <<= num_bits2;
|
||||
prob3 = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
|
||||
} else {
|
||||
for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--)
|
||||
rep0 = (rep0 << 1) | rc_direct_bit(rc);
|
||||
rep0 <<= LZMA_NUM_ALIGN_BITS;
|
||||
// Note: (int32_t)rep0 may be < 0 here
|
||||
// (I have linux-3.3.4.tar.lzma which has it).
|
||||
// I moved the check after "++rep0 == 0" check below.
|
||||
prob3 = p + LZMA_ALIGN;
|
||||
}
|
||||
i2 = 1;
|
||||
mi2 = 1;
|
||||
while (num_bits2--) {
|
||||
if (rc_get_bit(rc, prob3 + mi2, &mi2))
|
||||
rep0 |= i2;
|
||||
i2 <<= 1;
|
||||
}
|
||||
}
|
||||
rep0++;
|
||||
if ((int32_t)rep0 <= 0) {
|
||||
if (rep0 == 0)
|
||||
break;
|
||||
dbg("%d rep0:%d", __LINE__, rep0);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
len += LZMA_MATCH_MIN_LEN;
|
||||
/*
|
||||
* LZMA SDK has this optimized:
|
||||
* it precalculates size and copies many bytes
|
||||
* in a loop with simpler checks, a-la:
|
||||
* do
|
||||
* *(dest) = *(dest + ofs);
|
||||
* while (++dest != lim);
|
||||
* and
|
||||
* do {
|
||||
* buffer[buffer_pos++] = buffer[pos];
|
||||
* if (++pos == header.dict_size)
|
||||
* pos = 0;
|
||||
* } while (--cur_len != 0);
|
||||
* Our code is slower (more checks per byte copy):
|
||||
*/
|
||||
IF_NOT_FEATURE_LZMA_FAST(string:)
|
||||
do {
|
||||
uint32_t pos = buffer_pos - rep0;
|
||||
if ((int32_t)pos < 0) {
|
||||
pos += header.dict_size;
|
||||
/* bug 10436 has an example file where this triggers: */
|
||||
//if ((int32_t)pos < 0)
|
||||
// goto bad;
|
||||
/* more stringent test (see unzip_bad_lzma_1.zip): */
|
||||
if (pos >= buffer_size)
|
||||
goto bad;
|
||||
}
|
||||
previous_byte = buffer[pos];
|
||||
IF_NOT_FEATURE_LZMA_FAST(one_byte2:)
|
||||
buffer[buffer_pos++] = previous_byte;
|
||||
if (buffer_pos == header.dict_size) {
|
||||
buffer_pos = 0;
|
||||
global_pos += header.dict_size;
|
||||
if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size)
|
||||
goto bad;
|
||||
IF_DESKTOP(total_written += header.dict_size;)
|
||||
}
|
||||
len--;
|
||||
} while (len != 0 && buffer_pos < header.dst_size);
|
||||
/* FIXME: ...........^^^^^
|
||||
* shouldn't it be "global_pos + buffer_pos < header.dst_size"?
|
||||
* It probably should, but it is a "do we accidentally
|
||||
* unpack more bytes than expected?" check - which
|
||||
* never happens for well-formed compression data...
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
IF_NOT_DESKTOP(int total_written = 0; /* success */)
|
||||
IF_DESKTOP(total_written += buffer_pos;)
|
||||
if (transformer_write(xstate, buffer, buffer_pos) != (ssize_t)buffer_pos) {
|
||||
bad:
|
||||
/* One of our users, bbunpack(), expects _us_ to emit
|
||||
* the error message (since it's the best place to give
|
||||
* potentially more detailed information).
|
||||
* Do not fail silently.
|
||||
*/
|
||||
bb_simple_error_msg("corrupted data");
|
||||
total_written = -1; /* failure */
|
||||
}
|
||||
rc_free(rc);
|
||||
free(p);
|
||||
free(buffer);
|
||||
return total_written;
|
||||
}
|
||||
}
|
154
busybox-1_37_0/archival/libarchive/decompress_unxz.c
Normal file
154
busybox-1_37_0/archival/libarchive/decompress_unxz.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file uses XZ Embedded library code which is written
|
||||
* by Lasse Collin <lasse.collin@tukaani.org>
|
||||
* and Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* See README file in unxz/ directory for more information.
|
||||
*
|
||||
* This file is:
|
||||
* Copyright (C) 2010 Denys Vlasenko <vda.linux@googlemail.com>
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#define XZ_FUNC FAST_FUNC
|
||||
#define XZ_EXTERN static
|
||||
|
||||
#define XZ_DEC_DYNALLOC
|
||||
|
||||
/* Skip check (rather than fail) of unsupported hash functions */
|
||||
#define XZ_DEC_ANY_CHECK 1
|
||||
|
||||
/* We use our own crc32 function */
|
||||
#define XZ_INTERNAL_CRC32 0
|
||||
static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
return ~crc32_block_endian0(~crc, buf, size, global_crc32_table);
|
||||
}
|
||||
|
||||
/* We use arch-optimized unaligned fixed-endian accessors.
|
||||
* They have been moved to libbb (proved to be useful elsewhere as well),
|
||||
* just check that we have them defined:
|
||||
*/
|
||||
#if !defined(get_unaligned_le32) \
|
||||
|| !defined(get_unaligned_be32) \
|
||||
|| !defined(put_unaligned_le32) \
|
||||
|| !defined(put_unaligned_be32)
|
||||
# error get_unaligned_le32 accessors are not defined
|
||||
#endif
|
||||
|
||||
#include "unxz/xz_dec_bcj.c"
|
||||
#include "unxz/xz_dec_lzma2.c"
|
||||
#include "unxz/xz_dec_stream.c"
|
||||
|
||||
IF_DESKTOP(long long) int FAST_FUNC
|
||||
unpack_xz_stream(transformer_state_t *xstate)
|
||||
{
|
||||
enum xz_ret xz_result;
|
||||
struct xz_buf iobuf;
|
||||
struct xz_dec *state;
|
||||
unsigned char *membuf;
|
||||
IF_DESKTOP(long long) int total = 0;
|
||||
|
||||
if (!global_crc32_table)
|
||||
global_crc32_new_table_le();
|
||||
|
||||
memset(&iobuf, 0, sizeof(iobuf));
|
||||
membuf = xmalloc(2 * BUFSIZ);
|
||||
iobuf.in = membuf;
|
||||
iobuf.out = membuf + BUFSIZ;
|
||||
iobuf.out_size = BUFSIZ;
|
||||
|
||||
if (!xstate || xstate->signature_skipped) {
|
||||
/* Preload XZ file signature */
|
||||
strcpy((char*)membuf, HEADER_MAGIC);
|
||||
iobuf.in_size = HEADER_MAGIC_SIZE;
|
||||
} /* else: let xz code read & check it */
|
||||
|
||||
/* Limit memory usage to about 64 MiB. */
|
||||
state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
|
||||
|
||||
xz_result = X_OK;
|
||||
while (1) {
|
||||
if (iobuf.in_pos == iobuf.in_size) {
|
||||
int rd = safe_read(xstate->src_fd, membuf, BUFSIZ);
|
||||
if (rd < 0) {
|
||||
bb_simple_error_msg(bb_msg_read_error);
|
||||
total = -1;
|
||||
break;
|
||||
}
|
||||
if (rd == 0 && xz_result == XZ_STREAM_END)
|
||||
break;
|
||||
iobuf.in_size = rd;
|
||||
iobuf.in_pos = 0;
|
||||
}
|
||||
if (xz_result == XZ_STREAM_END) {
|
||||
/*
|
||||
* Try to start decoding next concatenated stream.
|
||||
* Stream padding must always be a multiple of four
|
||||
* bytes to preserve four-byte alignment. To keep the
|
||||
* code slightly smaller, we aren't as strict here as
|
||||
* the .xz spec requires. We just skip all zero-bytes
|
||||
* without checking the alignment and thus can accept
|
||||
* files that aren't valid, e.g. the XZ utils test
|
||||
* files bad-0pad-empty.xz and bad-0catpad-empty.xz.
|
||||
*/
|
||||
do {
|
||||
if (membuf[iobuf.in_pos] != 0) {
|
||||
/* There is more data, but is it XZ data?
|
||||
* Example: dpkg-deb -f busybox_1.30.1-4_amd64.deb
|
||||
* reads control.tar.xz "control" file
|
||||
* inside the ar archive, but tar.xz
|
||||
* extraction code reaches end of xz data,
|
||||
* reached this code and reads the beginning
|
||||
* of data.tar.xz's ar header, which isn't xz data,
|
||||
* and prints "corrupted data".
|
||||
* The correct solution is to not read
|
||||
* past nested archive (to simulate EOF).
|
||||
* This is a workaround:
|
||||
*/
|
||||
if (membuf[iobuf.in_pos] != 0xfd) {
|
||||
/* It's definitely not a xz signature
|
||||
* (which is 0xfd,"7zXZ",0x00).
|
||||
*/
|
||||
goto end;
|
||||
}
|
||||
xz_dec_reset(state);
|
||||
goto do_run;
|
||||
}
|
||||
iobuf.in_pos++;
|
||||
} while (iobuf.in_pos < iobuf.in_size);
|
||||
}
|
||||
do_run:
|
||||
// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d",
|
||||
// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size);
|
||||
xz_result = xz_dec_run(state, &iobuf);
|
||||
// bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d",
|
||||
// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result);
|
||||
if (iobuf.out_pos) {
|
||||
xtransformer_write(xstate, iobuf.out, iobuf.out_pos);
|
||||
IF_DESKTOP(total += iobuf.out_pos;)
|
||||
iobuf.out_pos = 0;
|
||||
}
|
||||
if (xz_result == XZ_STREAM_END) {
|
||||
/*
|
||||
* Can just "break;" here, if not for concatenated
|
||||
* .xz streams.
|
||||
* Checking for padding may require buffer
|
||||
* replenishment. Can't do it here.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (xz_result != XZ_OK && xz_result != XZ_UNSUPPORTED_CHECK) {
|
||||
bb_simple_error_msg("corrupted data");
|
||||
total = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end:
|
||||
xz_dec_end(state);
|
||||
free(membuf);
|
||||
|
||||
return total;
|
||||
}
|
16
busybox-1_37_0/archival/libarchive/filter_accept_all.c
Normal file
16
busybox-1_37_0/archival/libarchive/filter_accept_all.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2002 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/* Accept any non-null name, its not really a filter at all */
|
||||
char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle)
|
||||
{
|
||||
if (archive_handle->file_header->name)
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
18
busybox-1_37_0/archival/libarchive/filter_accept_list.c
Normal file
18
busybox-1_37_0/archival/libarchive/filter_accept_list.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2002 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/*
|
||||
* Accept names that are in the accept list, ignoring reject list.
|
||||
*/
|
||||
char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle)
|
||||
{
|
||||
if (find_list_entry(archive_handle->accept, archive_handle->file_header->name))
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2002 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */
|
||||
|
||||
/*
|
||||
* Reassign the subarchive metadata parser based on the filename extension
|
||||
* e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz
|
||||
* or if its a .tar.bz2 make archive_handle->sub_archive handle that
|
||||
*/
|
||||
char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
|
||||
{
|
||||
/* Check the file entry is in the accept list */
|
||||
if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) {
|
||||
const char *name_ptr;
|
||||
|
||||
/* Find extension */
|
||||
name_ptr = strrchr(archive_handle->file_header->name, '.');
|
||||
if (!name_ptr)
|
||||
return EXIT_FAILURE;
|
||||
name_ptr++;
|
||||
|
||||
/* Modify the subarchive handler based on the extension */
|
||||
if (strcmp(name_ptr, "tar") == 0) {
|
||||
archive_handle->dpkg__action_data_subarchive = get_header_tar;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_GZ
|
||||
&& strcmp(name_ptr, "gz") == 0
|
||||
) {
|
||||
archive_handle->dpkg__action_data_subarchive = get_header_tar_gz;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_BZ2
|
||||
&& strcmp(name_ptr, "bz2") == 0
|
||||
) {
|
||||
archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_LZMA
|
||||
&& strcmp(name_ptr, "lzma") == 0
|
||||
) {
|
||||
archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_XZ
|
||||
&& strcmp(name_ptr, "xz") == 0
|
||||
) {
|
||||
archive_handle->dpkg__action_data_subarchive = get_header_tar_xz;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2002 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/*
|
||||
* Accept names that are in the accept list and not in the reject list
|
||||
*/
|
||||
char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle)
|
||||
{
|
||||
const char *key;
|
||||
const llist_t *reject_entry;
|
||||
const llist_t *accept_entry;
|
||||
|
||||
key = archive_handle->file_header->name;
|
||||
|
||||
/* If the key is in a reject list fail */
|
||||
reject_entry = find_list_entry2(archive_handle->reject, key);
|
||||
if (reject_entry) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Fail if an accept list was specified and the key wasnt in there */
|
||||
if (archive_handle->accept) {
|
||||
accept_entry = find_list_entry2(archive_handle->accept, key);
|
||||
if (!accept_entry) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accepted */
|
||||
return EXIT_SUCCESS;
|
||||
}
|
53
busybox-1_37_0/archival/libarchive/find_list_entry.c
Normal file
53
busybox-1_37_0/archival/libarchive/find_list_entry.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2002 by Glenn McGrath
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/* Find a string in a shell pattern list */
|
||||
const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename)
|
||||
{
|
||||
while (list) {
|
||||
if (fnmatch(list->data, filename, 0) == 0) {
|
||||
return list;
|
||||
}
|
||||
list = list->link;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Same, but compares only path components present in pattern
|
||||
* (extra trailing path components in filename are assumed to match)
|
||||
*/
|
||||
const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
int pattern_slash_cnt;
|
||||
const char *c;
|
||||
char *d;
|
||||
|
||||
while (list) {
|
||||
c = list->data;
|
||||
pattern_slash_cnt = 0;
|
||||
while (*c)
|
||||
if (*c++ == '/') pattern_slash_cnt++;
|
||||
c = filename;
|
||||
d = buf;
|
||||
/* paranoia is better than buffer overflows */
|
||||
while (*c && d != buf + sizeof(buf)-1) {
|
||||
if (*c == '/' && --pattern_slash_cnt < 0)
|
||||
break;
|
||||
*d++ = *c++;
|
||||
}
|
||||
*d = '\0';
|
||||
if (fnmatch(list->data, buf, 0) == 0) {
|
||||
return list;
|
||||
}
|
||||
list = list->link;
|
||||
}
|
||||
return NULL;
|
||||
}
|
146
busybox-1_37_0/archival/libarchive/get_header_ar.c
Normal file
146
busybox-1_37_0/archival/libarchive/get_header_ar.c
Normal file
@ -0,0 +1,146 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright 2001 Glenn McGrath.
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
#include "ar_.h"
|
||||
|
||||
/* WARNING: Clobbers str[len], so fields must be read in reverse order! */
|
||||
static unsigned read_num(char *str, int base, int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* ar fields are fixed length text strings (padded with spaces).
|
||||
* Ensure bb_strtou doesn't read past the field in case the full
|
||||
* width is used. */
|
||||
str[len] = 0;
|
||||
|
||||
/* This code works because
|
||||
* on misformatted numbers bb_strtou returns all-ones */
|
||||
err = bb_strtou(str, NULL, base);
|
||||
if (err == -1)
|
||||
bb_simple_error_msg_and_die("invalid ar header");
|
||||
return err;
|
||||
}
|
||||
|
||||
char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
|
||||
{
|
||||
file_header_t *typed = archive_handle->file_header;
|
||||
unsigned size;
|
||||
union {
|
||||
char raw[60];
|
||||
struct ar_header formatted;
|
||||
} ar;
|
||||
|
||||
/* dont use xread as we want to handle the error ourself */
|
||||
if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
|
||||
/* End Of File */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* ar header starts on an even byte (2 byte aligned)
|
||||
* '\n' is used for padding
|
||||
*/
|
||||
if (ar.raw[0] == '\n') {
|
||||
/* fix up the header, we started reading 1 byte too early */
|
||||
memmove(ar.raw, &ar.raw[1], 59);
|
||||
ar.raw[59] = xread_char(archive_handle->src_fd);
|
||||
archive_handle->offset++;
|
||||
}
|
||||
archive_handle->offset += 60;
|
||||
|
||||
if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
|
||||
bb_simple_error_msg_and_die("invalid ar header");
|
||||
|
||||
/*
|
||||
* Note that the fields MUST be read in reverse order as
|
||||
* read_num() clobbers the next byte after the field!
|
||||
* Order is: name, date, uid, gid, mode, size, magic.
|
||||
*/
|
||||
typed->size = size = read_num(ar.formatted.size, 10,
|
||||
sizeof(ar.formatted.size));
|
||||
|
||||
/* special filenames have '/' as the first character */
|
||||
if (ar.formatted.name[0] == '/') {
|
||||
if (ar.formatted.name[1] == ' ') {
|
||||
/* This is the index of symbols in the file for compilers */
|
||||
data_skip(archive_handle);
|
||||
archive_handle->offset += size;
|
||||
return get_header_ar(archive_handle); /* Return next header */
|
||||
}
|
||||
#if ENABLE_FEATURE_AR_LONG_FILENAMES
|
||||
if (ar.formatted.name[1] == '/') {
|
||||
/* If the second char is a '/' then this entries data section
|
||||
* stores long filename for multiple entries, they are stored
|
||||
* in static variable long_names for use in future entries
|
||||
*/
|
||||
archive_handle->ar__long_name_size = size;
|
||||
free(archive_handle->ar__long_names);
|
||||
archive_handle->ar__long_names = xzalloc(size + 1);
|
||||
xread(archive_handle->src_fd, archive_handle->ar__long_names, size);
|
||||
archive_handle->offset += size;
|
||||
/* Return next header */
|
||||
return get_header_ar(archive_handle);
|
||||
}
|
||||
#else
|
||||
bb_simple_error_msg_and_die("long filenames not supported");
|
||||
#endif
|
||||
}
|
||||
/* Only size is always present, the rest may be missing in
|
||||
* long filename pseudo file. Thus we decode the rest
|
||||
* after dealing with long filename pseudo file.
|
||||
*
|
||||
* GNU binutils in deterministic mode hard codes mode to 0644 (NOT
|
||||
* 0100644). AR archives can only contain files, so force file
|
||||
* mode.
|
||||
*/
|
||||
typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode)) | S_IFREG;
|
||||
typed->gid = read_num(ar.formatted.gid, 10, sizeof(ar.formatted.gid));
|
||||
typed->uid = read_num(ar.formatted.uid, 10, sizeof(ar.formatted.uid));
|
||||
typed->mtime = read_num(ar.formatted.date, 10, sizeof(ar.formatted.date));
|
||||
|
||||
#if ENABLE_FEATURE_AR_LONG_FILENAMES
|
||||
if (ar.formatted.name[0] == '/') {
|
||||
unsigned long_offset;
|
||||
|
||||
/* The number after the '/' indicates the offset in the ar data section
|
||||
* (saved in ar__long_names) that contains the real filename */
|
||||
long_offset = read_num(&ar.formatted.name[1], 10,
|
||||
sizeof(ar.formatted.name) - 1);
|
||||
if (long_offset >= archive_handle->ar__long_name_size) {
|
||||
bb_simple_error_msg_and_die("can't resolve long filename");
|
||||
}
|
||||
typed->name = xstrdup(archive_handle->ar__long_names + long_offset);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* short filenames */
|
||||
typed->name = xstrndup(ar.formatted.name, 16);
|
||||
}
|
||||
|
||||
typed->name[strcspn(typed->name, " /")] = '\0';
|
||||
|
||||
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
|
||||
archive_handle->action_header(typed);
|
||||
#if ENABLE_DPKG || ENABLE_DPKG_DEB
|
||||
if (archive_handle->dpkg__sub_archive) {
|
||||
struct archive_handle_t *sa = archive_handle->dpkg__sub_archive;
|
||||
while (archive_handle->dpkg__action_data_subarchive(sa) == EXIT_SUCCESS)
|
||||
continue;
|
||||
create_links_from_list(sa->link_placeholders);
|
||||
} else
|
||||
#endif
|
||||
archive_handle->action_data(archive_handle);
|
||||
} else {
|
||||
data_skip(archive_handle);
|
||||
}
|
||||
|
||||
archive_handle->offset += typed->size;
|
||||
/* Set the file pointer to the correct spot, we may have been reading a compressed file */
|
||||
lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
192
busybox-1_37_0/archival/libarchive/get_header_cpio.c
Normal file
192
busybox-1_37_0/archival/libarchive/get_header_cpio.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright 2002 Laurence Anderson
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
typedef struct hardlinks_t {
|
||||
struct hardlinks_t *next;
|
||||
int inode; /* TODO: must match maj/min too! */
|
||||
int mode ;
|
||||
int mtime; /* These three are useful only in corner case */
|
||||
int uid ; /* of hardlinks with zero size body */
|
||||
int gid ;
|
||||
char name[1];
|
||||
} hardlinks_t;
|
||||
|
||||
char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
|
||||
{
|
||||
file_header_t *file_header = archive_handle->file_header;
|
||||
char cpio_header[111];
|
||||
int namesize;
|
||||
int major, minor, nlink, mode, inode;
|
||||
unsigned size, uid, gid, mtime;
|
||||
|
||||
/* There can be padding before archive header */
|
||||
data_align(archive_handle, 4);
|
||||
|
||||
size = full_read(archive_handle->src_fd, cpio_header, 110);
|
||||
if (size == 0) {
|
||||
goto create_hardlinks;
|
||||
}
|
||||
if (size != 110) {
|
||||
bb_simple_error_msg_and_die("short read");
|
||||
}
|
||||
archive_handle->offset += 110;
|
||||
|
||||
if (!is_prefixed_with(&cpio_header[0], "07070")
|
||||
|| (cpio_header[5] != '1' && cpio_header[5] != '2')
|
||||
) {
|
||||
bb_simple_error_msg_and_die("unsupported cpio format, use newc or crc");
|
||||
}
|
||||
|
||||
cpio_header[110] = '\0'; /* sscanf may call strlen which may break without this */
|
||||
if (sscanf(cpio_header + 6,
|
||||
"%8x" "%8x" "%8x" "%8x"
|
||||
"%8x" "%8x" "%8x" /*maj,min:*/ "%*16c"
|
||||
/*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/,
|
||||
&inode, &mode, &uid, &gid,
|
||||
&nlink, &mtime, &size,
|
||||
&major, &minor, &namesize) != 10)
|
||||
bb_simple_error_msg_and_die("damaged cpio file");
|
||||
file_header->mode = mode;
|
||||
/* "cpio -R USER:GRP" support: */
|
||||
if (archive_handle->cpio__owner.uid != (uid_t)-1L)
|
||||
uid = archive_handle->cpio__owner.uid;
|
||||
if (archive_handle->cpio__owner.gid != (gid_t)-1L)
|
||||
gid = archive_handle->cpio__owner.gid;
|
||||
file_header->uid = uid;
|
||||
file_header->gid = gid;
|
||||
file_header->mtime = mtime;
|
||||
file_header->size = size;
|
||||
|
||||
namesize &= 0x1fff; /* paranoia: limit names to 8k chars */
|
||||
file_header->name = xzalloc(namesize + 1);
|
||||
/* Read in filename */
|
||||
xread(archive_handle->src_fd, file_header->name, namesize);
|
||||
if (file_header->name[0] == '/') {
|
||||
/* Testcase: echo /etc/hosts | cpio -pvd /tmp
|
||||
* Without this code, it tries to unpack /etc/hosts
|
||||
* into "/etc/hosts", not "etc/hosts".
|
||||
*/
|
||||
char *p = file_header->name;
|
||||
do p++; while (*p == '/');
|
||||
overlapping_strcpy(file_header->name, p);
|
||||
}
|
||||
archive_handle->offset += namesize;
|
||||
|
||||
/* Update offset amount and skip padding before file contents */
|
||||
data_align(archive_handle, 4);
|
||||
|
||||
if (strcmp(file_header->name, cpio_TRAILER) == 0) {
|
||||
/* Always round up. ">> 9" divides by 512 */
|
||||
archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9;
|
||||
goto create_hardlinks;
|
||||
}
|
||||
|
||||
file_header->link_target = NULL;
|
||||
if (S_ISLNK(file_header->mode)) {
|
||||
file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */
|
||||
file_header->link_target = xzalloc(file_header->size + 1);
|
||||
xread(archive_handle->src_fd, file_header->link_target, file_header->size);
|
||||
archive_handle->offset += file_header->size;
|
||||
file_header->size = 0; /* Stop possible seeks in future */
|
||||
}
|
||||
|
||||
// TODO: data_extract_all can't deal with hardlinks to non-files...
|
||||
// when fixed, change S_ISREG to !S_ISDIR here
|
||||
|
||||
if (nlink > 1 && S_ISREG(file_header->mode)) {
|
||||
hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
|
||||
new->inode = inode;
|
||||
new->mode = mode ;
|
||||
new->mtime = mtime;
|
||||
new->uid = uid ;
|
||||
new->gid = gid ;
|
||||
strcpy(new->name, file_header->name);
|
||||
/* Put file on a linked list for later */
|
||||
if (size == 0) {
|
||||
new->next = archive_handle->cpio__hardlinks_to_create;
|
||||
archive_handle->cpio__hardlinks_to_create = new;
|
||||
return EXIT_SUCCESS; /* Skip this one */
|
||||
/* TODO: this breaks cpio -t (it does not show hardlinks) */
|
||||
}
|
||||
new->next = archive_handle->cpio__created_hardlinks;
|
||||
archive_handle->cpio__created_hardlinks = new;
|
||||
}
|
||||
file_header->device = makedev(major, minor);
|
||||
|
||||
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
|
||||
archive_handle->action_data(archive_handle);
|
||||
//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run:
|
||||
//cpio: etc/hosts not created: newer or same age file exists
|
||||
//etc/hosts <-- should NOT show it
|
||||
//2 blocks <-- should say "0 blocks"
|
||||
archive_handle->action_header(file_header);
|
||||
} else {
|
||||
data_skip(archive_handle);
|
||||
}
|
||||
|
||||
archive_handle->offset += file_header->size;
|
||||
|
||||
free(file_header->link_target);
|
||||
free(file_header->name);
|
||||
file_header->link_target = NULL;
|
||||
file_header->name = NULL;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
create_hardlinks:
|
||||
free(file_header->link_target);
|
||||
free(file_header->name);
|
||||
|
||||
while (archive_handle->cpio__hardlinks_to_create) {
|
||||
hardlinks_t *cur;
|
||||
hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create;
|
||||
|
||||
archive_handle->cpio__hardlinks_to_create = make_me->next;
|
||||
|
||||
memset(file_header, 0, sizeof(*file_header));
|
||||
file_header->mtime = make_me->mtime;
|
||||
file_header->name = make_me->name;
|
||||
file_header->mode = make_me->mode;
|
||||
file_header->uid = make_me->uid;
|
||||
file_header->gid = make_me->gid;
|
||||
/*file_header->size = 0;*/
|
||||
/*file_header->link_target = NULL;*/
|
||||
|
||||
/* Try to find a file we are hardlinked to */
|
||||
cur = archive_handle->cpio__created_hardlinks;
|
||||
while (cur) {
|
||||
/* TODO: must match maj/min too! */
|
||||
if (cur->inode == make_me->inode) {
|
||||
file_header->link_target = cur->name;
|
||||
/* link_target != NULL, size = 0: "I am a hardlink" */
|
||||
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
|
||||
archive_handle->action_data(archive_handle);
|
||||
free(make_me);
|
||||
goto next_link;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
/* Oops... no file with such inode was created... do it now
|
||||
* (happens when hardlinked files are empty (zero length)) */
|
||||
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
|
||||
archive_handle->action_data(archive_handle);
|
||||
/* Move to the list of created hardlinked files */
|
||||
make_me->next = archive_handle->cpio__created_hardlinks;
|
||||
archive_handle->cpio__created_hardlinks = make_me;
|
||||
next_link: ;
|
||||
}
|
||||
|
||||
while (archive_handle->cpio__created_hardlinks) {
|
||||
hardlinks_t *p = archive_handle->cpio__created_hardlinks;
|
||||
archive_handle->cpio__created_hardlinks = p->next;
|
||||
free(p);
|
||||
}
|
||||
|
||||
return EXIT_FAILURE; /* "No more files to process" */
|
||||
}
|
491
busybox-1_37_0/archival/libarchive/get_header_tar.c
Normal file
491
busybox-1_37_0/archival/libarchive/get_header_tar.c
Normal file
@ -0,0 +1,491 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*
|
||||
* FIXME:
|
||||
* In privileged mode if uname and gname map to a uid and gid then use the
|
||||
* mapped value instead of the uid/gid values in tar header
|
||||
*
|
||||
* References:
|
||||
* GNU tar and star man pages,
|
||||
* Opengroup's ustar interchange format,
|
||||
* http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
typedef uint32_t aliased_uint32_t FIX_ALIASING;
|
||||
typedef off_t aliased_off_t FIX_ALIASING;
|
||||
|
||||
/* NB: _DESTROYS_ str[len] character! */
|
||||
static unsigned long long getOctal(char *str, int len)
|
||||
{
|
||||
unsigned long long v;
|
||||
char *end;
|
||||
/* NB: leading spaces are allowed. Using strtoull to handle that.
|
||||
* The downside is that we accept e.g. "-123" too :(
|
||||
*/
|
||||
str[len] = '\0';
|
||||
v = strtoull(str, &end, 8);
|
||||
/* std: "Each numeric field is terminated by one or more
|
||||
* <space> or NUL characters". We must support ' '! */
|
||||
if (*end != '\0' && *end != ' ') {
|
||||
int8_t first = str[0];
|
||||
if (!(first & 0x80))
|
||||
bb_simple_error_msg_and_die("corrupted octal value in tar header");
|
||||
/*
|
||||
* GNU tar uses "base-256 encoding" for very large numbers.
|
||||
* Encoding is binary, with highest bit always set as a marker
|
||||
* and sign in next-highest bit:
|
||||
* 80 00 .. 00 - zero
|
||||
* bf ff .. ff - largest positive number
|
||||
* ff ff .. ff - minus 1
|
||||
* c0 00 .. 00 - smallest negative number
|
||||
*
|
||||
* Example of tar file with 8914993153 (0x213600001) byte file.
|
||||
* Field starts at offset 7c:
|
||||
* 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
|
||||
* 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
|
||||
*
|
||||
* NB: tarballs with NEGATIVE unix times encoded that way were seen!
|
||||
*/
|
||||
/* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
|
||||
first <<= 1;
|
||||
first >>= 1; /* now 7th bit = 6th bit */
|
||||
v = first; /* sign-extend 8 bits to 64 */
|
||||
while (--len != 0)
|
||||
v = (v << 8) + (uint8_t) *++str;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
#define GET_OCTAL(a) getOctal((a), sizeof(a))
|
||||
|
||||
#define TAR_EXTD (ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX)
|
||||
#if !TAR_EXTD
|
||||
#define process_pax_hdr(archive_handle, sz, global) \
|
||||
process_pax_hdr(archive_handle, sz)
|
||||
#endif
|
||||
/* "global" is 0 or 1 */
|
||||
static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
|
||||
{
|
||||
#if !TAR_EXTD
|
||||
unsigned blk_sz = (sz + 511) & (~511);
|
||||
seek_by_read(archive_handle->src_fd, blk_sz);
|
||||
#else
|
||||
unsigned blk_sz = (sz + 511) & (~511);
|
||||
char *buf, *p;
|
||||
|
||||
p = buf = xmalloc(blk_sz + 1);
|
||||
xread(archive_handle->src_fd, buf, blk_sz);
|
||||
archive_handle->offset += blk_sz;
|
||||
|
||||
/* prevent bb_strtou from running off the buffer */
|
||||
buf[sz] = '\0';
|
||||
|
||||
while (sz != 0) {
|
||||
char *end, *value;
|
||||
unsigned len;
|
||||
|
||||
/* Every record has this format: "LEN NAME=VALUE\n" */
|
||||
len = bb_strtou(p, &end, 10);
|
||||
/* expect errno to be EINVAL, because the character
|
||||
* following the digits should be a space
|
||||
*/
|
||||
p += len;
|
||||
sz -= len;
|
||||
if (
|
||||
/** (int)sz < 0 - not good enough for huge malicious VALUE of 2^32-1 */
|
||||
(int)(sz|len) < 0 /* this works */
|
||||
|| len == 0
|
||||
|| errno != EINVAL
|
||||
|| *end != ' '
|
||||
) {
|
||||
bb_simple_error_msg("malformed extended header, skipped");
|
||||
// More verbose version:
|
||||
//bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped",
|
||||
// archive_handle->offset - (sz + len));
|
||||
break;
|
||||
}
|
||||
/* overwrite the terminating newline with NUL
|
||||
* (we do not bother to check that it *was* a newline)
|
||||
*/
|
||||
p[-1] = '\0';
|
||||
value = end + 1;
|
||||
|
||||
# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
if (!global) {
|
||||
if (is_prefixed_with(value, "path=")) {
|
||||
value += sizeof("path=") - 1;
|
||||
free(archive_handle->tar__longname);
|
||||
archive_handle->tar__longname = xstrdup(value);
|
||||
continue;
|
||||
}
|
||||
if (is_prefixed_with(value, "linkpath=")) {
|
||||
value += sizeof("linkpath=") - 1;
|
||||
free(archive_handle->tar__linkname);
|
||||
archive_handle->tar__linkname = xstrdup(value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# if ENABLE_FEATURE_TAR_SELINUX
|
||||
/* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
|
||||
* This is what Red Hat's patched version of tar uses.
|
||||
*/
|
||||
# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
|
||||
if (is_prefixed_with(value, SELINUX_CONTEXT_KEYWORD"=")) {
|
||||
value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
|
||||
free(archive_handle->tar__sctx[global]);
|
||||
archive_handle->tar__sctx[global] = xstrdup(value);
|
||||
continue;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
free(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
static void die_if_bad_fnamesize(off_t sz)
|
||||
{
|
||||
if ((uoff_t)sz > 0xfff) /* more than 4k?! no funny business please */
|
||||
bb_simple_error_msg_and_die("bad archive");
|
||||
}
|
||||
#endif
|
||||
|
||||
char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
|
||||
{
|
||||
file_header_t *file_header = archive_handle->file_header;
|
||||
struct tar_header_t tar;
|
||||
char *cp;
|
||||
int tar_typeflag; /* can be "char", "int" seems give smaller code */
|
||||
int i, sum_u, sum;
|
||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||
int sum_s;
|
||||
#endif
|
||||
int parse_names;
|
||||
|
||||
/* Our "private data" */
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
# define p_longname (archive_handle->tar__longname)
|
||||
# define p_linkname (archive_handle->tar__linkname)
|
||||
#else
|
||||
# define p_longname 0
|
||||
# define p_linkname 0
|
||||
#endif
|
||||
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
|
||||
again:
|
||||
#endif
|
||||
/* Align header */
|
||||
data_align(archive_handle, 512);
|
||||
|
||||
again_after_align:
|
||||
|
||||
#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
|
||||
/* to prevent misdetection of bz2 sig */
|
||||
*(aliased_uint32_t*)&tar = 0;
|
||||
i = full_read(archive_handle->src_fd, &tar, 512);
|
||||
/* If GNU tar sees EOF in above read, it says:
|
||||
* "tar: A lone zero block at N", where N = kilobyte
|
||||
* where EOF was met (not EOF block, actual EOF!),
|
||||
* and exits with EXIT_SUCCESS.
|
||||
* We will mimic exit(EXIT_SUCCESS), although we will not mimic
|
||||
* the message and we don't check whether we indeed
|
||||
* saw zero block directly before this. */
|
||||
if (i == 0) {
|
||||
/* GNU tar 1.29 will be silent if tar archive ends abruptly
|
||||
* (if there are no zero blocks at all, and last read returns zero,
|
||||
* not short read 0 < len < 512). Complain only if
|
||||
* the very first read fails. Grrr.
|
||||
*/
|
||||
if (archive_handle->offset == 0)
|
||||
bb_simple_error_msg("short read");
|
||||
/* this merely signals end of archive, not exit(1): */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (i != 512) {
|
||||
IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
|
||||
bb_simple_error_msg_and_die("short read");
|
||||
}
|
||||
|
||||
#else
|
||||
i = 512;
|
||||
xread(archive_handle->src_fd, &tar, i);
|
||||
#endif
|
||||
archive_handle->offset += i;
|
||||
|
||||
/* If there is no filename its an empty header */
|
||||
if (tar.name[0] == 0 && tar.prefix[0] == 0
|
||||
/* Have seen a tar archive with pax 'x' header supplying UTF8 filename,
|
||||
* with actual file having all name fields NUL-filled. Check this: */
|
||||
&& !p_longname
|
||||
) {
|
||||
if (archive_handle->tar__end) {
|
||||
/* Second consecutive empty header - end of archive.
|
||||
* Read until the end to empty the pipe from gz or bz2
|
||||
*/
|
||||
while (full_read(archive_handle->src_fd, &tar, 512) == 512)
|
||||
continue;
|
||||
return EXIT_FAILURE; /* "end of archive" */
|
||||
}
|
||||
archive_handle->tar__end = 1;
|
||||
return EXIT_SUCCESS; /* "decoded one header" */
|
||||
}
|
||||
archive_handle->tar__end = 0;
|
||||
|
||||
/* Check header has valid magic, "ustar" is for the proper tar,
|
||||
* five NULs are for the old tar format */
|
||||
if (!is_prefixed_with(tar.magic, "ustar")
|
||||
&& (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
|
||||
|| memcmp(tar.magic, "\0\0\0\0", 5) != 0)
|
||||
) {
|
||||
#if ENABLE_FEATURE_TAR_AUTODETECT
|
||||
autodetect:
|
||||
/* Two different causes for lseek() != 0:
|
||||
* unseekable fd (would like to support that too, but...),
|
||||
* or not first block (false positive, it's not .gz/.bz2!) */
|
||||
if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
|
||||
goto err;
|
||||
if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 0) != 0)
|
||||
err:
|
||||
bb_simple_error_msg_and_die("invalid tar magic");
|
||||
archive_handle->offset = 0;
|
||||
goto again_after_align;
|
||||
#endif
|
||||
bb_simple_error_msg_and_die("invalid tar magic");
|
||||
}
|
||||
|
||||
/* Do checksum on headers.
|
||||
* POSIX says that checksum is done on unsigned bytes, but
|
||||
* Sun and HP-UX gets it wrong... more details in
|
||||
* GNU tar source. */
|
||||
sum_u = ' ' * sizeof(tar.chksum);
|
||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||
sum_s = sum_u;
|
||||
#endif
|
||||
for (i = 0; i < 148; i++) {
|
||||
sum_u += ((unsigned char*)&tar)[i];
|
||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||
sum_s += ((signed char*)&tar)[i];
|
||||
#endif
|
||||
}
|
||||
for (i = 156; i < 512; i++) {
|
||||
sum_u += ((unsigned char*)&tar)[i];
|
||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||
sum_s += ((signed char*)&tar)[i];
|
||||
#endif
|
||||
}
|
||||
/* Most tarfiles have tar.chksum NUL or space terminated, but
|
||||
* github.com decided to be "special" and have unterminated field:
|
||||
* 0090: 30343300 30303031 33323731 30000000 |043.000132710...|
|
||||
* ^^^^^^^^|
|
||||
* Need to use GET_OCTAL. This overwrites tar.typeflag ---+
|
||||
* (the '0' char immediately after chksum in example above) with NUL.
|
||||
*/
|
||||
tar_typeflag = (uint8_t)tar.typeflag; /* save it */
|
||||
sum = GET_OCTAL(tar.chksum);
|
||||
if (sum_u != sum
|
||||
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
|
||||
) {
|
||||
bb_simple_error_msg_and_die("invalid tar header checksum");
|
||||
}
|
||||
|
||||
/* GET_OCTAL trashes subsequent field, therefore we call it
|
||||
* on fields in reverse order */
|
||||
if (tar.devmajor[0]) {
|
||||
char t = tar.prefix[0];
|
||||
/* we trash prefix[0] here, but we DO need it later! */
|
||||
unsigned minor = GET_OCTAL(tar.devminor);
|
||||
unsigned major = GET_OCTAL(tar.devmajor);
|
||||
file_header->device = makedev(major, minor);
|
||||
tar.prefix[0] = t;
|
||||
}
|
||||
|
||||
/* 0 is reserved for high perf file, treat as normal file */
|
||||
if (tar_typeflag == '\0') tar_typeflag = '0';
|
||||
parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
|
||||
|
||||
file_header->link_target = NULL;
|
||||
if (!p_linkname && parse_names && tar.linkname[0]) {
|
||||
file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
|
||||
/* FIXME: what if we have non-link object with link_target? */
|
||||
/* Will link_target be free()ed? */
|
||||
}
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
|
||||
file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
|
||||
#endif
|
||||
file_header->mtime = GET_OCTAL(tar.mtime);
|
||||
file_header->size = GET_OCTAL(tar.size);
|
||||
file_header->gid = GET_OCTAL(tar.gid);
|
||||
file_header->uid = GET_OCTAL(tar.uid);
|
||||
/* Set bits 0-11 of the files mode */
|
||||
file_header->mode = 07777 & GET_OCTAL(tar.mode);
|
||||
|
||||
file_header->name = NULL;
|
||||
if (!p_longname && parse_names) {
|
||||
/* we trash mode[0] here, it's ok */
|
||||
//tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
|
||||
tar.mode[0] = '\0';
|
||||
if (tar.prefix[0]) {
|
||||
/* and padding[0] */
|
||||
//tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
|
||||
tar.padding[0] = '\0';
|
||||
file_header->name = concat_path_file(tar.prefix, tar.name);
|
||||
} else
|
||||
file_header->name = xstrdup(tar.name);
|
||||
}
|
||||
|
||||
switch (tar_typeflag) {
|
||||
case '1': /* hardlink */
|
||||
/* we mark hardlinks as regular files with zero size and a link name */
|
||||
file_header->mode |= S_IFREG;
|
||||
/* on size of link fields from star(4)
|
||||
* ... For tar archives written by pre POSIX.1-1988
|
||||
* implementations, the size field usually contains the size of
|
||||
* the file and needs to be ignored as no data may follow this
|
||||
* header type. For POSIX.1-1988 compliant archives, the size
|
||||
* field needs to be 0. For POSIX.1-2001 compliant archives,
|
||||
* the size field may be non zero, indicating that file data is
|
||||
* included in the archive.
|
||||
* i.e; always assume this is zero for safety.
|
||||
*/
|
||||
goto size0;
|
||||
case '7':
|
||||
/* case 0: */
|
||||
case '0':
|
||||
#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
|
||||
if (file_header->name && last_char_is(file_header->name, '/')) {
|
||||
goto set_dir;
|
||||
}
|
||||
#endif
|
||||
file_header->mode |= S_IFREG;
|
||||
break;
|
||||
case '2':
|
||||
file_header->mode |= S_IFLNK;
|
||||
/* have seen tarballs with size field containing
|
||||
* the size of the link target's name */
|
||||
size0:
|
||||
file_header->size = 0;
|
||||
break;
|
||||
case '3':
|
||||
file_header->mode |= S_IFCHR;
|
||||
goto size0; /* paranoia */
|
||||
case '4':
|
||||
file_header->mode |= S_IFBLK;
|
||||
goto size0;
|
||||
case '5':
|
||||
IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
|
||||
file_header->mode |= S_IFDIR;
|
||||
goto size0;
|
||||
case '6':
|
||||
file_header->mode |= S_IFIFO;
|
||||
goto size0;
|
||||
case 'g': /* pax global header */
|
||||
case 'x': { /* pax extended header */
|
||||
if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
|
||||
goto skip_ext_hdr;
|
||||
process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
|
||||
goto again_after_align;
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */
|
||||
case 'L':
|
||||
/* free: paranoia: tar with several consecutive longnames */
|
||||
free(p_longname);
|
||||
/* For paranoia reasons we allocate extra NUL char */
|
||||
die_if_bad_fnamesize(file_header->size);
|
||||
p_longname = xzalloc(file_header->size + 1);
|
||||
/* We read ASCIZ string, including NUL */
|
||||
xread(archive_handle->src_fd, p_longname, file_header->size);
|
||||
archive_handle->offset += file_header->size;
|
||||
/* return get_header_tar(archive_handle); */
|
||||
/* gcc 4.1.1 didn't optimize it into jump */
|
||||
/* so we will do it ourself, this also saves stack */
|
||||
goto again;
|
||||
case 'K':
|
||||
free(p_linkname);
|
||||
die_if_bad_fnamesize(file_header->size);
|
||||
p_linkname = xzalloc(file_header->size + 1);
|
||||
xread(archive_handle->src_fd, p_linkname, file_header->size);
|
||||
archive_handle->offset += file_header->size;
|
||||
/* return get_header_tar(archive_handle); */
|
||||
goto again;
|
||||
/*
|
||||
* case 'S': // Sparse file
|
||||
* Was seen in the wild. Not supported (yet?).
|
||||
* See https://www.gnu.org/software/tar/manual/html_section/tar_92.html
|
||||
* for the format. (An "Old GNU Format" was seen, not PAX formats).
|
||||
*/
|
||||
// case 'D': /* GNU dump dir */
|
||||
// case 'M': /* Continuation of multi volume archive */
|
||||
// case 'N': /* Old GNU for names > 100 characters */
|
||||
case 'V': /* Volume header */
|
||||
; /* Fall through to skip it */
|
||||
#endif
|
||||
}
|
||||
skip_ext_hdr:
|
||||
{
|
||||
off_t sz;
|
||||
bb_error_msg("warning: skipping header '%c'", tar_typeflag);
|
||||
sz = (file_header->size + 511) & ~(off_t)511;
|
||||
archive_handle->offset += sz;
|
||||
sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
|
||||
while (sz--)
|
||||
xread(archive_handle->src_fd, &tar, 512);
|
||||
/* return get_header_tar(archive_handle); */
|
||||
goto again_after_align;
|
||||
}
|
||||
default:
|
||||
bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
if (p_longname) {
|
||||
file_header->name = p_longname;
|
||||
p_longname = NULL;
|
||||
}
|
||||
if (p_linkname) {
|
||||
file_header->link_target = p_linkname;
|
||||
p_linkname = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Everything up to and including last ".." component is stripped */
|
||||
overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name));
|
||||
//TODO: do the same for file_header->link_target?
|
||||
|
||||
/* Strip trailing '/' in directories */
|
||||
/* Must be done after mode is set as '/' is used to check if it's a directory */
|
||||
cp = last_char_is(file_header->name, '/');
|
||||
|
||||
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
|
||||
archive_handle->action_header(/*archive_handle->*/ file_header);
|
||||
/* Note that we kill the '/' only after action_header() */
|
||||
/* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
|
||||
if (cp)
|
||||
*cp = '\0';
|
||||
archive_handle->action_data(archive_handle);
|
||||
if (archive_handle->accept || archive_handle->reject
|
||||
|| (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
|
||||
) {
|
||||
llist_add_to(&archive_handle->passed, file_header->name);
|
||||
} else /* Caller isn't interested in list of unpacked files */
|
||||
free(file_header->name);
|
||||
} else {
|
||||
data_skip(archive_handle);
|
||||
free(file_header->name);
|
||||
}
|
||||
archive_handle->offset += file_header->size;
|
||||
|
||||
free(file_header->link_target);
|
||||
/* Do not free(file_header->name)!
|
||||
* It might be inserted in archive_handle->passed - see above */
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
free(file_header->tar__uname);
|
||||
free(file_header->tar__gname);
|
||||
#endif
|
||||
return EXIT_SUCCESS; /* "decoded one header" */
|
||||
}
|
20
busybox-1_37_0/archival/libarchive/get_header_tar_bz2.c
Normal file
20
busybox-1_37_0/archival/libarchive/get_header_tar_bz2.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
|
||||
{
|
||||
/* Can't lseek over pipes */
|
||||
archive_handle->seek = seek_by_read;
|
||||
|
||||
fork_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
|
||||
archive_handle->offset = 0;
|
||||
while (get_header_tar(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
/* Can only do one file at a time */
|
||||
return EXIT_FAILURE;
|
||||
}
|
20
busybox-1_37_0/archival/libarchive/get_header_tar_gz.c
Normal file
20
busybox-1_37_0/archival/libarchive/get_header_tar_gz.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
|
||||
{
|
||||
/* Can't lseek over pipes */
|
||||
archive_handle->seek = seek_by_read;
|
||||
|
||||
fork_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip");
|
||||
archive_handle->offset = 0;
|
||||
while (get_header_tar(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
/* Can only do one file at a time */
|
||||
return EXIT_FAILURE;
|
||||
}
|
23
busybox-1_37_0/archival/libarchive/get_header_tar_lzma.c
Normal file
23
busybox-1_37_0/archival/libarchive/get_header_tar_lzma.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Small lzma deflate implementation.
|
||||
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
|
||||
{
|
||||
/* Can't lseek over pipes */
|
||||
archive_handle->seek = seek_by_read;
|
||||
|
||||
fork_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
|
||||
archive_handle->offset = 0;
|
||||
while (get_header_tar(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
/* Can only do one file at a time */
|
||||
return EXIT_FAILURE;
|
||||
}
|
20
busybox-1_37_0/archival/libarchive/get_header_tar_xz.c
Normal file
20
busybox-1_37_0/archival/libarchive/get_header_tar_xz.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
char FAST_FUNC get_header_tar_xz(archive_handle_t *archive_handle)
|
||||
{
|
||||
/* Can't lseek over pipes */
|
||||
archive_handle->seek = seek_by_read;
|
||||
|
||||
fork_transformer_with_sig(archive_handle->src_fd, unpack_xz_stream, "unxz");
|
||||
archive_handle->offset = 0;
|
||||
while (get_header_tar(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
|
||||
/* Can only do one file at a time */
|
||||
return EXIT_FAILURE;
|
||||
}
|
12
busybox-1_37_0/archival/libarchive/header_list.c
Normal file
12
busybox-1_37_0/archival/libarchive/header_list.c
Normal file
@ -0,0 +1,12 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC header_list(const file_header_t *file_header)
|
||||
{
|
||||
//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */
|
||||
puts(file_header->name);
|
||||
}
|
10
busybox-1_37_0/archival/libarchive/header_skip.c
Normal file
10
busybox-1_37_0/archival/libarchive/header_skip.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
|
||||
{
|
||||
}
|
69
busybox-1_37_0/archival/libarchive/header_verbose_list.c
Normal file
69
busybox-1_37_0/archival/libarchive/header_verbose_list.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC header_verbose_list(const file_header_t *file_header)
|
||||
{
|
||||
struct tm tm_time;
|
||||
struct tm *ptm = &tm_time; //localtime(&file_header->mtime);
|
||||
char modestr[12];
|
||||
|
||||
#if ENABLE_FEATURE_TAR_UNAME_GNAME
|
||||
char uid[sizeof(int)*3 + 2];
|
||||
/*char gid[sizeof(int)*3 + 2];*/
|
||||
char *user;
|
||||
char *group;
|
||||
|
||||
localtime_r(&file_header->mtime, ptm);
|
||||
|
||||
user = file_header->tar__uname;
|
||||
if (user == NULL) {
|
||||
sprintf(uid, "%u", (unsigned)file_header->uid);
|
||||
user = uid;
|
||||
}
|
||||
group = file_header->tar__gname;
|
||||
if (group == NULL) {
|
||||
/*sprintf(gid, "%u", (unsigned)file_header->gid);*/
|
||||
group = utoa(file_header->gid);
|
||||
}
|
||||
printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
|
||||
bb_mode_string(modestr, file_header->mode),
|
||||
user,
|
||||
group,
|
||||
file_header->size,
|
||||
1900 + ptm->tm_year,
|
||||
1 + ptm->tm_mon,
|
||||
ptm->tm_mday,
|
||||
ptm->tm_hour,
|
||||
ptm->tm_min,
|
||||
ptm->tm_sec,
|
||||
file_header->name);
|
||||
|
||||
#else /* !FEATURE_TAR_UNAME_GNAME */
|
||||
|
||||
localtime_r(&file_header->mtime, ptm);
|
||||
|
||||
printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s",
|
||||
bb_mode_string(modestr, file_header->mode),
|
||||
(unsigned)file_header->uid,
|
||||
(unsigned)file_header->gid,
|
||||
file_header->size,
|
||||
1900 + ptm->tm_year,
|
||||
1 + ptm->tm_mon,
|
||||
ptm->tm_mday,
|
||||
ptm->tm_hour,
|
||||
ptm->tm_min,
|
||||
ptm->tm_sec,
|
||||
file_header->name);
|
||||
|
||||
#endif /* FEATURE_TAR_UNAME_GNAME */
|
||||
|
||||
/* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */
|
||||
if (file_header->link_target) {
|
||||
printf(" -> %s", file_header->link_target);
|
||||
}
|
||||
bb_putchar('\n');
|
||||
}
|
25
busybox-1_37_0/archival/libarchive/init_handle.c
Normal file
25
busybox-1_37_0/archival/libarchive/init_handle.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
archive_handle_t* FAST_FUNC init_handle(void)
|
||||
{
|
||||
archive_handle_t *archive_handle;
|
||||
|
||||
/* Initialize default values */
|
||||
archive_handle = xzalloc(sizeof(archive_handle_t));
|
||||
archive_handle->file_header = xzalloc(sizeof(file_header_t));
|
||||
archive_handle->action_header = header_skip;
|
||||
archive_handle->action_data = data_skip;
|
||||
archive_handle->filter = filter_accept_all;
|
||||
archive_handle->seek = seek_by_jump;
|
||||
#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
|
||||
archive_handle->cpio__owner.uid = (uid_t)-1L;
|
||||
archive_handle->cpio__owner.gid = (gid_t)-1L;
|
||||
#endif
|
||||
|
||||
return archive_handle;
|
||||
}
|
95
busybox-1_37_0/archival/libarchive/liblzo.h
Normal file
95
busybox-1_37_0/archival/libarchive/liblzo.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
Markus F.X.J. Oberhumer <markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "liblzo_interface.h"
|
||||
|
||||
/* lzo-2.03/src/config1x.h */
|
||||
#define M2_MIN_LEN 3
|
||||
#define M2_MAX_LEN 8
|
||||
#define M3_MAX_LEN 33
|
||||
#define M4_MAX_LEN 9
|
||||
#define M1_MAX_OFFSET 0x0400
|
||||
#define M2_MAX_OFFSET 0x0800
|
||||
#define M3_MAX_OFFSET 0x4000
|
||||
#define M4_MAX_OFFSET 0xbfff
|
||||
#define M1_MARKER 0
|
||||
#define M3_MARKER 32
|
||||
#define M4_MARKER 16
|
||||
|
||||
#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
|
||||
#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
|
||||
|
||||
#define LZO_EOF_CODE
|
||||
|
||||
/* lzo-2.03/src/lzo_dict.h */
|
||||
#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
|
||||
#define DX2(p,s1,s2) \
|
||||
(((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
|
||||
//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
|
||||
//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
|
||||
#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
|
||||
|
||||
#define D_SIZE (1U << D_BITS)
|
||||
#define D_MASK ((1U << D_BITS) - 1)
|
||||
#define D_HIGH ((D_MASK >> 1) + 1)
|
||||
|
||||
#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
|
||||
( \
|
||||
m_pos = ip - (unsigned)(ip - m_pos), \
|
||||
((uintptr_t)m_pos < (uintptr_t)in \
|
||||
|| (m_off = (unsigned)(ip - m_pos)) <= 0 \
|
||||
|| m_off > max_offset) \
|
||||
)
|
||||
|
||||
#define DENTRY(p,in) (p)
|
||||
#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
|
||||
|
||||
#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s)))
|
||||
#define DM(v) ((unsigned) ((v) & D_MASK))
|
||||
#define DMUL(a,b) ((unsigned) ((a) * (b)))
|
||||
|
||||
/* lzo-2.03/src/lzo_ptr.h */
|
||||
#define pd(a,b) ((unsigned)((a)-(b)))
|
||||
|
||||
# define TEST_IP (ip < ip_end)
|
||||
# define NEED_IP(x) \
|
||||
if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun
|
||||
# define TEST_IV(x) if ((x) > (unsigned)0 - (511)) goto input_overrun
|
||||
|
||||
# undef TEST_OP /* don't need both of the tests here */
|
||||
# define TEST_OP 1
|
||||
# define NEED_OP(x) \
|
||||
if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun
|
||||
# define TEST_OV(x) if ((x) > (unsigned)0 - (511)) goto output_overrun
|
||||
|
||||
#define HAVE_ANY_OP 1
|
||||
|
||||
//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
|
||||
# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun
|
||||
//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
|
||||
//#else
|
||||
//# define TEST_LB(m_pos) ((void) 0)
|
||||
//# define TEST_LBO(m_pos,o) ((void) 0)
|
||||
//#endif
|
35
busybox-1_37_0/archival/libarchive/lzo1x_1.c
Normal file
35
busybox-1_37_0/archival/libarchive/lzo1x_1.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* LZO1X-1 compression
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
Markus F.X.J. Oberhumer <markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "liblzo.h"
|
||||
|
||||
#define D_BITS 14
|
||||
#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
|
||||
#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
|
||||
|
||||
#define DO_COMPRESS lzo1x_1_compress
|
||||
|
||||
#include "lzo1x_c.c"
|
35
busybox-1_37_0/archival/libarchive/lzo1x_1o.c
Normal file
35
busybox-1_37_0/archival/libarchive/lzo1x_1o.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* LZO1X-1(15) compression
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
Markus F.X.J. Oberhumer <markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "liblzo.h"
|
||||
|
||||
#define D_BITS 15
|
||||
#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
|
||||
#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
|
||||
|
||||
#define DO_COMPRESS lzo1x_1_15_compress
|
||||
|
||||
#include "lzo1x_c.c"
|
919
busybox-1_37_0/archival/libarchive/lzo1x_9x.c
Normal file
919
busybox-1_37_0/archival/libarchive/lzo1x_9x.c
Normal file
@ -0,0 +1,919 @@
|
||||
/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
#include "libbb.h"
|
||||
|
||||
/* The following is probably only safe on Intel-compatible processors ... */
|
||||
#define LZO_UNALIGNED_OK_2
|
||||
#define LZO_UNALIGNED_OK_4
|
||||
|
||||
#include "liblzo.h"
|
||||
|
||||
#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
#define SWD_N M4_MAX_OFFSET /* size of ring buffer */
|
||||
#define SWD_F 2048 /* upper limit for match length */
|
||||
|
||||
#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1)
|
||||
|
||||
typedef struct {
|
||||
int init;
|
||||
|
||||
unsigned look; /* bytes in lookahead buffer */
|
||||
|
||||
unsigned m_len;
|
||||
unsigned m_off;
|
||||
|
||||
const uint8_t *bp;
|
||||
const uint8_t *ip;
|
||||
const uint8_t *in;
|
||||
const uint8_t *in_end;
|
||||
uint8_t *out;
|
||||
|
||||
unsigned r1_lit;
|
||||
} lzo1x_999_t;
|
||||
|
||||
#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
|
||||
|
||||
/* lzo_swd.c -- sliding window dictionary */
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
#define SWD_UINT_MAX USHRT_MAX
|
||||
|
||||
#ifndef SWD_HSIZE
|
||||
# define SWD_HSIZE 16384
|
||||
#endif
|
||||
#ifndef SWD_MAX_CHAIN
|
||||
# define SWD_MAX_CHAIN 2048
|
||||
#endif
|
||||
|
||||
#define HEAD3(b, p) \
|
||||
( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
|
||||
|
||||
#if defined(LZO_UNALIGNED_OK_2)
|
||||
# define HEAD2(b,p) (* (bb__aliased_uint16_t *) &(b[p]))
|
||||
#else
|
||||
# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
|
||||
#endif
|
||||
#define NIL2 SWD_UINT_MAX
|
||||
|
||||
typedef struct lzo_swd {
|
||||
/* public - "built-in" */
|
||||
|
||||
/* public - configuration */
|
||||
unsigned max_chain;
|
||||
int use_best_off;
|
||||
|
||||
/* public - output */
|
||||
unsigned m_len;
|
||||
unsigned m_off;
|
||||
unsigned look;
|
||||
int b_char;
|
||||
#if defined(SWD_BEST_OFF)
|
||||
unsigned best_off[SWD_BEST_OFF];
|
||||
#endif
|
||||
|
||||
/* semi public */
|
||||
lzo1x_999_t *c;
|
||||
unsigned m_pos;
|
||||
#if defined(SWD_BEST_OFF)
|
||||
unsigned best_pos[SWD_BEST_OFF];
|
||||
#endif
|
||||
|
||||
/* private */
|
||||
unsigned ip; /* input pointer (lookahead) */
|
||||
unsigned bp; /* buffer pointer */
|
||||
unsigned rp; /* remove pointer */
|
||||
|
||||
unsigned node_count;
|
||||
unsigned first_rp;
|
||||
|
||||
uint8_t b[SWD_N + SWD_F];
|
||||
uint8_t b_wrap[SWD_F]; /* must follow b */
|
||||
uint16_t head3[SWD_HSIZE];
|
||||
uint16_t succ3[SWD_N + SWD_F];
|
||||
uint16_t best3[SWD_N + SWD_F];
|
||||
uint16_t llen3[SWD_HSIZE];
|
||||
#ifdef HEAD2
|
||||
uint16_t head2[65536L];
|
||||
#endif
|
||||
} lzo_swd_t, *lzo_swd_p;
|
||||
|
||||
#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t))
|
||||
|
||||
|
||||
/* Access macro for head3.
|
||||
* head3[key] may be uninitialized, but then its value will never be used.
|
||||
*/
|
||||
#define s_get_head3(s,key) s->head3[key]
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
#define B_SIZE (SWD_N + SWD_F)
|
||||
|
||||
static int swd_init(lzo_swd_p s)
|
||||
{
|
||||
/* defaults */
|
||||
s->node_count = SWD_N;
|
||||
|
||||
memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE);
|
||||
#ifdef HEAD2
|
||||
memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L);
|
||||
assert(s->head2[0] == NIL2);
|
||||
#endif
|
||||
|
||||
s->ip = 0;
|
||||
s->bp = s->ip;
|
||||
s->first_rp = s->ip;
|
||||
|
||||
assert(s->ip + SWD_F <= B_SIZE);
|
||||
s->look = (unsigned) (s->c->in_end - s->c->ip);
|
||||
if (s->look > 0) {
|
||||
if (s->look > SWD_F)
|
||||
s->look = SWD_F;
|
||||
memcpy(&s->b[s->ip], s->c->ip, s->look);
|
||||
s->c->ip += s->look;
|
||||
s->ip += s->look;
|
||||
}
|
||||
if (s->ip == B_SIZE)
|
||||
s->ip = 0;
|
||||
|
||||
s->rp = s->first_rp;
|
||||
if (s->rp >= s->node_count)
|
||||
s->rp -= s->node_count;
|
||||
else
|
||||
s->rp += B_SIZE - s->node_count;
|
||||
|
||||
return LZO_E_OK;
|
||||
}
|
||||
|
||||
#define swd_pos2off(s,pos) \
|
||||
(s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static void swd_getbyte(lzo_swd_p s)
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = getbyte(*(s->c))) < 0) {
|
||||
if (s->look > 0)
|
||||
--s->look;
|
||||
} else {
|
||||
s->b[s->ip] = c;
|
||||
if (s->ip < SWD_F)
|
||||
s->b_wrap[s->ip] = c;
|
||||
}
|
||||
if (++s->ip == B_SIZE)
|
||||
s->ip = 0;
|
||||
if (++s->bp == B_SIZE)
|
||||
s->bp = 0;
|
||||
if (++s->rp == B_SIZE)
|
||||
s->rp = 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// remove node from lists
|
||||
************************************************************************/
|
||||
static void swd_remove_node(lzo_swd_p s, unsigned node)
|
||||
{
|
||||
if (s->node_count == 0) {
|
||||
unsigned key;
|
||||
|
||||
key = HEAD3(s->b,node);
|
||||
assert(s->llen3[key] > 0);
|
||||
--s->llen3[key];
|
||||
|
||||
#ifdef HEAD2
|
||||
key = HEAD2(s->b,node);
|
||||
assert(s->head2[key] != NIL2);
|
||||
if ((unsigned) s->head2[key] == node)
|
||||
s->head2[key] = NIL2;
|
||||
#endif
|
||||
} else
|
||||
--s->node_count;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static void swd_accept(lzo_swd_p s, unsigned n)
|
||||
{
|
||||
assert(n <= s->look);
|
||||
|
||||
while (n--) {
|
||||
unsigned key;
|
||||
|
||||
swd_remove_node(s,s->rp);
|
||||
|
||||
/* add bp into HEAD3 */
|
||||
key = HEAD3(s->b, s->bp);
|
||||
s->succ3[s->bp] = s_get_head3(s, key);
|
||||
s->head3[key] = s->bp;
|
||||
s->best3[s->bp] = SWD_F + 1;
|
||||
s->llen3[key]++;
|
||||
assert(s->llen3[key] <= SWD_N);
|
||||
|
||||
#ifdef HEAD2
|
||||
/* add bp into HEAD2 */
|
||||
key = HEAD2(s->b, s->bp);
|
||||
s->head2[key] = s->bp;
|
||||
#endif
|
||||
|
||||
swd_getbyte(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt)
|
||||
{
|
||||
const uint8_t *p1;
|
||||
const uint8_t *p2;
|
||||
const uint8_t *px;
|
||||
unsigned m_len = s->m_len;
|
||||
const uint8_t *b = s->b;
|
||||
const uint8_t *bp = s->b + s->bp;
|
||||
const uint8_t *bx = s->b + s->bp + s->look;
|
||||
unsigned char scan_end1;
|
||||
|
||||
assert(s->m_len > 0);
|
||||
|
||||
scan_end1 = bp[m_len - 1];
|
||||
for ( ; cnt-- > 0; node = s->succ3[node]) {
|
||||
p1 = bp;
|
||||
p2 = b + node;
|
||||
px = bx;
|
||||
|
||||
assert(m_len < s->look);
|
||||
|
||||
if (p2[m_len - 1] == scan_end1
|
||||
&& p2[m_len] == p1[m_len]
|
||||
&& p2[0] == p1[0]
|
||||
&& p2[1] == p1[1]
|
||||
) {
|
||||
unsigned i;
|
||||
assert(lzo_memcmp(bp, &b[node], 3) == 0);
|
||||
|
||||
p1 += 2; p2 += 2;
|
||||
do {} while (++p1 < px && *p1 == *++p2);
|
||||
i = p1-bp;
|
||||
|
||||
assert(lzo_memcmp(bp, &b[node], i) == 0);
|
||||
|
||||
#if defined(SWD_BEST_OFF)
|
||||
if (i < SWD_BEST_OFF) {
|
||||
if (s->best_pos[i] == 0)
|
||||
s->best_pos[i] = node + 1;
|
||||
}
|
||||
#endif
|
||||
if (i > m_len) {
|
||||
s->m_len = m_len = i;
|
||||
s->m_pos = node;
|
||||
if (m_len == s->look)
|
||||
return;
|
||||
if (m_len >= SWD_F)
|
||||
return;
|
||||
if (m_len > (unsigned) s->best3[node])
|
||||
return;
|
||||
scan_end1 = bp[m_len - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
#ifdef HEAD2
|
||||
|
||||
static int swd_search2(lzo_swd_p s)
|
||||
{
|
||||
unsigned key;
|
||||
|
||||
assert(s->look >= 2);
|
||||
assert(s->m_len > 0);
|
||||
|
||||
key = s->head2[HEAD2(s->b, s->bp)];
|
||||
if (key == NIL2)
|
||||
return 0;
|
||||
assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0);
|
||||
#if defined(SWD_BEST_OFF)
|
||||
if (s->best_pos[2] == 0)
|
||||
s->best_pos[2] = key + 1;
|
||||
#endif
|
||||
|
||||
if (s->m_len < 2) {
|
||||
s->m_len = 2;
|
||||
s->m_pos = key;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static void swd_findbest(lzo_swd_p s)
|
||||
{
|
||||
unsigned key;
|
||||
unsigned cnt, node;
|
||||
unsigned len;
|
||||
|
||||
assert(s->m_len > 0);
|
||||
|
||||
/* get current head, add bp into HEAD3 */
|
||||
key = HEAD3(s->b,s->bp);
|
||||
node = s->succ3[s->bp] = s_get_head3(s, key);
|
||||
cnt = s->llen3[key]++;
|
||||
assert(s->llen3[key] <= SWD_N + SWD_F);
|
||||
if (cnt > s->max_chain)
|
||||
cnt = s->max_chain;
|
||||
s->head3[key] = s->bp;
|
||||
|
||||
s->b_char = s->b[s->bp];
|
||||
len = s->m_len;
|
||||
if (s->m_len >= s->look) {
|
||||
if (s->look == 0)
|
||||
s->b_char = -1;
|
||||
s->m_off = 0;
|
||||
s->best3[s->bp] = SWD_F + 1;
|
||||
} else {
|
||||
#ifdef HEAD2
|
||||
if (swd_search2(s))
|
||||
#endif
|
||||
if (s->look >= 3)
|
||||
swd_search(s, node, cnt);
|
||||
if (s->m_len > len)
|
||||
s->m_off = swd_pos2off(s,s->m_pos);
|
||||
s->best3[s->bp] = s->m_len;
|
||||
|
||||
#if defined(SWD_BEST_OFF)
|
||||
if (s->use_best_off) {
|
||||
int i;
|
||||
for (i = 2; i < SWD_BEST_OFF; i++) {
|
||||
if (s->best_pos[i] > 0)
|
||||
s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1);
|
||||
else
|
||||
s->best_off[i] = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
swd_remove_node(s,s->rp);
|
||||
|
||||
#ifdef HEAD2
|
||||
/* add bp into HEAD2 */
|
||||
key = HEAD2(s->b, s->bp);
|
||||
s->head2[key] = s->bp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef HEAD3
|
||||
#undef HEAD2
|
||||
#undef s_get_head3
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(!c->init);
|
||||
c->init = 1;
|
||||
|
||||
s->c = c;
|
||||
|
||||
r = swd_init(s);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
s->use_best_off = use_best_off;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static int find_match(lzo1x_999_t *c, lzo_swd_p s,
|
||||
unsigned this_len, unsigned skip)
|
||||
{
|
||||
assert(c->init);
|
||||
|
||||
if (skip > 0) {
|
||||
assert(this_len >= skip);
|
||||
swd_accept(s, this_len - skip);
|
||||
} else {
|
||||
assert(this_len <= 1);
|
||||
}
|
||||
|
||||
s->m_len = 1;
|
||||
#ifdef SWD_BEST_OFF
|
||||
if (s->use_best_off)
|
||||
memset(s->best_pos, 0, sizeof(s->best_pos));
|
||||
#endif
|
||||
swd_findbest(s);
|
||||
c->m_len = s->m_len;
|
||||
c->m_off = s->m_off;
|
||||
|
||||
swd_getbyte(s);
|
||||
|
||||
if (s->b_char < 0) {
|
||||
c->look = 0;
|
||||
c->m_len = 0;
|
||||
} else {
|
||||
c->look = s->look + 1;
|
||||
}
|
||||
c->bp = c->ip - c->look;
|
||||
|
||||
return LZO_E_OK;
|
||||
}
|
||||
|
||||
/* this is a public functions, but there is no prototype in a header file */
|
||||
static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
|
||||
uint8_t *out, unsigned *out_len,
|
||||
void *wrkmem,
|
||||
unsigned good_length,
|
||||
unsigned max_lazy,
|
||||
unsigned max_chain,
|
||||
uint32_t use_best_off);
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static uint8_t *code_match(lzo1x_999_t *c,
|
||||
uint8_t *op, unsigned m_len, unsigned m_off)
|
||||
{
|
||||
assert(op > c->out);
|
||||
if (m_len == 2) {
|
||||
assert(m_off <= M1_MAX_OFFSET);
|
||||
assert(c->r1_lit > 0);
|
||||
assert(c->r1_lit < 4);
|
||||
m_off -= 1;
|
||||
*op++ = M1_MARKER | ((m_off & 3) << 2);
|
||||
*op++ = m_off >> 2;
|
||||
} else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
|
||||
assert(m_len >= 3);
|
||||
m_off -= 1;
|
||||
*op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2);
|
||||
*op++ = m_off >> 3;
|
||||
assert(op[-2] >= M2_MARKER);
|
||||
} else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) {
|
||||
assert(m_len == 3);
|
||||
assert(m_off > M2_MAX_OFFSET);
|
||||
m_off -= 1 + M2_MAX_OFFSET;
|
||||
*op++ = M1_MARKER | ((m_off & 3) << 2);
|
||||
*op++ = m_off >> 2;
|
||||
} else if (m_off <= M3_MAX_OFFSET) {
|
||||
assert(m_len >= 3);
|
||||
m_off -= 1;
|
||||
if (m_len <= M3_MAX_LEN)
|
||||
*op++ = M3_MARKER | (m_len - 2);
|
||||
else {
|
||||
m_len -= M3_MAX_LEN;
|
||||
*op++ = M3_MARKER | 0;
|
||||
while (m_len > 255) {
|
||||
m_len -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(m_len > 0);
|
||||
*op++ = m_len;
|
||||
}
|
||||
*op++ = m_off << 2;
|
||||
*op++ = m_off >> 6;
|
||||
} else {
|
||||
unsigned k;
|
||||
|
||||
assert(m_len >= 3);
|
||||
assert(m_off > 0x4000);
|
||||
assert(m_off <= 0xbfff);
|
||||
m_off -= 0x4000;
|
||||
k = (m_off & 0x4000) >> 11;
|
||||
if (m_len <= M4_MAX_LEN)
|
||||
*op++ = M4_MARKER | k | (m_len - 2);
|
||||
else {
|
||||
m_len -= M4_MAX_LEN;
|
||||
*op++ = M4_MARKER | k | 0;
|
||||
while (m_len > 255) {
|
||||
m_len -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(m_len > 0);
|
||||
*op++ = m_len;
|
||||
}
|
||||
*op++ = m_off << 2;
|
||||
*op++ = m_off >> 6;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op,
|
||||
const uint8_t *ii, unsigned t)
|
||||
{
|
||||
if (op == c->out && t <= 238) {
|
||||
*op++ = 17 + t;
|
||||
} else if (t <= 3) {
|
||||
op[-2] |= t;
|
||||
} else if (t <= 18) {
|
||||
*op++ = t - 3;
|
||||
} else {
|
||||
unsigned tt = t - 18;
|
||||
|
||||
*op++ = 0;
|
||||
while (tt > 255) {
|
||||
tt -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(tt > 0);
|
||||
*op++ = tt;
|
||||
}
|
||||
do *op++ = *ii++; while (--t > 0);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii,
|
||||
unsigned lit)
|
||||
{
|
||||
if (lit > 0) {
|
||||
assert(m_len >= 2);
|
||||
op = STORE_RUN(c, op, ii, lit);
|
||||
} else {
|
||||
assert(m_len >= 3);
|
||||
}
|
||||
c->r1_lit = lit;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit)
|
||||
{
|
||||
int n = 4;
|
||||
|
||||
if (m_len < 2)
|
||||
return -1;
|
||||
if (m_len == 2)
|
||||
return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1;
|
||||
if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
|
||||
return 2;
|
||||
if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
|
||||
return 2;
|
||||
if (m_off <= M3_MAX_OFFSET) {
|
||||
if (m_len <= M3_MAX_LEN)
|
||||
return 3;
|
||||
m_len -= M3_MAX_LEN;
|
||||
} else if (m_off <= M4_MAX_OFFSET) {
|
||||
if (m_len <= M4_MAX_LEN)
|
||||
return 3;
|
||||
m_len -= M4_MAX_LEN;
|
||||
} else
|
||||
return -1;
|
||||
while (m_len > 255) {
|
||||
m_len -= 255;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static int min_gain(unsigned ahead, unsigned lit1,
|
||||
unsigned lit2, int l1, int l2, int l3)
|
||||
{
|
||||
int lazy_match_min_gain = 0;
|
||||
|
||||
assert (ahead >= 1);
|
||||
lazy_match_min_gain += ahead;
|
||||
|
||||
if (lit1 <= 3)
|
||||
lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
|
||||
else if (lit1 <= 18)
|
||||
lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
|
||||
|
||||
lazy_match_min_gain += (l2 - l1) * 2;
|
||||
if (l3 > 0)
|
||||
lazy_match_min_gain -= (ahead - l3) * 2;
|
||||
|
||||
if (lazy_match_min_gain < 0)
|
||||
lazy_match_min_gain = 0;
|
||||
|
||||
return lazy_match_min_gain;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
#if defined(SWD_BEST_OFF)
|
||||
|
||||
static void better_match(const lzo_swd_p swd,
|
||||
unsigned *m_len, unsigned *m_off)
|
||||
{
|
||||
if (*m_len <= M2_MIN_LEN)
|
||||
return;
|
||||
|
||||
if (*m_off <= M2_MAX_OFFSET)
|
||||
return;
|
||||
|
||||
/* M3/M4 -> M2 */
|
||||
if (*m_off > M2_MAX_OFFSET
|
||||
&& *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1
|
||||
&& swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET
|
||||
) {
|
||||
*m_len = *m_len - 1;
|
||||
*m_off = swd->best_off[*m_len];
|
||||
return;
|
||||
}
|
||||
|
||||
/* M4 -> M2 */
|
||||
if (*m_off > M3_MAX_OFFSET
|
||||
&& *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2
|
||||
&& swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET
|
||||
) {
|
||||
*m_len = *m_len - 2;
|
||||
*m_off = swd->best_off[*m_len];
|
||||
return;
|
||||
}
|
||||
/* M4 -> M3 */
|
||||
if (*m_off > M3_MAX_OFFSET
|
||||
&& *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1
|
||||
&& swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET
|
||||
) {
|
||||
*m_len = *m_len - 1;
|
||||
*m_off = swd->best_off[*m_len];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
|
||||
uint8_t *out, unsigned *out_len,
|
||||
void *wrkmem,
|
||||
unsigned good_length,
|
||||
unsigned max_lazy,
|
||||
unsigned max_chain,
|
||||
uint32_t use_best_off)
|
||||
{
|
||||
uint8_t *op;
|
||||
const uint8_t *ii;
|
||||
unsigned lit;
|
||||
unsigned m_len, m_off;
|
||||
lzo1x_999_t cc;
|
||||
lzo1x_999_t *const c = &cc;
|
||||
const lzo_swd_p swd = (lzo_swd_p) wrkmem;
|
||||
int r;
|
||||
|
||||
c->init = 0;
|
||||
c->ip = c->in = in;
|
||||
c->in_end = in + in_len;
|
||||
c->out = out;
|
||||
|
||||
op = out;
|
||||
ii = c->ip; /* point to start of literal run */
|
||||
lit = 0;
|
||||
c->r1_lit = 0;
|
||||
|
||||
r = init_match(c, swd, use_best_off);
|
||||
if (r != 0)
|
||||
return r;
|
||||
swd->max_chain = max_chain;
|
||||
|
||||
r = find_match(c, swd, 0, 0);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
while (c->look > 0) {
|
||||
unsigned ahead;
|
||||
unsigned max_ahead;
|
||||
int l1, l2, l3;
|
||||
|
||||
m_len = c->m_len;
|
||||
m_off = c->m_off;
|
||||
|
||||
assert(c->bp == c->ip - c->look);
|
||||
assert(c->bp >= in);
|
||||
if (lit == 0)
|
||||
ii = c->bp;
|
||||
assert(ii + lit == c->bp);
|
||||
assert(swd->b_char == *(c->bp));
|
||||
|
||||
if (m_len < 2
|
||||
|| (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4))
|
||||
/* Do not accept this match for compressed-data compatibility
|
||||
* with LZO v1.01 and before
|
||||
* [ might be a problem for decompress() and optimize() ]
|
||||
*/
|
||||
|| (m_len == 2 && op == out)
|
||||
|| (op == out && lit == 0)
|
||||
) {
|
||||
/* a literal */
|
||||
m_len = 0;
|
||||
}
|
||||
else if (m_len == M2_MIN_LEN) {
|
||||
/* compression ratio improves if we code a literal in some cases */
|
||||
if (m_off > MX_MAX_OFFSET && lit >= 4)
|
||||
m_len = 0;
|
||||
}
|
||||
|
||||
if (m_len == 0) {
|
||||
/* a literal */
|
||||
lit++;
|
||||
swd->max_chain = max_chain;
|
||||
r = find_match(c, swd, 1, 0);
|
||||
assert(r == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* a match */
|
||||
#if defined(SWD_BEST_OFF)
|
||||
if (swd->use_best_off)
|
||||
better_match(swd, &m_len, &m_off);
|
||||
#endif
|
||||
|
||||
/* shall we try a lazy match ? */
|
||||
ahead = 0;
|
||||
if (m_len >= max_lazy) {
|
||||
/* no */
|
||||
l1 = 0;
|
||||
max_ahead = 0;
|
||||
} else {
|
||||
/* yes, try a lazy match */
|
||||
l1 = len_of_coded_match(m_len, m_off, lit);
|
||||
assert(l1 > 0);
|
||||
max_ahead = LZO_MIN(2, (unsigned)l1 - 1);
|
||||
}
|
||||
|
||||
|
||||
while (ahead < max_ahead && c->look > m_len) {
|
||||
int lazy_match_min_gain;
|
||||
|
||||
if (m_len >= good_length)
|
||||
swd->max_chain = max_chain >> 2;
|
||||
else
|
||||
swd->max_chain = max_chain;
|
||||
r = find_match(c, swd, 1, 0);
|
||||
ahead++;
|
||||
|
||||
assert(r == 0);
|
||||
assert(c->look > 0);
|
||||
assert(ii + lit + ahead == c->bp);
|
||||
|
||||
if (c->m_len < m_len)
|
||||
continue;
|
||||
if (c->m_len == m_len && c->m_off >= m_off)
|
||||
continue;
|
||||
#if defined(SWD_BEST_OFF)
|
||||
if (swd->use_best_off)
|
||||
better_match(swd, &c->m_len, &c->m_off);
|
||||
#endif
|
||||
l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead);
|
||||
if (l2 < 0)
|
||||
continue;
|
||||
|
||||
/* compressed-data compatibility [see above] */
|
||||
l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit);
|
||||
|
||||
lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3);
|
||||
if (c->m_len >= m_len + lazy_match_min_gain) {
|
||||
if (l3 > 0) {
|
||||
/* code previous run */
|
||||
op = code_run(c, op, ii, lit);
|
||||
lit = 0;
|
||||
/* code shortened match */
|
||||
op = code_match(c, op, ahead, m_off);
|
||||
} else {
|
||||
lit += ahead;
|
||||
assert(ii + lit == c->bp);
|
||||
}
|
||||
goto lazy_match_done;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ii + lit + ahead == c->bp);
|
||||
|
||||
/* 1 - code run */
|
||||
op = code_run(c, op, ii, lit);
|
||||
lit = 0;
|
||||
|
||||
/* 2 - code match */
|
||||
op = code_match(c, op, m_len, m_off);
|
||||
swd->max_chain = max_chain;
|
||||
r = find_match(c, swd, m_len, 1+ahead);
|
||||
assert(r == 0);
|
||||
|
||||
lazy_match_done: ;
|
||||
}
|
||||
|
||||
/* store final run */
|
||||
if (lit > 0)
|
||||
op = STORE_RUN(c, op, ii, lit);
|
||||
|
||||
#if defined(LZO_EOF_CODE)
|
||||
*op++ = M4_MARKER | 1;
|
||||
*op++ = 0;
|
||||
*op++ = 0;
|
||||
#endif
|
||||
|
||||
*out_len = op - out;
|
||||
|
||||
return LZO_E_OK;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len,
|
||||
uint8_t *out, unsigned *out_len,
|
||||
void *wrkmem,
|
||||
int compression_level)
|
||||
{
|
||||
static const struct {
|
||||
uint16_t good_length;
|
||||
uint16_t max_lazy;
|
||||
uint16_t max_chain;
|
||||
uint16_t use_best_off;
|
||||
} c[3] = {
|
||||
{ 8, 32, 256, 0 },
|
||||
{ 32, 128, 2048, 1 },
|
||||
{ SWD_F, SWD_F, 4096, 1 } /* max. compression */
|
||||
};
|
||||
|
||||
if (compression_level < 7 || compression_level > 9)
|
||||
return LZO_E_ERROR;
|
||||
|
||||
compression_level -= 7;
|
||||
return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem,
|
||||
c[compression_level].good_length,
|
||||
c[compression_level].max_lazy,
|
||||
c[compression_level].max_chain,
|
||||
c[compression_level].use_best_off);
|
||||
}
|
296
busybox-1_37_0/archival/libarchive/lzo1x_c.c
Normal file
296
busybox-1_37_0/archival/libarchive/lzo1x_c.c
Normal file
@ -0,0 +1,296 @@
|
||||
/* implementation of the LZO1[XY]-1 compression algorithm
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
Markus F.X.J. Oberhumer <markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/***********************************************************************
|
||||
// compress a block of data.
|
||||
************************************************************************/
|
||||
static NOINLINE unsigned
|
||||
do_compress(const uint8_t* in, unsigned in_len,
|
||||
uint8_t* out, unsigned* out_len,
|
||||
void* wrkmem)
|
||||
{
|
||||
register const uint8_t* ip;
|
||||
uint8_t* op;
|
||||
const uint8_t* const in_end = in + in_len;
|
||||
const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5;
|
||||
const uint8_t* ii;
|
||||
const void* *const dict = (const void**) wrkmem;
|
||||
|
||||
op = out;
|
||||
ip = in;
|
||||
ii = ip;
|
||||
|
||||
ip += 4;
|
||||
for (;;) {
|
||||
register const uint8_t* m_pos;
|
||||
unsigned m_off;
|
||||
unsigned m_len;
|
||||
unsigned dindex;
|
||||
|
||||
D_INDEX1(dindex,ip);
|
||||
GINDEX(m_pos,m_off,dict,dindex,in);
|
||||
if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
|
||||
goto literal;
|
||||
#if 1
|
||||
if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
|
||||
goto try_match;
|
||||
D_INDEX2(dindex,ip);
|
||||
#endif
|
||||
GINDEX(m_pos,m_off,dict,dindex,in);
|
||||
if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
|
||||
goto literal;
|
||||
if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
|
||||
goto try_match;
|
||||
goto literal;
|
||||
|
||||
try_match:
|
||||
#if 1 && defined(LZO_UNALIGNED_OK_2)
|
||||
if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
|
||||
#else
|
||||
if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
if (m_pos[2] == ip[2]) {
|
||||
#if 0
|
||||
if (m_off <= M2_MAX_OFFSET)
|
||||
goto match;
|
||||
if (lit <= 3)
|
||||
goto match;
|
||||
if (lit == 3) { /* better compression, but slower */
|
||||
assert(op - 2 > out); op[-2] |= (uint8_t)(3);
|
||||
*op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
|
||||
goto code_match;
|
||||
}
|
||||
if (m_pos[3] == ip[3])
|
||||
#endif
|
||||
goto match;
|
||||
}
|
||||
else {
|
||||
/* still need a better way for finding M1 matches */
|
||||
#if 0
|
||||
/* a M1 match */
|
||||
#if 0
|
||||
if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
|
||||
#else
|
||||
if (m_off <= M1_MAX_OFFSET && lit == 3)
|
||||
#endif
|
||||
{
|
||||
register unsigned t;
|
||||
|
||||
t = lit;
|
||||
assert(op - 2 > out); op[-2] |= (uint8_t)(t);
|
||||
do *op++ = *ii++; while (--t > 0);
|
||||
assert(ii == ip);
|
||||
m_off -= 1;
|
||||
*op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2));
|
||||
*op++ = (uint8_t)(m_off >> 2);
|
||||
ip += 2;
|
||||
goto match_done;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* a literal */
|
||||
literal:
|
||||
UPDATE_I(dict, 0, dindex, ip, in);
|
||||
++ip;
|
||||
if (ip >= ip_end)
|
||||
break;
|
||||
continue;
|
||||
|
||||
/* a match */
|
||||
match:
|
||||
UPDATE_I(dict, 0, dindex, ip, in);
|
||||
/* store current literal run */
|
||||
if (pd(ip, ii) > 0) {
|
||||
register unsigned t = pd(ip, ii);
|
||||
|
||||
if (t <= 3) {
|
||||
assert(op - 2 > out);
|
||||
op[-2] |= (uint8_t)(t);
|
||||
}
|
||||
else if (t <= 18)
|
||||
*op++ = (uint8_t)(t - 3);
|
||||
else {
|
||||
register unsigned tt = t - 18;
|
||||
|
||||
*op++ = 0;
|
||||
while (tt > 255) {
|
||||
tt -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(tt > 0);
|
||||
*op++ = (uint8_t)(tt);
|
||||
}
|
||||
do *op++ = *ii++; while (--t > 0);
|
||||
}
|
||||
|
||||
/* code the match */
|
||||
assert(ii == ip);
|
||||
ip += 3;
|
||||
if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++
|
||||
|| m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
|
||||
#ifdef LZO1Y
|
||||
|| m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
|
||||
|| m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
|
||||
#endif
|
||||
) {
|
||||
--ip;
|
||||
m_len = pd(ip, ii);
|
||||
assert(m_len >= 3);
|
||||
assert(m_len <= M2_MAX_LEN);
|
||||
|
||||
if (m_off <= M2_MAX_OFFSET) {
|
||||
m_off -= 1;
|
||||
#if defined(LZO1X)
|
||||
*op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2));
|
||||
*op++ = (uint8_t)(m_off >> 3);
|
||||
#elif defined(LZO1Y)
|
||||
*op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2));
|
||||
*op++ = (uint8_t)(m_off >> 2);
|
||||
#endif
|
||||
}
|
||||
else if (m_off <= M3_MAX_OFFSET) {
|
||||
m_off -= 1;
|
||||
*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
|
||||
goto m3_m4_offset;
|
||||
} else {
|
||||
#if defined(LZO1X)
|
||||
m_off -= 0x4000;
|
||||
assert(m_off > 0);
|
||||
assert(m_off <= 0x7fff);
|
||||
*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
|
||||
goto m3_m4_offset;
|
||||
#elif defined(LZO1Y)
|
||||
goto m4_match;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
{
|
||||
const uint8_t* end = in_end;
|
||||
const uint8_t* m = m_pos + M2_MAX_LEN + 1;
|
||||
while (ip < end && *m == *ip)
|
||||
m++, ip++;
|
||||
m_len = pd(ip, ii);
|
||||
}
|
||||
assert(m_len > M2_MAX_LEN);
|
||||
|
||||
if (m_off <= M3_MAX_OFFSET) {
|
||||
m_off -= 1;
|
||||
if (m_len <= 33)
|
||||
*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
|
||||
else {
|
||||
m_len -= 33;
|
||||
*op++ = M3_MARKER | 0;
|
||||
goto m3_m4_len;
|
||||
}
|
||||
} else {
|
||||
#if defined(LZO1Y)
|
||||
m4_match:
|
||||
#endif
|
||||
m_off -= 0x4000;
|
||||
assert(m_off > 0);
|
||||
assert(m_off <= 0x7fff);
|
||||
if (m_len <= M4_MAX_LEN)
|
||||
*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
|
||||
else {
|
||||
m_len -= M4_MAX_LEN;
|
||||
*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11));
|
||||
m3_m4_len:
|
||||
while (m_len > 255) {
|
||||
m_len -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(m_len > 0);
|
||||
*op++ = (uint8_t)(m_len);
|
||||
}
|
||||
}
|
||||
m3_m4_offset:
|
||||
*op++ = (uint8_t)((m_off & 63) << 2);
|
||||
*op++ = (uint8_t)(m_off >> 6);
|
||||
}
|
||||
#if 0
|
||||
match_done:
|
||||
#endif
|
||||
ii = ip;
|
||||
if (ip >= ip_end)
|
||||
break;
|
||||
}
|
||||
|
||||
*out_len = pd(op, out);
|
||||
return pd(in_end, ii);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
// public entry point
|
||||
************************************************************************/
|
||||
int DO_COMPRESS(const uint8_t* in, unsigned in_len,
|
||||
uint8_t* out, unsigned* out_len,
|
||||
void* wrkmem)
|
||||
{
|
||||
uint8_t* op = out;
|
||||
unsigned t;
|
||||
|
||||
if (in_len <= M2_MAX_LEN + 5)
|
||||
t = in_len;
|
||||
else {
|
||||
t = do_compress(in,in_len,op,out_len,wrkmem);
|
||||
op += *out_len;
|
||||
}
|
||||
|
||||
if (t > 0) {
|
||||
const uint8_t* ii = in + in_len - t;
|
||||
|
||||
if (op == out && t <= 238)
|
||||
*op++ = (uint8_t)(17 + t);
|
||||
else if (t <= 3)
|
||||
op[-2] |= (uint8_t)(t);
|
||||
else if (t <= 18)
|
||||
*op++ = (uint8_t)(t - 3);
|
||||
else {
|
||||
unsigned tt = t - 18;
|
||||
|
||||
*op++ = 0;
|
||||
while (tt > 255) {
|
||||
tt -= 255;
|
||||
*op++ = 0;
|
||||
}
|
||||
assert(tt > 0);
|
||||
*op++ = (uint8_t)(tt);
|
||||
}
|
||||
do *op++ = *ii++; while (--t > 0);
|
||||
}
|
||||
|
||||
*op++ = M4_MARKER | 1;
|
||||
*op++ = 0;
|
||||
*op++ = 0;
|
||||
|
||||
*out_len = pd(op, out);
|
||||
return 0; /*LZO_E_OK*/
|
||||
}
|
422
busybox-1_37_0/archival/libarchive/lzo1x_d.c
Normal file
422
busybox-1_37_0/archival/libarchive/lzo1x_d.c
Normal file
@ -0,0 +1,422 @@
|
||||
/* implementation of the LZO1X decompression algorithm
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
Markus F.X.J. Oberhumer <markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "liblzo.h"
|
||||
|
||||
/***********************************************************************
|
||||
// decompress a block of data.
|
||||
************************************************************************/
|
||||
/* safe decompression with overrun testing */
|
||||
int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
|
||||
uint8_t* out, unsigned* out_len /*, void* wrkmem */)
|
||||
{
|
||||
register uint8_t* op;
|
||||
register const uint8_t* ip;
|
||||
register unsigned t;
|
||||
#if defined(COPY_DICT)
|
||||
unsigned m_off;
|
||||
const uint8_t* dict_end;
|
||||
#else
|
||||
register const uint8_t* m_pos = NULL; /* possibly not needed */
|
||||
#endif
|
||||
const uint8_t* const ip_end = in + in_len;
|
||||
#if defined(HAVE_ANY_OP)
|
||||
uint8_t* const op_end = out + *out_len;
|
||||
#endif
|
||||
#if defined(LZO1Z)
|
||||
unsigned last_m_off = 0;
|
||||
#endif
|
||||
|
||||
// LZO_UNUSED(wrkmem);
|
||||
|
||||
#if defined(COPY_DICT)
|
||||
if (dict) {
|
||||
if (dict_len > M4_MAX_OFFSET) {
|
||||
dict += dict_len - M4_MAX_OFFSET;
|
||||
dict_len = M4_MAX_OFFSET;
|
||||
}
|
||||
dict_end = dict + dict_len;
|
||||
} else {
|
||||
dict_len = 0;
|
||||
dict_end = NULL;
|
||||
}
|
||||
#endif /* COPY_DICT */
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
op = out;
|
||||
ip = in;
|
||||
|
||||
if (*ip > 17) {
|
||||
t = *ip++ - 17;
|
||||
if (t < 4)
|
||||
goto match_next;
|
||||
assert(t > 0); NEED_OP(t); NEED_IP(t+1);
|
||||
do *op++ = *ip++; while (--t > 0);
|
||||
goto first_literal_run;
|
||||
}
|
||||
|
||||
while (TEST_IP && TEST_OP) {
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
/* a literal run */
|
||||
if (t == 0) {
|
||||
NEED_IP(1);
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP(1);
|
||||
}
|
||||
TEST_IV(t);
|
||||
t += 15 + *ip++;
|
||||
}
|
||||
/* copy literals */
|
||||
assert(t > 0);
|
||||
NEED_OP(t+3);
|
||||
NEED_IP(t+4);
|
||||
#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
|
||||
# if !defined(LZO_UNALIGNED_OK_4)
|
||||
if (PTR_ALIGNED2_4(op, ip))
|
||||
# endif
|
||||
{
|
||||
COPY4(op, ip);
|
||||
op += 4;
|
||||
ip += 4;
|
||||
if (--t > 0) {
|
||||
if (t >= 4) {
|
||||
do {
|
||||
COPY4(op, ip);
|
||||
op += 4;
|
||||
ip += 4;
|
||||
t -= 4;
|
||||
} while (t >= 4);
|
||||
if (t > 0)
|
||||
do *op++ = *ip++; while (--t > 0);
|
||||
} else {
|
||||
do *op++ = *ip++; while (--t > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
# if !defined(LZO_UNALIGNED_OK_4)
|
||||
else
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(LZO_UNALIGNED_OK_4)
|
||||
{
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
do *op++ = *ip++; while (--t > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
first_literal_run:
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
#if defined(COPY_DICT)
|
||||
#if defined(LZO1Z)
|
||||
m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
|
||||
last_m_off = m_off;
|
||||
#else
|
||||
m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
|
||||
#endif
|
||||
NEED_OP(3);
|
||||
t = 3; COPY_DICT(t,m_off)
|
||||
#else /* !COPY_DICT */
|
||||
#if defined(LZO1Z)
|
||||
t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
|
||||
m_pos = op - t;
|
||||
last_m_off = t;
|
||||
#else
|
||||
m_pos = op - (1 + M2_MAX_OFFSET);
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
#endif
|
||||
TEST_LB(m_pos); NEED_OP(3);
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
#endif /* COPY_DICT */
|
||||
goto match_done;
|
||||
|
||||
/* handle matches */
|
||||
do {
|
||||
match:
|
||||
if (t >= 64) { /* a M2 match */
|
||||
#if defined(COPY_DICT)
|
||||
#if defined(LZO1X)
|
||||
m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
|
||||
t = (t >> 5) - 1;
|
||||
#elif defined(LZO1Y)
|
||||
m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
|
||||
t = (t >> 4) - 3;
|
||||
#elif defined(LZO1Z)
|
||||
m_off = t & 0x1f;
|
||||
if (m_off >= 0x1c)
|
||||
m_off = last_m_off;
|
||||
else {
|
||||
m_off = 1 + (m_off << 6) + (*ip++ >> 2);
|
||||
last_m_off = m_off;
|
||||
}
|
||||
t = (t >> 5) - 1;
|
||||
#endif
|
||||
#else /* !COPY_DICT */
|
||||
#if defined(LZO1X)
|
||||
m_pos = op - 1;
|
||||
m_pos -= (t >> 2) & 7;
|
||||
m_pos -= *ip++ << 3;
|
||||
t = (t >> 5) - 1;
|
||||
#elif defined(LZO1Y)
|
||||
m_pos = op - 1;
|
||||
m_pos -= (t >> 2) & 3;
|
||||
m_pos -= *ip++ << 2;
|
||||
t = (t >> 4) - 3;
|
||||
#elif defined(LZO1Z)
|
||||
{
|
||||
unsigned off = t & 0x1f;
|
||||
m_pos = op;
|
||||
if (off >= 0x1c) {
|
||||
assert(last_m_off > 0);
|
||||
m_pos -= last_m_off;
|
||||
} else {
|
||||
off = 1 + (off << 6) + (*ip++ >> 2);
|
||||
m_pos -= off;
|
||||
last_m_off = off;
|
||||
}
|
||||
}
|
||||
t = (t >> 5) - 1;
|
||||
#endif
|
||||
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
|
||||
goto copy_match;
|
||||
#endif /* COPY_DICT */
|
||||
}
|
||||
else if (t >= 32) { /* a M3 match */
|
||||
t &= 31;
|
||||
if (t == 0) {
|
||||
NEED_IP(1);
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP(1);
|
||||
}
|
||||
TEST_IV(t);
|
||||
t += 31 + *ip++;
|
||||
}
|
||||
#if defined(COPY_DICT)
|
||||
#if defined(LZO1Z)
|
||||
m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
|
||||
last_m_off = m_off;
|
||||
#else
|
||||
m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
|
||||
#endif
|
||||
#else /* !COPY_DICT */
|
||||
#if defined(LZO1Z)
|
||||
{
|
||||
unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2);
|
||||
m_pos = op - off;
|
||||
last_m_off = off;
|
||||
}
|
||||
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
|
||||
m_pos = op - 1;
|
||||
m_pos -= (* (const lzo_ushortp) ip) >> 2;
|
||||
#else
|
||||
m_pos = op - 1;
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
#endif
|
||||
#endif /* COPY_DICT */
|
||||
ip += 2;
|
||||
}
|
||||
else if (t >= 16) { /* a M4 match */
|
||||
#if defined(COPY_DICT)
|
||||
m_off = (t & 8) << 11;
|
||||
#else /* !COPY_DICT */
|
||||
m_pos = op;
|
||||
m_pos -= (t & 8) << 11;
|
||||
#endif /* COPY_DICT */
|
||||
t &= 7;
|
||||
if (t == 0) {
|
||||
NEED_IP(1);
|
||||
while (*ip == 0) {
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP(1);
|
||||
}
|
||||
TEST_IV(t);
|
||||
t += 7 + *ip++;
|
||||
}
|
||||
#if defined(COPY_DICT)
|
||||
#if defined(LZO1Z)
|
||||
m_off += (ip[0] << 6) + (ip[1] >> 2);
|
||||
#else
|
||||
m_off += (ip[0] >> 2) + (ip[1] << 6);
|
||||
#endif
|
||||
ip += 2;
|
||||
if (m_off == 0)
|
||||
goto eof_found;
|
||||
m_off += 0x4000;
|
||||
#if defined(LZO1Z)
|
||||
last_m_off = m_off;
|
||||
#endif
|
||||
#else /* !COPY_DICT */
|
||||
#if defined(LZO1Z)
|
||||
m_pos -= (ip[0] << 6) + (ip[1] >> 2);
|
||||
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
|
||||
m_pos -= (* (const lzo_ushortp) ip) >> 2;
|
||||
#else
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
#endif
|
||||
ip += 2;
|
||||
if (m_pos == op)
|
||||
goto eof_found;
|
||||
m_pos -= 0x4000;
|
||||
#if defined(LZO1Z)
|
||||
last_m_off = pd((const uint8_t*)op, m_pos);
|
||||
#endif
|
||||
#endif /* COPY_DICT */
|
||||
}
|
||||
else { /* a M1 match */
|
||||
#if defined(COPY_DICT)
|
||||
#if defined(LZO1Z)
|
||||
m_off = 1 + (t << 6) + (*ip++ >> 2);
|
||||
last_m_off = m_off;
|
||||
#else
|
||||
m_off = 1 + (t >> 2) + (*ip++ << 2);
|
||||
#endif
|
||||
NEED_OP(2);
|
||||
t = 2; COPY_DICT(t,m_off)
|
||||
#else /* !COPY_DICT */
|
||||
#if defined(LZO1Z)
|
||||
t = 1 + (t << 6) + (*ip++ >> 2);
|
||||
m_pos = op - t;
|
||||
last_m_off = t;
|
||||
#else
|
||||
m_pos = op - 1;
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
#endif
|
||||
TEST_LB(m_pos); NEED_OP(2);
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
#endif /* COPY_DICT */
|
||||
goto match_done;
|
||||
}
|
||||
|
||||
/* copy match */
|
||||
#if defined(COPY_DICT)
|
||||
|
||||
NEED_OP(t+3-1);
|
||||
t += 3-1; COPY_DICT(t,m_off)
|
||||
|
||||
#else /* !COPY_DICT */
|
||||
|
||||
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
|
||||
#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
|
||||
# if !defined(LZO_UNALIGNED_OK_4)
|
||||
if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) {
|
||||
assert((op - m_pos) >= 4); /* both pointers are aligned */
|
||||
# else
|
||||
if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
|
||||
# endif
|
||||
COPY4(op,m_pos);
|
||||
op += 4; m_pos += 4; t -= 4 - (3 - 1);
|
||||
do {
|
||||
COPY4(op,m_pos);
|
||||
op += 4; m_pos += 4; t -= 4;
|
||||
} while (t >= 4);
|
||||
if (t > 0)
|
||||
do *op++ = *m_pos++; while (--t > 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
copy_match:
|
||||
*op++ = *m_pos++; *op++ = *m_pos++;
|
||||
do *op++ = *m_pos++; while (--t > 0);
|
||||
}
|
||||
|
||||
#endif /* COPY_DICT */
|
||||
|
||||
match_done:
|
||||
#if defined(LZO1Z)
|
||||
t = ip[-1] & 3;
|
||||
#else
|
||||
t = ip[-2] & 3;
|
||||
#endif
|
||||
if (t == 0)
|
||||
break;
|
||||
|
||||
/* copy literals */
|
||||
match_next:
|
||||
assert(t > 0);
|
||||
assert(t < 4);
|
||||
NEED_OP(t);
|
||||
NEED_IP(t+1);
|
||||
#if 0
|
||||
do *op++ = *ip++; while (--t > 0);
|
||||
#else
|
||||
*op++ = *ip++;
|
||||
if (t > 1) {
|
||||
*op++ = *ip++;
|
||||
if (t > 2)
|
||||
*op++ = *ip++;
|
||||
}
|
||||
#endif
|
||||
t = *ip++;
|
||||
} while (TEST_IP && TEST_OP);
|
||||
}
|
||||
|
||||
//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
|
||||
/* no EOF code was found */
|
||||
*out_len = pd(op, out);
|
||||
return LZO_E_EOF_NOT_FOUND;
|
||||
//#endif
|
||||
|
||||
eof_found:
|
||||
assert(t == 1);
|
||||
*out_len = pd(op, out);
|
||||
return (ip == ip_end ? LZO_E_OK :
|
||||
(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
|
||||
|
||||
//#if defined(HAVE_NEED_IP)
|
||||
input_overrun:
|
||||
*out_len = pd(op, out);
|
||||
return LZO_E_INPUT_OVERRUN;
|
||||
//#endif
|
||||
|
||||
//#if defined(HAVE_NEED_OP)
|
||||
output_overrun:
|
||||
*out_len = pd(op, out);
|
||||
return LZO_E_OUTPUT_OVERRUN;
|
||||
//#endif
|
||||
|
||||
//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
|
||||
lookbehind_overrun:
|
||||
*out_len = pd(op, out);
|
||||
return LZO_E_LOOKBEHIND_OVERRUN;
|
||||
//#endif
|
||||
}
|
386
busybox-1_37_0/archival/libarchive/open_transformer.c
Normal file
386
busybox-1_37_0/archival/libarchive/open_transformer.c
Normal file
@ -0,0 +1,386 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC init_transformer_state(transformer_state_t *xstate)
|
||||
{
|
||||
memset(xstate, 0, sizeof(*xstate));
|
||||
}
|
||||
|
||||
int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16)
|
||||
{
|
||||
if (!xstate->signature_skipped) {
|
||||
uint16_t magic2;
|
||||
if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) {
|
||||
bb_simple_error_msg("invalid magic");
|
||||
return -1;
|
||||
}
|
||||
xstate->signature_skipped = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t nwrote;
|
||||
|
||||
if (xstate->mem_output_size_max != 0) {
|
||||
size_t pos = xstate->mem_output_size;
|
||||
size_t size;
|
||||
|
||||
size = (xstate->mem_output_size += bufsize);
|
||||
if (size > xstate->mem_output_size_max) {
|
||||
free(xstate->mem_output_buf);
|
||||
xstate->mem_output_buf = NULL;
|
||||
bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max);
|
||||
nwrote = -1;
|
||||
goto ret;
|
||||
}
|
||||
xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1);
|
||||
memcpy(xstate->mem_output_buf + pos, buf, bufsize);
|
||||
xstate->mem_output_buf[size] = '\0';
|
||||
nwrote = bufsize;
|
||||
} else {
|
||||
nwrote = full_write(xstate->dst_fd, buf, bufsize);
|
||||
if (nwrote != (ssize_t)bufsize) {
|
||||
bb_simple_perror_msg("write");
|
||||
nwrote = -1;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
ret:
|
||||
return nwrote;
|
||||
}
|
||||
|
||||
ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t nwrote = transformer_write(xstate, buf, bufsize);
|
||||
if (nwrote != (ssize_t)bufsize) {
|
||||
xfunc_die();
|
||||
}
|
||||
return nwrote;
|
||||
}
|
||||
|
||||
void check_errors_in_children(int signo)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (!signo) {
|
||||
/* block waiting for any child */
|
||||
if (wait(&status) < 0)
|
||||
//FIXME: check EINTR?
|
||||
return; /* probably there are no children */
|
||||
goto check_status;
|
||||
}
|
||||
|
||||
/* Wait for any child without blocking */
|
||||
for (;;) {
|
||||
if (wait_any_nohang(&status) < 0)
|
||||
//FIXME: check EINTR?
|
||||
/* wait failed?! I'm confused... */
|
||||
return;
|
||||
check_status:
|
||||
/*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
|
||||
/* On Linux, the above can be checked simply as: */
|
||||
if (status == 0)
|
||||
/* this child exited with 0 */
|
||||
continue;
|
||||
/* Cannot happen:
|
||||
if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
|
||||
*/
|
||||
bb_got_signal = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* transformer(), more than meets the eye */
|
||||
#if BB_MMU
|
||||
void FAST_FUNC fork_transformer(int fd,
|
||||
int signature_skipped,
|
||||
IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate)
|
||||
)
|
||||
#else
|
||||
void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
|
||||
#endif
|
||||
{
|
||||
struct fd_pair fd_pipe;
|
||||
int pid;
|
||||
|
||||
xpiped_pair(fd_pipe);
|
||||
pid = BB_MMU ? xfork() : xvfork();
|
||||
if (pid == 0) {
|
||||
/* Child */
|
||||
close(fd_pipe.rd); /* we don't want to read from the parent */
|
||||
// FIXME: error check?
|
||||
#if BB_MMU
|
||||
{
|
||||
IF_DESKTOP(long long) int r;
|
||||
transformer_state_t xstate;
|
||||
init_transformer_state(&xstate);
|
||||
xstate.signature_skipped = signature_skipped;
|
||||
xstate.src_fd = fd;
|
||||
xstate.dst_fd = fd_pipe.wr;
|
||||
r = transformer(&xstate);
|
||||
if (ENABLE_FEATURE_CLEAN_UP) {
|
||||
close(fd_pipe.wr); /* send EOF */
|
||||
close(fd);
|
||||
}
|
||||
/* must be _exit! bug was actually seen here */
|
||||
_exit(/*error if:*/ r < 0);
|
||||
}
|
||||
#else
|
||||
{
|
||||
char *argv[4];
|
||||
xmove_fd(fd, 0);
|
||||
xmove_fd(fd_pipe.wr, 1);
|
||||
argv[0] = (char*)transform_prog;
|
||||
argv[1] = (char*)"-cf";
|
||||
argv[2] = (char*)"-";
|
||||
argv[3] = NULL;
|
||||
BB_EXECVP(transform_prog, argv);
|
||||
bb_perror_msg_and_die("can't execute '%s'", transform_prog);
|
||||
}
|
||||
#endif
|
||||
/* notreached */
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
close(fd_pipe.wr); /* don't want to write to the child */
|
||||
xmove_fd(fd_pipe.rd, fd);
|
||||
}
|
||||
|
||||
|
||||
#if SEAMLESS_COMPRESSION
|
||||
|
||||
/* Used by e.g. rpm which gives us a fd without filename,
|
||||
* thus we can't guess the format from filename's extension.
|
||||
*/
|
||||
static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
|
||||
{
|
||||
transformer_state_t *xstate;
|
||||
|
||||
xstate = xzalloc(sizeof(*xstate));
|
||||
xstate->src_fd = fd;
|
||||
|
||||
/* .gz and .bz2 both have 2-byte signature, and their
|
||||
* unpack_XXX_stream wants this header skipped. */
|
||||
xstate->signature_skipped = 2;
|
||||
xread(fd, xstate->magic.b16, 2);
|
||||
if (ENABLE_FEATURE_SEAMLESS_GZ
|
||||
&& xstate->magic.b16[0] == GZIP_MAGIC
|
||||
) {
|
||||
xstate->xformer = unpack_gz_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
|
||||
goto found_magic;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_Z
|
||||
&& xstate->magic.b16[0] == COMPRESS_MAGIC
|
||||
) {
|
||||
xstate->xformer = unpack_Z_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";)
|
||||
goto found_magic;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_BZ2
|
||||
&& xstate->magic.b16[0] == BZIP2_MAGIC
|
||||
) {
|
||||
xstate->xformer = unpack_bz2_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
|
||||
goto found_magic;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_XZ
|
||||
&& xstate->magic.b16[0] == XZ_MAGIC1
|
||||
) {
|
||||
uint32_t v32;
|
||||
xstate->signature_skipped = 6;
|
||||
xread(fd, &xstate->magic.b16[1], 4);
|
||||
move_from_unaligned32(v32, &xstate->magic.b16[1]);
|
||||
if (v32 == XZ_MAGIC2) {
|
||||
xstate->xformer = unpack_xz_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
|
||||
goto found_magic;
|
||||
}
|
||||
}
|
||||
|
||||
/* No known magic seen */
|
||||
if (fail_if_not_compressed)
|
||||
bb_simple_error_msg_and_die("no gzip"
|
||||
IF_FEATURE_SEAMLESS_BZ2("/bzip2")
|
||||
IF_FEATURE_SEAMLESS_XZ("/xz")
|
||||
" magic");
|
||||
|
||||
/* Some callers expect this function to "consume" fd
|
||||
* even if data is not compressed. In this case,
|
||||
* we return a state with trivial transformer.
|
||||
*/
|
||||
// USE_FOR_MMU(xstate->xformer = copy_stream;)
|
||||
// USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
|
||||
|
||||
found_magic:
|
||||
return xstate;
|
||||
}
|
||||
|
||||
static void fork_transformer_and_free(transformer_state_t *xstate)
|
||||
{
|
||||
# if BB_MMU
|
||||
fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
|
||||
# else
|
||||
/* NOMMU version of fork_transformer execs
|
||||
* an external unzipper that wants
|
||||
* file position at the start of the file.
|
||||
*/
|
||||
xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR);
|
||||
xstate->signature_skipped = 0;
|
||||
fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
|
||||
# endif
|
||||
free(xstate);
|
||||
}
|
||||
|
||||
/* Used by e.g. rpm which gives us a fd without filename,
|
||||
* thus we can't guess the format from filename's extension.
|
||||
*/
|
||||
int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
|
||||
{
|
||||
transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
|
||||
|
||||
if (!xstate->xformer) {
|
||||
free(xstate);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fork_transformer_and_free(xstate);
|
||||
return 0;
|
||||
}
|
||||
#if ENABLE_FEATURE_SEAMLESS_LZMA
|
||||
/* ...and custom version for LZMA */
|
||||
void FAST_FUNC setup_lzma_on_fd(int fd)
|
||||
{
|
||||
transformer_state_t *xstate = xzalloc(sizeof(*xstate));
|
||||
xstate->src_fd = fd;
|
||||
xstate->xformer = unpack_lzma_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
|
||||
fork_transformer_and_free(xstate);
|
||||
}
|
||||
#endif
|
||||
|
||||
static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
|
||||
{
|
||||
transformer_state_t *xstate;
|
||||
int fd;
|
||||
|
||||
fd = open(fname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (ENABLE_FEATURE_SEAMLESS_LZMA) {
|
||||
/* .lzma has no header/signature, can only detect it by extension */
|
||||
if (is_suffixed_with(fname, ".lzma")) {
|
||||
xstate = xzalloc(sizeof(*xstate));
|
||||
xstate->src_fd = fd;
|
||||
xstate->xformer = unpack_lzma_stream;
|
||||
USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
|
||||
return xstate;
|
||||
}
|
||||
}
|
||||
|
||||
xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
|
||||
|
||||
return xstate;
|
||||
}
|
||||
|
||||
int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
|
||||
{
|
||||
int fd;
|
||||
transformer_state_t *xstate;
|
||||
|
||||
xstate = open_transformer(fname, fail_if_not_compressed);
|
||||
if (!xstate)
|
||||
return -1;
|
||||
|
||||
fd = xstate->src_fd;
|
||||
# if BB_MMU
|
||||
if (xstate->xformer) {
|
||||
fork_transformer_with_no_sig(fd, xstate->xformer);
|
||||
} else {
|
||||
/* the file is not compressed */
|
||||
xlseek(fd, - xstate->signature_skipped, SEEK_CUR);
|
||||
xstate->signature_skipped = 0;
|
||||
}
|
||||
# else
|
||||
/* NOMMU can't avoid the seek :( */
|
||||
xlseek(fd, - xstate->signature_skipped, SEEK_CUR);
|
||||
xstate->signature_skipped = 0;
|
||||
if (xstate->xformer) {
|
||||
fork_transformer_with_sig(fd, xstate->xformer, xstate->xformer_prog);
|
||||
} /* else: the file is not compressed */
|
||||
# endif
|
||||
|
||||
free(xstate);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
|
||||
{
|
||||
# if 1
|
||||
transformer_state_t *xstate;
|
||||
char *image;
|
||||
|
||||
xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0);
|
||||
if (!xstate) /* file open error */
|
||||
return NULL;
|
||||
|
||||
image = NULL;
|
||||
if (xstate->xformer) {
|
||||
/* In-memory decompression */
|
||||
xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095);
|
||||
xstate->xformer(xstate);
|
||||
if (xstate->mem_output_buf) {
|
||||
image = xstate->mem_output_buf;
|
||||
if (maxsz_p)
|
||||
*maxsz_p = xstate->mem_output_size;
|
||||
}
|
||||
} else {
|
||||
/* File is not compressed.
|
||||
* We already read first few bytes, account for that.
|
||||
* Example where it happens:
|
||||
* "modinfo MODULE.ko" (not compressed)
|
||||
* open("MODULE.ko", O_RDONLY|O_LARGEFILE) = 4
|
||||
* read(4, "\177E", 2) = 2
|
||||
* fstat64(4, ...)
|
||||
* mmap(...)
|
||||
* read(4, "LF\2\1\1\0\0\0\0"...
|
||||
* ...and we avoided seeking on the fd! :)
|
||||
*/
|
||||
image = xmalloc_read_with_initial_buf(
|
||||
xstate->src_fd,
|
||||
maxsz_p,
|
||||
xmemdup(&xstate->magic, xstate->signature_skipped),
|
||||
xstate->signature_skipped
|
||||
);
|
||||
xstate->signature_skipped = 0;
|
||||
}
|
||||
|
||||
if (!image)
|
||||
bb_perror_msg("read error from '%s'", fname);
|
||||
close(xstate->src_fd);
|
||||
free(xstate);
|
||||
return image;
|
||||
# else
|
||||
/* This version forks a subprocess - much more expensive */
|
||||
int fd;
|
||||
char *image;
|
||||
|
||||
fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
image = xmalloc_read(fd, maxsz_p);
|
||||
if (!image)
|
||||
bb_perror_msg("read error from '%s'", fname);
|
||||
close(fd);
|
||||
return image;
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif /* SEAMLESS_COMPRESSION */
|
18
busybox-1_37_0/archival/libarchive/seek_by_jump.c
Normal file
18
busybox-1_37_0/archival/libarchive/seek_by_jump.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC seek_by_jump(int fd, off_t amount)
|
||||
{
|
||||
if (amount
|
||||
&& lseek(fd, amount, SEEK_CUR) == (off_t) -1
|
||||
) {
|
||||
if (errno == ESPIPE)
|
||||
seek_by_read(fd, amount);
|
||||
else
|
||||
bb_simple_perror_msg_and_die("seek failure");
|
||||
}
|
||||
}
|
15
busybox-1_37_0/archival/libarchive/seek_by_read.c
Normal file
15
busybox-1_37_0/archival/libarchive/seek_by_read.c
Normal file
@ -0,0 +1,15 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/* If we are reading through a pipe, or from stdin then we can't lseek,
|
||||
* we must read and discard the data to skip over it.
|
||||
*/
|
||||
void FAST_FUNC seek_by_read(int fd, off_t amount)
|
||||
{
|
||||
if (amount)
|
||||
bb_copyfd_exact_size(fd, -1, amount);
|
||||
}
|
21
busybox-1_37_0/archival/libarchive/unpack_ar_archive.c
Normal file
21
busybox-1_37_0/archival/libarchive/unpack_ar_archive.c
Normal file
@ -0,0 +1,21 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
#include "ar_.h"
|
||||
|
||||
void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
|
||||
{
|
||||
char magic[7];
|
||||
|
||||
xread(ar_archive->src_fd, magic, AR_MAGIC_LEN);
|
||||
if (!is_prefixed_with(magic, AR_MAGIC)) {
|
||||
bb_simple_error_msg_and_die("invalid ar magic");
|
||||
}
|
||||
ar_archive->offset += AR_MAGIC_LEN;
|
||||
|
||||
while (get_header_ar(ar_archive) == EXIT_SUCCESS)
|
||||
continue;
|
||||
}
|
35
busybox-1_37_0/archival/libarchive/unsafe_prefix.c
Normal file
35
busybox-1_37_0/archival/libarchive/unsafe_prefix.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
const char* FAST_FUNC strip_unsafe_prefix(const char *str)
|
||||
{
|
||||
const char *cp = str;
|
||||
while (1) {
|
||||
char *cp2;
|
||||
if (*cp == '/') {
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
if (is_prefixed_with(cp, "/../"+1)) {
|
||||
cp += 3;
|
||||
continue;
|
||||
}
|
||||
cp2 = strstr(cp, "/../");
|
||||
if (!cp2)
|
||||
break;
|
||||
cp = cp2 + 4;
|
||||
}
|
||||
if (cp != str) {
|
||||
static smallint warned = 0;
|
||||
if (!warned) {
|
||||
warned = 1;
|
||||
bb_error_msg("removing leading '%.*s' from member names",
|
||||
(int)(cp - str), str);
|
||||
}
|
||||
}
|
||||
return cp;
|
||||
}
|
42
busybox-1_37_0/archival/libarchive/unsafe_symlink_target.c
Normal file
42
busybox-1_37_0/archival/libarchive/unsafe_symlink_target.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
void FAST_FUNC create_or_remember_link(llist_t **link_placeholders,
|
||||
const char *target,
|
||||
const char *linkname,
|
||||
int hard_link)
|
||||
{
|
||||
if (hard_link || target[0] == '/' || strstr(target, "..")) {
|
||||
llist_add_to_end(link_placeholders,
|
||||
xasprintf("%c%s%c%s", hard_link, linkname, '\0', target)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (symlink(target, linkname) != 0) {
|
||||
/* shared message */
|
||||
bb_perror_msg_and_die("can't create %slink '%s' to '%s'",
|
||||
"sym", linkname, target
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void FAST_FUNC create_links_from_list(llist_t *list)
|
||||
{
|
||||
while (list) {
|
||||
char *target;
|
||||
|
||||
target = list->data + 1 + strlen(list->data + 1) + 1;
|
||||
if ((*list->data ? link : symlink) (target, list->data + 1)) {
|
||||
/* shared message */
|
||||
bb_error_msg_and_die("can't create %slink '%s' to '%s'",
|
||||
*list->data ? "hard" : "sym",
|
||||
list->data + 1, target
|
||||
);
|
||||
}
|
||||
list = list->link;
|
||||
}
|
||||
}
|
135
busybox-1_37_0/archival/libarchive/unxz/README
Normal file
135
busybox-1_37_0/archival/libarchive/unxz/README
Normal file
@ -0,0 +1,135 @@
|
||||
|
||||
XZ Embedded
|
||||
===========
|
||||
|
||||
XZ Embedded is a relatively small, limited implementation of the .xz
|
||||
file format. Currently only decoding is implemented.
|
||||
|
||||
XZ Embedded was written for use in the Linux kernel, but the code can
|
||||
be easily used in other environments too, including regular userspace
|
||||
applications. See userspace/xzminidec.c for an example program.
|
||||
|
||||
This README contains information that is useful only when the copy
|
||||
of XZ Embedded isn't part of the Linux kernel tree. You should also
|
||||
read linux/Documentation/xz.txt even if you aren't using XZ Embedded
|
||||
as part of Linux; information in that file is not repeated in this
|
||||
README.
|
||||
|
||||
Compiling the Linux kernel module
|
||||
|
||||
The xz_dec module depends on crc32 module, so make sure that you have
|
||||
it enabled (CONFIG_CRC32).
|
||||
|
||||
Building the xz_dec and xz_dec_test modules without support for BCJ
|
||||
filters:
|
||||
|
||||
cd linux/lib/xz
|
||||
make -C /path/to/kernel/source \
|
||||
KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
|
||||
CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m
|
||||
|
||||
Building the xz_dec and xz_dec_test modules with support for BCJ
|
||||
filters:
|
||||
|
||||
cd linux/lib/xz
|
||||
make -C /path/to/kernel/source \
|
||||
KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
|
||||
CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \
|
||||
CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \
|
||||
CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \
|
||||
CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y
|
||||
|
||||
If you want only one or a few of the BCJ filters, omit the appropriate
|
||||
variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support
|
||||
code shared between all BCJ filters.
|
||||
|
||||
Most people don't need the xz_dec_test module. You can skip building
|
||||
it by omitting CONFIG_XZ_DEC_TEST=m from the make command line.
|
||||
|
||||
Compiler requirements
|
||||
|
||||
XZ Embedded should compile as either GNU-C89 (used in the Linux
|
||||
kernel) or with any C99 compiler. Getting the code to compile with
|
||||
non-GNU C89 compiler or a C++ compiler should be quite easy as
|
||||
long as there is a data type for unsigned 64-bit integer (or the
|
||||
code is modified not to support large files, which needs some more
|
||||
care than just using 32-bit integer instead of 64-bit).
|
||||
|
||||
If you use GCC, try to use a recent version. For example, on x86-32,
|
||||
xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when
|
||||
compiled with GCC 4.3.3.
|
||||
|
||||
Embedding into userspace applications
|
||||
|
||||
To embed the XZ decoder, copy the following files into a single
|
||||
directory in your source code tree:
|
||||
|
||||
linux/include/linux/xz.h
|
||||
linux/lib/xz/xz_crc32.c
|
||||
linux/lib/xz/xz_dec_lzma2.c
|
||||
linux/lib/xz/xz_dec_stream.c
|
||||
linux/lib/xz/xz_lzma2.h
|
||||
linux/lib/xz/xz_private.h
|
||||
linux/lib/xz/xz_stream.h
|
||||
userspace/xz_config.h
|
||||
|
||||
Alternatively, xz.h may be placed into a different directory but then
|
||||
that directory must be in the compiler include path when compiling
|
||||
the .c files.
|
||||
|
||||
Your code should use only the functions declared in xz.h. The rest of
|
||||
the .h files are meant only for internal use in XZ Embedded.
|
||||
|
||||
You may want to modify xz_config.h to be more suitable for your build
|
||||
environment. Probably you should at least skim through it even if the
|
||||
default file works as is.
|
||||
|
||||
BCJ filter support
|
||||
|
||||
If you want support for one or more BCJ filters, you need to copy also
|
||||
linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate
|
||||
#defines in xz_config.h or in compiler flags. You don't need these
|
||||
#defines in the code that just uses XZ Embedded via xz.h, but having
|
||||
them always #defined doesn't hurt either.
|
||||
|
||||
#define Instruction set BCJ filter endianness
|
||||
XZ_DEC_X86 x86-32 or x86-64 Little endian only
|
||||
XZ_DEC_POWERPC PowerPC Big endian only
|
||||
XZ_DEC_IA64 Itanium (IA-64) Big or little endian
|
||||
XZ_DEC_ARM ARM Little endian only
|
||||
XZ_DEC_ARMTHUMB ARM-Thumb Little endian only
|
||||
XZ_DEC_SPARC SPARC Big or little endian
|
||||
|
||||
While some architectures are (partially) bi-endian, the endianness
|
||||
setting doesn't change the endianness of the instructions on all
|
||||
architectures. That's why Itanium and SPARC filters work for both big
|
||||
and little endian executables (Itanium has little endian instructions
|
||||
and SPARC has big endian instructions).
|
||||
|
||||
There currently is no filter for little endian PowerPC or big endian
|
||||
ARM or ARM-Thumb. Implementing filters for them can be considered if
|
||||
there is a need for such filters in real-world applications.
|
||||
|
||||
Notes about shared libraries
|
||||
|
||||
If you are including XZ Embedded into a shared library, you very
|
||||
probably should rename the xz_* functions to prevent symbol
|
||||
conflicts in case your library is linked against some other library
|
||||
or application that also has XZ Embedded in it (which may even be
|
||||
a different version of XZ Embedded). TODO: Provide an easy way
|
||||
to do this.
|
||||
|
||||
Please don't create a shared library of XZ Embedded itself unless
|
||||
it is fine to rebuild everything depending on that shared library
|
||||
everytime you upgrade to a newer version of XZ Embedded. There are
|
||||
no API or ABI stability guarantees between different versions of
|
||||
XZ Embedded.
|
||||
|
||||
Specifying the calling convention
|
||||
|
||||
XZ_FUNC macro was included to support declaring functions with __init
|
||||
in Linux. Outside Linux, it can be used to specify the calling
|
||||
convention on systems that support multiple calling conventions.
|
||||
For example, on Windows, you may make all functions use the stdcall
|
||||
calling convention by defining XZ_FUNC=__stdcall when building and
|
||||
using the functions from XZ Embedded.
|
280
busybox-1_37_0/archival/libarchive/unxz/xz.h
Normal file
280
busybox-1_37_0/archival/libarchive/unxz/xz.h
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* XZ decompressor
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef XZ_H
|
||||
#define XZ_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/stddef.h>
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* In Linux, this is used to make extern functions static when needed. */
|
||||
#ifndef XZ_EXTERN
|
||||
# define XZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
/* In Linux, this is used to mark the functions with __init when needed. */
|
||||
#ifndef XZ_FUNC
|
||||
# define XZ_FUNC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum xz_mode - Operation mode
|
||||
*
|
||||
* @XZ_SINGLE: Single-call mode. This uses less RAM than
|
||||
* than multi-call modes, because the LZMA2
|
||||
* dictionary doesn't need to be allocated as
|
||||
* part of the decoder state. All required data
|
||||
* structures are allocated at initialization,
|
||||
* so xz_dec_run() cannot return XZ_MEM_ERROR.
|
||||
* @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
|
||||
* dictionary buffer. All data structures are
|
||||
* allocated at initialization, so xz_dec_run()
|
||||
* cannot return XZ_MEM_ERROR.
|
||||
* @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
|
||||
* allocated once the required size has been
|
||||
* parsed from the stream headers. If the
|
||||
* allocation fails, xz_dec_run() will return
|
||||
* XZ_MEM_ERROR.
|
||||
*
|
||||
* It is possible to enable support only for a subset of the above
|
||||
* modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
|
||||
* or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
|
||||
* with support for all operation modes, but the preboot code may
|
||||
* be built with fewer features to minimize code size.
|
||||
*/
|
||||
enum xz_mode {
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
* enum xz_ret - Return codes
|
||||
* @XZ_OK: Everything is OK so far. More input or more
|
||||
* output space is required to continue. This
|
||||
* return code is possible only in multi-call mode
|
||||
* (XZ_PREALLOC or XZ_DYNALLOC).
|
||||
* @XZ_STREAM_END: Operation finished successfully.
|
||||
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
|
||||
* is still possible in multi-call mode by simply
|
||||
* calling xz_dec_run() again.
|
||||
* Note that this return value is used only if
|
||||
* XZ_DEC_ANY_CHECK was defined at build time,
|
||||
* which is not used in the kernel. Unsupported
|
||||
* check types return XZ_OPTIONS_ERROR if
|
||||
* XZ_DEC_ANY_CHECK was not defined at build time.
|
||||
* @XZ_MEM_ERROR: Allocating memory failed. This return code is
|
||||
* possible only if the decoder was initialized
|
||||
* with XZ_DYNALLOC. The amount of memory that was
|
||||
* tried to be allocated was no more than the
|
||||
* dict_max argument given to xz_dec_init().
|
||||
* @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
|
||||
* allowed by the dict_max argument given to
|
||||
* xz_dec_init(). This return value is possible
|
||||
* only in multi-call mode (XZ_PREALLOC or
|
||||
* XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
|
||||
* ignores the dict_max argument.
|
||||
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
|
||||
* bytes).
|
||||
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
|
||||
* compression options. In the decoder this means
|
||||
* that the header CRC32 matches, but the header
|
||||
* itself specifies something that we don't support.
|
||||
* @XZ_DATA_ERROR: Compressed data is corrupt.
|
||||
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
|
||||
* different between multi-call and single-call
|
||||
* mode; more information below.
|
||||
*
|
||||
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
|
||||
* to XZ code cannot consume any input and cannot produce any new output.
|
||||
* This happens when there is no new input available, or the output buffer
|
||||
* is full while at least one output byte is still pending. Assuming your
|
||||
* code is not buggy, you can get this error only when decoding a compressed
|
||||
* stream that is truncated or otherwise corrupt.
|
||||
*
|
||||
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
|
||||
* is too small or the compressed input is corrupt in a way that makes the
|
||||
* decoder produce more output than the caller expected. When it is
|
||||
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
|
||||
* is used instead of XZ_BUF_ERROR.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_buf - Passing input and output buffers to XZ code
|
||||
* @in: Beginning of the input buffer. This may be NULL if and only
|
||||
* if in_pos is equal to in_size.
|
||||
* @in_pos: Current position in the input buffer. This must not exceed
|
||||
* in_size.
|
||||
* @in_size: Size of the input buffer
|
||||
* @out: Beginning of the output buffer. This may be NULL if and only
|
||||
* if out_pos is equal to out_size.
|
||||
* @out_pos: Current position in the output buffer. This must not exceed
|
||||
* out_size.
|
||||
* @out_size: Size of the output buffer
|
||||
*
|
||||
* Only the contents of the output buffer from out[out_pos] onward, and
|
||||
* the variables in_pos and out_pos are modified by the XZ code.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_dec - Opaque type to hold the XZ decoder state
|
||||
*/
|
||||
struct xz_dec;
|
||||
|
||||
/**
|
||||
* xz_dec_init() - Allocate and initialize a XZ decoder state
|
||||
* @mode: Operation mode
|
||||
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
|
||||
* multi-call decoding. This is ignored in single-call mode
|
||||
* (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
|
||||
* or 2^n + 2^(n-1) bytes (the latter sizes are less common
|
||||
* in practice), so other values for dict_max don't make sense.
|
||||
* In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
|
||||
* 512 KiB, and 1 MiB are probably the only reasonable values,
|
||||
* except for kernel and initramfs images where a bigger
|
||||
* dictionary can be fine and useful.
|
||||
*
|
||||
* Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
|
||||
* once. The caller must provide enough output space or the decoding will
|
||||
* fail. The output space is used as the dictionary buffer, which is why
|
||||
* there is no need to allocate the dictionary as part of the decoder's
|
||||
* internal state.
|
||||
*
|
||||
* Because the output buffer is used as the workspace, streams encoded using
|
||||
* a big dictionary are not a problem in single-call mode. It is enough that
|
||||
* the output buffer is big enough to hold the actual uncompressed data; it
|
||||
* can be smaller than the dictionary size stored in the stream headers.
|
||||
*
|
||||
* Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
|
||||
* of memory is preallocated for the LZMA2 dictionary. This way there is no
|
||||
* risk that xz_dec_run() could run out of memory, since xz_dec_run() will
|
||||
* never allocate any memory. Instead, if the preallocated dictionary is too
|
||||
* small for decoding the given input stream, xz_dec_run() will return
|
||||
* XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
|
||||
* decoded to avoid allocating excessive amount of memory for the dictionary.
|
||||
*
|
||||
* Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
|
||||
* dict_max specifies the maximum allowed dictionary size that xz_dec_run()
|
||||
* may allocate once it has parsed the dictionary size from the stream
|
||||
* headers. This way excessive allocations can be avoided while still
|
||||
* limiting the maximum memory usage to a sane value to prevent running the
|
||||
* system out of memory when decompressing streams from untrusted sources.
|
||||
*
|
||||
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
|
||||
* ready to be used with xz_dec_run(). If memory allocation fails,
|
||||
* xz_dec_init() returns NULL.
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
|
||||
enum xz_mode mode, uint32_t dict_max);
|
||||
|
||||
/**
|
||||
* xz_dec_run() - Run the XZ decoder
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
* @b: Input and output buffers
|
||||
*
|
||||
* The possible return values depend on build options and operation mode.
|
||||
* See enum xz_ret for details.
|
||||
*
|
||||
* Note that if an error occurs in single-call mode (return value is not
|
||||
* XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
|
||||
* contents of the output buffer from b->out[b->out_pos] onward are
|
||||
* undefined. This is true even after XZ_BUF_ERROR, because with some filter
|
||||
* chains, there may be a second pass over the output buffer, and this pass
|
||||
* cannot be properly done if the output buffer is truncated. Thus, you
|
||||
* cannot give the single-call decoder a too small buffer and then expect to
|
||||
* get that amount valid data from the beginning of the stream. You must use
|
||||
* the multi-call decoder if you don't want to uncompress the whole stream.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_reset() - Reset an already allocated decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
*
|
||||
* This function can be used to reset the multi-call decoder state without
|
||||
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
|
||||
*
|
||||
* In single-call mode, xz_dec_reset() is always called in the beginning of
|
||||
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
|
||||
* multi-call mode.
|
||||
*/
|
||||
XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* xz_dec_end() - Free the memory allocated for the decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
|
||||
* this function does nothing.
|
||||
*/
|
||||
XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s);
|
||||
|
||||
/*
|
||||
* Standalone build (userspace build or in-kernel build for boot time use)
|
||||
* needs a CRC32 implementation. For normal in-kernel use, kernel's own
|
||||
* CRC32 module is used instead, and users of this module don't need to
|
||||
* care about the functions below.
|
||||
*/
|
||||
#ifndef XZ_INTERNAL_CRC32
|
||||
# ifdef __KERNEL__
|
||||
# define XZ_INTERNAL_CRC32 0
|
||||
# else
|
||||
# define XZ_INTERNAL_CRC32 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if XZ_INTERNAL_CRC32
|
||||
/*
|
||||
* This must be called before any other xz_* function to initialize
|
||||
* the CRC32 lookup table.
|
||||
*/
|
||||
XZ_EXTERN void XZ_FUNC xz_crc32_init(void);
|
||||
|
||||
/*
|
||||
* Update CRC32 value using the polynomial from IEEE-802.3. To start a new
|
||||
* calculation, the third argument must be zero. To continue the calculation,
|
||||
* the previously returned value is passed as the third argument.
|
||||
*/
|
||||
XZ_EXTERN uint32_t XZ_FUNC xz_crc32(
|
||||
const uint8_t *buf, size_t size, uint32_t crc);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
123
busybox-1_37_0/archival/libarchive/unxz/xz_config.h
Normal file
123
busybox-1_37_0/archival/libarchive/unxz/xz_config.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Private includes and definitions for userspace use of XZ Embedded
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef XZ_CONFIG_H
|
||||
#define XZ_CONFIG_H
|
||||
|
||||
/* Uncomment as needed to enable BCJ filter decoders. */
|
||||
/* #define XZ_DEC_X86 */
|
||||
/* #define XZ_DEC_POWERPC */
|
||||
/* #define XZ_DEC_IA64 */
|
||||
/* #define XZ_DEC_ARM */
|
||||
/* #define XZ_DEC_ARMTHUMB */
|
||||
/* #define XZ_DEC_SPARC */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xz.h"
|
||||
|
||||
#define kmalloc(size, flags) malloc(size)
|
||||
#define kfree(ptr) free(ptr)
|
||||
#define vmalloc(size) malloc(size)
|
||||
#define vfree(ptr) free(ptr)
|
||||
|
||||
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
|
||||
#define memzero(buf, size) memset(buf, 0, size)
|
||||
|
||||
#undef min
|
||||
#undef min_t
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define min_t(type, x, y) min(x, y)
|
||||
|
||||
/*
|
||||
* Some functions have been marked with __always_inline to keep the
|
||||
* performance reasonable even when the compiler is optimizing for
|
||||
* small code size. You may be able to save a few bytes by #defining
|
||||
* __always_inline to plain inline, but don't complain if the code
|
||||
* becomes slow.
|
||||
*
|
||||
* NOTE: System headers on GNU/Linux may #define this macro already,
|
||||
* so if you want to change it, you need to #undef it first.
|
||||
*/
|
||||
#ifndef __always_inline
|
||||
# ifdef __GNUC__
|
||||
# define __always_inline \
|
||||
inline __attribute__((__always_inline__))
|
||||
# else
|
||||
# define __always_inline inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some functions are marked to never be inlined to reduce stack usage.
|
||||
* If you don't care about stack usage, you may want to modify this so
|
||||
* that noinline_for_stack is #defined to be empty even when using GCC.
|
||||
* Doing so may save a few bytes in binary size.
|
||||
*/
|
||||
#ifndef noinline_for_stack
|
||||
# ifdef __GNUC__
|
||||
# define noinline_for_stack __attribute__((__noinline__))
|
||||
# else
|
||||
# define noinline_for_stack
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Inline functions to access unaligned unsigned 32-bit integers */
|
||||
#ifndef get_unaligned_le32
|
||||
static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef get_unaligned_be32
|
||||
static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)(buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_le32
|
||||
static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_be32
|
||||
static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use get_unaligned_le32() also for aligned access for simplicity. On
|
||||
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
|
||||
* could save a few bytes in code size.
|
||||
*/
|
||||
#ifndef get_le32
|
||||
# define get_le32 get_unaligned_le32
|
||||
#endif
|
||||
|
||||
#endif
|
580
busybox-1_37_0/archival/libarchive/unxz/xz_dec_bcj.c
Normal file
580
busybox-1_37_0/archival/libarchive/unxz/xz_dec_bcj.c
Normal file
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Branch/Call/Jump (BCJ) filter decoders
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/*
|
||||
* The rest of the file is inside this ifdef. It makes things a little more
|
||||
* convenient when building without support for any BCJ filters.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
|
||||
struct xz_dec_bcj {
|
||||
/* Type of the BCJ filter being used */
|
||||
enum {
|
||||
BCJ_X86 = 4, /* x86 or x86-64 */
|
||||
BCJ_POWERPC = 5, /* Big endian only */
|
||||
BCJ_IA64 = 6, /* Big or little endian */
|
||||
BCJ_ARM = 7, /* Little endian only */
|
||||
BCJ_ARMTHUMB = 8, /* Little endian only */
|
||||
BCJ_SPARC = 9 /* Big or little endian */
|
||||
} type;
|
||||
|
||||
/*
|
||||
* Return value of the next filter in the chain. We need to preserve
|
||||
* this information across calls, because we must not call the next
|
||||
* filter anymore once it has returned XZ_STREAM_END.
|
||||
*/
|
||||
enum xz_ret ret;
|
||||
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
|
||||
/*
|
||||
* Absolute position relative to the beginning of the uncompressed
|
||||
* data (in a single .xz Block). We care only about the lowest 32
|
||||
* bits so this doesn't need to be uint64_t even with big files.
|
||||
*/
|
||||
uint32_t pos;
|
||||
|
||||
/* x86 filter state */
|
||||
uint32_t x86_prev_mask;
|
||||
|
||||
/* Temporary space to hold the variables from struct xz_buf */
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
|
||||
struct {
|
||||
/* Amount of already filtered data in the beginning of buf */
|
||||
size_t filtered;
|
||||
|
||||
/* Total amount of data currently stored in buf */
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Buffer to hold a mix of filtered and unfiltered data. This
|
||||
* needs to be big enough to hold Alignment + 2 * Look-ahead:
|
||||
*
|
||||
* Type Alignment Look-ahead
|
||||
* x86 1 4
|
||||
* PowerPC 4 0
|
||||
* IA-64 16 0
|
||||
* ARM 4 0
|
||||
* ARM-Thumb 2 2
|
||||
* SPARC 4 0
|
||||
*/
|
||||
uint8_t buf[16];
|
||||
} temp;
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_X86
|
||||
/*
|
||||
* This is used to test the most significant byte of a memory address
|
||||
* in an x86 instruction.
|
||||
*/
|
||||
static inline int bcj_x86_test_msbyte(uint8_t b)
|
||||
{
|
||||
return b == 0x00 || b == 0xFF;
|
||||
}
|
||||
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_x86(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const bool mask_to_allowed_status[8]
|
||||
= { true, true, true, false, true, false, false, false };
|
||||
|
||||
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
size_t i;
|
||||
size_t prev_pos = (size_t)-1;
|
||||
uint32_t prev_mask = s->x86_prev_mask;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t j;
|
||||
uint8_t b;
|
||||
|
||||
if (size <= 4)
|
||||
return 0;
|
||||
|
||||
size -= 4;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3) {
|
||||
prev_mask = 0;
|
||||
} else {
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0) {
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask]
|
||||
|| bcj_x86_test_msbyte(b)) {
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i;
|
||||
|
||||
if (bcj_x86_test_msbyte(buf[i + 4])) {
|
||||
src = get_unaligned_le32(buf + i + 1);
|
||||
while (true) {
|
||||
dest = src - (s->pos + (uint32_t)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
|
||||
j = mask_to_bit_num[prev_mask] * 8;
|
||||
b = (uint8_t)(dest >> (24 - j));
|
||||
if (!bcj_x86_test_msbyte(b))
|
||||
break;
|
||||
|
||||
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
|
||||
}
|
||||
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= (uint32_t)0 - (dest & 0x01000000);
|
||||
put_unaligned_le32(dest, buf + i + 1);
|
||||
i += 4;
|
||||
} else {
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_powerpc(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr & 0xFC000003) == 0x48000001) {
|
||||
instr &= 0x03FFFFFC;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr &= 0x03FFFFFC;
|
||||
instr |= 0x48000001;
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_IA64
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_ia64(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const uint8_t branch_table[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7,
|
||||
4, 4, 0, 0, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* The local variables take a little bit stack space, but it's less
|
||||
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
|
||||
* stack usage here without doing that for the LZMA2 decoder too.
|
||||
*/
|
||||
|
||||
/* Loop counters */
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
|
||||
uint32_t slot;
|
||||
|
||||
/* Bitwise offset of the instruction indicated by slot */
|
||||
uint32_t bit_pos;
|
||||
|
||||
/* bit_pos split into byte and bit parts */
|
||||
uint32_t byte_pos;
|
||||
uint32_t bit_res;
|
||||
|
||||
/* Address part of an instruction */
|
||||
uint32_t addr;
|
||||
|
||||
/* Mask used to detect which instructions to convert */
|
||||
uint32_t mask;
|
||||
|
||||
/* 41-bit instruction stored somewhere in the lowest 48 bits */
|
||||
uint64_t instr;
|
||||
|
||||
/* Instruction normalized with bit_res for easier manipulation */
|
||||
uint64_t norm;
|
||||
|
||||
for (i = 0; i + 16 <= size; i += 16) {
|
||||
mask = branch_table[buf[i] & 0x1F];
|
||||
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
|
||||
byte_pos = bit_pos >> 3;
|
||||
bit_res = bit_pos & 7;
|
||||
instr = 0;
|
||||
for (j = 0; j < 6; ++j)
|
||||
instr |= (uint64_t)(buf[i + j + byte_pos])
|
||||
<< (8 * j);
|
||||
|
||||
norm = instr >> bit_res;
|
||||
|
||||
if (((norm >> 37) & 0x0F) == 0x05
|
||||
&& ((norm >> 9) & 0x07) == 0) {
|
||||
addr = (norm >> 13) & 0x0FFFFF;
|
||||
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
|
||||
addr <<= 4;
|
||||
addr -= s->pos + (uint32_t)i;
|
||||
addr >>= 4;
|
||||
|
||||
norm &= ~((uint64_t)0x8FFFFF << 13);
|
||||
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
|
||||
norm |= (uint64_t)(addr & 0x100000)
|
||||
<< (36 - 20);
|
||||
|
||||
instr &= (1 << bit_res) - 1;
|
||||
instr |= norm << bit_res;
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
buf[i + j + byte_pos]
|
||||
= (uint8_t)(instr >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARM
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_arm(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
if (buf[i + 3] == 0xEB) {
|
||||
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
|
||||
| ((uint32_t)buf[i + 2] << 16);
|
||||
addr <<= 2;
|
||||
addr -= s->pos + (uint32_t)i + 8;
|
||||
addr >>= 2;
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_armthumb(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 2) {
|
||||
if ((buf[i + 1] & 0xF8) == 0xF0
|
||||
&& (buf[i + 3] & 0xF8) == 0xF8) {
|
||||
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
|
||||
| ((uint32_t)buf[i] << 11)
|
||||
| (((uint32_t)buf[i + 3] & 0x07) << 8)
|
||||
| (uint32_t)buf[i + 2];
|
||||
addr <<= 1;
|
||||
addr -= s->pos + (uint32_t)i + 4;
|
||||
addr >>= 1;
|
||||
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
|
||||
buf[i] = (uint8_t)(addr >> 11);
|
||||
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
|
||||
buf[i + 2] = (uint8_t)addr;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_SPARC
|
||||
static noinline_for_stack size_t XZ_FUNC bcj_sparc(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
|
||||
instr <<= 2;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
|
||||
| 0x40000000 | (instr & 0x3FFFFF);
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
|
||||
* of data that got filtered.
|
||||
*
|
||||
* NOTE: This is implemented as a switch statement to avoid using function
|
||||
* pointers, which could be problematic in the kernel boot code, which must
|
||||
* avoid pointers to static data (at least on x86).
|
||||
*/
|
||||
static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s,
|
||||
uint8_t *buf, size_t *pos, size_t size)
|
||||
{
|
||||
size_t filtered;
|
||||
|
||||
buf += *pos;
|
||||
size -= *pos;
|
||||
|
||||
switch (s->type) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
filtered = bcj_x86(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
filtered = bcj_powerpc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
filtered = bcj_ia64(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
filtered = bcj_arm(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
filtered = bcj_armthumb(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
filtered = bcj_sparc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Never reached but silence compiler warnings. */
|
||||
filtered = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*pos += filtered;
|
||||
s->pos += filtered;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush pending filtered data from temp to the output buffer.
|
||||
* Move the remaining mixture of possibly filtered and unfiltered
|
||||
* data to the beginning of temp.
|
||||
*/
|
||||
static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size;
|
||||
|
||||
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
|
||||
s->temp.filtered -= copy_size;
|
||||
s->temp.size -= copy_size;
|
||||
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
|
||||
}
|
||||
|
||||
/*
|
||||
* The BCJ filter functions are primitive in sense that they process the
|
||||
* data in chunks of 1-16 bytes. To hide this issue, this function does
|
||||
* some buffering.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2, struct xz_buf *b)
|
||||
{
|
||||
size_t out_start;
|
||||
|
||||
/*
|
||||
* Flush pending already filtered data to the output buffer. Return
|
||||
* immediatelly if we couldn't flush everything, or if the next
|
||||
* filter in the chain had already returned XZ_STREAM_END.
|
||||
*/
|
||||
if (s->temp.filtered > 0) {
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have more output space than what is currently pending in
|
||||
* temp, copy the unfiltered data from temp to the output buffer
|
||||
* and try to fill the output buffer by decoding more data from the
|
||||
* next filter in the chain. Apply the BCJ filter on the new data
|
||||
* in the output buffer. If everything cannot be filtered, copy it
|
||||
* to temp and rewind the output buffer position accordingly.
|
||||
*
|
||||
* This needs to be always run when temp.size == 0 to handle a special
|
||||
* case where the output buffer is full and the next filter has no
|
||||
* more output coming but hasn't returned XZ_STREAM_END yet.
|
||||
*/
|
||||
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
|
||||
out_start = b->out_pos;
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
|
||||
b->out_pos += s->temp.size;
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
if (s->ret != XZ_STREAM_END
|
||||
&& (s->ret != XZ_OK || s->single_call))
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, b->out, &out_start, b->out_pos);
|
||||
|
||||
/*
|
||||
* As an exception, if the next filter returned XZ_STREAM_END,
|
||||
* we can do that too, since the last few bytes that remain
|
||||
* unfiltered are meant to remain unfiltered.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
|
||||
s->temp.size = b->out_pos - out_start;
|
||||
b->out_pos -= s->temp.size;
|
||||
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
|
||||
|
||||
/*
|
||||
* If there wasn't enough input to the next filter to fill
|
||||
* the output buffer with unfiltered data, there's no point
|
||||
* to try decoding more data to temp.
|
||||
*/
|
||||
if (b->out_pos + s->temp.size < b->out_size)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have unfiltered data in temp. If the output buffer isn't full
|
||||
* yet, try to fill the temp buffer by decoding more data from the
|
||||
* next filter. Apply the BCJ filter on temp. Then we hopefully can
|
||||
* fill the actual output buffer by copying filtered data from temp.
|
||||
* A mix of filtered and unfiltered data may be left in temp; it will
|
||||
* be taken care on the next call to this function.
|
||||
*/
|
||||
if (b->out_pos < b->out_size) {
|
||||
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
|
||||
s->out = b->out;
|
||||
s->out_pos = b->out_pos;
|
||||
s->out_size = b->out_size;
|
||||
b->out = s->temp.buf;
|
||||
b->out_pos = s->temp.size;
|
||||
b->out_size = sizeof(s->temp.buf);
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
|
||||
s->temp.size = b->out_pos;
|
||||
b->out = s->out;
|
||||
b->out_pos = s->out_pos;
|
||||
b->out_size = s->out_size;
|
||||
|
||||
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
|
||||
|
||||
/*
|
||||
* If the next filter returned XZ_STREAM_END, we mark that
|
||||
* everything is filtered, since the last unfiltered bytes
|
||||
* of the stream are meant to be left as is.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
s->temp.filtered = s->temp.size;
|
||||
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
return s->ret;
|
||||
}
|
||||
|
||||
XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call)
|
||||
{
|
||||
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s != NULL)
|
||||
s->single_call = single_call;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
|
||||
struct xz_dec_bcj *s, uint8_t id)
|
||||
{
|
||||
switch (id) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unsupported Filter ID */
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
s->type = id;
|
||||
s->ret = XZ_OK;
|
||||
s->pos = 0;
|
||||
s->x86_prev_mask = 0;
|
||||
s->temp.filtered = 0;
|
||||
s->temp.size = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
#endif
|
1171
busybox-1_37_0/archival/libarchive/unxz/xz_dec_lzma2.c
Normal file
1171
busybox-1_37_0/archival/libarchive/unxz/xz_dec_lzma2.c
Normal file
File diff suppressed because it is too large
Load Diff
820
busybox-1_37_0/archival/libarchive/unxz/xz_dec_stream.c
Normal file
820
busybox-1_37_0/archival/libarchive/unxz/xz_dec_stream.c
Normal file
@ -0,0 +1,820 @@
|
||||
/*
|
||||
* .xz Stream decoder
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
#include "xz_stream.h"
|
||||
|
||||
/* Hash used to validate the Index field */
|
||||
struct xz_dec_hash {
|
||||
vli_type unpadded;
|
||||
vli_type uncompressed;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct xz_dec {
|
||||
/* Position in dec_main() */
|
||||
enum {
|
||||
SEQ_STREAM_HEADER,
|
||||
SEQ_BLOCK_START,
|
||||
SEQ_BLOCK_HEADER,
|
||||
SEQ_BLOCK_UNCOMPRESS,
|
||||
SEQ_BLOCK_PADDING,
|
||||
SEQ_BLOCK_CHECK,
|
||||
SEQ_INDEX,
|
||||
SEQ_INDEX_PADDING,
|
||||
SEQ_INDEX_CRC32,
|
||||
SEQ_STREAM_FOOTER
|
||||
} sequence;
|
||||
|
||||
/* Position in variable-length integers and Check fields */
|
||||
uint32_t pos;
|
||||
|
||||
/* Variable-length integer decoded by dec_vli() */
|
||||
vli_type vli;
|
||||
|
||||
/* Saved in_pos and out_pos */
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
|
||||
/* CRC32 value in Block or Index */
|
||||
uint32_t crc32;
|
||||
|
||||
/* Type of the integrity check calculated from uncompressed data */
|
||||
enum xz_check check_type;
|
||||
|
||||
/* Operation mode */
|
||||
enum xz_mode mode;
|
||||
|
||||
/*
|
||||
* True if the next call to xz_dec_run() is allowed to return
|
||||
* XZ_BUF_ERROR.
|
||||
*/
|
||||
bool allow_buf_error;
|
||||
|
||||
/* Information stored in Block Header */
|
||||
struct {
|
||||
/*
|
||||
* Value stored in the Compressed Size field, or
|
||||
* VLI_UNKNOWN if Compressed Size is not present.
|
||||
*/
|
||||
vli_type compressed;
|
||||
|
||||
/*
|
||||
* Value stored in the Uncompressed Size field, or
|
||||
* VLI_UNKNOWN if Uncompressed Size is not present.
|
||||
*/
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Size of the Block Header field */
|
||||
uint32_t size;
|
||||
} block_header;
|
||||
|
||||
/* Information collected when decoding Blocks */
|
||||
struct {
|
||||
/* Observed compressed size of the current Block */
|
||||
vli_type compressed;
|
||||
|
||||
/* Observed uncompressed size of the current Block */
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Number of Blocks decoded so far */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Block sizes. This is used to
|
||||
* validate the Index field.
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} block;
|
||||
|
||||
/* Variables needed when verifying the Index field */
|
||||
struct {
|
||||
/* Position in dec_index() */
|
||||
enum {
|
||||
SEQ_INDEX_COUNT,
|
||||
SEQ_INDEX_UNPADDED,
|
||||
SEQ_INDEX_UNCOMPRESSED
|
||||
} sequence;
|
||||
|
||||
/* Size of the Index in bytes */
|
||||
vli_type size;
|
||||
|
||||
/* Number of Records (matches block.count in valid files) */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Records (matches block.hash in
|
||||
* valid files).
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} index;
|
||||
|
||||
/*
|
||||
* Temporary buffer needed to hold Stream Header, Block Header,
|
||||
* and Stream Footer. The Block Header is the biggest (1 KiB)
|
||||
* so we reserve space according to that. buf[] has to be aligned
|
||||
* to a multiple of four bytes; the size_t variables before it
|
||||
* should guarantee this.
|
||||
*/
|
||||
struct {
|
||||
size_t pos;
|
||||
size_t size;
|
||||
uint8_t buf[1024];
|
||||
} temp;
|
||||
|
||||
struct xz_dec_lzma2 *lzma2;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
struct xz_dec_bcj *bcj;
|
||||
bool bcj_active;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/* Sizes of the Check field with different Check IDs */
|
||||
static const uint8_t check_sizes[16] = {
|
||||
0,
|
||||
4, 4, 4,
|
||||
8, 8, 8,
|
||||
16, 16, 16,
|
||||
32, 32, 32,
|
||||
64, 64, 64
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
|
||||
* must have set s->temp.pos to indicate how much data we are supposed
|
||||
* to copy into s->temp.buf. Return true once s->temp.pos has reached
|
||||
* s->temp.size.
|
||||
*/
|
||||
static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size = min_t(size_t,
|
||||
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
|
||||
|
||||
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
|
||||
b->in_pos += copy_size;
|
||||
s->temp.pos += copy_size;
|
||||
|
||||
if (s->temp.pos == s->temp.size) {
|
||||
s->temp.pos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Decode a variable-length integer (little-endian base-128 encoding) */
|
||||
static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s,
|
||||
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (s->pos == 0)
|
||||
s->vli = 0;
|
||||
|
||||
while (*in_pos < in_size) {
|
||||
byte = in[*in_pos];
|
||||
++*in_pos;
|
||||
|
||||
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
|
||||
|
||||
if ((byte & 0x80) == 0) {
|
||||
/* Don't allow non-minimal encodings. */
|
||||
if (byte == 0 && s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos = 0;
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
s->pos += 7;
|
||||
if (s->pos == 7 * VLI_BYTES_MAX)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Compressed Data field from a Block. Update and validate
|
||||
* the observed compressed and uncompressed sizes of the Block so that
|
||||
* they don't exceed the values possibly stored in the Block Header
|
||||
* (validation assumes that no integer overflow occurs, since vli_type
|
||||
* is normally uint64_t). Update the CRC32 if presence of the CRC32
|
||||
* field was indicated in Stream Header.
|
||||
*
|
||||
* Once the decoding is finished, validate that the observed sizes match
|
||||
* the sizes possibly stored in the Block Header. Update the hash and
|
||||
* Block count, which are later used to validate the Index field.
|
||||
*/
|
||||
static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
s->in_start = b->in_pos;
|
||||
s->out_start = b->out_pos;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->bcj_active)
|
||||
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
|
||||
else
|
||||
#endif
|
||||
ret = xz_dec_lzma2_run(s->lzma2, b);
|
||||
|
||||
s->block.compressed += b->in_pos - s->in_start;
|
||||
s->block.uncompressed += b->out_pos - s->out_start;
|
||||
|
||||
/*
|
||||
* There is no need to separately check for VLI_UNKNOWN, since
|
||||
* the observed sizes are always smaller than VLI_UNKNOWN.
|
||||
*/
|
||||
if (s->block.compressed > s->block_header.compressed
|
||||
|| s->block.uncompressed
|
||||
> s->block_header.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->crc32 = xz_crc32(b->out + s->out_start,
|
||||
b->out_pos - s->out_start, s->crc32);
|
||||
|
||||
if (ret == XZ_STREAM_END) {
|
||||
if (s->block_header.compressed != VLI_UNKNOWN
|
||||
&& s->block_header.compressed
|
||||
!= s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block_header.uncompressed != VLI_UNKNOWN
|
||||
&& s->block_header.uncompressed
|
||||
!= s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block.hash.unpadded += s->block_header.size
|
||||
+ s->block.compressed;
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
s->block.hash.unpadded += check_sizes[s->check_type];
|
||||
#else
|
||||
if (s->check_type == XZ_CHECK_CRC32)
|
||||
s->block.hash.unpadded += 4;
|
||||
#endif
|
||||
|
||||
s->block.hash.uncompressed += s->block.uncompressed;
|
||||
s->block.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->block.hash,
|
||||
sizeof(s->block.hash), s->block.hash.crc32);
|
||||
|
||||
++s->block.count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the Index size and the CRC32 value. */
|
||||
static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b)
|
||||
{
|
||||
size_t in_used = b->in_pos - s->in_start;
|
||||
s->index.size += in_used;
|
||||
s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
|
||||
* fields from the Index field. That is, Index Padding and CRC32 are not
|
||||
* decoded by this function.
|
||||
*
|
||||
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
|
||||
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
|
||||
*/
|
||||
static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
do {
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret != XZ_STREAM_END) {
|
||||
index_update(s, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (s->index.sequence) {
|
||||
case SEQ_INDEX_COUNT:
|
||||
s->index.count = s->vli;
|
||||
|
||||
/*
|
||||
* Validate that the Number of Records field
|
||||
* indicates the same number of Records as
|
||||
* there were Blocks in the Stream.
|
||||
*/
|
||||
if (s->index.count != s->block.count)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNPADDED:
|
||||
s->index.hash.unpadded += s->vli;
|
||||
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNCOMPRESSED:
|
||||
s->index.hash.uncompressed += s->vli;
|
||||
s->index.hash.crc32 = xz_crc32(
|
||||
(const uint8_t *)&s->index.hash,
|
||||
sizeof(s->index.hash),
|
||||
s->index.hash.crc32);
|
||||
--s->index.count;
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
}
|
||||
} while (s->index.count > 0);
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the next four input bytes match the value of s->crc32.
|
||||
* s->pos must be zero when starting to validate the first byte.
|
||||
*/
|
||||
static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
do {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos += 8;
|
||||
} while (s->pos < 32);
|
||||
|
||||
s->crc32 = 0;
|
||||
s->pos = 0;
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
/*
|
||||
* Skip over the Check field when the Check ID is not supported.
|
||||
* Returns true once the whole Check field has been skipped over.
|
||||
*/
|
||||
static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
while (s->pos < check_sizes[s->check_type]) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return false;
|
||||
|
||||
++b->in_pos;
|
||||
++s->pos;
|
||||
}
|
||||
|
||||
s->pos = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
|
||||
static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
|
||||
return XZ_FORMAT_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
|
||||
!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/*
|
||||
* Of integrity checks, we support only none (Check ID = 0) and
|
||||
* CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
|
||||
* we will accept other check types too, but then the check won't
|
||||
* be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
|
||||
*/
|
||||
s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
if (s->check_type > XZ_CHECK_MAX)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
if (s->check_type > XZ_CHECK_CRC32)
|
||||
return XZ_UNSUPPORTED_CHECK;
|
||||
#else
|
||||
if (s->check_type > XZ_CHECK_CRC32)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
#endif
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
|
||||
static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
|
||||
{
|
||||
if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Validate Backward Size. Note that we never added the size of the
|
||||
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
|
||||
* instead of s->index.size / 4 - 1.
|
||||
*/
|
||||
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
|
||||
* for the caller.
|
||||
*/
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/* Decode the Block Header and initialize the filter chain. */
|
||||
static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Validate the CRC32. We know that the temp buffer is at least
|
||||
* eight bytes so this is safe.
|
||||
*/
|
||||
s->temp.size -= 4;
|
||||
if (xz_crc32(s->temp.buf, s->temp.size, 0)
|
||||
!= get_le32(s->temp.buf + s->temp.size))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->temp.pos = 2;
|
||||
|
||||
/*
|
||||
* Catch unsupported Block Flags. We support only one or two filters
|
||||
* in the chain, so we catch that with the same test.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->temp.buf[1] & 0x3E)
|
||||
#else
|
||||
if (s->temp.buf[1] & 0x3F)
|
||||
#endif
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Compressed Size */
|
||||
if (s->temp.buf[1] & 0x40) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.compressed = s->vli;
|
||||
} else {
|
||||
s->block_header.compressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Uncompressed Size */
|
||||
if (s->temp.buf[1] & 0x80) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.uncompressed = s->vli;
|
||||
} else {
|
||||
s->block_header.uncompressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/* If there are two filters, the first one must be a BCJ filter. */
|
||||
s->bcj_active = s->temp.buf[1] & 0x01;
|
||||
if (s->bcj_active) {
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We don't support custom start offset,
|
||||
* so Size of Properties must be zero.
|
||||
*/
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid Filter Flags always take at least two bytes. */
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* Filter ID = LZMA2 */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x21)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Size of Properties = 1-byte Filter Properties */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x01)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Filter Properties contains LZMA2 dictionary size. */
|
||||
if (s->temp.size - s->temp.pos < 1)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* The rest must be Header Padding. */
|
||||
while (s->temp.pos < s->temp.size)
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->temp.pos = 0;
|
||||
s->block.compressed = 0;
|
||||
s->block.uncompressed = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
static NOINLINE enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Store the start position for the case when we are in the middle
|
||||
* of the Index field.
|
||||
*/
|
||||
s->in_start = b->in_pos;
|
||||
|
||||
while (true) {
|
||||
switch (s->sequence) {
|
||||
case SEQ_STREAM_HEADER:
|
||||
/*
|
||||
* Stream Header is copied to s->temp, and then
|
||||
* decoded from there. This way if the caller
|
||||
* gives us only little input at a time, we can
|
||||
* still keep the Stream Header decoding code
|
||||
* simple. Similar approach is used in many places
|
||||
* in this file.
|
||||
*/
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
/*
|
||||
* If dec_stream_header() returns
|
||||
* XZ_UNSUPPORTED_CHECK, it is still possible
|
||||
* to continue decoding if working in multi-call
|
||||
* mode. Thus, update s->sequence before calling
|
||||
* dec_stream_header().
|
||||
*/
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
|
||||
ret = dec_stream_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/* We need one byte of input to continue. */
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
/* See if this is the beginning of the Index field. */
|
||||
if (b->in[b->in_pos] == 0) {
|
||||
s->in_start = b->in_pos++;
|
||||
s->sequence = SEQ_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the size of the Block Header and
|
||||
* prepare to decode it.
|
||||
*/
|
||||
s->block_header.size
|
||||
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
|
||||
|
||||
s->temp.size = s->block_header.size;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_block_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS:
|
||||
ret = dec_block(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
* Size of Compressed Data + Block Padding
|
||||
* must be a multiple of four. We don't need
|
||||
* s->block.compressed for anything else
|
||||
* anymore, so we use it here to test the size
|
||||
* of the Block Padding field.
|
||||
*/
|
||||
while (s->block.compressed & 3) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
++s->block.compressed;
|
||||
}
|
||||
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
if (s->check_type == XZ_CHECK_CRC32) {
|
||||
ret = crc32_validate(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
else if (!check_skip(s, b)) {
|
||||
return XZ_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX:
|
||||
ret = dec_index(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
while ((s->index.size + (b->in_pos - s->in_start))
|
||||
& 3) {
|
||||
if (b->in_pos == b->in_size) {
|
||||
index_update(s, b);
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Finish the CRC32 value and Index size. */
|
||||
index_update(s, b);
|
||||
|
||||
/* Compare the hashes to validate the Index field. */
|
||||
if (!memeq(&s->block.hash, &s->index.hash,
|
||||
sizeof(s->block.hash)))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
ret = crc32_validate(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
return dec_stream_footer(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
|
||||
* multi-call and single-call decoding.
|
||||
*
|
||||
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
|
||||
* are not going to make any progress anymore. This is to prevent the caller
|
||||
* from calling us infinitely when the input file is truncated or otherwise
|
||||
* corrupt. Since zlib-style API allows that the caller fills the input buffer
|
||||
* only when the decoder doesn't produce any new output, we have to be careful
|
||||
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
|
||||
* after the second consecutive call to xz_dec_run() that makes no progress.
|
||||
*
|
||||
* In single-call mode, if we couldn't decode everything and no error
|
||||
* occurred, either the input is truncated or the output buffer is too small.
|
||||
* Since we know that the last input byte never produces any output, we know
|
||||
* that if all the input was consumed and decoding wasn't finished, the file
|
||||
* must be corrupt. Otherwise the output buffer has to be too small or the
|
||||
* file is corrupt in a way that decoding it produces too big output.
|
||||
*
|
||||
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
|
||||
* their original values. This is because with some filter chains there won't
|
||||
* be any valid uncompressed data in the output buffer unless the decoding
|
||||
* actually succeeds (that's the price to pay of using the output buffer as
|
||||
* the workspace).
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
enum xz_ret ret;
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode))
|
||||
xz_dec_reset(s);
|
||||
|
||||
in_start = b->in_pos;
|
||||
out_start = b->out_pos;
|
||||
ret = dec_main(s, b);
|
||||
|
||||
if (DEC_IS_SINGLE(s->mode)) {
|
||||
if (ret == XZ_OK)
|
||||
ret = b->in_pos == b->in_size
|
||||
? XZ_DATA_ERROR : XZ_BUF_ERROR;
|
||||
|
||||
if (ret != XZ_STREAM_END) {
|
||||
b->in_pos = in_start;
|
||||
b->out_pos = out_start;
|
||||
}
|
||||
} else if (ret == XZ_OK && in_start == b->in_pos
|
||||
&& out_start == b->out_pos) {
|
||||
if (s->allow_buf_error)
|
||||
ret = XZ_BUF_ERROR;
|
||||
|
||||
s->allow_buf_error = true;
|
||||
} else {
|
||||
s->allow_buf_error = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
|
||||
enum xz_mode mode, uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->mode = mode;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
|
||||
if (s->bcj == NULL)
|
||||
goto error_bcj;
|
||||
#endif
|
||||
|
||||
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
|
||||
if (s->lzma2 == NULL)
|
||||
goto error_lzma2;
|
||||
|
||||
xz_dec_reset(s);
|
||||
return s;
|
||||
|
||||
error_lzma2:
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
error_bcj:
|
||||
#endif
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s)
|
||||
{
|
||||
s->sequence = SEQ_STREAM_HEADER;
|
||||
s->allow_buf_error = false;
|
||||
s->pos = 0;
|
||||
s->crc32 = 0;
|
||||
memzero(&s->block, sizeof(s->block));
|
||||
memzero(&s->index, sizeof(s->index));
|
||||
s->temp.pos = 0;
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
}
|
||||
|
||||
XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
xz_dec_lzma2_end(s->lzma2);
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
#endif
|
||||
kfree(s);
|
||||
}
|
||||
}
|
204
busybox-1_37_0/archival/libarchive/unxz/xz_lzma2.h
Normal file
204
busybox-1_37_0/archival/libarchive/unxz/xz_lzma2.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* LZMA2 definitions
|
||||
*
|
||||
* Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||
* Igor Pavlov <http://7-zip.org/>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef XZ_LZMA2_H
|
||||
#define XZ_LZMA2_H
|
||||
|
||||
/* Range coder constants */
|
||||
#define RC_SHIFT_BITS 8
|
||||
#define RC_TOP_BITS 24
|
||||
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
|
||||
#define RC_BIT_MODEL_TOTAL_BITS 11
|
||||
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
|
||||
#define RC_MOVE_BITS 5
|
||||
|
||||
/*
|
||||
* Maximum number of position states. A position state is the lowest pb
|
||||
* number of bits of the current uncompressed offset. In some places there
|
||||
* are different sets of probabilities for different position states.
|
||||
*/
|
||||
#define POS_STATES_MAX (1 << 4)
|
||||
|
||||
/*
|
||||
* This enum is used to track which LZMA symbols have occurred most recently
|
||||
* and in which order. This information is used to predict the next symbol.
|
||||
*
|
||||
* Symbols:
|
||||
* - Literal: One 8-bit byte
|
||||
* - Match: Repeat a chunk of data at some distance
|
||||
* - Long repeat: Multi-byte match at a recently seen distance
|
||||
* - Short repeat: One-byte repeat at a recently seen distance
|
||||
*
|
||||
* The symbol names are in from STATE_oldest_older_previous. REP means
|
||||
* either short or long repeated match, and NONLIT means any non-literal.
|
||||
*/
|
||||
enum lzma_state {
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
};
|
||||
|
||||
/* Total number of states */
|
||||
#define STATES 12
|
||||
|
||||
/* The lowest 7 states indicate that the previous state was a literal. */
|
||||
#define LIT_STATES 7
|
||||
|
||||
/* Indicate that the latest symbol was a literal. */
|
||||
static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state)
|
||||
{
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a match. */
|
||||
static inline void XZ_FUNC lzma_state_match(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||
}
|
||||
|
||||
/* Indicate that the latest state was a long repeated match. */
|
||||
static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a short match. */
|
||||
static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Test if the previous symbol was a literal. */
|
||||
static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state)
|
||||
{
|
||||
return state < LIT_STATES;
|
||||
}
|
||||
|
||||
/* Each literal coder is divided in three sections:
|
||||
* - 0x001-0x0FF: Without match byte
|
||||
* - 0x101-0x1FF: With match byte; match bit is 0
|
||||
* - 0x201-0x2FF: With match byte; match bit is 1
|
||||
*
|
||||
* Match byte is used when the previous LZMA symbol was something else than
|
||||
* a literal (that is, it was some kind of match).
|
||||
*/
|
||||
#define LITERAL_CODER_SIZE 0x300
|
||||
|
||||
/* Maximum number of literal coders */
|
||||
#define LITERAL_CODERS_MAX (1 << 4)
|
||||
|
||||
/* Minimum length of a match is two bytes. */
|
||||
#define MATCH_LEN_MIN 2
|
||||
|
||||
/* Match length is encoded with 4, 5, or 10 bits.
|
||||
*
|
||||
* Length Bits
|
||||
* 2-9 4 = Choice=0 + 3 bits
|
||||
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
|
||||
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
|
||||
*/
|
||||
#define LEN_LOW_BITS 3
|
||||
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
|
||||
#define LEN_MID_BITS 3
|
||||
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
|
||||
#define LEN_HIGH_BITS 8
|
||||
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
|
||||
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
|
||||
|
||||
/*
|
||||
* Maximum length of a match is 273 which is a result of the encoding
|
||||
* described above.
|
||||
*/
|
||||
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
|
||||
|
||||
/*
|
||||
* Different sets of probabilities are used for match distances that have
|
||||
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
|
||||
* set of probabilities for each length. The matches with longer length
|
||||
* use a shared set of probabilities.
|
||||
*/
|
||||
#define DIST_STATES 4
|
||||
|
||||
/*
|
||||
* Get the index of the appropriate probability array for decoding
|
||||
* the distance slot.
|
||||
*/
|
||||
static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The highest two bits of a 32-bit match distance are encoded using six bits.
|
||||
* This six-bit value is called a distance slot. This way encoding a 32-bit
|
||||
* value takes 6-36 bits, larger values taking more bits.
|
||||
*/
|
||||
#define DIST_SLOT_BITS 6
|
||||
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
|
||||
|
||||
/* Match distances up to 127 are fully encoded using probabilities. Since
|
||||
* the highest two bits (distance slot) are always encoded using six bits,
|
||||
* the distances 0-3 don't need any additional bits to encode, since the
|
||||
* distance slot itself is the same as the actual distance. DIST_MODEL_START
|
||||
* indicates the first distance slot where at least one additional bit is
|
||||
* needed.
|
||||
*/
|
||||
#define DIST_MODEL_START 4
|
||||
|
||||
/*
|
||||
* Match distances greater than 127 are encoded in three pieces:
|
||||
* - distance slot: the highest two bits
|
||||
* - direct bits: 2-26 bits below the highest two bits
|
||||
* - alignment bits: four lowest bits
|
||||
*
|
||||
* Direct bits don't use any probabilities.
|
||||
*
|
||||
* The distance slot value of 14 is for distances 128-191.
|
||||
*/
|
||||
#define DIST_MODEL_END 14
|
||||
|
||||
/* Distance slots that indicate a distance <= 127. */
|
||||
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
|
||||
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
|
||||
|
||||
/*
|
||||
* For match distances greater than 127, only the highest two bits and the
|
||||
* lowest four bits (alignment) is encoded using probabilities.
|
||||
*/
|
||||
#define ALIGN_BITS 4
|
||||
#define ALIGN_SIZE (1 << ALIGN_BITS)
|
||||
#define ALIGN_MASK (ALIGN_SIZE - 1)
|
||||
|
||||
/* Total number of all probability variables */
|
||||
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
|
||||
|
||||
/*
|
||||
* LZMA remembers the four most recent match distances. Reusing these
|
||||
* distances tends to take less space than re-encoding the actual
|
||||
* distance value.
|
||||
*/
|
||||
#define REPS 4
|
||||
|
||||
#endif
|
159
busybox-1_37_0/archival/libarchive/unxz/xz_private.h
Normal file
159
busybox-1_37_0/archival/libarchive/unxz/xz_private.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Private includes and definitions
|
||||
*
|
||||
* Author: Lasse Collin <lasse.collin@tukaani.org>
|
||||
*
|
||||
* This file has been put into the public domain.
|
||||
* You can do whatever you want with this file.
|
||||
*/
|
||||
|
||||
#ifndef XZ_PRIVATE_H
|
||||
#define XZ_PRIVATE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
|
||||
# ifndef XZ_PREBOOT
|
||||
# include <linux/slab.h>
|
||||
# include <linux/vmalloc.h>
|
||||
# include <linux/string.h>
|
||||
# define memeq(a, b, size) (memcmp(a, b, size) == 0)
|
||||
# define memzero(buf, size) memset(buf, 0, size)
|
||||
# endif
|
||||
# include <asm/byteorder.h>
|
||||
# include <asm/unaligned.h>
|
||||
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
|
||||
/* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */
|
||||
# ifndef XZ_IGNORE_KCONFIG
|
||||
# ifdef CONFIG_XZ_DEC_X86
|
||||
# define XZ_DEC_X86
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_POWERPC
|
||||
# define XZ_DEC_POWERPC
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_IA64
|
||||
# define XZ_DEC_IA64
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_ARM
|
||||
# define XZ_DEC_ARM
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_ARMTHUMB
|
||||
# define XZ_DEC_ARMTHUMB
|
||||
# endif
|
||||
# ifdef CONFIG_XZ_DEC_SPARC
|
||||
# define XZ_DEC_SPARC
|
||||
# endif
|
||||
# endif
|
||||
# include <linux/xz.h>
|
||||
#else
|
||||
/*
|
||||
* For userspace builds, use a separate header to define the required
|
||||
* macros and functions. This makes it easier to adapt the code into
|
||||
* different environments and avoids clutter in the Linux kernel tree.
|
||||
*/
|
||||
# include "xz_config.h"
|
||||
#endif
|
||||
|
||||
/* If no specific decoding mode is requested, enable support for all modes. */
|
||||
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
|
||||
&& !defined(XZ_DEC_DYNALLOC)
|
||||
# define XZ_DEC_SINGLE
|
||||
# define XZ_DEC_PREALLOC
|
||||
# define XZ_DEC_DYNALLOC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The DEC_IS_foo(mode) macros are used in "if" statements. If only some
|
||||
* of the supported modes are enabled, these macros will evaluate to true or
|
||||
* false at compile time and thus allow the compiler to omit unneeded code.
|
||||
*/
|
||||
#ifdef XZ_DEC_SINGLE
|
||||
# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
|
||||
#else
|
||||
# define DEC_IS_SINGLE(mode) (false)
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_PREALLOC
|
||||
# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
|
||||
#else
|
||||
# define DEC_IS_PREALLOC(mode) (false)
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_DYNALLOC
|
||||
# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
|
||||
#else
|
||||
# define DEC_IS_DYNALLOC(mode) (false)
|
||||
#endif
|
||||
|
||||
#if !defined(XZ_DEC_SINGLE)
|
||||
# define DEC_IS_MULTI(mode) (true)
|
||||
#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
|
||||
# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
|
||||
#else
|
||||
# define DEC_IS_MULTI(mode) (false)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
|
||||
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
|
||||
*/
|
||||
#ifndef XZ_DEC_BCJ
|
||||
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
||||
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||
|| defined(XZ_DEC_SPARC)
|
||||
# define XZ_DEC_BCJ
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
|
||||
* before calling xz_dec_lzma2_run().
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(
|
||||
enum xz_mode mode, uint32_t dict_max);
|
||||
|
||||
/*
|
||||
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
|
||||
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
|
||||
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
|
||||
* decoder doesn't support.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset(
|
||||
struct xz_dec_lzma2 *s, uint8_t props);
|
||||
|
||||
/* Decode raw LZMA2 stream from b->in to b->out. */
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run(
|
||||
struct xz_dec_lzma2 *s, struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the LZMA2 decoder. */
|
||||
XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/*
|
||||
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
|
||||
* calling xz_dec_bcj_run().
|
||||
*/
|
||||
XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call);
|
||||
|
||||
/*
|
||||
* Decode the Filter ID of a BCJ filter. This implementation doesn't
|
||||
* support custom start offsets, so no decoding of Filter Properties
|
||||
* is needed. Returns XZ_OK if the given Filter ID is supported.
|
||||
* Otherwise XZ_OPTIONS_ERROR is returned.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
|
||||
struct xz_dec_bcj *s, uint8_t id);
|
||||
|
||||
/*
|
||||
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
|
||||
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
|
||||
* must be called directly.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2, struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the BCJ filters. */
|
||||
#define xz_dec_bcj_end(s) kfree(s)
|
||||
#endif
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user