mirror of
https://github.com/sheumann/hush.git
synced 2025-04-22 20:37:21 +00:00
Delete the stuff that's irrelevant to hush. Also, include (a simplified version of) the autoconf-generated headers and a simple build script, so it can easily be build in the hush-only configuration.
This commit is contained in:
parent
ef1a853400
commit
472db3bd56
176
AUTHORS
176
AUTHORS
@ -1,176 +0,0 @@
|
||||
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
|
||||
|
||||
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)
|
831
Config.in
831
Config.in
@ -1,831 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see scripts/kbuild/config-language.txt.
|
||||
#
|
||||
|
||||
mainmenu "BusyBox Configuration"
|
||||
|
||||
config HAVE_DOT_CONFIG
|
||||
bool
|
||||
default y
|
||||
|
||||
menu "Busybox Settings"
|
||||
|
||||
menu "General Configuration"
|
||||
|
||||
config DESKTOP
|
||||
bool "Enable options for full-blown desktop systems"
|
||||
default y
|
||||
help
|
||||
Enable options and features which are not essential.
|
||||
Select this only if you plan to use busybox on full-blown
|
||||
desktop machine with common Linux distro, not on an embedded box.
|
||||
|
||||
config EXTRA_COMPAT
|
||||
bool "Provide compatible behavior for rare corner cases (bigger code)"
|
||||
default n
|
||||
help
|
||||
This option makes grep, sed etc handle rare corner cases
|
||||
(embedded NUL bytes and such). This makes code bigger and uses
|
||||
some GNU extensions in libc. You probably only need this option
|
||||
if you plan to run busybox on desktop.
|
||||
|
||||
config INCLUDE_SUSv2
|
||||
bool "Enable obsolete features removed before SUSv3"
|
||||
default y
|
||||
help
|
||||
This option will enable backwards compatibility with SuSv2,
|
||||
specifically, old-style numeric options ('command -1 <file>')
|
||||
will be supported in head, tail, and fold. (Note: should
|
||||
affect renice too.)
|
||||
|
||||
config USE_PORTABLE_CODE
|
||||
bool "Avoid using GCC-specific code constructs"
|
||||
default n
|
||||
help
|
||||
Use this option if you are trying to compile busybox with
|
||||
compiler other than gcc.
|
||||
If you do use gcc, this option may needlessly increase code size.
|
||||
|
||||
config PLATFORM_LINUX
|
||||
bool "Enable Linux-specific applets and features"
|
||||
default y
|
||||
help
|
||||
For the most part, busybox requires only POSIX compatibility
|
||||
from the target system, but some applets and features use
|
||||
Linux-specific interfaces.
|
||||
|
||||
Answering 'N' here will disable such applets and hide the
|
||||
corresponding configuration options.
|
||||
|
||||
choice
|
||||
prompt "Buffer allocation policy"
|
||||
default FEATURE_BUFFERS_USE_MALLOC
|
||||
help
|
||||
There are 3 ways BusyBox can handle buffer allocations:
|
||||
- Use malloc. This costs code size for the call to xmalloc.
|
||||
- Put them on stack. For some very small machines with limited stack
|
||||
space, this can be deadly. For most folks, this works just fine.
|
||||
- Put them in BSS. This works beautifully for computers with a real
|
||||
MMU (and OS support), but wastes runtime RAM for uCLinux. This
|
||||
behavior was the only one available for BusyBox versions 0.48 and
|
||||
earlier.
|
||||
|
||||
config FEATURE_BUFFERS_USE_MALLOC
|
||||
bool "Allocate with Malloc"
|
||||
|
||||
config FEATURE_BUFFERS_GO_ON_STACK
|
||||
bool "Allocate on the Stack"
|
||||
|
||||
config FEATURE_BUFFERS_GO_IN_BSS
|
||||
bool "Allocate in the .bss section"
|
||||
|
||||
endchoice
|
||||
|
||||
config SHOW_USAGE
|
||||
bool "Show applet usage messages"
|
||||
default y
|
||||
help
|
||||
Enabling this option, BusyBox applets will show terse help messages
|
||||
when invoked with wrong arguments.
|
||||
If you do not want to show any (helpful) usage message when
|
||||
issuing wrong command syntax, you can say 'N' here,
|
||||
saving approximately 7k.
|
||||
|
||||
config FEATURE_VERBOSE_USAGE
|
||||
bool "Show verbose applet usage messages"
|
||||
default y
|
||||
depends on SHOW_USAGE
|
||||
help
|
||||
All BusyBox applets will show verbose help messages when
|
||||
busybox is invoked with --help. This will add a lot of text to the
|
||||
busybox binary. In the default configuration, this will add about
|
||||
13k, but it can add much more depending on your configuration.
|
||||
|
||||
config FEATURE_COMPRESS_USAGE
|
||||
bool "Store applet usage messages in compressed form"
|
||||
default y
|
||||
depends on SHOW_USAGE
|
||||
help
|
||||
Store usage messages in .bz compressed form, uncompress them
|
||||
on-the-fly when <applet> --help is called.
|
||||
|
||||
If you have a really tiny busybox with few applets enabled (and
|
||||
bunzip2 isn't one of them), the overhead of the decompressor might
|
||||
be noticeable. Also, if you run executables directly from ROM
|
||||
and have very little memory, this might not be a win. Otherwise,
|
||||
you probably want this.
|
||||
|
||||
config FEATURE_INSTALLER
|
||||
bool "Support --install [-s] to install applet links at runtime"
|
||||
default y
|
||||
help
|
||||
Enable 'busybox --install [-s]' support. This will allow you to use
|
||||
busybox at runtime to create hard links or symlinks for all the
|
||||
applets that are compiled into busybox.
|
||||
|
||||
config INSTALL_NO_USR
|
||||
bool "Don't use /usr"
|
||||
default n
|
||||
help
|
||||
Disable use of /usr. busybox --install and "make install"
|
||||
will install applets only to /bin and /sbin,
|
||||
never to /usr/bin or /usr/sbin.
|
||||
|
||||
config LOCALE_SUPPORT
|
||||
bool "Enable locale support (system needs locale for this to work)"
|
||||
default n
|
||||
help
|
||||
Enable this if your system has locale support and you would like
|
||||
busybox to support locale settings.
|
||||
|
||||
config UNICODE_SUPPORT
|
||||
bool "Support Unicode"
|
||||
default y
|
||||
help
|
||||
This makes various applets aware that one byte is not
|
||||
one character on screen.
|
||||
|
||||
Busybox aims to eventually work correctly with Unicode displays.
|
||||
Any older encodings are not guaranteed to work.
|
||||
Probably by the time when busybox will be fully Unicode-clean,
|
||||
other encodings will be mainly of historic interest.
|
||||
|
||||
config UNICODE_USING_LOCALE
|
||||
bool "Use libc routines for Unicode (else uses internal ones)"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT && LOCALE_SUPPORT
|
||||
help
|
||||
With this option on, Unicode support is implemented using libc
|
||||
routines. Otherwise, internal implementation is used.
|
||||
Internal implementation is smaller.
|
||||
|
||||
config FEATURE_CHECK_UNICODE_IN_ENV
|
||||
bool "Check $LC_ALL, $LC_CTYPE and $LANG environment variables"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE
|
||||
help
|
||||
With this option on, Unicode support is activated
|
||||
only if locale-related variables have the value of the form
|
||||
"xxxx.utf8"
|
||||
|
||||
Otherwise, Unicode support will be always enabled and active.
|
||||
|
||||
config SUBST_WCHAR
|
||||
int "Character code to substitute unprintable characters with"
|
||||
depends on UNICODE_SUPPORT
|
||||
default 63
|
||||
help
|
||||
Typical values are 63 for '?' (works with any output device),
|
||||
30 for ASCII substitute control code,
|
||||
65533 (0xfffd) for Unicode replacement character.
|
||||
|
||||
config LAST_SUPPORTED_WCHAR
|
||||
int "Range of supported Unicode characters"
|
||||
depends on UNICODE_SUPPORT
|
||||
default 767
|
||||
help
|
||||
Any character with Unicode value bigger than this is assumed
|
||||
to be non-printable on output device. Many applets replace
|
||||
such chars with substitution character.
|
||||
|
||||
The idea is that many valid printable Unicode chars are
|
||||
nevertheless are not displayed correctly. Think about
|
||||
combining charachers, double-wide hieroglyphs, obscure
|
||||
characters in dozens of ancient scripts...
|
||||
Many terminals, terminal emulators, xterms etc will fail
|
||||
to handle them correctly. Choose the smallest value
|
||||
which suits your needs.
|
||||
|
||||
Typical values are:
|
||||
126 - ASCII only
|
||||
767 (0x2ff) - there are no combining chars in [0..767] range
|
||||
(the range includes Latin 1, Latin Ext. A and B),
|
||||
code is ~700 bytes smaller for this case.
|
||||
4351 (0x10ff) - there are no double-wide chars in [0..4351] range,
|
||||
code is ~300 bytes smaller for this case.
|
||||
12799 (0x31ff) - nearly all non-ideographic characters are
|
||||
available in [0..12799] range, including
|
||||
East Asian scripts like katakana, hiragana, hangul,
|
||||
bopomofo...
|
||||
0 - off, any valid printable Unicode character will be printed.
|
||||
|
||||
config UNICODE_COMBINING_WCHARS
|
||||
bool "Allow zero-width Unicode characters on output"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT
|
||||
help
|
||||
With this option off, any Unicode char with width of 0
|
||||
is substituted on output.
|
||||
|
||||
config UNICODE_WIDE_WCHARS
|
||||
bool "Allow wide Unicode characters on output"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT
|
||||
help
|
||||
With this option off, any Unicode char with width > 1
|
||||
is substituted on output.
|
||||
|
||||
config UNICODE_BIDI_SUPPORT
|
||||
bool "Bidirectional character-aware line input"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE
|
||||
help
|
||||
With this option on, right-to-left Unicode characters
|
||||
are treated differently on input (e.g. cursor movement).
|
||||
|
||||
config UNICODE_NEUTRAL_TABLE
|
||||
bool "In bidi input, support non-ASCII neutral chars too"
|
||||
default n
|
||||
depends on UNICODE_BIDI_SUPPORT
|
||||
help
|
||||
In most cases it's enough to treat only ASCII non-letters
|
||||
(i.e. punctuation, numbers and space) as characters
|
||||
with neutral directionality.
|
||||
With this option on, more extensive (and bigger) table
|
||||
of neutral chars will be used.
|
||||
|
||||
config UNICODE_PRESERVE_BROKEN
|
||||
bool "Make it possible to enter sequences of chars which are not Unicode"
|
||||
default n
|
||||
depends on UNICODE_SUPPORT
|
||||
help
|
||||
With this option on, on line-editing input (such as used by shells)
|
||||
invalid UTF-8 bytes are not substituted with the selected
|
||||
substitution character.
|
||||
For example, this means that entering 'l', 's', ' ', 0xff, [Enter]
|
||||
at shell prompt will list file named 0xff (single char name
|
||||
with char value 255), not file named '?'.
|
||||
|
||||
config PAM
|
||||
bool "Support for PAM (Pluggable Authentication Modules)"
|
||||
default n
|
||||
help
|
||||
Use PAM in some busybox applets (currently login and httpd) instead
|
||||
of direct access to password database.
|
||||
|
||||
config LONG_OPTS
|
||||
bool "Support for --long-options"
|
||||
default y
|
||||
help
|
||||
Enable this if you want busybox applets to use the gnu --long-option
|
||||
style, in addition to single character -a -b -c style options.
|
||||
|
||||
config FEATURE_DEVPTS
|
||||
bool "Use the devpts filesystem for Unix98 PTYs"
|
||||
default y
|
||||
help
|
||||
Enable if you want BusyBox to use Unix98 PTY support. If enabled,
|
||||
busybox will use /dev/ptmx for the master side of the pseudoterminal
|
||||
and /dev/pts/<number> for the slave side. Otherwise, BSD style
|
||||
/dev/ttyp<number> will be used. To use this option, you should have
|
||||
devpts mounted.
|
||||
|
||||
config FEATURE_CLEAN_UP
|
||||
bool "Clean up all memory before exiting (usually not needed)"
|
||||
default n
|
||||
help
|
||||
As a size optimization, busybox normally exits without explicitly
|
||||
freeing dynamically allocated memory or closing files. This saves
|
||||
space since the OS will clean up for us, but it can confuse debuggers
|
||||
like valgrind, which report tons of memory and resource leaks.
|
||||
|
||||
Don't enable this unless you have a really good reason to clean
|
||||
things up manually.
|
||||
|
||||
config FEATURE_UTMP
|
||||
bool "Support utmp file"
|
||||
default y
|
||||
help
|
||||
The file /var/run/utmp is used to track who is currently logged in.
|
||||
With this option on, certain applets (getty, login, telnetd etc)
|
||||
will create and delete entries there.
|
||||
"who" applet requires this option.
|
||||
|
||||
config FEATURE_WTMP
|
||||
bool "Support wtmp file"
|
||||
default y
|
||||
depends on FEATURE_UTMP
|
||||
help
|
||||
The file /var/run/wtmp is used to track when users have logged into
|
||||
and logged out of the system.
|
||||
With this option on, certain applets (getty, login, telnetd etc)
|
||||
will append new entries there.
|
||||
"last" applet requires this option.
|
||||
|
||||
config FEATURE_PIDFILE
|
||||
bool "Support writing pidfiles"
|
||||
default y
|
||||
help
|
||||
This option makes some applets (e.g. crond, syslogd, inetd) write
|
||||
a pidfile at the configured PID_FILE_PATH. It has no effect
|
||||
on applets which require pidfiles to run.
|
||||
|
||||
config PID_FILE_PATH
|
||||
string "Path to directory for pidfile"
|
||||
default "/var/run"
|
||||
depends on FEATURE_PIDFILE
|
||||
help
|
||||
This is the default path where pidfiles are created. Applets which
|
||||
allow you to set the pidfile path on the command line will override
|
||||
this value. The option has no effect on applets that require you to
|
||||
specify a pidfile path.
|
||||
|
||||
config FEATURE_SUID
|
||||
bool "Support for SUID/SGID handling"
|
||||
default y
|
||||
help
|
||||
With this option you can install the busybox binary belonging
|
||||
to root with the suid bit set, enabling some applets to perform
|
||||
root-level operations even when run by ordinary users
|
||||
(for example, mounting of user mounts in fstab needs this).
|
||||
|
||||
Busybox will automatically drop privileges for applets
|
||||
that don't need root access.
|
||||
|
||||
If you are really paranoid and don't want to do this, build two
|
||||
busybox binaries with different applets in them (and the appropriate
|
||||
symlinks pointing to each binary), and only set the suid bit on the
|
||||
one that needs it.
|
||||
|
||||
The applets which require root rights (need suid bit or
|
||||
to be run by root) and will refuse to execute otherwise:
|
||||
crontab, login, passwd, su, vlock, wall.
|
||||
|
||||
The applets which will use root rights if they have them
|
||||
(via suid bit, or because run by root), but would try to work
|
||||
without root right nevertheless:
|
||||
findfs, ping[6], traceroute[6], mount.
|
||||
|
||||
Note that if you DONT select this option, but DO make busybox
|
||||
suid root, ALL applets will run under root, which is a huge
|
||||
security hole (think "cp /some/file /etc/passwd").
|
||||
|
||||
config FEATURE_SUID_CONFIG
|
||||
bool "Runtime SUID/SGID configuration via /etc/busybox.conf"
|
||||
default y
|
||||
depends on FEATURE_SUID
|
||||
help
|
||||
Allow the SUID / SGID state of an applet to be determined at runtime
|
||||
by checking /etc/busybox.conf. (This is sort of a poor man's sudo.)
|
||||
The format of this file is as follows:
|
||||
|
||||
APPLET = [Ssx-][Ssx-][x-] [USER.GROUP]
|
||||
|
||||
s: USER or GROUP is allowed to execute APPLET.
|
||||
APPLET will run under USER or GROUP
|
||||
(reagardless of who's running it).
|
||||
S: USER or GROUP is NOT allowed to execute APPLET.
|
||||
APPLET will run under USER or GROUP.
|
||||
This option is not very sensical.
|
||||
x: USER/GROUP/others are allowed to execute APPLET.
|
||||
No UID/GID change will be done when it is run.
|
||||
-: USER/GROUP/others are not allowed to execute APPLET.
|
||||
|
||||
An example might help:
|
||||
|
||||
[SUID]
|
||||
su = ssx root.0 # applet su can be run by anyone and runs with
|
||||
# euid=0/egid=0
|
||||
su = ssx # exactly the same
|
||||
|
||||
mount = sx- root.disk # applet mount can be run by root and members
|
||||
# of group disk (but not anyone else)
|
||||
# and runs with euid=0 (egid is not changed)
|
||||
|
||||
cp = --- # disable applet cp for everyone
|
||||
|
||||
The file has to be owned by user root, group root and has to be
|
||||
writeable only by root:
|
||||
(chown 0.0 /etc/busybox.conf; chmod 600 /etc/busybox.conf)
|
||||
The busybox executable has to be owned by user root, group
|
||||
root and has to be setuid root for this to work:
|
||||
(chown 0.0 /bin/busybox; chmod 4755 /bin/busybox)
|
||||
|
||||
Robert 'sandman' Griebl has more information here:
|
||||
<url: http://www.softforge.de/bb/suid.html >.
|
||||
|
||||
config FEATURE_SUID_CONFIG_QUIET
|
||||
bool "Suppress warning message if /etc/busybox.conf is not readable"
|
||||
default y
|
||||
depends on FEATURE_SUID_CONFIG
|
||||
help
|
||||
/etc/busybox.conf should be readable by the user needing the SUID,
|
||||
check this option to avoid users to be notified about missing
|
||||
permissions.
|
||||
|
||||
config SELINUX
|
||||
bool "Support NSA Security Enhanced Linux"
|
||||
default n
|
||||
select PLATFORM_LINUX
|
||||
help
|
||||
Enable support for SELinux in applets ls, ps, and id. Also provide
|
||||
the option of compiling in SELinux applets.
|
||||
|
||||
If you do not have a complete SELinux userland installed, this stuff
|
||||
will not compile. Specifially, libselinux 1.28 or better is
|
||||
directly required by busybox. If the installation is located in a
|
||||
non-standard directory, provide it by invoking make as follows:
|
||||
CFLAGS=-I<libselinux-include-path> \
|
||||
LDFLAGS=-L<libselinux-lib-path> \
|
||||
make
|
||||
|
||||
Most people will leave this set to 'N'.
|
||||
|
||||
config FEATURE_PREFER_APPLETS
|
||||
bool "exec prefers applets"
|
||||
default n
|
||||
help
|
||||
This is an experimental option which directs applets about to
|
||||
call 'exec' to try and find an applicable busybox applet before
|
||||
searching the PATH. This is typically done by exec'ing
|
||||
/proc/self/exe.
|
||||
This may affect shell, find -exec, xargs and similar applets.
|
||||
They will use applets even if /bin/<applet> -> busybox link
|
||||
is missing (or is not a link to busybox). However, this causes
|
||||
problems in chroot jails without mounted /proc and with ps/top
|
||||
(command name can be shown as 'exe' for applets started this way).
|
||||
|
||||
config BUSYBOX_EXEC_PATH
|
||||
string "Path to BusyBox executable"
|
||||
default "/proc/self/exe"
|
||||
help
|
||||
When Busybox applets need to run other busybox applets, BusyBox
|
||||
sometimes needs to exec() itself. When the /proc filesystem is
|
||||
mounted, /proc/self/exe always points to the currently running
|
||||
executable. If you haven't got /proc, set this to wherever you
|
||||
want to run BusyBox from.
|
||||
|
||||
# These are auto-selected by other options
|
||||
|
||||
config FEATURE_SYSLOG
|
||||
bool #No description makes it a hidden option
|
||||
default n
|
||||
#help
|
||||
# This option is auto-selected when you select any applet which may
|
||||
# send its output to syslog. You do not need to select it manually.
|
||||
|
||||
config FEATURE_HAVE_RPC
|
||||
bool #No description makes it a hidden option
|
||||
default n
|
||||
#help
|
||||
# This is automatically selected if any of enabled applets need it.
|
||||
# You do not need to select it manually.
|
||||
|
||||
endmenu
|
||||
|
||||
menu 'Build Options'
|
||||
|
||||
config STATIC
|
||||
bool "Build BusyBox as a static binary (no shared libs)"
|
||||
default n
|
||||
help
|
||||
If you want to build a static BusyBox binary, which does not
|
||||
use or require any shared libraries, then enable this option.
|
||||
This can cause BusyBox to be considerably larger, so you should
|
||||
leave this option false unless you have a good reason (i.e.
|
||||
your target platform does not support shared libraries, or
|
||||
you are building an initrd which doesn't need anything but
|
||||
BusyBox, etc).
|
||||
|
||||
Most people will leave this set to 'N'.
|
||||
|
||||
config PIE
|
||||
bool "Build BusyBox as a position independent executable"
|
||||
default n
|
||||
depends on !STATIC
|
||||
help
|
||||
Hardened code option. PIE binaries are loaded at a different
|
||||
address at each invocation. This has some overhead,
|
||||
particularly on x86-32 which is short on registers.
|
||||
|
||||
Most people will leave this set to 'N'.
|
||||
|
||||
config NOMMU
|
||||
bool "Force NOMMU build"
|
||||
default n
|
||||
help
|
||||
Busybox tries to detect whether architecture it is being
|
||||
built against supports MMU or not. If this detection fails,
|
||||
or if you want to build NOMMU version of busybox for testing,
|
||||
you may force NOMMU build here.
|
||||
|
||||
Most people will leave this set to 'N'.
|
||||
|
||||
# PIE can be made to work with BUILD_LIBBUSYBOX, but currently
|
||||
# build system does not support that
|
||||
config BUILD_LIBBUSYBOX
|
||||
bool "Build shared libbusybox"
|
||||
default n
|
||||
depends on !FEATURE_PREFER_APPLETS && !PIE && !STATIC
|
||||
help
|
||||
Build a shared library libbusybox.so.N.N.N which contains all
|
||||
busybox code.
|
||||
|
||||
This feature allows every applet to be built as a tiny
|
||||
separate executable. Enabling it for "one big busybox binary"
|
||||
approach serves no purpose and increases code size.
|
||||
You should almost certainly say "no" to this.
|
||||
|
||||
### config FEATURE_FULL_LIBBUSYBOX
|
||||
### bool "Feature-complete libbusybox"
|
||||
### default n if !FEATURE_SHARED_BUSYBOX
|
||||
### depends on BUILD_LIBBUSYBOX
|
||||
### help
|
||||
### Build a libbusybox with the complete feature-set, disregarding
|
||||
### the actually selected config.
|
||||
###
|
||||
### Normally, libbusybox will only contain the features which are
|
||||
### used by busybox itself. If you plan to write a separate
|
||||
### standalone application which uses libbusybox say 'Y'.
|
||||
###
|
||||
### Note: libbusybox is GPL, not LGPL, and exports no stable API that
|
||||
### might act as a copyright barrier. We can and will modify the
|
||||
### exported function set between releases (even minor version number
|
||||
### changes), and happily break out-of-tree features.
|
||||
###
|
||||
### Say 'N' if in doubt.
|
||||
|
||||
config FEATURE_INDIVIDUAL
|
||||
bool "Produce a binary for each applet, linked against libbusybox"
|
||||
default y
|
||||
depends on BUILD_LIBBUSYBOX
|
||||
help
|
||||
If your CPU architecture doesn't allow for sharing text/rodata
|
||||
sections of running binaries, but allows for runtime dynamic
|
||||
libraries, this option will allow you to reduce memory footprint
|
||||
when you have many different applets running at once.
|
||||
|
||||
If your CPU architecture allows for sharing text/rodata,
|
||||
having single binary is more optimal.
|
||||
|
||||
Each applet will be a tiny program, dynamically linked
|
||||
against libbusybox.so.N.N.N.
|
||||
|
||||
You need to have a working dynamic linker.
|
||||
|
||||
config FEATURE_SHARED_BUSYBOX
|
||||
bool "Produce additional busybox binary linked against libbusybox"
|
||||
default y
|
||||
depends on BUILD_LIBBUSYBOX
|
||||
help
|
||||
Build busybox, dynamically linked against libbusybox.so.N.N.N.
|
||||
|
||||
You need to have a working dynamic linker.
|
||||
|
||||
### config BUILD_AT_ONCE
|
||||
### bool "Compile all sources at once"
|
||||
### default n
|
||||
### help
|
||||
### Normally each source-file is compiled with one invocation of
|
||||
### the compiler.
|
||||
### If you set this option, all sources are compiled at once.
|
||||
### This gives the compiler more opportunities to optimize which can
|
||||
### result in smaller and/or faster binaries.
|
||||
###
|
||||
### Setting this option will consume alot of memory, e.g. if you
|
||||
### enable all applets with all features, gcc uses more than 300MB
|
||||
### RAM during compilation of busybox.
|
||||
###
|
||||
### This option is most likely only beneficial for newer compilers
|
||||
### such as gcc-4.1 and above.
|
||||
###
|
||||
### Say 'N' unless you know what you are doing.
|
||||
|
||||
config LFS
|
||||
bool "Build with Large File Support (for accessing files > 2 GB)"
|
||||
default y
|
||||
help
|
||||
If you want to build BusyBox with large file support, then enable
|
||||
this option. This will have no effect if your kernel or your C
|
||||
library lacks large file support for large files. Some of the
|
||||
programs that can benefit from large file support include dd, gzip,
|
||||
cp, mount, tar, and many others. If you want to access files larger
|
||||
than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'.
|
||||
|
||||
config CROSS_COMPILER_PREFIX
|
||||
string "Cross Compiler prefix"
|
||||
default ""
|
||||
help
|
||||
If you want to build BusyBox with a cross compiler, then you
|
||||
will need to set this to the cross-compiler prefix, for example,
|
||||
"i386-uclibc-".
|
||||
|
||||
Note that CROSS_COMPILE environment variable or
|
||||
"make CROSS_COMPILE=xxx ..." will override this selection.
|
||||
|
||||
Native builds leave this empty.
|
||||
|
||||
config SYSROOT
|
||||
string "Path to sysroot"
|
||||
default ""
|
||||
help
|
||||
If you want to build BusyBox with a cross compiler, then you
|
||||
might also need to specify where /usr/include and /usr/lib
|
||||
will be found.
|
||||
|
||||
For example, BusyBox can be built against an installed
|
||||
Android NDK, platform version 9, for ARM ABI with
|
||||
|
||||
CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm
|
||||
|
||||
Native builds leave this empty.
|
||||
|
||||
config EXTRA_CFLAGS
|
||||
string "Additional CFLAGS"
|
||||
default ""
|
||||
help
|
||||
Additional CFLAGS to pass to the compiler verbatim.
|
||||
|
||||
config EXTRA_LDFLAGS
|
||||
string "Additional LDFLAGS"
|
||||
default ""
|
||||
help
|
||||
Additional LDFLAGS to pass to the linker verbatim.
|
||||
|
||||
config EXTRA_LDLIBS
|
||||
string "Additional LDLIBS"
|
||||
default ""
|
||||
help
|
||||
Additional LDLIBS to pass to the linker with -l.
|
||||
|
||||
endmenu
|
||||
|
||||
menu 'Debugging Options'
|
||||
|
||||
config DEBUG
|
||||
bool "Build BusyBox with extra Debugging symbols"
|
||||
default n
|
||||
help
|
||||
Say Y here if you wish to examine BusyBox internals while applets are
|
||||
running. This increases the size of the binary considerably, and
|
||||
should only be used when doing development. If you are doing
|
||||
development and want to debug BusyBox, answer Y.
|
||||
|
||||
Most people should answer N.
|
||||
|
||||
config DEBUG_PESSIMIZE
|
||||
bool "Disable compiler optimizations"
|
||||
default n
|
||||
depends on DEBUG
|
||||
help
|
||||
The compiler's optimization of source code can eliminate and reorder
|
||||
code, resulting in an executable that's hard to understand when
|
||||
stepping through it with a debugger. This switches it off, resulting
|
||||
in a much bigger executable that more closely matches the source
|
||||
code.
|
||||
|
||||
config UNIT_TEST
|
||||
bool "Build unit tests"
|
||||
default n
|
||||
help
|
||||
Say Y here if you want to build unit tests (both the framework and
|
||||
test cases) as a Busybox applet. This results in bigger code, so you
|
||||
probably don't want this option in production builds.
|
||||
|
||||
config WERROR
|
||||
bool "Abort compilation on any warning"
|
||||
default n
|
||||
help
|
||||
Selecting this will add -Werror to gcc command line.
|
||||
|
||||
Most people should answer N.
|
||||
|
||||
choice
|
||||
prompt "Additional debugging library"
|
||||
default NO_DEBUG_LIB
|
||||
help
|
||||
Using an additional debugging library will make BusyBox become
|
||||
considerable larger and will cause it to run more slowly. You
|
||||
should always leave this option disabled for production use.
|
||||
|
||||
dmalloc support:
|
||||
----------------
|
||||
This enables compiling with dmalloc ( http://dmalloc.com/ )
|
||||
which is an excellent public domain mem leak and malloc problem
|
||||
detector. To enable dmalloc, before running busybox you will
|
||||
want to properly set your environment, for example:
|
||||
export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile
|
||||
The 'debug=' value is generated using the following command
|
||||
dmalloc -p log-stats -p log-non-free -p log-bad-space \
|
||||
-p log-elapsed-time -p check-fence -p check-heap \
|
||||
-p check-lists -p check-blank -p check-funcs -p realloc-copy \
|
||||
-p allow-free-null
|
||||
|
||||
Electric-fence support:
|
||||
-----------------------
|
||||
This enables compiling with Electric-fence support. Electric
|
||||
fence is another very useful malloc debugging library which uses
|
||||
your computer's virtual memory hardware to detect illegal memory
|
||||
accesses. This support will make BusyBox be considerable larger
|
||||
and run slower, so you should leave this option disabled unless
|
||||
you are hunting a hard to find memory problem.
|
||||
|
||||
|
||||
config NO_DEBUG_LIB
|
||||
bool "None"
|
||||
|
||||
config DMALLOC
|
||||
bool "Dmalloc"
|
||||
|
||||
config EFENCE
|
||||
bool "Electric-fence"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
menu 'Installation Options ("make install" behavior)'
|
||||
|
||||
choice
|
||||
prompt "What kind of applet links to install"
|
||||
default INSTALL_APPLET_SYMLINKS
|
||||
help
|
||||
Choose what kind of links to applets are created by "make install".
|
||||
|
||||
config INSTALL_APPLET_SYMLINKS
|
||||
bool "as soft-links"
|
||||
help
|
||||
Install applets as soft-links to the busybox binary. This needs some
|
||||
free inodes on the filesystem, but might help with filesystem
|
||||
generators that can't cope with hard-links.
|
||||
|
||||
config INSTALL_APPLET_HARDLINKS
|
||||
bool "as hard-links"
|
||||
help
|
||||
Install applets as hard-links to the busybox binary. This might
|
||||
count on a filesystem with few inodes.
|
||||
|
||||
config INSTALL_APPLET_SCRIPT_WRAPPERS
|
||||
bool "as script wrappers"
|
||||
help
|
||||
Install applets as script wrappers that call the busybox binary.
|
||||
|
||||
config INSTALL_APPLET_DONT
|
||||
bool "not installed"
|
||||
help
|
||||
Do not install applet links. Useful when you plan to use
|
||||
busybox --install for installing links, or plan to use
|
||||
a standalone shell and thus don't need applet links.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "/bin/sh applet link"
|
||||
default INSTALL_SH_APPLET_SYMLINK
|
||||
depends on INSTALL_APPLET_SCRIPT_WRAPPERS
|
||||
help
|
||||
Choose how you install /bin/sh applet link.
|
||||
|
||||
config INSTALL_SH_APPLET_SYMLINK
|
||||
bool "as soft-link"
|
||||
help
|
||||
Install /bin/sh applet as soft-link to the busybox binary.
|
||||
|
||||
config INSTALL_SH_APPLET_HARDLINK
|
||||
bool "as hard-link"
|
||||
help
|
||||
Install /bin/sh applet as hard-link to the busybox binary.
|
||||
|
||||
config INSTALL_SH_APPLET_SCRIPT_WRAPPER
|
||||
bool "as script wrapper"
|
||||
help
|
||||
Install /bin/sh applet as script wrapper that calls
|
||||
the busybox binary.
|
||||
|
||||
endchoice
|
||||
|
||||
config PREFIX
|
||||
string "BusyBox installation prefix"
|
||||
default "./_install"
|
||||
help
|
||||
Define your directory to install BusyBox files/subdirs in.
|
||||
|
||||
endmenu
|
||||
|
||||
source libbb/Config.in
|
||||
|
||||
endmenu
|
||||
|
||||
comment "Applets"
|
||||
|
||||
source archival/Config.in
|
||||
source coreutils/Config.in
|
||||
source console-tools/Config.in
|
||||
source debianutils/Config.in
|
||||
source editors/Config.in
|
||||
source findutils/Config.in
|
||||
source init/Config.in
|
||||
source loginutils/Config.in
|
||||
source e2fsprogs/Config.in
|
||||
source modutils/Config.in
|
||||
source util-linux/Config.in
|
||||
source miscutils/Config.in
|
||||
source networking/Config.in
|
||||
source printutils/Config.in
|
||||
source mailutils/Config.in
|
||||
source procps/Config.in
|
||||
source runit/Config.in
|
||||
source selinux/Config.in
|
||||
source shell/Config.in
|
||||
source sysklogd/Config.in
|
142
INSTALL
142
INSTALL
@ -1,142 +0,0 @@
|
||||
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
|
191
Makefile.custom
191
Makefile.custom
@ -1,191 +0,0 @@
|
||||
# ==========================================================================
|
||||
# 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_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
|
||||
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
|
||||
|
||||
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
|
179
Makefile.flags
179
Makefile.flags
@ -1,179 +0,0 @@
|
||||
# ==========================================================================
|
||||
# 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) \
|
||||
-D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP
|
||||
|
||||
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)
|
||||
|
||||
CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -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 -static-libgcc,)
|
||||
CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,)
|
||||
# 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,)
|
||||
|
||||
# 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,-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,-Os,$(call cc-option,-O2,))
|
||||
endif
|
||||
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
|
||||
|
||||
# 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;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c)
|
||||
ifeq ($(CRYPT_AVAILABLE),y)
|
||||
LDLIBS += m crypt
|
||||
else
|
||||
LDLIBS += m
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PAM),y)
|
||||
# libpam uses libpthread, so for static builds busybox must be linked to
|
||||
# libpthread. On some platforms that requires an explicit -lpthread, so
|
||||
# it should be in LDLIBS. For non-static builds, scripts/trylink will
|
||||
# take care of removing -lpthread if possible. (Not bothering to check
|
||||
# CONFIG_STATIC because even in a non-static build it could be that the
|
||||
# only libpam available is libpam.a, so -lpthread could still be
|
||||
# needed.)
|
||||
LDLIBS += pam pam_misc pthread
|
||||
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_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),)
|
||||
EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS)))
|
||||
#"))
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_EXTRA_LDLIBS),)
|
||||
LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS)))
|
||||
#"))
|
||||
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
|
@ -1,44 +0,0 @@
|
||||
# ==========================================================================
|
||||
# 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
|
204
README
204
README
@ -1,204 +0,0 @@
|
||||
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, v850e, and x86_64. 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>
|
262
TODO
262
TODO
@ -1,262 +0,0 @@
|
||||
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.
|
||||
---
|
||||
support start-stop-daemon -d <chdir-path>
|
||||
---
|
||||
vdprintf() -> similar sized functionality
|
||||
---
|
||||
|
||||
(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
|
||||
|
||||
* even more support for statistics: mpstat, iostat, powertop....
|
45
TODO_unicode
45
TODO_unicode
@ -1,45 +0,0 @@
|
||||
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
applets/.gitignore
vendored
3
applets/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/applet_tables
|
||||
/usage
|
||||
/usage_pod
|
@ -1,47 +0,0 @@
|
||||
# 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/applet_tables.h include/applets.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
|
||||
cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h
|
||||
|
||||
include/applet_tables.h: applets/applet_tables
|
||||
$(call cmd,gen_applet_tables)
|
||||
|
||||
include/NUM_APPLETS.h: applets/applet_tables
|
||||
$(call cmd,gen_applet_tables)
|
@ -1,174 +0,0 @@
|
||||
/* 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 <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])))
|
||||
|
||||
#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 offset[NUM_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(*s) && *s != '_')
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int ofs;
|
||||
// unsigned MAX_APPLET_NAME_LEN = 1;
|
||||
|
||||
qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name);
|
||||
|
||||
ofs = 0;
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
offset[i] = ofs;
|
||||
ofs += strlen(applets[i].name) + 1;
|
||||
}
|
||||
/* We reuse 4 high-order bits of offset array for other purposes,
|
||||
* so if they are indeed needed, refuse to proceed */
|
||||
if (ofs > 0xfff)
|
||||
return 1;
|
||||
if (!argv[1])
|
||||
return 1;
|
||||
|
||||
i = open(argv[1], 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("\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");
|
||||
|
||||
printf("const uint16_t applet_nameofs[] ALIGN2 = {\n");
|
||||
for (i = 0; i < NUM_APPLETS; i++) {
|
||||
printf("0x%04x,\n",
|
||||
offset[i]
|
||||
#if ENABLE_FEATURE_PREFER_APPLETS
|
||||
+ (applets[i].nofork << 12)
|
||||
+ (applets[i].noexec << 13)
|
||||
#endif
|
||||
#if ENABLE_FEATURE_SUID
|
||||
+ (applets[i].need_suid << 14) /* 2 bits */
|
||||
#endif
|
||||
);
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
#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]) {
|
||||
char line_old[80];
|
||||
char line_new[80];
|
||||
FILE *fp;
|
||||
|
||||
line_old[0] = 0;
|
||||
fp = fopen(argv[2], "r");
|
||||
if (fp) {
|
||||
fgets(line_old, sizeof(line_old), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS);
|
||||
if (strcmp(line_old, line_new) != 0) {
|
||||
fp = fopen(argv[2], "w");
|
||||
if (!fp)
|
||||
return 1;
|
||||
fputs(line_new, fp);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
/* 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
|
@ -1,24 +0,0 @@
|
||||
#!/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
|
||||
}'
|
@ -1,54 +0,0 @@
|
||||
#!/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
|
||||
|
@ -1,24 +0,0 @@
|
||||
/* 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(APPLET_full_usage "\n", stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LC_ALL=POSIX
|
||||
export LC_CTYPE=POSIX
|
||||
|
||||
prefix=$1
|
||||
if [ -z "$prefix" ]; then
|
||||
echo "usage: applets/install.sh DESTINATION [--symlinks/--hardlinks/--scriptwrapper]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
h=`sort busybox.links | uniq`
|
||||
|
||||
linkopts=""
|
||||
scriptwrapper="n"
|
||||
cleanup="0"
|
||||
noclobber="0"
|
||||
case "$2" in
|
||||
--hardlinks) linkopts="-f";;
|
||||
--symlinks) linkopts="-fs";;
|
||||
--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";;
|
||||
"") h="";;
|
||||
*) echo "Unknown install option: $2"; exit 1;;
|
||||
esac
|
||||
|
||||
if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "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
|
||||
cp -pPR "$i" "$prefix/$libdir/" || exit 1
|
||||
chmod 0644 "$prefix/$libdir/$i" || exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$cleanup" = "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"`
|
||||
mkdir -p "$prefix/$appdir" || exit 1
|
||||
if [ "$scriptwrapper" = "y" ]; then
|
||||
if [ "$swrapall" != "y" ] && [ "$i" = "/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"
|
||||
else
|
||||
if [ "$2" = "--hardlinks" ]; 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
|
||||
if [ "$noclobber" = "0" ] || [ ! -e "$prefix/$i" ]; then
|
||||
echo " $prefix/$i -> $bb_path"
|
||||
ln $linkopts "$bb_path" "$prefix/$i" || exit 1
|
||||
else
|
||||
echo " $prefix/$i already exists"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
@ -1,55 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#!/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 \
|
||||
| $SED -e 's/^[^ ]*//' \
|
||||
-e 's/ //g' \
|
||||
-e '/^$/d' \
|
||||
-e 's/\(...\)/\\\1/g' \
|
||||
-e 's/^/"/' \
|
||||
-e 's/$/" \\/'
|
||||
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 \
|
||||
| $SED -e 's/^[^ ]*//' \
|
||||
-e 's/ //g' \
|
||||
-e '/^$/d' \
|
||||
-e 's/\(...\)/0\1,/g' \
|
||||
-e 's/$/ \\/'
|
||||
echo ''
|
||||
|
||||
mv -- "$target.$$" "$target"
|
@ -1,111 +0,0 @@
|
||||
/* 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(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);
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
*/
|
@ -1,5 +0,0 @@
|
||||
This directory contains examples of applets implemented as shell scripts.
|
||||
|
||||
So far these scripts are not hooked to the build system and are not
|
||||
installed by "make install". If you want to use them,
|
||||
you need to install them by hand.
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
# TODO: use getopt to avoid parsing options as filenames,
|
||||
# and to support -- and --help
|
||||
[ $# -ne 0 ] && DASH_I=-i
|
||||
sed $DASH_I -e 's/\r$//' "$@"
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cat /etc/nologin.txt 2>/dev/null || echo "This account is not available"
|
||||
sleep 5
|
||||
exit 1
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
# TODO: use getopt to avoid parsing options as filenames,
|
||||
# and to support -- and --help
|
||||
for i in "$@"
|
||||
do
|
||||
sed -e '1!G;h;$!d' "$i"
|
||||
done
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
# TODO: use getopt to avoid parsing options as filenames,
|
||||
# and to support -- and --help
|
||||
[ $# -ne 0 ] && DASH_I=-i
|
||||
sed $DASH_I -e 's/$/\r/' "$@"
|
@ -1,7 +0,0 @@
|
||||
# ==========================================================================
|
||||
# Build system
|
||||
# ==========================================================================
|
||||
|
||||
# -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,-march=i386 -mpreferred-stack-boundary=2,)
|
@ -1,40 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see scripts/kbuild/config-language.txt.
|
||||
#
|
||||
|
||||
menu "Archival Utilities"
|
||||
|
||||
config FEATURE_SEAMLESS_XZ
|
||||
bool "Make tar, rpm, modprobe etc understand .xz data"
|
||||
default y
|
||||
help
|
||||
Make tar, rpm, modprobe etc understand .xz data.
|
||||
|
||||
config FEATURE_SEAMLESS_LZMA
|
||||
bool "Make tar, rpm, modprobe etc understand .lzma data"
|
||||
default y
|
||||
help
|
||||
Make tar, rpm, modprobe etc understand .lzma data.
|
||||
|
||||
config FEATURE_SEAMLESS_BZ2
|
||||
bool "Make tar, rpm, modprobe etc understand .bz2 data"
|
||||
default y
|
||||
help
|
||||
Make tar, rpm, modprobe etc understand .bz2 data.
|
||||
|
||||
config FEATURE_SEAMLESS_GZ
|
||||
bool "Make tar, rpm, modprobe etc understand .gz data"
|
||||
default y
|
||||
help
|
||||
Make tar, rpm, modprobe etc understand .gz data.
|
||||
|
||||
config FEATURE_SEAMLESS_Z
|
||||
bool "tar, rpm, modprobe etc understand .Z data"
|
||||
default n
|
||||
help
|
||||
Make tar, rpm, modprobe etc understand .Z data.
|
||||
|
||||
INSERT
|
||||
|
||||
endmenu
|
@ -1,11 +0,0 @@
|
||||
# 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
|
304
archival/ar.c
304
archival/ar.c
@ -1,304 +0,0 @@
|
||||
/* 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"
|
||||
//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. An archive is a single file holding
|
||||
//config: a collection of other files in a structure that makes it possible to
|
||||
//config: retrieve the original individual files (called archive members).
|
||||
//config: The original files' contents, mode (permissions), timestamp, owner,
|
||||
//config: and group are preserved in the archive, and can be restored on
|
||||
//config: extraction.
|
||||
//config:
|
||||
//config: The stored filename is limited to 15 characters. (for more information
|
||||
//config: see long filename support).
|
||||
//config: ar has 60 bytes of overheads for every stored file.
|
||||
//config:
|
||||
//config: This implementation of ar can extract archives, it cannot create or
|
||||
//config: modify them.
|
||||
//config: On an x86 system, the ar applet adds about 1K.
|
||||
//config:
|
||||
//config: Unless you have a specific application which requires ar, you should
|
||||
//config: probably say N here.
|
||||
//config:
|
||||
//config:config FEATURE_AR_LONG_FILENAMES
|
||||
//config: bool "Support for 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
|
||||
|
||||
//usage:#define ar_trivial_usage
|
||||
//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES"
|
||||
//usage:#define ar_full_usage "\n\n"
|
||||
//usage: "Extract or list FILES from an ar archive\n"
|
||||
//usage: "\n -o Preserve original dates"
|
||||
//usage: "\n -p Extract to stdout"
|
||||
//usage: "\n -t List"
|
||||
//usage: "\n -x Extract"
|
||||
//usage: "\n -v Verbose"
|
||||
|
||||
#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)
|
||||
{
|
||||
const char *mode = bb_mode_string(file_header->mode);
|
||||
char *mtime;
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
#define AR_OPT_VERBOSE (1 << 0)
|
||||
#define AR_OPT_PRESERVE_DATE (1 << 1)
|
||||
/* "ar r" implies create, but warns about it. c suppresses warning.
|
||||
* bbox accepts but ignores it: */
|
||||
#define AR_OPT_CREATE (1 << 2)
|
||||
|
||||
#define AR_CMD_PRINT (1 << 3)
|
||||
#define FIRST_CMD AR_CMD_PRINT
|
||||
#define AR_CMD_LIST (1 << 4)
|
||||
#define AR_CMD_EXTRACT (1 << 5)
|
||||
#define AR_CMD_INSERT (1 << 6)
|
||||
|
||||
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;
|
||||
|
||||
archive_handle = init_handle();
|
||||
|
||||
/* --: prepend '-' to the first argument if required */
|
||||
/* -1: at least one param is reqd */
|
||||
/* one of p,t,x[,r] is required */
|
||||
opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r");
|
||||
opt = getopt32(argv, "voc""ptx"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 & AR_CMD_PRINT) {
|
||||
archive_handle->action_data = data_extract_to_stdout;
|
||||
}
|
||||
if (opt & AR_CMD_LIST) {
|
||||
archive_handle->action_header = header_list;
|
||||
}
|
||||
if (opt & AR_CMD_EXTRACT) {
|
||||
archive_handle->action_data = data_extract_all;
|
||||
}
|
||||
if (opt & AR_OPT_PRESERVE_DATE) {
|
||||
archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
|
||||
}
|
||||
if (opt & AR_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 & AR_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 & AR_CMD_INSERT)
|
||||
return write_ar_archive(archive_handle);
|
||||
#endif
|
||||
|
||||
unpack_ar_archive(archive_handle);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,561 +0,0 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Common code for gunzip-like applets
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
/* lzop_main() uses bbunpack(), need this: */
|
||||
//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o
|
||||
|
||||
/* Note: must be kept in sync with archival/lzop.c */
|
||||
enum {
|
||||
OPT_STDOUT = 1 << 0,
|
||||
OPT_FORCE = 1 << 1,
|
||||
/* only some decompressors: */
|
||||
OPT_VERBOSE = 1 << 2,
|
||||
OPT_QUIET = 1 << 3,
|
||||
OPT_DECOMPRESS = 1 << 4,
|
||||
OPT_TEST = 1 << 5,
|
||||
SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION,
|
||||
};
|
||||
|
||||
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_aux_data_t *aux),
|
||||
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_aux_data_t aux;
|
||||
|
||||
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 & 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 & 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 & (OPT_STDOUT|OPT_TEST)) {
|
||||
if (option_mask32 & 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 & 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 & OPT_FORCE) && isatty(STDIN_FILENO)) {
|
||||
bb_error_msg_and_die("compressed data not read from terminal, "
|
||||
"use -f to force it");
|
||||
}
|
||||
|
||||
if (!(option_mask32 & SEAMLESS_MAGIC)) {
|
||||
init_transformer_aux_data(&aux);
|
||||
aux.check_signature = 1;
|
||||
status = unpacker(&aux);
|
||||
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 & 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 (aux.mtime != 0) {
|
||||
struct timeval times[2];
|
||||
|
||||
times[1].tv_sec = times[0].tv_sec = aux.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 & 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;
|
||||
}
|
||||
xunlink(del);
|
||||
free_name:
|
||||
if (new_name != filename)
|
||||
free(new_name);
|
||||
}
|
||||
} while (*argv && *++argv);
|
||||
|
||||
if (option_mask32 & OPT_STDOUT)
|
||||
xclose(STDOUT_FILENO); /* with error check! */
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
#if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ
|
||||
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 .Z file[s]\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Overwrite"
|
||||
|
||||
//config:config UNCOMPRESS
|
||||
//config: bool "uncompress"
|
||||
//config: default n
|
||||
//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
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
|
||||
{
|
||||
return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int uncompress_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
getopt32(argv, "cf");
|
||||
argv += optind;
|
||||
|
||||
return bbunpack(argv, unpack_uncompress, 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: "[-cft] [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 -t Test file 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"
|
||||
//config: default y
|
||||
//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.
|
||||
|
||||
//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
|
||||
//applet:IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
|
||||
//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o
|
||||
#if ENABLE_GUNZIP
|
||||
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;
|
||||
}
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
|
||||
{
|
||||
return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
getopt32(argv, "cfvqdtn");
|
||||
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 (applet_name[1] == 'c')
|
||||
option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC;
|
||||
|
||||
return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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: "[-cf] [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:#define bzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define bzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config BUNZIP2
|
||||
//config: bool "bunzip2"
|
||||
//config: default y
|
||||
//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.
|
||||
|
||||
//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
|
||||
//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o
|
||||
//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o
|
||||
#if ENABLE_BUNZIP2
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
|
||||
{
|
||||
return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int bunzip2_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
getopt32(argv, "cfvqdt");
|
||||
argv += optind;
|
||||
if (applet_name[2] == 'c') /* bzcat */
|
||||
option_mask32 |= OPT_STDOUT;
|
||||
|
||||
return bbunpack(argv, unpack_bunzip2, 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: "[-cf] [FILE]..."
|
||||
//usage:#define unlzma_full_usage "\n\n"
|
||||
//usage: "Decompress FILE (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage:
|
||||
//usage:#define lzma_trivial_usage
|
||||
//usage: "-d [-cf] [FILE]..."
|
||||
//usage:#define lzma_full_usage "\n\n"
|
||||
//usage: "Decompress FILE (or stdin)\n"
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage:
|
||||
//usage:#define lzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define lzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
//usage:
|
||||
//usage:#define unxz_trivial_usage
|
||||
//usage: "[-cf] [FILE]..."
|
||||
//usage:#define unxz_full_usage "\n\n"
|
||||
//usage: "Decompress FILE (or stdin)\n"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage:
|
||||
//usage:#define xz_trivial_usage
|
||||
//usage: "-d [-cf] [FILE]..."
|
||||
//usage:#define xz_full_usage "\n\n"
|
||||
//usage: "Decompress FILE (or stdin)\n"
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
//usage:
|
||||
//usage:#define xzcat_trivial_usage
|
||||
//usage: "[FILE]..."
|
||||
//usage:#define xzcat_full_usage "\n\n"
|
||||
//usage: "Decompress to stdout"
|
||||
|
||||
//config:config UNLZMA
|
||||
//config: bool "unlzma"
|
||||
//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: The BusyBox unlzma applet is limited to decompression only.
|
||||
//config: On an x86 system, this applet adds about 4K.
|
||||
//config:
|
||||
//config:config FEATURE_LZMA_FAST
|
||||
//config: bool "Optimize unlzma for speed"
|
||||
//config: default n
|
||||
//config: depends on UNLZMA
|
||||
//config: help
|
||||
//config: This option reduces decompression time by about 25% at the cost of
|
||||
//config: a 1K bigger binary.
|
||||
//config:
|
||||
//config:config LZMA
|
||||
//config: bool "Provide lzma alias which supports only unpacking"
|
||||
//config: default y
|
||||
//config: depends on UNLZMA
|
||||
//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:IF_UNLZMA(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
|
||||
#if ENABLE_UNLZMA
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
|
||||
{
|
||||
return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
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, "cfvqdt");
|
||||
# if ENABLE_LZMA
|
||||
/* lzma without -d or -t? */
|
||||
if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
|
||||
bb_show_usage();
|
||||
# endif
|
||||
/* lzcat? */
|
||||
if (applet_name[2] == 'c')
|
||||
option_mask32 |= OPT_STDOUT;
|
||||
|
||||
argv += optind;
|
||||
return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//config:config UNXZ
|
||||
//config: bool "unxz"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: unxz is a unlzma successor.
|
||||
//config:
|
||||
//config:config XZ
|
||||
//config: bool "Provide xz alias which supports only unpacking"
|
||||
//config: default y
|
||||
//config: depends on UNXZ
|
||||
//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:IF_UNXZ(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
|
||||
#if ENABLE_UNXZ
|
||||
static
|
||||
IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
|
||||
{
|
||||
return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
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, "cfvqdt");
|
||||
# if ENABLE_XZ
|
||||
/* xz without -d or -t? */
|
||||
if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
|
||||
bb_show_usage();
|
||||
# endif
|
||||
/* xzcat? */
|
||||
if (applet_name[2] == 'c')
|
||||
option_mask32 |= OPT_STDOUT;
|
||||
|
||||
argv += optind;
|
||||
return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz");
|
||||
}
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
#!/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
|
@ -1,10 +0,0 @@
|
||||
#!/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
|
@ -1,23 +0,0 @@
|
||||
#!/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
|
206
archival/bzip2.c
206
archival/bzip2.c
@ -1,206 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
//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.
|
||||
|
||||
//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o
|
||||
|
||||
//usage:#define bzip2_trivial_usage
|
||||
//usage: "[OPTIONS] [FILE]..."
|
||||
//usage:#define bzip2_full_usage "\n\n"
|
||||
//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n"
|
||||
//usage: "\n -1..9 Compression level"
|
||||
//usage: "\n -d Decompress"
|
||||
//usage: "\n -c Write to stdout"
|
||||
//usage: "\n -f Force"
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
#define CONFIG_BZIP2_FAST 1
|
||||
|
||||
/* 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 CONFIG_BZIP2_FAST 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 is page aligned and thus (maybe) have one memcpy less
|
||||
* if kernel is clever enough.
|
||||
*/
|
||||
enum {
|
||||
IOBUF_SIZE = 8 * 1024
|
||||
};
|
||||
|
||||
static uint8_t level;
|
||||
|
||||
/* 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_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_aux_data_t *aux UNUSED_PARAM)
|
||||
{
|
||||
IF_DESKTOP(long long) int total;
|
||||
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);
|
||||
BZ2_bzCompressInit(strm, level);
|
||||
|
||||
while (1) {
|
||||
count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE);
|
||||
if (count < 0) {
|
||||
bb_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_complementary = "s2"; /* -s means -2 (compatibility) */
|
||||
/* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
|
||||
opt = getopt32(argv, "cfv" IF_BUNZIP2("dt") "123456789qzs");
|
||||
#if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */
|
||||
if (opt & 0x18) // -d and/or -t
|
||||
return bunzip2_main(argc, argv);
|
||||
opt >>= 5;
|
||||
#else
|
||||
opt >>= 3;
|
||||
#endif
|
||||
opt = (uint8_t)opt; /* isolate bits for -1..-8 */
|
||||
opt |= 0x100; /* if nothing else, assume -9 */
|
||||
level = 1;
|
||||
while (!(opt & 1)) {
|
||||
level++;
|
||||
opt >>= 1;
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
option_mask32 &= 0x7; /* ignore all except -cfv */
|
||||
return bbunpack(argv, compressStream, append_ext, "bz2");
|
||||
}
|
491
archival/cpio.c
491
archival/cpio.c
@ -1,491 +0,0 @@
|
||||
/* 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
|
||||
*/
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
//config:config CPIO
|
||||
//config: bool "cpio"
|
||||
//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, it cannot create or modify them.
|
||||
//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 for 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 for passthrough mode"
|
||||
//config: default y
|
||||
//config: depends on FEATURE_CPIO_O
|
||||
//config: help
|
||||
//config: Passthrough mode. Rarely used.
|
||||
|
||||
//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]" 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 or list files from a cpio archive"
|
||||
//usage: IF_FEATURE_CPIO_O(", or"
|
||||
//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)")
|
||||
//usage: " using file list on stdin"
|
||||
//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: "\n -d Make leading directories"
|
||||
//usage: "\n -m Preserve mtime"
|
||||
//usage: "\n -v Verbose"
|
||||
//usage: "\n -u Overwrite"
|
||||
//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
|
||||
//usage: IF_FEATURE_CPIO_O(
|
||||
//usage: "\n -H newc Archive format"
|
||||
//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][:.][GROUP] 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
|
||||
*/
|
||||
|
||||
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),
|
||||
OPTBIT_FILE = 8,
|
||||
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 ,)
|
||||
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,
|
||||
};
|
||||
|
||||
#define OPTION_STR "it0uvdmLF:"
|
||||
|
||||
#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)
|
||||
{
|
||||
static const char trailer[] ALIGN1 = "TRAILER!!!";
|
||||
struct name_s {
|
||||
struct name_s *next;
|
||||
char name[1];
|
||||
};
|
||||
struct inodes_s {
|
||||
struct inodes_s *next;
|
||||
struct name_s *names;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
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 (!(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;
|
||||
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;
|
||||
}
|
||||
|
||||
} else { /* line == NULL: EOF */
|
||||
next_link:
|
||||
if (links) {
|
||||
/* Output hardlink's data */
|
||||
st = links->st;
|
||||
name = links->names->name;
|
||||
links->names = links->names->next;
|
||||
/* 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 = 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 */
|
||||
}
|
||||
}
|
||||
|
||||
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 != 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;
|
||||
IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
|
||||
unsigned opt;
|
||||
|
||||
#if ENABLE_LONG_OPTS
|
||||
applet_long_options =
|
||||
"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
|
||||
"verbose\0" No_argument "v"
|
||||
"quiet\0" No_argument "\xff"
|
||||
"to-stdout\0" No_argument "\xfe"
|
||||
;
|
||||
#endif
|
||||
|
||||
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 = getopt32(argv, OPTION_STR, &cpio_filename);
|
||||
argv += optind;
|
||||
if (opt & OPT_FILE) { /* -F */
|
||||
xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
|
||||
}
|
||||
#else
|
||||
opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
|
||||
argv += optind;
|
||||
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)
|
||||
mkdir(argv[0], 0777);
|
||||
/* 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.
|
||||
*/
|
||||
#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 */
|
||||
USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */
|
||||
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;
|
||||
|
||||
if (archive_handle->cpio__blocks != (off_t)-1
|
||||
&& !(opt & OPT_QUIET)
|
||||
) {
|
||||
fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1937
archival/dpkg.c
1937
archival/dpkg.c
File diff suppressed because it is too large
Load Diff
@ -1,146 +0,0 @@
|
||||
/* 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"
|
||||
//config: default n
|
||||
//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.
|
||||
//config:
|
||||
//config:config FEATURE_DPKG_DEB_EXTRACT_ONLY
|
||||
//config: bool "Extract only (-x)"
|
||||
//config: default n
|
||||
//config: depends on DPKG_DEB
|
||||
//config: help
|
||||
//config: This reduces dpkg-deb to the equivalent of
|
||||
//config: "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
|
||||
//config: of the extra dpkg-deb, ar or tar options are needed, they are linked
|
||||
//config: to internally.
|
||||
|
||||
//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 [argument]"
|
||||
//usage:#define dpkg_deb_full_usage "\n\n"
|
||||
//usage: "Perform actions on Debian packages (.debs)\n"
|
||||
//usage: "\n -c List contents of filesystem tree"
|
||||
//usage: "\n -e Extract control files to [argument] directory"
|
||||
//usage: "\n -f Display control field name starting with [argument]"
|
||||
//usage: "\n -x Extract packages filesystem tree to directory"
|
||||
//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 8
|
||||
#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16
|
||||
|
||||
int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int dpkg_deb_main(int argc, char **argv)
|
||||
{
|
||||
archive_handle_t *ar_archive;
|
||||
archive_handle_t *tar_archive;
|
||||
llist_t *control_tar_llist = NULL;
|
||||
unsigned opt;
|
||||
const char *extract_dir;
|
||||
int need_args;
|
||||
|
||||
/* 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;
|
||||
|
||||
#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
|
||||
|
||||
opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
|
||||
opt = getopt32(argv, "cefXx");
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (opt & DPKG_DEB_OPT_CONTENTS) {
|
||||
tar_archive->action_header = header_verbose_list;
|
||||
}
|
||||
extract_dir = NULL;
|
||||
need_args = 1;
|
||||
if (opt & DPKG_DEB_OPT_CONTROL) {
|
||||
ar_archive->accept = control_tar_llist;
|
||||
tar_archive->action_data = data_extract_all;
|
||||
if (1 == argc) {
|
||||
extract_dir = "./DEBIAN";
|
||||
} else {
|
||||
need_args++;
|
||||
}
|
||||
}
|
||||
if (opt & DPKG_DEB_OPT_FIELD) {
|
||||
/* Print the entire control file
|
||||
* it should accept a second argument which specifies a
|
||||
* specific field 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 (opt & DPKG_DEB_OPT_EXTRACT) {
|
||||
tar_archive->action_header = header_list;
|
||||
}
|
||||
if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) {
|
||||
tar_archive->action_data = data_extract_all;
|
||||
need_args = 2;
|
||||
}
|
||||
|
||||
if (need_args != argc) {
|
||||
bb_show_usage();
|
||||
}
|
||||
|
||||
tar_archive->src_fd = ar_archive->src_fd = xopen(argv[0], O_RDONLY);
|
||||
|
||||
/* Work out where to extract the files */
|
||||
/* 2nd argument is a dir name */
|
||||
if (argv[1]) {
|
||||
extract_dir = argv[1];
|
||||
}
|
||||
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;
|
||||
}
|
2155
archival/gzip.c
2155
archival/gzip.c
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@
|
||||
# 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_FILES:= \
|
||||
\
|
||||
data_skip.o \
|
||||
data_extract_all.o \
|
||||
data_extract_to_stdout.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 \
|
||||
get_header_ar.o \
|
||||
get_header_tar.o \
|
||||
get_header_tar_gz.o \
|
||||
get_header_tar_bz2.o \
|
||||
get_header_tar_lzma.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
|
||||
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_LZOP_COMPR_HIGH) += lzo1x_9x.o
|
||||
lib-$(CONFIG_BUNZIP2) += open_transformer.o decompress_bunzip2.o
|
||||
lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o
|
||||
lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o
|
||||
lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o
|
||||
lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o
|
||||
lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.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
|
||||
|
||||
ifneq ($(lib-y),)
|
||||
lib-y += $(COMMON_FILES)
|
||||
endif
|
@ -1,44 +0,0 @@
|
||||
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
|
@ -1,90 +0,0 @@
|
||||
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)
|
File diff suppressed because it is too large
Load Diff
@ -1,429 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
s->numZ = 0;
|
||||
s->state_out_pos = 0;
|
||||
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)
|
||||
{
|
||||
int32_t 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;
|
||||
s->ftab = xmalloc(65537 * sizeof(uint32_t));
|
||||
|
||||
s->crc32table = crc32_filltable(NULL, 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->numZ) break;
|
||||
|
||||
/*progress_out = True;*/
|
||||
*(s->strm->next_out) = s->zbits[s->state_out_pos];
|
||||
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->numZ) 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->numZ)
|
||||
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->numZ)
|
||||
//# return BZ_FINISH_OK;
|
||||
if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
|
||||
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);
|
||||
free(s->crc32table);
|
||||
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 ---*/
|
||||
/*-------------------------------------------------------------*/
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 ---*/
|
||||
/*-------------------------------------------------------------*/
|
@ -1,219 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
int32_t mode;
|
||||
int32_t state;
|
||||
|
||||
/* 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 */
|
||||
int32_t origPtr;
|
||||
uint32_t *arr1;
|
||||
uint32_t *arr2;
|
||||
uint32_t *ftab;
|
||||
|
||||
/* aliases for arr1 and arr2 */
|
||||
uint32_t *ptr;
|
||||
uint8_t *block;
|
||||
uint16_t *mtfv;
|
||||
uint8_t *zbits;
|
||||
|
||||
/* guess what */
|
||||
uint32_t *crc32table;
|
||||
|
||||
/* 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;
|
||||
int32_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;
|
||||
int32_t blockSize100k;
|
||||
|
||||
/* 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];
|
||||
|
||||
/* 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 CONFIG_BZIP2_FAST >= 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__runningOrder[256];
|
||||
int32_t mainSort__copyStart[256];
|
||||
int32_t mainSort__copyEnd[256];
|
||||
} EState;
|
||||
|
||||
|
||||
/*-- compression. --*/
|
||||
|
||||
static void
|
||||
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 ---*/
|
||||
/*-------------------------------------------------------------*/
|
@ -1,678 +0,0 @@
|
||||
/*
|
||||
* 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" */
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- 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->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
|
||||
s->numZ++;
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
/* Helps only on level 5, on other levels hurts. ? */
|
||||
#if CONFIG_BZIP2_FAST >= 5
|
||||
ALWAYS_INLINE
|
||||
#endif
|
||||
void bsW(EState* s, int32_t n, uint32_t v)
|
||||
{
|
||||
while (s->bsLive >= 8) {
|
||||
s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24);
|
||||
s->numZ++;
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
s->bsBuff |= (v << (32 - s->bsLive - n));
|
||||
s->bsLive += n;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutU32(EState* s, unsigned u)
|
||||
{
|
||||
bsW(s, 8, (u >> 24) & 0xff);
|
||||
bsW(s, 8, (u >> 16) & 0xff);
|
||||
bsW(s, 8, (u >> 8) & 0xff);
|
||||
bsW(s, 8, u & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutU16(EState* s, unsigned u)
|
||||
{
|
||||
bsW(s, 8, (u >> 8) & 0xff);
|
||||
bsW(s, 8, u & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- The back end proper ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_e(EState* s)
|
||||
{
|
||||
int i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (s->inUse[i]) {
|
||||
s->unseqToSeq[i] = s->nInUse;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static NOINLINE
|
||||
void generateMTFValues(EState* s)
|
||||
{
|
||||
uint8_t yy[256];
|
||||
int32_t i, j;
|
||||
int32_t zPend;
|
||||
int32_t wr;
|
||||
int32_t EOB;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
uint8_t* block = s->block;
|
||||
uint16_t* mtfv = s->mtfv;
|
||||
|
||||
makeMaps_e(s);
|
||||
EOB = s->nInUse+1;
|
||||
|
||||
for (i = 0; i <= EOB; i++)
|
||||
s->mtfFreq[i] = 0;
|
||||
|
||||
wr = 0;
|
||||
zPend = 0;
|
||||
for (i = 0; i < s->nInUse; i++)
|
||||
yy[i] = (uint8_t) i;
|
||||
|
||||
for (i = 0; i < s->nblock; i++) {
|
||||
uint8_t ll_i;
|
||||
AssertD(wr <= i, "generateMTFValues(1)");
|
||||
j = ptr[i] - 1;
|
||||
if (j < 0)
|
||||
j += s->nblock;
|
||||
ll_i = s->unseqToSeq[block[j]];
|
||||
AssertD(ll_i < s->nInUse, "generateMTFValues(2a)");
|
||||
|
||||
if (yy[0] == ll_i) {
|
||||
zPend++;
|
||||
} else {
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (1) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (uint32_t)(zPend - 2) / 2;
|
||||
/* bbox: unsigned div is easier */
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
{
|
||||
register uint8_t rtmp;
|
||||
register uint8_t* ryy_j;
|
||||
register uint8_t rll_i;
|
||||
rtmp = yy[1];
|
||||
yy[1] = yy[0];
|
||||
ryy_j = &(yy[1]);
|
||||
rll_i = ll_i;
|
||||
while (rll_i != rtmp) {
|
||||
register uint8_t rtmp2;
|
||||
ryy_j++;
|
||||
rtmp2 = rtmp;
|
||||
rtmp = *ryy_j;
|
||||
*ryy_j = rtmp2;
|
||||
};
|
||||
yy[0] = rtmp;
|
||||
j = ryy_j - &(yy[0]);
|
||||
mtfv[wr] = j+1;
|
||||
wr++;
|
||||
s->mtfFreq[j+1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (1) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB;
|
||||
wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA;
|
||||
wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2)
|
||||
break;
|
||||
zPend = (uint32_t)(zPend - 2) / 2;
|
||||
/* bbox: unsigned div is easier */
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
|
||||
mtfv[wr] = EOB;
|
||||
wr++;
|
||||
s->mtfFreq[EOB]++;
|
||||
|
||||
s->nMTF = wr;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define BZ_LESSER_ICOST 0
|
||||
#define BZ_GREATER_ICOST 15
|
||||
|
||||
static NOINLINE
|
||||
void sendMTFValues(EState* s)
|
||||
{
|
||||
int32_t v, t, i, j, gs, ge, bt, bc, iter;
|
||||
int32_t nSelectors, alphaSize, minLen, maxLen, 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
|
||||
|
||||
uint16_t cost[BZ_N_GROUPS];
|
||||
int32_t fave[BZ_N_GROUPS];
|
||||
|
||||
uint16_t* mtfv = s->mtfv;
|
||||
|
||||
alphaSize = s->nInUse + 2;
|
||||
for (t = 0; t < BZ_N_GROUPS; t++)
|
||||
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);
|
||||
if (s->nMTF < 200) nGroups = 2; else
|
||||
if (s->nMTF < 600) nGroups = 3; else
|
||||
if (s->nMTF < 1200) nGroups = 4; else
|
||||
if (s->nMTF < 2400) nGroups = 5; else
|
||||
nGroups = 6;
|
||||
|
||||
/*--- Generate an initial set of coding tables ---*/
|
||||
{
|
||||
int32_t nPart, remF, tFreq, aFreq;
|
||||
|
||||
nPart = nGroups;
|
||||
remF = s->nMTF;
|
||||
gs = 0;
|
||||
while (nPart > 0) {
|
||||
tFreq = remF / nPart;
|
||||
ge = gs - 1;
|
||||
aFreq = 0;
|
||||
while (aFreq < tFreq && ge < alphaSize-1) {
|
||||
ge++;
|
||||
aFreq += s->mtfFreq[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++)
|
||||
fave[t] = 0;
|
||||
|
||||
for (t = 0; t < nGroups; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->rfreq[t][v] = 0;
|
||||
|
||||
#if CONFIG_BZIP2_FAST >= 5
|
||||
/*
|
||||
* Set up an auxiliary length table which is used to fast-track
|
||||
* the common case (nGroups == 6).
|
||||
*/
|
||||
if (nGroups == 6) {
|
||||
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) {
|
||||
/*--- 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 CONFIG_BZIP2_FAST >= 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++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
fave[bt]++;
|
||||
s->selector[nSelectors] = bt;
|
||||
nSelectors++;
|
||||
|
||||
/*
|
||||
* Increment the symbol frequencies for the selected table.
|
||||
*/
|
||||
/* 1% faster compress. +800 bytes */
|
||||
#if CONFIG_BZIP2_FAST >= 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++) {
|
||||
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++) {
|
||||
minLen = 32;
|
||||
maxLen = 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);
|
||||
}
|
||||
}
|
||||
|
||||
bsW(s, 16, inUse16);
|
||||
|
||||
inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (inUse16 < 0) {
|
||||
unsigned v16 = 0;
|
||||
for (j = 0; j < 16; j++)
|
||||
v16 = v16*2 + s->inUse[i * 16 + j];
|
||||
bsW(s, 16, v16);
|
||||
}
|
||||
inUse16 <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Now the selectors. ---*/
|
||||
bsW(s, 3, nGroups);
|
||||
bsW(s, 15, nSelectors);
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
for (j = 0; j < s->selectorMtf[i]; j++)
|
||||
bsW(s, 1, 1);
|
||||
bsW(s, 1, 0);
|
||||
}
|
||||
|
||||
/*--- Now the coding tables. ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
int32_t 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 */ };
|
||||
bsW(s, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*--- And finally, the block data proper ---*/
|
||||
selCtr = 0;
|
||||
gs = 0;
|
||||
while (1) {
|
||||
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)
|
||||
{
|
||||
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->numZ = 0;
|
||||
|
||||
BZ2_blockSort(s);
|
||||
}
|
||||
|
||||
s->zbits = &((uint8_t*)s->arr2)[s->nblock];
|
||||
|
||||
/*-- 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.
|
||||
*/
|
||||
bsW(s, 1, 0);
|
||||
|
||||
bsW(s, 24, s->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 ---*/
|
||||
/*-------------------------------------------------------------*/
|
@ -1,229 +0,0 @@
|
||||
/*
|
||||
* 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 CONFIG_BZIP2_FAST >= 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 ---*/
|
||||
/*-------------------------------------------------------------*/
|
@ -1,15 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
#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
|
||||
|
||||
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
|
||||
char *slash = strrchr(file_header->name, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
bb_make_directory(file_header->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)) {
|
||||
/* Is it hardlink?
|
||||
* We encode hard links as regular files of size 0 with a symlink */
|
||||
if (S_ISREG(file_header->mode)
|
||||
&& file_header->link_target
|
||||
&& file_header->size == 0
|
||||
) {
|
||||
/* Ugly special case:
|
||||
* tar cf t.tar hardlink1 hardlink2 hardlink1
|
||||
* results in this tarball structure:
|
||||
* hardlink1
|
||||
* hardlink2 -> hardlink1
|
||||
* hardlink1 -> hardlink1 <== !!!
|
||||
*/
|
||||
if (strcmp(file_header->link_target, file_header->name) == 0)
|
||||
goto ret;
|
||||
}
|
||||
/* Proceed with deleting */
|
||||
if (unlink(file_header->name) == -1
|
||||
&& errno != ENOENT
|
||||
) {
|
||||
bb_perror_msg_and_die("can't remove old file %s",
|
||||
file_header->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(file_header->name, &existing_sb) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
bb_perror_msg_and_die("can't stat old file");
|
||||
}
|
||||
}
|
||||
else if (existing_sb.st_mtime >= file_header->mtime) {
|
||||
if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
|
||||
&& !S_ISDIR(file_header->mode)
|
||||
) {
|
||||
bb_error_msg("%s not created: newer or "
|
||||
"same age file exists", file_header->name);
|
||||
}
|
||||
data_skip(archive_handle);
|
||||
goto ret;
|
||||
}
|
||||
else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
|
||||
bb_perror_msg_and_die("can't remove old file %s",
|
||||
file_header->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle hard links separately
|
||||
* We encode hard links as regular files of size 0 with a symlink */
|
||||
if (S_ISREG(file_header->mode)
|
||||
&& file_header->link_target
|
||||
&& file_header->size == 0
|
||||
) {
|
||||
/* hard link */
|
||||
res = link(file_header->link_target, file_header->name);
|
||||
if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
|
||||
bb_perror_msg("can't create %slink "
|
||||
"from %s to %s", "hard",
|
||||
file_header->name,
|
||||
file_header->link_target);
|
||||
}
|
||||
/* 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_name;
|
||||
int flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||
if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
dst_name = file_header->name;
|
||||
#ifdef ARCHIVE_REPLACE_VIA_RENAME
|
||||
if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME)
|
||||
/* rpm-style temp file name */
|
||||
dst_name = xasprintf("%s;%x", dst_name, (int)getpid());
|
||||
#endif
|
||||
dst_fd = xopen3(dst_name,
|
||||
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_name, file_header->name);
|
||||
free(dst_name);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case S_IFDIR:
|
||||
res = mkdir(file_header->name, file_header->mode);
|
||||
if ((res == -1)
|
||||
&& (errno != EISDIR) /* btw, Linux doesn't return this */
|
||||
&& (errno != EEXIST)
|
||||
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
|
||||
) {
|
||||
bb_perror_msg("can't make dir %s", file_header->name);
|
||||
}
|
||||
break;
|
||||
case S_IFLNK:
|
||||
/* Symlink */
|
||||
//TODO: what if file_header->link_target == NULL (say, corrupted tarball?)
|
||||
res = symlink(file_header->link_target, file_header->name);
|
||||
if ((res == -1)
|
||||
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
|
||||
) {
|
||||
bb_perror_msg("can't create %slink "
|
||||
"from %s to %s", "sym",
|
||||
file_header->name,
|
||||
file_header->link_target);
|
||||
}
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
case S_IFIFO:
|
||||
res = mknod(file_header->name, file_header->mode, file_header->device);
|
||||
if ((res == -1)
|
||||
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
|
||||
) {
|
||||
bb_perror_msg("can't create node %s", file_header->name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bb_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(file_header->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(file_header->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(file_header->name, t);
|
||||
}
|
||||
}
|
||||
|
||||
ret: ;
|
||||
#if ENABLE_FEATURE_TAR_SELINUX
|
||||
if (sctx) {
|
||||
/* reset the context after creating an entry */
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/* 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[] = {
|
||||
// "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_error_msg_and_die(bb_msg_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]);
|
||||
|
||||
if (safe_waitpid(pid, &status, 0) == -1)
|
||||
bb_perror_msg_and_die("waitpid");
|
||||
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 on 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
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/* 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);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/* 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);
|
||||
}
|
@ -1,830 +0,0 @@
|
||||
/* 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; -- done in .h file */
|
||||
|
||||
|
||||
/* 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 & ((1 << 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;
|
||||
}
|
||||
|
||||
/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */
|
||||
static int get_next_block(bunzip_data *bd)
|
||||
{
|
||||
struct group_data *hufGroup;
|
||||
int dbufCount, dbufSize, groupCount, *base, *limit, selector,
|
||||
i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256];
|
||||
int runCnt = runCnt; /* for compiler */
|
||||
uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
|
||||
uint32_t *dbuf;
|
||||
unsigned origPtr;
|
||||
|
||||
dbuf = bd->dbuf;
|
||||
dbufSize = bd->dbufSize;
|
||||
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 ((int)origPtr > 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)) {
|
||||
if (n >= groupCount) return RETVAL_DATA_ERROR;
|
||||
n++;
|
||||
}
|
||||
/* Decode MTF to get the next selector */
|
||||
tmp_byte = mtfSymbol[n];
|
||||
while (--n >= 0)
|
||||
mtfSymbol[n + 1] = mtfSymbol[n];
|
||||
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];
|
||||
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[]. Concurently, 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 (;;) {
|
||||
int nextSym;
|
||||
|
||||
/* Fetch next Huffman coding group from list. */
|
||||
symCount = GROUP_SIZE - 1;
|
||||
if (selector >= nSelectors) return RETVAL_DATA_ERROR;
|
||||
hufGroup = bd->groups + selectors[selector++];
|
||||
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 */
|
||||
if (runPos < 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 > dbufSize) {
|
||||
dbg("dbufCount:%d+runCnt:%d %d > dbufSize:%d RETVAL_DATA_ERROR",
|
||||
dbufCount, runCnt, dbufCount + runCnt, dbufSize);
|
||||
return RETVAL_DATA_ERROR;
|
||||
}
|
||||
tmp_byte = symToByte[mtfSymbol[0]];
|
||||
byteCount[tmp_byte] += runCnt;
|
||||
while (--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 >= 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)
|
||||
*/
|
||||
int FAST_FUNC 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! */
|
||||
int FAST_FUNC start_bunzip(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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Setup for I/O error handling via longjmp */
|
||||
i = setjmp(bd->jmpbuf);
|
||||
if (i) return i;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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_aux_data_t *aux, int src_fd, int dst_fd)
|
||||
{
|
||||
IF_DESKTOP(long long total_written = 0;)
|
||||
bunzip_data *bd;
|
||||
char *outbuf;
|
||||
int i;
|
||||
unsigned len;
|
||||
|
||||
if (check_signature16(aux, src_fd, BZIP2_MAGIC))
|
||||
return -1;
|
||||
|
||||
outbuf = xmalloc(IOBUF_SIZE);
|
||||
len = 0;
|
||||
while (1) { /* "Process one BZ... stream" loop */
|
||||
|
||||
i = start_bunzip(&bd, 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 != full_write(dst_fd, outbuf, i)) {
|
||||
bb_error_msg("short write");
|
||||
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_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(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;
|
||||
}
|
||||
|
||||
#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
|
File diff suppressed because it is too large
Load Diff
@ -1,315 +0,0 @@
|
||||
/* 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_aux_data_t *aux, int src_fd, int dst_fd)
|
||||
{
|
||||
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(aux, src_fd, 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(src_fd, inbuf, 1) != 1) {
|
||||
bb_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(src_fd, inbuf + insize, IBUFSIZ);
|
||||
if (rsize < 0)
|
||||
bb_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_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_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_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) {
|
||||
xwrite(dst_fd, 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) {
|
||||
xwrite(dst_fd, outbuf, outpos);
|
||||
IF_DESKTOP(total_written += outpos;)
|
||||
}
|
||||
|
||||
retval = IF_DESKTOP(total_written) + 0;
|
||||
err:
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
free(htab);
|
||||
free(codetab);
|
||||
return retval;
|
||||
}
|
@ -1,467 +0,0 @@
|
||||
/* 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 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_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_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd)
|
||||
{
|
||||
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;
|
||||
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(src_fd, &header, sizeof(header)) != sizeof(header)
|
||||
|| header.pos >= (9 * 5 * 5)
|
||||
) {
|
||||
bb_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 = xmalloc(MIN(header.dst_size, header.dict_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(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 = buffer_pos - rep0;
|
||||
|
||||
while (pos >= header.dict_size)
|
||||
pos += header.dict_size;
|
||||
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 (full_write(dst_fd, 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 = buffer_pos - rep0;
|
||||
state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
|
||||
while (pos >= header.dict_size)
|
||||
pos += header.dict_size;
|
||||
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;
|
||||
prob3 = p + LZMA_ALIGN;
|
||||
}
|
||||
i2 = 1;
|
||||
mi2 = 1;
|
||||
while (num_bits2--) {
|
||||
if (rc_get_bit(rc, prob3 + mi2, &mi2))
|
||||
rep0 |= i2;
|
||||
i2 <<= 1;
|
||||
}
|
||||
}
|
||||
if (++rep0 == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
len += LZMA_MATCH_MIN_LEN;
|
||||
IF_NOT_FEATURE_LZMA_FAST(string:)
|
||||
do {
|
||||
uint32_t pos = buffer_pos - rep0;
|
||||
while (pos >= header.dict_size)
|
||||
pos += header.dict_size;
|
||||
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 (full_write(dst_fd, 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"?
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
IF_NOT_DESKTOP(int total_written = 0; /* success */)
|
||||
IF_DESKTOP(total_written += buffer_pos;)
|
||||
if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) {
|
||||
bad:
|
||||
total_written = -1; /* failure */
|
||||
}
|
||||
rc_free(rc);
|
||||
free(p);
|
||||
free(buffer);
|
||||
return total_written;
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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 accessors */
|
||||
#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); })
|
||||
#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); })
|
||||
#define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val))
|
||||
#define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val))
|
||||
|
||||
#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_aux_data_t *aux, int src_fd, int dst_fd)
|
||||
{
|
||||
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_table = crc32_filltable(NULL, /*endian:*/ 0);
|
||||
|
||||
memset(&iobuf, 0, sizeof(iobuf));
|
||||
membuf = xmalloc(2 * BUFSIZ);
|
||||
iobuf.in = membuf;
|
||||
iobuf.out = membuf + BUFSIZ;
|
||||
iobuf.out_size = BUFSIZ;
|
||||
|
||||
if (!aux || aux->check_signature == 0) {
|
||||
/* 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(src_fd, membuf, BUFSIZ);
|
||||
if (rd < 0) {
|
||||
bb_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) {
|
||||
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) {
|
||||
xwrite(dst_fd, 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_error_msg("corrupted data");
|
||||
total = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xz_dec_end(state);
|
||||
free(membuf);
|
||||
|
||||
return total;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/* 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 (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;
|
||||
}
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/* 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_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;
|
||||
#if ENABLE_FEATURE_AR_LONG_FILENAMES
|
||||
static char *ar_long_names;
|
||||
static unsigned ar_long_name_size;
|
||||
#endif
|
||||
|
||||
/* 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_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
|
||||
*/
|
||||
ar_long_name_size = size;
|
||||
free(ar_long_names);
|
||||
ar_long_names = xmalloc(size);
|
||||
xread(archive_handle->src_fd, ar_long_names, size);
|
||||
archive_handle->offset += size;
|
||||
/* Return next header */
|
||||
return get_header_ar(archive_handle);
|
||||
}
|
||||
#else
|
||||
bb_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.
|
||||
*/
|
||||
typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode));
|
||||
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 conatains the real filename */
|
||||
long_offset = read_num(&ar.formatted.name[1], 10,
|
||||
sizeof(ar.formatted.name) - 1);
|
||||
if (long_offset >= ar_long_name_size) {
|
||||
bb_error_msg_and_die("can't resolve long filename");
|
||||
}
|
||||
typed->name = xstrdup(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) {
|
||||
while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS)
|
||||
continue;
|
||||
} 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;
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/* 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[110];
|
||||
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_error_msg_and_die("short read");
|
||||
}
|
||||
archive_handle->offset += 110;
|
||||
|
||||
if (strncmp(&cpio_header[0], "07070", 5) != 0
|
||||
|| (cpio_header[5] != '1' && cpio_header[5] != '2')
|
||||
) {
|
||||
bb_error_msg_and_die("unsupported cpio format, use newc or crc");
|
||||
}
|
||||
|
||||
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_error_msg_and_die("damaged cpio file");
|
||||
file_header->mode = mode;
|
||||
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, "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" */
|
||||
}
|
@ -1,477 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
|
||||
const char* FAST_FUNC strip_unsafe_prefix(const char *str)
|
||||
{
|
||||
const char *cp = str;
|
||||
while (1) {
|
||||
char *cp2;
|
||||
if (*cp == '/') {
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(cp, "/../"+1, 3) == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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_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))
|
||||
|
||||
/* "global" is 0 or 1 */
|
||||
static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
|
||||
{
|
||||
char *buf, *p;
|
||||
unsigned blk_sz;
|
||||
|
||||
blk_sz = (sz + 511) & (~511);
|
||||
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_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 && strncmp(value, "path=", sizeof("path=") - 1) == 0) {
|
||||
value += sizeof("path=") - 1;
|
||||
free(archive_handle->tar__longname);
|
||||
archive_handle->tar__longname = 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 (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
|
||||
value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
|
||||
free(archive_handle->tar__sctx[global]);
|
||||
archive_handle->tar__sctx[global] = xstrdup(value);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
bb_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_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) {
|
||||
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 (strncmp(tar.magic, "ustar", 5) != 0
|
||||
&& (!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_error_msg_and_die("invalid tar magic");
|
||||
archive_handle->offset = 0;
|
||||
goto again_after_align;
|
||||
#endif
|
||||
bb_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. */
|
||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||
sum_s = ' ' * sizeof(tar.chksum);
|
||||
#endif
|
||||
sum_u = ' ' * sizeof(tar.chksum);
|
||||
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
|
||||
}
|
||||
/* This field does not need special treatment (getOctal) */
|
||||
{
|
||||
char *endp; /* gcc likes temp var for &endp */
|
||||
sum = strtoul(tar.chksum, &endp, 8);
|
||||
if ((*endp != '\0' && *endp != ' ')
|
||||
|| (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
|
||||
) {
|
||||
bb_error_msg_and_die("invalid tar header checksum");
|
||||
}
|
||||
}
|
||||
/* don't use xstrtoul, tar.chksum may have leading spaces */
|
||||
sum = strtoul(tar.chksum, NULL, 8);
|
||||
if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
|
||||
bb_error_msg_and_die("invalid tar header checksum");
|
||||
}
|
||||
|
||||
/* 0 is reserved for high perf file, treat as normal file */
|
||||
if (!tar.typeflag) tar.typeflag = '0';
|
||||
parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
|
||||
|
||||
/* getOctal 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* Set bits 12-15 of the files mode */
|
||||
/* (typeflag was not trashed because chksum does not use getOctal) */
|
||||
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 (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;
|
||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||
case 'L':
|
||||
/* free: paranoia: tar with several consecutive longnames */
|
||||
free(p_longname);
|
||||
/* For paranoia reasons we allocate extra NUL char */
|
||||
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);
|
||||
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 'D': /* GNU dump dir */
|
||||
case 'M': /* Continuation of multi volume archive */
|
||||
case 'N': /* Old GNU for names > 100 characters */
|
||||
case 'S': /* Sparse file */
|
||||
case 'V': /* Volume header */
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
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));
|
||||
|
||||
/* 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" */
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
open_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;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
open_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;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
open_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;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/* 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);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/* 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)
|
||||
{
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/* 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);
|
||||
|
||||
#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(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(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');
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
return archive_handle;
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
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
|
@ -1,35 +0,0 @@
|
||||
/* 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"
|
@ -1,35 +0,0 @@
|
||||
/* 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"
|
@ -1,920 +0,0 @@
|
||||
/* 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);
|
||||
}
|
@ -1,296 +0,0 @@
|
||||
/* 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*/
|
||||
}
|
@ -1,423 +0,0 @@
|
||||
/* 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 UNUSED_PARAM)
|
||||
{
|
||||
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
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
/* 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_aux_data(transformer_aux_data_t *aux)
|
||||
{
|
||||
memset(aux, 0, sizeof(*aux));
|
||||
}
|
||||
|
||||
int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16)
|
||||
{
|
||||
if (aux && aux->check_signature) {
|
||||
uint16_t magic2;
|
||||
if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) {
|
||||
bb_error_msg("invalid magic");
|
||||
#if 0 /* possible future extension */
|
||||
if (aux->check_signature > 1)
|
||||
xfunc_die();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 open_transformer(int fd,
|
||||
int check_signature,
|
||||
IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
|
||||
)
|
||||
#else
|
||||
void FAST_FUNC open_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_aux_data_t aux;
|
||||
init_transformer_aux_data(&aux);
|
||||
aux.check_signature = check_signature;
|
||||
r = transformer(&aux, fd, fd_pipe.wr);
|
||||
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.
|
||||
*/
|
||||
int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
|
||||
{
|
||||
union {
|
||||
uint8_t b[4];
|
||||
uint16_t b16[2];
|
||||
uint32_t b32[1];
|
||||
} magic;
|
||||
int offset = -2;
|
||||
USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
|
||||
USE_FOR_NOMMU(const char *xformer_prog;)
|
||||
|
||||
/* .gz and .bz2 both have 2-byte signature, and their
|
||||
* unpack_XXX_stream wants this header skipped. */
|
||||
xread(fd, magic.b16, sizeof(magic.b16[0]));
|
||||
if (ENABLE_FEATURE_SEAMLESS_GZ
|
||||
&& magic.b16[0] == GZIP_MAGIC
|
||||
) {
|
||||
USE_FOR_MMU(xformer = unpack_gz_stream;)
|
||||
USE_FOR_NOMMU(xformer_prog = "gunzip";)
|
||||
goto found_magic;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_BZ2
|
||||
&& magic.b16[0] == BZIP2_MAGIC
|
||||
) {
|
||||
USE_FOR_MMU(xformer = unpack_bz2_stream;)
|
||||
USE_FOR_NOMMU(xformer_prog = "bunzip2";)
|
||||
goto found_magic;
|
||||
}
|
||||
if (ENABLE_FEATURE_SEAMLESS_XZ
|
||||
&& magic.b16[0] == XZ_MAGIC1
|
||||
) {
|
||||
offset = -6;
|
||||
xread(fd, magic.b32, sizeof(magic.b32[0]));
|
||||
if (magic.b32[0] == XZ_MAGIC2) {
|
||||
USE_FOR_MMU(xformer = unpack_xz_stream;)
|
||||
USE_FOR_NOMMU(xformer_prog = "unxz";)
|
||||
goto found_magic;
|
||||
}
|
||||
}
|
||||
|
||||
/* No known magic seen */
|
||||
if (fail_if_not_compressed)
|
||||
bb_error_msg_and_die("no gzip"
|
||||
IF_FEATURE_SEAMLESS_BZ2("/bzip2")
|
||||
IF_FEATURE_SEAMLESS_XZ("/xz")
|
||||
" magic");
|
||||
xlseek(fd, offset, SEEK_CUR);
|
||||
return 1;
|
||||
|
||||
found_magic:
|
||||
# if BB_MMU
|
||||
open_transformer_with_no_sig(fd, xformer);
|
||||
# else
|
||||
/* NOMMU version of open_transformer execs
|
||||
* an external unzipper that wants
|
||||
* file position at the start of the file */
|
||||
xlseek(fd, offset, SEEK_CUR);
|
||||
open_transformer_with_sig(fd, xformer, xformer_prog);
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (ENABLE_FEATURE_SEAMLESS_LZMA) {
|
||||
/* .lzma has no header/signature, can only detect it by extension */
|
||||
char *sfx = strrchr(fname, '.');
|
||||
if (sfx && strcmp(sfx+1, "lzma") == 0) {
|
||||
open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma");
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
if ((ENABLE_FEATURE_SEAMLESS_GZ)
|
||||
|| (ENABLE_FEATURE_SEAMLESS_BZ2)
|
||||
|| (ENABLE_FEATURE_SEAMLESS_XZ)
|
||||
) {
|
||||
setup_unzip_on_fd(fd, fail_if_not_compressed);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif /* SEAMLESS_COMPRESSION */
|
||||
|
||||
void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
|
||||
{
|
||||
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;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/* 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_perror_msg_and_die("seek failure");
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
/* 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);
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/* 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 (strncmp(magic, AR_MAGIC, AR_MAGIC_LEN) != 0) {
|
||||
bb_error_msg_and_die("invalid ar magic");
|
||||
}
|
||||
ar_archive->offset += AR_MAGIC_LEN;
|
||||
|
||||
while (get_header_ar(ar_archive) == EXIT_SUCCESS)
|
||||
continue;
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
|
||||
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.
|
@ -1,280 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,580 +0,0 @@
|
||||
/*
|
||||
* 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
|
File diff suppressed because it is too large
Load Diff
@ -1,822 +0,0 @@
|
||||
/*
|
||||
* .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 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);
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Definitions for handling the .xz file format
|
||||
*
|
||||
* 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_STREAM_H
|
||||
#define XZ_STREAM_H
|
||||
|
||||
#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
|
||||
# include <linux/crc32.h>
|
||||
# undef crc32
|
||||
# define xz_crc32(buf, size, crc) \
|
||||
(~crc32_le(~(uint32_t)(crc), buf, size))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See the .xz file format specification at
|
||||
* http://tukaani.org/xz/xz-file-format.txt
|
||||
* to understand the container format.
|
||||
*/
|
||||
|
||||
#define STREAM_HEADER_SIZE 12
|
||||
|
||||
#define HEADER_MAGIC "\3757zXZ"
|
||||
#define HEADER_MAGIC_SIZE 6
|
||||
|
||||
#define FOOTER_MAGIC "YZ"
|
||||
#define FOOTER_MAGIC_SIZE 2
|
||||
|
||||
/*
|
||||
* Variable-length integer can hold a 63-bit unsigned integer or a special
|
||||
* value indicating that the value is unknown.
|
||||
*
|
||||
* Experimental: vli_type can be defined to uint32_t to save a few bytes
|
||||
* in code size (no effect on speed). Doing so limits the uncompressed and
|
||||
* compressed size of the file to less than 256 MiB and may also weaken
|
||||
* error detection slightly.
|
||||
*/
|
||||
typedef uint64_t vli_type;
|
||||
|
||||
#define VLI_MAX ((vli_type)-1 / 2)
|
||||
#define VLI_UNKNOWN ((vli_type)-1)
|
||||
|
||||
/* Maximum encoded size of a VLI */
|
||||
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
|
||||
|
||||
/* Integrity Check types */
|
||||
enum xz_check {
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
};
|
||||
|
||||
/* Maximum possible Check ID */
|
||||
#define XZ_CHECK_MAX 15
|
||||
|
||||
#endif
|
1123
archival/lzop.c
1123
archival/lzop.c
File diff suppressed because it is too large
Load Diff
404
archival/rpm.c
404
archival/rpm.c
@ -1,404 +0,0 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Mini rpm applet for busybox
|
||||
*
|
||||
* Copyright (C) 2001,2002 by Laurence Anderson
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
//config:config RPM
|
||||
//config: bool "rpm"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Mini RPM applet - queries and extracts RPM packages.
|
||||
|
||||
//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
|
||||
//kbuild:lib-$(CONFIG_RPM) += rpm.o
|
||||
|
||||
//usage:#define rpm_trivial_usage
|
||||
//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
|
||||
//usage:#define rpm_full_usage "\n\n"
|
||||
//usage: "Manipulate RPM packages\n"
|
||||
//usage: "\nCommands:"
|
||||
//usage: "\n -i Install package"
|
||||
//usage: "\n -qp Query package"
|
||||
//usage: "\n -qpi Show information"
|
||||
//usage: "\n -qpl List contents"
|
||||
//usage: "\n -qpd List documents"
|
||||
//usage: "\n -qpc List config files"
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
#include "rpm.h"
|
||||
|
||||
#define RPM_CHAR_TYPE 1
|
||||
#define RPM_INT8_TYPE 2
|
||||
#define RPM_INT16_TYPE 3
|
||||
#define RPM_INT32_TYPE 4
|
||||
/* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */
|
||||
#define RPM_STRING_TYPE 6
|
||||
#define RPM_BIN_TYPE 7
|
||||
#define RPM_STRING_ARRAY_TYPE 8
|
||||
#define RPM_I18NSTRING_TYPE 9
|
||||
|
||||
#define TAG_NAME 1000
|
||||
#define TAG_VERSION 1001
|
||||
#define TAG_RELEASE 1002
|
||||
#define TAG_SUMMARY 1004
|
||||
#define TAG_DESCRIPTION 1005
|
||||
#define TAG_BUILDTIME 1006
|
||||
#define TAG_BUILDHOST 1007
|
||||
#define TAG_SIZE 1009
|
||||
#define TAG_VENDOR 1011
|
||||
#define TAG_LICENSE 1014
|
||||
#define TAG_PACKAGER 1015
|
||||
#define TAG_GROUP 1016
|
||||
#define TAG_URL 1020
|
||||
#define TAG_PREIN 1023
|
||||
#define TAG_POSTIN 1024
|
||||
#define TAG_FILEFLAGS 1037
|
||||
#define TAG_FILEUSERNAME 1039
|
||||
#define TAG_FILEGROUPNAME 1040
|
||||
#define TAG_SOURCERPM 1044
|
||||
#define TAG_PREINPROG 1085
|
||||
#define TAG_POSTINPROG 1086
|
||||
#define TAG_PREFIXS 1098
|
||||
#define TAG_DIRINDEXES 1116
|
||||
#define TAG_BASENAMES 1117
|
||||
#define TAG_DIRNAMES 1118
|
||||
|
||||
#define RPMFILE_CONFIG (1 << 0)
|
||||
#define RPMFILE_DOC (1 << 1)
|
||||
|
||||
enum rpm_functions_e {
|
||||
rpm_query = 1,
|
||||
rpm_install = 2,
|
||||
rpm_query_info = 4,
|
||||
rpm_query_package = 8,
|
||||
rpm_query_list = 16,
|
||||
rpm_query_list_doc = 32,
|
||||
rpm_query_list_config = 64
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t tag; /* 4 byte tag */
|
||||
uint32_t type; /* 4 byte type */
|
||||
uint32_t offset; /* 4 byte offset */
|
||||
uint32_t count; /* 4 byte count */
|
||||
} rpm_index;
|
||||
|
||||
struct globals {
|
||||
void *map;
|
||||
rpm_index **mytags;
|
||||
int tagcount;
|
||||
} FIX_ALIASING;
|
||||
#define G (*(struct globals*)&bb_common_bufsiz1)
|
||||
#define INIT_G() do { } while (0)
|
||||
|
||||
static void extract_cpio(int fd, const char *source_rpm)
|
||||
{
|
||||
archive_handle_t *archive_handle;
|
||||
|
||||
if (source_rpm != NULL) {
|
||||
/* Binary rpm (it was built from some SRPM), install to root */
|
||||
xchdir("/");
|
||||
} /* else: SRPM, install to current dir */
|
||||
|
||||
/* Initialize */
|
||||
archive_handle = init_handle();
|
||||
archive_handle->seek = seek_by_read;
|
||||
archive_handle->action_data = data_extract_all;
|
||||
#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
|
||||
archive_handle->action_header = header_list;
|
||||
archive_handle->action_data = data_skip;
|
||||
#endif
|
||||
archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
|
||||
/* compat: overwrite existing files.
|
||||
* try "rpm -i foo.src.rpm" few times in a row -
|
||||
* standard rpm will not complain.
|
||||
*/
|
||||
| ARCHIVE_REPLACE_VIA_RENAME;
|
||||
archive_handle->src_fd = fd;
|
||||
/*archive_handle->offset = 0; - init_handle() did it */
|
||||
|
||||
setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1);
|
||||
while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
|
||||
static rpm_index **rpm_gettags(int fd, int *num_tags)
|
||||
{
|
||||
/* We should never need more than 200 (shrink via realloc later) */
|
||||
rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
|
||||
int pass, tagindex = 0;
|
||||
|
||||
xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */
|
||||
|
||||
/* 1st pass is the signature headers, 2nd is the main stuff */
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
struct rpm_header header;
|
||||
rpm_index *tmpindex;
|
||||
int storepos;
|
||||
|
||||
xread(fd, &header, sizeof(header));
|
||||
if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
|
||||
return NULL; /* Invalid magic, or not version 1 */
|
||||
header.size = ntohl(header.size);
|
||||
header.entries = ntohl(header.entries);
|
||||
storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
|
||||
|
||||
while (header.entries--) {
|
||||
tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
|
||||
xread(fd, tmpindex, sizeof(*tmpindex));
|
||||
tmpindex->tag = ntohl(tmpindex->tag);
|
||||
tmpindex->type = ntohl(tmpindex->type);
|
||||
tmpindex->count = ntohl(tmpindex->count);
|
||||
tmpindex->offset = storepos + ntohl(tmpindex->offset);
|
||||
if (pass == 0)
|
||||
tmpindex->tag -= 743;
|
||||
}
|
||||
storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
|
||||
/* Skip padding to 8 byte boundary after reading signature headers */
|
||||
if (pass == 0)
|
||||
xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
|
||||
}
|
||||
/* realloc tags to save space */
|
||||
tags = xrealloc(tags, tagindex * sizeof(tags[0]));
|
||||
*num_tags = tagindex;
|
||||
/* All done, leave the file at the start of the gzipped cpio archive */
|
||||
return tags;
|
||||
}
|
||||
|
||||
static int bsearch_rpmtag(const void *key, const void *item)
|
||||
{
|
||||
int *tag = (int *)key;
|
||||
rpm_index **tmp = (rpm_index **) item;
|
||||
return (*tag - tmp[0]->tag);
|
||||
}
|
||||
|
||||
static int rpm_getcount(int tag)
|
||||
{
|
||||
rpm_index **found;
|
||||
found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
|
||||
if (!found)
|
||||
return 0;
|
||||
return found[0]->count;
|
||||
}
|
||||
|
||||
static char *rpm_getstr(int tag, int itemindex)
|
||||
{
|
||||
rpm_index **found;
|
||||
found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
|
||||
if (!found || itemindex >= found[0]->count)
|
||||
return NULL;
|
||||
if (found[0]->type == RPM_STRING_TYPE
|
||||
|| found[0]->type == RPM_I18NSTRING_TYPE
|
||||
|| found[0]->type == RPM_STRING_ARRAY_TYPE
|
||||
) {
|
||||
int n;
|
||||
char *tmpstr = (char *) G.map + found[0]->offset;
|
||||
for (n = 0; n < itemindex; n++)
|
||||
tmpstr = tmpstr + strlen(tmpstr) + 1;
|
||||
return tmpstr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rpm_getint(int tag, int itemindex)
|
||||
{
|
||||
rpm_index **found;
|
||||
char *tmpint;
|
||||
|
||||
/* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
|
||||
* it's ok to ignore it because tag won't be used as a pointer */
|
||||
found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
|
||||
if (!found || itemindex >= found[0]->count)
|
||||
return -1;
|
||||
|
||||
tmpint = (char *) G.map + found[0]->offset;
|
||||
if (found[0]->type == RPM_INT32_TYPE) {
|
||||
tmpint += itemindex*4;
|
||||
return ntohl(*(int32_t*)tmpint);
|
||||
}
|
||||
if (found[0]->type == RPM_INT16_TYPE) {
|
||||
tmpint += itemindex*2;
|
||||
return ntohs(*(int16_t*)tmpint);
|
||||
}
|
||||
if (found[0]->type == RPM_INT8_TYPE) {
|
||||
tmpint += itemindex;
|
||||
return *(int8_t*)tmpint;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fileaction_dobackup(char *filename, int fileref)
|
||||
{
|
||||
struct stat oldfile;
|
||||
int stat_res;
|
||||
char *newname;
|
||||
if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) {
|
||||
/* Only need to backup config files */
|
||||
stat_res = lstat(filename, &oldfile);
|
||||
if (stat_res == 0 && S_ISREG(oldfile.st_mode)) {
|
||||
/* File already exists - really should check MD5's etc to see if different */
|
||||
newname = xasprintf("%s.rpmorig", filename);
|
||||
copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
|
||||
remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
|
||||
free(newname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fileaction_setowngrp(char *filename, int fileref)
|
||||
{
|
||||
/* real rpm warns: "user foo does not exist - using <you>" */
|
||||
struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
|
||||
int uid = pw ? pw->pw_uid : getuid(); /* or euid? */
|
||||
struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
|
||||
int gid = gr ? gr->gr_gid : getgid();
|
||||
chown(filename, uid, gid);
|
||||
}
|
||||
|
||||
static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
|
||||
{
|
||||
int count = 0;
|
||||
while (rpm_getstr(filetag, count)) {
|
||||
char* filename = xasprintf("%s%s",
|
||||
rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)),
|
||||
rpm_getstr(TAG_BASENAMES, count));
|
||||
fileaction(filename, count++);
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int rpm_main(int argc, char **argv)
|
||||
{
|
||||
int opt, func = 0;
|
||||
const unsigned pagesize = getpagesize();
|
||||
|
||||
while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i': /* First arg: Install mode, with q: Information */
|
||||
if (!func) func = rpm_install;
|
||||
else func |= rpm_query_info;
|
||||
break;
|
||||
case 'q': /* First arg: Query mode */
|
||||
if (func) bb_show_usage();
|
||||
func = rpm_query;
|
||||
break;
|
||||
case 'p': /* Query a package */
|
||||
func |= rpm_query_package;
|
||||
break;
|
||||
case 'l': /* List files in a package */
|
||||
func |= rpm_query_list;
|
||||
break;
|
||||
case 'd': /* List doc files in a package (implies list) */
|
||||
func |= rpm_query_list;
|
||||
func |= rpm_query_list_doc;
|
||||
break;
|
||||
case 'c': /* List config files in a package (implies list) */
|
||||
func |= rpm_query_list;
|
||||
func |= rpm_query_list_config;
|
||||
break;
|
||||
default:
|
||||
bb_show_usage();
|
||||
}
|
||||
}
|
||||
argv += optind;
|
||||
//argc -= optind;
|
||||
if (!argv[0]) {
|
||||
bb_show_usage();
|
||||
}
|
||||
|
||||
while (*argv) {
|
||||
int rpm_fd;
|
||||
unsigned mapsize;
|
||||
const char *source_rpm;
|
||||
|
||||
rpm_fd = xopen(*argv++, O_RDONLY);
|
||||
G.mytags = rpm_gettags(rpm_fd, &G.tagcount);
|
||||
if (!G.mytags)
|
||||
bb_error_msg_and_die("error reading rpm header");
|
||||
mapsize = xlseek(rpm_fd, 0, SEEK_CUR);
|
||||
mapsize = (mapsize + pagesize) & -(int)pagesize;
|
||||
/* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
|
||||
G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
|
||||
//FIXME: error check?
|
||||
|
||||
source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
|
||||
|
||||
if (func & rpm_install) {
|
||||
/* Backup any config files */
|
||||
loop_through_files(TAG_BASENAMES, fileaction_dobackup);
|
||||
/* Extact the archive */
|
||||
extract_cpio(rpm_fd, source_rpm);
|
||||
/* Set the correct file uid/gid's */
|
||||
loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
|
||||
}
|
||||
else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
|
||||
if (!(func & (rpm_query_info|rpm_query_list))) {
|
||||
/* If just a straight query, just give package name */
|
||||
printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
|
||||
}
|
||||
if (func & rpm_query_info) {
|
||||
/* Do the nice printout */
|
||||
time_t bdate_time;
|
||||
struct tm *bdate_ptm;
|
||||
char bdatestring[50];
|
||||
const char *p;
|
||||
|
||||
printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0));
|
||||
/* TODO compat: add "Epoch" here */
|
||||
printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0));
|
||||
printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0));
|
||||
/* add "Architecture" */
|
||||
printf("%-12s: %s\n", "Install Date", "(not installed)");
|
||||
printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0));
|
||||
printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0));
|
||||
printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0));
|
||||
/* add "Signature" */
|
||||
printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)");
|
||||
bdate_time = rpm_getint(TAG_BUILDTIME, 0);
|
||||
bdate_ptm = localtime(&bdate_time);
|
||||
strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
|
||||
printf("%-12s: %s\n", "Build Date" , bdatestring);
|
||||
printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0));
|
||||
p = rpm_getstr(TAG_PREFIXS, 0);
|
||||
printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)");
|
||||
/* add "Packager" */
|
||||
p = rpm_getstr(TAG_VENDOR, 0);
|
||||
printf("%-12s: %s\n", "Vendor" , p ? p : "(none)");
|
||||
printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0));
|
||||
printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0));
|
||||
printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
|
||||
}
|
||||
if (func & rpm_query_list) {
|
||||
int count, it, flags;
|
||||
count = rpm_getcount(TAG_BASENAMES);
|
||||
for (it = 0; it < count; it++) {
|
||||
flags = rpm_getint(TAG_FILEFLAGS, it);
|
||||
switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
|
||||
case rpm_query_list_doc:
|
||||
if (!(flags & RPMFILE_DOC)) continue;
|
||||
break;
|
||||
case rpm_query_list_config:
|
||||
if (!(flags & RPMFILE_CONFIG)) continue;
|
||||
break;
|
||||
case rpm_query_list_doc|rpm_query_list_config:
|
||||
if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
|
||||
break;
|
||||
}
|
||||
printf("%s%s\n",
|
||||
rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
|
||||
rpm_getstr(TAG_BASENAMES, it));
|
||||
}
|
||||
}
|
||||
}
|
||||
munmap(G.map, mapsize);
|
||||
free(G.mytags);
|
||||
close(rpm_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* RPM structs and consts
|
||||
*
|
||||
* Copyright (C) 2001 by Laurence Anderson
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
/* RPM file starts with this struct: */
|
||||
struct rpm_lead {
|
||||
uint32_t magic;
|
||||
uint8_t major, minor;
|
||||
uint16_t type;
|
||||
uint16_t archnum;
|
||||
char name[66];
|
||||
uint16_t osnum;
|
||||
uint16_t signature_type;
|
||||
char reserved[16];
|
||||
};
|
||||
struct BUG_rpm_lead {
|
||||
char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1];
|
||||
};
|
||||
#define RPM_LEAD_MAGIC 0xedabeedb
|
||||
#define RPM_LEAD_MAGIC_STR "\355\253\356\333"
|
||||
|
||||
/* Then follows the header: */
|
||||
struct rpm_header {
|
||||
uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */
|
||||
uint32_t reserved; /* 4 bytes reserved */
|
||||
uint32_t entries; /* Number of entries in header (4 bytes) */
|
||||
uint32_t size; /* Size of store (4 bytes) */
|
||||
};
|
||||
struct BUG_rpm_header {
|
||||
char bug[sizeof(struct rpm_header) == 16 ? 1 : -1];
|
||||
};
|
||||
#define RPM_HEADER_MAGICnVER 0x8eade801
|
||||
#define RPM_HEADER_MAGIC_STR "\216\255\350"
|
@ -1,96 +0,0 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Mini rpm2cpio implementation for busybox
|
||||
*
|
||||
* Copyright (C) 2001 by Laurence Anderson
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
//config:config RPM2CPIO
|
||||
//config: bool "rpm2cpio"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: Converts a RPM file into a CPIO archive.
|
||||
|
||||
//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
|
||||
|
||||
//usage:#define rpm2cpio_trivial_usage
|
||||
//usage: "package.rpm"
|
||||
//usage:#define rpm2cpio_full_usage "\n\n"
|
||||
//usage: "Output a cpio archive of the rpm file"
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
#include "rpm.h"
|
||||
|
||||
enum { rpm_fd = STDIN_FILENO };
|
||||
|
||||
static unsigned skip_header(void)
|
||||
{
|
||||
struct rpm_header header;
|
||||
unsigned len;
|
||||
|
||||
xread(rpm_fd, &header, sizeof(header));
|
||||
// if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) {
|
||||
// bb_error_msg_and_die("invalid RPM header magic");
|
||||
// }
|
||||
// if (header.version != 1) {
|
||||
// bb_error_msg_and_die("unsupported RPM header version");
|
||||
// }
|
||||
if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) {
|
||||
bb_error_msg_and_die("invalid RPM header magic or unsupported version");
|
||||
// ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER));
|
||||
}
|
||||
|
||||
/* Seek past index entries, and past store */
|
||||
len = 16 * ntohl(header.entries) + ntohl(header.size);
|
||||
seek_by_jump(rpm_fd, len);
|
||||
|
||||
return sizeof(header) + len;
|
||||
}
|
||||
|
||||
/* No getopt required */
|
||||
int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
struct rpm_lead lead;
|
||||
unsigned pos;
|
||||
|
||||
if (argv[1]) {
|
||||
xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd);
|
||||
}
|
||||
xread(rpm_fd, &lead, sizeof(lead));
|
||||
|
||||
/* Just check the magic, the rest is irrelevant */
|
||||
if (lead.magic != htonl(RPM_LEAD_MAGIC)) {
|
||||
bb_error_msg_and_die("invalid RPM magic");
|
||||
}
|
||||
|
||||
/* Skip the signature header, align to 8 bytes */
|
||||
pos = skip_header();
|
||||
seek_by_jump(rpm_fd, (-(int)pos) & 7);
|
||||
|
||||
/* Skip the main header */
|
||||
skip_header();
|
||||
|
||||
//if (SEAMLESS_COMPRESSION)
|
||||
// /* We need to know whether child (gzip/bzip/etc) exits abnormally */
|
||||
// signal(SIGCHLD, check_errors_in_children);
|
||||
|
||||
/* This works, but doesn't report uncompress errors (they happen in child) */
|
||||
setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1);
|
||||
if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
|
||||
bb_error_msg_and_die("error unpacking");
|
||||
|
||||
if (ENABLE_FEATURE_CLEAN_UP) {
|
||||
close(rpm_fd);
|
||||
}
|
||||
|
||||
if (SEAMLESS_COMPRESSION) {
|
||||
check_errors_in_children(0);
|
||||
return bb_got_signal;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
1227
archival/tar.c
1227
archival/tar.c
File diff suppressed because it is too large
Load Diff
753
archival/unzip.c
753
archival/unzip.c
@ -1,753 +0,0 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Mini unzip implementation for busybox
|
||||
*
|
||||
* Copyright (C) 2004 by Ed Clark
|
||||
*
|
||||
* Loosely based on original busybox unzip applet by Laurence Anderson.
|
||||
* All options and features should work in this version.
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
/* For reference see
|
||||
* http://www.pkware.com/company/standards/appnote/
|
||||
* http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
|
||||
*
|
||||
* TODO
|
||||
* Zip64 + other methods
|
||||
*/
|
||||
|
||||
//config:config UNZIP
|
||||
//config: bool "unzip"
|
||||
//config: default y
|
||||
//config: help
|
||||
//config: unzip will list or extract files from a ZIP archive,
|
||||
//config: commonly found on DOS/WIN systems. The default behavior
|
||||
//config: (with no options) is to extract the archive into the
|
||||
//config: current directory. Use the `-d' option to extract to a
|
||||
//config: directory of your choice.
|
||||
|
||||
//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
|
||||
//kbuild:lib-$(CONFIG_UNZIP) += unzip.o
|
||||
|
||||
//usage:#define unzip_trivial_usage
|
||||
//usage: "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
|
||||
//usage:#define unzip_full_usage "\n\n"
|
||||
//usage: "Extract FILEs from ZIP archive\n"
|
||||
//usage: "\n -l List contents (with -q for short form)"
|
||||
//usage: "\n -n Never overwrite files (default: ask)"
|
||||
//usage: "\n -o Overwrite"
|
||||
//usage: "\n -p Print to stdout"
|
||||
//usage: "\n -q Quiet"
|
||||
//usage: "\n -x FILE Exclude FILEs"
|
||||
//usage: "\n -d DIR Extract into DIR"
|
||||
|
||||
#include "libbb.h"
|
||||
#include "bb_archive.h"
|
||||
|
||||
enum {
|
||||
#if BB_BIG_ENDIAN
|
||||
ZIP_FILEHEADER_MAGIC = 0x504b0304,
|
||||
ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */
|
||||
ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */
|
||||
ZIP_DD_MAGIC = 0x504b0708,
|
||||
#else
|
||||
ZIP_FILEHEADER_MAGIC = 0x04034b50,
|
||||
ZIP_CDF_MAGIC = 0x02014b50,
|
||||
ZIP_CDE_MAGIC = 0x06054b50,
|
||||
ZIP_DD_MAGIC = 0x08074b50,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ZIP_HEADER_LEN 26
|
||||
|
||||
typedef union {
|
||||
uint8_t raw[ZIP_HEADER_LEN];
|
||||
struct {
|
||||
uint16_t version; /* 0-1 */
|
||||
uint16_t zip_flags; /* 2-3 */
|
||||
uint16_t method; /* 4-5 */
|
||||
uint16_t modtime; /* 6-7 */
|
||||
uint16_t moddate; /* 8-9 */
|
||||
uint32_t crc32 PACKED; /* 10-13 */
|
||||
uint32_t cmpsize PACKED; /* 14-17 */
|
||||
uint32_t ucmpsize PACKED; /* 18-21 */
|
||||
uint16_t filename_len; /* 22-23 */
|
||||
uint16_t extra_len; /* 24-25 */
|
||||
} formatted PACKED;
|
||||
} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
|
||||
|
||||
/* Check the offset of the last element, not the length. This leniency
|
||||
* allows for poor packing, whereby the overall struct may be too long,
|
||||
* even though the elements are all in the right place.
|
||||
*/
|
||||
struct BUG_zip_header_must_be_26_bytes {
|
||||
char BUG_zip_header_must_be_26_bytes[
|
||||
offsetof(zip_header_t, formatted.extra_len) + 2
|
||||
== ZIP_HEADER_LEN ? 1 : -1];
|
||||
};
|
||||
|
||||
#define FIX_ENDIANNESS_ZIP(zip_header) do { \
|
||||
(zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \
|
||||
(zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \
|
||||
(zip_header).formatted.modtime = SWAP_LE16((zip_header).formatted.modtime ); \
|
||||
(zip_header).formatted.moddate = SWAP_LE16((zip_header).formatted.moddate ); \
|
||||
(zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \
|
||||
(zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \
|
||||
(zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \
|
||||
(zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
|
||||
(zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \
|
||||
} while (0)
|
||||
|
||||
#define CDF_HEADER_LEN 42
|
||||
|
||||
typedef union {
|
||||
uint8_t raw[CDF_HEADER_LEN];
|
||||
struct {
|
||||
/* uint32_t signature; 50 4b 01 02 */
|
||||
uint16_t version_made_by; /* 0-1 */
|
||||
uint16_t version_needed; /* 2-3 */
|
||||
uint16_t cdf_flags; /* 4-5 */
|
||||
uint16_t method; /* 6-7 */
|
||||
uint16_t mtime; /* 8-9 */
|
||||
uint16_t mdate; /* 10-11 */
|
||||
uint32_t crc32; /* 12-15 */
|
||||
uint32_t cmpsize; /* 16-19 */
|
||||
uint32_t ucmpsize; /* 20-23 */
|
||||
uint16_t file_name_length; /* 24-25 */
|
||||
uint16_t extra_field_length; /* 26-27 */
|
||||
uint16_t file_comment_length; /* 28-29 */
|
||||
uint16_t disk_number_start; /* 30-31 */
|
||||
uint16_t internal_file_attributes; /* 32-33 */
|
||||
uint32_t external_file_attributes PACKED; /* 34-37 */
|
||||
uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
|
||||
} formatted PACKED;
|
||||
} cdf_header_t;
|
||||
|
||||
struct BUG_cdf_header_must_be_42_bytes {
|
||||
char BUG_cdf_header_must_be_42_bytes[
|
||||
offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
|
||||
== CDF_HEADER_LEN ? 1 : -1];
|
||||
};
|
||||
|
||||
#define FIX_ENDIANNESS_CDF(cdf_header) do { \
|
||||
(cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \
|
||||
(cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \
|
||||
(cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \
|
||||
(cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
|
||||
(cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
|
||||
(cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
|
||||
IF_DESKTOP( \
|
||||
(cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
|
||||
(cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
|
||||
) \
|
||||
} while (0)
|
||||
|
||||
#define CDE_HEADER_LEN 16
|
||||
|
||||
typedef union {
|
||||
uint8_t raw[CDE_HEADER_LEN];
|
||||
struct {
|
||||
/* uint32_t signature; 50 4b 05 06 */
|
||||
uint16_t this_disk_no;
|
||||
uint16_t disk_with_cdf_no;
|
||||
uint16_t cdf_entries_on_this_disk;
|
||||
uint16_t cdf_entries_total;
|
||||
uint32_t cdf_size;
|
||||
uint32_t cdf_offset;
|
||||
/* uint16_t file_comment_length; */
|
||||
/* .ZIP file comment (variable size) */
|
||||
} formatted PACKED;
|
||||
} cde_header_t;
|
||||
|
||||
struct BUG_cde_header_must_be_16_bytes {
|
||||
char BUG_cde_header_must_be_16_bytes[
|
||||
sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
|
||||
};
|
||||
|
||||
#define FIX_ENDIANNESS_CDE(cde_header) do { \
|
||||
(cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
|
||||
} while (0)
|
||||
|
||||
enum { zip_fd = 3 };
|
||||
|
||||
|
||||
#if ENABLE_DESKTOP
|
||||
|
||||
/* Seen in the wild:
|
||||
* Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive,
|
||||
* where CDE was nearly 48 kbytes before EOF.
|
||||
* (Surprisingly, it also apparently has *another* CDE structure
|
||||
* closer to the end, with bogus cdf_offset).
|
||||
* To make extraction work, bumped PEEK_FROM_END from 16k to 64k.
|
||||
*/
|
||||
#define PEEK_FROM_END (64*1024)
|
||||
|
||||
/* This value means that we failed to find CDF */
|
||||
#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
|
||||
|
||||
/* NB: does not preserve file position! */
|
||||
static uint32_t find_cdf_offset(void)
|
||||
{
|
||||
cde_header_t cde_header;
|
||||
unsigned char *p;
|
||||
off_t end;
|
||||
unsigned char *buf = xzalloc(PEEK_FROM_END);
|
||||
|
||||
end = xlseek(zip_fd, 0, SEEK_END);
|
||||
end -= PEEK_FROM_END;
|
||||
if (end < 0)
|
||||
end = 0;
|
||||
xlseek(zip_fd, end, SEEK_SET);
|
||||
full_read(zip_fd, buf, PEEK_FROM_END);
|
||||
|
||||
cde_header.formatted.cdf_offset = BAD_CDF_OFFSET;
|
||||
p = buf;
|
||||
while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
|
||||
if (*p != 'P') {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (*++p != 'K')
|
||||
continue;
|
||||
if (*++p != 5)
|
||||
continue;
|
||||
if (*++p != 6)
|
||||
continue;
|
||||
/* we found CDE! */
|
||||
memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
|
||||
FIX_ENDIANNESS_CDE(cde_header);
|
||||
/*
|
||||
* I've seen .ZIP files with seemingly valid CDEs
|
||||
* where cdf_offset points past EOF - ??
|
||||
* Ignore such CDEs:
|
||||
*/
|
||||
if (cde_header.formatted.cdf_offset < end + (p - buf))
|
||||
break;
|
||||
cde_header.formatted.cdf_offset = BAD_CDF_OFFSET;
|
||||
}
|
||||
free(buf);
|
||||
return cde_header.formatted.cdf_offset;
|
||||
};
|
||||
|
||||
static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
|
||||
{
|
||||
off_t org;
|
||||
|
||||
org = xlseek(zip_fd, 0, SEEK_CUR);
|
||||
|
||||
if (!cdf_offset)
|
||||
cdf_offset = find_cdf_offset();
|
||||
|
||||
if (cdf_offset != BAD_CDF_OFFSET) {
|
||||
xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
|
||||
xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
|
||||
FIX_ENDIANNESS_CDF(*cdf_ptr);
|
||||
cdf_offset += 4 + CDF_HEADER_LEN
|
||||
+ cdf_ptr->formatted.file_name_length
|
||||
+ cdf_ptr->formatted.extra_field_length
|
||||
+ cdf_ptr->formatted.file_comment_length;
|
||||
}
|
||||
|
||||
xlseek(zip_fd, org, SEEK_SET);
|
||||
return cdf_offset;
|
||||
};
|
||||
#endif
|
||||
|
||||
static void unzip_skip(off_t skip)
|
||||
{
|
||||
if (skip != 0)
|
||||
if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
|
||||
bb_copyfd_exact_size(zip_fd, -1, skip);
|
||||
}
|
||||
|
||||
static void unzip_create_leading_dirs(const char *fn)
|
||||
{
|
||||
/* Create all leading directories */
|
||||
char *name = xstrdup(fn);
|
||||
if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
|
||||
xfunc_die(); /* bb_make_directory is noisy */
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void unzip_extract(zip_header_t *zip_header, int dst_fd)
|
||||
{
|
||||
if (zip_header->formatted.method == 0) {
|
||||
/* Method 0 - stored (not compressed) */
|
||||
off_t size = zip_header->formatted.ucmpsize;
|
||||
if (size)
|
||||
bb_copyfd_exact_size(zip_fd, dst_fd, size);
|
||||
} else {
|
||||
/* Method 8 - inflate */
|
||||
transformer_aux_data_t aux;
|
||||
init_transformer_aux_data(&aux);
|
||||
aux.bytes_in = zip_header->formatted.cmpsize;
|
||||
if (inflate_unzip(&aux, zip_fd, dst_fd) < 0)
|
||||
bb_error_msg_and_die("inflate error");
|
||||
/* Validate decompression - crc */
|
||||
if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) {
|
||||
bb_error_msg_and_die("crc error");
|
||||
}
|
||||
/* Validate decompression - size */
|
||||
if (zip_header->formatted.ucmpsize != aux.bytes_out) {
|
||||
/* Don't die. Who knows, maybe len calculation
|
||||
* was botched somewhere. After all, crc matched! */
|
||||
bb_error_msg("bad length");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void my_fgets80(char *buf80)
|
||||
{
|
||||
fflush_all();
|
||||
if (!fgets(buf80, 80, stdin)) {
|
||||
bb_perror_msg_and_die("can't read standard input");
|
||||
}
|
||||
}
|
||||
|
||||
int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int unzip_main(int argc, char **argv)
|
||||
{
|
||||
enum { O_PROMPT, O_NEVER, O_ALWAYS };
|
||||
|
||||
zip_header_t zip_header;
|
||||
smallint quiet = 0;
|
||||
IF_NOT_DESKTOP(const) smallint verbose = 0;
|
||||
smallint listing = 0;
|
||||
smallint overwrite = O_PROMPT;
|
||||
smallint x_opt_seen;
|
||||
#if ENABLE_DESKTOP
|
||||
uint32_t cdf_offset;
|
||||
#endif
|
||||
unsigned long total_usize;
|
||||
unsigned long total_size;
|
||||
unsigned total_entries;
|
||||
int dst_fd = -1;
|
||||
char *src_fn = NULL;
|
||||
char *dst_fn = NULL;
|
||||
llist_t *zaccept = NULL;
|
||||
llist_t *zreject = NULL;
|
||||
char *base_dir = NULL;
|
||||
int i, opt;
|
||||
char key_buf[80]; /* must match size used by my_fgets80 */
|
||||
struct stat stat_buf;
|
||||
|
||||
/* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP:
|
||||
*
|
||||
* # /usr/bin/unzip -qq -v decompress_unlzma.i.zip
|
||||
* 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
|
||||
* # /usr/bin/unzip -q -v decompress_unlzma.i.zip
|
||||
* Length Method Size Ratio Date Time CRC-32 Name
|
||||
* -------- ------ ------- ----- ---- ---- ------ ----
|
||||
* 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
|
||||
* -------- ------- --- -------
|
||||
* 204372 35278 83% 1 file
|
||||
* # /usr/bin/unzip -v decompress_unlzma.i.zip
|
||||
* Archive: decompress_unlzma.i.zip
|
||||
* Length Method Size Ratio Date Time CRC-32 Name
|
||||
* -------- ------ ------- ----- ---- ---- ------ ----
|
||||
* 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i
|
||||
* -------- ------- --- -------
|
||||
* 204372 35278 83% 1 file
|
||||
* # unzip -v decompress_unlzma.i.zip
|
||||
* Archive: decompress_unlzma.i.zip
|
||||
* Length Date Time Name
|
||||
* -------- ---- ---- ----
|
||||
* 204372 09-06-09 14:23 decompress_unlzma.i
|
||||
* -------- -------
|
||||
* 204372 1 files
|
||||
* # /usr/bin/unzip -l -qq decompress_unlzma.i.zip
|
||||
* 204372 09-06-09 14:23 decompress_unlzma.i
|
||||
* # /usr/bin/unzip -l -q decompress_unlzma.i.zip
|
||||
* Length Date Time Name
|
||||
* -------- ---- ---- ----
|
||||
* 204372 09-06-09 14:23 decompress_unlzma.i
|
||||
* -------- -------
|
||||
* 204372 1 file
|
||||
* # /usr/bin/unzip -l decompress_unlzma.i.zip
|
||||
* Archive: decompress_unlzma.i.zip
|
||||
* Length Date Time Name
|
||||
* -------- ---- ---- ----
|
||||
* 204372 09-06-09 14:23 decompress_unlzma.i
|
||||
* -------- -------
|
||||
* 204372 1 file
|
||||
*/
|
||||
|
||||
x_opt_seen = 0;
|
||||
/* '-' makes getopt return 1 for non-options */
|
||||
while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd': /* Extract to base directory */
|
||||
base_dir = optarg;
|
||||
break;
|
||||
|
||||
case 'l': /* List */
|
||||
listing = 1;
|
||||
break;
|
||||
|
||||
case 'n': /* Never overwrite existing files */
|
||||
overwrite = O_NEVER;
|
||||
break;
|
||||
|
||||
case 'o': /* Always overwrite existing files */
|
||||
overwrite = O_ALWAYS;
|
||||
break;
|
||||
|
||||
case 'p': /* Extract files to stdout and fall through to set verbosity */
|
||||
dst_fd = STDOUT_FILENO;
|
||||
|
||||
case 'q': /* Be quiet */
|
||||
quiet++;
|
||||
break;
|
||||
|
||||
case 'v': /* Verbose list */
|
||||
IF_DESKTOP(verbose++;)
|
||||
listing = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
x_opt_seen = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!src_fn) {
|
||||
/* The zip file */
|
||||
/* +5: space for ".zip" and NUL */
|
||||
src_fn = xmalloc(strlen(optarg) + 5);
|
||||
strcpy(src_fn, optarg);
|
||||
} else if (!x_opt_seen) {
|
||||
/* Include files */
|
||||
llist_add_to(&zaccept, optarg);
|
||||
} else {
|
||||
/* Exclude files */
|
||||
llist_add_to(&zreject, optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
bb_show_usage();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __GLIBC__
|
||||
/*
|
||||
* This code is needed for non-GNU getopt
|
||||
* which doesn't understand "-" in option string.
|
||||
* The -x option won't work properly in this case:
|
||||
* "unzip a.zip q -x w e" will be interpreted as
|
||||
* "unzip a.zip q w e -x" = "unzip a.zip q w e"
|
||||
*/
|
||||
argv += optind;
|
||||
if (argv[0]) {
|
||||
/* +5: space for ".zip" and NUL */
|
||||
src_fn = xmalloc(strlen(argv[0]) + 5);
|
||||
strcpy(src_fn, argv[0]);
|
||||
while (*++argv)
|
||||
llist_add_to(&zaccept, *argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!src_fn) {
|
||||
bb_show_usage();
|
||||
}
|
||||
|
||||
/* Open input file */
|
||||
if (LONE_DASH(src_fn)) {
|
||||
xdup2(STDIN_FILENO, zip_fd);
|
||||
/* Cannot use prompt mode since zip data is arriving on STDIN */
|
||||
if (overwrite == O_PROMPT)
|
||||
overwrite = O_NEVER;
|
||||
} else {
|
||||
static const char extn[][5] = { ".zip", ".ZIP" };
|
||||
char *ext = src_fn + strlen(src_fn);
|
||||
int src_fd;
|
||||
|
||||
i = 0;
|
||||
for (;;) {
|
||||
src_fd = open(src_fn, O_RDONLY);
|
||||
if (src_fd >= 0)
|
||||
break;
|
||||
if (++i > 2) {
|
||||
*ext = '\0';
|
||||
bb_error_msg_and_die("can't open %s[.zip]", src_fn);
|
||||
}
|
||||
strcpy(ext, extn[i - 1]);
|
||||
}
|
||||
xmove_fd(src_fd, zip_fd);
|
||||
}
|
||||
|
||||
/* Change dir if necessary */
|
||||
if (base_dir)
|
||||
xchdir(base_dir);
|
||||
|
||||
if (quiet <= 1) { /* not -qq */
|
||||
if (quiet == 0)
|
||||
printf("Archive: %s\n", src_fn);
|
||||
if (listing) {
|
||||
puts(verbose ?
|
||||
" Length Method Size Ratio Date Time CRC-32 Name\n"
|
||||
"-------- ------ ------- ----- ---- ---- ------ ----"
|
||||
:
|
||||
" Length Date Time Name\n"
|
||||
" -------- ---- ---- ----"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Example of an archive with one 0-byte long file named 'z'
|
||||
* created by Zip 2.31 on Unix:
|
||||
* 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
|
||||
* sig........ vneed flags compr mtime mdate crc32>
|
||||
* 0010 00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
|
||||
* >..... csize...... usize...... fnlen exlen fn ex>
|
||||
* 0020 54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
|
||||
* >tra_field......................................
|
||||
* 0030 00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
|
||||
* ........... sig........ vmade vneed flags compr
|
||||
* 0040 42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
|
||||
* mtime mdate crc32...... csize...... usize......
|
||||
* 0050 01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
|
||||
* fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
|
||||
* 0060 00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
|
||||
* >..... fn extra_field...........................
|
||||
* 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
|
||||
* 0080 34 00 00 00 00 00 |4.....|
|
||||
*/
|
||||
total_usize = 0;
|
||||
total_size = 0;
|
||||
total_entries = 0;
|
||||
#if ENABLE_DESKTOP
|
||||
cdf_offset = 0;
|
||||
#endif
|
||||
while (1) {
|
||||
uint32_t magic;
|
||||
mode_t dir_mode = 0777;
|
||||
#if ENABLE_DESKTOP
|
||||
mode_t file_mode = 0666;
|
||||
#endif
|
||||
|
||||
/* Check magic number */
|
||||
xread(zip_fd, &magic, 4);
|
||||
/* Central directory? It's at the end, so exit */
|
||||
if (magic == ZIP_CDF_MAGIC)
|
||||
break;
|
||||
#if ENABLE_DESKTOP
|
||||
/* Data descriptor? It was a streaming file, go on */
|
||||
if (magic == ZIP_DD_MAGIC) {
|
||||
/* skip over duplicate crc32, cmpsize and ucmpsize */
|
||||
unzip_skip(3 * 4);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (magic != ZIP_FILEHEADER_MAGIC)
|
||||
bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
|
||||
|
||||
/* Read the file header */
|
||||
xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
|
||||
FIX_ENDIANNESS_ZIP(zip_header);
|
||||
if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
|
||||
bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
|
||||
}
|
||||
#if !ENABLE_DESKTOP
|
||||
if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
|
||||
bb_error_msg_and_die("zip flags 1 and 8 are not supported");
|
||||
}
|
||||
#else
|
||||
if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
|
||||
/* 0x0001 - encrypted */
|
||||
bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
|
||||
}
|
||||
|
||||
if (cdf_offset != BAD_CDF_OFFSET) {
|
||||
cdf_header_t cdf_header;
|
||||
cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
|
||||
/*
|
||||
* Note: cdf_offset can become BAD_CDF_OFFSET after the above call.
|
||||
*/
|
||||
if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
|
||||
/* 0x0008 - streaming. [u]cmpsize can be reliably gotten
|
||||
* only from Central Directory. See unzip_doc.txt
|
||||
*/
|
||||
zip_header.formatted.crc32 = cdf_header.formatted.crc32;
|
||||
zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize;
|
||||
zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
|
||||
}
|
||||
if ((cdf_header.formatted.version_made_by >> 8) == 3) {
|
||||
/* This archive is created on Unix */
|
||||
dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
|
||||
}
|
||||
}
|
||||
if (cdf_offset == BAD_CDF_OFFSET
|
||||
&& (zip_header.formatted.zip_flags & SWAP_LE16(0x0008))
|
||||
) {
|
||||
/* If it's a streaming zip, we _require_ CDF */
|
||||
bb_error_msg_and_die("can't find file table");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read filename */
|
||||
free(dst_fn);
|
||||
dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
|
||||
xread(zip_fd, dst_fn, zip_header.formatted.filename_len);
|
||||
|
||||
/* Skip extra header bytes */
|
||||
unzip_skip(zip_header.formatted.extra_len);
|
||||
|
||||
/* Filter zip entries */
|
||||
if (find_list_entry(zreject, dst_fn)
|
||||
|| (zaccept && !find_list_entry(zaccept, dst_fn))
|
||||
) { /* Skip entry */
|
||||
i = 'n';
|
||||
|
||||
} else { /* Extract entry */
|
||||
if (listing) { /* List entry */
|
||||
unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
|
||||
if (!verbose) {
|
||||
// " Length Date Time Name\n"
|
||||
// " -------- ---- ---- ----"
|
||||
printf( "%9u %02u-%02u-%02u %02u:%02u %s\n",
|
||||
(unsigned)zip_header.formatted.ucmpsize,
|
||||
(dostime & 0x01e00000) >> 21,
|
||||
(dostime & 0x001f0000) >> 16,
|
||||
(((dostime & 0xfe000000) >> 25) + 1980) % 100,
|
||||
(dostime & 0x0000f800) >> 11,
|
||||
(dostime & 0x000007e0) >> 5,
|
||||
dst_fn);
|
||||
total_usize += zip_header.formatted.ucmpsize;
|
||||
} else {
|
||||
unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize;
|
||||
percents = percents * 100;
|
||||
if (zip_header.formatted.ucmpsize)
|
||||
percents /= zip_header.formatted.ucmpsize;
|
||||
// " Length Method Size Ratio Date Time CRC-32 Name\n"
|
||||
// "-------- ------ ------- ----- ---- ---- ------ ----"
|
||||
printf( "%8u Defl:N" "%9u%4u%% %02u-%02u-%02u %02u:%02u %08x %s\n",
|
||||
(unsigned)zip_header.formatted.ucmpsize,
|
||||
(unsigned)zip_header.formatted.cmpsize,
|
||||
(unsigned)percents,
|
||||
(dostime & 0x01e00000) >> 21,
|
||||
(dostime & 0x001f0000) >> 16,
|
||||
(((dostime & 0xfe000000) >> 25) + 1980) % 100,
|
||||
(dostime & 0x0000f800) >> 11,
|
||||
(dostime & 0x000007e0) >> 5,
|
||||
zip_header.formatted.crc32,
|
||||
dst_fn);
|
||||
total_usize += zip_header.formatted.ucmpsize;
|
||||
total_size += zip_header.formatted.cmpsize;
|
||||
}
|
||||
i = 'n';
|
||||
} else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
|
||||
i = -1;
|
||||
} else if (last_char_is(dst_fn, '/')) { /* Extract directory */
|
||||
if (stat(dst_fn, &stat_buf) == -1) {
|
||||
if (errno != ENOENT) {
|
||||
bb_perror_msg_and_die("can't stat '%s'", dst_fn);
|
||||
}
|
||||
if (!quiet) {
|
||||
printf(" creating: %s\n", dst_fn);
|
||||
}
|
||||
unzip_create_leading_dirs(dst_fn);
|
||||
if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
|
||||
xfunc_die();
|
||||
}
|
||||
} else {
|
||||
if (!S_ISDIR(stat_buf.st_mode)) {
|
||||
bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
|
||||
}
|
||||
}
|
||||
i = 'n';
|
||||
|
||||
} else { /* Extract file */
|
||||
check_file:
|
||||
if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
|
||||
if (errno != ENOENT) {
|
||||
bb_perror_msg_and_die("can't stat '%s'", dst_fn);
|
||||
}
|
||||
i = 'y';
|
||||
} else { /* File already exists */
|
||||
if (overwrite == O_NEVER) {
|
||||
i = 'n';
|
||||
} else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
|
||||
if (overwrite == O_ALWAYS) {
|
||||
i = 'y';
|
||||
} else {
|
||||
printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
|
||||
my_fgets80(key_buf);
|
||||
i = key_buf[0];
|
||||
}
|
||||
} else { /* File is not regular file */
|
||||
bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 'A':
|
||||
overwrite = O_ALWAYS;
|
||||
case 'y': /* Open file and fall into unzip */
|
||||
unzip_create_leading_dirs(dst_fn);
|
||||
#if ENABLE_DESKTOP
|
||||
dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
|
||||
#else
|
||||
dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
#endif
|
||||
case -1: /* Unzip */
|
||||
if (!quiet) {
|
||||
printf(" inflating: %s\n", dst_fn);
|
||||
}
|
||||
unzip_extract(&zip_header, dst_fd);
|
||||
if (dst_fd != STDOUT_FILENO) {
|
||||
/* closing STDOUT is potentially bad for future business */
|
||||
close(dst_fd);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
overwrite = O_NEVER;
|
||||
case 'n':
|
||||
/* Skip entry data */
|
||||
unzip_skip(zip_header.formatted.cmpsize);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
/* Prompt for new name */
|
||||
printf("new name: ");
|
||||
my_fgets80(key_buf);
|
||||
free(dst_fn);
|
||||
dst_fn = xstrdup(key_buf);
|
||||
chomp(dst_fn);
|
||||
goto check_file;
|
||||
|
||||
default:
|
||||
printf("error: invalid response [%c]\n", (char)i);
|
||||
goto check_file;
|
||||
}
|
||||
|
||||
total_entries++;
|
||||
}
|
||||
|
||||
if (listing && quiet <= 1) {
|
||||
if (!verbose) {
|
||||
// " Length Date Time Name\n"
|
||||
// " -------- ---- ---- ----"
|
||||
printf( " -------- -------\n"
|
||||
"%9lu" " %u files\n",
|
||||
total_usize, total_entries);
|
||||
} else {
|
||||
unsigned long percents = total_usize - total_size;
|
||||
percents = percents * 100;
|
||||
if (total_usize)
|
||||
percents /= total_usize;
|
||||
// " Length Method Size Ratio Date Time CRC-32 Name\n"
|
||||
// "-------- ------ ------- ----- ---- ---- ------ ----"
|
||||
printf( "-------- ------- --- -------\n"
|
||||
"%8lu" "%17lu%4u%% %u files\n",
|
||||
total_usize, total_size, (unsigned)percents,
|
||||
total_entries);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
55
build
55
build
@ -1 +1,54 @@
|
||||
gcc -Wp,-MD,shell/.hush.o.d -std=gnu99 -Iinclude -include include/autoconf.h -Dhush_main=main -D_GNU_SOURCE -DNDEBUG -D"BB_VER=KBUILD_STR(1.22.1)" -Wall -D"KBUILD_STR(s)=#s" -o hush shell/hush.c shell/match.c shell/math.c shell/random.c shell/shell_common.c libbb/xfuncs_printf.c libbb/xfuncs.c libbb/xgetcwd.c libbb/getopt32.c libbb/perror_msg.c libbb/xatonum.c libbb/u_signal_names.c libbb/ptr_to_globals.c libbb/default_error_retval.c libbb/xfunc_die.c libbb/safe_strncpy.c libbb/lineedit.c libbb/lineedit_ptr_hack.c libbb/platform.c libbb/endofname.c libbb/signals.c libbb/skip_whitespace.c libbb/wfopen.c libbb/verror_msg.c libbb/bb_strtonum.c libbb/time.c libbb/printable_string.c libbb/full_write.c libbb/bb_qsort.c libbb/xrealloc_vector.c libbb/copyfd.c libbb/read_key.c libbb/unicode.c libbb/safe_write.c libbb/read.c libbb/safe_gethostname.c libbb/get_line_from_file.c libbb/concat_path_file.c libbb/last_char_is.c libbb/safe_poll.c libbb/process_escape_sequence.c libbb/compare_string_array.c libbb/llist.c libbb/parse_mode.c coreutils/echo.c coreutils/test.c coreutils/test_ptr_hack.c libbb/messages.c libbb/appletlib.c libbb/get_last_path_component.c libbb/mempcpy.c
|
||||
gcc -Wp,-MD,shell/.hush.o.d -std=gnu99 -Wall -o hush \
|
||||
-Iinclude -include include/autoconf.h \
|
||||
-Dhush_main=main -D_GNU_SOURCE -DNDEBUG -D"BB_VER=KBUILD_STR(1.22.1)" -D"KBUILD_STR(s)=#s" \
|
||||
shell/hush.c \
|
||||
shell/match.c \
|
||||
shell/math.c \
|
||||
shell/random.c \
|
||||
shell/shell_common.c \
|
||||
coreutils/echo.c \
|
||||
coreutils/test.c \
|
||||
coreutils/test_ptr_hack.c \
|
||||
libbb/xfuncs_printf.c \
|
||||
libbb/xfuncs.c \
|
||||
libbb/xgetcwd.c \
|
||||
libbb/getopt32.c \
|
||||
libbb/perror_msg.c \
|
||||
libbb/xatonum.c \
|
||||
libbb/u_signal_names.c \
|
||||
libbb/ptr_to_globals.c \
|
||||
libbb/default_error_retval.c \
|
||||
libbb/xfunc_die.c \
|
||||
libbb/safe_strncpy.c \
|
||||
libbb/lineedit.c \
|
||||
libbb/lineedit_ptr_hack.c \
|
||||
libbb/platform.c \
|
||||
libbb/endofname.c \
|
||||
libbb/signals.c \
|
||||
libbb/skip_whitespace.c \
|
||||
libbb/wfopen.c \
|
||||
libbb/verror_msg.c \
|
||||
libbb/bb_strtonum.c \
|
||||
libbb/time.c \
|
||||
libbb/printable_string.c \
|
||||
libbb/full_write.c \
|
||||
libbb/bb_qsort.c \
|
||||
libbb/xrealloc_vector.c \
|
||||
libbb/copyfd.c \
|
||||
libbb/read_key.c \
|
||||
libbb/unicode.c \
|
||||
libbb/safe_write.c \
|
||||
libbb/read.c \
|
||||
libbb/safe_gethostname.c \
|
||||
libbb/get_line_from_file.c \
|
||||
libbb/concat_path_file.c \
|
||||
libbb/last_char_is.c \
|
||||
libbb/safe_poll.c \
|
||||
libbb/process_escape_sequence.c \
|
||||
libbb/compare_string_array.c \
|
||||
libbb/llist.c \
|
||||
libbb/parse_mode.c \
|
||||
libbb/messages.c \
|
||||
libbb/appletlib.c \
|
||||
libbb/get_last_path_component.c \
|
||||
libbb/mempcpy.c
|
||||
|
@ -1,925 +0,0 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Busybox version: 1.16.0
|
||||
# Wed Jan 27 21:01:26 2010
|
||||
#
|
||||
CONFIG_HAVE_DOT_CONFIG=y
|
||||
|
||||
#
|
||||
# Busybox Settings
|
||||
#
|
||||
|
||||
#
|
||||
# General Configuration
|
||||
#
|
||||
CONFIG_DESKTOP=y
|
||||
CONFIG_EXTRA_COMPAT=y
|
||||
CONFIG_INCLUDE_SUSv2=y
|
||||
# CONFIG_USE_PORTABLE_CODE is not set
|
||||
CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
|
||||
# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
|
||||
# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
|
||||
CONFIG_SHOW_USAGE=y
|
||||
CONFIG_FEATURE_VERBOSE_USAGE=y
|
||||
CONFIG_FEATURE_COMPRESS_USAGE=y
|
||||
CONFIG_FEATURE_INSTALLER=y
|
||||
# CONFIG_LOCALE_SUPPORT is not set
|
||||
# CONFIG_UNICODE_SUPPORT is not set
|
||||
# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
|
||||
CONFIG_LONG_OPTS=y
|
||||
CONFIG_FEATURE_DEVPTS=y
|
||||
# CONFIG_FEATURE_CLEAN_UP is not set
|
||||
CONFIG_FEATURE_PIDFILE=y
|
||||
CONFIG_FEATURE_SUID=y
|
||||
CONFIG_FEATURE_SUID_CONFIG=y
|
||||
CONFIG_FEATURE_SUID_CONFIG_QUIET=y
|
||||
CONFIG_SELINUX=y
|
||||
CONFIG_FEATURE_PREFER_APPLETS=y
|
||||
CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
|
||||
CONFIG_FEATURE_SYSLOG=y
|
||||
CONFIG_FEATURE_HAVE_RPC=y
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
# CONFIG_STATIC is not set
|
||||
# CONFIG_PIE is not set
|
||||
CONFIG_NOMMU=y
|
||||
# CONFIG_BUILD_LIBBUSYBOX is not set
|
||||
# CONFIG_FEATURE_INDIVIDUAL is not set
|
||||
# CONFIG_FEATURE_SHARED_BUSYBOX is not set
|
||||
CONFIG_LFS=y
|
||||
CONFIG_CROSS_COMPILER_PREFIX=""
|
||||
CONFIG_EXTRA_CFLAGS=""
|
||||
|
||||
#
|
||||
# Debugging Options
|
||||
#
|
||||
# CONFIG_DEBUG is not set
|
||||
# CONFIG_DEBUG_PESSIMIZE is not set
|
||||
# CONFIG_WERROR is not set
|
||||
CONFIG_NO_DEBUG_LIB=y
|
||||
# CONFIG_DMALLOC is not set
|
||||
# CONFIG_EFENCE is not set
|
||||
|
||||
#
|
||||
# Installation Options
|
||||
#
|
||||
# CONFIG_INSTALL_NO_USR is not set
|
||||
CONFIG_INSTALL_APPLET_SYMLINKS=y
|
||||
# CONFIG_INSTALL_APPLET_HARDLINKS is not set
|
||||
# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
|
||||
# CONFIG_INSTALL_APPLET_DONT is not set
|
||||
# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
|
||||
# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
|
||||
# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
|
||||
CONFIG_PREFIX="./_install"
|
||||
|
||||
#
|
||||
# Busybox Library Tuning
|
||||
#
|
||||
CONFIG_PASSWORD_MINLEN=6
|
||||
CONFIG_MD5_SMALL=1
|
||||
CONFIG_FEATURE_FAST_TOP=y
|
||||
CONFIG_FEATURE_ETC_NETWORKS=y
|
||||
CONFIG_FEATURE_EDITING=y
|
||||
CONFIG_FEATURE_EDITING_MAX_LEN=1024
|
||||
CONFIG_FEATURE_EDITING_VI=y
|
||||
CONFIG_FEATURE_EDITING_HISTORY=15
|
||||
# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
|
||||
CONFIG_FEATURE_TAB_COMPLETION=y
|
||||
CONFIG_FEATURE_USERNAME_COMPLETION=y
|
||||
CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
|
||||
CONFIG_FEATURE_EDITING_ASK_TERMINAL=y
|
||||
CONFIG_FEATURE_NON_POSIX_CP=y
|
||||
CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y
|
||||
CONFIG_FEATURE_COPYBUF_KB=4
|
||||
CONFIG_MONOTONIC_SYSCALL=y
|
||||
CONFIG_IOCTL_HEX2STR_ERROR=y
|
||||
CONFIG_FEATURE_HWIB=y
|
||||
|
||||
#
|
||||
# Applets
|
||||
#
|
||||
|
||||
#
|
||||
# Archival Utilities
|
||||
#
|
||||
CONFIG_FEATURE_SEAMLESS_LZMA=y
|
||||
CONFIG_FEATURE_SEAMLESS_BZ2=y
|
||||
CONFIG_FEATURE_SEAMLESS_GZ=y
|
||||
CONFIG_FEATURE_SEAMLESS_Z=y
|
||||
CONFIG_AR=y
|
||||
CONFIG_FEATURE_AR_LONG_FILENAMES=y
|
||||
CONFIG_BUNZIP2=y
|
||||
CONFIG_BZIP2=y
|
||||
CONFIG_CPIO=y
|
||||
CONFIG_FEATURE_CPIO_O=y
|
||||
CONFIG_FEATURE_CPIO_P=y
|
||||
CONFIG_DPKG=y
|
||||
CONFIG_DPKG_DEB=y
|
||||
CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY=y
|
||||
CONFIG_GUNZIP=y
|
||||
CONFIG_GZIP=y
|
||||
CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
|
||||
CONFIG_LZOP=y
|
||||
CONFIG_LZOP_COMPR_HIGH=y
|
||||
CONFIG_RPM2CPIO=y
|
||||
CONFIG_RPM=y
|
||||
CONFIG_TAR=y
|
||||
CONFIG_FEATURE_TAR_CREATE=y
|
||||
CONFIG_FEATURE_TAR_AUTODETECT=y
|
||||
CONFIG_FEATURE_TAR_FROM=y
|
||||
CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
|
||||
CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
|
||||
CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
|
||||
CONFIG_FEATURE_TAR_LONG_OPTIONS=y
|
||||
CONFIG_FEATURE_TAR_UNAME_GNAME=y
|
||||
CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
|
||||
CONFIG_UNCOMPRESS=y
|
||||
CONFIG_UNLZMA=y
|
||||
CONFIG_FEATURE_LZMA_FAST=y
|
||||
CONFIG_UNZIP=y
|
||||
|
||||
#
|
||||
# Coreutils
|
||||
#
|
||||
CONFIG_BASENAME=y
|
||||
CONFIG_CAL=y
|
||||
CONFIG_CAT=y
|
||||
CONFIG_CATV=y
|
||||
CONFIG_CHGRP=y
|
||||
CONFIG_CHMOD=y
|
||||
CONFIG_CHOWN=y
|
||||
CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y
|
||||
CONFIG_CHROOT=y
|
||||
CONFIG_CKSUM=y
|
||||
CONFIG_COMM=y
|
||||
CONFIG_CP=y
|
||||
CONFIG_FEATURE_CP_LONG_OPTIONS=y
|
||||
CONFIG_CUT=y
|
||||
CONFIG_DATE=y
|
||||
CONFIG_FEATURE_DATE_ISOFMT=y
|
||||
CONFIG_FEATURE_DATE_COMPAT=y
|
||||
CONFIG_DD=y
|
||||
CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
|
||||
CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
|
||||
CONFIG_FEATURE_DD_IBS_OBS=y
|
||||
CONFIG_DF=y
|
||||
CONFIG_FEATURE_DF_FANCY=y
|
||||
CONFIG_DIRNAME=y
|
||||
CONFIG_DOS2UNIX=y
|
||||
CONFIG_UNIX2DOS=y
|
||||
CONFIG_DU=y
|
||||
CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
|
||||
CONFIG_ECHO=y
|
||||
CONFIG_FEATURE_FANCY_ECHO=y
|
||||
CONFIG_ENV=y
|
||||
CONFIG_FEATURE_ENV_LONG_OPTIONS=y
|
||||
CONFIG_EXPAND=y
|
||||
CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
|
||||
CONFIG_EXPR=y
|
||||
CONFIG_EXPR_MATH_SUPPORT_64=y
|
||||
CONFIG_FALSE=y
|
||||
CONFIG_FOLD=y
|
||||
CONFIG_FSYNC=y
|
||||
CONFIG_HEAD=y
|
||||
CONFIG_FEATURE_FANCY_HEAD=y
|
||||
CONFIG_HOSTID=y
|
||||
CONFIG_ID=y
|
||||
CONFIG_INSTALL=y
|
||||
CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
|
||||
CONFIG_LN=y
|
||||
CONFIG_LOGNAME=y
|
||||
CONFIG_LS=y
|
||||
CONFIG_FEATURE_LS_FILETYPES=y
|
||||
CONFIG_FEATURE_LS_FOLLOWLINKS=y
|
||||
CONFIG_FEATURE_LS_RECURSIVE=y
|
||||
CONFIG_FEATURE_LS_SORTFILES=y
|
||||
CONFIG_FEATURE_LS_TIMESTAMPS=y
|
||||
CONFIG_FEATURE_LS_USERNAME=y
|
||||
CONFIG_FEATURE_LS_COLOR=y
|
||||
CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
|
||||
CONFIG_MD5SUM=y
|
||||
CONFIG_MKDIR=y
|
||||
CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
|
||||
CONFIG_MKFIFO=y
|
||||
CONFIG_MKNOD=y
|
||||
CONFIG_MV=y
|
||||
CONFIG_FEATURE_MV_LONG_OPTIONS=y
|
||||
CONFIG_NICE=y
|
||||
CONFIG_NOHUP=y
|
||||
CONFIG_OD=y
|
||||
CONFIG_PRINTENV=y
|
||||
CONFIG_PRINTF=y
|
||||
CONFIG_PWD=y
|
||||
CONFIG_READLINK=y
|
||||
CONFIG_FEATURE_READLINK_FOLLOW=y
|
||||
CONFIG_REALPATH=y
|
||||
CONFIG_RM=y
|
||||
CONFIG_RMDIR=y
|
||||
CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
|
||||
CONFIG_SEQ=y
|
||||
CONFIG_SHA1SUM=y
|
||||
CONFIG_SHA256SUM=y
|
||||
CONFIG_SHA512SUM=y
|
||||
CONFIG_SLEEP=y
|
||||
CONFIG_FEATURE_FANCY_SLEEP=y
|
||||
CONFIG_FEATURE_FLOAT_SLEEP=y
|
||||
CONFIG_SORT=y
|
||||
CONFIG_FEATURE_SORT_BIG=y
|
||||
CONFIG_SPLIT=y
|
||||
CONFIG_FEATURE_SPLIT_FANCY=y
|
||||
CONFIG_STAT=y
|
||||
CONFIG_FEATURE_STAT_FORMAT=y
|
||||
CONFIG_STTY=y
|
||||
CONFIG_SUM=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_TAC=y
|
||||
CONFIG_TAIL=y
|
||||
CONFIG_FEATURE_FANCY_TAIL=y
|
||||
CONFIG_TEE=y
|
||||
CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
|
||||
CONFIG_TEST=y
|
||||
CONFIG_FEATURE_TEST_64=y
|
||||
CONFIG_TOUCH=y
|
||||
CONFIG_TR=y
|
||||
CONFIG_FEATURE_TR_CLASSES=y
|
||||
CONFIG_FEATURE_TR_EQUIV=y
|
||||
CONFIG_TRUE=y
|
||||
CONFIG_TTY=y
|
||||
CONFIG_UNAME=y
|
||||
CONFIG_UNEXPAND=y
|
||||
CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
|
||||
CONFIG_UNIQ=y
|
||||
CONFIG_USLEEP=y
|
||||
CONFIG_UUDECODE=y
|
||||
CONFIG_UUENCODE=y
|
||||
CONFIG_WC=y
|
||||
CONFIG_FEATURE_WC_LARGE=y
|
||||
CONFIG_WHO=y
|
||||
CONFIG_WHOAMI=y
|
||||
CONFIG_YES=y
|
||||
|
||||
#
|
||||
# Common options for cp and mv
|
||||
#
|
||||
CONFIG_FEATURE_PRESERVE_HARDLINKS=y
|
||||
|
||||
#
|
||||
# Common options for ls, more and telnet
|
||||
#
|
||||
CONFIG_FEATURE_AUTOWIDTH=y
|
||||
|
||||
#
|
||||
# Common options for df, du, ls
|
||||
#
|
||||
CONFIG_FEATURE_HUMAN_READABLE=y
|
||||
|
||||
#
|
||||
# Common options for md5sum, sha1sum, sha256sum, sha512sum
|
||||
#
|
||||
CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
|
||||
|
||||
#
|
||||
# Console Utilities
|
||||
#
|
||||
CONFIG_CHVT=y
|
||||
CONFIG_CLEAR=y
|
||||
CONFIG_DEALLOCVT=y
|
||||
CONFIG_DUMPKMAP=y
|
||||
CONFIG_KBD_MODE=y
|
||||
CONFIG_LOADFONT=y
|
||||
CONFIG_LOADKMAP=y
|
||||
CONFIG_OPENVT=y
|
||||
CONFIG_RESET=y
|
||||
CONFIG_RESIZE=y
|
||||
CONFIG_FEATURE_RESIZE_PRINT=y
|
||||
CONFIG_SETCONSOLE=y
|
||||
CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y
|
||||
CONFIG_SETFONT=y
|
||||
CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y
|
||||
CONFIG_DEFAULT_SETFONT_DIR=""
|
||||
CONFIG_SETKEYCODES=y
|
||||
CONFIG_SETLOGCONS=y
|
||||
CONFIG_SHOWKEY=y
|
||||
|
||||
#
|
||||
# Debian Utilities
|
||||
#
|
||||
CONFIG_MKTEMP=y
|
||||
CONFIG_PIPE_PROGRESS=y
|
||||
CONFIG_RUN_PARTS=y
|
||||
CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y
|
||||
CONFIG_FEATURE_RUN_PARTS_FANCY=y
|
||||
CONFIG_START_STOP_DAEMON=y
|
||||
CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
|
||||
CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y
|
||||
CONFIG_WHICH=y
|
||||
|
||||
#
|
||||
# Editors
|
||||
#
|
||||
CONFIG_AWK=y
|
||||
CONFIG_FEATURE_AWK_LIBM=y
|
||||
CONFIG_CMP=y
|
||||
CONFIG_DIFF=y
|
||||
CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
|
||||
CONFIG_FEATURE_DIFF_DIR=y
|
||||
CONFIG_ED=y
|
||||
CONFIG_PATCH=y
|
||||
CONFIG_SED=y
|
||||
CONFIG_VI=y
|
||||
CONFIG_FEATURE_VI_MAX_LEN=4096
|
||||
CONFIG_FEATURE_VI_8BIT=y
|
||||
CONFIG_FEATURE_VI_COLON=y
|
||||
CONFIG_FEATURE_VI_YANKMARK=y
|
||||
CONFIG_FEATURE_VI_SEARCH=y
|
||||
CONFIG_FEATURE_VI_USE_SIGNALS=y
|
||||
CONFIG_FEATURE_VI_DOT_CMD=y
|
||||
CONFIG_FEATURE_VI_READONLY=y
|
||||
CONFIG_FEATURE_VI_SETOPTS=y
|
||||
CONFIG_FEATURE_VI_SET=y
|
||||
CONFIG_FEATURE_VI_WIN_RESIZE=y
|
||||
CONFIG_FEATURE_ALLOW_EXEC=y
|
||||
|
||||
#
|
||||
# Finding Utilities
|
||||
#
|
||||
CONFIG_FIND=y
|
||||
CONFIG_FEATURE_FIND_PRINT0=y
|
||||
CONFIG_FEATURE_FIND_MTIME=y
|
||||
CONFIG_FEATURE_FIND_MMIN=y
|
||||
CONFIG_FEATURE_FIND_PERM=y
|
||||
CONFIG_FEATURE_FIND_TYPE=y
|
||||
CONFIG_FEATURE_FIND_XDEV=y
|
||||
CONFIG_FEATURE_FIND_MAXDEPTH=y
|
||||
CONFIG_FEATURE_FIND_NEWER=y
|
||||
CONFIG_FEATURE_FIND_INUM=y
|
||||
CONFIG_FEATURE_FIND_EXEC=y
|
||||
CONFIG_FEATURE_FIND_USER=y
|
||||
CONFIG_FEATURE_FIND_GROUP=y
|
||||
CONFIG_FEATURE_FIND_NOT=y
|
||||
CONFIG_FEATURE_FIND_DEPTH=y
|
||||
CONFIG_FEATURE_FIND_PAREN=y
|
||||
CONFIG_FEATURE_FIND_SIZE=y
|
||||
CONFIG_FEATURE_FIND_PRUNE=y
|
||||
CONFIG_FEATURE_FIND_DELETE=y
|
||||
CONFIG_FEATURE_FIND_PATH=y
|
||||
CONFIG_FEATURE_FIND_REGEX=y
|
||||
CONFIG_FEATURE_FIND_CONTEXT=y
|
||||
CONFIG_FEATURE_FIND_LINKS=y
|
||||
CONFIG_GREP=y
|
||||
CONFIG_FEATURE_GREP_EGREP_ALIAS=y
|
||||
CONFIG_FEATURE_GREP_FGREP_ALIAS=y
|
||||
CONFIG_FEATURE_GREP_CONTEXT=y
|
||||
CONFIG_XARGS=y
|
||||
CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
|
||||
CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
|
||||
CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
|
||||
CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
|
||||
|
||||
#
|
||||
# Init Utilities
|
||||
#
|
||||
CONFIG_INIT=y
|
||||
CONFIG_FEATURE_USE_INITTAB=y
|
||||
CONFIG_FEATURE_KILL_REMOVED=y
|
||||
CONFIG_FEATURE_KILL_DELAY=1
|
||||
CONFIG_FEATURE_INIT_SCTTY=y
|
||||
CONFIG_FEATURE_INIT_SYSLOG=y
|
||||
CONFIG_FEATURE_EXTRA_QUIET=y
|
||||
CONFIG_FEATURE_INIT_COREDUMPS=y
|
||||
CONFIG_FEATURE_INITRD=y
|
||||
CONFIG_HALT=y
|
||||
# CONFIG_FEATURE_CALL_TELINIT is not set
|
||||
CONFIG_TELINIT_PATH=""
|
||||
CONFIG_MESG=y
|
||||
|
||||
#
|
||||
# Login/Password Management Utilities
|
||||
#
|
||||
CONFIG_FEATURE_SHADOWPASSWDS=y
|
||||
CONFIG_USE_BB_PWD_GRP=y
|
||||
CONFIG_USE_BB_SHADOW=y
|
||||
CONFIG_USE_BB_CRYPT=y
|
||||
CONFIG_USE_BB_CRYPT_SHA=y
|
||||
CONFIG_ADDGROUP=y
|
||||
CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y
|
||||
CONFIG_FEATURE_ADDUSER_TO_GROUP=y
|
||||
CONFIG_DELGROUP=y
|
||||
CONFIG_FEATURE_DEL_USER_FROM_GROUP=y
|
||||
CONFIG_FEATURE_CHECK_NAMES=y
|
||||
CONFIG_ADDUSER=y
|
||||
CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y
|
||||
CONFIG_FIRST_SYSTEM_ID=100
|
||||
CONFIG_LAST_SYSTEM_ID=999
|
||||
CONFIG_DELUSER=y
|
||||
CONFIG_GETTY=y
|
||||
CONFIG_FEATURE_UTMP=y
|
||||
CONFIG_FEATURE_WTMP=y
|
||||
CONFIG_LOGIN=y
|
||||
# CONFIG_PAM is not set
|
||||
CONFIG_LOGIN_SCRIPTS=y
|
||||
CONFIG_FEATURE_NOLOGIN=y
|
||||
CONFIG_FEATURE_SECURETTY=y
|
||||
CONFIG_PASSWD=y
|
||||
CONFIG_FEATURE_PASSWD_WEAK_CHECK=y
|
||||
CONFIG_CRYPTPW=y
|
||||
CONFIG_CHPASSWD=y
|
||||
CONFIG_SU=y
|
||||
CONFIG_FEATURE_SU_SYSLOG=y
|
||||
CONFIG_FEATURE_SU_CHECKS_SHELLS=y
|
||||
CONFIG_SULOGIN=y
|
||||
CONFIG_VLOCK=y
|
||||
|
||||
#
|
||||
# Linux Ext2 FS Progs
|
||||
#
|
||||
CONFIG_CHATTR=y
|
||||
CONFIG_FSCK=y
|
||||
CONFIG_LSATTR=y
|
||||
|
||||
#
|
||||
# Linux Module Utilities
|
||||
#
|
||||
CONFIG_MODPROBE_SMALL=y
|
||||
CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y
|
||||
CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y
|
||||
# CONFIG_INSMOD is not set
|
||||
# CONFIG_RMMOD is not set
|
||||
# CONFIG_LSMOD is not set
|
||||
# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
|
||||
# CONFIG_MODPROBE is not set
|
||||
# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
|
||||
# CONFIG_DEPMOD is not set
|
||||
|
||||
#
|
||||
# Options common to multiple modutils
|
||||
#
|
||||
# CONFIG_FEATURE_2_4_MODULES is not set
|
||||
CONFIG_FEATURE_INSMOD_TRY_MMAP=y
|
||||
# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
|
||||
# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
|
||||
# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
|
||||
# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
|
||||
# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
|
||||
# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
|
||||
# CONFIG_FEATURE_MODUTILS_ALIAS is not set
|
||||
# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
|
||||
CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
|
||||
CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
|
||||
|
||||
#
|
||||
# Linux System Utilities
|
||||
#
|
||||
# CONFIG_ACPID is not set
|
||||
# CONFIG_FEATURE_ACPID_COMPAT is not set
|
||||
CONFIG_BLKID=y
|
||||
CONFIG_DMESG=y
|
||||
CONFIG_FEATURE_DMESG_PRETTY=y
|
||||
CONFIG_FBSET=y
|
||||
CONFIG_FEATURE_FBSET_FANCY=y
|
||||
CONFIG_FEATURE_FBSET_READMODE=y
|
||||
CONFIG_FDFLUSH=y
|
||||
CONFIG_FDFORMAT=y
|
||||
CONFIG_FDISK=y
|
||||
CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
|
||||
CONFIG_FEATURE_FDISK_WRITABLE=y
|
||||
CONFIG_FEATURE_AIX_LABEL=y
|
||||
CONFIG_FEATURE_SGI_LABEL=y
|
||||
CONFIG_FEATURE_SUN_LABEL=y
|
||||
CONFIG_FEATURE_OSF_LABEL=y
|
||||
CONFIG_FEATURE_FDISK_ADVANCED=y
|
||||
CONFIG_FINDFS=y
|
||||
CONFIG_FREERAMDISK=y
|
||||
CONFIG_FSCK_MINIX=y
|
||||
CONFIG_MKFS_EXT2=y
|
||||
CONFIG_MKFS_MINIX=y
|
||||
|
||||
#
|
||||
# Minix filesystem support
|
||||
#
|
||||
CONFIG_FEATURE_MINIX2=y
|
||||
CONFIG_MKFS_REISER=y
|
||||
CONFIG_MKFS_VFAT=y
|
||||
CONFIG_GETOPT=y
|
||||
CONFIG_FEATURE_GETOPT_LONG=y
|
||||
CONFIG_HEXDUMP=y
|
||||
CONFIG_FEATURE_HEXDUMP_REVERSE=y
|
||||
CONFIG_HD=y
|
||||
CONFIG_HWCLOCK=y
|
||||
CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y
|
||||
CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y
|
||||
CONFIG_IPCRM=y
|
||||
CONFIG_IPCS=y
|
||||
CONFIG_LOSETUP=y
|
||||
CONFIG_LSPCI=y
|
||||
CONFIG_LSUSB=y
|
||||
CONFIG_MDEV=y
|
||||
CONFIG_FEATURE_MDEV_CONF=y
|
||||
CONFIG_FEATURE_MDEV_RENAME=y
|
||||
CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
|
||||
CONFIG_FEATURE_MDEV_EXEC=y
|
||||
CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
|
||||
CONFIG_MKSWAP=y
|
||||
CONFIG_FEATURE_MKSWAP_UUID=y
|
||||
CONFIG_MORE=y
|
||||
CONFIG_FEATURE_USE_TERMIOS=y
|
||||
CONFIG_VOLUMEID=y
|
||||
CONFIG_FEATURE_VOLUMEID_EXT=y
|
||||
CONFIG_FEATURE_VOLUMEID_BTRFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_REISERFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_FAT=y
|
||||
CONFIG_FEATURE_VOLUMEID_HFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_JFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_XFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_NTFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_ISO9660=y
|
||||
CONFIG_FEATURE_VOLUMEID_UDF=y
|
||||
CONFIG_FEATURE_VOLUMEID_LUKS=y
|
||||
CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
|
||||
CONFIG_FEATURE_VOLUMEID_CRAMFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_ROMFS=y
|
||||
CONFIG_FEATURE_VOLUMEID_SYSV=y
|
||||
CONFIG_FEATURE_VOLUMEID_OCFS2=y
|
||||
CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
|
||||
CONFIG_MOUNT=y
|
||||
CONFIG_FEATURE_MOUNT_FAKE=y
|
||||
CONFIG_FEATURE_MOUNT_VERBOSE=y
|
||||
CONFIG_FEATURE_MOUNT_HELPERS=y
|
||||
CONFIG_FEATURE_MOUNT_LABEL=y
|
||||
CONFIG_FEATURE_MOUNT_NFS=y
|
||||
CONFIG_FEATURE_MOUNT_CIFS=y
|
||||
CONFIG_FEATURE_MOUNT_FLAGS=y
|
||||
CONFIG_FEATURE_MOUNT_FSTAB=y
|
||||
CONFIG_PIVOT_ROOT=y
|
||||
CONFIG_RDATE=y
|
||||
CONFIG_RDEV=y
|
||||
CONFIG_READPROFILE=y
|
||||
CONFIG_RTCWAKE=y
|
||||
CONFIG_SCRIPT=y
|
||||
CONFIG_SCRIPTREPLAY=y
|
||||
CONFIG_SETARCH=y
|
||||
CONFIG_SWAPONOFF=y
|
||||
CONFIG_FEATURE_SWAPON_PRI=y
|
||||
CONFIG_SWITCH_ROOT=y
|
||||
CONFIG_UMOUNT=y
|
||||
CONFIG_FEATURE_UMOUNT_ALL=y
|
||||
|
||||
#
|
||||
# Common options for mount/umount
|
||||
#
|
||||
CONFIG_FEATURE_MOUNT_LOOP=y
|
||||
# CONFIG_FEATURE_MTAB_SUPPORT is not set
|
||||
|
||||
#
|
||||
# Miscellaneous Utilities
|
||||
#
|
||||
CONFIG_ADJTIMEX=y
|
||||
CONFIG_BBCONFIG=y
|
||||
CONFIG_BEEP=y
|
||||
CONFIG_FEATURE_BEEP_FREQ=4000
|
||||
CONFIG_FEATURE_BEEP_LENGTH_MS=30
|
||||
CONFIG_CHAT=y
|
||||
CONFIG_FEATURE_CHAT_NOFAIL=y
|
||||
CONFIG_FEATURE_CHAT_TTY_HIFI=y
|
||||
CONFIG_FEATURE_CHAT_IMPLICIT_CR=y
|
||||
CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y
|
||||
CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
|
||||
CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
|
||||
CONFIG_FEATURE_CHAT_CLR_ABORT=y
|
||||
CONFIG_CHRT=y
|
||||
CONFIG_CROND=y
|
||||
CONFIG_FEATURE_CROND_D=y
|
||||
CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
|
||||
CONFIG_FEATURE_CROND_DIR="/var/spool/cron"
|
||||
CONFIG_CRONTAB=y
|
||||
CONFIG_DC=y
|
||||
CONFIG_FEATURE_DC_LIBM=y
|
||||
# CONFIG_DEVFSD is not set
|
||||
# CONFIG_DEVFSD_MODLOAD is not set
|
||||
# CONFIG_DEVFSD_FG_NP is not set
|
||||
# CONFIG_DEVFSD_VERBOSE is not set
|
||||
# CONFIG_FEATURE_DEVFS is not set
|
||||
CONFIG_DEVMEM=y
|
||||
CONFIG_EJECT=y
|
||||
CONFIG_FEATURE_EJECT_SCSI=y
|
||||
CONFIG_FBSPLASH=y
|
||||
CONFIG_FLASHCP=y
|
||||
# CONFIG_FLASH_LOCK is not set
|
||||
# CONFIG_FLASH_UNLOCK is not set
|
||||
# CONFIG_FLASH_ERASEALL is not set
|
||||
CONFIG_IONICE=y
|
||||
CONFIG_INOTIFYD=y
|
||||
CONFIG_LAST=y
|
||||
CONFIG_FEATURE_LAST_SMALL=y
|
||||
# CONFIG_FEATURE_LAST_FANCY is not set
|
||||
CONFIG_LESS=y
|
||||
CONFIG_FEATURE_LESS_MAXLINES=9999999
|
||||
CONFIG_FEATURE_LESS_BRACKETS=y
|
||||
CONFIG_FEATURE_LESS_FLAGS=y
|
||||
CONFIG_FEATURE_LESS_MARKS=y
|
||||
CONFIG_FEATURE_LESS_REGEXP=y
|
||||
CONFIG_FEATURE_LESS_WINCH=y
|
||||
CONFIG_FEATURE_LESS_DASHCMD=y
|
||||
CONFIG_FEATURE_LESS_LINENUMS=y
|
||||
CONFIG_HDPARM=y
|
||||
CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
|
||||
CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
|
||||
CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y
|
||||
CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y
|
||||
CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y
|
||||
CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y
|
||||
CONFIG_MAKEDEVS=y
|
||||
# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
|
||||
CONFIG_FEATURE_MAKEDEVS_TABLE=y
|
||||
CONFIG_MAN=y
|
||||
CONFIG_MICROCOM=y
|
||||
CONFIG_MOUNTPOINT=y
|
||||
CONFIG_MT=y
|
||||
CONFIG_RAIDAUTORUN=y
|
||||
CONFIG_READAHEAD=y
|
||||
CONFIG_RUNLEVEL=y
|
||||
CONFIG_RX=y
|
||||
CONFIG_SETSID=y
|
||||
CONFIG_STRINGS=y
|
||||
CONFIG_TASKSET=y
|
||||
CONFIG_FEATURE_TASKSET_FANCY=y
|
||||
CONFIG_TIME=y
|
||||
CONFIG_TIMEOUT=y
|
||||
CONFIG_TTYSIZE=y
|
||||
CONFIG_VOLNAME=y
|
||||
CONFIG_WALL=y
|
||||
CONFIG_WATCHDOG=y
|
||||
|
||||
#
|
||||
# Networking Utilities
|
||||
#
|
||||
CONFIG_FEATURE_IPV6=y
|
||||
CONFIG_FEATURE_UNIX_LOCAL=y
|
||||
CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
|
||||
CONFIG_VERBOSE_RESOLUTION_ERRORS=y
|
||||
CONFIG_ARP=y
|
||||
CONFIG_ARPING=y
|
||||
CONFIG_BRCTL=y
|
||||
CONFIG_FEATURE_BRCTL_FANCY=y
|
||||
CONFIG_FEATURE_BRCTL_SHOW=y
|
||||
CONFIG_DNSD=y
|
||||
CONFIG_ETHER_WAKE=y
|
||||
CONFIG_FAKEIDENTD=y
|
||||
CONFIG_FTPD=y
|
||||
CONFIG_FEATURE_FTP_WRITE=y
|
||||
CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y
|
||||
CONFIG_FTPGET=y
|
||||
CONFIG_FTPPUT=y
|
||||
CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
|
||||
CONFIG_HOSTNAME=y
|
||||
CONFIG_HTTPD=y
|
||||
CONFIG_FEATURE_HTTPD_RANGES=y
|
||||
CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
|
||||
CONFIG_FEATURE_HTTPD_SETUID=y
|
||||
CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
|
||||
CONFIG_FEATURE_HTTPD_AUTH_MD5=y
|
||||
CONFIG_FEATURE_HTTPD_CGI=y
|
||||
CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
|
||||
CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
|
||||
CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
|
||||
CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
|
||||
CONFIG_FEATURE_HTTPD_PROXY=y
|
||||
CONFIG_IFCONFIG=y
|
||||
CONFIG_FEATURE_IFCONFIG_STATUS=y
|
||||
CONFIG_FEATURE_IFCONFIG_SLIP=y
|
||||
CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
|
||||
CONFIG_FEATURE_IFCONFIG_HW=y
|
||||
CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
|
||||
CONFIG_IFENSLAVE=y
|
||||
CONFIG_IFPLUGD=y
|
||||
CONFIG_IFUPDOWN=y
|
||||
CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
|
||||
CONFIG_FEATURE_IFUPDOWN_IP=y
|
||||
CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
|
||||
# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
|
||||
CONFIG_FEATURE_IFUPDOWN_IPV4=y
|
||||
CONFIG_FEATURE_IFUPDOWN_IPV6=y
|
||||
CONFIG_FEATURE_IFUPDOWN_MAPPING=y
|
||||
CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
|
||||
CONFIG_INETD=y
|
||||
CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y
|
||||
CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y
|
||||
CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y
|
||||
CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y
|
||||
CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y
|
||||
CONFIG_FEATURE_INETD_RPC=y
|
||||
CONFIG_IP=y
|
||||
CONFIG_FEATURE_IP_ADDRESS=y
|
||||
CONFIG_FEATURE_IP_LINK=y
|
||||
CONFIG_FEATURE_IP_ROUTE=y
|
||||
CONFIG_FEATURE_IP_TUNNEL=y
|
||||
CONFIG_FEATURE_IP_RULE=y
|
||||
CONFIG_FEATURE_IP_SHORT_FORMS=y
|
||||
CONFIG_FEATURE_IP_RARE_PROTOCOLS=y
|
||||
CONFIG_IPADDR=y
|
||||
CONFIG_IPLINK=y
|
||||
CONFIG_IPROUTE=y
|
||||
CONFIG_IPTUNNEL=y
|
||||
CONFIG_IPRULE=y
|
||||
CONFIG_IPCALC=y
|
||||
CONFIG_FEATURE_IPCALC_FANCY=y
|
||||
CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
|
||||
CONFIG_NAMEIF=y
|
||||
CONFIG_FEATURE_NAMEIF_EXTENDED=y
|
||||
CONFIG_NC=y
|
||||
CONFIG_NC_SERVER=y
|
||||
CONFIG_NC_EXTRA=y
|
||||
CONFIG_NETSTAT=y
|
||||
CONFIG_FEATURE_NETSTAT_WIDE=y
|
||||
CONFIG_FEATURE_NETSTAT_PRG=y
|
||||
CONFIG_NSLOOKUP=y
|
||||
CONFIG_NTPD=y
|
||||
CONFIG_FEATURE_NTPD_SERVER=y
|
||||
CONFIG_PING=y
|
||||
CONFIG_PING6=y
|
||||
CONFIG_FEATURE_FANCY_PING=y
|
||||
CONFIG_PSCAN=y
|
||||
CONFIG_ROUTE=y
|
||||
CONFIG_SLATTACH=y
|
||||
CONFIG_TELNET=y
|
||||
CONFIG_FEATURE_TELNET_TTYPE=y
|
||||
CONFIG_FEATURE_TELNET_AUTOLOGIN=y
|
||||
CONFIG_TELNETD=y
|
||||
CONFIG_FEATURE_TELNETD_STANDALONE=y
|
||||
CONFIG_FEATURE_TELNETD_INETD_WAIT=y
|
||||
CONFIG_TFTP=y
|
||||
CONFIG_TFTPD=y
|
||||
CONFIG_FEATURE_TFTP_GET=y
|
||||
CONFIG_FEATURE_TFTP_PUT=y
|
||||
CONFIG_FEATURE_TFTP_BLOCKSIZE=y
|
||||
CONFIG_FEATURE_TFTP_PROGRESS_BAR=y
|
||||
CONFIG_TFTP_DEBUG=y
|
||||
CONFIG_TRACEROUTE=y
|
||||
CONFIG_TRACEROUTE6=y
|
||||
CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
|
||||
CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y
|
||||
CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y
|
||||
CONFIG_UDHCPD=y
|
||||
CONFIG_DHCPRELAY=y
|
||||
CONFIG_DUMPLEASES=y
|
||||
CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y
|
||||
CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases"
|
||||
CONFIG_UDHCPC=y
|
||||
CONFIG_FEATURE_UDHCPC_ARPING=y
|
||||
CONFIG_FEATURE_UDHCP_PORT=y
|
||||
CONFIG_UDHCP_DEBUG=9
|
||||
CONFIG_FEATURE_UDHCP_RFC3397=y
|
||||
CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
|
||||
CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
|
||||
CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n"
|
||||
CONFIG_VCONFIG=y
|
||||
CONFIG_WGET=y
|
||||
CONFIG_FEATURE_WGET_STATUSBAR=y
|
||||
CONFIG_FEATURE_WGET_AUTHENTICATION=y
|
||||
CONFIG_FEATURE_WGET_LONG_OPTIONS=y
|
||||
CONFIG_ZCIP=y
|
||||
CONFIG_TCPSVD=y
|
||||
CONFIG_TUNCTL=y
|
||||
CONFIG_FEATURE_TUNCTL_UG=y
|
||||
CONFIG_UDPSVD=y
|
||||
|
||||
#
|
||||
# Print Utilities
|
||||
#
|
||||
CONFIG_LPD=y
|
||||
CONFIG_LPR=y
|
||||
CONFIG_LPQ=y
|
||||
|
||||
#
|
||||
# Mail Utilities
|
||||
#
|
||||
CONFIG_MAKEMIME=y
|
||||
CONFIG_FEATURE_MIME_CHARSET="us-ascii"
|
||||
CONFIG_POPMAILDIR=y
|
||||
CONFIG_FEATURE_POPMAILDIR_DELIVERY=y
|
||||
CONFIG_REFORMIME=y
|
||||
CONFIG_FEATURE_REFORMIME_COMPAT=y
|
||||
CONFIG_SENDMAIL=y
|
||||
|
||||
#
|
||||
# Process Utilities
|
||||
#
|
||||
CONFIG_FREE=y
|
||||
CONFIG_FUSER=y
|
||||
CONFIG_KILL=y
|
||||
CONFIG_KILLALL=y
|
||||
CONFIG_KILLALL5=y
|
||||
CONFIG_NMETER=y
|
||||
CONFIG_PGREP=y
|
||||
CONFIG_PIDOF=y
|
||||
CONFIG_FEATURE_PIDOF_SINGLE=y
|
||||
CONFIG_FEATURE_PIDOF_OMIT=y
|
||||
CONFIG_PKILL=y
|
||||
CONFIG_PS=y
|
||||
CONFIG_FEATURE_PS_WIDE=y
|
||||
CONFIG_FEATURE_PS_TIME=y
|
||||
CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
|
||||
CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS=y
|
||||
CONFIG_RENICE=y
|
||||
CONFIG_BB_SYSCTL=y
|
||||
CONFIG_TOP=y
|
||||
CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
|
||||
CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
|
||||
CONFIG_FEATURE_TOP_SMP_CPU=y
|
||||
CONFIG_FEATURE_TOP_DECIMALS=y
|
||||
CONFIG_FEATURE_TOP_SMP_PROCESS=y
|
||||
CONFIG_FEATURE_TOPMEM=y
|
||||
CONFIG_FEATURE_SHOW_THREADS=y
|
||||
CONFIG_UPTIME=y
|
||||
CONFIG_WATCH=y
|
||||
|
||||
#
|
||||
# Runit Utilities
|
||||
#
|
||||
CONFIG_RUNSV=y
|
||||
CONFIG_RUNSVDIR=y
|
||||
CONFIG_FEATURE_RUNSVDIR_LOG=y
|
||||
CONFIG_SV=y
|
||||
CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service"
|
||||
CONFIG_SVLOGD=y
|
||||
CONFIG_CHPST=y
|
||||
CONFIG_SETUIDGID=y
|
||||
CONFIG_ENVUIDGID=y
|
||||
CONFIG_ENVDIR=y
|
||||
CONFIG_SOFTLIMIT=y
|
||||
|
||||
#
|
||||
# SELinux Utilities
|
||||
#
|
||||
CONFIG_CHCON=y
|
||||
CONFIG_FEATURE_CHCON_LONG_OPTIONS=y
|
||||
CONFIG_GETENFORCE=y
|
||||
CONFIG_GETSEBOOL=y
|
||||
CONFIG_LOAD_POLICY=y
|
||||
CONFIG_MATCHPATHCON=y
|
||||
CONFIG_RESTORECON=y
|
||||
CONFIG_RUNCON=y
|
||||
CONFIG_FEATURE_RUNCON_LONG_OPTIONS=y
|
||||
CONFIG_SELINUXENABLED=y
|
||||
CONFIG_SETENFORCE=y
|
||||
CONFIG_SETFILES=y
|
||||
CONFIG_FEATURE_SETFILES_CHECK_OPTION=y
|
||||
CONFIG_SETSEBOOL=y
|
||||
CONFIG_SESTATUS=y
|
||||
|
||||
#
|
||||
# Shells
|
||||
#
|
||||
# CONFIG_FEATURE_SH_IS_ASH is not set
|
||||
CONFIG_FEATURE_SH_IS_HUSH=y
|
||||
# CONFIG_FEATURE_SH_IS_NONE is not set
|
||||
# CONFIG_ASH is not set
|
||||
# CONFIG_ASH_BASH_COMPAT is not set
|
||||
# CONFIG_ASH_JOB_CONTROL is not set
|
||||
# CONFIG_ASH_ALIAS is not set
|
||||
# CONFIG_ASH_GETOPTS is not set
|
||||
# CONFIG_ASH_BUILTIN_ECHO is not set
|
||||
# CONFIG_ASH_BUILTIN_PRINTF is not set
|
||||
# CONFIG_ASH_BUILTIN_TEST is not set
|
||||
# CONFIG_ASH_CMDCMD is not set
|
||||
# CONFIG_ASH_MAIL is not set
|
||||
# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
|
||||
# CONFIG_ASH_RANDOM_SUPPORT is not set
|
||||
# CONFIG_ASH_EXPAND_PRMT is not set
|
||||
CONFIG_HUSH=y
|
||||
CONFIG_HUSH_BASH_COMPAT=y
|
||||
CONFIG_HUSH_HELP=y
|
||||
CONFIG_HUSH_INTERACTIVE=y
|
||||
CONFIG_HUSH_JOB=y
|
||||
CONFIG_HUSH_TICK=y
|
||||
CONFIG_HUSH_IF=y
|
||||
CONFIG_HUSH_LOOPS=y
|
||||
CONFIG_HUSH_CASE=y
|
||||
CONFIG_HUSH_FUNCTIONS=y
|
||||
CONFIG_HUSH_LOCAL=y
|
||||
CONFIG_HUSH_EXPORT_N=y
|
||||
CONFIG_HUSH_RANDOM_SUPPORT=y
|
||||
CONFIG_MSH=y
|
||||
CONFIG_SH_MATH_SUPPORT=y
|
||||
CONFIG_SH_MATH_SUPPORT_64=y
|
||||
CONFIG_FEATURE_SH_EXTRA_QUIET=y
|
||||
CONFIG_FEATURE_SH_STANDALONE=y
|
||||
CONFIG_FEATURE_SH_NOFORK=y
|
||||
CONFIG_CTTYHACK=y
|
||||
|
||||
#
|
||||
# System Logging Utilities
|
||||
#
|
||||
CONFIG_SYSLOGD=y
|
||||
CONFIG_FEATURE_ROTATE_LOGFILE=y
|
||||
CONFIG_FEATURE_REMOTE_LOG=y
|
||||
CONFIG_FEATURE_SYSLOGD_DUP=y
|
||||
CONFIG_FEATURE_IPC_SYSLOG=y
|
||||
CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16
|
||||
CONFIG_LOGREAD=y
|
||||
CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
|
||||
CONFIG_KLOGD=y
|
||||
CONFIG_LOGGER=y
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user