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
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
|
||||
*************
|
||||
|
||||
|