Adding upstream version 0.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
7b75053a36
commit
481ef88a11
43 changed files with 4518 additions and 0 deletions
AUTHORSCOPYINGChangeLogINSTALLMakefile.inNEWSREADMEarg_parser.ccarg_parser.hconfigurecreate.cc
doc
extract.cclzip.hmain.cctarlz.htestsuite
check.shdotdot1.tar.lzdotdot2.tar.lzdotdot3.tar.lzdotdot4.tar.lzdotdot5.tar.lzeof.tar.lztest.txttest.txt.lztest.txt.tartest.txt.tar.lztest3.tartest3.tar.lztest3_bad1.tartest3_bad1.tar.lztest3_bad2.tartest3_bad2.tar.lztest3_bad3.tartest3_bad3.tar.lztest3_bad4.tartest3_bad4.tar.lztest3_bad5.tartest3_bad5.tar.lztest3_bad6.tar.lztest3a.tar.lz
1
AUTHORS
Normal file
1
AUTHORS
Normal file
|
@ -0,0 +1 @@
|
|||
Tarlz was written by Antonio Diaz Diaz.
|
338
COPYING
Normal file
338
COPYING
Normal file
|
@ -0,0 +1,338 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) <year> <name of author>
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
37
ChangeLog
Normal file
37
ChangeLog
Normal file
|
@ -0,0 +1,37 @@
|
|||
2018-04-23 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.4 released.
|
||||
* Added some missing #includes.
|
||||
* main.cc: Open files in binary mode on OS2.
|
||||
|
||||
2018-03-19 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.3 released.
|
||||
* Project renamed to 'tarlz' from 'pmtar' (Poor Man's Tar).
|
||||
* Added new option '-C, --directory'.
|
||||
* Implemented lzip compression of members at archive creation.
|
||||
* Added new option '-r, --append'.
|
||||
* Added new options '--owner', '--group'.
|
||||
* Added new options '--asolid', '--dsolid', '--solid'.
|
||||
* Implemented file appending to compressed archive.
|
||||
* Implemented transparent decompression of the archive.
|
||||
* Implemented skipping over damaged (un)compressed members.
|
||||
* Implemented recursive extraction/listing of directories.
|
||||
* Implemented verbose extract/list output.
|
||||
* tarlz.texi: New file.
|
||||
|
||||
2014-01-22 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.2 released.
|
||||
* configure: Options now accept a separate argument.
|
||||
|
||||
2013-02-16 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.1 released.
|
||||
|
||||
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This file is a collection of facts, and thus it is not copyrightable,
|
||||
but just in case, you have unlimited permission to copy, distribute and
|
||||
modify it.
|
65
INSTALL
Normal file
65
INSTALL
Normal file
|
@ -0,0 +1,65 @@
|
|||
Requirements
|
||||
------------
|
||||
You will need a C++ compiler and the lzlib compression library installed.
|
||||
I use gcc 5.3.0 and 4.1.2, but the code should compile with any
|
||||
standards compliant compiler.
|
||||
Gcc is available at http://gcc.gnu.org.
|
||||
Lzlib is available at http://www.nongnu.org/lzip/lzlib.html.
|
||||
|
||||
|
||||
Procedure
|
||||
---------
|
||||
1. Unpack the archive if you have not done so already:
|
||||
|
||||
tar -xf tarlz[version].tar.lz
|
||||
or
|
||||
lzip -cd tarlz[version].tar.lz | tar -xf -
|
||||
|
||||
This creates the directory ./tarlz[version] containing the source from
|
||||
the main archive.
|
||||
|
||||
2. Change to tarlz directory and run configure.
|
||||
(Try 'configure --help' for usage instructions).
|
||||
|
||||
cd tarlz[version]
|
||||
./configure
|
||||
|
||||
3. Run make.
|
||||
|
||||
make
|
||||
|
||||
4. Optionally, type 'make check' to run the tests that come with tarlz.
|
||||
|
||||
5. Type 'make install' to install the program and any data files and
|
||||
documentation.
|
||||
|
||||
Or type 'make install-compress', which additionally compresses the
|
||||
info manual and the man page after installation. (Installing
|
||||
compressed docs may become the default in the future).
|
||||
|
||||
You can install only the program, the info manual or the man page by
|
||||
typing 'make install-bin', 'make install-info' or 'make install-man'
|
||||
respectively.
|
||||
|
||||
|
||||
Another way
|
||||
-----------
|
||||
You can also compile tarlz into a separate directory.
|
||||
To do this, you must use a version of 'make' that supports the 'VPATH'
|
||||
variable, such as GNU 'make'. 'cd' to the directory where you want the
|
||||
object files and executables to go and run the 'configure' script.
|
||||
'configure' automatically checks for the source code in '.', in '..' and
|
||||
in the directory that 'configure' is in.
|
||||
|
||||
'configure' recognizes the option '--srcdir=DIR' to control where to
|
||||
look for the sources. Usually 'configure' can determine that directory
|
||||
automatically.
|
||||
|
||||
After running 'configure', you can run 'make' and 'make install' as
|
||||
explained above.
|
||||
|
||||
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
137
Makefile.in
Normal file
137
Makefile.in
Normal file
|
@ -0,0 +1,137 @@
|
|||
|
||||
DISTNAME = $(pkgname)-$(pkgversion)
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL) -m 755
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
INSTALL_DIR = $(INSTALL) -d -m 755
|
||||
LIBS = -llz
|
||||
SHELL = /bin/sh
|
||||
CAN_RUN_INSTALLINFO = $(SHELL) -c "install-info --version" > /dev/null 2>&1
|
||||
|
||||
objs = arg_parser.o create.o extract.o main.o
|
||||
|
||||
|
||||
.PHONY : all install install-bin install-info install-man \
|
||||
install-strip install-compress install-strip-compress \
|
||||
install-bin-strip install-info-compress install-man-compress \
|
||||
uninstall uninstall-bin uninstall-info uninstall-man \
|
||||
doc info man check dist clean distclean
|
||||
|
||||
all : $(progname)
|
||||
|
||||
$(progname) : $(objs)
|
||||
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(objs) $(LIBS)
|
||||
|
||||
main.o : main.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
%.o : %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(objs) : Makefile
|
||||
arg_parser.o : arg_parser.h
|
||||
create.o : arg_parser.h lzip.h tarlz.h
|
||||
extract.o : arg_parser.h lzip.h tarlz.h
|
||||
main.o : arg_parser.h tarlz.h
|
||||
|
||||
|
||||
doc : info man
|
||||
|
||||
info : $(VPATH)/doc/$(pkgname).info
|
||||
|
||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi
|
||||
cd $(VPATH)/doc && makeinfo $(pkgname).texi
|
||||
|
||||
man : $(VPATH)/doc/$(progname).1
|
||||
|
||||
$(VPATH)/doc/$(progname).1 : $(progname)
|
||||
help2man -n 'creates tar archives with multimember lzip compression' \
|
||||
-o $@ ./$(progname)
|
||||
|
||||
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
||||
./config.status
|
||||
|
||||
check : all
|
||||
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
||||
|
||||
install : install-bin install-info install-man
|
||||
install-strip : install-bin-strip install-info install-man
|
||||
install-compress : install-bin install-info-compress install-man-compress
|
||||
install-strip-compress : install-bin-strip install-info-compress install-man-compress
|
||||
|
||||
install-bin : all
|
||||
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
||||
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
||||
|
||||
install-bin-strip : all
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install-bin
|
||||
|
||||
install-info :
|
||||
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||
fi
|
||||
|
||||
install-info-compress : install-info
|
||||
lzip -v -9 "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
|
||||
install-man :
|
||||
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
|
||||
install-man-compress : install-man
|
||||
lzip -v -9 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
|
||||
uninstall : uninstall-man uninstall-info uninstall-bin
|
||||
|
||||
uninstall-bin :
|
||||
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
||||
|
||||
uninstall-info :
|
||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||
install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||
fi
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||
|
||||
uninstall-man :
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||
|
||||
dist : doc
|
||||
ln -sf $(VPATH) $(DISTNAME)
|
||||
tar -Hustar --owner=root --group=root -cvf $(DISTNAME).tar \
|
||||
$(DISTNAME)/AUTHORS \
|
||||
$(DISTNAME)/COPYING \
|
||||
$(DISTNAME)/ChangeLog \
|
||||
$(DISTNAME)/INSTALL \
|
||||
$(DISTNAME)/Makefile.in \
|
||||
$(DISTNAME)/NEWS \
|
||||
$(DISTNAME)/README \
|
||||
$(DISTNAME)/configure \
|
||||
$(DISTNAME)/doc/$(progname).1 \
|
||||
$(DISTNAME)/doc/$(pkgname).info \
|
||||
$(DISTNAME)/doc/$(pkgname).texi \
|
||||
$(DISTNAME)/*.h \
|
||||
$(DISTNAME)/*.cc \
|
||||
$(DISTNAME)/testsuite/check.sh \
|
||||
$(DISTNAME)/testsuite/test.txt \
|
||||
$(DISTNAME)/testsuite/test.txt.tar \
|
||||
$(DISTNAME)/testsuite/test3.tar \
|
||||
$(DISTNAME)/testsuite/test3_bad[1-5].tar \
|
||||
$(DISTNAME)/testsuite/test.txt.lz \
|
||||
$(DISTNAME)/testsuite/test.txt.tar.lz \
|
||||
$(DISTNAME)/testsuite/test3.tar.lz \
|
||||
$(DISTNAME)/testsuite/test3a.tar.lz \
|
||||
$(DISTNAME)/testsuite/test3_bad[1-6].tar.lz \
|
||||
$(DISTNAME)/testsuite/dotdot[1-5].tar.lz \
|
||||
$(DISTNAME)/testsuite/eof.tar.lz
|
||||
rm -f $(DISTNAME)
|
||||
lzip -v -9 $(DISTNAME).tar
|
||||
|
||||
clean :
|
||||
-rm -f $(progname) $(objs)
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile config.status *.tar *.tar.lz
|
5
NEWS
Normal file
5
NEWS
Normal file
|
@ -0,0 +1,5 @@
|
|||
Changes in version 0.4:
|
||||
|
||||
Some missing #includes have been fixed.
|
||||
|
||||
Open files in binary mode on OS2.
|
62
README
Normal file
62
README
Normal file
|
@ -0,0 +1,62 @@
|
|||
Description
|
||||
|
||||
Tarlz is a small and simple implementation of the tar archiver. By
|
||||
default tarlz creates, lists and extracts archives in the 'ustar' format
|
||||
compressed with lzip on a per file basis. Tarlz can append files to the
|
||||
end of such compressed archives.
|
||||
|
||||
Each tar member is compressed in its own lzip member, as well as the
|
||||
end-of-file blocks. This same method works for any tar format (gnu,
|
||||
ustar, posix) and is fully backward compatible with standard tar tools
|
||||
like GNU tar, which treat the resulting multimember tar.lz archive like
|
||||
any other tar.lz archive.
|
||||
|
||||
Tarlz can create tar archives with four levels of compression
|
||||
granularity; per file, per directory, appendable solid, and solid.
|
||||
|
||||
Tarlz is intended as a showcase project for the maintainers of real tar
|
||||
programs to evaluate the format and perhaps implement it in their tools.
|
||||
|
||||
The diagram below shows the correspondence between tar members (formed
|
||||
by a header plus optional data) in the tar archive and lzip members in
|
||||
the resulting multimember tar.lz archive:
|
||||
|
||||
tar
|
||||
+========+======+========+======+========+======+========+
|
||||
| header | data | header | data | header | data | eof |
|
||||
+========+======+========+======+========+======+========+
|
||||
|
||||
tar.lz
|
||||
+===============+===============+===============+========+
|
||||
| member | member | member | member |
|
||||
+===============+===============+===============+========+
|
||||
|
||||
Of course, compressing each file (or each directory) individually is
|
||||
less efficient than compressing the whole tar archive, but it has the
|
||||
following advantages:
|
||||
|
||||
* The resulting multimember tar.lz archive can be decompressed in
|
||||
parallel with plzip, multiplying the decompression speed.
|
||||
|
||||
* New members can be appended to the archive (by removing the eof
|
||||
member) just like to an uncompressed tar archive.
|
||||
|
||||
* It is a safe posix-style backup format. In case of corruption,
|
||||
tarlz can extract all the undamaged members from the tar.lz
|
||||
archive, skipping over the damaged members, just like the standard
|
||||
(uncompressed) tar. Moreover, lziprecover can be used to recover at
|
||||
least part of the contents of the damaged members.
|
||||
|
||||
* A multimember tar.lz archive is usually smaller than the
|
||||
corresponding solidly compressed tar.gz archive, except when
|
||||
individually compressing files smaller than about 32 KiB.
|
||||
|
||||
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
||||
|
||||
The file Makefile.in is a data file used by configure to produce the
|
||||
Makefile. It has the same copyright owner and permissions that configure
|
||||
itself.
|
196
arg_parser.cc
Normal file
196
arg_parser.cc
Normal file
|
@ -0,0 +1,196 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2018 Antonio Diaz Diaz.
|
||||
|
||||
This library is free software. 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. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
This 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.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arg_parser.h"
|
||||
|
||||
|
||||
bool Arg_parser::parse_long_option( const char * const opt, const char * const arg,
|
||||
const Option options[], int & argind )
|
||||
{
|
||||
unsigned len;
|
||||
int index = -1;
|
||||
bool exact = false, ambig = false;
|
||||
|
||||
for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
|
||||
|
||||
// Test all long options for either exact match or abbreviated matches.
|
||||
for( int i = 0; options[i].code != 0; ++i )
|
||||
if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 )
|
||||
{
|
||||
if( std::strlen( options[i].name ) == len ) // Exact match found
|
||||
{ index = i; exact = true; break; }
|
||||
else if( index < 0 ) index = i; // First nonexact match found
|
||||
else if( options[index].code != options[i].code ||
|
||||
options[index].has_arg != options[i].has_arg )
|
||||
ambig = true; // Second or later nonexact match found
|
||||
}
|
||||
|
||||
if( ambig && !exact )
|
||||
{
|
||||
error_ = "option '"; error_ += opt; error_ += "' is ambiguous";
|
||||
return false;
|
||||
}
|
||||
|
||||
if( index < 0 ) // nothing found
|
||||
{
|
||||
error_ = "unrecognized option '"; error_ += opt; error_ += '\'';
|
||||
return false;
|
||||
}
|
||||
|
||||
++argind;
|
||||
data.push_back( Record( options[index].code ) );
|
||||
|
||||
if( opt[len+2] ) // '--<long_option>=<argument>' syntax
|
||||
{
|
||||
if( options[index].has_arg == no )
|
||||
{
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' doesn't allow an argument";
|
||||
return false;
|
||||
}
|
||||
if( options[index].has_arg == yes && !opt[len+3] )
|
||||
{
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' requires an argument";
|
||||
return false;
|
||||
}
|
||||
data.back().argument = &opt[len+3];
|
||||
return true;
|
||||
}
|
||||
|
||||
if( options[index].has_arg == yes )
|
||||
{
|
||||
if( !arg || !arg[0] )
|
||||
{
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' requires an argument";
|
||||
return false;
|
||||
}
|
||||
++argind; data.back().argument = arg;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Arg_parser::parse_short_option( const char * const opt, const char * const arg,
|
||||
const Option options[], int & argind )
|
||||
{
|
||||
int cind = 1; // character index in opt
|
||||
|
||||
while( cind > 0 )
|
||||
{
|
||||
int index = -1;
|
||||
const unsigned char c = opt[cind];
|
||||
|
||||
if( c != 0 )
|
||||
for( int i = 0; options[i].code; ++i )
|
||||
if( c == options[i].code )
|
||||
{ index = i; break; }
|
||||
|
||||
if( index < 0 )
|
||||
{
|
||||
error_ = "invalid option -- '"; error_ += c; error_ += '\'';
|
||||
return false;
|
||||
}
|
||||
|
||||
data.push_back( Record( c ) );
|
||||
if( opt[++cind] == 0 ) { ++argind; cind = 0; } // opt finished
|
||||
|
||||
if( options[index].has_arg != no && cind > 0 && opt[cind] )
|
||||
{
|
||||
data.back().argument = &opt[cind]; ++argind; cind = 0;
|
||||
}
|
||||
else if( options[index].has_arg == yes )
|
||||
{
|
||||
if( !arg || !arg[0] )
|
||||
{
|
||||
error_ = "option requires an argument -- '"; error_ += c;
|
||||
error_ += '\'';
|
||||
return false;
|
||||
}
|
||||
data.back().argument = arg; ++argind; cind = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Arg_parser::Arg_parser( const int argc, const char * const argv[],
|
||||
const Option options[], const bool in_order )
|
||||
{
|
||||
if( argc < 2 || !argv || !options ) return;
|
||||
|
||||
std::vector< const char * > non_options; // skipped non-options
|
||||
int argind = 1; // index in argv
|
||||
|
||||
while( argind < argc )
|
||||
{
|
||||
const unsigned char ch1 = argv[argind][0];
|
||||
const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
|
||||
|
||||
if( ch1 == '-' && ch2 ) // we found an option
|
||||
{
|
||||
const char * const opt = argv[argind];
|
||||
const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
|
||||
if( ch2 == '-' )
|
||||
{
|
||||
if( !argv[argind][2] ) { ++argind; break; } // we found "--"
|
||||
else if( !parse_long_option( opt, arg, options, argind ) ) break;
|
||||
}
|
||||
else if( !parse_short_option( opt, arg, options, argind ) ) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( in_order ) data.push_back( Record( argv[argind++] ) );
|
||||
else non_options.push_back( argv[argind++] );
|
||||
}
|
||||
}
|
||||
if( error_.size() ) data.clear();
|
||||
else
|
||||
{
|
||||
for( unsigned i = 0; i < non_options.size(); ++i )
|
||||
data.push_back( Record( non_options[i] ) );
|
||||
while( argind < argc )
|
||||
data.push_back( Record( argv[argind++] ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Arg_parser::Arg_parser( const char * const opt, const char * const arg,
|
||||
const Option options[] )
|
||||
{
|
||||
if( !opt || !opt[0] || !options ) return;
|
||||
|
||||
if( opt[0] == '-' && opt[1] ) // we found an option
|
||||
{
|
||||
int argind = 1; // dummy
|
||||
if( opt[1] == '-' )
|
||||
{ if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
|
||||
else
|
||||
parse_short_option( opt, arg, options, argind );
|
||||
if( error_.size() ) data.clear();
|
||||
}
|
||||
else data.push_back( Record( opt ) );
|
||||
}
|
98
arg_parser.h
Normal file
98
arg_parser.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006-2018 Antonio Diaz Diaz.
|
||||
|
||||
This library is free software. 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. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
This 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.
|
||||
*/
|
||||
|
||||
/* Arg_parser reads the arguments in 'argv' and creates a number of
|
||||
option codes, option arguments and non-option arguments.
|
||||
|
||||
In case of error, 'error' returns a non-empty error message.
|
||||
|
||||
'options' is an array of 'struct Option' terminated by an element
|
||||
containing a code which is zero. A null name means a short-only
|
||||
option. A code value outside the unsigned char range means a
|
||||
long-only option.
|
||||
|
||||
Arg_parser normally makes it appear as if all the option arguments
|
||||
were specified before all the non-option arguments for the purposes
|
||||
of parsing, even if the user of your program intermixed option and
|
||||
non-option arguments. If you want the arguments in the exact order
|
||||
the user typed them, call 'Arg_parser' with 'in_order' = true.
|
||||
|
||||
The argument '--' terminates all options; any following arguments are
|
||||
treated as non-option arguments, even if they begin with a hyphen.
|
||||
|
||||
The syntax for optional option arguments is '-<short_option><argument>'
|
||||
(without whitespace), or '--<long_option>=<argument>'.
|
||||
*/
|
||||
|
||||
class Arg_parser
|
||||
{
|
||||
public:
|
||||
enum Has_arg { no, yes, maybe };
|
||||
|
||||
struct Option
|
||||
{
|
||||
int code; // Short option letter or code ( code != 0 )
|
||||
const char * name; // Long option name (maybe null)
|
||||
Has_arg has_arg;
|
||||
};
|
||||
|
||||
private:
|
||||
struct Record
|
||||
{
|
||||
int code;
|
||||
std::string argument;
|
||||
explicit Record( const int c ) : code( c ) {}
|
||||
explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {}
|
||||
};
|
||||
|
||||
std::string error_;
|
||||
std::vector< Record > data;
|
||||
|
||||
bool parse_long_option( const char * const opt, const char * const arg,
|
||||
const Option options[], int & argind );
|
||||
bool parse_short_option( const char * const opt, const char * const arg,
|
||||
const Option options[], int & argind );
|
||||
|
||||
public:
|
||||
Arg_parser( const int argc, const char * const argv[],
|
||||
const Option options[], const bool in_order = false );
|
||||
|
||||
// Restricted constructor. Parses a single token and argument (if any)
|
||||
Arg_parser( const char * const opt, const char * const arg,
|
||||
const Option options[] );
|
||||
|
||||
const std::string & error() const { return error_; }
|
||||
|
||||
// The number of arguments parsed (may be different from argc)
|
||||
int arguments() const { return data.size(); }
|
||||
|
||||
// If code( i ) is 0, argument( i ) is a non-option.
|
||||
// Else argument( i ) is the option's argument (or empty).
|
||||
int code( const int i ) const
|
||||
{
|
||||
if( i >= 0 && i < arguments() ) return data[i].code;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
const std::string & argument( const int i ) const
|
||||
{
|
||||
if( i >= 0 && i < arguments() ) return data[i].argument;
|
||||
else return error_;
|
||||
}
|
||||
};
|
196
configure
vendored
Executable file
196
configure
vendored
Executable file
|
@ -0,0 +1,196 @@
|
|||
#! /bin/sh
|
||||
# configure script for Tarlz - Archiver with multimember lzip compression
|
||||
# Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
#
|
||||
# This configure script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
pkgname=tarlz
|
||||
pkgversion=0.4
|
||||
progname=tarlz
|
||||
srctrigger=doc/${pkgname}.texi
|
||||
|
||||
# clear some things potentially inherited from environment.
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
srcdir=
|
||||
prefix=/usr/local
|
||||
exec_prefix='$(prefix)'
|
||||
bindir='$(exec_prefix)/bin'
|
||||
datarootdir='$(prefix)/share'
|
||||
infodir='$(datarootdir)/info'
|
||||
mandir='$(datarootdir)/man'
|
||||
CXX=g++
|
||||
CPPFLAGS=
|
||||
CXXFLAGS='-Wall -W -O2'
|
||||
LDFLAGS=
|
||||
|
||||
# checking whether we are using GNU C++.
|
||||
/bin/sh -c "${CXX} --version" > /dev/null 2>&1 ||
|
||||
{
|
||||
CXX=c++
|
||||
CXXFLAGS=-O2
|
||||
}
|
||||
|
||||
# Loop over all args
|
||||
args=
|
||||
no_create=
|
||||
while [ $# != 0 ] ; do
|
||||
|
||||
# Get the first arg, and shuffle
|
||||
option=$1 ; arg2=no
|
||||
shift
|
||||
|
||||
# Add the argument quoted to args
|
||||
args="${args} \"${option}\""
|
||||
|
||||
# Split out the argument for options that take them
|
||||
case ${option} in
|
||||
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
|
||||
esac
|
||||
|
||||
# Process the options
|
||||
case ${option} in
|
||||
--help | -h)
|
||||
echo "Usage: $0 [OPTION]... [VAR=VALUE]..."
|
||||
echo
|
||||
echo "To assign makefile variables (e.g., CXX, CXXFLAGS...), specify them as"
|
||||
echo "arguments to configure in the form VAR=VALUE."
|
||||
echo
|
||||
echo "Options and variables: [defaults in brackets]"
|
||||
echo " -h, --help display this help and exit"
|
||||
echo " -V, --version output version information and exit"
|
||||
echo " --srcdir=DIR find the sources in DIR [. or ..]"
|
||||
echo " --prefix=DIR install into DIR [${prefix}]"
|
||||
echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]"
|
||||
echo " --bindir=DIR user executables directory [${bindir}]"
|
||||
echo " --datarootdir=DIR base directory for doc and data [${datarootdir}]"
|
||||
echo " --infodir=DIR info files directory [${infodir}]"
|
||||
echo " --mandir=DIR man pages directory [${mandir}]"
|
||||
echo " CXX=COMPILER C++ compiler to use [${CXX}]"
|
||||
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
|
||||
echo
|
||||
exit 0 ;;
|
||||
--version | -V)
|
||||
echo "Configure script for ${pkgname} version ${pkgversion}"
|
||||
exit 0 ;;
|
||||
--srcdir) srcdir=$1 ; arg2=yes ;;
|
||||
--prefix) prefix=$1 ; arg2=yes ;;
|
||||
--exec-prefix) exec_prefix=$1 ; arg2=yes ;;
|
||||
--bindir) bindir=$1 ; arg2=yes ;;
|
||||
--datarootdir) datarootdir=$1 ; arg2=yes ;;
|
||||
--infodir) infodir=$1 ; arg2=yes ;;
|
||||
--mandir) mandir=$1 ; arg2=yes ;;
|
||||
|
||||
--srcdir=*) srcdir=${optarg} ;;
|
||||
--prefix=*) prefix=${optarg} ;;
|
||||
--exec-prefix=*) exec_prefix=${optarg} ;;
|
||||
--bindir=*) bindir=${optarg} ;;
|
||||
--datarootdir=*) datarootdir=${optarg} ;;
|
||||
--infodir=*) infodir=${optarg} ;;
|
||||
--mandir=*) mandir=${optarg} ;;
|
||||
--no-create) no_create=yes ;;
|
||||
|
||||
CXX=*) CXX=${optarg} ;;
|
||||
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
|
||||
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
||||
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
||||
|
||||
--*)
|
||||
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
|
||||
*=* | *-*-*) ;;
|
||||
*)
|
||||
echo "configure: unrecognized option: '${option}'" 1>&2
|
||||
echo "Try 'configure --help' for more information." 1>&2
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
# Check if the option took a separate argument
|
||||
if [ "${arg2}" = yes ] ; then
|
||||
if [ $# != 0 ] ; then args="${args} \"$1\"" ; shift
|
||||
else echo "configure: Missing argument to '${option}'" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Find the source files, if location was not specified.
|
||||
srcdirtext=
|
||||
if [ -z "${srcdir}" ] ; then
|
||||
srcdirtext="or . or .." ; srcdir=.
|
||||
if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi
|
||||
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
|
||||
## the sed command below emulates the dirname command
|
||||
srcdir=`echo $0 | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
|
||||
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2
|
||||
echo "configure: (At least ${srctrigger} is missing)." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set srcdir to . if that's what it is.
|
||||
if [ "`pwd`" = "`cd "${srcdir}" ; pwd`" ] ; then srcdir=. ; fi
|
||||
|
||||
echo
|
||||
if [ -z "${no_create}" ] ; then
|
||||
echo "creating config.status"
|
||||
rm -f config.status
|
||||
cat > config.status << EOF
|
||||
#! /bin/sh
|
||||
# This file was generated automatically by configure. Don't edit.
|
||||
# Run this file to recreate the current configuration.
|
||||
#
|
||||
# This script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
exec /bin/sh $0 ${args} --no-create
|
||||
EOF
|
||||
chmod +x config.status
|
||||
fi
|
||||
|
||||
echo "creating Makefile"
|
||||
echo "VPATH = ${srcdir}"
|
||||
echo "prefix = ${prefix}"
|
||||
echo "exec_prefix = ${exec_prefix}"
|
||||
echo "bindir = ${bindir}"
|
||||
echo "datarootdir = ${datarootdir}"
|
||||
echo "infodir = ${infodir}"
|
||||
echo "mandir = ${mandir}"
|
||||
echo "CXX = ${CXX}"
|
||||
echo "CPPFLAGS = ${CPPFLAGS}"
|
||||
echo "CXXFLAGS = ${CXXFLAGS}"
|
||||
echo "LDFLAGS = ${LDFLAGS}"
|
||||
rm -f Makefile
|
||||
cat > Makefile << EOF
|
||||
# Makefile for Tarlz - Archiver with multimember lzip compression
|
||||
# Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
# This file was generated automatically by configure. Don't edit.
|
||||
#
|
||||
# This Makefile is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
pkgname = ${pkgname}
|
||||
pkgversion = ${pkgversion}
|
||||
progname = ${progname}
|
||||
VPATH = ${srcdir}
|
||||
prefix = ${prefix}
|
||||
exec_prefix = ${exec_prefix}
|
||||
bindir = ${bindir}
|
||||
datarootdir = ${datarootdir}
|
||||
infodir = ${infodir}
|
||||
mandir = ${mandir}
|
||||
CXX = ${CXX}
|
||||
CPPFLAGS = ${CPPFLAGS}
|
||||
CXXFLAGS = ${CXXFLAGS}
|
||||
LDFLAGS = ${LDFLAGS}
|
||||
EOF
|
||||
cat "${srcdir}/Makefile.in" >> Makefile
|
||||
|
||||
echo "OK. Now you can run make."
|
||||
echo "If make fails, verify that the lzlib compression library is correctly"
|
||||
echo "installed (see INSTALL)."
|
412
create.cc
Normal file
412
create.cc
Normal file
|
@ -0,0 +1,412 @@
|
|||
/* Tarlz - Archiver with multimember lzip compression
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ftw.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <lzlib.h>
|
||||
|
||||
#include "arg_parser.h"
|
||||
#include "lzip.h"
|
||||
#include "tarlz.h"
|
||||
|
||||
int cl_owner = -1; // global vars needed by add_member
|
||||
int cl_group = -1;
|
||||
int cl_solid = 0; // 1 = dsolid, 2 = asolid, 3 = solid
|
||||
|
||||
namespace {
|
||||
|
||||
LZ_Encoder * encoder = 0; // local vars needed by add_member
|
||||
int outfd = -1;
|
||||
int gretval = 0;
|
||||
|
||||
int seek_read( const int fd, uint8_t * const buf, const int size,
|
||||
const long long pos )
|
||||
{
|
||||
if( lseek( fd, pos, SEEK_SET ) == pos )
|
||||
return readblock( fd, buf, size );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check archive type, remove EOF blocks, and leave outfd file pos at EOF
|
||||
bool check_appendable()
|
||||
{
|
||||
struct stat st;
|
||||
if( fstat( outfd, &st ) != 0 || !S_ISREG( st.st_mode ) ) return false;
|
||||
uint8_t buf[header_size];
|
||||
int rd = readblock( outfd, buf, header_size );
|
||||
if( rd == 0 && errno == 0 ) return true; // append to empty archive
|
||||
if( rd < min_member_size || ( rd != header_size && errno ) ) return false;
|
||||
const Lzip_header * const p = (Lzip_header *)buf; // shut up gcc
|
||||
if( !p->verify_magic() ) return false;
|
||||
LZ_Decoder * decoder = LZ_decompress_open(); // decompress first header
|
||||
if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok ||
|
||||
LZ_decompress_write( decoder, buf, rd ) != rd ||
|
||||
( rd = LZ_decompress_read( decoder, buf, header_size ) ) <
|
||||
magic_o + magic_l )
|
||||
{ LZ_decompress_close( decoder ); return false; }
|
||||
LZ_decompress_close( decoder );
|
||||
const bool maybe_eof = ( buf[0] == 0 );
|
||||
if( !verify_ustar_chksum( buf ) && !maybe_eof ) return false;
|
||||
const long long end = lseek( outfd, 0, SEEK_END );
|
||||
if( end < min_member_size ) return false;
|
||||
|
||||
Lzip_trailer trailer;
|
||||
if( seek_read( outfd, trailer.data, Lzip_trailer::size,
|
||||
end - Lzip_trailer::size ) != Lzip_trailer::size )
|
||||
return false;
|
||||
const long long member_size = trailer.member_size();
|
||||
if( member_size < min_member_size || member_size > end ||
|
||||
( maybe_eof && member_size != end ) ) return false;
|
||||
|
||||
Lzip_header header;
|
||||
if( seek_read( outfd, header.data, Lzip_header::size,
|
||||
end - member_size ) != Lzip_header::size )
|
||||
return false;
|
||||
if( !header.verify_magic() || !isvalid_ds( header.dictionary_size() ) )
|
||||
return false;
|
||||
|
||||
const unsigned long long data_size = trailer.data_size();
|
||||
if( data_size < header_size || data_size > 32256 ) return false;
|
||||
const unsigned data_crc = trailer.data_crc();
|
||||
const CRC32 crc32;
|
||||
uint32_t crc = 0xFFFFFFFFU;
|
||||
for( unsigned i = 0; i < data_size; ++i ) crc32.update_byte( crc, 0 );
|
||||
crc ^= 0xFFFFFFFFU;
|
||||
if( crc != data_crc ) return false;
|
||||
|
||||
if( lseek( outfd, end - member_size, SEEK_SET ) != end - member_size ||
|
||||
ftruncate( outfd, end - member_size ) != 0 ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool archive_write( const uint8_t * const buf, const int size )
|
||||
{
|
||||
if( !encoder ) // uncompressed
|
||||
return ( writeblock( outfd, buf, size ) == size );
|
||||
enum { obuf_size = 65536 };
|
||||
uint8_t obuf[obuf_size];
|
||||
int sz = 0;
|
||||
if( size <= 0 ) LZ_compress_finish( encoder ); // flush encoder
|
||||
while( sz < size || size <= 0 )
|
||||
{
|
||||
const int wr = LZ_compress_write( encoder, buf + sz, size - sz );
|
||||
if( wr < 0 ) internal_error( "library error (LZ_compress_write)." );
|
||||
sz += wr;
|
||||
const int rd = LZ_compress_read( encoder, obuf, obuf_size );
|
||||
if( rd < 0 ) internal_error( "library error (LZ_compress_read)." );
|
||||
if( rd == 0 && sz == size ) break;
|
||||
if( writeblock( outfd, obuf, rd ) != rd ) return false;
|
||||
}
|
||||
if( LZ_compress_finished( encoder ) == 1 &&
|
||||
LZ_compress_restart_member( encoder, LLONG_MAX ) < 0 )
|
||||
internal_error( "library error (LZ_compress_restart_member)." );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void print_octal( char * const buf, int size, unsigned long long num )
|
||||
{
|
||||
while( --size >= 0 ) { buf[size] = '0' + ( num % 8 ); num /= 8; }
|
||||
}
|
||||
|
||||
|
||||
const char * remove_leading_dotdot( const char * const filename )
|
||||
{
|
||||
static std::string prefix;
|
||||
const char * p = filename;
|
||||
|
||||
for( int i = 0; filename[i]; ++i )
|
||||
if( filename[i] == '.' && filename[i+1] == '.' &&
|
||||
( i == 0 || filename[i-1] == '/' ) &&
|
||||
( filename[i+2] == 0 || filename[i+2] == '/' ) ) p = filename + i + 2;
|
||||
while( *p == '/' || ( *p == '.' && p[1] == '/' ) ) ++p;
|
||||
if( p != filename )
|
||||
{
|
||||
std::string msg( filename, p - filename );
|
||||
if( prefix != msg )
|
||||
{
|
||||
prefix = msg;
|
||||
msg = "Removing leading '"; msg += prefix; msg += "' from member names.";
|
||||
show_error( msg.c_str() );
|
||||
}
|
||||
}
|
||||
if( *p == 0 ) p = ".";
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
bool split_name( const char * const filename, Tar_header header )
|
||||
{
|
||||
const char * const stored_name = remove_leading_dotdot( filename );
|
||||
const int len = std::strlen( stored_name );
|
||||
enum { max_len = prefix_l + 1 + name_l }; // prefix + '/' + name
|
||||
if( len <= name_l ) // stored_name fits in name
|
||||
{ std::memcpy( header + name_o, stored_name, len ); return true; }
|
||||
if( len <= max_len ) // find shortest prefix
|
||||
for( int i = len - name_l - 1; i < len && i <= prefix_l; ++i )
|
||||
if( stored_name[i] == '/' )
|
||||
{
|
||||
std::memcpy( header + name_o, stored_name + i + 1, len - i - 1 );
|
||||
std::memcpy( header + prefix_o, stored_name, i );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int add_member( const char * const filename, const struct stat *,
|
||||
const int flag, struct FTW * )
|
||||
{
|
||||
struct stat st;
|
||||
if( lstat( filename, &st ) != 0 )
|
||||
{ show_file_error( filename, "Can't stat input file", errno );
|
||||
gretval = 1; return 0; }
|
||||
Tar_header header;
|
||||
std::memset( header, 0, header_size );
|
||||
if( !split_name( filename, header ) )
|
||||
{ show_file_error( filename, "File name is too long." );
|
||||
gretval = 2; return 0; }
|
||||
|
||||
const mode_t mode = st.st_mode;
|
||||
print_octal( header + mode_o, mode_l - 1,
|
||||
mode & ( S_ISUID | S_ISGID | S_ISVTX |
|
||||
S_IRWXU | S_IRWXG | S_IRWXO ) );
|
||||
const uid_t uid = ( cl_owner >= 0 ) ? (uid_t)cl_owner : st.st_uid;
|
||||
const gid_t gid = ( cl_group >= 0 ) ? (gid_t)cl_group : st.st_gid;
|
||||
print_octal( header + uid_o, uid_l - 1, uid );
|
||||
print_octal( header + gid_o, gid_l - 1, gid );
|
||||
unsigned long long file_size = 0;
|
||||
print_octal( header + mtime_o, mtime_l - 1, st.st_mtime );
|
||||
Typeflag typeflag;
|
||||
if( S_ISREG( mode ) ) { typeflag = tf_regular; file_size = st.st_size; }
|
||||
else if( S_ISDIR( mode ) )
|
||||
{
|
||||
typeflag = tf_directory;
|
||||
if( flag == FTW_DNR )
|
||||
{ show_file_error( filename, "Can't open directory", errno );
|
||||
gretval = 1; return 0; }
|
||||
}
|
||||
else if( S_ISLNK( mode ) )
|
||||
{
|
||||
typeflag = tf_symlink;
|
||||
if( st.st_size > linkname_l ||
|
||||
readlink( filename, header + linkname_o, linkname_l ) != st.st_size )
|
||||
{
|
||||
show_file_error( filename, "Link destination name is too long." );
|
||||
gretval = 2; return 0;
|
||||
}
|
||||
}
|
||||
else if( S_ISCHR( mode ) || S_ISBLK( mode ) )
|
||||
{
|
||||
typeflag = S_ISCHR( mode ) ? tf_chardev : tf_blockdev;
|
||||
print_octal( header + devmajor_o, devmajor_l - 1, major( st.st_dev ) );
|
||||
print_octal( header + devminor_o, devminor_l - 1, minor( st.st_dev ) );
|
||||
}
|
||||
else if( S_ISFIFO( mode ) ) typeflag = tf_fifo;
|
||||
else { show_file_error( filename, "Unknown file type." );
|
||||
gretval = 2; return 0; }
|
||||
header[typeflag_o] = typeflag;
|
||||
std::memcpy( header + magic_o, ustar_magic, magic_l - 1 );
|
||||
header[version_o] = header[version_o+1] = '0';
|
||||
const struct passwd * const pw = getpwuid( uid );
|
||||
if( pw && pw->pw_name )
|
||||
std::strncpy( header + uname_o, pw->pw_name, uname_l - 1 );
|
||||
const struct group * const gr = getgrgid( gid );
|
||||
if( gr && gr->gr_name )
|
||||
std::strncpy( header + gname_o, gr->gr_name, gname_l - 1 );
|
||||
print_octal( header + size_o, size_l - 1, file_size );
|
||||
print_octal( header + chksum_o, chksum_l - 1,
|
||||
ustar_chksum( (const uint8_t *)header ) );
|
||||
|
||||
const int infd = file_size ? open_instream( filename ) : -1;
|
||||
if( file_size && infd < 0 ) { gretval = 1; return 0; }
|
||||
if( !archive_write( (const uint8_t *)header, header_size ) )
|
||||
{ show_error( "Error writing archive header", errno ); return 1; }
|
||||
if( file_size )
|
||||
{
|
||||
enum { bufsize = 32 * header_size };
|
||||
uint8_t buf[bufsize];
|
||||
unsigned long long rest = file_size;
|
||||
while( rest > 0 )
|
||||
{
|
||||
int size = std::min( rest, (unsigned long long)bufsize );
|
||||
const int rd = readblock( infd, buf, size );
|
||||
rest -= rd;
|
||||
if( rd != size )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "File '%s' ends unexpectedly at pos %llu\n",
|
||||
filename, file_size - rest );
|
||||
close( infd ); return 1;
|
||||
}
|
||||
if( rest == 0 ) // last read
|
||||
{
|
||||
const int rem = file_size % header_size;
|
||||
if( rem > 0 )
|
||||
{ const int padding = header_size - rem;
|
||||
std::memset( buf + size, 0, padding ); size += padding; }
|
||||
}
|
||||
if( !archive_write( buf, size ) )
|
||||
{ show_error( "Error writing archive", errno ); close( infd );
|
||||
return 1; }
|
||||
}
|
||||
if( close( infd ) != 0 )
|
||||
{ show_file_error( filename, "Error closing file", errno ); return 1; }
|
||||
}
|
||||
if( encoder && cl_solid == 0 && !archive_write( 0, 0 ) ) // flush encoder
|
||||
{ show_error( "Error flushing encoder", errno ); return 1; }
|
||||
if( verbosity >= 1 ) std::fprintf( stderr, "%s\n", filename );
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
unsigned ustar_chksum( const uint8_t * const buf )
|
||||
{
|
||||
unsigned chksum = chksum_l * 0x20; // treat chksum field as spaces
|
||||
for( int i = 0; i < chksum_o; ++i ) chksum += buf[i];
|
||||
for( int i = chksum_o + chksum_l; i < header_size; ++i ) chksum += buf[i];
|
||||
return chksum;
|
||||
}
|
||||
|
||||
|
||||
bool verify_ustar_chksum( const uint8_t * const buf )
|
||||
{ return ( verify_ustar_magic( buf ) &&
|
||||
ustar_chksum( buf ) == strtoul( (const char *)buf + chksum_o, 0, 8 ) ); }
|
||||
|
||||
|
||||
int encode( const std::string & archive_name, const Arg_parser & parser,
|
||||
const int filenames, const int level, const bool append )
|
||||
{
|
||||
struct Lzma_options
|
||||
{
|
||||
int dictionary_size; // 4 KiB .. 512 MiB
|
||||
int match_len_limit; // 5 .. 273
|
||||
};
|
||||
const Lzma_options option_mapping[] =
|
||||
{
|
||||
{ 65535, 16 }, // -0
|
||||
{ 1 << 20, 5 }, // -1
|
||||
{ 3 << 19, 6 }, // -2
|
||||
{ 1 << 21, 8 }, // -3
|
||||
{ 3 << 20, 12 }, // -4
|
||||
{ 1 << 22, 20 }, // -5
|
||||
{ 1 << 23, 36 }, // -6
|
||||
{ 1 << 24, 68 }, // -7
|
||||
{ 3 << 23, 132 }, // -8
|
||||
{ 1 << 25, 273 } }; // -9
|
||||
const bool compressed = ( level >= 0 && level <= 9 );
|
||||
|
||||
if( !append )
|
||||
{
|
||||
if( !filenames )
|
||||
{ show_error( "Cowardly refusing to create an empty archive.", 0, true );
|
||||
return 1; }
|
||||
if( archive_name.empty() ) outfd = STDOUT_FILENO;
|
||||
else if( ( outfd = open_outstream( archive_name ) ) < 0 ) return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !filenames )
|
||||
{ if( verbosity >= 1 ) show_error( "Nothing to append." ); return 0; }
|
||||
if( archive_name.empty() )
|
||||
{ show_error( "'--append' is incompatible with '-f -'.", 0, true );
|
||||
return 1; }
|
||||
if( !compressed )
|
||||
{ show_error( "'--append' is incompatible with '--uncompressed'.", 0, true );
|
||||
return 1; }
|
||||
if( ( outfd = open_outstream( archive_name, false ) ) < 0 ) return 1;
|
||||
if( !check_appendable() )
|
||||
{ show_error( "This does not look like an appendable tar.lz archive." );
|
||||
return 2; }
|
||||
}
|
||||
|
||||
if( compressed )
|
||||
{
|
||||
encoder = LZ_compress_open( option_mapping[level].dictionary_size,
|
||||
option_mapping[level].match_len_limit, LLONG_MAX );
|
||||
if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
|
||||
{
|
||||
if( !encoder || LZ_compress_errno( encoder ) == LZ_mem_error )
|
||||
show_error( "Not enough memory. Try a lower compression level." );
|
||||
else
|
||||
internal_error( "invalid argument to encoder." );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int retval = 0;
|
||||
std::string deslashed; // arg without trailing slashes
|
||||
for( int i = 0; i < parser.arguments(); ++i ) // write members
|
||||
{
|
||||
const int code = parser.code( i );
|
||||
const std::string & arg = parser.argument( i );
|
||||
const char * filename = arg.c_str();
|
||||
if( code == 'C' && chdir( filename ) != 0 )
|
||||
{ show_file_error( filename, "Error changing working directory", errno );
|
||||
retval = 1; break; }
|
||||
if( code ) continue; // skip options
|
||||
unsigned len = arg.size();
|
||||
while( len > 1 && arg[len-1] == '/' ) --len;
|
||||
if( len < arg.size() )
|
||||
{ deslashed.assign( arg, 0, len ); filename = deslashed.c_str(); }
|
||||
struct stat st;
|
||||
if( lstat( filename, &st ) != 0 )
|
||||
{ show_file_error( filename, "Can't stat input file", errno );
|
||||
if( gretval < 1 ) gretval = 1; }
|
||||
else if( ( retval = nftw( filename, add_member, 16, FTW_PHYS ) ) != 0 )
|
||||
break; // write error
|
||||
else if( encoder && cl_solid == 1 && !archive_write( 0, 0 ) ) // flush encoder
|
||||
{ show_error( "Error flushing encoder", errno ); retval = 1; }
|
||||
}
|
||||
|
||||
if( !retval ) // write End-Of-Archive records
|
||||
{
|
||||
uint8_t buf[header_size];
|
||||
std::memset( buf, 0, header_size );
|
||||
if( encoder && cl_solid == 2 && !archive_write( 0, 0 ) ) // flush encoder
|
||||
{ show_error( "Error flushing encoder", errno ); retval = 1; }
|
||||
else if( !archive_write( buf, header_size ) ||
|
||||
!archive_write( buf, header_size ) ||
|
||||
( encoder && !archive_write( 0, 0 ) ) ) // flush encoder
|
||||
{ show_error( "Error writing end-of-archive blocks", errno );
|
||||
retval = 1; }
|
||||
}
|
||||
if( close( outfd ) != 0 && !retval )
|
||||
{ show_error( "Error closing archive", errno ); retval = 1; }
|
||||
if( retval && archive_name.size() && !append )
|
||||
std::remove( archive_name.c_str() );
|
||||
if( !retval && gretval )
|
||||
{ show_error( "Exiting with failure status due to previous errors." );
|
||||
retval = gretval; }
|
||||
return retval;
|
||||
}
|
88
doc/tarlz.1
Normal file
88
doc/tarlz.1
Normal file
|
@ -0,0 +1,88 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
|
||||
.TH TARLZ "1" "April 2018" "tarlz 0.4" "User Commands"
|
||||
.SH NAME
|
||||
tarlz \- creates tar archives with multimember lzip compression
|
||||
.SH SYNOPSIS
|
||||
.B tarlz
|
||||
[\fI\,options\/\fR] [\fI\,files\/\fR]
|
||||
.SH DESCRIPTION
|
||||
Tarlz \- Archiver with multimember lzip compression.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
display this help and exit
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
output version information and exit
|
||||
.TP
|
||||
\fB\-c\fR, \fB\-\-create\fR
|
||||
create a new archive
|
||||
.TP
|
||||
\fB\-C\fR, \fB\-\-directory=\fR<dir>
|
||||
change to directory <dir>
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-file=\fR<archive>
|
||||
use archive file <archive>
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
suppress all messages
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-append\fR
|
||||
append files to the end of an archive
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-list\fR
|
||||
list the contents of an archive
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
verbosely list files processed
|
||||
.TP
|
||||
\fB\-x\fR, \fB\-\-extract\fR
|
||||
extract files from an archive
|
||||
.TP
|
||||
\fB\-0\fR .. \fB\-9\fR
|
||||
set compression level [default 6]
|
||||
.TP
|
||||
\fB\-\-asolid\fR
|
||||
create solidly compressed appendable archive
|
||||
.TP
|
||||
\fB\-\-dsolid\fR
|
||||
create per\-directory compressed archive
|
||||
.TP
|
||||
\fB\-\-solid\fR
|
||||
create solidly compressed archive
|
||||
.TP
|
||||
\fB\-\-group=\fR<group>
|
||||
use <group> name/id for added files
|
||||
.TP
|
||||
\fB\-\-owner=\fR<owner>
|
||||
use <owner> name/id for added files
|
||||
.TP
|
||||
\fB\-\-uncompressed\fR
|
||||
don't compress the created archive
|
||||
.PP
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems (file
|
||||
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
|
||||
invalid input file, 3 for an internal consistency error (eg, bug) which
|
||||
caused tarlz to panic.
|
||||
.SH "REPORTING BUGS"
|
||||
Report bugs to lzip\-bug@nongnu.org
|
||||
.br
|
||||
Tarlz home page: http://www.nongnu.org/lzip/tarlz.html
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2018 Antonio Diaz Diaz.
|
||||
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
|
||||
.br
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
.SH "SEE ALSO"
|
||||
The full documentation for
|
||||
.B tarlz
|
||||
is maintained as a Texinfo manual. If the
|
||||
.B info
|
||||
and
|
||||
.B tarlz
|
||||
programs are properly installed at your site, the command
|
||||
.IP
|
||||
.B info tarlz
|
||||
.PP
|
||||
should give you access to the complete manual.
|
311
doc/tarlz.info
Normal file
311
doc/tarlz.info
Normal file
|
@ -0,0 +1,311 @@
|
|||
This is tarlz.info, produced by makeinfo version 4.13+ from tarlz.texi.
|
||||
|
||||
INFO-DIR-SECTION Data Compression
|
||||
START-INFO-DIR-ENTRY
|
||||
* Tarlz: (tarlz). Archiver with multimember lzip compression
|
||||
END-INFO-DIR-ENTRY
|
||||
|
||||
|
||||
File: tarlz.info, Node: Top, Next: Introduction, Up: (dir)
|
||||
|
||||
Tarlz Manual
|
||||
************
|
||||
|
||||
This manual is for Tarlz (version 0.4, 23 April 2018).
|
||||
|
||||
* Menu:
|
||||
|
||||
* Introduction:: Purpose and features of tarlz
|
||||
* Invoking tarlz:: Command line interface
|
||||
* Examples:: A small tutorial with examples
|
||||
* Problems:: Reporting bugs
|
||||
* Concept index:: Index of concepts
|
||||
|
||||
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This manual is free documentation: you have unlimited permission to
|
||||
copy, distribute and modify it.
|
||||
|
||||
|
||||
File: tarlz.info, Node: Introduction, Next: Invoking tarlz, Prev: Top, Up: Top
|
||||
|
||||
1 Introduction
|
||||
**************
|
||||
|
||||
Tarlz is a small and simple implementation of the tar archiver. By
|
||||
default tarlz creates, lists and extracts archives in the 'ustar' format
|
||||
compressed with lzip on a per file basis. Tarlz can append files to the
|
||||
end of such compressed archives.
|
||||
|
||||
Each tar member is compressed in its own lzip member, as well as the
|
||||
end-of-file blocks. This same method works for any tar format (gnu,
|
||||
ustar, posix) and is fully backward compatible with standard tar tools
|
||||
like GNU tar, which treat the resulting multimember tar.lz archive like
|
||||
any other tar.lz archive.
|
||||
|
||||
Tarlz can create tar archives with four levels of compression
|
||||
granularity; per file, per directory, appendable solid, and solid.
|
||||
|
||||
Tarlz is intended as a showcase project for the maintainers of real
|
||||
tar programs to evaluate the format and perhaps implement it in their
|
||||
tools.
|
||||
|
||||
The diagram below shows the correspondence between tar members
|
||||
(formed by a header plus optional data) in the tar archive and lzip
|
||||
members in the resulting multimember tar.lz archive: *Note File format:
|
||||
(lzip)File format.
|
||||
|
||||
tar
|
||||
+========+======+========+======+========+======+========+
|
||||
| header | data | header | data | header | data | eof |
|
||||
+========+======+========+======+========+======+========+
|
||||
|
||||
tar.lz
|
||||
+===============+===============+===============+========+
|
||||
| member | member | member | member |
|
||||
+===============+===============+===============+========+
|
||||
|
||||
Of course, compressing each file (or each directory) individually is
|
||||
less efficient than compressing the whole tar archive, but it has the
|
||||
following advantages:
|
||||
|
||||
* The resulting multimember tar.lz archive can be decompressed in
|
||||
parallel with plzip, multiplying the decompression speed.
|
||||
|
||||
* New members can be appended to the archive (by removing the eof
|
||||
member) just like to an uncompressed tar archive.
|
||||
|
||||
* It is a safe posix-style backup format. In case of corruption,
|
||||
tarlz can extract all the undamaged members from the tar.lz
|
||||
archive, skipping over the damaged members, just like the standard
|
||||
(uncompressed) tar. Moreover, lziprecover can be used to recover at
|
||||
least part of the contents of the damaged members.
|
||||
|
||||
* A multimember tar.lz archive is usually smaller than the
|
||||
corresponding solidly compressed tar.gz archive, except when
|
||||
individually compressing files smaller than about 32 KiB.
|
||||
|
||||
|
||||
File: tarlz.info, Node: Invoking tarlz, Next: Examples, Prev: Introduction, Up: Top
|
||||
|
||||
2 Invoking tarlz
|
||||
****************
|
||||
|
||||
The format for running tarlz is:
|
||||
|
||||
tarlz [OPTIONS] [FILES]
|
||||
|
||||
On archive creation or appending, tarlz removes leading and trailing
|
||||
slashes from file names, as well as file name prefixes containing a
|
||||
'..' component. On extraction, archive members containing a '..'
|
||||
component are skipped.
|
||||
|
||||
tarlz supports the following options:
|
||||
|
||||
'-h'
|
||||
'--help'
|
||||
Print an informative help message describing the options and exit.
|
||||
|
||||
'-V'
|
||||
'--version'
|
||||
Print the version number of tarlz on the standard output and exit.
|
||||
|
||||
'-c'
|
||||
'--create'
|
||||
Create a new archive.
|
||||
|
||||
'-C DIR'
|
||||
'--directory=DIR'
|
||||
Change to directory DIR. When creating or appending, the position
|
||||
of each '-C' option in the command line is significant; it will
|
||||
change the current working directory for the following FILES until
|
||||
a new '-C' option appears in the command line. When extracting, all
|
||||
the '-C' options are executed in sequence before starting the
|
||||
extraction. Listing ignores any '-C' options specified. DIR is
|
||||
relative to the then current working directory, perhaps changed by
|
||||
a previous '-C' option.
|
||||
|
||||
'-f ARCHIVE'
|
||||
'--file=ARCHIVE'
|
||||
Use archive file ARCHIVE. '-' used as an ARCHIVE argument reads
|
||||
from standard input or writes to standard output.
|
||||
|
||||
'-q'
|
||||
'--quiet'
|
||||
Quiet operation. Suppress all messages.
|
||||
|
||||
'-r'
|
||||
'--append'
|
||||
Append files to the end of an archive. The archive must be a
|
||||
regular (seekable) file compressed as a multimember lzip file, and
|
||||
the two end-of-file blocks plus any zero padding must be contained
|
||||
in the last lzip member of the archive. First this last member is
|
||||
removed, then the new members are appended, and then a new
|
||||
end-of-file member is appended to the archive. Exit with status 0
|
||||
without modifying the archive if no FILES have been specified.
|
||||
tarlz can't append files to an uncompressed tar archive.
|
||||
|
||||
'-t'
|
||||
'--list'
|
||||
List the contents of an archive.
|
||||
|
||||
'-v'
|
||||
'--verbose'
|
||||
Verbosely list files processed.
|
||||
|
||||
'-x'
|
||||
'--extract'
|
||||
Extract files from an archive.
|
||||
|
||||
'-0 .. -9'
|
||||
Set the compression level. The default compression level is '-6'.
|
||||
|
||||
'--asolid'
|
||||
When creating or appending to a compressed archive, use appendable
|
||||
solid compression. All the files being added to the archive are
|
||||
compressed into a single lzip member, but the end-of-file blocks
|
||||
are compressed into a separate lzip member. This creates a solidly
|
||||
compressed appendable archive.
|
||||
|
||||
'--dsolid'
|
||||
When creating or appending to a compressed archive, use solid
|
||||
compression for each directory especified in the command line. The
|
||||
end-of-file blocks are compressed into a separate lzip member. This
|
||||
creates a compressed appendable archive with a separate lzip
|
||||
member for each top-level directory.
|
||||
|
||||
'--solid'
|
||||
When creating or appending to a compressed archive, use solid
|
||||
compression. The files being added to the archive, along with the
|
||||
end-of-file blocks, are compressed into a single lzip member. The
|
||||
resulting archive is not appendable. No more files can be later
|
||||
appended to the archive without decompressing it first.
|
||||
|
||||
'--group=GROUP'
|
||||
When creating or appending, use GROUP for files added to the
|
||||
archive. If GROUP is not a valid group name, it is decoded as a
|
||||
decimal numeric group ID.
|
||||
|
||||
'--owner=OWNER'
|
||||
When creating or appending, use OWNER for files added to the
|
||||
archive. If OWNER is not a valid user name, it is decoded as a
|
||||
decimal numeric user ID.
|
||||
|
||||
'--uncompressed'
|
||||
With '--create', don't compress the created tar archive. Create an
|
||||
uncompressed tar archive instead.
|
||||
|
||||
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems (file
|
||||
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
|
||||
invalid input file, 3 for an internal consistency error (eg, bug) which
|
||||
caused tarlz to panic.
|
||||
|
||||
|
||||
File: tarlz.info, Node: Examples, Next: Problems, Prev: Invoking tarlz, Up: Top
|
||||
|
||||
3 A small tutorial with examples
|
||||
********************************
|
||||
|
||||
Example 1: Create a multimember compressed archive 'archive.tar.lz'
|
||||
containing files 'a', 'b' and 'c'.
|
||||
|
||||
tarlz -cf archive.tar.lz a b c
|
||||
|
||||
|
||||
Example 2: Append files 'd' and 'e' to the multimember compressed
|
||||
archive 'archive.tar.lz'.
|
||||
|
||||
tarlz -rf archive.tar.lz d e
|
||||
|
||||
|
||||
Example 3: Create a solidly compressed appendable archive
|
||||
'archive.tar.lz' containing files 'a', 'b' and 'c'. Then append files
|
||||
'd' and 'e' to the archive.
|
||||
|
||||
tarlz --asolid -cf archive.tar.lz a b c
|
||||
tarlz --asolid -rf archive.tar.lz d e
|
||||
|
||||
|
||||
Example 4: Create a compressed appendable archive containing directories
|
||||
'dir1', 'dir2' and 'dir3' with a separate lzip member per directory.
|
||||
Then append files 'a', 'b', 'c', 'd' and 'e' to the archive, all of
|
||||
them contained in a single lzip member. The resulting archive
|
||||
'archive.tar.lz' contains 5 lzip members (including the eof member).
|
||||
|
||||
tarlz --dsolid -cf archive.tar.lz dir1 dir2 dir3
|
||||
tarlz --asolid -rf archive.tar.lz a b c d e
|
||||
|
||||
|
||||
Example 5: Create a solidly compressed archive 'archive.tar.lz'
|
||||
containing files 'a', 'b' and 'c'. Note that no more files can be later
|
||||
appended to the archive without decompressing it first.
|
||||
|
||||
tarlz --solid -cf archive.tar.lz a b c
|
||||
|
||||
|
||||
Example 6: Extract all files from archive 'archive.tar.lz'.
|
||||
|
||||
tarlz -xf archive.tar.lz
|
||||
|
||||
|
||||
Example 7: Extract files 'a' and 'c' from archive 'archive.tar.lz'.
|
||||
|
||||
tarlz -xf archive.tar.lz a c
|
||||
|
||||
|
||||
Example 8: Copy the contents of directory 'sourcedir' to the directory
|
||||
'targetdir'.
|
||||
|
||||
tarlz -C sourcedir -c . | tarlz -C targetdir -x
|
||||
|
||||
|
||||
File: tarlz.info, Node: Problems, Next: Concept index, Prev: Examples, Up: Top
|
||||
|
||||
4 Reporting bugs
|
||||
****************
|
||||
|
||||
There are probably bugs in tarlz. There are certainly errors and
|
||||
omissions in this manual. If you report them, they will get fixed. If
|
||||
you don't, no one will ever know about them and they will remain unfixed
|
||||
for all eternity, if not longer.
|
||||
|
||||
If you find a bug in tarlz, please send electronic mail to
|
||||
<lzip-bug@nongnu.org>. Include the version number, which you can find
|
||||
by running 'tarlz --version'.
|
||||
|
||||
|
||||
File: tarlz.info, Node: Concept index, Prev: Problems, Up: Top
|
||||
|
||||
Concept index
|
||||
*************
|
||||
|
||||
[index]
|
||||
* Menu:
|
||||
|
||||
* bugs: Problems. (line 6)
|
||||
* examples: Examples. (line 6)
|
||||
* getting help: Problems. (line 6)
|
||||
* introduction: Introduction. (line 6)
|
||||
* invoking: Invoking tarlz. (line 6)
|
||||
* options: Invoking tarlz. (line 6)
|
||||
* usage: Invoking tarlz. (line 6)
|
||||
* version: Invoking tarlz. (line 6)
|
||||
|
||||
|
||||
|
||||
Tag Table:
|
||||
Node: Top223
|
||||
Node: Introduction785
|
||||
Node: Invoking tarlz3280
|
||||
Node: Examples7278
|
||||
Node: Problems8975
|
||||
Node: Concept index9501
|
||||
|
||||
End Tag Table
|
||||
|
||||
|
||||
Local Variables:
|
||||
coding: iso-8859-15
|
||||
End:
|
348
doc/tarlz.texi
Normal file
348
doc/tarlz.texi
Normal file
|
@ -0,0 +1,348 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename tarlz.info
|
||||
@documentencoding ISO-8859-15
|
||||
@settitle Tarlz Manual
|
||||
@finalout
|
||||
@c %**end of header
|
||||
|
||||
@set UPDATED 23 April 2018
|
||||
@set VERSION 0.4
|
||||
|
||||
@dircategory Data Compression
|
||||
@direntry
|
||||
* Tarlz: (tarlz). Archiver with multimember lzip compression
|
||||
@end direntry
|
||||
|
||||
|
||||
@ifnothtml
|
||||
@titlepage
|
||||
@title Tarlz
|
||||
@subtitle Archiver with multimember lzip compression
|
||||
@subtitle for Tarlz version @value{VERSION}, @value{UPDATED}
|
||||
@author by Antonio Diaz Diaz
|
||||
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
@end titlepage
|
||||
|
||||
@contents
|
||||
@end ifnothtml
|
||||
|
||||
@node Top
|
||||
@top
|
||||
|
||||
This manual is for Tarlz (version @value{VERSION}, @value{UPDATED}).
|
||||
|
||||
@menu
|
||||
* Introduction:: Purpose and features of tarlz
|
||||
* Invoking tarlz:: Command line interface
|
||||
* Examples:: A small tutorial with examples
|
||||
* Problems:: Reporting bugs
|
||||
* Concept index:: Index of concepts
|
||||
@end menu
|
||||
|
||||
@sp 1
|
||||
Copyright @copyright{} 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This manual is free documentation: you have unlimited permission
|
||||
to copy, distribute and modify it.
|
||||
|
||||
|
||||
@node Introduction
|
||||
@chapter Introduction
|
||||
@cindex introduction
|
||||
|
||||
Tarlz is a small and simple implementation of the tar archiver. By
|
||||
default tarlz creates, lists and extracts archives in the 'ustar' format
|
||||
compressed with lzip on a per file basis. Tarlz can append files to the
|
||||
end of such compressed archives.
|
||||
|
||||
Each tar member is compressed in its own lzip member, as well as the
|
||||
end-of-file blocks. This same method works for any tar format (gnu,
|
||||
ustar, posix) and is fully backward compatible with standard tar tools
|
||||
like GNU tar, which treat the resulting multimember tar.lz archive like
|
||||
any other tar.lz archive.
|
||||
|
||||
Tarlz can create tar archives with four levels of compression
|
||||
granularity; per file, per directory, appendable solid, and solid.
|
||||
|
||||
Tarlz is intended as a showcase project for the maintainers of real tar
|
||||
programs to evaluate the format and perhaps implement it in their tools.
|
||||
|
||||
The diagram below shows the correspondence between tar members (formed
|
||||
by a header plus optional data) in the tar archive and
|
||||
@uref{http://www.nongnu.org/lzip/manual/lzip_manual.html#File-format,,lzip members}
|
||||
in the resulting multimember tar.lz archive:
|
||||
@ifnothtml
|
||||
@xref{File format,,,lzip}.
|
||||
@end ifnothtml
|
||||
|
||||
@verbatim
|
||||
tar
|
||||
+========+======+========+======+========+======+========+
|
||||
| header | data | header | data | header | data | eof |
|
||||
+========+======+========+======+========+======+========+
|
||||
|
||||
tar.lz
|
||||
+===============+===============+===============+========+
|
||||
| member | member | member | member |
|
||||
+===============+===============+===============+========+
|
||||
@end verbatim
|
||||
|
||||
@noindent
|
||||
Of course, compressing each file (or each directory) individually is
|
||||
less efficient than compressing the whole tar archive, but it has the
|
||||
following advantages:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
The resulting multimember tar.lz archive can be decompressed in
|
||||
parallel with plzip, multiplying the decompression speed.
|
||||
|
||||
@item
|
||||
New members can be appended to the archive (by removing the eof
|
||||
member) just like to an uncompressed tar archive.
|
||||
|
||||
@item
|
||||
It is a safe posix-style backup format. In case of corruption,
|
||||
tarlz can extract all the undamaged members from the tar.lz
|
||||
archive, skipping over the damaged members, just like the standard
|
||||
(uncompressed) tar. Moreover, lziprecover can be used to recover at
|
||||
least part of the contents of the damaged members.
|
||||
|
||||
@item
|
||||
A multimember tar.lz archive is usually smaller than the
|
||||
corresponding solidly compressed tar.gz archive, except when
|
||||
individually compressing files smaller than about 32 KiB.
|
||||
@end itemize
|
||||
|
||||
|
||||
@node Invoking tarlz
|
||||
@chapter Invoking tarlz
|
||||
@cindex invoking
|
||||
@cindex options
|
||||
@cindex usage
|
||||
@cindex version
|
||||
|
||||
The format for running tarlz is:
|
||||
|
||||
@example
|
||||
tarlz [@var{options}] [@var{files}]
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
On archive creation or appending, tarlz removes leading and trailing
|
||||
slashes from file names, as well as file name prefixes containing a
|
||||
@samp{..} component. On extraction, archive members containing a
|
||||
@samp{..} component are skipped.
|
||||
|
||||
tarlz supports the following options:
|
||||
|
||||
@table @code
|
||||
@item -h
|
||||
@itemx --help
|
||||
Print an informative help message describing the options and exit.
|
||||
|
||||
@item -V
|
||||
@itemx --version
|
||||
Print the version number of tarlz on the standard output and exit.
|
||||
|
||||
@item -c
|
||||
@itemx --create
|
||||
Create a new archive.
|
||||
|
||||
@item -C @var{dir}
|
||||
@itemx --directory=@var{dir}
|
||||
Change to directory @var{dir}. When creating or appending, the position
|
||||
of each @code{-C} option in the command line is significant; it will
|
||||
change the current working directory for the following @var{files} until
|
||||
a new @code{-C} option appears in the command line. When extracting, all
|
||||
the @code{-C} options are executed in sequence before starting the
|
||||
extraction. Listing ignores any @code{-C} options specified. @var{dir}
|
||||
is relative to the then current working directory, perhaps changed by a
|
||||
previous @code{-C} option.
|
||||
|
||||
@item -f @var{archive}
|
||||
@itemx --file=@var{archive}
|
||||
Use archive file @var{archive}. @samp{-} used as an @var{archive}
|
||||
argument reads from standard input or writes to standard output.
|
||||
|
||||
@item -q
|
||||
@itemx --quiet
|
||||
Quiet operation. Suppress all messages.
|
||||
|
||||
@item -r
|
||||
@itemx --append
|
||||
Append files to the end of an archive. The archive must be a regular
|
||||
(seekable) file compressed as a multimember lzip file, and the two
|
||||
end-of-file blocks plus any zero padding must be contained in the last
|
||||
lzip member of the archive. First this last member is removed, then the
|
||||
new members are appended, and then a new end-of-file member is appended
|
||||
to the archive. Exit with status 0 without modifying the archive if no
|
||||
@var{files} have been specified. tarlz can't append files to an
|
||||
uncompressed tar archive.
|
||||
|
||||
@item -t
|
||||
@itemx --list
|
||||
List the contents of an archive.
|
||||
|
||||
@item -v
|
||||
@itemx --verbose
|
||||
Verbosely list files processed.
|
||||
|
||||
@item -x
|
||||
@itemx --extract
|
||||
Extract files from an archive.
|
||||
|
||||
@item -0 .. -9
|
||||
Set the compression level. The default compression level is @samp{-6}.
|
||||
|
||||
@item --asolid
|
||||
When creating or appending to a compressed archive, use appendable solid
|
||||
compression. All the files being added to the archive are compressed
|
||||
into a single lzip member, but the end-of-file blocks are compressed
|
||||
into a separate lzip member. This creates a solidly compressed
|
||||
appendable archive.
|
||||
|
||||
@item --dsolid
|
||||
When creating or appending to a compressed archive, use solid
|
||||
compression for each directory especified in the command line. The
|
||||
end-of-file blocks are compressed into a separate lzip member. This
|
||||
creates a compressed appendable archive with a separate lzip member for
|
||||
each top-level directory.
|
||||
|
||||
@item --solid
|
||||
When creating or appending to a compressed archive, use solid
|
||||
compression. The files being added to the archive, along with the
|
||||
end-of-file blocks, are compressed into a single lzip member. The
|
||||
resulting archive is not appendable. No more files can be later appended
|
||||
to the archive without decompressing it first.
|
||||
|
||||
@item --group=@var{group}
|
||||
When creating or appending, use @var{group} for files added to the
|
||||
archive. If @var{group} is not a valid group name, it is decoded as a
|
||||
decimal numeric group ID.
|
||||
|
||||
@item --owner=@var{owner}
|
||||
When creating or appending, use @var{owner} for files added to the
|
||||
archive. If @var{owner} is not a valid user name, it is decoded as a
|
||||
decimal numeric user ID.
|
||||
|
||||
@item --uncompressed
|
||||
With @code{--create}, don't compress the created tar archive. Create an
|
||||
uncompressed tar archive instead.
|
||||
|
||||
@end table
|
||||
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems (file not
|
||||
found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
|
||||
invalid input file, 3 for an internal consistency error (eg, bug) which
|
||||
caused tarlz to panic.
|
||||
|
||||
|
||||
@node Examples
|
||||
@chapter A small tutorial with examples
|
||||
@cindex examples
|
||||
|
||||
@noindent
|
||||
Example 1: Create a multimember compressed archive @samp{archive.tar.lz}
|
||||
containing files @samp{a}, @samp{b} and @samp{c}.
|
||||
|
||||
@example
|
||||
tarlz -cf archive.tar.lz a b c
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 2: Append files @samp{d} and @samp{e} to the multimember
|
||||
compressed archive @samp{archive.tar.lz}.
|
||||
|
||||
@example
|
||||
tarlz -rf archive.tar.lz d e
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 3: Create a solidly compressed appendable archive
|
||||
@samp{archive.tar.lz} containing files @samp{a}, @samp{b} and @samp{c}.
|
||||
Then append files @samp{d} and @samp{e} to the archive.
|
||||
|
||||
@example
|
||||
tarlz --asolid -cf archive.tar.lz a b c
|
||||
tarlz --asolid -rf archive.tar.lz d e
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 4: Create a compressed appendable archive containing directories
|
||||
@samp{dir1}, @samp{dir2} and @samp{dir3} with a separate lzip member per
|
||||
directory. Then append files @samp{a}, @samp{b}, @samp{c}, @samp{d} and
|
||||
@samp{e} to the archive, all of them contained in a single lzip member.
|
||||
The resulting archive @samp{archive.tar.lz} contains 5 lzip members
|
||||
(including the eof member).
|
||||
|
||||
@example
|
||||
tarlz --dsolid -cf archive.tar.lz dir1 dir2 dir3
|
||||
tarlz --asolid -rf archive.tar.lz a b c d e
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 5: Create a solidly compressed archive @samp{archive.tar.lz}
|
||||
containing files @samp{a}, @samp{b} and @samp{c}. Note that no more
|
||||
files can be later appended to the archive without decompressing it
|
||||
first.
|
||||
|
||||
@example
|
||||
tarlz --solid -cf archive.tar.lz a b c
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 6: Extract all files from archive @samp{archive.tar.lz}.
|
||||
|
||||
@example
|
||||
tarlz -xf archive.tar.lz
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 7: Extract files @samp{a} and @samp{c} from archive
|
||||
@samp{archive.tar.lz}.
|
||||
|
||||
@example
|
||||
tarlz -xf archive.tar.lz a c
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@noindent
|
||||
Example 8: Copy the contents of directory @samp{sourcedir} to the
|
||||
directory @samp{targetdir}.
|
||||
|
||||
@example
|
||||
tarlz -C sourcedir -c . | tarlz -C targetdir -x
|
||||
@end example
|
||||
|
||||
|
||||
@node Problems
|
||||
@chapter Reporting bugs
|
||||
@cindex bugs
|
||||
@cindex getting help
|
||||
|
||||
There are probably bugs in tarlz. There are certainly errors and
|
||||
omissions in this manual. If you report them, they will get fixed. If
|
||||
you don't, no one will ever know about them and they will remain unfixed
|
||||
for all eternity, if not longer.
|
||||
|
||||
If you find a bug in tarlz, please send electronic mail to
|
||||
@email{lzip-bug@@nongnu.org}. Include the version number, which you can
|
||||
find by running @w{@code{tarlz --version}}.
|
||||
|
||||
|
||||
@node Concept index
|
||||
@unnumbered Concept index
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
561
extract.cc
Normal file
561
extract.cc
Normal file
|
@ -0,0 +1,561 @@
|
|||
/* Tarlz - Archiver with multimember lzip compression
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lzlib.h>
|
||||
|
||||
#include "arg_parser.h"
|
||||
#include "lzip.h"
|
||||
#include "tarlz.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
int gretval = 0;
|
||||
|
||||
bool make_path( const std::string & name )
|
||||
{
|
||||
const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||
unsigned end = name.size(); // first slash before last component
|
||||
|
||||
while( end > 0 && name[end-1] == '/' ) --end; // remove trailing slashes
|
||||
while( end > 0 && name[end-1] != '/' ) --end; // remove last component
|
||||
while( end > 0 && name[end-1] == '/' ) --end; // remove more slashes
|
||||
|
||||
unsigned index = 0;
|
||||
while( index < end )
|
||||
{
|
||||
while( index < end && name[index] == '/' ) ++index;
|
||||
unsigned first = index;
|
||||
while( index < end && name[index] != '/' ) ++index;
|
||||
if( first < index )
|
||||
{
|
||||
const std::string partial( name, 0, index );
|
||||
struct stat st;
|
||||
if( stat( partial.c_str(), &st ) == 0 )
|
||||
{ if( !S_ISDIR( st.st_mode ) ) return false; }
|
||||
else if( mkdir( partial.c_str(), mode ) != 0 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Returns in buf the first rd bytes of the second lzip member or
|
||||
// the first 512 bytes of the second tar member, and sets islz if lzip member
|
||||
bool skip_first_member( const int infd, uint8_t * const buf,
|
||||
int & rd, bool & islz )
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
for( int i = 0; i < rd; ++i )
|
||||
if( buf[i] == 'L' && (*(Lzip_header *)( buf + i )).verify_prefix( rd - i ) )
|
||||
{
|
||||
const int ts = rd - i; // tail size
|
||||
std::memmove( buf, buf + i, ts );
|
||||
if( ts >= (int)sizeof lzip_magic )
|
||||
{ rd = ts; islz = true; return true; }
|
||||
int rd2 = readblock( infd, buf + ts, header_size - ts );
|
||||
if( rd2 != header_size - ts && errno )
|
||||
{ show_error( "Error reading archive", errno ); return false; }
|
||||
if( ts + rd2 >= min_member_size &&
|
||||
(*(Lzip_header *)buf).verify_magic() )
|
||||
{ rd = ts + rd2; islz = true; return true; }
|
||||
std::memmove( buf, buf + ts, rd2 );
|
||||
int rd3 = readblock( infd, buf + rd2, header_size - rd2 );
|
||||
if( rd3 != header_size - rd2 && errno )
|
||||
{ show_error( "Error reading archive", errno ); return false; }
|
||||
rd = rd2 + rd3; i = -1;
|
||||
}
|
||||
if( rd < header_size ) return false; // eof
|
||||
if( rd == header_size && verify_ustar_chksum( buf ) )
|
||||
{ islz = false; return true; }
|
||||
rd = readblock( infd, buf, header_size );
|
||||
if( rd != header_size && errno )
|
||||
{ show_error( "Error reading archive", errno ); return false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool block_is_zero( const uint8_t * const buf, const int size )
|
||||
{
|
||||
for( int i = 0; i < size; ++i ) if( buf[i] != 0 ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool archive_read( const int infd, uint8_t * const buf, const int size )
|
||||
{
|
||||
static LZ_Decoder * decoder = 0;
|
||||
static bool first_call = true;
|
||||
static bool at_eof = false;
|
||||
|
||||
if( first_call ) // check format
|
||||
{
|
||||
first_call = false;
|
||||
if( size != header_size )
|
||||
internal_error( "size != header_size on first call." );
|
||||
int rd = readblock( infd, buf, size );
|
||||
if( rd != size && errno )
|
||||
{ show_error( "Error reading archive", errno ); return false; }
|
||||
bool islz =
|
||||
( rd >= min_member_size && (*(Lzip_header *)buf).verify_magic() );
|
||||
const bool istar = ( rd == size && verify_ustar_chksum( buf ) );
|
||||
const bool iseof =
|
||||
( !islz && !istar && rd == size && block_is_zero( buf, size ) );
|
||||
if( !islz && !istar && !iseof )
|
||||
{
|
||||
show_error( "This does not look like a tar archive." );
|
||||
show_error( "Skipping to next header." );
|
||||
// std::fprintf( stderr, "%07o\n", ustar_chksum( buf ) );
|
||||
gretval = 2;
|
||||
if( !skip_first_member( infd, buf, rd, islz ) ) return false;
|
||||
}
|
||||
if( !islz ) return true; // uncompressed
|
||||
decoder = LZ_decompress_open(); // compressed
|
||||
if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
|
||||
{ show_error( "Not enough memory." );
|
||||
LZ_decompress_close( decoder ); return false; }
|
||||
if( LZ_decompress_write( decoder, buf, rd ) != rd )
|
||||
internal_error( "library error (LZ_decompress_write)." );
|
||||
if( !archive_read( infd, buf, size ) ) return false;
|
||||
if( verify_ustar_chksum( buf ) || block_is_zero( buf, size ) ) return true;
|
||||
show_error( "This does not look like a tar archive." );
|
||||
show_error( "Skipping to next header." );
|
||||
gretval = 2;
|
||||
if( LZ_decompress_sync_to_member( decoder ) < 0 )
|
||||
internal_error( "library error (LZ_decompress_sync_to_member)." );
|
||||
}
|
||||
|
||||
if( !decoder ) // uncompressed
|
||||
{ if( readblock( infd, buf, size ) == size ) return true;
|
||||
show_error( "Archive ends unexpectedly." ); return false; }
|
||||
const int ibuf_size = 16384;
|
||||
uint8_t ibuf[ibuf_size];
|
||||
int sz = 0;
|
||||
while( sz < size )
|
||||
{
|
||||
if( !at_eof && LZ_decompress_write_size( decoder ) > 0 )
|
||||
{
|
||||
const int rsize = std::min( ibuf_size, LZ_decompress_write_size( decoder ) );
|
||||
const int rd = readblock( infd, ibuf, rsize );
|
||||
if( LZ_decompress_write( decoder, ibuf, rd ) != rd )
|
||||
internal_error( "library error (LZ_decompress_write)." );
|
||||
if( rd < rsize )
|
||||
{
|
||||
at_eof = true; LZ_decompress_finish( decoder );
|
||||
if( errno )
|
||||
{ show_error( "Error reading archive", errno ); return false; }
|
||||
}
|
||||
}
|
||||
const int rd = LZ_decompress_read( decoder, buf + sz, size - sz );
|
||||
if( rd < 0 )
|
||||
{
|
||||
show_error( "Skipping to next header." );
|
||||
gretval = 2;
|
||||
if( LZ_decompress_sync_to_member( decoder ) < 0 )
|
||||
internal_error( "library error (LZ_decompress_sync_to_member)." );
|
||||
continue;
|
||||
}
|
||||
if( rd == 0 && LZ_decompress_finished( decoder ) == 1 )
|
||||
{ LZ_decompress_close( decoder );
|
||||
show_error( "Archive ends unexpectedly." ); return false; }
|
||||
sz += rd;
|
||||
if( sz == size && LZ_decompress_finished( decoder ) == 1 &&
|
||||
LZ_decompress_close( decoder ) < 0 )
|
||||
{ show_error( "LZ_decompress_close failed." ); return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char * mode_string( const Tar_header header )
|
||||
{
|
||||
static char buf[11];
|
||||
const Typeflag typeflag = (Typeflag)header[typeflag_o];
|
||||
|
||||
std::memcpy( buf, "----------", sizeof buf - 1 );
|
||||
switch( typeflag )
|
||||
{
|
||||
case tf_regular: break;
|
||||
case tf_link: buf[0] = 'h'; break;
|
||||
case tf_symlink: buf[0] = 'l'; break;
|
||||
case tf_chardev: buf[0] = 'c'; break;
|
||||
case tf_blockdev: buf[0] = 'b'; break;
|
||||
case tf_directory: buf[0] = 'd'; break;
|
||||
case tf_fifo: buf[0] = 'p'; break;
|
||||
case tf_hiperf: buf[0] = 'C'; break;
|
||||
default: buf[0] = '?';
|
||||
}
|
||||
const mode_t mode = strtoul( header + mode_o, 0, 8 ); // 12 bits
|
||||
const bool setuid = mode & S_ISUID;
|
||||
const bool setgid = mode & S_ISGID;
|
||||
const bool sticky = mode & S_ISVTX;
|
||||
if( mode & S_IRUSR ) buf[1] = 'r';
|
||||
if( mode & S_IWUSR ) buf[2] = 'w';
|
||||
if( mode & S_IXUSR ) buf[3] = setuid ? 's' : 'x';
|
||||
else if( setuid ) buf[3] = 'S';
|
||||
if( mode & S_IRGRP ) buf[4] = 'r';
|
||||
if( mode & S_IWGRP ) buf[5] = 'w';
|
||||
if( mode & S_IXGRP ) buf[6] = setgid ? 's' : 'x';
|
||||
else if( setgid ) buf[6] = 'S';
|
||||
if( mode & S_IROTH ) buf[7] = 'r';
|
||||
if( mode & S_IWOTH ) buf[8] = 'w';
|
||||
if( mode & S_IXOTH ) buf[9] = sticky ? 't' : 'x';
|
||||
else if( sticky ) buf[9] = 'T';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
const char * user_group_string( const Tar_header header )
|
||||
{
|
||||
enum { bufsize = uname_l + 1 + gname_l + 1 };
|
||||
static char buf[bufsize];
|
||||
|
||||
if( header[uname_o] && header[gname_o] )
|
||||
snprintf( buf, bufsize, "%.32s/%.32s", header + uname_o, header + gname_o );
|
||||
else
|
||||
{
|
||||
const int uid = strtoul( header + uid_o, 0, 8 );
|
||||
const int gid = strtoul( header + gid_o, 0, 8 );
|
||||
snprintf( buf, bufsize, "%u/%u", uid, gid );
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
const char * link_string( const Tar_header header )
|
||||
{
|
||||
enum { bufsize = 9 + linkname_l + 1 };
|
||||
static char buf[bufsize];
|
||||
const Typeflag typeflag = (Typeflag)header[typeflag_o];
|
||||
|
||||
if( typeflag == tf_link )
|
||||
snprintf( buf, bufsize, " link to %.100s", header + linkname_o );
|
||||
else if( typeflag == tf_symlink )
|
||||
snprintf( buf, bufsize, " -> %.100s", header + linkname_o );
|
||||
else buf[0] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void show_member_name( const char * const filename, const Tar_header header,
|
||||
const int vlevel )
|
||||
{
|
||||
if( verbosity < vlevel ) return;
|
||||
if( verbosity > vlevel )
|
||||
{
|
||||
const time_t mtime = strtoull( header + mtime_o, 0, 8 ); // 33 bits
|
||||
struct tm * tm = localtime( &mtime );
|
||||
std::printf( "%s %s %9llu %4d-%02u-%02u %02u:%02u %s%s\n",
|
||||
mode_string( header ), user_group_string( header ),
|
||||
strtoull( header + size_o, 0, 8 ), 1900 + tm->tm_year,
|
||||
1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min,
|
||||
filename, link_string( header ) );
|
||||
}
|
||||
else std::printf( "%s\n", filename );
|
||||
std::fflush( stdout );
|
||||
}
|
||||
|
||||
|
||||
int list_member( const int infd, const char * const filename,
|
||||
const unsigned long long file_size, const Tar_header header,
|
||||
const bool skip )
|
||||
{
|
||||
if( !skip ) show_member_name( filename, header, 0 );
|
||||
|
||||
const unsigned bufsize = 32 * header_size;
|
||||
uint8_t buf[bufsize];
|
||||
unsigned long long rest = file_size;
|
||||
const int rem = file_size % header_size;
|
||||
const int padding = rem ? header_size - rem : 0;
|
||||
while( rest > 0 )
|
||||
{
|
||||
const int rsize = ( rest >= bufsize ) ? bufsize : rest + padding;
|
||||
if( !archive_read( infd, buf, rsize ) ) return 2;
|
||||
if( rest < bufsize ) break;
|
||||
rest -= rsize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool contains_dotdot( const char * const filename )
|
||||
{
|
||||
for( int i = 0; filename[i]; ++i )
|
||||
if( filename[i] == '.' && filename[i+1] == '.' &&
|
||||
( i == 0 || filename[i-1] == '/' ) &&
|
||||
( filename[i+2] == 0 || filename[i+2] == '/' ) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int extract_member( const int infd, const char * const filename,
|
||||
const unsigned long long file_size, const Tar_header header )
|
||||
{
|
||||
if( contains_dotdot( filename ) )
|
||||
{
|
||||
show_file_error( filename, "Contains a '..' component, skipping." );
|
||||
return list_member( infd, filename, file_size, header, true );
|
||||
}
|
||||
const mode_t mode = strtoul( header + mode_o, 0, 8 ); // 12 bits
|
||||
const time_t mtime = strtoull( header + mtime_o, 0, 8 ); // 33 bits
|
||||
const Typeflag typeflag = (Typeflag)header[typeflag_o];
|
||||
const bool islink = ( typeflag == tf_link || typeflag == tf_symlink );
|
||||
int outfd = -1;
|
||||
|
||||
show_member_name( filename, header, 1 );
|
||||
std::remove( filename );
|
||||
make_path( filename );
|
||||
switch( typeflag )
|
||||
{
|
||||
case tf_regular:
|
||||
case tf_hiperf:
|
||||
outfd = open_outstream( filename );
|
||||
if( outfd < 0 ) return 2;
|
||||
chmod( filename, mode ); // ignore errors
|
||||
break;
|
||||
case tf_link:
|
||||
case tf_symlink:
|
||||
{
|
||||
char linkname[linkname_l+1];
|
||||
std::memcpy( linkname, header + linkname_o, linkname_l );
|
||||
linkname[linkname_l] = 0;
|
||||
/* if( contains_dotdot( linkname ) )
|
||||
{
|
||||
show_file_error( filename,
|
||||
"Link destination contains a '..' component, skipping." );
|
||||
return list_member( infd, filename, file_size, header, false );
|
||||
}*/
|
||||
const bool hard = typeflag == tf_link;
|
||||
if( ( hard && link( linkname, filename ) != 0 ) ||
|
||||
( !hard && symlink( linkname, filename ) != 0 ) )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "Can't %slink file '%s' to '%s': %s.\n",
|
||||
hard ? "" : "sym", linkname, filename,
|
||||
std::strerror( errno ) );
|
||||
return 2;
|
||||
}
|
||||
} break;
|
||||
case tf_directory:
|
||||
if( mkdir( filename, mode ) != 0 && errno != EEXIST )
|
||||
{
|
||||
show_file_error( filename, "Can't create directory", errno );
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case tf_chardev:
|
||||
case tf_blockdev:
|
||||
{
|
||||
const unsigned dev = makedev( strtoul( header + devmajor_o, 0, 8 ),
|
||||
strtoul( header + devminor_o, 0, 8 ) );
|
||||
const int dmode = ( typeflag == tf_chardev ? S_IFCHR : S_IFBLK ) | mode;
|
||||
if( mknod( filename, dmode, dev ) != 0 )
|
||||
{
|
||||
show_file_error( filename, "Can't create device node", errno );
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tf_fifo:
|
||||
if( mkfifo( filename, mode ) != 0 && errno != EEXIST )
|
||||
{
|
||||
show_file_error( filename, "Can't create FIFO file", errno );
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "File type '%c' not supported for file '%s'.\n",
|
||||
typeflag, filename );
|
||||
return 2;
|
||||
}
|
||||
|
||||
const uid_t uid = (uid_t)strtoul( header + uid_o, 0, 8 );
|
||||
const gid_t gid = (gid_t)strtoul( header + gid_o, 0, 8 );
|
||||
if( !islink && chown( filename, uid, gid ) != 0 &&
|
||||
errno != EPERM && errno != EINVAL )
|
||||
{
|
||||
show_file_error( filename, "Can't change file owner", errno );
|
||||
return 2;
|
||||
}
|
||||
|
||||
const unsigned bufsize = 32 * header_size;
|
||||
uint8_t buf[bufsize];
|
||||
unsigned long long rest = file_size;
|
||||
const int rem = file_size % header_size;
|
||||
const int padding = rem ? header_size - rem : 0;
|
||||
while( rest > 0 )
|
||||
{
|
||||
const int rsize = ( rest >= bufsize ) ? bufsize : rest + padding;
|
||||
if( !archive_read( infd, buf, rsize ) )
|
||||
{ if( outfd >= 0 ) { close( outfd ); std::remove( filename ); }
|
||||
return 2; }
|
||||
const int wsize = ( rest >= bufsize ) ? bufsize : rest;
|
||||
if( outfd >= 0 && writeblock( outfd, buf, wsize ) != wsize )
|
||||
{ show_file_error( filename, "Error writing file", errno ); return 2; }
|
||||
rest -= wsize;
|
||||
}
|
||||
if( outfd >= 0 && close( outfd ) != 0 )
|
||||
{ show_file_error( filename, "Error closing file", errno ); return 2; }
|
||||
if( !islink )
|
||||
{
|
||||
struct utimbuf t;
|
||||
t.actime = mtime;
|
||||
t.modtime = mtime;
|
||||
utime( filename, &t ); // ignore errors
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char * remove_leading_slash( const char * const filename )
|
||||
{
|
||||
static bool first_post = true;
|
||||
const char * p = filename;
|
||||
|
||||
while( *p == '/' || ( *p == '.' && p[1] == '/' ) ) ++p;
|
||||
if( p != filename && first_post )
|
||||
{
|
||||
first_post = false;
|
||||
std::string msg( "Removing leading '" );
|
||||
msg.append( filename, p - filename );
|
||||
msg += "' from member names.";
|
||||
show_error( msg.c_str() );
|
||||
}
|
||||
if( *p == 0 ) p = ".";
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// return true if dir is a parent directory of name
|
||||
bool compare_prefix_dir( const char * const dir, const char * const name )
|
||||
{
|
||||
int len = 0;
|
||||
while( dir[len] && dir[len] == name[len] ) ++len;
|
||||
return ( !dir[len] && len > 0 && ( dir[len-1] == '/' || name[len] == '/' ) );
|
||||
}
|
||||
|
||||
|
||||
// compare two file names ignoring trailing slashes
|
||||
bool compare_tslash( const char * const name1, const char * const name2 )
|
||||
{
|
||||
const char * p = name1;
|
||||
const char * q = name2;
|
||||
while( *p && *p == *q ) { ++p; ++q; }
|
||||
while( *p == '/' ) ++p;
|
||||
while( *q == '/' ) ++q;
|
||||
return ( !*p && !*q );
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
int decode( const std::string & archive_name, const Arg_parser & parser,
|
||||
const int filenames, const bool listing )
|
||||
{
|
||||
const int infd = archive_name.size() ?
|
||||
open_instream( archive_name ) : STDIN_FILENO;
|
||||
if( infd < 0 ) return 1;
|
||||
|
||||
std::vector< bool > name_pending( parser.arguments(), false );
|
||||
for( int i = 0; i < parser.arguments(); ++i )
|
||||
{
|
||||
const int code = parser.code( i );
|
||||
if( code == 'C' && !listing )
|
||||
{
|
||||
const char * const filename = parser.argument( i ).c_str();
|
||||
if( chdir( filename ) != 0 )
|
||||
{ show_file_error( filename, "Error changing working directory", errno );
|
||||
return 1; }
|
||||
}
|
||||
if( !code ) name_pending[i] = true;
|
||||
}
|
||||
|
||||
int retval = 0;
|
||||
bool skipping = false;
|
||||
while( true ) // process one member per iteration
|
||||
{
|
||||
uint8_t buf[header_size];
|
||||
if( !archive_read( infd, buf, header_size ) ) return 2;
|
||||
if( !verify_ustar_chksum( buf ) )
|
||||
{
|
||||
if( block_is_zero( buf, header_size ) ) break;
|
||||
gretval = 2;
|
||||
if( !skipping )
|
||||
{ skipping = true; show_error( "Skipping to next header." ); }
|
||||
continue;
|
||||
}
|
||||
skipping = false;
|
||||
|
||||
const char * const header = (const char *)buf;
|
||||
enum { max_filename_size = prefix_l + 1 + name_l + 1 };
|
||||
char stored_name[max_filename_size];
|
||||
int len = 0;
|
||||
while( len < prefix_l && header[prefix_o+len] )
|
||||
{ stored_name[len] = header[prefix_o+len]; ++len; }
|
||||
if( len && header[name_o] ) stored_name[len++] = '/';
|
||||
for( int i = 0; i < name_l && header[name_o+i]; ++i )
|
||||
{ stored_name[len] = header[name_o+i]; ++len; }
|
||||
while( len > 0 && stored_name[len-1] == '/' ) --len; // trailing '/'
|
||||
stored_name[len] = 0;
|
||||
const char * const filename = remove_leading_slash( stored_name );
|
||||
|
||||
bool skip = filenames > 0;
|
||||
if( skip )
|
||||
for( int i = 0; i < parser.arguments(); ++i )
|
||||
if( parser.code( i ) == 0 &&
|
||||
( compare_prefix_dir( parser.argument( i ).c_str(), filename ) ||
|
||||
compare_tslash( filename, parser.argument( i ).c_str() ) ) )
|
||||
{ skip = false; name_pending[i] = false; break; }
|
||||
|
||||
const Typeflag typeflag = (Typeflag)header[typeflag_o];
|
||||
const unsigned long long file_size =
|
||||
( typeflag == tf_regular || typeflag == tf_hiperf ) ?
|
||||
strtoull( header + size_o, 0, 8 ) : 0;
|
||||
if( listing || skip )
|
||||
retval = list_member( infd, filename, file_size, header, skip );
|
||||
else
|
||||
retval = extract_member( infd, filename, file_size, header );
|
||||
if( retval ) return retval;
|
||||
}
|
||||
|
||||
for( int i = 0; i < parser.arguments(); ++i )
|
||||
if( parser.code( i ) == 0 && name_pending[i] )
|
||||
{
|
||||
show_file_error( parser.argument( i ).c_str(), "Not found in archive." );
|
||||
if( gretval < 1 ) gretval = 1;
|
||||
}
|
||||
if( !retval && gretval )
|
||||
{ show_error( "Exiting with failure status due to previous errors." );
|
||||
retval = gretval; }
|
||||
return retval;
|
||||
}
|
112
lzip.h
Normal file
112
lzip.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* Tarlz - Archiver with multimember lzip compression
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LZ_API_VERSION
|
||||
#define LZ_API_VERSION 1
|
||||
#endif
|
||||
|
||||
enum {
|
||||
min_dictionary_bits = 12,
|
||||
min_dictionary_size = 1 << min_dictionary_bits,
|
||||
max_dictionary_bits = 29,
|
||||
max_dictionary_size = 1 << max_dictionary_bits,
|
||||
min_member_size = 36 };
|
||||
|
||||
|
||||
class CRC32
|
||||
{
|
||||
uint32_t data[256]; // Table of CRCs of all 8-bit messages.
|
||||
|
||||
public:
|
||||
CRC32()
|
||||
{
|
||||
for( unsigned n = 0; n < 256; ++n )
|
||||
{
|
||||
unsigned c = n;
|
||||
for( int k = 0; k < 8; ++k )
|
||||
{ if( c & 1 ) c = 0xEDB88320U ^ ( c >> 1 ); else c >>= 1; }
|
||||
data[n] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void update_byte( uint32_t & crc, const uint8_t byte ) const
|
||||
{ crc = data[(crc^byte)&0xFF] ^ ( crc >> 8 ); }
|
||||
};
|
||||
|
||||
|
||||
inline bool isvalid_ds( const unsigned dictionary_size )
|
||||
{ return ( dictionary_size >= min_dictionary_size &&
|
||||
dictionary_size <= max_dictionary_size ); }
|
||||
|
||||
|
||||
const uint8_t lzip_magic[5] = { 0x4C, 0x5A, 0x49, 0x50, 1 }; // "LZIP\1"
|
||||
|
||||
struct Lzip_header
|
||||
{
|
||||
uint8_t data[6]; // 0-3 magic bytes
|
||||
// 4 version
|
||||
// 5 coded_dict_size
|
||||
enum { size = 6 };
|
||||
|
||||
bool verify_magic() const
|
||||
{ return ( std::memcmp( data, lzip_magic, 5 ) == 0 ); }
|
||||
|
||||
bool verify_prefix( const int sz ) const // detect (truncated) header
|
||||
{
|
||||
for( int i = 0; i < sz && i < 5; ++i )
|
||||
if( data[i] != lzip_magic[i] ) return false;
|
||||
return ( sz > 0 );
|
||||
}
|
||||
|
||||
unsigned dictionary_size() const
|
||||
{
|
||||
unsigned sz = ( 1 << ( data[5] & 0x1F ) );
|
||||
if( sz > min_dictionary_size )
|
||||
sz -= ( sz / 16 ) * ( ( data[5] >> 5 ) & 7 );
|
||||
return sz;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Lzip_trailer
|
||||
{
|
||||
uint8_t data[20]; // 0-3 CRC32 of the uncompressed data
|
||||
// 4-11 size of the uncompressed data
|
||||
// 12-19 member size including header and trailer
|
||||
enum { size = 20 };
|
||||
|
||||
unsigned data_crc() const
|
||||
{
|
||||
unsigned tmp = 0;
|
||||
for( int i = 3; i >= 0; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned long long data_size() const
|
||||
{
|
||||
unsigned long long tmp = 0;
|
||||
for( int i = 11; i >= 4; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned long long member_size() const
|
||||
{
|
||||
unsigned long long tmp = 0;
|
||||
for( int i = 19; i >= 12; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
};
|
369
main.cc
Normal file
369
main.cc
Normal file
|
@ -0,0 +1,369 @@
|
|||
/* Tarlz - Archiver with multimember lzip compression
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Exit status: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file, 3 for an internal consistency error
|
||||
(eg, bug) which caused tarlz to panic.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#if defined(__OS2__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "arg_parser.h"
|
||||
#include "tarlz.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
#error "Environments where CHAR_BIT != 8 are not supported."
|
||||
#endif
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const Program_name = "Tarlz";
|
||||
const char * const program_name = "tarlz";
|
||||
const char * const program_year = "2018";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
enum Mode { m_none, m_append, m_create, m_extract, m_list };
|
||||
|
||||
|
||||
void show_help()
|
||||
{
|
||||
std::printf( "%s - Archiver with multimember lzip compression.\n", Program_name );
|
||||
std::printf( "\nUsage: %s [options] [files]\n", invocation_name );
|
||||
std::printf( "\nOptions:\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
" -c, --create create a new archive\n"
|
||||
" -C, --directory=<dir> change to directory <dir>\n"
|
||||
" -f, --file=<archive> use archive file <archive>\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -r, --append append files to the end of an archive\n"
|
||||
" -t, --list list the contents of an archive\n"
|
||||
" -v, --verbose verbosely list files processed\n"
|
||||
" -x, --extract extract files from an archive\n"
|
||||
" -0 .. -9 set compression level [default 6]\n"
|
||||
" --asolid create solidly compressed appendable archive\n"
|
||||
" --dsolid create per-directory compressed archive\n"
|
||||
" --solid create solidly compressed archive\n"
|
||||
" --group=<group> use <group> name/id for added files\n"
|
||||
" --owner=<owner> use <owner> name/id for added files\n"
|
||||
" --uncompressed don't compress the created archive\n"
|
||||
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
|
||||
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
|
||||
"invalid input file, 3 for an internal consistency error (eg, bug) which\n"
|
||||
"caused tarlz to panic.\n"
|
||||
"\nReport bugs to lzip-bug@nongnu.org\n"
|
||||
"Tarlz home page: http://www.nongnu.org/lzip/tarlz.html\n" );
|
||||
}
|
||||
|
||||
|
||||
void show_version()
|
||||
{
|
||||
std::printf( "%s %s\n", program_name, PROGVERSION );
|
||||
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
|
||||
std::printf( "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n" );
|
||||
}
|
||||
|
||||
|
||||
unsigned long long getnum( const char * const ptr,
|
||||
const unsigned long long llimit,
|
||||
const unsigned long long ulimit )
|
||||
{
|
||||
char * tail;
|
||||
errno = 0;
|
||||
unsigned long long result = strtoull( ptr, &tail, 0 );
|
||||
if( tail == ptr )
|
||||
{
|
||||
show_error( "Bad or missing numerical argument.", 0, true );
|
||||
std::exit( 1 );
|
||||
}
|
||||
|
||||
if( !errno && tail[0] )
|
||||
{
|
||||
const unsigned factor = ( tail[1] == 'i' ) ? 1024 : 1000;
|
||||
int exponent = 0; // 0 = bad multiplier
|
||||
switch( tail[0] )
|
||||
{
|
||||
case 'Y': exponent = 8; break;
|
||||
case 'Z': exponent = 7; break;
|
||||
case 'E': exponent = 6; break;
|
||||
case 'P': exponent = 5; break;
|
||||
case 'T': exponent = 4; break;
|
||||
case 'G': exponent = 3; break;
|
||||
case 'M': exponent = 2; break;
|
||||
case 'K': if( factor == 1024 ) exponent = 1; break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; break;
|
||||
}
|
||||
if( exponent <= 0 )
|
||||
{
|
||||
show_error( "Bad multiplier in numerical argument.", 0, true );
|
||||
std::exit( 1 );
|
||||
}
|
||||
for( int i = 0; i < exponent; ++i )
|
||||
{
|
||||
if( ulimit / factor >= result ) result *= factor;
|
||||
else { errno = ERANGE; break; }
|
||||
}
|
||||
}
|
||||
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
|
||||
if( errno )
|
||||
{
|
||||
show_error( "Numerical argument out of limits." );
|
||||
std::exit( 1 );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void set_mode( Mode & program_mode, const Mode new_mode )
|
||||
{
|
||||
if( program_mode != m_none && program_mode != new_mode )
|
||||
{
|
||||
show_error( "Only one operation can be specified.", 0, true );
|
||||
std::exit( 1 );
|
||||
}
|
||||
program_mode = new_mode;
|
||||
}
|
||||
|
||||
|
||||
void set_owner( const char * const arg )
|
||||
{
|
||||
const struct passwd * const pw = getpwnam( arg );
|
||||
if( pw ) cl_owner = pw->pw_uid;
|
||||
else if( std::isdigit( arg[0] ) ) cl_owner = getnum( arg, 0, INT_MAX );
|
||||
else { show_file_error( arg, "Invalid owner" ); std::exit( 1 ); }
|
||||
}
|
||||
|
||||
void set_group( const char * const arg )
|
||||
{
|
||||
const struct group * const gr = getgrnam( arg );
|
||||
if( gr ) cl_group = gr->gr_gid;
|
||||
else if( std::isdigit( arg[0] ) ) cl_group = getnum( arg, 0, INT_MAX );
|
||||
else { show_file_error( arg, "Invalid group" ); std::exit( 1 ); }
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
int open_instream( const std::string & name )
|
||||
{
|
||||
const int infd = open( name.c_str(), O_RDONLY | O_BINARY );
|
||||
if( infd < 0 )
|
||||
show_file_error( name.c_str(), "Can't open for reading", errno );
|
||||
return infd;
|
||||
}
|
||||
|
||||
|
||||
int open_outstream( const std::string & name, const bool create )
|
||||
{
|
||||
const int flags = (create ? O_CREAT | O_WRONLY | O_TRUNC : O_RDWR) | O_BINARY;
|
||||
const mode_t outfd_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
const int outfd = open( name.c_str(), flags, outfd_mode );
|
||||
if( outfd < 0 )
|
||||
show_file_error( name.c_str(), create ?
|
||||
"Can't create file" : "Error opening file", errno );
|
||||
return outfd;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the number of bytes really read.
|
||||
If (returned value < size) and (errno == 0), means EOF was reached.
|
||||
*/
|
||||
int readblock( const int fd, uint8_t * const buf, const int size )
|
||||
{
|
||||
int sz = 0;
|
||||
errno = 0;
|
||||
while( sz < size )
|
||||
{
|
||||
const int n = read( fd, buf + sz, size - sz );
|
||||
if( n > 0 ) sz += n;
|
||||
else if( n == 0 ) break; // EOF
|
||||
else if( errno != EINTR ) break;
|
||||
errno = 0;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the number of bytes really written.
|
||||
If (returned value < size), it is always an error.
|
||||
*/
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size )
|
||||
{
|
||||
int sz = 0;
|
||||
errno = 0;
|
||||
while( sz < size )
|
||||
{
|
||||
const int n = write( fd, buf + sz, size - sz );
|
||||
if( n > 0 ) sz += n;
|
||||
else if( n < 0 && errno != EINTR ) break;
|
||||
errno = 0;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
void show_error( const char * const msg, const int errcode, const bool help )
|
||||
{
|
||||
if( verbosity < 0 ) return;
|
||||
if( msg && msg[0] )
|
||||
std::fprintf( stderr, "%s: %s%s%s\n", program_name, msg,
|
||||
( errcode > 0 ) ? ": " : "",
|
||||
( errcode > 0 ) ? std::strerror( errcode ) : "" );
|
||||
if( help )
|
||||
std::fprintf( stderr, "Try '%s --help' for more information.\n",
|
||||
invocation_name );
|
||||
}
|
||||
|
||||
|
||||
void show_file_error( const char * const filename, const char * const msg,
|
||||
const int errcode )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: %s: %s%s%s\n", program_name, filename, msg,
|
||||
( errcode > 0 ) ? ": " : "",
|
||||
( errcode > 0 ) ? std::strerror( errcode ) : "" );
|
||||
}
|
||||
|
||||
|
||||
void internal_error( const char * const msg )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: internal error: %s\n", program_name, msg );
|
||||
std::exit( 3 );
|
||||
}
|
||||
|
||||
|
||||
int main( const int argc, const char * const argv[] )
|
||||
{
|
||||
std::string archive_name;
|
||||
Mode program_mode = m_none;
|
||||
int level = 6; // compression level, < 0 = uncompressed
|
||||
invocation_name = argv[0];
|
||||
|
||||
enum { opt_aso = 256, opt_dso, opt_grp, opt_own, opt_sol, opt_un };
|
||||
const Arg_parser::Option options[] =
|
||||
{
|
||||
{ '0', 0, Arg_parser::no },
|
||||
{ '1', 0, Arg_parser::no },
|
||||
{ '2', 0, Arg_parser::no },
|
||||
{ '3', 0, Arg_parser::no },
|
||||
{ '4', 0, Arg_parser::no },
|
||||
{ '5', 0, Arg_parser::no },
|
||||
{ '6', 0, Arg_parser::no },
|
||||
{ '7', 0, Arg_parser::no },
|
||||
{ '8', 0, Arg_parser::no },
|
||||
{ '9', 0, Arg_parser::no },
|
||||
{ 'c', "create", Arg_parser::no },
|
||||
{ 'C', "directory", Arg_parser::yes },
|
||||
{ 'f', "file", Arg_parser::yes },
|
||||
{ 'h', "help", Arg_parser::no },
|
||||
{ 'H', "format", Arg_parser::yes },
|
||||
{ 'q', "quiet", Arg_parser::no },
|
||||
{ 'r', "append", Arg_parser::no },
|
||||
{ 't', "list", Arg_parser::no },
|
||||
{ 'v', "verbose", Arg_parser::no },
|
||||
{ 'V', "version", Arg_parser::no },
|
||||
{ 'x', "extract", Arg_parser::no },
|
||||
{ opt_aso, "asolid", Arg_parser::no },
|
||||
{ opt_dso, "dsolid", Arg_parser::no },
|
||||
{ opt_grp, "group", Arg_parser::yes },
|
||||
{ opt_own, "owner", Arg_parser::yes },
|
||||
{ opt_sol, "solid", Arg_parser::no },
|
||||
{ opt_un, "uncompressed", Arg_parser::no },
|
||||
{ 0 , 0, Arg_parser::no } };
|
||||
|
||||
const Arg_parser parser( argc, argv, options, true );
|
||||
if( parser.error().size() ) // bad option
|
||||
{ show_error( parser.error().c_str(), 0, true ); return 1; }
|
||||
|
||||
int filenames = 0;
|
||||
for( int argind = 0; argind < parser.arguments(); ++argind )
|
||||
{
|
||||
const int code = parser.code( argind );
|
||||
if( !code ) { ++filenames; continue; } // skip non-options
|
||||
const std::string & sarg = parser.argument( argind );
|
||||
const char * const arg = sarg.c_str();
|
||||
switch( code )
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
level = code - '0'; break;
|
||||
case 'c': set_mode( program_mode, m_create ); break;
|
||||
case 'C': break; // skip chdir
|
||||
case 'f': if( sarg != "-" ) archive_name = sarg; break;
|
||||
case 'h': show_help(); return 0;
|
||||
case 'H': break; // ignore format
|
||||
case 'q': verbosity = -1; break;
|
||||
case 'r': set_mode( program_mode, m_append ); break;
|
||||
case 't': set_mode( program_mode, m_list ); break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
case 'V': show_version(); return 0;
|
||||
case 'x': set_mode( program_mode, m_extract ); break;
|
||||
case opt_aso: cl_solid = 2; break;
|
||||
case opt_dso: cl_solid = 1; break;
|
||||
case opt_grp: set_group( arg ); break;
|
||||
case opt_own: set_owner( arg ); break;
|
||||
case opt_sol: cl_solid = 3; break;
|
||||
case opt_un: level = -1; break;
|
||||
default : internal_error( "uncaught option" );
|
||||
}
|
||||
} // end process options
|
||||
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
setmode( STDIN_FILENO, O_BINARY );
|
||||
setmode( STDOUT_FILENO, O_BINARY );
|
||||
#endif
|
||||
|
||||
switch( program_mode )
|
||||
{
|
||||
case m_none: show_error( "Missing operation.", 0, true ); return 2;
|
||||
case m_append:
|
||||
case m_create: return encode( archive_name, parser, filenames, level,
|
||||
program_mode == m_append );
|
||||
case m_extract:
|
||||
case m_list:
|
||||
return decode( archive_name, parser, filenames, program_mode == m_list );
|
||||
}
|
||||
}
|
68
tarlz.h
Normal file
68
tarlz.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* Tarlz - Archiver with multimember lzip compression
|
||||
Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
enum { header_size = 512 };
|
||||
typedef char Tar_header[header_size];
|
||||
|
||||
enum Offsets {
|
||||
name_o = 0, mode_o = 100, uid_o = 108, gid_o = 116, size_o = 124,
|
||||
mtime_o = 136, chksum_o = 148, typeflag_o = 156, linkname_o = 157,
|
||||
magic_o = 257, version_o = 263, uname_o = 265, gname_o = 297,
|
||||
devmajor_o = 329, devminor_o = 337, prefix_o = 345 };
|
||||
|
||||
enum Lengths {
|
||||
name_l = 100, mode_l = 8, uid_l = 8, gid_l = 8, size_l = 12,
|
||||
mtime_l = 12, chksum_l = 8, typeflag_l = 1, linkname_l = 100,
|
||||
magic_l = 6, version_l = 2, uname_l = 32, gname_l = 32,
|
||||
devmajor_l = 8, devminor_l = 8, prefix_l = 155 };
|
||||
|
||||
enum Typeflag {
|
||||
tf_regular = '0', tf_link = '1', tf_symlink = '2', tf_chardev = '3',
|
||||
tf_blockdev = '4', tf_directory = '5', tf_fifo = '6', tf_hiperf = '7' };
|
||||
|
||||
const uint8_t ustar_magic[magic_l] =
|
||||
{ 0x75, 0x73, 0x74, 0x61, 0x72, 0 }; // "ustar\0"
|
||||
|
||||
inline bool verify_ustar_magic( const uint8_t * const buf )
|
||||
{ return std::memcmp( buf + magic_o, ustar_magic, magic_l ) == 0; }
|
||||
|
||||
|
||||
// defined in create.cc
|
||||
extern int cl_owner;
|
||||
extern int cl_group;
|
||||
extern int cl_solid;
|
||||
unsigned ustar_chksum( const uint8_t * const buf );
|
||||
bool verify_ustar_chksum( const uint8_t * const buf );
|
||||
class Arg_parser;
|
||||
int encode( const std::string & archive_name, const Arg_parser & parser,
|
||||
const int filenames, const int level, const bool append );
|
||||
|
||||
// defined in extract.cc
|
||||
int decode( const std::string & archive_name, const Arg_parser & parser,
|
||||
const int filenames, const bool listing );
|
||||
|
||||
// defined in main.cc
|
||||
extern int verbosity;
|
||||
int open_instream( const std::string & name );
|
||||
int open_outstream( const std::string & name, const bool create = true );
|
||||
int readblock( const int fd, uint8_t * const buf, const int size );
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size );
|
||||
void show_error( const char * const msg, const int errcode = 0,
|
||||
const bool help = false );
|
||||
void show_file_error( const char * const filename, const char * const msg,
|
||||
const int errcode = 0 );
|
||||
void internal_error( const char * const msg );
|
438
testsuite/check.sh
Executable file
438
testsuite/check.sh
Executable file
|
@ -0,0 +1,438 @@
|
|||
#! /bin/sh
|
||||
# check script for Tarlz - Archiver with multimember lzip compression
|
||||
# Copyright (C) 2013-2018 Antonio Diaz Diaz.
|
||||
#
|
||||
# This script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
objdir=`pwd`
|
||||
testdir=`cd "$1" ; pwd`
|
||||
TARLZ="${objdir}"/tarlz
|
||||
framework_failure() { echo "failure in testing framework" ; exit 1 ; }
|
||||
|
||||
if [ ! -f "${TARLZ}" ] || [ ! -x "${TARLZ}" ] ; then
|
||||
echo "${TARLZ}: cannot execute"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -e "${TARLZ}" ] 2> /dev/null ||
|
||||
{
|
||||
echo "$0: a POSIX shell is required to run the tests"
|
||||
echo "Try bash -c \"$0 $1 $2\""
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -d tmp ] ; then rm -rf tmp ; fi
|
||||
mkdir tmp
|
||||
cd "${objdir}"/tmp || framework_failure
|
||||
|
||||
in="${testdir}"/test.txt
|
||||
in_lz="${testdir}"/test.txt.lz
|
||||
in_tar="${testdir}"/test.txt.tar
|
||||
in_tar_lz="${testdir}"/test.txt.tar.lz
|
||||
test3="${testdir}"/test3.tar
|
||||
test3_lz="${testdir}"/test3.tar.lz
|
||||
test3a_lz="${testdir}"/test3a.tar.lz
|
||||
bad1="${testdir}"/test3_bad1.tar
|
||||
bad2="${testdir}"/test3_bad2.tar
|
||||
bad3="${testdir}"/test3_bad3.tar
|
||||
bad4="${testdir}"/test3_bad4.tar
|
||||
bad5="${testdir}"/test3_bad5.tar
|
||||
bad1_lz="${testdir}"/test3_bad1.tar.lz
|
||||
bad2_lz="${testdir}"/test3_bad2.tar.lz
|
||||
bad3_lz="${testdir}"/test3_bad3.tar.lz
|
||||
bad4_lz="${testdir}"/test3_bad4.tar.lz
|
||||
bad5_lz="${testdir}"/test3_bad5.tar.lz
|
||||
bad6_lz="${testdir}"/test3_bad6.tar.lz
|
||||
eof_lz="${testdir}"/eof.tar.lz
|
||||
fail=0
|
||||
test_failed() { fail=1 ; printf " $1" ; [ -z "$2" ] || printf "($2)" ; }
|
||||
|
||||
# Description of test files for lziprecover:
|
||||
# test3.tar: 3 members (foo bar baz) + 2 zeroed 512-byte blocks
|
||||
# test3_bad1.tar: byte at offset 259 changed from 't' to '0' (magic)
|
||||
# test3_bad2.tar: byte at offset 1283 changed from 't' to '0' (magic)
|
||||
# test3_bad3.tar: byte at offset 2559 changed from 0x00 to 0x20 (padding)
|
||||
# test3_bad4.tar: byte at offset 1283 changed from 't' to '0' (magic)
|
||||
# byte at offset 2307 changed from 't' to '0' (magic)
|
||||
# test3_bad5.tar: 510 zeros + "LZ" prepended to test3.tar (bogus lz header)
|
||||
# test3_bad1.tar.lz: byte at offset 2 changed from 'I' to 'i' (magic)
|
||||
# test3_bad2.tar.lz: byte at offset 49 changed from 0x49 to 0x69 (mid stream)
|
||||
# test3_bad3.tar.lz: byte at offset 149 changed from 0x2D to 0x3D (mid stream)
|
||||
# test3_bad4.tar.lz: combined damage of test3_bad2.tar.lz and test3_bad3.tar.lz
|
||||
# test3_bad5.tar.lz: [71-134] --> zeroed (first trailer + seconf header)
|
||||
# test3_bad6.tar.lz: 510 zeros prepended to test3.tar.lz (header in two blocks)
|
||||
|
||||
printf "testing tarlz-%s..." "$2"
|
||||
|
||||
"${TARLZ}" -qtf ${in}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qtf ${in_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qtf nx_file
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -tf 2> /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qcf out.tar.lz
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
[ ! -e out.tar.lz ] || test_failed $LINENO
|
||||
"${TARLZ}" -rf out.tar.lz || test_failed $LINENO
|
||||
[ ! -e out.tar.lz ] || test_failed $LINENO
|
||||
"${TARLZ}" -qrf - ${in}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
[ ! -e - ] || test_failed $LINENO
|
||||
"${TARLZ}" -qr ${in}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" --uncompressed -qrf out.tar ${in}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
[ ! -e out.tar ] || test_failed $LINENO
|
||||
cat ${test3_lz} > test.tar.lz || framework_failure
|
||||
"${TARLZ}" --uncompressed -qrf test.tar.lz ${in}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
cmp ${test3_lz} test.tar.lz || test_failed $LINENO
|
||||
rm -f test.tar.lz || framework_failure
|
||||
cat ${test3} > test.tar || framework_failure
|
||||
"${TARLZ}" -qrf test.tar ${in}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
cmp ${test3} test.tar || test_failed $LINENO
|
||||
rm -f test.tar || framework_failure
|
||||
"${TARLZ}" -qc ${in} nx_file > /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qc -C nx_dir ${in}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qx -C nx_dir ${test3_lz}
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qcr
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qct
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qcx
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qtx
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qctx
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" --help > /dev/null || test_failed $LINENO
|
||||
"${TARLZ}" -V > /dev/null || test_failed $LINENO
|
||||
"${TARLZ}" --bad_option -tf ${test3_lz} 2> /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" -tf 2> /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" --owner=invalid_oner_name -tf ${test3_lz} 2> /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
"${TARLZ}" --group=invalid_goup_name -tf ${test3_lz} 2> /dev/null
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
|
||||
"${TARLZ}" -tf ${eof_lz} || test_failed $LINENO
|
||||
"${TARLZ}" -xf ${eof_lz} || test_failed $LINENO
|
||||
"${TARLZ}" -tf ${in_tar_lz} > /dev/null || test_failed $LINENO
|
||||
"${TARLZ}" -xf ${in_tar_lz} || test_failed $LINENO
|
||||
cmp ${in} test.txt || test_failed $LINENO
|
||||
rm -f test.txt || framework_failure
|
||||
"${TARLZ}" -C nx_dir -tf ${in_tar} > /dev/null || test_failed $LINENO
|
||||
"${TARLZ}" -xf ${in_tar} || test_failed $LINENO
|
||||
cmp ${in} test.txt || test_failed $LINENO
|
||||
rm -f test.txt || framework_failure
|
||||
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -xf ${test3_lz} || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -xf ${test3} || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${test3a_lz} || test_failed $LINENO
|
||||
[ -e dir/foo ] || test_failed $LINENO
|
||||
[ -e dir/bar ] || test_failed $LINENO
|
||||
[ -e dir/baz ] || test_failed $LINENO
|
||||
rm -rf dir || framework_failure
|
||||
|
||||
cat ${in} > test.txt || framework_failure
|
||||
"${TARLZ}" -0 -cf out.tar.lz test.txt || test_failed $LINENO
|
||||
rm -f test.txt || framework_failure
|
||||
"${TARLZ}" -xf out.tar.lz || test_failed $LINENO
|
||||
cmp ${in} test.txt || test_failed $LINENO
|
||||
cat ${in} > test.txt || framework_failure
|
||||
"${TARLZ}" --uncompressed -cf out.tar test.txt || test_failed $LINENO
|
||||
rm -f test.txt || framework_failure
|
||||
"${TARLZ}" -xf out.tar || test_failed $LINENO
|
||||
cmp ${in} test.txt || test_failed $LINENO
|
||||
rm -f test.txt out.tar out.tar.lz || framework_failure
|
||||
|
||||
printf "foo" > foo || framework_failure
|
||||
rm -f bar || framework_failure
|
||||
printf "baz" > baz || framework_failure
|
||||
"${TARLZ}" -qcf out.tar.lz foo bar baz
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -xf out.tar.lz || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf out.tar.lz bar
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ ! -e baz ] || test_failed $LINENO
|
||||
rm -f out.tar.lz || framework_failure
|
||||
|
||||
printf "foo" > foo || framework_failure
|
||||
printf "bar" > bar || framework_failure
|
||||
printf "baz" > baz || framework_failure
|
||||
"${TARLZ}" -0 -cf out.tar.lz foo bar baz || test_failed $LINENO
|
||||
"${TARLZ}" --dsolid -0 -cf aout.tar.lz foo bar baz || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
rm -f aout.tar.lz || framework_failure
|
||||
"${TARLZ}" -0 -qcf aout.tar.lz foo/ ./bar ./baz/ || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
rm -f aout.tar.lz || framework_failure
|
||||
"${TARLZ}" -0 -cf aout.tar.lz foo || test_failed $LINENO
|
||||
"${TARLZ}" -0 -rf aout.tar.lz bar baz || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
rm -f aout.tar.lz || framework_failure
|
||||
touch aout.tar.lz || framework_failure # append to empty file
|
||||
"${TARLZ}" -0 -rf aout.tar.lz foo bar baz || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
"${TARLZ}" -0 -rf aout.tar.lz || test_failed $LINENO # append nothing
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
"${TARLZ}" -0 -rf aout.tar.lz -C nx_dir || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
"${TARLZ}" -0 -qrf aout.tar.lz nx_file
|
||||
[ $? = 1 ] || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
cat ${eof_lz} > aout.tar.lz || framework_failure # append to empty archive
|
||||
"${TARLZ}" -0 -rf aout.tar.lz foo bar baz || test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
mv -f foo foo.orig || framework_failure
|
||||
mv -f bar bar.orig || framework_failure
|
||||
mv -f baz baz.orig || framework_failure
|
||||
"${TARLZ}" -xf out.tar.lz foo/ bar// baz/// || test_failed $LINENO
|
||||
cmp foo foo.orig || test_failed $LINENO
|
||||
cmp bar bar.orig || test_failed $LINENO
|
||||
cmp baz baz.orig || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -xf out.tar.lz || test_failed $LINENO
|
||||
cmp foo foo.orig || test_failed $LINENO
|
||||
cmp bar bar.orig || test_failed $LINENO
|
||||
cmp baz baz.orig || test_failed $LINENO
|
||||
mkdir dir1 || framework_failure
|
||||
"${TARLZ}" -C dir1 -xf out.tar.lz || test_failed $LINENO
|
||||
cmp dir1/foo foo.orig || test_failed $LINENO
|
||||
cmp dir1/bar bar.orig || test_failed $LINENO
|
||||
cmp dir1/baz baz.orig || test_failed $LINENO
|
||||
rm -f aout.tar.lz foo bar baz || framework_failure
|
||||
"${TARLZ}" -C dir1 -0 -cf aout.tar.lz foo bar baz || test_failed $LINENO
|
||||
"${TARLZ}" -xf aout.tar.lz || test_failed $LINENO
|
||||
cmp foo foo.orig || test_failed $LINENO
|
||||
cmp bar bar.orig || test_failed $LINENO
|
||||
cmp baz baz.orig || test_failed $LINENO
|
||||
rm -f aout.tar.lz foo bar baz || framework_failure
|
||||
"${TARLZ}" -C dir1 -0 -c foo bar baz | "${TARLZ}" -x || test_failed $LINENO
|
||||
cmp foo foo.orig || test_failed $LINENO
|
||||
cmp bar bar.orig || test_failed $LINENO
|
||||
cmp baz baz.orig || test_failed $LINENO
|
||||
rm -f dir1/foo dir1/bar dir1/baz || framework_failure
|
||||
"${TARLZ}" -0 -c foo bar baz | "${TARLZ}" -C dir1 -x || test_failed $LINENO
|
||||
cmp dir1/foo foo.orig || test_failed $LINENO
|
||||
cmp dir1/bar bar.orig || test_failed $LINENO
|
||||
cmp dir1/baz baz.orig || test_failed $LINENO
|
||||
rm -f dir1/foo dir1/bar dir1/baz || framework_failure
|
||||
"${TARLZ}" -0 -c foo bar baz | "${TARLZ}" -x foo bar baz -C dir1 ||
|
||||
test_failed $LINENO
|
||||
cmp dir1/foo foo.orig || test_failed $LINENO
|
||||
cmp dir1/bar bar.orig || test_failed $LINENO
|
||||
cmp dir1/baz baz.orig || test_failed $LINENO
|
||||
rm -f foo dir1/bar baz || framework_failure
|
||||
"${TARLZ}" -0 -cf aout.tar.lz -C dir1 foo -C .. bar -C dir1 baz ||
|
||||
test_failed $LINENO
|
||||
cmp out.tar.lz aout.tar.lz || test_failed $LINENO
|
||||
"${TARLZ}" -0 -cf aout.tar.lz dir1/foo dir1/baz || test_failed $LINENO
|
||||
rm -rf dir1 || framework_failure
|
||||
"${TARLZ}" -xf aout.tar.lz dir1 || test_failed $LINENO
|
||||
cmp dir1/foo foo.orig || test_failed $LINENO
|
||||
cmp dir1/baz baz.orig || test_failed $LINENO
|
||||
rm -rf dir1 || framework_failure
|
||||
rm -f out.tar.lz aout.tar.lz || framework_failure
|
||||
|
||||
# append to solid archive
|
||||
printf "foo" > foo || framework_failure
|
||||
printf "bar" > bar || framework_failure
|
||||
printf "baz" > baz || framework_failure
|
||||
"${TARLZ}" --solid -0 -cf out.tar.lz foo || test_failed $LINENO
|
||||
for i in --asolid --dsolid --solid -0 ; do
|
||||
"${TARLZ}" $i -qrf out.tar.lz bar baz
|
||||
[ $? = 2 ] || test_failed $LINENO $i
|
||||
[ -e out.tar.lz ] || test_failed $LINENO $i
|
||||
done
|
||||
rm -f out.tar.lz || framework_failure
|
||||
for i in --asolid --dsolid -0 ; do
|
||||
for j in --asolid --dsolid --solid -0 ; do
|
||||
"${TARLZ}" $i -0 -cf out.tar.lz foo ||
|
||||
test_failed $LINENO "$i $j"
|
||||
"${TARLZ}" $j -0 -rf out.tar.lz bar baz ||
|
||||
test_failed $LINENO "$i $j"
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -xf out.tar.lz || test_failed $LINENO "$i $j"
|
||||
cmp foo foo.orig || test_failed $LINENO "$i $j"
|
||||
cmp bar bar.orig || test_failed $LINENO "$i $j"
|
||||
cmp baz baz.orig || test_failed $LINENO "$i $j"
|
||||
rm -f out.tar.lz || framework_failure
|
||||
done
|
||||
done
|
||||
rm -f foo foo.orig bar bar.orig baz baz.orig || framework_failure
|
||||
|
||||
mkdir dir1 || framework_failure
|
||||
"${TARLZ}" -0 -cf out.tar dir1 || test_failed $LINENO
|
||||
rmdir dir1 || framework_failure
|
||||
"${TARLZ}" -xf out.tar || test_failed $LINENO
|
||||
[ -d dir1 ] || test_failed $LINENO
|
||||
rmdir dir1
|
||||
mkdir dir1 || framework_failure
|
||||
"${TARLZ}" --uncompressed -cf out.tar dir1 || test_failed $LINENO
|
||||
rmdir dir1 || framework_failure
|
||||
"${TARLZ}" -xf out.tar || test_failed $LINENO
|
||||
[ -d dir1 ] || test_failed $LINENO
|
||||
rmdir dir1
|
||||
rm -f out.tar || framework_failure
|
||||
|
||||
if ln ${in} dummy_link 2> /dev/null &&
|
||||
ln -s ${in} dummy_slink 2> /dev/null ; then
|
||||
name_100=name_100_bytes_long_nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
|
||||
path_100=dir1/dir2/dir3/path_100_bytes_long_nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
|
||||
path_106=dir1/dir2/dir3/path_longer_than_100_bytes_nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
|
||||
mkdir dir1 || framework_failure
|
||||
mkdir dir1/dir2 || framework_failure
|
||||
mkdir dir1/dir2/dir3 || framework_failure
|
||||
cat ${in} > dir1/dir2/dir3/in || framework_failure
|
||||
ln dir1/dir2/dir3/in dir1/dir2/dir3/${name_100} || framework_failure
|
||||
ln dir1/dir2/dir3/in ${path_100} || framework_failure
|
||||
ln dir1/dir2/dir3/in ${path_106} || framework_failure
|
||||
ln -s in dir1/dir2/dir3/link || framework_failure
|
||||
ln -s ${name_100} dir1/dir2/dir3/link_100 || framework_failure
|
||||
"${TARLZ}" -0 -cf out.tar dir1 || test_failed $LINENO
|
||||
rm -rf dir1 || framework_failure
|
||||
"${TARLZ}" -xf out.tar || test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/in || test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/${name_100} || test_failed $LINENO
|
||||
cmp ${in} ${path_100} || test_failed $LINENO
|
||||
cmp ${in} ${path_106} || test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/link || test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/link_100 || test_failed $LINENO
|
||||
rm -f dir1/dir2/dir3/in || framework_failure
|
||||
cmp ${in} dir1/dir2/dir3/link 2> /dev/null && test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/link_100 || test_failed $LINENO
|
||||
"${TARLZ}" -xf out.tar || test_failed $LINENO
|
||||
rm -f out.tar || framework_failure
|
||||
cmp ${in} dir1/dir2/dir3/in || test_failed $LINENO
|
||||
cmp ${in} dir1/dir2/dir3/link || test_failed $LINENO
|
||||
"${TARLZ}" -0 -qc ../tmp/dir1 > /dev/null || test_failed $LINENO
|
||||
rm -rf dir1 || framework_failure
|
||||
else
|
||||
printf "\nwarning: skipping link test: 'ln' does not work on your system."
|
||||
fi
|
||||
rm -f dummy_link dummy_slink || framework_failure
|
||||
|
||||
"${TARLZ}" -qxf "${testdir}"/dotdot1.tar.lz || test_failed $LINENO
|
||||
[ ! -e ../dir ] || test_failed $LINENO
|
||||
"${TARLZ}" -qxf "${testdir}"/dotdot2.tar.lz || test_failed $LINENO
|
||||
[ ! -e ../dir ] || test_failed $LINENO
|
||||
"${TARLZ}" -qxf "${testdir}"/dotdot3.tar.lz || test_failed $LINENO
|
||||
[ ! -e dir ] || test_failed $LINENO
|
||||
"${TARLZ}" -qxf "${testdir}"/dotdot4.tar.lz || test_failed $LINENO
|
||||
[ ! -e dir ] || test_failed $LINENO
|
||||
"${TARLZ}" -qxf "${testdir}"/dotdot5.tar.lz || test_failed $LINENO
|
||||
[ ! -e dir ] || test_failed $LINENO
|
||||
|
||||
printf "\ntesting bad input..."
|
||||
|
||||
dd if=${in_tar} of=truncated.tar bs=1000 count=1 2> /dev/null
|
||||
"${TARLZ}" -qtf truncated.tar > /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
"${TARLZ}" -qxf truncated.tar
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e test.txt ] || test_failed $LINENO
|
||||
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad1_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad2_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad3_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad4_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad5_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad6_lz}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad1}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ ! -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad2}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad3}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ ! -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad4}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ ! -e bar ] || test_failed $LINENO
|
||||
[ ! -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
"${TARLZ}" -qxf ${bad5}
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
[ -e foo ] || test_failed $LINENO
|
||||
[ -e bar ] || test_failed $LINENO
|
||||
[ -e baz ] || test_failed $LINENO
|
||||
rm -f foo bar baz || framework_failure
|
||||
|
||||
echo
|
||||
if [ ${fail} = 0 ] ; then
|
||||
echo "tests completed successfully."
|
||||
cd "${objdir}" && rm -r tmp
|
||||
else
|
||||
echo "tests failed."
|
||||
fi
|
||||
exit ${fail}
|
BIN
testsuite/dotdot1.tar.lz
Normal file
BIN
testsuite/dotdot1.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/dotdot2.tar.lz
Normal file
BIN
testsuite/dotdot2.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/dotdot3.tar.lz
Normal file
BIN
testsuite/dotdot3.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/dotdot4.tar.lz
Normal file
BIN
testsuite/dotdot4.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/dotdot5.tar.lz
Normal file
BIN
testsuite/dotdot5.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/eof.tar.lz
Normal file
BIN
testsuite/eof.tar.lz
Normal file
Binary file not shown.
676
testsuite/test.txt
Normal file
676
testsuite/test.txt
Normal file
|
@ -0,0 +1,676 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) <year> <name of author>
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) <year> <name of author>
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
BIN
testsuite/test.txt.lz
Normal file
BIN
testsuite/test.txt.lz
Normal file
Binary file not shown.
BIN
testsuite/test.txt.tar
Normal file
BIN
testsuite/test.txt.tar
Normal file
Binary file not shown.
BIN
testsuite/test.txt.tar.lz
Normal file
BIN
testsuite/test.txt.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3.tar
Normal file
BIN
testsuite/test3.tar
Normal file
Binary file not shown.
BIN
testsuite/test3.tar.lz
Normal file
BIN
testsuite/test3.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad1.tar
Normal file
BIN
testsuite/test3_bad1.tar
Normal file
Binary file not shown.
BIN
testsuite/test3_bad1.tar.lz
Normal file
BIN
testsuite/test3_bad1.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad2.tar
Normal file
BIN
testsuite/test3_bad2.tar
Normal file
Binary file not shown.
BIN
testsuite/test3_bad2.tar.lz
Normal file
BIN
testsuite/test3_bad2.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad3.tar
Normal file
BIN
testsuite/test3_bad3.tar
Normal file
Binary file not shown.
BIN
testsuite/test3_bad3.tar.lz
Normal file
BIN
testsuite/test3_bad3.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad4.tar
Normal file
BIN
testsuite/test3_bad4.tar
Normal file
Binary file not shown.
BIN
testsuite/test3_bad4.tar.lz
Normal file
BIN
testsuite/test3_bad4.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad5.tar
Normal file
BIN
testsuite/test3_bad5.tar
Normal file
Binary file not shown.
BIN
testsuite/test3_bad5.tar.lz
Normal file
BIN
testsuite/test3_bad5.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3_bad6.tar.lz
Normal file
BIN
testsuite/test3_bad6.tar.lz
Normal file
Binary file not shown.
BIN
testsuite/test3a.tar.lz
Normal file
BIN
testsuite/test3a.tar.lz
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue