Send our ancienv GNU tar into Attic.
Suggested by: ps
This commit is contained in:
parent
0f4e165dc0
commit
bf15d27233
@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: 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) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
File diff suppressed because it is too large
Load Diff
@ -1,185 +0,0 @@
|
||||
# Generated automatically from Makefile.in by configure.
|
||||
# Un*x Makefile for GNU tar program.
|
||||
# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
# 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, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = .
|
||||
VPATH = .
|
||||
|
||||
# If you use gcc, you should either run the fixincludes script that
|
||||
# comes with it or else use gcc with the -traditional option. Otherwise
|
||||
# ioctl calls will be compiled incorrectly on some systems.
|
||||
CC = gcc
|
||||
YACC = bison -y
|
||||
INSTALL = /usr/local/bin/install -c
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
|
||||
# Things you might add to DEFS:
|
||||
# -DSTDC_HEADERS If you have ANSI C headers and libraries.
|
||||
# -DHAVE_UNISTD_H If you have unistd.h.
|
||||
# -DHAVE_STRING_H If you don't have ANSI C headers but have string.h.
|
||||
# -DHAVE_LIMITS_H If you have limits.h.
|
||||
# -DBSD42 If you have sys/dir.h (unless you use -DPOSIX),
|
||||
# sys/file.h, and st_blocks in `struct stat'.
|
||||
# -DDIRENT If you have dirent.h.
|
||||
# -DSYSNDIR Old Xenix systems (sys/ndir.h).
|
||||
# -DSYSDIR Old BSD systems (sys/dir.h).
|
||||
# -DNDIR Old System V systems (ndir.h).
|
||||
# -DMAJOR_IN_MKDEV If major, minor, makedev defined in sys/mkdev.h.
|
||||
# -DMAJOR_IN_SYSMACROS If major, minor, makedev defined in sys/sysmacros.h.
|
||||
# -DRETSIGTYPE=int If your signal handlers return int, not void.
|
||||
# -DHAVE_SYS_MTIO_H If you have sys/mtio.h (magtape ioctls).
|
||||
# -DHAVE_SYS_GENTAPE_H If you have sys/gentape.h (ISC magtape ioctls).
|
||||
# -DHAVE_NETDB_H To use rexec for remote tape operations
|
||||
# instead of forking rsh or remsh.
|
||||
# -DNO_REMOTE If you have neither a remote shell nor rexec.
|
||||
# -DHAVE_VPRINTF If you have vprintf function.
|
||||
# -DHAVE_DOPRNT If you have _doprnt function (but lack vprintf).
|
||||
# -DHAVE_FTIME If you have ftime system call.
|
||||
# -DHAVE_STRSTR If you have strstr function.
|
||||
# -DHAVE_VALLOC If you have valloc function.
|
||||
# -DHAVE_MKDIR If you have mkdir and rmdir system calls.
|
||||
# -DHAVE_MKNOD If you have mknod system call.
|
||||
# -DHAVE_RENAME If you have rename system call.
|
||||
# -DHAVE_GETCWD If not POSIX.1 but have getcwd function.
|
||||
# -DHAVE_FTRUNCATE If you have ftruncate system call.
|
||||
# -DV7 On Version 7 Unix (not tested in a long time).
|
||||
# -DEMUL_OPEN3 If you lack a 3-argument version of open, and want
|
||||
# to emulate it with system calls you do have.
|
||||
# -DNO_OPEN3 If you lack the 3-argument open and want to
|
||||
# disable the tar -k option instead of emulating open.
|
||||
# -DXENIX If you have sys/inode.h and need it to be included.
|
||||
|
||||
DEF_AR_FILE = /dev/rst0
|
||||
DEFBLOCKING = 20
|
||||
DEFS = -DRETSIGTYPE=void -DDIRENT=1 -DHAVE_SYS_MTIO_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETGRGID=1 -DHAVE_GETPWUID=1 -DHAVE_STRING_H=1 -DHAVE_LIMITS_H=1 -DHAVE_STRSTR=1 -DHAVE_VALLOC=1 -DHAVE_MKDIR=1 -DHAVE_MKNOD=1 -DHAVE_RENAME=1 -DHAVE_FTRUNCATE=1 -DHAVE_GETCWD=1 -DHAVE_VPRINTF=1 -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" -DDEFBLOCKING=$(DEFBLOCKING)
|
||||
|
||||
# Set this to rtapelib.o unless you defined NO_REMOTE, in which case
|
||||
# make it empty.
|
||||
RTAPELIB = rtapelib.o
|
||||
LIBS =
|
||||
|
||||
CFLAGS = -g
|
||||
LDFLAGS = -g
|
||||
|
||||
prefix = /usr/bin
|
||||
exec_prefix = $(prefix)
|
||||
|
||||
# Prefix for each installed program, normally empty or `g'.
|
||||
binprefix =
|
||||
|
||||
# The directory to install tar in.
|
||||
bindir = $(exec_prefix)/bin
|
||||
|
||||
# Where to put the rmt executable.
|
||||
libdir = /sbin
|
||||
|
||||
# The directory to install the info files in.
|
||||
infodir = $(prefix)/info
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SRC1 = tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c
|
||||
SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c
|
||||
SRC3 = getopt1.c regex.c getdate.y getdate.c alloca.c
|
||||
SRCS = $(SRC1) $(SRC2) $(SRC3)
|
||||
OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o
|
||||
OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o
|
||||
OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB)
|
||||
OBJS = $(OBJ1) $(OBJ2) $(OBJ3)
|
||||
AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \
|
||||
configure configure.in \
|
||||
tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \
|
||||
rmt.h rmt.c rtapelib.c \
|
||||
msd_dir.h msd_dir.c tcexparg.c \
|
||||
level-0 level-1 backup-specs dump-remind getpagesize.h
|
||||
# tar.texinfo tar.info* texinfo.tex \
|
||||
|
||||
all: tar rmt
|
||||
# tar.info
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $<
|
||||
|
||||
tar: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
rmt: rmt.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(srcdir)/rmt.c $(LIBS)
|
||||
|
||||
tar.info: tar.texinfo
|
||||
makeinfo $(srcdir)/tar.texinfo
|
||||
|
||||
install: all
|
||||
$(INSTALL_PROGRAM) tar $(bindir)/$(binprefix)tar
|
||||
-test ! -f rmt || $(INSTALL_PROGRAM) rmt $(libdir)/rmt
|
||||
# for file in $(srcdir)/tar.info*; \
|
||||
# do $(INSTALL_DATA) $$file $(infodir)/$$file; \
|
||||
# done
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/$(binprefix)tar $(infodir)/tar.info*
|
||||
-rm -f $(libdir)/rmt
|
||||
|
||||
$(OBJS): tar.h pathmax.h port.h
|
||||
regex.o buffer.o tar.o: regex.h
|
||||
tar.o fnmatch.o: fnmatch.h
|
||||
|
||||
getdate.c: getdate.y
|
||||
$(YACC) $(srcdir)/getdate.y
|
||||
mv y.tab.c getdate.c
|
||||
# getdate.y has 8 shift/reduce conflicts.
|
||||
|
||||
TAGS: $(SRCS)
|
||||
etags $(SRCS)
|
||||
|
||||
clean:
|
||||
rm -f *.o tar rmt core
|
||||
mostlyclean: clean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.status
|
||||
|
||||
realclean: distclean
|
||||
rm -f TAGS *.info* getdate.c y.tab.c
|
||||
|
||||
shar: $(SRCS) $(AUX)
|
||||
shar $(SRCS) $(AUX) | gzip > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.z
|
||||
|
||||
dist: $(SRCS) $(AUX)
|
||||
echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname
|
||||
-rm -rf `cat .fname`
|
||||
mkdir `cat .fname`
|
||||
for file in $(SRCS) $(AUX); do \
|
||||
ln $$file `cat .fname` || cp $$file `cat .fname`; done
|
||||
tar chzf `cat .fname`.tar.z `cat .fname`
|
||||
-rm -rf `cat .fname` .fname
|
||||
|
||||
tar.zoo: $(SRCS) $(AUX)
|
||||
-rm -rf tmp.dir
|
||||
-mkdir tmp.dir
|
||||
-rm tar.zoo
|
||||
for X in $(SRCS) $(AUX) ; do echo $$X ; sed 's/$$/
/' $$X > tmp.dir/$$X ; done
|
||||
cd tmp.dir ; zoo aM ../tar.zoo *
|
||||
-rm -rf tmp.dir
|
||||
|
||||
# Prevent GNU make v3 from overflowing arg limit on SysV.
|
||||
.NOEXPORT:
|
@ -1,40 +0,0 @@
|
||||
Hey! Emacs! Yo! This is -*- Text -*- !!!
|
||||
|
||||
This GNU tar 1.11.2. Please send bug reports, etc., to
|
||||
bug-gnu-utils@prep.ai.mit.edu. This is a beta-test release. Please
|
||||
try it out. There is no manual; the release of version 1.12 will
|
||||
contain a manual.
|
||||
|
||||
GNU tar is based heavily on John Gilmore's public domain tar, but with
|
||||
added features. The manual is currently being written.
|
||||
|
||||
This distribution also includes rmt, the remote tape server (which
|
||||
normally must reside in /etc). The mt tape drive control program is
|
||||
in the GNU cpio distribution.
|
||||
|
||||
See the file INSTALL for compilation and installation instructions for Unix.
|
||||
See the file NEWS for information on all that is new in this version
|
||||
of tar.
|
||||
|
||||
makefile.pc is a makefile for Turbo C 2.0 on MS-DOS.
|
||||
|
||||
Various people have been having problems using floppies on a NeXT. In
|
||||
order to have them work right, you need to kill the automounting
|
||||
program which tries to monut floppies as soon as they are added.
|
||||
|
||||
If you want to do incremental dumps, use the distributed backup
|
||||
scripts. They are what we use at the FSF to do all our backups. Most
|
||||
importantly, do not use --incremental (-G) or --after-date (-N) or
|
||||
--newer-mtime to do incremental dumps. The only option that works
|
||||
correctly for this purpose is --listed-incremental. (When extracting
|
||||
incremental dumps, use --incremental (-G).)
|
||||
|
||||
If your system needs to link with -lPW to get alloca, but has
|
||||
rename in the C library (so HAVE_RENAME is defined), -lPW might
|
||||
give you an incorrect version of rename. On HP-UX this manifests
|
||||
itself as an undefined data symbol called "Error" when linking cp, ln,
|
||||
and mv. If this happens, use `ar x' to extract alloca.o from libPW.a
|
||||
and `ar rc' to put it in a library liballoca.a, and put that in LIBS
|
||||
instead of -lPW. This problem does not occur when using gcc, which
|
||||
has alloca built in.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,764 +0,0 @@
|
||||
/* Diff files from a tar archive.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*
|
||||
* Diff files from a tar archive.
|
||||
*
|
||||
* Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MTIO_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
#include "rmt.h"
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define lstat stat
|
||||
#endif
|
||||
|
||||
extern void *valloc ();
|
||||
|
||||
extern union record *head; /* Points to current tape header */
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
extern int head_standard; /* Tape header is in ANSI format */
|
||||
|
||||
void decode_header ();
|
||||
void diff_sparse_files ();
|
||||
void fill_in_sparse_array ();
|
||||
void fl_read ();
|
||||
long from_oct ();
|
||||
int do_stat ();
|
||||
extern void print_header ();
|
||||
int read_header ();
|
||||
void saverec ();
|
||||
void sigh ();
|
||||
extern void skip_file ();
|
||||
extern void skip_extended_headers ();
|
||||
int wantbytes ();
|
||||
|
||||
extern FILE *msg_file;
|
||||
|
||||
int now_verifying = 0; /* Are we verifying at the moment? */
|
||||
|
||||
int diff_fd; /* Descriptor of file we're diffing */
|
||||
|
||||
char *diff_buf = 0; /* Pointer to area for reading
|
||||
file contents into */
|
||||
|
||||
char *diff_dir; /* Directory contents for LF_DUMPDIR */
|
||||
|
||||
int different = 0;
|
||||
|
||||
/*struct sp_array *sparsearray;
|
||||
int sp_ar_size = 10;*/
|
||||
/*
|
||||
* Initialize for a diff operation
|
||||
*/
|
||||
void
|
||||
diff_init ()
|
||||
{
|
||||
/*NOSTRICT*/
|
||||
diff_buf = (char *) valloc ((unsigned) blocksize);
|
||||
if (!diff_buf)
|
||||
{
|
||||
msg ("could not allocate memory for diff buffer of %d bytes",
|
||||
blocksize);
|
||||
exit (EX_ARGSBAD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Diff a file against the archive.
|
||||
*/
|
||||
void
|
||||
diff_archive ()
|
||||
{
|
||||
register char *data;
|
||||
int check, namelen;
|
||||
int err;
|
||||
long offset;
|
||||
struct stat filestat;
|
||||
int compare_chunk ();
|
||||
int compare_dir ();
|
||||
int no_op ();
|
||||
#ifndef __MSDOS__
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
#endif
|
||||
char *get_dir_contents ();
|
||||
long from_oct ();
|
||||
|
||||
errno = EPIPE; /* FIXME, remove perrors */
|
||||
|
||||
saverec (&head); /* Make sure it sticks around */
|
||||
userec (head); /* And go past it in the archive */
|
||||
decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */
|
||||
|
||||
/* Print the record from 'head' and 'hstat' */
|
||||
if (f_verbose)
|
||||
{
|
||||
if (now_verifying)
|
||||
fprintf (msg_file, "Verify ");
|
||||
print_header ();
|
||||
}
|
||||
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
|
||||
default:
|
||||
msg ("Unknown file type '%c' for %s, diffed as normal file",
|
||||
head->header.linkflag, current_file_name);
|
||||
/* FALL THRU */
|
||||
|
||||
case LF_OLDNORMAL:
|
||||
case LF_NORMAL:
|
||||
case LF_SPARSE:
|
||||
case LF_CONTIG:
|
||||
/*
|
||||
* Appears to be a file.
|
||||
* See if it's really a directory.
|
||||
*/
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
if (current_file_name[namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
|
||||
if (do_stat (&filestat))
|
||||
{
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (!S_ISREG (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s: not a regular file\n",
|
||||
current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
filestat.st_mode &= 07777;
|
||||
if (filestat.st_mode != hstat.st_mode)
|
||||
sigh ("mode");
|
||||
if (filestat.st_uid != hstat.st_uid)
|
||||
sigh ("uid");
|
||||
if (filestat.st_gid != hstat.st_gid)
|
||||
sigh ("gid");
|
||||
if (filestat.st_mtime != hstat.st_mtime)
|
||||
sigh ("mod time");
|
||||
if (head->header.linkflag != LF_SPARSE &&
|
||||
filestat.st_size != hstat.st_size)
|
||||
{
|
||||
sigh ("size");
|
||||
skip_file ((long) hstat.st_size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
|
||||
|
||||
if (diff_fd < 0 && !f_absolute_paths)
|
||||
{
|
||||
char tmpbuf[NAMSIZ + 2];
|
||||
|
||||
tmpbuf[0] = '/';
|
||||
strcpy (&tmpbuf[1], current_file_name);
|
||||
diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY);
|
||||
}
|
||||
if (diff_fd < 0)
|
||||
{
|
||||
msg_perror ("cannot open %s", current_file_name);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
goto quit;
|
||||
}
|
||||
/*
|
||||
* Need to treat sparse files completely differently here.
|
||||
*/
|
||||
if (head->header.linkflag == LF_SPARSE)
|
||||
diff_sparse_files (hstat.st_size);
|
||||
else
|
||||
wantbytes ((long) (hstat.st_size), compare_chunk);
|
||||
|
||||
check = close (diff_fd);
|
||||
if (check < 0)
|
||||
msg_perror ("Error while closing %s", current_file_name);
|
||||
|
||||
quit:
|
||||
break;
|
||||
|
||||
#ifndef __MSDOS__
|
||||
case LF_LINK:
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
dev = filestat.st_dev;
|
||||
ino = filestat.st_ino;
|
||||
err = stat (current_link_name, &filestat);
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file, "%s: does not exist\n", current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg_perror ("cannot stat file %s", current_file_name);
|
||||
}
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
if (filestat.st_dev != dev || filestat.st_ino != ino)
|
||||
{
|
||||
fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISLNK
|
||||
case LF_SYMLINK:
|
||||
{
|
||||
char linkbuf[NAMSIZ + 3];
|
||||
check = readlink (current_file_name, linkbuf,
|
||||
(sizeof linkbuf) - 1);
|
||||
|
||||
if (check < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file,
|
||||
"%s: no such file or directory\n",
|
||||
current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg_perror ("cannot read link %s", current_file_name);
|
||||
}
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
linkbuf[check] = '\0'; /* Null-terminate it */
|
||||
if (strncmp (current_link_name, linkbuf, check) != 0)
|
||||
{
|
||||
fprintf (msg_file, "%s: symlink differs\n",
|
||||
current_link_name);
|
||||
different++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFCHR
|
||||
case LF_CHR:
|
||||
hstat.st_mode |= S_IFCHR;
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFBLK
|
||||
/* If local system doesn't support block devices, use default case */
|
||||
case LF_BLK:
|
||||
hstat.st_mode |= S_IFBLK;
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISFIFO
|
||||
/* If local system doesn't support FIFOs, use default case */
|
||||
case LF_FIFO:
|
||||
#ifdef S_IFIFO
|
||||
hstat.st_mode |= S_IFIFO;
|
||||
#endif
|
||||
hstat.st_rdev = 0; /* FIXME, do we need this? */
|
||||
goto check_node;
|
||||
#endif
|
||||
|
||||
check_node:
|
||||
/* FIXME, deal with umask */
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
if (hstat.st_rdev != filestat.st_rdev)
|
||||
{
|
||||
fprintf (msg_file, "%s: device numbers changed\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
#ifdef S_IFMT
|
||||
if (hstat.st_mode != filestat.st_mode)
|
||||
#else /* POSIX lossage */
|
||||
if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777))
|
||||
#endif
|
||||
{
|
||||
fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_DUMPDIR:
|
||||
data = diff_dir = get_dir_contents (current_file_name, 0);
|
||||
if (data)
|
||||
{
|
||||
wantbytes ((long) (hstat.st_size), compare_dir);
|
||||
free (data);
|
||||
}
|
||||
else
|
||||
wantbytes ((long) (hstat.st_size), no_op);
|
||||
/* FALL THROUGH */
|
||||
|
||||
case LF_DIR:
|
||||
/* Check for trailing / */
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
really_dir:
|
||||
while (namelen && current_file_name[namelen] == '/')
|
||||
current_file_name[namelen--] = '\0'; /* Zap / */
|
||||
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
if (!S_ISDIR (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s is no longer a directory\n", current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777))
|
||||
sigh ("mode");
|
||||
break;
|
||||
|
||||
case LF_VOLHDR:
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
namelen = strlen (current_file_name) - 1;
|
||||
if (current_file_name[namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
if (do_stat (&filestat))
|
||||
break;
|
||||
|
||||
if (!S_ISREG (filestat.st_mode))
|
||||
{
|
||||
fprintf (msg_file, "%s: not a regular file\n",
|
||||
current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
filestat.st_mode &= 07777;
|
||||
offset = from_oct (1 + 12, head->header.offset);
|
||||
if (filestat.st_size != hstat.st_size + offset)
|
||||
{
|
||||
sigh ("size");
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
|
||||
|
||||
if (diff_fd < 0)
|
||||
{
|
||||
msg_perror ("cannot open file %s", current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
err = lseek (diff_fd, offset, 0);
|
||||
if (err != offset)
|
||||
{
|
||||
msg_perror ("cannot seek to %ld in file %s", offset, current_file_name);
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
|
||||
wantbytes ((long) (hstat.st_size), compare_chunk);
|
||||
|
||||
check = close (diff_fd);
|
||||
if (check < 0)
|
||||
{
|
||||
msg_perror ("Error while closing %s", current_file_name);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* We don't need to save it any longer. */
|
||||
saverec ((union record **) 0);/* Unsave it */
|
||||
}
|
||||
|
||||
int
|
||||
compare_chunk (bytes, buffer)
|
||||
long bytes;
|
||||
char *buffer;
|
||||
{
|
||||
int err;
|
||||
|
||||
err = read (diff_fd, diff_buf, bytes);
|
||||
if (err != bytes)
|
||||
{
|
||||
if (err < 0)
|
||||
{
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (msg_file, "%s: could only read %d of %ld bytes\n",
|
||||
current_file_name, err, bytes);
|
||||
}
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
if (bcmp (buffer, diff_buf, bytes))
|
||||
{
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
compare_dir (bytes, buffer)
|
||||
long bytes;
|
||||
char *buffer;
|
||||
{
|
||||
if (bcmp (buffer, diff_dir, bytes))
|
||||
{
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
different++;
|
||||
return -1;
|
||||
}
|
||||
diff_dir += bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sigh about something that differs.
|
||||
*/
|
||||
void
|
||||
sigh (what)
|
||||
char *what;
|
||||
{
|
||||
|
||||
fprintf (msg_file, "%s: %s differs\n",
|
||||
current_file_name, what);
|
||||
}
|
||||
|
||||
void
|
||||
verify_volume ()
|
||||
{
|
||||
int status;
|
||||
#ifdef MTIOCTOP
|
||||
struct mtop t;
|
||||
int er;
|
||||
#endif
|
||||
|
||||
current_file_name = NULL;
|
||||
current_link_name = NULL;
|
||||
if (!diff_buf)
|
||||
diff_init ();
|
||||
#ifdef MTIOCTOP
|
||||
t.mt_op = MTBSF;
|
||||
t.mt_count = 1;
|
||||
if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
|
||||
{
|
||||
if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
|
||||
{
|
||||
#endif
|
||||
if (rmtlseek (archive, 0L, 0) != 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method */
|
||||
msg_perror ("Couldn't rewind archive file for verify");
|
||||
return;
|
||||
}
|
||||
#ifdef MTIOCTOP
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ar_reading = 1;
|
||||
now_verifying = 1;
|
||||
fl_read ();
|
||||
for (;;)
|
||||
{
|
||||
status = read_header ();
|
||||
if (status == 0)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
n++;
|
||||
status = read_header ();
|
||||
}
|
||||
while (status == 0);
|
||||
msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s");
|
||||
}
|
||||
if (status == 2 || status == EOF)
|
||||
break;
|
||||
diff_archive ();
|
||||
}
|
||||
ar_reading = 0;
|
||||
now_verifying = 0;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
do_stat (statp)
|
||||
struct stat *statp;
|
||||
{
|
||||
int err;
|
||||
|
||||
err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp);
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (msg_file, "%s: does not exist\n", current_file_name);
|
||||
}
|
||||
else
|
||||
msg_perror ("can't stat file %s", current_file_name);
|
||||
/* skip_file((long)hstat.st_size);
|
||||
different++;*/
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* JK
|
||||
* Diff'ing a sparse file with its counterpart on the tar file is a
|
||||
* bit of a different story than a normal file. First, we must know
|
||||
* what areas of the file to skip through, i.e., we need to contruct
|
||||
* a sparsearray, which will hold all the information we need. We must
|
||||
* compare small amounts of data at a time as we find it.
|
||||
*/
|
||||
|
||||
void
|
||||
diff_sparse_files (filesize)
|
||||
int filesize;
|
||||
|
||||
{
|
||||
int sparse_ind = 0;
|
||||
char *buf;
|
||||
int buf_size = RECORDSIZE;
|
||||
union record *datarec;
|
||||
int err;
|
||||
long numbytes;
|
||||
/* int amt_read = 0;*/
|
||||
int size = filesize;
|
||||
|
||||
buf = (char *) ck_malloc (buf_size * sizeof (char));
|
||||
|
||||
fill_in_sparse_array ();
|
||||
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
datarec = findrec ();
|
||||
if (!sparsearray[sparse_ind].numbytes)
|
||||
break;
|
||||
|
||||
/*
|
||||
* 'numbytes' is nicer to write than
|
||||
* 'sparsearray[sparse_ind].numbytes' all the time ...
|
||||
*/
|
||||
numbytes = sparsearray[sparse_ind].numbytes;
|
||||
|
||||
lseek (diff_fd, sparsearray[sparse_ind].offset, 0);
|
||||
/*
|
||||
* take care to not run out of room in our buffer
|
||||
*/
|
||||
while (buf_size < numbytes)
|
||||
{
|
||||
buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char));
|
||||
buf_size *= 2;
|
||||
}
|
||||
while (numbytes > RECORDSIZE)
|
||||
{
|
||||
if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE)
|
||||
{
|
||||
if (err < 0)
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
else
|
||||
fprintf (msg_file, "%s: could only read %d of %ld bytes\n",
|
||||
current_file_name, err, numbytes);
|
||||
break;
|
||||
}
|
||||
if (bcmp (buf, datarec->charptr, RECORDSIZE))
|
||||
{
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
numbytes -= err;
|
||||
size -= err;
|
||||
userec (datarec);
|
||||
datarec = findrec ();
|
||||
}
|
||||
if ((err = read (diff_fd, buf, numbytes)) != numbytes)
|
||||
{
|
||||
if (err < 0)
|
||||
msg_perror ("can't read %s", current_file_name);
|
||||
else
|
||||
fprintf (msg_file, "%s: could only read %d of %ld bytes\n",
|
||||
current_file_name, err, numbytes);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bcmp (buf, datarec->charptr, numbytes))
|
||||
{
|
||||
different++;
|
||||
break;
|
||||
}
|
||||
/* amt_read += numbytes;
|
||||
if (amt_read >= RECORDSIZE) {
|
||||
amt_read = 0;
|
||||
userec(datarec);
|
||||
datarec = findrec();
|
||||
}*/
|
||||
userec (datarec);
|
||||
sparse_ind++;
|
||||
size -= numbytes;
|
||||
}
|
||||
/*
|
||||
* if the number of bytes read isn't the
|
||||
* number of bytes supposedly in the file,
|
||||
* they're different
|
||||
*/
|
||||
/* if (amt_read != filesize)
|
||||
different++;*/
|
||||
userec (datarec);
|
||||
free (sparsearray);
|
||||
if (different)
|
||||
fprintf (msg_file, "%s: data differs\n", current_file_name);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* JK
|
||||
* This routine should be used more often than it is ... look into
|
||||
* that. Anyhow, what it does is translate the sparse information
|
||||
* on the header, and in any subsequent extended headers, into an
|
||||
* array of structures with true numbers, as opposed to character
|
||||
* strings. It simply makes our life much easier, doing so many
|
||||
* comparisong and such.
|
||||
*/
|
||||
void
|
||||
fill_in_sparse_array ()
|
||||
{
|
||||
int ind;
|
||||
|
||||
/*
|
||||
* allocate space for our scratch space; it's initially
|
||||
* 10 elements long, but can change in this routine if
|
||||
* necessary
|
||||
*/
|
||||
sp_array_size = 10;
|
||||
sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
|
||||
|
||||
/*
|
||||
* there are at most five of these structures in the header
|
||||
* itself; read these in first
|
||||
*/
|
||||
for (ind = 0; ind < SPARSE_IN_HDR; ind++)
|
||||
{
|
||||
if (!head->header.sp[ind].numbytes)
|
||||
break;
|
||||
sparsearray[ind].offset =
|
||||
from_oct (1 + 12, head->header.sp[ind].offset);
|
||||
sparsearray[ind].numbytes =
|
||||
from_oct (1 + 12, head->header.sp[ind].numbytes);
|
||||
}
|
||||
/*
|
||||
* if the header's extended, we gotta read in exhdr's till
|
||||
* we're done
|
||||
*/
|
||||
if (head->header.isextended)
|
||||
{
|
||||
/* how far into the sparsearray we are 'so far' */
|
||||
static int so_far_ind = SPARSE_IN_HDR;
|
||||
union record *exhdr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
exhdr = findrec ();
|
||||
for (ind = 0; ind < SPARSE_EXT_HDR; ind++)
|
||||
{
|
||||
if (ind + so_far_ind > sp_array_size - 1)
|
||||
{
|
||||
/*
|
||||
* we just ran out of room in our
|
||||
* scratch area - realloc it
|
||||
*/
|
||||
sparsearray = (struct sp_array *)
|
||||
ck_realloc (sparsearray,
|
||||
sp_array_size * 2 * sizeof (struct sp_array));
|
||||
sp_array_size *= 2;
|
||||
}
|
||||
/*
|
||||
* convert the character strings into longs
|
||||
*/
|
||||
sparsearray[ind + so_far_ind].offset =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset);
|
||||
sparsearray[ind + so_far_ind].numbytes =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes);
|
||||
}
|
||||
/*
|
||||
* if this is the last extended header for this
|
||||
* file, we can stop
|
||||
*/
|
||||
if (!exhdr->ext_hdr.isextended)
|
||||
break;
|
||||
else
|
||||
{
|
||||
so_far_ind += SPARSE_EXT_HDR;
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
/* be sure to skip past the last one */
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
@ -1,946 +0,0 @@
|
||||
/* Extract files from a tar archive.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Extract files from a tar archive.
|
||||
*
|
||||
* Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
time_t time ();
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_OPEN3
|
||||
/* We need the #define's even though we don't use them. */
|
||||
#include "open3.h"
|
||||
#endif
|
||||
|
||||
#ifdef EMUL_OPEN3
|
||||
/* Simulated 3-argument open for systems that don't have it */
|
||||
#include "open3.h"
|
||||
#endif
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
#if defined(_POSIX_VERSION)
|
||||
#include <utime.h>
|
||||
#else
|
||||
struct utimbuf
|
||||
{
|
||||
long actime;
|
||||
long modtime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *msg_file;
|
||||
|
||||
extern union record *head; /* Points to current tape header */
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
extern int head_standard; /* Tape header is in ANSI format */
|
||||
|
||||
extern char *save_name;
|
||||
extern long save_totsize;
|
||||
extern long save_sizeleft;
|
||||
|
||||
int confirm ();
|
||||
void decode_header ();
|
||||
void extract_mangle ();
|
||||
void extract_sparse_file ();
|
||||
long from_oct ();
|
||||
void gnu_restore ();
|
||||
extern void print_header ();
|
||||
extern void skip_file ();
|
||||
extern void skip_extended_headers ();
|
||||
extern void pr_mkdir ();
|
||||
void saverec ();
|
||||
|
||||
int make_dirs (); /* Makes required directories */
|
||||
|
||||
static time_t now = 0; /* Current time */
|
||||
static we_are_root = 0; /* True if our effective uid == 0 */
|
||||
static int notumask = ~0; /* Masks out bits user doesn't want */
|
||||
|
||||
/*
|
||||
* "Scratch" space to store the information about a sparse file before
|
||||
* writing the info into the header or extended header
|
||||
*/
|
||||
/*struct sp_array *sparsearray;*/
|
||||
|
||||
/* number of elts storable in the sparsearray */
|
||||
/*int sp_array_size = 10;*/
|
||||
|
||||
struct saved_dir_info
|
||||
{
|
||||
char *path;
|
||||
int mode;
|
||||
int atime;
|
||||
int mtime;
|
||||
struct saved_dir_info *next;
|
||||
};
|
||||
|
||||
struct saved_dir_info *saved_dir_info_head;
|
||||
|
||||
/*
|
||||
* Set up to extract files.
|
||||
*/
|
||||
void
|
||||
extr_init ()
|
||||
{
|
||||
int ourmask;
|
||||
|
||||
now = time ((time_t *) 0);
|
||||
if (geteuid () == 0)
|
||||
we_are_root = 1;
|
||||
|
||||
/*
|
||||
* We need to know our umask. But if f_use_protection is set,
|
||||
* leave our kernel umask at 0, and our "notumask" at ~0.
|
||||
*/
|
||||
ourmask = umask (0); /* Read it */
|
||||
if (!f_use_protection)
|
||||
{
|
||||
(void) umask (ourmask); /* Set it back how it was */
|
||||
notumask = ~ourmask; /* Make umask override permissions */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extract a file from the archive.
|
||||
*/
|
||||
void
|
||||
extract_archive ()
|
||||
{
|
||||
register char *data;
|
||||
int fd, check, namelen, written, openflag;
|
||||
long size;
|
||||
struct utimbuf acc_upd_times;
|
||||
register int skipcrud;
|
||||
register int i;
|
||||
/* int sparse_ind = 0;*/
|
||||
union record *exhdr;
|
||||
struct saved_dir_info *tmp;
|
||||
/* int end_nulls; */
|
||||
|
||||
saverec (&head); /* Make sure it sticks around */
|
||||
userec (head); /* And go past it in the archive */
|
||||
decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */
|
||||
|
||||
if ((f_confirm && !confirm ("extract", current_file_name)) ||
|
||||
(f_exstdout && head->header.linkflag != LF_OLDNORMAL &&
|
||||
head->header.linkflag != LF_NORMAL &&
|
||||
head->header.linkflag != LF_CONTIG))
|
||||
{
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
saverec ((union record **) 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print the record from 'head' and 'hstat' */
|
||||
if (f_verbose)
|
||||
print_header ();
|
||||
|
||||
/*
|
||||
* Check for fully specified pathnames and other atrocities.
|
||||
*
|
||||
* Note, we can't just make a pointer to the new file name,
|
||||
* since saverec() might move the header and adjust "head".
|
||||
* We have to start from "head" every time we want to touch
|
||||
* the header record.
|
||||
*/
|
||||
skipcrud = 0;
|
||||
while (!f_absolute_paths
|
||||
&& '/' == current_file_name[skipcrud])
|
||||
{
|
||||
static int warned_once = 0;
|
||||
|
||||
skipcrud++; /* Force relative path */
|
||||
if (!warned_once++)
|
||||
{
|
||||
msg ("Removing leading / from absolute path names in the archive.");
|
||||
}
|
||||
}
|
||||
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
|
||||
default:
|
||||
msg ("Unknown file type '%c' for %s, extracted as normal file",
|
||||
head->header.linkflag, skipcrud + current_file_name);
|
||||
/* FALL THRU */
|
||||
|
||||
/*
|
||||
* JK - What we want to do if the file is sparse is loop through
|
||||
* the array of sparse structures in the header and read in
|
||||
* and translate the character strings representing 1) the offset
|
||||
* at which to write and 2) how many bytes to write into numbers,
|
||||
* which we store into the scratch array, "sparsearray". This
|
||||
* array makes our life easier the same way it did in creating
|
||||
* the tar file that had to deal with a sparse file.
|
||||
*
|
||||
* After we read in the first five (at most) sparse structures,
|
||||
* we check to see if the file has an extended header, i.e.,
|
||||
* if more sparse structures are needed to describe the contents
|
||||
* of the new file. If so, we read in the extended headers
|
||||
* and continue to store their contents into the sparsearray.
|
||||
*/
|
||||
case LF_SPARSE:
|
||||
sp_array_size = 10;
|
||||
sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
|
||||
for (i = 0; i < SPARSE_IN_HDR; i++)
|
||||
{
|
||||
sparsearray[i].offset =
|
||||
from_oct (1 + 12, head->header.sp[i].offset);
|
||||
sparsearray[i].numbytes =
|
||||
from_oct (1 + 12, head->header.sp[i].numbytes);
|
||||
if (!sparsearray[i].numbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
/* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
|
||||
|
||||
if (head->header.isextended)
|
||||
{
|
||||
/* read in the list of extended headers
|
||||
and translate them into the sparsearray
|
||||
as before */
|
||||
|
||||
/* static */ int ind = SPARSE_IN_HDR;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
exhdr = findrec ();
|
||||
for (i = 0; i < SPARSE_EXT_HDR; i++)
|
||||
{
|
||||
|
||||
if (i + ind > sp_array_size - 1)
|
||||
{
|
||||
/*
|
||||
* realloc the scratch area
|
||||
* since we've run out of room --
|
||||
*/
|
||||
sparsearray = (struct sp_array *)
|
||||
ck_realloc (sparsearray,
|
||||
2 * sp_array_size * (sizeof (struct sp_array)));
|
||||
sp_array_size *= 2;
|
||||
}
|
||||
if (!exhdr->ext_hdr.sp[i].numbytes)
|
||||
break;
|
||||
sparsearray[i + ind].offset =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset);
|
||||
sparsearray[i + ind].numbytes =
|
||||
from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes);
|
||||
}
|
||||
if (!exhdr->ext_hdr.isextended)
|
||||
break;
|
||||
else
|
||||
{
|
||||
ind += SPARSE_EXT_HDR;
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
userec (exhdr);
|
||||
}
|
||||
|
||||
/* FALL THRU */
|
||||
case LF_OLDNORMAL:
|
||||
case LF_NORMAL:
|
||||
case LF_CONTIG:
|
||||
/*
|
||||
* Appears to be a file.
|
||||
* See if it's really a directory.
|
||||
*/
|
||||
namelen = strlen (skipcrud + current_file_name) - 1;
|
||||
if (current_file_name[skipcrud + namelen] == '/')
|
||||
goto really_dir;
|
||||
|
||||
/* FIXME, deal with protection issues */
|
||||
again_file:
|
||||
openflag = (f_keep ?
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
|
||||
| ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
|
||||
/*
|
||||
* JK - The last | is a kludge to solve the problem
|
||||
* the O_APPEND flag causes with files we are
|
||||
* trying to make sparse: when a file is opened
|
||||
* with O_APPEND, it writes to the last place
|
||||
* that something was written, thereby ignoring
|
||||
* any lseeks that we have done. We add this
|
||||
* extra condition to make it able to lseek when
|
||||
* a file is sparse, i.e., we don't open the new
|
||||
* file with this flag. (Grump -- this bug caused
|
||||
* me to waste a good deal of time, I might add)
|
||||
*/
|
||||
|
||||
if (f_exstdout)
|
||||
{
|
||||
fd = 1;
|
||||
goto extract_file;
|
||||
}
|
||||
|
||||
if (f_unlink && !f_keep) {
|
||||
if (unlink(skipcrud + current_file_name) == -1)
|
||||
if (errno != ENOENT)
|
||||
msg_perror ("Could not unlink %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
#ifdef O_CTG
|
||||
/*
|
||||
* Contiguous files (on the Masscomp) have to specify
|
||||
* the size in the open call that creates them.
|
||||
*/
|
||||
if (head->header.linkflag == LF_CONTIG)
|
||||
fd = open ((longname ? longname : head->header.name)
|
||||
+ skipcrud,
|
||||
openflag | O_CTG,
|
||||
hstat.st_mode, hstat.st_size);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NO_OPEN3
|
||||
/*
|
||||
* On raw V7 we won't let them specify -k (f_keep), but
|
||||
* we just bull ahead and create the files.
|
||||
*/
|
||||
fd = creat ((longname
|
||||
? longname
|
||||
: head->header.name) + skipcrud,
|
||||
hstat.st_mode);
|
||||
#else
|
||||
/*
|
||||
* With 3-arg open(), we can do this up right.
|
||||
*/
|
||||
fd = open (skipcrud + current_file_name,
|
||||
openflag, hstat.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_file;
|
||||
msg_perror ("Could not create file %s",
|
||||
skipcrud + current_file_name);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
extract_file:
|
||||
if (head->header.linkflag == LF_SPARSE)
|
||||
{
|
||||
char *name;
|
||||
int namelen;
|
||||
|
||||
/*
|
||||
* Kludge alert. NAME is assigned to header.name
|
||||
* because during the extraction, the space that
|
||||
* contains the header will get scribbled on, and
|
||||
* the name will get munged, so any error messages
|
||||
* that happen to contain the filename will look
|
||||
* REAL interesting unless we do this.
|
||||
*/
|
||||
namelen = strlen (skipcrud + current_file_name) + 1;
|
||||
name = (char *) ck_malloc ((sizeof (char)) * namelen);
|
||||
bcopy (skipcrud + current_file_name, name, namelen);
|
||||
size = hstat.st_size;
|
||||
extract_sparse_file (fd, &size, hstat.st_size, name);
|
||||
}
|
||||
else
|
||||
for (size = hstat.st_size;
|
||||
size > 0;
|
||||
size -= written)
|
||||
{
|
||||
|
||||
/* long offset,
|
||||
numbytes;*/
|
||||
|
||||
if (f_multivol)
|
||||
{
|
||||
save_name = current_file_name;
|
||||
save_totsize = hstat.st_size;
|
||||
save_sizeleft = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate data, determine max length
|
||||
* writeable, write it, record that
|
||||
* we have used the data, then check
|
||||
* if the write worked.
|
||||
*/
|
||||
data = findrec ()->charptr;
|
||||
if (data == NULL)
|
||||
{ /* Check it... */
|
||||
msg ("Unexpected EOF on archive file");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* JK - If the file is sparse, use the sparsearray
|
||||
* that we created before to lseek into the new
|
||||
* file the proper amount, and to see how many
|
||||
* bytes we want to write at that position.
|
||||
*/
|
||||
/* if (head->header.linkflag == LF_SPARSE) {
|
||||
off_t pos;
|
||||
|
||||
pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
|
||||
printf("%d at %d\n", (int) pos, sparse_ind);
|
||||
written = sparsearray[sparse_ind++].numbytes;
|
||||
} else*/
|
||||
written = endofrecs ()->charptr - data;
|
||||
if (written > size)
|
||||
written = size;
|
||||
errno = 0;
|
||||
check = write (fd, data, written);
|
||||
/*
|
||||
* The following is in violation of strict
|
||||
* typing, since the arg to userec
|
||||
* should be a struct rec *. FIXME.
|
||||
*/
|
||||
userec ((union record *) (data + written - 1));
|
||||
if (check == written)
|
||||
continue;
|
||||
/*
|
||||
* Error in writing to file.
|
||||
* Print it, skip to next file in archive.
|
||||
*/
|
||||
if (check < 0)
|
||||
msg_perror ("couldn't write to file %s",
|
||||
skipcrud + current_file_name);
|
||||
else
|
||||
msg ("could only write %d of %d bytes to file %s",
|
||||
check, written, skipcrud + current_file_name);
|
||||
skip_file ((long) (size - written));
|
||||
break; /* Still do the close, mod time, chmod, etc */
|
||||
}
|
||||
|
||||
if (f_multivol)
|
||||
save_name = 0;
|
||||
|
||||
/* If writing to stdout, don't try to do anything
|
||||
to the filename; it doesn't exist, or we don't
|
||||
want to touch it anyway */
|
||||
if (f_exstdout)
|
||||
break;
|
||||
|
||||
/* if (head->header.isextended) {
|
||||
register union record *exhdr;
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < 21; i++) {
|
||||
long offset;
|
||||
|
||||
if (!exhdr->ext_hdr.sp[i].numbytes)
|
||||
break;
|
||||
offset = from_oct(1+12,
|
||||
exhdr->ext_hdr.sp[i].offset);
|
||||
written = from_oct(1+12,
|
||||
exhdr->ext_hdr.sp[i].numbytes);
|
||||
lseek(fd, offset, 0);
|
||||
check = write(fd, data, written);
|
||||
if (check == written) continue;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}*/
|
||||
check = close (fd);
|
||||
if (check < 0)
|
||||
{
|
||||
msg_perror ("Error while closing %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
|
||||
set_filestat:
|
||||
|
||||
/*
|
||||
* If we are root, set the owner and group of the extracted
|
||||
* file. This does what is wanted both on real Unix and on
|
||||
* System V. If we are running as a user, we extract as that
|
||||
* user; if running as root, we extract as the original owner.
|
||||
*/
|
||||
if (we_are_root || f_do_chown)
|
||||
{
|
||||
if (chown (skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot chown file %s to uid %d gid %d",
|
||||
skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the modified time of the file.
|
||||
*
|
||||
* Note that we set the accessed time to "now", which
|
||||
* is really "the time we started extracting files".
|
||||
* unless f_gnudump is used, in which case .st_atime is used
|
||||
*/
|
||||
if (!f_modified)
|
||||
{
|
||||
/* fixme if f_gnudump should set ctime too, but how? */
|
||||
if (f_gnudump)
|
||||
acc_upd_times.actime = hstat.st_atime;
|
||||
else
|
||||
acc_upd_times.actime = now; /* Accessed now */
|
||||
acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */
|
||||
if (utime (skipcrud + current_file_name,
|
||||
&acc_upd_times) < 0)
|
||||
{
|
||||
msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
|
||||
}
|
||||
}
|
||||
/* We do the utime before the chmod because some versions of
|
||||
utime are broken and trash the modes of the file. Since
|
||||
we then change the mode anyway, we don't care. . . */
|
||||
|
||||
/*
|
||||
* If '-k' is not set, open() or creat() could have saved
|
||||
* the permission bits from a previously created file,
|
||||
* ignoring the ones we specified.
|
||||
* Even if -k is set, if the file has abnormal
|
||||
* mode bits, we must chmod since writing or chown() has
|
||||
* probably reset them.
|
||||
*
|
||||
* If -k is set, we know *we* created this file, so the mode
|
||||
* bits were set by our open(). If the file is "normal", we
|
||||
* skip the chmod. This works because we did umask(0) if -p
|
||||
* is set, so umask will have left the specified mode alone.
|
||||
*/
|
||||
if ((!f_keep)
|
||||
|| (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to 0%o",
|
||||
skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
quit:
|
||||
break;
|
||||
|
||||
case LF_LINK:
|
||||
again_link:
|
||||
{
|
||||
struct stat st1, st2;
|
||||
|
||||
if (f_unlink && !f_keep) {
|
||||
if (unlink(skipcrud + current_file_name) == -1)
|
||||
if (errno != ENOENT)
|
||||
msg_perror ("Could not unlink %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
check = link (current_link_name, skipcrud + current_file_name);
|
||||
|
||||
if (check == 0)
|
||||
break;
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_link;
|
||||
if (f_gnudump && errno == EEXIST)
|
||||
break;
|
||||
if (stat (current_link_name, &st1) == 0
|
||||
&& stat (current_file_name + skipcrud, &st2) == 0
|
||||
&& st1.st_dev == st2.st_dev
|
||||
&& st1.st_ino == st2.st_ino)
|
||||
break;
|
||||
msg_perror ("Could not link %s to %s",
|
||||
skipcrud + current_file_name,
|
||||
current_link_name);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef S_ISLNK
|
||||
case LF_SYMLINK:
|
||||
again_symlink:
|
||||
if (f_unlink && !f_keep) {
|
||||
if (unlink(skipcrud + current_file_name) == -1)
|
||||
if (errno != ENOENT)
|
||||
msg_perror ("Could not unlink %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
check = symlink (current_link_name,
|
||||
skipcrud + current_file_name);
|
||||
/* FIXME, don't worry uid, gid, etc... */
|
||||
if (check == 0)
|
||||
break;
|
||||
if (make_dirs (current_file_name + skipcrud))
|
||||
goto again_symlink;
|
||||
msg_perror ("Could not create symlink to %s",
|
||||
current_link_name);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFCHR
|
||||
case LF_CHR:
|
||||
hstat.st_mode |= S_IFCHR;
|
||||
goto make_node;
|
||||
#endif
|
||||
|
||||
#ifdef S_IFBLK
|
||||
case LF_BLK:
|
||||
hstat.st_mode |= S_IFBLK;
|
||||
#endif
|
||||
#if defined(S_IFCHR) || defined(S_IFBLK)
|
||||
make_node:
|
||||
if (f_unlink && !f_keep) {
|
||||
if (unlink(skipcrud + current_file_name) == -1)
|
||||
if (errno != ENOENT)
|
||||
msg_perror ("Could not unlink %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
check = mknod (current_file_name + skipcrud,
|
||||
(int) hstat.st_mode, (int) hstat.st_rdev);
|
||||
if (check != 0)
|
||||
{
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto make_node;
|
||||
msg_perror ("Could not make %s",
|
||||
current_file_name + skipcrud);
|
||||
break;
|
||||
};
|
||||
goto set_filestat;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISFIFO
|
||||
/* If local system doesn't support FIFOs, use default case */
|
||||
case LF_FIFO:
|
||||
make_fifo:
|
||||
if (f_unlink && !f_keep) {
|
||||
if (unlink(skipcrud + current_file_name) == -1)
|
||||
if (errno != ENOENT)
|
||||
msg_perror ("Could not unlink %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
check = mkfifo (current_file_name + skipcrud,
|
||||
(int) hstat.st_mode);
|
||||
if (check != 0)
|
||||
{
|
||||
if (make_dirs (current_file_name + skipcrud))
|
||||
goto make_fifo;
|
||||
msg_perror ("Could not make %s",
|
||||
skipcrud + current_file_name);
|
||||
break;
|
||||
};
|
||||
goto set_filestat;
|
||||
#endif
|
||||
|
||||
case LF_DIR:
|
||||
case LF_DUMPDIR:
|
||||
namelen = strlen (current_file_name + skipcrud) - 1;
|
||||
really_dir:
|
||||
/* Check for trailing /, and zap as many as we find. */
|
||||
while (namelen
|
||||
&& current_file_name[skipcrud + namelen] == '/')
|
||||
current_file_name[skipcrud + namelen--] = '\0';
|
||||
if (f_gnudump)
|
||||
{ /* Read the entry and delete files
|
||||
that aren't listed in the archive */
|
||||
gnu_restore (skipcrud);
|
||||
|
||||
}
|
||||
else if (head->header.linkflag == LF_DUMPDIR)
|
||||
skip_file ((long) (hstat.st_size));
|
||||
|
||||
|
||||
again_dir:
|
||||
check = mkdir (skipcrud + current_file_name,
|
||||
(we_are_root ? 0 : 0300) | (int) hstat.st_mode);
|
||||
if (check != 0)
|
||||
{
|
||||
struct stat st1;
|
||||
|
||||
if (make_dirs (skipcrud + current_file_name))
|
||||
goto again_dir;
|
||||
/* If we're trying to create '.', let it be. */
|
||||
if (current_file_name[skipcrud + namelen] == '.' &&
|
||||
(namelen == 0 ||
|
||||
current_file_name[skipcrud + namelen - 1] == '/'))
|
||||
goto check_perms;
|
||||
if (errno == EEXIST
|
||||
&& stat (skipcrud + current_file_name, &st1) == 0
|
||||
&& (S_ISDIR (st1.st_mode)))
|
||||
break;
|
||||
msg_perror ("Could not create directory %s", skipcrud + current_file_name);
|
||||
break;
|
||||
}
|
||||
|
||||
check_perms:
|
||||
if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
|
||||
{
|
||||
hstat.st_mode |= 0300;
|
||||
msg ("Added write and execute permission to directory %s",
|
||||
skipcrud + current_file_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are root, set the owner and group of the extracted
|
||||
* file. This does what is wanted both on real Unix and on
|
||||
* System V. If we are running as a user, we extract as that
|
||||
* user; if running as root, we extract as the original owner.
|
||||
*/
|
||||
if (we_are_root || f_do_chown)
|
||||
{
|
||||
if (chown (skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot chown file %s to uid %d gid %d",
|
||||
skipcrud + current_file_name,
|
||||
hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!f_modified)
|
||||
{
|
||||
tmp = ((struct saved_dir_info *)
|
||||
ck_malloc (sizeof (struct saved_dir_info)));
|
||||
tmp->path = (char *) ck_malloc (strlen (skipcrud
|
||||
+ current_file_name) + 1);
|
||||
strcpy (tmp->path, skipcrud + current_file_name);
|
||||
tmp->mode = hstat.st_mode;
|
||||
tmp->atime = hstat.st_atime;
|
||||
tmp->mtime = hstat.st_mtime;
|
||||
tmp->next = saved_dir_info_head;
|
||||
saved_dir_info_head = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This functions exactly as the code for set_filestat above. */
|
||||
if ((!f_keep)
|
||||
|| (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to 0%o",
|
||||
skipcrud + current_file_name,
|
||||
notumask & (int) hstat.st_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_VOLHDR:
|
||||
if (f_verbose)
|
||||
{
|
||||
printf ("Reading %s\n", current_file_name);
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_NAMES:
|
||||
extract_mangle (head);
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
|
||||
skip_file ((long) hstat.st_size);
|
||||
break;
|
||||
|
||||
case LF_LONGNAME:
|
||||
case LF_LONGLINK:
|
||||
msg ("Visible long name error\n");
|
||||
skip_file ((long) hstat.st_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We don't need to save it any longer. */
|
||||
saverec ((union record **) 0);/* Unsave it */
|
||||
}
|
||||
|
||||
/*
|
||||
* After a file/link/symlink/dir creation has failed, see if
|
||||
* it's because some required directory was not present, and if
|
||||
* so, create all required dirs.
|
||||
*/
|
||||
int
|
||||
make_dirs (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
char *p; /* Points into path */
|
||||
int madeone = 0; /* Did we do anything yet? */
|
||||
int save_errno = errno; /* Remember caller's errno */
|
||||
int check;
|
||||
|
||||
if (errno != ENOENT)
|
||||
return 0; /* Not our problem */
|
||||
|
||||
for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/'))
|
||||
{
|
||||
/* Avoid mkdir of empty string, if leading or double '/' */
|
||||
if (p == pathname || p[-1] == '/')
|
||||
continue;
|
||||
/* Avoid mkdir where last part of path is '.' */
|
||||
if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
|
||||
continue;
|
||||
*p = 0; /* Truncate the path there */
|
||||
check = mkdir (pathname, 0777); /* Try to create it as a dir */
|
||||
if (check == 0)
|
||||
{
|
||||
/* Fix ownership */
|
||||
if (we_are_root)
|
||||
{
|
||||
if (chown (pathname, hstat.st_uid,
|
||||
hstat.st_gid) < 0)
|
||||
{
|
||||
msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid);
|
||||
}
|
||||
}
|
||||
pr_mkdir (pathname, p - pathname, notumask & 0777);
|
||||
madeone++; /* Remember if we made one */
|
||||
*p = '/';
|
||||
continue;
|
||||
}
|
||||
*p = '/';
|
||||
if (errno == EEXIST) /* Directory already exists */
|
||||
continue;
|
||||
/*
|
||||
* Some other error in the mkdir. We return to the caller.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
errno = save_errno; /* Restore caller's errno */
|
||||
return madeone; /* Tell them to retry if we made one */
|
||||
}
|
||||
|
||||
void
|
||||
extract_sparse_file (fd, sizeleft, totalsize, name)
|
||||
int fd;
|
||||
long *sizeleft, totalsize;
|
||||
char *name;
|
||||
{
|
||||
/* register char *data;*/
|
||||
union record *datarec;
|
||||
int sparse_ind = 0;
|
||||
int written, count;
|
||||
|
||||
/* assuming sizeleft is initially totalsize */
|
||||
|
||||
|
||||
while (*sizeleft > 0)
|
||||
{
|
||||
datarec = findrec ();
|
||||
if (datarec == NULL)
|
||||
{
|
||||
msg ("Unexpected EOF on archive file");
|
||||
return;
|
||||
}
|
||||
lseek (fd, sparsearray[sparse_ind].offset, 0);
|
||||
written = sparsearray[sparse_ind++].numbytes;
|
||||
while (written > RECORDSIZE)
|
||||
{
|
||||
count = write (fd, datarec->charptr, RECORDSIZE);
|
||||
if (count < 0)
|
||||
msg_perror ("couldn't write to file %s", name);
|
||||
written -= count;
|
||||
*sizeleft -= count;
|
||||
userec (datarec);
|
||||
datarec = findrec ();
|
||||
}
|
||||
|
||||
count = write (fd, datarec->charptr, written);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
msg_perror ("couldn't write to file %s", name);
|
||||
}
|
||||
else if (count != written)
|
||||
{
|
||||
msg ("could only write %d of %d bytes to file %s", count,
|
||||
totalsize, name);
|
||||
skip_file ((long) (*sizeleft));
|
||||
}
|
||||
|
||||
written -= count;
|
||||
*sizeleft -= count;
|
||||
userec (datarec);
|
||||
}
|
||||
free (sparsearray);
|
||||
/* if (end_nulls) {
|
||||
register int i;
|
||||
|
||||
printf("%d\n", (int) end_nulls);
|
||||
for (i = 0; i < end_nulls; i++)
|
||||
write(fd, "\000", 1);
|
||||
}*/
|
||||
userec (datarec);
|
||||
}
|
||||
|
||||
/* Set back the utime and mode for all the extracted directories. */
|
||||
void
|
||||
restore_saved_dir_info ()
|
||||
{
|
||||
struct utimbuf acc_upd_times;
|
||||
|
||||
while (saved_dir_info_head != NULL)
|
||||
{
|
||||
/* fixme if f_gnudump should set ctime too, but how? */
|
||||
if (f_gnudump)
|
||||
acc_upd_times.actime = saved_dir_info_head->atime;
|
||||
else
|
||||
acc_upd_times.actime = now; /* Accessed now */
|
||||
acc_upd_times.modtime = saved_dir_info_head->mtime; /* Mod'd */
|
||||
if (utime (saved_dir_info_head->path, &acc_upd_times) < 0)
|
||||
{
|
||||
msg_perror ("couldn't change access and modification times of %s",
|
||||
saved_dir_info_head->path);
|
||||
}
|
||||
if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
{
|
||||
if (chmod (saved_dir_info_head->path,
|
||||
notumask & saved_dir_info_head->mode) < 0)
|
||||
{
|
||||
msg_perror ("cannot change mode of file %s to 0%o",
|
||||
saved_dir_info_head->path,
|
||||
notumask & saved_dir_info_head->mode);
|
||||
}
|
||||
}
|
||||
saved_dir_info_head = saved_dir_info_head->next;
|
||||
}
|
||||
}
|
@ -1,977 +0,0 @@
|
||||
%{
|
||||
/* $Revision: 2.1 $
|
||||
**
|
||||
** Originally written by Steven M. Bellovin <smb@research.att.com> while
|
||||
** at the University of North Carolina at Chapel Hill. Later tweaked by
|
||||
** a couple of people on Usenet. Completely overhauled by Rich $alz
|
||||
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
|
||||
** send any email to Rich.
|
||||
**
|
||||
** This grammar has eight shift/reduce conflicts.
|
||||
**
|
||||
** This code is in the public domain and has no copyright.
|
||||
*/
|
||||
/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
|
||||
/* SUPPRESS 288 on yyerrlab *//* Label unused */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifdef _AIX /* for Bison */
|
||||
#pragma alloca
|
||||
#else
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* The code at the top of get_date which figures out the offset of the
|
||||
current time zone checks various CPP symbols to see if special
|
||||
tricks are need, but defaults to using the gettimeofday system call.
|
||||
Include <sys/time.h> if that will be used. */
|
||||
|
||||
#if !defined (USG) && !defined (sgi) && !defined (__FreeBSD__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(vms)
|
||||
|
||||
#include <types.h>
|
||||
#include <time.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(USG) || !defined(HAVE_FTIME)
|
||||
/*
|
||||
** If you need to do a tzset() call to set the
|
||||
** timezone, and don't have ftime().
|
||||
*/
|
||||
struct timeb {
|
||||
time_t time; /* Seconds since the epoch */
|
||||
unsigned short millitm; /* Field not used */
|
||||
short timezone;
|
||||
short dstflag; /* Field not used */
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#endif /* defined(USG) && !defined(HAVE_FTIME) */
|
||||
|
||||
#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#if defined(_AIX)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#endif /* defined(BSD4_2) */
|
||||
|
||||
#endif /* defined(vms) */
|
||||
|
||||
#if defined (STDC_HEADERS) || defined (USG)
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if sgi
|
||||
#undef timezone
|
||||
#endif
|
||||
|
||||
extern struct tm *localtime();
|
||||
|
||||
#define yyparse getdate_yyparse
|
||||
#define yylex getdate_yylex
|
||||
#define yyerror getdate_yyerror
|
||||
|
||||
#if !defined(lint) && !defined(SABER)
|
||||
static char RCS[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* !defined(lint) && !defined(SABER) */
|
||||
|
||||
|
||||
#define EPOCH 1970
|
||||
#define HOUR(x) ((time_t)(x) * 60)
|
||||
#define SECSPERDAY (24L * 60L * 60L)
|
||||
|
||||
|
||||
/*
|
||||
** An entry in the lexical lookup table.
|
||||
*/
|
||||
typedef struct _TABLE {
|
||||
char *name;
|
||||
int type;
|
||||
time_t value;
|
||||
} TABLE;
|
||||
|
||||
|
||||
/*
|
||||
** Daylight-savings mode: on, off, or not yet known.
|
||||
*/
|
||||
typedef enum _DSTMODE {
|
||||
DSTon, DSToff, DSTmaybe
|
||||
} DSTMODE;
|
||||
|
||||
/*
|
||||
** Meridian: am, pm, or 24-hour style.
|
||||
*/
|
||||
typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} MERIDIAN;
|
||||
|
||||
|
||||
/*
|
||||
** Global variables. We could get rid of most of these by using a good
|
||||
** union as the yacc stack. (This routine was originally written before
|
||||
** yacc had the %union construct.) Maybe someday; right now we only use
|
||||
** the %union very rarely.
|
||||
*/
|
||||
static char *yyInput;
|
||||
static DSTMODE yyDSTmode;
|
||||
static time_t yyDayOrdinal;
|
||||
static time_t yyDayNumber;
|
||||
static int yyHaveDate;
|
||||
static int yyHaveDay;
|
||||
static int yyHaveRel;
|
||||
static int yyHaveTime;
|
||||
static int yyHaveZone;
|
||||
static time_t yyTimezone;
|
||||
static time_t yyDay;
|
||||
static time_t yyHour;
|
||||
static time_t yyMinutes;
|
||||
static time_t yyMonth;
|
||||
static time_t yySeconds;
|
||||
static time_t yyYear;
|
||||
static MERIDIAN yyMeridian;
|
||||
static time_t yyRelMonth;
|
||||
static time_t yyRelSeconds;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
time_t Number;
|
||||
enum _MERIDIAN Meridian;
|
||||
}
|
||||
|
||||
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
|
||||
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
|
||||
|
||||
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
|
||||
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
|
||||
%type <Meridian> tMERIDIAN o_merid
|
||||
|
||||
%%
|
||||
|
||||
spec : /* NULL */
|
||||
| spec item
|
||||
;
|
||||
|
||||
item : time {
|
||||
yyHaveTime++;
|
||||
}
|
||||
| zone {
|
||||
yyHaveZone++;
|
||||
}
|
||||
| date {
|
||||
yyHaveDate++;
|
||||
}
|
||||
| day {
|
||||
yyHaveDay++;
|
||||
}
|
||||
| rel {
|
||||
yyHaveRel++;
|
||||
}
|
||||
| number
|
||||
;
|
||||
|
||||
time : tUNUMBER tMERIDIAN {
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $2;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $4;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yyMeridian = MER24;
|
||||
yyDSTmode = DSToff;
|
||||
yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = $6;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = MER24;
|
||||
yyDSTmode = DSToff;
|
||||
yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
|
||||
}
|
||||
;
|
||||
|
||||
zone : tZONE {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSToff;
|
||||
}
|
||||
| tDAYZONE {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSTon;
|
||||
}
|
||||
|
|
||||
tZONE tDST {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSTon;
|
||||
}
|
||||
;
|
||||
|
||||
day : tDAY {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
}
|
||||
| tDAY ',' {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
}
|
||||
| tUNUMBER tDAY {
|
||||
yyDayOrdinal = $1;
|
||||
yyDayNumber = $2;
|
||||
}
|
||||
;
|
||||
|
||||
date : tUNUMBER '/' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
}
|
||||
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
yyYear = $5;
|
||||
}
|
||||
| tUNUMBER tSNUMBER tSNUMBER {
|
||||
/* ISO 8601 format. yyyy-mm-dd. */
|
||||
yyYear = $1;
|
||||
yyMonth = -$2;
|
||||
yyDay = -$3;
|
||||
}
|
||||
| tMONTH tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
}
|
||||
| tMONTH tUNUMBER ',' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
yyYear = $4;
|
||||
}
|
||||
| tUNUMBER tMONTH {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
}
|
||||
| tUNUMBER tMONTH tUNUMBER {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
yyYear = $3;
|
||||
}
|
||||
;
|
||||
|
||||
rel : relunit tAGO {
|
||||
yyRelSeconds = -yyRelSeconds;
|
||||
yyRelMonth = -yyRelMonth;
|
||||
}
|
||||
| relunit
|
||||
;
|
||||
|
||||
relunit : tUNUMBER tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * $2 * 60L;
|
||||
}
|
||||
| tSNUMBER tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * $2 * 60L;
|
||||
}
|
||||
| tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * 60L;
|
||||
}
|
||||
| tSNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1;
|
||||
}
|
||||
| tUNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1;
|
||||
}
|
||||
| tSEC_UNIT {
|
||||
yyRelSeconds++;
|
||||
}
|
||||
| tSNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tUNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tMONTH_UNIT {
|
||||
yyRelMonth += $1;
|
||||
}
|
||||
;
|
||||
|
||||
number : tUNUMBER {
|
||||
if (yyHaveTime && yyHaveDate && !yyHaveRel)
|
||||
yyYear = $1;
|
||||
else {
|
||||
if($1>10000) {
|
||||
time_t date_part;
|
||||
|
||||
date_part= $1/10000;
|
||||
yyHaveDate++;
|
||||
yyDay= (date_part)%100;
|
||||
yyMonth= (date_part/100)%100;
|
||||
yyYear = date_part/10000;
|
||||
}
|
||||
yyHaveTime++;
|
||||
if ($1 < 100) {
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
}
|
||||
else {
|
||||
yyHour = $1 / 100;
|
||||
yyMinutes = $1 % 100;
|
||||
}
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
o_merid : /* NULL */ {
|
||||
$$ = MER24;
|
||||
}
|
||||
| tMERIDIAN {
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
/* Month and day table. */
|
||||
static TABLE const MonthDayTable[] = {
|
||||
{ "january", tMONTH, 1 },
|
||||
{ "february", tMONTH, 2 },
|
||||
{ "march", tMONTH, 3 },
|
||||
{ "april", tMONTH, 4 },
|
||||
{ "may", tMONTH, 5 },
|
||||
{ "june", tMONTH, 6 },
|
||||
{ "july", tMONTH, 7 },
|
||||
{ "august", tMONTH, 8 },
|
||||
{ "september", tMONTH, 9 },
|
||||
{ "sept", tMONTH, 9 },
|
||||
{ "october", tMONTH, 10 },
|
||||
{ "november", tMONTH, 11 },
|
||||
{ "december", tMONTH, 12 },
|
||||
{ "sunday", tDAY, 0 },
|
||||
{ "monday", tDAY, 1 },
|
||||
{ "tuesday", tDAY, 2 },
|
||||
{ "tues", tDAY, 2 },
|
||||
{ "wednesday", tDAY, 3 },
|
||||
{ "wednes", tDAY, 3 },
|
||||
{ "thursday", tDAY, 4 },
|
||||
{ "thur", tDAY, 4 },
|
||||
{ "thurs", tDAY, 4 },
|
||||
{ "friday", tDAY, 5 },
|
||||
{ "saturday", tDAY, 6 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Time units table. */
|
||||
static TABLE const UnitsTable[] = {
|
||||
{ "year", tMONTH_UNIT, 12 },
|
||||
{ "month", tMONTH_UNIT, 1 },
|
||||
{ "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
|
||||
{ "week", tMINUTE_UNIT, 7 * 24 * 60 },
|
||||
{ "day", tMINUTE_UNIT, 1 * 24 * 60 },
|
||||
{ "hour", tMINUTE_UNIT, 60 },
|
||||
{ "minute", tMINUTE_UNIT, 1 },
|
||||
{ "min", tMINUTE_UNIT, 1 },
|
||||
{ "second", tSEC_UNIT, 1 },
|
||||
{ "sec", tSEC_UNIT, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Assorted relative-time words. */
|
||||
static TABLE const OtherTable[] = {
|
||||
{ "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
|
||||
{ "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
|
||||
{ "today", tMINUTE_UNIT, 0 },
|
||||
{ "now", tMINUTE_UNIT, 0 },
|
||||
{ "last", tUNUMBER, -1 },
|
||||
{ "this", tMINUTE_UNIT, 0 },
|
||||
{ "next", tUNUMBER, 2 },
|
||||
{ "first", tUNUMBER, 1 },
|
||||
/* { "second", tUNUMBER, 2 }, */
|
||||
{ "third", tUNUMBER, 3 },
|
||||
{ "fourth", tUNUMBER, 4 },
|
||||
{ "fifth", tUNUMBER, 5 },
|
||||
{ "sixth", tUNUMBER, 6 },
|
||||
{ "seventh", tUNUMBER, 7 },
|
||||
{ "eighth", tUNUMBER, 8 },
|
||||
{ "ninth", tUNUMBER, 9 },
|
||||
{ "tenth", tUNUMBER, 10 },
|
||||
{ "eleventh", tUNUMBER, 11 },
|
||||
{ "twelfth", tUNUMBER, 12 },
|
||||
{ "ago", tAGO, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* The timezone table. */
|
||||
/* Some of these are commented out because a time_t can't store a float. */
|
||||
static TABLE const TimezoneTable[] = {
|
||||
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
|
||||
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
|
||||
{ "utc", tZONE, HOUR( 0) },
|
||||
{ "wet", tZONE, HOUR( 0) }, /* Western European */
|
||||
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
|
||||
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
|
||||
{ "at", tZONE, HOUR( 2) }, /* Azores */
|
||||
#if 0
|
||||
/* For completeness. BST is also British Summer, and GST is
|
||||
* also Guam Standard. */
|
||||
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
|
||||
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
|
||||
#endif
|
||||
#if 0
|
||||
{ "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
|
||||
{ "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
|
||||
{ "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
|
||||
#endif
|
||||
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
|
||||
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
|
||||
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
|
||||
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
|
||||
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
|
||||
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
|
||||
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
|
||||
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
|
||||
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
|
||||
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
|
||||
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
|
||||
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
|
||||
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
|
||||
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
|
||||
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
|
||||
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
|
||||
{ "nt", tZONE, HOUR(11) }, /* Nome */
|
||||
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
|
||||
{ "cet", tZONE, -HOUR(1) }, /* Central European */
|
||||
{ "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
|
||||
{ "met", tZONE, -HOUR(1) }, /* Middle European */
|
||||
{ "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
|
||||
{ "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
|
||||
{ "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
|
||||
{ "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
|
||||
{ "fwt", tZONE, -HOUR(1) }, /* French Winter */
|
||||
{ "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
|
||||
{ "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
|
||||
{ "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
|
||||
#if 0
|
||||
{ "it", tZONE, -HOUR(3.5) },/* Iran */
|
||||
#endif
|
||||
{ "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
|
||||
{ "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
|
||||
#if 0
|
||||
{ "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
|
||||
#endif
|
||||
{ "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
|
||||
#if 0
|
||||
/* For completeness. NST is also Newfoundland Stanard, and SST is
|
||||
* also Swedish Summer. */
|
||||
{ "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
|
||||
{ "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
|
||||
#endif /* 0 */
|
||||
{ "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
|
||||
{ "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
|
||||
#if 0
|
||||
{ "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
|
||||
#endif
|
||||
{ "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
|
||||
{ "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
|
||||
#if 0
|
||||
{ "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
|
||||
{ "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
|
||||
#endif
|
||||
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
|
||||
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
|
||||
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
|
||||
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
|
||||
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
|
||||
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
|
||||
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Military timezone table. */
|
||||
static TABLE const MilitaryTable[] = {
|
||||
{ "a", tZONE, HOUR( 1) },
|
||||
{ "b", tZONE, HOUR( 2) },
|
||||
{ "c", tZONE, HOUR( 3) },
|
||||
{ "d", tZONE, HOUR( 4) },
|
||||
{ "e", tZONE, HOUR( 5) },
|
||||
{ "f", tZONE, HOUR( 6) },
|
||||
{ "g", tZONE, HOUR( 7) },
|
||||
{ "h", tZONE, HOUR( 8) },
|
||||
{ "i", tZONE, HOUR( 9) },
|
||||
{ "k", tZONE, HOUR( 10) },
|
||||
{ "l", tZONE, HOUR( 11) },
|
||||
{ "m", tZONE, HOUR( 12) },
|
||||
{ "n", tZONE, HOUR(- 1) },
|
||||
{ "o", tZONE, HOUR(- 2) },
|
||||
{ "p", tZONE, HOUR(- 3) },
|
||||
{ "q", tZONE, HOUR(- 4) },
|
||||
{ "r", tZONE, HOUR(- 5) },
|
||||
{ "s", tZONE, HOUR(- 6) },
|
||||
{ "t", tZONE, HOUR(- 7) },
|
||||
{ "u", tZONE, HOUR(- 8) },
|
||||
{ "v", tZONE, HOUR(- 9) },
|
||||
{ "w", tZONE, HOUR(-10) },
|
||||
{ "x", tZONE, HOUR(-11) },
|
||||
{ "y", tZONE, HOUR(-12) },
|
||||
{ "z", tZONE, HOUR( 0) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
yyerror(s)
|
||||
char *s;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
ToSeconds(Hours, Minutes, Seconds, Meridian)
|
||||
time_t Hours;
|
||||
time_t Minutes;
|
||||
time_t Seconds;
|
||||
MERIDIAN Meridian;
|
||||
{
|
||||
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
|
||||
return -1;
|
||||
switch (Meridian) {
|
||||
case MER24:
|
||||
if (Hours < 0 || Hours > 23)
|
||||
return -1;
|
||||
return (Hours * 60L + Minutes) * 60L + Seconds;
|
||||
case MERam:
|
||||
if (Hours < 1 || Hours > 12)
|
||||
return -1;
|
||||
return (Hours * 60L + Minutes) * 60L + Seconds;
|
||||
case MERpm:
|
||||
if (Hours < 1 || Hours > 12)
|
||||
return -1;
|
||||
return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
|
||||
time_t Month;
|
||||
time_t Day;
|
||||
time_t Year;
|
||||
time_t Hours;
|
||||
time_t Minutes;
|
||||
time_t Seconds;
|
||||
MERIDIAN Meridian;
|
||||
DSTMODE DSTmode;
|
||||
{
|
||||
static int DaysInMonth[12] = {
|
||||
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
time_t tod;
|
||||
time_t Julian;
|
||||
int i;
|
||||
|
||||
if (Year < 0)
|
||||
Year = -Year;
|
||||
|
||||
/* Might as well allow up to 2069, as the code below has
|
||||
* never worked for dates prior to 1970.
|
||||
*/
|
||||
if (Year > 69 && Year < 100)
|
||||
Year += 1900;
|
||||
else if (Year < 70)
|
||||
Year += 2000;
|
||||
|
||||
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
|
||||
? 29 : 28;
|
||||
if (Year < EPOCH || Year > 2069 /* Code not valid past 2069 */
|
||||
|| Month < 1 || Month > 12
|
||||
/* Lint fluff: "conversion from long may lose accuracy" */
|
||||
|| Day < 1 || Day > DaysInMonth[(int)--Month])
|
||||
return -1;
|
||||
|
||||
for (Julian = Day - 1, i = 0; i < Month; i++)
|
||||
Julian += DaysInMonth[i];
|
||||
for (i = EPOCH; i < Year; i++)
|
||||
Julian += 365 + (i % 4 == 0); /* Not valid in 2100 - Not leap year */
|
||||
Julian *= SECSPERDAY;
|
||||
Julian += yyTimezone * 60L;
|
||||
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
|
||||
return -1;
|
||||
Julian += tod;
|
||||
if (DSTmode == DSTon
|
||||
|| (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
|
||||
Julian -= 60 * 60;
|
||||
return Julian;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
DSTcorrect(Start, Future)
|
||||
time_t Start;
|
||||
time_t Future;
|
||||
{
|
||||
time_t StartDay;
|
||||
time_t FutureDay;
|
||||
|
||||
StartDay = (localtime(&Start)->tm_hour + 1) % 24;
|
||||
FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
|
||||
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
RelativeDate(Start, DayOrdinal, DayNumber)
|
||||
time_t Start;
|
||||
time_t DayOrdinal;
|
||||
time_t DayNumber;
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
|
||||
now = Start;
|
||||
tm = localtime(&now);
|
||||
now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
|
||||
now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
|
||||
return DSTcorrect(Start, now);
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
RelativeMonth(Start, RelMonth)
|
||||
time_t Start;
|
||||
time_t RelMonth;
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t Month;
|
||||
time_t Year;
|
||||
|
||||
if (RelMonth == 0)
|
||||
return 0;
|
||||
tm = localtime(&Start);
|
||||
Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
|
||||
Year = Month / 12;
|
||||
Month = Month % 12 + 1;
|
||||
return DSTcorrect(Start,
|
||||
Convert(Month, (time_t)tm->tm_mday, Year,
|
||||
(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
|
||||
MER24, DSTmaybe));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
LookupWord(buff)
|
||||
char *buff;
|
||||
{
|
||||
register char *p;
|
||||
register char *q;
|
||||
register const TABLE *tp;
|
||||
int i;
|
||||
int abbrev;
|
||||
|
||||
/* Make it lowercase. */
|
||||
for (p = buff; *p; p++)
|
||||
if (isupper(*p))
|
||||
*p = tolower(*p);
|
||||
|
||||
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
|
||||
yylval.Meridian = MERam;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
|
||||
yylval.Meridian = MERpm;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
|
||||
/* See if we have an abbreviation for a month. */
|
||||
if (strlen(buff) == 3)
|
||||
abbrev = 1;
|
||||
else if (strlen(buff) == 4 && buff[3] == '.') {
|
||||
abbrev = 1;
|
||||
buff[3] = '\0';
|
||||
}
|
||||
else
|
||||
abbrev = 0;
|
||||
|
||||
for (tp = MonthDayTable; tp->name; tp++) {
|
||||
if (abbrev) {
|
||||
if (strncmp(buff, tp->name, 3) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
else if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
if (strcmp(buff, "dst") == 0)
|
||||
return tDST;
|
||||
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
/* Strip off any plural and try the units table again. */
|
||||
i = strlen(buff) - 1;
|
||||
if (buff[i] == 's') {
|
||||
buff[i] = '\0';
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
buff[i] = 's'; /* Put back for "this" in OtherTable. */
|
||||
}
|
||||
|
||||
for (tp = OtherTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
/* Military timezones. */
|
||||
if (buff[1] == '\0' && isalpha(*buff)) {
|
||||
for (tp = MilitaryTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop out any periods and try the timezone table again. */
|
||||
for (i = 0, p = q = buff; *q; q++)
|
||||
if (*q != '.')
|
||||
*p++ = *q;
|
||||
else
|
||||
i++;
|
||||
*p = '\0';
|
||||
if (i)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
return tID;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
yylex()
|
||||
{
|
||||
register char c;
|
||||
register char *p;
|
||||
char buff[20];
|
||||
int Count;
|
||||
int sign;
|
||||
|
||||
for ( ; ; ) {
|
||||
while (isspace(*yyInput))
|
||||
yyInput++;
|
||||
|
||||
if (isdigit(c = *yyInput) || c == '-' || c == '+') {
|
||||
if (c == '-' || c == '+') {
|
||||
sign = c == '-' ? -1 : 1;
|
||||
if (!isdigit(*++yyInput))
|
||||
/* skip the '-' sign */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
for (yylval.Number = 0; isdigit(c = *yyInput++); )
|
||||
yylval.Number = 10 * yylval.Number + c - '0';
|
||||
yyInput--;
|
||||
if (sign < 0)
|
||||
yylval.Number = -yylval.Number;
|
||||
return sign ? tSNUMBER : tUNUMBER;
|
||||
}
|
||||
if (isalpha(c)) {
|
||||
for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
|
||||
if (p < &buff[sizeof buff - 1])
|
||||
*p++ = c;
|
||||
*p = '\0';
|
||||
yyInput--;
|
||||
return LookupWord(buff);
|
||||
}
|
||||
if (c != '(')
|
||||
return *yyInput++;
|
||||
Count = 0;
|
||||
do {
|
||||
c = *yyInput++;
|
||||
if (c == '\0')
|
||||
return c;
|
||||
if (c == '(')
|
||||
Count++;
|
||||
else if (c == ')')
|
||||
Count--;
|
||||
} while (Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
time_t
|
||||
get_date(p, now)
|
||||
char *p;
|
||||
struct timeb *now;
|
||||
{
|
||||
struct tm *tm;
|
||||
struct timeb ftz;
|
||||
time_t Start;
|
||||
time_t tod;
|
||||
|
||||
yyInput = p;
|
||||
if (now == NULL) {
|
||||
now = &ftz;
|
||||
#if !defined(HAVE_FTIME)
|
||||
(void)time(&ftz.time);
|
||||
/* Set the timezone global. */
|
||||
tzset();
|
||||
{
|
||||
#if sgi
|
||||
ftz.timezone = (int) _timezone / 60;
|
||||
#else /* not sgi */
|
||||
#ifdef __FreeBSD__
|
||||
ftz.timezone = 0;
|
||||
#else /* neither sgi nor 386BSD */
|
||||
#if defined (USG)
|
||||
extern time_t timezone;
|
||||
|
||||
ftz.timezone = (int) timezone / 60;
|
||||
#else /* neither sgi nor 386BSD nor USG */
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
gettimeofday (&tv, &tz);
|
||||
ftz.timezone = (int) tz.tz_minuteswest;
|
||||
#endif /* neither sgi nor 386BSD nor USG */
|
||||
#endif /* neither sgi nor 386BSD */
|
||||
#endif /* not sgi */
|
||||
}
|
||||
#else /* HAVE_FTIME */
|
||||
(void)ftime(&ftz);
|
||||
#endif /* HAVE_FTIME */
|
||||
}
|
||||
|
||||
tm = localtime(&now->time);
|
||||
yyYear = tm->tm_year;
|
||||
yyMonth = tm->tm_mon + 1;
|
||||
yyDay = tm->tm_mday;
|
||||
yyTimezone = now->timezone;
|
||||
yyDSTmode = DSTmaybe;
|
||||
yyHour = 0;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
yyRelMonth = 0;
|
||||
yyHaveDate = 0;
|
||||
yyHaveDay = 0;
|
||||
yyHaveRel = 0;
|
||||
yyHaveTime = 0;
|
||||
yyHaveZone = 0;
|
||||
|
||||
if (yyparse()
|
||||
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
|
||||
return -1;
|
||||
|
||||
if (yyHaveDate || yyHaveTime || yyHaveDay) {
|
||||
Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
|
||||
yyMeridian, yyDSTmode);
|
||||
if (Start < 0)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
Start = now->time;
|
||||
if (!yyHaveRel)
|
||||
Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
|
||||
}
|
||||
|
||||
Start += yyRelSeconds;
|
||||
Start += RelativeMonth(Start, yyRelMonth);
|
||||
|
||||
if (yyHaveDay && !yyHaveDate) {
|
||||
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
|
||||
Start += tod;
|
||||
}
|
||||
|
||||
/* Have to do *something* with a legitimate -1 so it's distinguishable
|
||||
* from the error return value. (Alternately could set errno on error.) */
|
||||
return Start == -1 ? 0 : Start;
|
||||
}
|
||||
|
||||
|
||||
#if defined(TEST)
|
||||
|
||||
/* ARGSUSED */
|
||||
main(ac, av)
|
||||
int ac;
|
||||
char *av[];
|
||||
{
|
||||
char buff[128];
|
||||
time_t d;
|
||||
|
||||
(void)printf("Enter date, or blank line to exit.\n\t> ");
|
||||
(void)fflush(stdout);
|
||||
while (gets(buff) && buff[0]) {
|
||||
d = get_date(buff, (struct timeb *)NULL);
|
||||
if (d == -1)
|
||||
(void)printf("Bad format - couldn't convert.\n");
|
||||
else
|
||||
(void)printf("%s", ctime(&d));
|
||||
(void)printf("\t> ");
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
exit(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif /* defined(TEST) */
|
@ -1,96 +0,0 @@
|
||||
/* Replacement for getopt() that can be used by tar.
|
||||
Copyright (C) 1988 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Plug-compatible replacement for getopt() for parsing tar-like
|
||||
* arguments. If the first argument begins with "-", it uses getopt;
|
||||
* otherwise, it uses the old rules used by tar, dump, and ps.
|
||||
*
|
||||
* Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "getopt.h"
|
||||
#include "tar.h" /* For msg() declaration if STDC_MSG. */
|
||||
#include <sys/types.h>
|
||||
#include "port.h"
|
||||
|
||||
int
|
||||
getoldopt (argc, argv, optstring, long_options, opt_index)
|
||||
int argc;
|
||||
char **argv;
|
||||
char *optstring;
|
||||
struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
extern char *optarg; /* Points to next arg */
|
||||
extern int optind; /* Global argv index */
|
||||
static char *key; /* Points to next keyletter */
|
||||
static char use_getopt; /* !=0 if argv[1][0] was '-' */
|
||||
char c;
|
||||
char *place;
|
||||
|
||||
optarg = NULL;
|
||||
|
||||
if (key == NULL)
|
||||
{ /* First time */
|
||||
if (argc < 2)
|
||||
return EOF;
|
||||
key = argv[1];
|
||||
if ((*key == '-') || (*key == '+'))
|
||||
use_getopt++;
|
||||
else
|
||||
optind = 2;
|
||||
}
|
||||
|
||||
if (use_getopt)
|
||||
return getopt_long (argc, argv, optstring,
|
||||
long_options, opt_index);
|
||||
|
||||
c = *key++;
|
||||
if (c == '\0')
|
||||
{
|
||||
key--;
|
||||
return EOF;
|
||||
}
|
||||
place = index (optstring, c);
|
||||
|
||||
if (place == NULL || c == ':')
|
||||
{
|
||||
msg ("unknown option %c", c);
|
||||
return ('?');
|
||||
}
|
||||
|
||||
place++;
|
||||
if (*place == ':')
|
||||
{
|
||||
if (optind < argc)
|
||||
{
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg ("%c argument missing", c);
|
||||
return ('?');
|
||||
}
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
@ -1,712 +0,0 @@
|
||||
/* Getopt for GNU.
|
||||
NOTE: getopt is now part of the C library, so if you don't know what
|
||||
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
|
||||
before changing it!
|
||||
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* NOTE!!! AIX requires this to be the first thing in the file.
|
||||
Do not put ANYTHING before it! */
|
||||
#if !defined (__GNUC__) && defined (_AIX)
|
||||
#pragma alloca
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not __GNUC__ */
|
||||
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifndef _AIX
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif /* alloca.h */
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
#if !__STDC__ && !defined(const) && IN_GCC
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#undef alloca
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
#include <stdlib.h>
|
||||
#else /* Not GNU C library. */
|
||||
#define __alloca alloca
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
|
||||
long-named option. Because this is not POSIX.2 compliant, it is
|
||||
being phased out. */
|
||||
/* #define GETOPT_COMPAT */
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
but it behaves differently for the user, since it allows the user
|
||||
to intersperse the options with the other arguments.
|
||||
|
||||
As `getopt' works, it permutes the elements of ARGV so that,
|
||||
when it is done, all the options precede everything else. Thus
|
||||
all application programs are extended to handle flexible argument order.
|
||||
|
||||
Setting the environment variable POSIXLY_CORRECT disables permutation.
|
||||
Then the behavior is completely standard.
|
||||
|
||||
GNU application programs can use a third alternative mode in which
|
||||
they can distinguish the relative order of options and other arguments. */
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
char *optarg = 0;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
/* XXX 1003.2 says this must be 1 before any call. */
|
||||
int optind = 0;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
This allows us to pick up the scan where we left off.
|
||||
|
||||
If this is zero, or a null string, it means resume the scan
|
||||
by advancing to the next ARGV-element. */
|
||||
|
||||
static char *nextchar;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
int opterr = 1;
|
||||
|
||||
/* Set to an option character which was unrecognized.
|
||||
This must be initialized on some systems to avoid linking in the
|
||||
system's own getopt implementation. */
|
||||
|
||||
int optopt = '?';
|
||||
|
||||
/* Describe how to deal with options that follow non-option ARGV-elements.
|
||||
|
||||
If the caller did not specify anything,
|
||||
the default is REQUIRE_ORDER if the environment variable
|
||||
POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options;
|
||||
stop option processing when the first non-option is seen.
|
||||
This is what Unix does.
|
||||
This mode of operation is selected by either setting the environment
|
||||
variable POSIXLY_CORRECT, or using `+' as the first character
|
||||
of the list of option characters.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan,
|
||||
so that eventually all the non-options are at the end. This allows options
|
||||
to be given in any order, even with programs that were not written to
|
||||
expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written
|
||||
to expect options and other ARGV-elements in any order and that care about
|
||||
the ordering of the two. We describe each non-option ARGV-element
|
||||
as if it were the argument of an option with character code 1.
|
||||
Using `-' as the first character of the list of option characters
|
||||
selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless
|
||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
|
||||
|
||||
static enum
|
||||
{
|
||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
||||
} ordering;
|
||||
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
||||
because there are many ways it can cause trouble.
|
||||
On some systems, it contains special magic macros that don't work
|
||||
in GCC. */
|
||||
#include <string.h>
|
||||
#define my_index strchr
|
||||
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
|
||||
char *getenv ();
|
||||
|
||||
static char *
|
||||
my_index (string, chr)
|
||||
char *string;
|
||||
int chr;
|
||||
{
|
||||
while (*string)
|
||||
{
|
||||
if (*string == chr)
|
||||
return string;
|
||||
string++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
my_bcopy (from, to, size)
|
||||
char *from, *to;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
to[i] = from[i];
|
||||
}
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* Handle permutation of arguments. */
|
||||
|
||||
/* Describe the part of ARGV that contains non-options that have
|
||||
been skipped. `first_nonopt' is the index in ARGV of the first of them;
|
||||
`last_nonopt' is the index after the last of them. */
|
||||
|
||||
static int first_nonopt;
|
||||
static int last_nonopt;
|
||||
|
||||
/* Exchange two adjacent subsequences of ARGV.
|
||||
One subsequence is elements [first_nonopt,last_nonopt)
|
||||
which contains all the non-options that have been skipped so far.
|
||||
The other is elements [last_nonopt,optind), which contains all
|
||||
the options processed since those non-options were skipped.
|
||||
|
||||
`first_nonopt' and `last_nonopt' are relocated so that they describe
|
||||
the new indices of the non-options in ARGV after they are moved. */
|
||||
|
||||
static void
|
||||
exchange (argv)
|
||||
char **argv;
|
||||
{
|
||||
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
|
||||
char **temp = (char **) __alloca (nonopts_size);
|
||||
|
||||
/* Interchange the two blocks of data in ARGV. */
|
||||
|
||||
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
|
||||
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
|
||||
(optind - last_nonopt) * sizeof (char *));
|
||||
my_bcopy ((char *) temp,
|
||||
(char *) &argv[first_nonopt + optind - last_nonopt],
|
||||
nonopts_size);
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
first_nonopt += (optind - last_nonopt);
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `getopt'
|
||||
is called repeatedly, it returns successively each of the option characters
|
||||
from each of the option elements.
|
||||
|
||||
If `getopt' finds another option character, it returns that character,
|
||||
updating `optind' and `nextchar' so that the next call to `getopt' can
|
||||
resume the scan with the following option character or ARGV-element.
|
||||
|
||||
If there are no more option characters, `getopt' returns `EOF'.
|
||||
Then `optind' is the index in ARGV of the first ARGV-element
|
||||
that is not an option. (The ARGV-elements have been permuted
|
||||
so that those that are not options now come last.)
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen that is not listed in OPTSTRING,
|
||||
return '?' after printing an error message. If you set `opterr' to
|
||||
zero, the error message is suppressed but we still return '?'.
|
||||
|
||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
||||
so the following text in the same ARGV-element, or the text of the following
|
||||
ARGV-element, is returned in `optarg'. Two colons mean an option that
|
||||
wants an optional arg; if there is text in the current ARGV-element,
|
||||
it is returned in `optarg', otherwise `optarg' is set to zero.
|
||||
|
||||
If OPTSTRING starts with `-' or `+', it requests different methods of
|
||||
handling the non-option ARGV-elements.
|
||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
|
||||
Long-named options begin with `--' instead of `-'.
|
||||
Their names may be abbreviated as long as the abbreviation is unique
|
||||
or is an exact match for some defined option. If they have an
|
||||
argument, it follows the option name in the same ARGV-element, separated
|
||||
from the option name by a `=', or else the in next ARGV-element.
|
||||
When `getopt' finds a long-named option, it returns 0 if that option's
|
||||
`flag' field is nonzero, the value of the option's `val' field
|
||||
if the `flag' field is zero.
|
||||
|
||||
The elements of ARGV aren't really const, because we permute them.
|
||||
But we pretend they're const in the prototype to be compatible
|
||||
with other systems.
|
||||
|
||||
LONGOPTS is a vector of `struct option' terminated by an
|
||||
element containing a name which is zero.
|
||||
|
||||
LONGIND returns the index in LONGOPT of the long-named option found.
|
||||
It is only valid when a long-named option has been found by the most
|
||||
recent call.
|
||||
|
||||
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
|
||||
long-named options. */
|
||||
|
||||
int
|
||||
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
const struct option *longopts;
|
||||
int *longind;
|
||||
int long_only;
|
||||
{
|
||||
int option_index;
|
||||
|
||||
optarg = 0;
|
||||
|
||||
/* Initialize the internal data when the first call is made.
|
||||
Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||
is the program name); the sequence of previously skipped
|
||||
non-option ARGV-elements is empty. */
|
||||
|
||||
if (optind == 0)
|
||||
{
|
||||
first_nonopt = last_nonopt = optind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
/* Determine how to handle the ordering of options and nonoptions. */
|
||||
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (getenv ("POSIXLY_CORRECT") != NULL)
|
||||
ordering = REQUIRE_ORDER;
|
||||
else
|
||||
ordering = PERMUTE;
|
||||
}
|
||||
|
||||
if (nextchar == NULL || *nextchar == '\0')
|
||||
{
|
||||
if (ordering == PERMUTE)
|
||||
{
|
||||
/* If we have just processed some options following some non-options,
|
||||
exchange them so that the options come first. */
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (last_nonopt != optind)
|
||||
first_nonopt = optind;
|
||||
|
||||
/* Now skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (optind < argc
|
||||
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
optind++;
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option,
|
||||
then exchange with previous non-options as if it were an option,
|
||||
then skip everything else like a non-option. */
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "--"))
|
||||
{
|
||||
optind++;
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (first_nonopt == last_nonopt)
|
||||
first_nonopt = optind;
|
||||
last_nonopt = argc;
|
||||
|
||||
optind = argc;
|
||||
}
|
||||
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
/* Set the next-arg-index to point at the non-options
|
||||
that we previously skipped, so the caller will digest them. */
|
||||
if (first_nonopt != last_nonopt)
|
||||
optind = first_nonopt;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option and did not permute it,
|
||||
either stop the scan or describe it to the caller and pass it by. */
|
||||
|
||||
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Start decoding its characters. */
|
||||
|
||||
nextchar = (argv[optind] + 1
|
||||
+ (longopts != NULL && argv[optind][1] == '-'));
|
||||
}
|
||||
|
||||
if (longopts != NULL
|
||||
&& ((argv[optind][0] == '-'
|
||||
&& (argv[optind][1] == '-' || long_only))
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
))
|
||||
{
|
||||
const struct option *p;
|
||||
char *s = nextchar;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
const struct option *pfound = NULL;
|
||||
int indfound;
|
||||
|
||||
while (*s && *s != '=')
|
||||
s++;
|
||||
|
||||
/* Test all options for either exact match or abbreviated matches. */
|
||||
for (p = longopts, option_index = 0; p->name;
|
||||
p++, option_index++)
|
||||
if (!strncmp (p->name, nextchar, s - nextchar))
|
||||
{
|
||||
if (s - nextchar == strlen (p->name))
|
||||
{
|
||||
/* Exact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
/* First nonexact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else
|
||||
/* Second nonexact match found. */
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' is ambiguous\n",
|
||||
argv[0], argv[optind]);
|
||||
nextchar += strlen (nextchar);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
optind++;
|
||||
if (*s)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (pfound->has_arg)
|
||||
optarg = s + 1;
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind - 1][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr,
|
||||
"%s: option `--%s' doesn't allow an argument\n",
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr,
|
||||
"%s: option `%c%s' doesn't allow an argument\n",
|
||||
argv[0], argv[optind - 1][0], pfound->name);
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' requires an argument\n",
|
||||
argv[0], argv[optind - 1]);
|
||||
nextchar += strlen (nextchar);
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||
or the option starts with '--' or is not a valid short
|
||||
option, then it's an error.
|
||||
Otherwise interpret it as a short option. */
|
||||
if (!long_only || argv[optind][1] == '-'
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
|| my_index (optstring, *nextchar) == NULL)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr, "%s: unrecognized option `--%s'\n",
|
||||
argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
|
||||
argv[0], argv[optind][0], nextchar);
|
||||
}
|
||||
nextchar = (char *) "";
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/* Look at and handle the next option-character. */
|
||||
|
||||
{
|
||||
char c = *nextchar++;
|
||||
char *temp = my_index (optstring, c);
|
||||
|
||||
/* Increment `optind' when we start to process its last character. */
|
||||
if (*nextchar == '\0')
|
||||
++optind;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
#if 0
|
||||
if (c < 040 || c >= 0177)
|
||||
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
|
||||
argv[0], c);
|
||||
else
|
||||
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
|
||||
#else
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
|
||||
#endif
|
||||
}
|
||||
optopt = c;
|
||||
return '?';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
/* This is an option that accepts an argument optionally. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
optarg = 0;
|
||||
nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
optind++;
|
||||
}
|
||||
else if (optind == argc)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
#if 0
|
||||
fprintf (stderr, "%s: option `-%c' requires an argument\n",
|
||||
argv[0], c);
|
||||
#else
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: option requires an argument -- %c\n",
|
||||
argv[0], c);
|
||||
#endif
|
||||
}
|
||||
optopt = c;
|
||||
if (optstring[0] == ':')
|
||||
c = ':';
|
||||
else
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `optind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
optarg = argv[optind++];
|
||||
nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getopt (argc, argv, optstring)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
{
|
||||
return _getopt_internal (argc, argv, optstring,
|
||||
(const struct option *) 0,
|
||||
(int *) 0,
|
||||
0);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/* Compile with -DTEST to make an executable for use in testing
|
||||
the above definition of `getopt'. */
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
|
||||
c = getopt (argc, argv, "abc:d:0123456789");
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
@ -1,125 +0,0 @@
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#if __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#if __STDC__
|
||||
#if defined(__GNU_LIBRARY__)
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
#endif /* not __GNU_LIBRARY__ */
|
||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
#endif /* not __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H */
|
@ -1,161 +0,0 @@
|
||||
/* Getopt for GNU.
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if !__STDC__ && !defined(const) && IN_GCC
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
@ -1,38 +0,0 @@
|
||||
#ifdef BSD
|
||||
#ifndef BSD4_1
|
||||
#define HAVE_GETPAGESIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
|
||||
#ifdef VMS
|
||||
#define getpagesize() 512
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _SC_PAGESIZE
|
||||
#define getpagesize() sysconf(_SC_PAGESIZE)
|
||||
#else
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef EXEC_PAGESIZE
|
||||
#define getpagesize() EXEC_PAGESIZE
|
||||
#else
|
||||
#ifdef NBPG
|
||||
#define getpagesize() NBPG * CLSIZE
|
||||
#ifndef CLSIZE
|
||||
#define CLSIZE 1
|
||||
#endif /* no CLSIZE */
|
||||
#else /* no NBPG */
|
||||
#define getpagesize() NBPC
|
||||
#endif /* no NBPG */
|
||||
#endif /* no EXEC_PAGESIZE */
|
||||
#endif /* no _SC_PAGESIZE */
|
||||
|
||||
#endif /* not HAVE_GETPAGESIZE */
|
||||
|
@ -1,677 +0,0 @@
|
||||
/* GNU dump extensions to tar.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <time.h>
|
||||
time_t time ();
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define lstat stat
|
||||
#endif
|
||||
|
||||
extern time_t new_time;
|
||||
extern FILE *msg_file;
|
||||
|
||||
void addname ();
|
||||
int check_exclude ();
|
||||
extern PTR ck_malloc ();
|
||||
extern PTR ck_realloc ();
|
||||
int confirm ();
|
||||
extern PTR init_buffer ();
|
||||
extern char *get_buffer ();
|
||||
int is_dot_or_dotdot ();
|
||||
extern void add_buffer ();
|
||||
extern void flush_buffer ();
|
||||
void name_gather ();
|
||||
int recursively_delete ();
|
||||
void skip_file ();
|
||||
char *un_quote_string ();
|
||||
|
||||
extern char *new_name ();
|
||||
|
||||
static void add_dir_name ();
|
||||
|
||||
struct dirname
|
||||
{
|
||||
struct dirname *next;
|
||||
char *name;
|
||||
char *dir_text;
|
||||
int dev;
|
||||
int ino;
|
||||
int allnew;
|
||||
};
|
||||
static struct dirname *dir_list;
|
||||
static time_t this_time;
|
||||
|
||||
void
|
||||
add_dir (name, dev, ino, text)
|
||||
char *name;
|
||||
char *text;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
{
|
||||
struct dirname *dp;
|
||||
|
||||
dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
|
||||
if (!dp)
|
||||
abort ();
|
||||
dp->next = dir_list;
|
||||
dir_list = dp;
|
||||
dp->dev = dev;
|
||||
dp->ino = ino;
|
||||
dp->name = ck_malloc (strlen (name) + 1);
|
||||
strcpy (dp->name, name);
|
||||
dp->dir_text = text;
|
||||
dp->allnew = 0;
|
||||
}
|
||||
|
||||
void
|
||||
read_dir_file ()
|
||||
{
|
||||
int dev;
|
||||
int ino;
|
||||
char *strp;
|
||||
FILE *fp;
|
||||
char buf[512];
|
||||
static char *path = 0;
|
||||
|
||||
if (path == 0)
|
||||
path = ck_malloc (PATH_MAX);
|
||||
time (&this_time);
|
||||
if (gnu_dumpfile[0] != '/')
|
||||
{
|
||||
#if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
|
||||
if (!getcwd (path, PATH_MAX))
|
||||
{
|
||||
msg ("Couldn't get current directory.");
|
||||
exit (EX_SYSTEM);
|
||||
}
|
||||
#else
|
||||
char *getwd ();
|
||||
|
||||
if (!getwd (path))
|
||||
{
|
||||
msg ("Couldn't get current directory: %s", path);
|
||||
exit (EX_SYSTEM);
|
||||
}
|
||||
#endif
|
||||
/* If this doesn't fit, we're in serious trouble */
|
||||
strcat (path, "/");
|
||||
strcat (path, gnu_dumpfile);
|
||||
gnu_dumpfile = path;
|
||||
}
|
||||
fp = fopen (gnu_dumpfile, "r");
|
||||
if (fp == 0 && errno != ENOENT)
|
||||
{
|
||||
msg_perror ("Can't open %s", gnu_dumpfile);
|
||||
return;
|
||||
}
|
||||
if (!fp)
|
||||
return;
|
||||
fgets (buf, sizeof (buf), fp);
|
||||
if (!f_new_files)
|
||||
{
|
||||
f_new_files++;
|
||||
new_time = atol (buf);
|
||||
}
|
||||
while (fgets (buf, sizeof (buf), fp))
|
||||
{
|
||||
strp = &buf[strlen (buf)];
|
||||
if (strp[-1] == '\n')
|
||||
strp[-1] = '\0';
|
||||
strp = buf;
|
||||
dev = atol (strp);
|
||||
while (isdigit ((unsigned char) *strp))
|
||||
strp++;
|
||||
ino = atol (strp);
|
||||
while (isspace ((unsigned char) *strp))
|
||||
strp++;
|
||||
while (isdigit ((unsigned char) *strp))
|
||||
strp++;
|
||||
strp++;
|
||||
add_dir (un_quote_string (strp), dev, ino, (char *) 0);
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
void
|
||||
write_dir_file ()
|
||||
{
|
||||
FILE *fp;
|
||||
struct dirname *dp;
|
||||
char *str;
|
||||
extern char *quote_copy_string ();
|
||||
|
||||
fp = fopen (gnu_dumpfile, "w");
|
||||
if (fp == 0)
|
||||
{
|
||||
msg_perror ("Can't write to %s", gnu_dumpfile);
|
||||
return;
|
||||
}
|
||||
fprintf (fp, "%lu\n", (unsigned long) this_time);
|
||||
for (dp = dir_list; dp; dp = dp->next)
|
||||
{
|
||||
if (!dp->dir_text)
|
||||
continue;
|
||||
str = quote_copy_string (dp->name);
|
||||
if (str)
|
||||
{
|
||||
fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
|
||||
free (str);
|
||||
}
|
||||
else
|
||||
fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
struct dirname *
|
||||
get_dir (name)
|
||||
char *name;
|
||||
{
|
||||
struct dirname *dp;
|
||||
|
||||
for (dp = dir_list; dp; dp = dp->next)
|
||||
{
|
||||
if (!strcmp (dp->name, name))
|
||||
return dp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Collect all the names from argv[] (or whatever), then expand them into
|
||||
a directory tree, and put all the directories at the beginning. */
|
||||
void
|
||||
collect_and_sort_names ()
|
||||
{
|
||||
struct name *n, *n_next;
|
||||
int num_names;
|
||||
struct stat statbuf;
|
||||
int name_cmp ();
|
||||
char *merge_sort ();
|
||||
|
||||
name_gather ();
|
||||
|
||||
if (gnu_dumpfile)
|
||||
read_dir_file ();
|
||||
if (!namelist)
|
||||
addname (".");
|
||||
for (n = namelist; n; n = n_next)
|
||||
{
|
||||
n_next = n->next;
|
||||
if (n->found || n->dir_contents)
|
||||
continue;
|
||||
if (n->regexp) /* FIXME just skip regexps for now */
|
||||
continue;
|
||||
if (n->change_dir)
|
||||
if (chdir (n->change_dir) < 0)
|
||||
{
|
||||
msg_perror ("can't chdir to %s", n->change_dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef AIX
|
||||
if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
|
||||
#else
|
||||
if (lstat (n->name, &statbuf) < 0)
|
||||
#endif /* AIX */
|
||||
{
|
||||
msg_perror ("can't stat %s", n->name);
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR (statbuf.st_mode))
|
||||
{
|
||||
n->found++;
|
||||
add_dir_name (n->name, statbuf.st_dev);
|
||||
}
|
||||
}
|
||||
|
||||
num_names = 0;
|
||||
for (n = namelist; n; n = n->next)
|
||||
num_names++;
|
||||
namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
|
||||
|
||||
for (n = namelist; n; n = n->next)
|
||||
{
|
||||
n->found = 0;
|
||||
}
|
||||
if (gnu_dumpfile)
|
||||
write_dir_file ();
|
||||
}
|
||||
|
||||
int
|
||||
name_cmp (n1, n2)
|
||||
struct name *n1, *n2;
|
||||
{
|
||||
if (n1->found)
|
||||
{
|
||||
if (n2->found)
|
||||
return strcmp (n1->name, n2->name);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (n2->found)
|
||||
return 1;
|
||||
else
|
||||
return strcmp (n1->name, n2->name);
|
||||
}
|
||||
|
||||
int
|
||||
dirent_cmp (p1, p2)
|
||||
const PTR p1;
|
||||
const PTR p2;
|
||||
{
|
||||
char *frst, *scnd;
|
||||
|
||||
frst = (*(char **) p1) + 1;
|
||||
scnd = (*(char **) p2) + 1;
|
||||
|
||||
return strcmp (frst, scnd);
|
||||
}
|
||||
|
||||
char *
|
||||
get_dir_contents (p, device)
|
||||
char *p;
|
||||
int device;
|
||||
{
|
||||
DIR *dirp;
|
||||
register struct dirent *d;
|
||||
char *new_buf;
|
||||
char *namebuf;
|
||||
int bufsiz;
|
||||
int len;
|
||||
PTR the_buffer;
|
||||
char *buf;
|
||||
size_t n_strs;
|
||||
/* int n_size;*/
|
||||
char *p_buf;
|
||||
char **vec, **p_vec;
|
||||
|
||||
extern int errno;
|
||||
|
||||
errno = 0;
|
||||
dirp = opendir (p);
|
||||
bufsiz = strlen (p) + NAMSIZ;
|
||||
namebuf = ck_malloc (bufsiz + 2);
|
||||
if (!dirp)
|
||||
{
|
||||
if (errno)
|
||||
msg_perror ("can't open directory %s", p);
|
||||
else
|
||||
msg ("error opening directory %s", p);
|
||||
new_buf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct dirname *dp;
|
||||
int all_children;
|
||||
|
||||
dp = get_dir (p);
|
||||
all_children = dp ? dp->allnew : 0;
|
||||
(void) strcpy (namebuf, p);
|
||||
if (p[strlen (p) - 1] != '/')
|
||||
(void) strcat (namebuf, "/");
|
||||
len = strlen (namebuf);
|
||||
|
||||
the_buffer = init_buffer ();
|
||||
while (d = readdir (dirp))
|
||||
{
|
||||
struct stat hs;
|
||||
|
||||
/* Skip . and .. */
|
||||
if (is_dot_or_dotdot (d->d_name))
|
||||
continue;
|
||||
if (NLENGTH (d) + len >= bufsiz)
|
||||
{
|
||||
bufsiz += NAMSIZ;
|
||||
namebuf = ck_realloc (namebuf, bufsiz + 2);
|
||||
}
|
||||
(void) strcpy (namebuf + len, d->d_name);
|
||||
#ifdef AIX
|
||||
if (0 != f_follow_links ?
|
||||
statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
|
||||
statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
|
||||
#else
|
||||
if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
|
||||
#endif
|
||||
{
|
||||
msg_perror ("can't stat %s", namebuf);
|
||||
continue;
|
||||
}
|
||||
if ((f_local_filesys && device != hs.st_dev)
|
||||
|| (f_exclude && check_exclude (namebuf)))
|
||||
add_buffer (the_buffer, "N", 1);
|
||||
#ifdef AIX
|
||||
else if (S_ISHIDDEN (hs.st_mode))
|
||||
{
|
||||
add_buffer (the_buffer, "D", 1);
|
||||
strcat (d->d_name, "A");
|
||||
d->d_namlen++;
|
||||
}
|
||||
#endif /* AIX */
|
||||
else if (S_ISDIR (hs.st_mode))
|
||||
{
|
||||
if (dp = get_dir (namebuf))
|
||||
{
|
||||
if (dp->dev != hs.st_dev
|
||||
|| dp->ino != hs.st_ino)
|
||||
{
|
||||
if (f_verbose)
|
||||
msg ("directory %s has been renamed.", namebuf);
|
||||
dp->allnew = 1;
|
||||
dp->dev = hs.st_dev;
|
||||
dp->ino = hs.st_ino;
|
||||
}
|
||||
dp->dir_text = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_verbose)
|
||||
msg ("Directory %s is new", namebuf);
|
||||
add_dir (namebuf, hs.st_dev, hs.st_ino, "");
|
||||
dp = get_dir (namebuf);
|
||||
dp->allnew = 1;
|
||||
}
|
||||
if (all_children)
|
||||
dp->allnew = 1;
|
||||
|
||||
add_buffer (the_buffer, "D", 1);
|
||||
}
|
||||
else if (!all_children
|
||||
&& f_new_files
|
||||
&& new_time > hs.st_mtime
|
||||
&& (f_new_files > 1
|
||||
|| new_time > hs.st_ctime))
|
||||
add_buffer (the_buffer, "N", 1);
|
||||
else
|
||||
add_buffer (the_buffer, "Y", 1);
|
||||
add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
|
||||
}
|
||||
add_buffer (the_buffer, "\000\000", 2);
|
||||
closedir (dirp);
|
||||
|
||||
/* Well, we've read in the contents of the dir, now sort them */
|
||||
buf = get_buffer (the_buffer);
|
||||
if (buf[0] == '\0')
|
||||
{
|
||||
flush_buffer (the_buffer);
|
||||
new_buf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
n_strs = 0;
|
||||
for (p_buf = buf; *p_buf;)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = strlen (p_buf) + 1;
|
||||
n_strs++;
|
||||
p_buf += tmp;
|
||||
}
|
||||
vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
|
||||
for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
|
||||
*p_vec++ = p_buf;
|
||||
*p_vec = 0;
|
||||
qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
|
||||
new_buf = (char *) ck_malloc (p_buf - buf + 2);
|
||||
for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
|
||||
{
|
||||
char *p_tmp;
|
||||
|
||||
for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
|
||||
;
|
||||
}
|
||||
*p_buf++ = '\0';
|
||||
free (vec);
|
||||
flush_buffer (the_buffer);
|
||||
}
|
||||
}
|
||||
free (namebuf);
|
||||
return new_buf;
|
||||
}
|
||||
|
||||
/* p is a directory. Add all the files in P to the namelist. If any of the
|
||||
files is a directory, recurse on the subdirectory. . . */
|
||||
static void
|
||||
add_dir_name (p, device)
|
||||
char *p;
|
||||
int device;
|
||||
{
|
||||
char *new_buf;
|
||||
char *p_buf;
|
||||
|
||||
char *namebuf;
|
||||
int buflen;
|
||||
register int len;
|
||||
int sublen;
|
||||
|
||||
/* PTR the_buffer;*/
|
||||
|
||||
/* char *buf;*/
|
||||
/* char **vec,**p_vec;*/
|
||||
/* int n_strs,n_size;*/
|
||||
|
||||
struct name *n;
|
||||
|
||||
int dirent_cmp ();
|
||||
|
||||
new_buf = get_dir_contents (p, device);
|
||||
|
||||
for (n = namelist; n; n = n->next)
|
||||
{
|
||||
if (!strcmp (n->name, p))
|
||||
{
|
||||
n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_buf)
|
||||
{
|
||||
len = strlen (p);
|
||||
buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
|
||||
namebuf = ck_malloc (buflen + 1);
|
||||
|
||||
(void) strcpy (namebuf, p);
|
||||
if (namebuf[len - 1] != '/')
|
||||
{
|
||||
namebuf[len++] = '/';
|
||||
namebuf[len] = '\0';
|
||||
}
|
||||
for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
|
||||
{
|
||||
sublen = strlen (p_buf);
|
||||
if (*p_buf == 'D')
|
||||
{
|
||||
if (len + sublen >= buflen)
|
||||
{
|
||||
buflen += NAMSIZ;
|
||||
namebuf = ck_realloc (namebuf, buflen + 1);
|
||||
}
|
||||
(void) strcpy (namebuf + len, p_buf + 1);
|
||||
addname (namebuf);
|
||||
add_dir_name (namebuf, device);
|
||||
}
|
||||
}
|
||||
free (namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns non-zero if p is . or .. This could be a macro for speed. */
|
||||
int
|
||||
is_dot_or_dotdot (p)
|
||||
char *p;
|
||||
{
|
||||
return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
gnu_restore (skipcrud)
|
||||
int skipcrud;
|
||||
{
|
||||
char *current_dir;
|
||||
/* int current_dir_length; */
|
||||
|
||||
char *archive_dir;
|
||||
/* int archive_dir_length; */
|
||||
PTR the_buffer;
|
||||
char *p;
|
||||
DIR *dirp;
|
||||
struct dirent *d;
|
||||
char *cur, *arc;
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
long size, copied;
|
||||
char *from, *to;
|
||||
extern union record *head;
|
||||
|
||||
dirp = opendir (skipcrud + current_file_name);
|
||||
|
||||
if (!dirp)
|
||||
{
|
||||
/* The directory doesn't exist now. It'll be created.
|
||||
In any case, we don't have to delete any files out
|
||||
of it */
|
||||
skip_file ((long) hstat.st_size);
|
||||
return;
|
||||
}
|
||||
|
||||
the_buffer = init_buffer ();
|
||||
while (d = readdir (dirp))
|
||||
{
|
||||
if (is_dot_or_dotdot (d->d_name))
|
||||
continue;
|
||||
|
||||
add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
|
||||
}
|
||||
closedir (dirp);
|
||||
add_buffer (the_buffer, "", 1);
|
||||
|
||||
current_dir = get_buffer (the_buffer);
|
||||
archive_dir = (char *) ck_malloc (hstat.st_size);
|
||||
if (archive_dir == 0)
|
||||
{
|
||||
msg ("Can't allocate %d bytes for restore", hstat.st_size);
|
||||
skip_file ((long) hstat.st_size);
|
||||
return;
|
||||
}
|
||||
to = archive_dir;
|
||||
for (size = hstat.st_size; size > 0; size -= copied)
|
||||
{
|
||||
from = findrec ()->charptr;
|
||||
if (!from)
|
||||
{
|
||||
msg ("Unexpected EOF in archive\n");
|
||||
break;
|
||||
}
|
||||
copied = endofrecs ()->charptr - from;
|
||||
if (copied > size)
|
||||
copied = size;
|
||||
bcopy ((PTR) from, (PTR) to, (int) copied);
|
||||
to += copied;
|
||||
userec ((union record *) (from + copied - 1));
|
||||
}
|
||||
|
||||
for (cur = current_dir; *cur; cur += strlen (cur) + 1)
|
||||
{
|
||||
for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
|
||||
{
|
||||
arc++;
|
||||
if (!strcmp (arc, cur))
|
||||
break;
|
||||
}
|
||||
if (*arc == '\0')
|
||||
{
|
||||
p = new_name (skipcrud + current_file_name, cur);
|
||||
if (f_confirm && !confirm ("delete", p))
|
||||
{
|
||||
free (p);
|
||||
continue;
|
||||
}
|
||||
if (f_verbose)
|
||||
fprintf (msg_file, "%s: deleting %s\n", tar, p);
|
||||
if (recursively_delete (p))
|
||||
{
|
||||
msg ("%s: Error while deleting %s\n", tar, p);
|
||||
}
|
||||
free (p);
|
||||
}
|
||||
|
||||
}
|
||||
flush_buffer (the_buffer);
|
||||
free (archive_dir);
|
||||
}
|
||||
|
||||
int
|
||||
recursively_delete (path)
|
||||
char *path;
|
||||
{
|
||||
struct stat sbuf;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char *path_buf;
|
||||
/* int path_len; */
|
||||
|
||||
|
||||
if (lstat (path, &sbuf) < 0)
|
||||
return 1;
|
||||
if (S_ISDIR (sbuf.st_mode))
|
||||
{
|
||||
|
||||
/* path_len=strlen(path); */
|
||||
dirp = opendir (path);
|
||||
if (dirp == 0)
|
||||
return 1;
|
||||
while (dp = readdir (dirp))
|
||||
{
|
||||
if (is_dot_or_dotdot (dp->d_name))
|
||||
continue;
|
||||
path_buf = new_name (path, dp->d_name);
|
||||
if (recursively_delete (path_buf))
|
||||
{
|
||||
free (path_buf);
|
||||
closedir (dirp);
|
||||
return 1;
|
||||
}
|
||||
free (path_buf);
|
||||
}
|
||||
closedir (dirp);
|
||||
|
||||
if (rmdir (path) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (unlink (path) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
@ -1,894 +0,0 @@
|
||||
/* List a tar archive.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$FreeBSD$
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* List a tar archive.
|
||||
*
|
||||
* Also includes support routines for reading a tar archive.
|
||||
*
|
||||
* this version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <langinfo.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
extern FILE *msg_file;
|
||||
|
||||
long from_oct (); /* Decode octal number */
|
||||
void demode (); /* Print file mode */
|
||||
void restore_saved_dir_info ();
|
||||
PTR ck_malloc ();
|
||||
|
||||
union record *head; /* Points to current archive header */
|
||||
struct stat hstat; /* Stat struct corresponding */
|
||||
int head_standard; /* Tape header is in ANSI format */
|
||||
|
||||
int check_exclude ();
|
||||
void close_archive ();
|
||||
void decode_header ();
|
||||
int findgid ();
|
||||
int finduid ();
|
||||
void name_gather ();
|
||||
int name_match ();
|
||||
void names_notfound ();
|
||||
void open_archive ();
|
||||
void print_header ();
|
||||
int read_header ();
|
||||
void saverec ();
|
||||
void skip_file ();
|
||||
void skip_extended_headers ();
|
||||
|
||||
extern char *quote_copy_string ();
|
||||
|
||||
|
||||
/*
|
||||
* Main loop for reading an archive.
|
||||
*/
|
||||
void
|
||||
read_and (do_something)
|
||||
void (*do_something) ();
|
||||
{
|
||||
int status = 3; /* Initial status at start of archive */
|
||||
int prev_status;
|
||||
extern time_t new_time;
|
||||
char save_linkflag;
|
||||
|
||||
name_gather (); /* Gather all the names */
|
||||
open_archive (1); /* Open for reading */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
prev_status = status;
|
||||
status = read_header ();
|
||||
/* check if the namelist got emptied during the course of reading */
|
||||
/* the tape, if so stop by setting status to EOF */
|
||||
if ((namelist == NULL) && nlpsfreed) {
|
||||
status = EOF;
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
|
||||
case 1: /* Valid header */
|
||||
/* We should decode next field (mode) first... */
|
||||
/* Ensure incoming names are null terminated. */
|
||||
|
||||
if (!name_match (current_file_name)
|
||||
|| (f_new_files && hstat.st_mtime < new_time)
|
||||
|| (f_exclude && check_exclude (current_file_name)))
|
||||
{
|
||||
|
||||
int isextended = 0;
|
||||
|
||||
if (head->header.linkflag == LF_VOLHDR
|
||||
|| head->header.linkflag == LF_MULTIVOL
|
||||
|| head->header.linkflag == LF_NAMES)
|
||||
{
|
||||
(*do_something) ();
|
||||
continue;
|
||||
}
|
||||
if (f_show_omitted_dirs
|
||||
&& head->header.linkflag == LF_DIR)
|
||||
msg ("Omitting %s\n", current_file_name);
|
||||
/* Skip past it in the archive */
|
||||
if (head->header.isextended)
|
||||
isextended = 1;
|
||||
save_linkflag = head->header.linkflag;
|
||||
userec (head);
|
||||
if (isextended)
|
||||
{
|
||||
/* register union record *exhdr;
|
||||
|
||||
for (;;) {
|
||||
exhdr = findrec();
|
||||
if (!exhdr->ext_hdr.isextended) {
|
||||
userec(exhdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
userec(exhdr);*/
|
||||
skip_extended_headers ();
|
||||
}
|
||||
/* Skip to the next header on the archive */
|
||||
if (save_linkflag != LF_DIR)
|
||||
skip_file ((long) hstat.st_size);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
(*do_something) ();
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If the previous header was good, tell them
|
||||
* that we are skipping bad ones.
|
||||
*/
|
||||
case 0: /* Invalid header */
|
||||
userec (head);
|
||||
switch (prev_status)
|
||||
{
|
||||
case 3: /* Error on first record */
|
||||
msg ("Hmm, this doesn't look like a tar archive.");
|
||||
/* FALL THRU */
|
||||
case 2: /* Error after record of zeroes */
|
||||
case 1: /* Error after header rec */
|
||||
msg ("Skipping to next file header...");
|
||||
case 0: /* Error after error */
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case 2: /* Record of zeroes */
|
||||
userec (head);
|
||||
status = prev_status; /* If error after 0's */
|
||||
if (f_ignorez)
|
||||
continue;
|
||||
/* FALL THRU */
|
||||
case EOF: /* End of archive */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
restore_saved_dir_info ();
|
||||
close_archive ();
|
||||
names_notfound (); /* Print names not found */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print a header record, based on tar options.
|
||||
*/
|
||||
void
|
||||
list_archive ()
|
||||
{
|
||||
extern char *save_name;
|
||||
int isextended = 0; /* Flag to remember if head is extended */
|
||||
|
||||
/* Save the record */
|
||||
saverec (&head);
|
||||
|
||||
/* Print the header record */
|
||||
if (f_verbose)
|
||||
{
|
||||
if (f_verbose > 1)
|
||||
decode_header (head, &hstat, &head_standard, 0);
|
||||
print_header ();
|
||||
}
|
||||
|
||||
if (f_gnudump && head->header.linkflag == LF_DUMPDIR)
|
||||
{
|
||||
size_t size, written, check;
|
||||
char *data;
|
||||
extern long save_totsize;
|
||||
extern long save_sizeleft;
|
||||
|
||||
userec (head);
|
||||
if (f_multivol)
|
||||
{
|
||||
save_name = current_file_name;
|
||||
save_totsize = hstat.st_size;
|
||||
}
|
||||
for (size = hstat.st_size; size > 0; size -= written)
|
||||
{
|
||||
if (f_multivol)
|
||||
save_sizeleft = size;
|
||||
data = findrec ()->charptr;
|
||||
if (data == NULL)
|
||||
{
|
||||
msg ("EOF in archive file?");
|
||||
break;
|
||||
}
|
||||
written = endofrecs ()->charptr - data;
|
||||
if (written > size)
|
||||
written = size;
|
||||
errno = 0;
|
||||
check = fwrite (data, sizeof (char), written, msg_file);
|
||||
userec ((union record *) (data + written - 1));
|
||||
if (check != written)
|
||||
{
|
||||
msg_perror ("only wrote %ld of %ld bytes to file %s", check, written, current_file_name);
|
||||
skip_file ((long) (size) - written);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f_multivol)
|
||||
save_name = 0;
|
||||
saverec ((union record **) 0); /* Unsave it */
|
||||
fputc ('\n', msg_file);
|
||||
fflush (msg_file);
|
||||
return;
|
||||
|
||||
}
|
||||
saverec ((union record **) 0);/* Unsave it */
|
||||
/* Check to see if we have an extended header to skip over also */
|
||||
if (head->header.isextended)
|
||||
isextended = 1;
|
||||
|
||||
/* Skip past the header in the archive */
|
||||
userec (head);
|
||||
|
||||
/*
|
||||
* If we needed to skip any extended headers, do so now, by
|
||||
* reading extended headers and skipping past them in the
|
||||
* archive.
|
||||
*/
|
||||
if (isextended)
|
||||
{
|
||||
/* register union record *exhdr;
|
||||
|
||||
for (;;) {
|
||||
exhdr = findrec();
|
||||
|
||||
if (!exhdr->ext_hdr.isextended) {
|
||||
userec(exhdr);
|
||||
break;
|
||||
}
|
||||
userec(exhdr);
|
||||
}*/
|
||||
skip_extended_headers ();
|
||||
}
|
||||
|
||||
if (f_multivol)
|
||||
save_name = current_file_name;
|
||||
/* Skip to the next header on the archive */
|
||||
|
||||
skip_file ((long) hstat.st_size);
|
||||
|
||||
if (f_multivol)
|
||||
save_name = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a record that's supposed to be a header record.
|
||||
* Return its address in "head", and if it is good, the file's
|
||||
* size in hstat.st_size.
|
||||
*
|
||||
* Return 1 for success, 0 if the checksum is bad, EOF on eof,
|
||||
* 2 for a record full of zeros (EOF marker).
|
||||
*
|
||||
* You must always userec(head) to skip past the header which this
|
||||
* routine reads.
|
||||
*/
|
||||
int
|
||||
read_header ()
|
||||
{
|
||||
register int i;
|
||||
register long sum, signed_sum, recsum;
|
||||
register char *p;
|
||||
register union record *header;
|
||||
long from_oct ();
|
||||
char **longp;
|
||||
char *bp, *data;
|
||||
int size, written;
|
||||
static char *next_long_name, *next_long_link;
|
||||
char *name;
|
||||
|
||||
recurse:
|
||||
|
||||
header = findrec ();
|
||||
head = header; /* This is our current header */
|
||||
if (NULL == header)
|
||||
return EOF;
|
||||
|
||||
recsum = from_oct (8, header->header.chksum);
|
||||
|
||||
signed_sum = sum = 0;
|
||||
p = header->charptr;
|
||||
for (i = sizeof (*header); --i >= 0;)
|
||||
{
|
||||
/*
|
||||
* We can't use unsigned char here because of old compilers,
|
||||
* e.g. V7.
|
||||
*/
|
||||
signed_sum += *p;
|
||||
sum += 0xFF & *p++;
|
||||
}
|
||||
|
||||
/* Adjust checksum to count the "chksum" field as blanks. */
|
||||
for (i = sizeof (header->header.chksum); --i >= 0;)
|
||||
{
|
||||
sum -= 0xFF & header->header.chksum[i];
|
||||
signed_sum -= (char) header->header.chksum[i];
|
||||
}
|
||||
sum += ' ' * sizeof header->header.chksum;
|
||||
signed_sum += ' ' * sizeof header->header.chksum;
|
||||
|
||||
if (sum == 8 * ' ')
|
||||
{
|
||||
/*
|
||||
* This is a zeroed record...whole record is 0's except
|
||||
* for the 8 blanks we faked for the checksum field.
|
||||
*/
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (sum != recsum && signed_sum != recsum)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Good record. Decode file size and return.
|
||||
*/
|
||||
if (header->header.linkflag == LF_LINK)
|
||||
hstat.st_size = 0; /* Links 0 size on tape */
|
||||
else
|
||||
hstat.st_size = from_oct (1 + 12, header->header.size);
|
||||
|
||||
header->header.arch_name[NAMSIZ - 1] = '\0';
|
||||
if (header->header.linkflag == LF_LONGNAME
|
||||
|| header->header.linkflag == LF_LONGLINK)
|
||||
{
|
||||
longp = ((header->header.linkflag == LF_LONGNAME)
|
||||
? &next_long_name
|
||||
: &next_long_link);
|
||||
|
||||
userec (header);
|
||||
if (*longp)
|
||||
free (*longp);
|
||||
bp = *longp = (char *) ck_malloc (hstat.st_size);
|
||||
|
||||
for (size = hstat.st_size;
|
||||
size > 0;
|
||||
size -= written)
|
||||
{
|
||||
data = findrec ()->charptr;
|
||||
if (data == NULL)
|
||||
{
|
||||
msg ("Unexpected EOF on archive file");
|
||||
break;
|
||||
}
|
||||
written = endofrecs ()->charptr - data;
|
||||
if (written > size)
|
||||
written = size;
|
||||
|
||||
bcopy (data, bp, written);
|
||||
bp += written;
|
||||
userec ((union record *) (data + written - 1));
|
||||
}
|
||||
goto recurse;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = (next_long_name
|
||||
? next_long_name
|
||||
: head->header.arch_name);
|
||||
if (current_file_name)
|
||||
free (current_file_name);
|
||||
current_file_name = ck_malloc (strlen (name) + 1);
|
||||
strcpy (current_file_name, name);
|
||||
|
||||
name = (next_long_link
|
||||
? next_long_link
|
||||
: head->header.arch_linkname);
|
||||
if (current_link_name)
|
||||
free (current_link_name);
|
||||
current_link_name = ck_malloc (strlen (name) + 1);
|
||||
strcpy (current_link_name, name);
|
||||
|
||||
next_long_link = next_long_name = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decode things from a file header record into a "struct stat".
|
||||
* Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
|
||||
* Standard" tar format or regular old tar format.
|
||||
*
|
||||
* read_header() has already decoded the checksum and length, so we don't.
|
||||
*
|
||||
* If wantug != 0, we want the uid/group info decoded from Unix Standard
|
||||
* tapes (for extraction). If == 0, we are just printing anyway, so save time.
|
||||
*
|
||||
* decode_header should NOT be called twice for the same record, since the
|
||||
* two calls might use different "wantug" values and thus might end up with
|
||||
* different uid/gid for the two calls. If anybody wants the uid/gid they
|
||||
* should decode it first, and other callers should decode it without uid/gid
|
||||
* before calling a routine, e.g. print_header, that assumes decoded data.
|
||||
*/
|
||||
void
|
||||
decode_header (header, st, stdp, wantug)
|
||||
register union record *header;
|
||||
register struct stat *st;
|
||||
int *stdp;
|
||||
int wantug;
|
||||
{
|
||||
long from_oct ();
|
||||
|
||||
st->st_mode = from_oct (8, header->header.mode);
|
||||
st->st_mode &= 07777;
|
||||
st->st_mtime = from_oct (1 + 12, header->header.mtime);
|
||||
if (f_gnudump)
|
||||
{
|
||||
st->st_atime = from_oct (1 + 12, header->header.atime);
|
||||
st->st_ctime = from_oct (1 + 12, header->header.ctime);
|
||||
}
|
||||
|
||||
if (0 == strcmp (header->header.magic, TMAGIC))
|
||||
{
|
||||
/* Unix Standard tar archive */
|
||||
*stdp = 1;
|
||||
if (wantug)
|
||||
{
|
||||
#ifdef NONAMES
|
||||
st->st_uid = from_oct (8, header->header.uid);
|
||||
st->st_gid = from_oct (8, header->header.gid);
|
||||
#else
|
||||
st->st_uid =
|
||||
(*header->header.uname
|
||||
? finduid (header->header.uname)
|
||||
: from_oct (8, header->header.uid));
|
||||
st->st_gid =
|
||||
(*header->header.gname
|
||||
? findgid (header->header.gname)
|
||||
: from_oct (8, header->header.gid));
|
||||
#endif
|
||||
}
|
||||
#if defined(S_IFBLK) || defined(S_IFCHR)
|
||||
switch (header->header.linkflag)
|
||||
{
|
||||
case LF_BLK:
|
||||
case LF_CHR:
|
||||
st->st_rdev = makedev (from_oct (8, header->header.devmajor),
|
||||
from_oct (8, header->header.devminor));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Old fashioned tar archive */
|
||||
*stdp = 0;
|
||||
st->st_uid = from_oct (8, header->header.uid);
|
||||
st->st_gid = from_oct (8, header->header.gid);
|
||||
st->st_rdev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Quick and dirty octal conversion.
|
||||
*
|
||||
* Result is -1 if the field is invalid (all blank, or nonoctal).
|
||||
*/
|
||||
long
|
||||
from_oct (digs, where)
|
||||
register int digs;
|
||||
register char *where;
|
||||
{
|
||||
register long value;
|
||||
|
||||
while (isspace ((unsigned char) *where))
|
||||
{ /* Skip spaces */
|
||||
where++;
|
||||
if (--digs <= 0)
|
||||
return -1; /* All blank field */
|
||||
}
|
||||
value = 0;
|
||||
while (digs > 0 && isodigit (*where))
|
||||
{ /* Scan til nonoctal */
|
||||
value = (value << 3) | (*where++ - '0');
|
||||
--digs;
|
||||
}
|
||||
|
||||
if (digs > 0 && *where && !isspace ((unsigned char) *where))
|
||||
return -1; /* Ended on non-space/nul */
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Actually print it.
|
||||
*
|
||||
* Plain and fancy file header block logging.
|
||||
* Non-verbose just prints the name, e.g. for "tar t" or "tar x".
|
||||
* This should just contain file names, so it can be fed back into tar
|
||||
* with xargs or the "-T" option. The verbose option can give a bunch
|
||||
* of info, one line per file. I doubt anybody tries to parse its
|
||||
* format, or if they do, they shouldn't. Unix tar is pretty random here
|
||||
* anyway.
|
||||
*
|
||||
* Note that print_header uses the globals <head>, <hstat>, and
|
||||
* <head_standard>, which must be set up in advance. This is not very clean
|
||||
* and should be cleaned up. FIXME.
|
||||
*/
|
||||
#define UGSWIDTH 18 /* min width of User, group, size */
|
||||
/* UGSWIDTH of 18 means that with user and group names <= 8 chars the columns
|
||||
never shift during the listing. */
|
||||
#define DATEWIDTH 19 /* Last mod date */
|
||||
static int ugswidth = UGSWIDTH; /* Max width encountered so far */
|
||||
|
||||
void
|
||||
print_header ()
|
||||
{
|
||||
char modes[11];
|
||||
char timestamp[80];
|
||||
char uform[11], gform[11]; /* These hold formatted ints */
|
||||
char *user, *group;
|
||||
char size[24]; /* Holds a formatted long or maj, min */
|
||||
time_t longie;
|
||||
int pad;
|
||||
static int d_first = -1;
|
||||
char *name;
|
||||
extern long baserec;
|
||||
|
||||
if (f_sayblock)
|
||||
fprintf (msg_file, "rec %10ld: ", baserec + (ar_record - ar_block));
|
||||
/* annofile(msg_file, (char *)NULL); */
|
||||
|
||||
if (f_verbose <= 1)
|
||||
{
|
||||
/* Just the fax, mam. */
|
||||
char *name;
|
||||
|
||||
name = quote_copy_string (current_file_name);
|
||||
if (name == 0)
|
||||
name = current_file_name;
|
||||
fprintf (msg_file, "%s\n", name);
|
||||
if (name != current_file_name)
|
||||
free (name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* File type and modes */
|
||||
modes[0] = '?';
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
case LF_VOLHDR:
|
||||
modes[0] = 'V';
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
modes[0] = 'M';
|
||||
break;
|
||||
|
||||
case LF_NAMES:
|
||||
modes[0] = 'N';
|
||||
break;
|
||||
|
||||
case LF_LONGNAME:
|
||||
case LF_LONGLINK:
|
||||
msg ("Visible longname error\n");
|
||||
break;
|
||||
|
||||
case LF_SPARSE:
|
||||
case LF_NORMAL:
|
||||
case LF_OLDNORMAL:
|
||||
case LF_LINK:
|
||||
modes[0] = '-';
|
||||
if ('/' == current_file_name[strlen (current_file_name) - 1])
|
||||
modes[0] = 'd';
|
||||
break;
|
||||
case LF_DUMPDIR:
|
||||
modes[0] = 'd';
|
||||
break;
|
||||
case LF_DIR:
|
||||
modes[0] = 'd';
|
||||
break;
|
||||
case LF_SYMLINK:
|
||||
modes[0] = 'l';
|
||||
break;
|
||||
case LF_BLK:
|
||||
modes[0] = 'b';
|
||||
break;
|
||||
case LF_CHR:
|
||||
modes[0] = 'c';
|
||||
break;
|
||||
case LF_FIFO:
|
||||
modes[0] = 'p';
|
||||
break;
|
||||
case LF_CONTIG:
|
||||
modes[0] = 'C';
|
||||
break;
|
||||
}
|
||||
|
||||
demode ((unsigned) hstat.st_mode, modes + 1);
|
||||
|
||||
/* Timestamp */
|
||||
if (d_first < 0)
|
||||
d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
|
||||
longie = hstat.st_mtime;
|
||||
strftime(timestamp, sizeof(timestamp),
|
||||
d_first ? "%e %b %R %Y" : "%b %e %R %Y",
|
||||
localtime(&longie));
|
||||
|
||||
/* User and group names */
|
||||
if (*head->header.uname && head_standard)
|
||||
{
|
||||
user = head->header.uname;
|
||||
}
|
||||
else
|
||||
{
|
||||
user = uform;
|
||||
(void) sprintf (uform, "%ld",
|
||||
from_oct (8, head->header.uid));
|
||||
}
|
||||
if (*head->header.gname && head_standard)
|
||||
{
|
||||
group = head->header.gname;
|
||||
}
|
||||
else
|
||||
{
|
||||
group = gform;
|
||||
(void) sprintf (gform, "%ld",
|
||||
from_oct (8, head->header.gid));
|
||||
}
|
||||
|
||||
/* Format the file size or major/minor device numbers */
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
#if defined(S_IFBLK) || defined(S_IFCHR)
|
||||
case LF_CHR:
|
||||
case LF_BLK:
|
||||
(void) sprintf (size, "%d,%d",
|
||||
major (hstat.st_rdev),
|
||||
minor (hstat.st_rdev));
|
||||
break;
|
||||
#endif
|
||||
case LF_SPARSE:
|
||||
(void) sprintf (size, "%ld",
|
||||
from_oct (1 + 12, head->header.realsize));
|
||||
break;
|
||||
default:
|
||||
(void) sprintf (size, "%ld", (long) hstat.st_size);
|
||||
}
|
||||
|
||||
/* Figure out padding and print the whole line. */
|
||||
pad = strlen (user) + strlen (group) + strlen (size) + 1;
|
||||
if (pad > ugswidth)
|
||||
ugswidth = pad;
|
||||
|
||||
name = quote_copy_string (current_file_name);
|
||||
if (!name)
|
||||
name = current_file_name;
|
||||
fprintf (msg_file, "%s %s/%s %*s%s %s %s",
|
||||
modes,
|
||||
user,
|
||||
group,
|
||||
ugswidth - pad,
|
||||
"",
|
||||
size,
|
||||
timestamp,
|
||||
name);
|
||||
|
||||
if (name != current_file_name)
|
||||
free (name);
|
||||
switch (head->header.linkflag)
|
||||
{
|
||||
case LF_SYMLINK:
|
||||
name = quote_copy_string (current_link_name);
|
||||
if (!name)
|
||||
name = current_link_name;
|
||||
fprintf (msg_file, " -> %s\n", name);
|
||||
if (name != current_link_name)
|
||||
free (name);
|
||||
break;
|
||||
|
||||
case LF_LINK:
|
||||
name = quote_copy_string (current_link_name);
|
||||
if (!name)
|
||||
name = current_link_name;
|
||||
fprintf (msg_file, " link to %s\n", current_link_name);
|
||||
if (name != current_link_name)
|
||||
free (name);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (msg_file, " unknown file type '%c'\n",
|
||||
head->header.linkflag);
|
||||
break;
|
||||
|
||||
case LF_OLDNORMAL:
|
||||
case LF_NORMAL:
|
||||
case LF_SPARSE:
|
||||
case LF_CHR:
|
||||
case LF_BLK:
|
||||
case LF_DIR:
|
||||
case LF_FIFO:
|
||||
case LF_CONTIG:
|
||||
case LF_DUMPDIR:
|
||||
putc ('\n', msg_file);
|
||||
break;
|
||||
|
||||
case LF_VOLHDR:
|
||||
fprintf (msg_file, "--Volume Header--\n");
|
||||
break;
|
||||
|
||||
case LF_MULTIVOL:
|
||||
fprintf (msg_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset));
|
||||
break;
|
||||
|
||||
case LF_NAMES:
|
||||
fprintf (msg_file, "--Mangled file names--\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fflush (msg_file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a similar line when we make a directory automatically.
|
||||
*/
|
||||
void
|
||||
pr_mkdir (pathname, length, mode)
|
||||
char *pathname;
|
||||
int length;
|
||||
int mode;
|
||||
{
|
||||
char modes[11];
|
||||
char *name;
|
||||
extern long baserec;
|
||||
|
||||
if (f_verbose > 1)
|
||||
{
|
||||
/* File type and modes */
|
||||
modes[0] = 'd';
|
||||
demode ((unsigned) mode, modes + 1);
|
||||
|
||||
if (f_sayblock)
|
||||
fprintf (msg_file, "rec %10ld: ", baserec + (ar_record - ar_block));
|
||||
/* annofile(msg_file, (char *)NULL); */
|
||||
name = quote_copy_string (pathname);
|
||||
if (!name)
|
||||
name = pathname;
|
||||
fprintf (msg_file, "%s %*s %.*s\n",
|
||||
modes,
|
||||
ugswidth + DATEWIDTH,
|
||||
"Creating directory:",
|
||||
length,
|
||||
pathname);
|
||||
if (name != pathname)
|
||||
free (name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skip over <size> bytes of data in records in the archive.
|
||||
*/
|
||||
void
|
||||
skip_file (size)
|
||||
register long size;
|
||||
{
|
||||
union record *x;
|
||||
extern long save_totsize;
|
||||
extern long save_sizeleft;
|
||||
|
||||
if (f_multivol)
|
||||
{
|
||||
save_totsize = size;
|
||||
save_sizeleft = size;
|
||||
}
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
x = findrec ();
|
||||
if (x == NULL)
|
||||
{ /* Check it... */
|
||||
msg ("Unexpected EOF on archive file");
|
||||
exit (EX_BADARCH);
|
||||
}
|
||||
userec (x);
|
||||
size -= RECORDSIZE;
|
||||
if (f_multivol)
|
||||
save_sizeleft -= RECORDSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
skip_extended_headers ()
|
||||
{
|
||||
register union record *exhdr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
exhdr = findrec ();
|
||||
if (!exhdr->ext_hdr.isextended)
|
||||
{
|
||||
userec (exhdr);
|
||||
break;
|
||||
}
|
||||
userec (exhdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the mode string from a stat entry into a 9-char string and a null.
|
||||
*/
|
||||
void
|
||||
demode (mode, string)
|
||||
register unsigned mode;
|
||||
register char *string;
|
||||
{
|
||||
register unsigned mask;
|
||||
register char *rwx = "rwxrwxrwx";
|
||||
|
||||
for (mask = 0400; mask != 0; mask >>= 1)
|
||||
{
|
||||
if (mode & mask)
|
||||
*string++ = *rwx++;
|
||||
else
|
||||
{
|
||||
*string++ = '-';
|
||||
rwx++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & S_ISUID)
|
||||
if (string[-7] == 'x')
|
||||
string[-7] = 's';
|
||||
else
|
||||
string[-7] = 'S';
|
||||
if (mode & S_ISGID)
|
||||
if (string[-4] == 'x')
|
||||
string[-4] = 's';
|
||||
else
|
||||
string[-4] = 'S';
|
||||
if (mode & S_ISVTX)
|
||||
if (string[-1] == 'x')
|
||||
string[-1] = 't';
|
||||
else
|
||||
string[-1] = 'T';
|
||||
*string = '\0';
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
/* mangle.c -- encode long filenames
|
||||
Copyright (C) 1988, 1992 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
time_t time ();
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
void add_buffer ();
|
||||
extern PTR ck_malloc ();
|
||||
void finish_header ();
|
||||
extern PTR init_buffer ();
|
||||
extern char *quote_copy_string ();
|
||||
extern char *get_buffer ();
|
||||
char *un_quote_string ();
|
||||
|
||||
extern union record *start_header ();
|
||||
|
||||
extern struct stat hstat; /* Stat struct corresponding */
|
||||
|
||||
struct mangled
|
||||
{
|
||||
struct mangled *next;
|
||||
int type;
|
||||
char mangled[NAMSIZ];
|
||||
char *linked_to;
|
||||
char normal[1];
|
||||
};
|
||||
|
||||
|
||||
/* Should use a hash table, etc. . */
|
||||
struct mangled *first_mangle;
|
||||
int mangled_num = 0;
|
||||
|
||||
#if 0 /* Deleted because there is now a better way to do all this */
|
||||
|
||||
char *
|
||||
find_mangled (name)
|
||||
char *name;
|
||||
{
|
||||
struct mangled *munge;
|
||||
|
||||
for (munge = first_mangle; munge; munge = munge->next)
|
||||
if (!strcmp (name, munge->normal))
|
||||
return munge->mangled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef S_ISLNK
|
||||
void
|
||||
add_symlink_mangle (symlink, linkto, buffer)
|
||||
char *symlink;
|
||||
char *linkto;
|
||||
char *buffer;
|
||||
{
|
||||
struct mangled *munge, *kludge;
|
||||
|
||||
munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (symlink) + strlen (linkto) + 2);
|
||||
if (!first_mangle)
|
||||
first_mangle = munge;
|
||||
else
|
||||
{
|
||||
for (kludge = first_mangle; kludge->next; kludge = kludge->next)
|
||||
;
|
||||
kludge->next = munge;
|
||||
}
|
||||
munge->type = 1;
|
||||
munge->next = 0;
|
||||
strcpy (munge->normal, symlink);
|
||||
munge->linked_to = munge->normal + strlen (symlink) + 1;
|
||||
strcpy (munge->linked_to, linkto);
|
||||
sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++);
|
||||
strncpy (buffer, munge->mangled, NAMSIZ);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
add_mangle (name, buffer)
|
||||
char *name;
|
||||
char *buffer;
|
||||
{
|
||||
struct mangled *munge, *kludge;
|
||||
|
||||
munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (name));
|
||||
if (!first_mangle)
|
||||
first_mangle = munge;
|
||||
else
|
||||
{
|
||||
for (kludge = first_mangle; kludge->next; kludge = kludge->next)
|
||||
;
|
||||
kludge->next = munge;
|
||||
}
|
||||
munge->next = 0;
|
||||
munge->type = 0;
|
||||
strcpy (munge->normal, name);
|
||||
sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++);
|
||||
strncpy (buffer, munge->mangled, NAMSIZ);
|
||||
}
|
||||
|
||||
void
|
||||
write_mangled ()
|
||||
{
|
||||
struct mangled *munge;
|
||||
struct stat hstat;
|
||||
union record *header;
|
||||
char *ptr1, *ptr2;
|
||||
PTR the_buffer;
|
||||
int size;
|
||||
int bufsize;
|
||||
|
||||
if (!first_mangle)
|
||||
return;
|
||||
the_buffer = init_buffer ();
|
||||
for (munge = first_mangle, size = 0; munge; munge = munge->next)
|
||||
{
|
||||
ptr1 = quote_copy_string (munge->normal);
|
||||
if (!ptr1)
|
||||
ptr1 = munge->normal;
|
||||
if (munge->type)
|
||||
{
|
||||
add_buffer (the_buffer, "Symlink ", 8);
|
||||
add_buffer (the_buffer, ptr1, strlen (ptr1));
|
||||
add_buffer (the_buffer, " to ", 4);
|
||||
|
||||
if (ptr2 = quote_copy_string (munge->linked_to))
|
||||
{
|
||||
add_buffer (the_buffer, ptr2, strlen (ptr2));
|
||||
free (ptr2);
|
||||
}
|
||||
else
|
||||
add_buffer (the_buffer, munge->linked_to, strlen (munge->linked_to));
|
||||
}
|
||||
else
|
||||
{
|
||||
add_buffer (the_buffer, "Rename ", 7);
|
||||
add_buffer (the_buffer, munge->mangled, strlen (munge->mangled));
|
||||
add_buffer (the_buffer, " to ", 4);
|
||||
add_buffer (the_buffer, ptr1, strlen (ptr1));
|
||||
}
|
||||
add_buffer (the_buffer, "\n", 1);
|
||||
if (ptr1 != munge->normal)
|
||||
free (ptr1);
|
||||
}
|
||||
|
||||
bzero (&hstat, sizeof (struct stat));
|
||||
hstat.st_atime = hstat.st_mtime = hstat.st_ctime = time (0);
|
||||
ptr1 = get_buffer (the_buffer);
|
||||
hstat.st_size = strlen (ptr1);
|
||||
|
||||
header = start_header ("././@MaNgLeD_NaMeS", &hstat);
|
||||
header->header.linkflag = LF_NAMES;
|
||||
finish_header (header);
|
||||
size = hstat.st_size;
|
||||
header = findrec ();
|
||||
bufsize = endofrecs ()->charptr - header->charptr;
|
||||
|
||||
while (bufsize < size)
|
||||
{
|
||||
bcopy (ptr1, header->charptr, bufsize);
|
||||
ptr1 += bufsize;
|
||||
size -= bufsize;
|
||||
userec (header + (bufsize - 1) / RECORDSIZE);
|
||||
header = findrec ();
|
||||
bufsize = endofrecs ()->charptr - header->charptr;
|
||||
}
|
||||
bcopy (ptr1, header->charptr, size);
|
||||
bzero (header->charptr + size, bufsize - size);
|
||||
userec (header + (size - 1) / RECORDSIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
extract_mangle (head)
|
||||
union record *head;
|
||||
{
|
||||
char *buf;
|
||||
char *fromtape;
|
||||
char *to;
|
||||
char *ptr, *ptrend;
|
||||
char *nam1, *nam1end;
|
||||
int size;
|
||||
int copied;
|
||||
|
||||
size = hstat.st_size;
|
||||
buf = to = ck_malloc (size + 1);
|
||||
buf[size] = '\0';
|
||||
while (size > 0)
|
||||
{
|
||||
fromtape = findrec ()->charptr;
|
||||
if (fromtape == 0)
|
||||
{
|
||||
msg ("Unexpected EOF in mangled names!");
|
||||
return;
|
||||
}
|
||||
copied = endofrecs ()->charptr - fromtape;
|
||||
if (copied > size)
|
||||
copied = size;
|
||||
bcopy (fromtape, to, copied);
|
||||
to += copied;
|
||||
size -= copied;
|
||||
userec ((union record *) (fromtape + copied - 1));
|
||||
}
|
||||
for (ptr = buf; *ptr; ptr = ptrend)
|
||||
{
|
||||
ptrend = index (ptr, '\n');
|
||||
*ptrend++ = '\0';
|
||||
|
||||
if (!strncmp (ptr, "Rename ", 7))
|
||||
{
|
||||
nam1 = ptr + 7;
|
||||
nam1end = index (nam1, ' ');
|
||||
while (strncmp (nam1end, " to ", 4))
|
||||
{
|
||||
nam1end++;
|
||||
nam1end = index (nam1end, ' ');
|
||||
}
|
||||
*nam1end = '\0';
|
||||
if (ptrend[-2] == '/')
|
||||
ptrend[-2] = '\0';
|
||||
un_quote_string (nam1end + 4);
|
||||
if (rename (nam1, nam1end + 4))
|
||||
msg_perror ("Can't rename %s to %s", nam1, nam1end + 4);
|
||||
else if (f_verbose)
|
||||
msg ("Renamed %s to %s", nam1, nam1end + 4);
|
||||
}
|
||||
#ifdef S_ISLNK
|
||||
else if (!strncmp (ptr, "Symlink ", 8))
|
||||
{
|
||||
nam1 = ptr + 8;
|
||||
nam1end = index (nam1, ' ');
|
||||
while (strncmp (nam1end, " to ", 4))
|
||||
{
|
||||
nam1end++;
|
||||
nam1end = index (nam1end, ' ');
|
||||
}
|
||||
*nam1end = '\0';
|
||||
un_quote_string (nam1);
|
||||
un_quote_string (nam1end + 4);
|
||||
if (symlink (nam1, nam1end + 4) && (unlink (nam1end + 4) || symlink (nam1, nam1end + 4)))
|
||||
msg_perror ("Can't symlink %s to %s", nam1, nam1end + 4);
|
||||
else if (f_verbose)
|
||||
msg ("Symlinkd %s to %s", nam1, nam1end + 4);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
msg ("Unknown demangling command %s", ptr);
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* @(#)msd_dir.h 1.4 87/11/06 Public Domain.
|
||||
*
|
||||
* A public domain implementation of BSD directory routines for
|
||||
* MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
|
||||
* August 1897
|
||||
*/
|
||||
|
||||
#define rewinddir(dirp) seekdir(dirp, 0L)
|
||||
|
||||
#define MAXNAMLEN 12
|
||||
|
||||
#ifdef __TURBOC__
|
||||
typedef int ino_t;
|
||||
typedef int dev_t;
|
||||
#endif
|
||||
|
||||
struct dirent
|
||||
{
|
||||
ino_t d_ino; /* a bit of a farce */
|
||||
int d_reclen; /* more farce */
|
||||
int d_namlen; /* length of d_name */
|
||||
char d_name[MAXNAMLEN + 1]; /* garentee null termination */
|
||||
};
|
||||
|
||||
struct _dircontents
|
||||
{
|
||||
char *_d_entry;
|
||||
struct _dircontents *_d_next;
|
||||
};
|
||||
|
||||
typedef struct _dirdesc
|
||||
{
|
||||
int dd_id; /* uniquely identify each open directory */
|
||||
long dd_loc; /* where we are in directory entry is this */
|
||||
struct _dircontents *dd_contents; /* pointer to contents of dir */
|
||||
struct _dircontents *dd_cp; /* pointer to current position */
|
||||
} DIR;
|
||||
|
||||
extern DIR *opendir ();
|
||||
extern struct dirent *readdir ();
|
||||
extern void seekdir ();
|
||||
extern long telldir ();
|
||||
extern void closedir ();
|
@ -1,149 +0,0 @@
|
||||
/* Look up user and/or group names.
|
||||
Copyright (C) 1988, 1992 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Look up user and/or group names.
|
||||
*
|
||||
* This file should be modified for non-unix systems to do something
|
||||
* reasonable.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
|
||||
#ifndef NONAMES
|
||||
/* Whole module goes away if NONAMES defined. Otherwise... */
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
static int saveuid = -993;
|
||||
static char saveuname[TUNMLEN];
|
||||
static int my_uid = -993;
|
||||
|
||||
static int savegid = -993;
|
||||
static char savegname[TGNMLEN];
|
||||
static int my_gid = -993;
|
||||
|
||||
#define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
|
||||
#define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
|
||||
|
||||
/*
|
||||
* Look up a user or group name from a uid/gid, maintaining a cache.
|
||||
* FIXME, for now it's a one-entry cache.
|
||||
* FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
|
||||
*
|
||||
* This is ifdef'd because on Suns, it drags in about 38K of "yellow
|
||||
* pages" code, roughly doubling the program size. Thanks guys.
|
||||
*/
|
||||
void
|
||||
finduname (uname, uid)
|
||||
char uname[TUNMLEN];
|
||||
int uid;
|
||||
{
|
||||
struct passwd *pw;
|
||||
#ifndef HAVE_GETPWUID
|
||||
extern struct passwd *getpwuid ();
|
||||
#endif
|
||||
|
||||
if (uid != saveuid)
|
||||
{
|
||||
saveuid = uid;
|
||||
saveuname[0] = '\0';
|
||||
pw = getpwuid (uid);
|
||||
if (pw)
|
||||
strncpy (saveuname, pw->pw_name, TUNMLEN);
|
||||
}
|
||||
strncpy (uname, saveuname, TUNMLEN);
|
||||
}
|
||||
|
||||
int
|
||||
finduid (uname)
|
||||
char uname[TUNMLEN];
|
||||
{
|
||||
struct passwd *pw;
|
||||
extern struct passwd *getpwnam ();
|
||||
|
||||
if (uname[0] != saveuname[0] /* Quick test w/o proc call */
|
||||
|| 0 != strncmp (uname, saveuname, TUNMLEN))
|
||||
{
|
||||
strncpy (saveuname, uname, TUNMLEN);
|
||||
pw = getpwnam (uname);
|
||||
if (pw)
|
||||
{
|
||||
saveuid = pw->pw_uid;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveuid = myuid;
|
||||
}
|
||||
}
|
||||
return saveuid;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
findgname (gname, gid)
|
||||
char gname[TGNMLEN];
|
||||
int gid;
|
||||
{
|
||||
struct group *gr;
|
||||
#ifndef HAVE_GETGRGID
|
||||
extern struct group *getgrgid ();
|
||||
#endif
|
||||
|
||||
if (gid != savegid)
|
||||
{
|
||||
savegid = gid;
|
||||
savegname[0] = '\0';
|
||||
(void) setgrent ();
|
||||
gr = getgrgid (gid);
|
||||
if (gr)
|
||||
strncpy (savegname, gr->gr_name, TGNMLEN);
|
||||
}
|
||||
(void) strncpy (gname, savegname, TGNMLEN);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
findgid (gname)
|
||||
char gname[TUNMLEN];
|
||||
{
|
||||
struct group *gr;
|
||||
extern struct group *getgrnam ();
|
||||
|
||||
if (gname[0] != savegname[0] /* Quick test w/o proc call */
|
||||
|| 0 != strncmp (gname, savegname, TUNMLEN))
|
||||
{
|
||||
strncpy (savegname, gname, TUNMLEN);
|
||||
gr = getgrnam (gname);
|
||||
if (gr)
|
||||
{
|
||||
savegid = gr->gr_gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
savegid = mygid;
|
||||
}
|
||||
}
|
||||
return savegid;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,67 +0,0 @@
|
||||
/* Defines for Sys V style 3-argument open call.
|
||||
Copyright (C) 1988 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* open3.h -- #defines for the various flags for the Sys V style 3-argument
|
||||
* open() call. On BSD or System 5, the system already has this in an
|
||||
* include file. This file is needed for V7 and MINIX systems for the
|
||||
* benefit of open3() in port.c, a routine that emulates the 3-argument
|
||||
* call using system calls available on V7/MINIX.
|
||||
*
|
||||
* This file is needed by PD tar even if we aren't using the
|
||||
* emulator, since the #defines for O_WRONLY, etc. are used in
|
||||
* a couple of places besides the open() calls, (e.g. in the assignment
|
||||
* to openflag in extract.c). We just #include this rather than
|
||||
* #ifdef them out.
|
||||
*
|
||||
* Written 6/10/87 by rmtodd@uokmax (Richard Todd).
|
||||
*
|
||||
* The names have been changed by John Gilmore, 31 July 1987, since
|
||||
* Richard called it "bsdopen", and really this change was introduced in
|
||||
* AT&T Unix systems before BSD picked it up.
|
||||
*/
|
||||
|
||||
/* Only one of the next three should be specified */
|
||||
#define O_RDONLY 0 /* only allow read */
|
||||
#define O_WRONLY 1 /* only allow write */
|
||||
#define O_RDWR 2 /* both are allowed */
|
||||
|
||||
/* The rest of these can be OR-ed in to the above. */
|
||||
/*
|
||||
* O_NDELAY isn't implemented by the emulator. It's only useful (to tar) on
|
||||
* systems that have named pipes anyway; it prevents tar's hanging by
|
||||
* opening a named pipe. We #ifndef it because some systems already have
|
||||
* it defined.
|
||||
*/
|
||||
#ifndef O_NDELAY
|
||||
#define O_NDELAY 4 /* don't block on opening devices that would
|
||||
* block on open -- ignored by emulator. */
|
||||
#endif
|
||||
#define O_CREAT 8 /* create file if needed */
|
||||
#define O_EXCL 16 /* file cannot already exist */
|
||||
#define O_TRUNC 32 /* truncate file on open */
|
||||
#define O_APPEND 64 /* always write at end of file -- ignored by emul */
|
||||
|
||||
#ifdef EMUL_OPEN3
|
||||
/*
|
||||
* make emulation transparent to rest of file -- redirect all open() calls
|
||||
* to our routine
|
||||
*/
|
||||
#define open open3
|
||||
#endif
|
@ -1,53 +0,0 @@
|
||||
/* Define PATH_MAX somehow. Requires sys/types.h.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _PATHMAX_H
|
||||
#define _PATHMAX_H
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
|
||||
PATH_MAX but might cause redefinition warnings when sys/param.h is
|
||||
later included (as on MORE/BSD 4.3). */
|
||||
#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && defined(USG))
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_PATH_MAX
|
||||
#define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
|
||||
#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
|
||||
#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
|
||||
#endif
|
||||
|
||||
/* Don't include sys/param.h if it already has been. */
|
||||
#if !defined(PATH_MAX) && !defined(MAXPATHLEN) && !defined(__MSDOS__)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if !defined(PATH_MAX) && defined(MAXPATHLEN)
|
||||
#define PATH_MAX MAXPATHLEN
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX _POSIX_PATH_MAX
|
||||
#endif
|
||||
|
||||
#endif /* _PATHMAX_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,220 +0,0 @@
|
||||
/* Portability declarations. Requires sys/types.h.
|
||||
Copyright (C) 1988, 1992 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/* AIX requires this to be the first thing in the file. */
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not __GNUC__ */
|
||||
#if HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#else /* not HAVE_ALLOCA_H */
|
||||
#ifdef _AIX
|
||||
#pragma alloca
|
||||
#else /* not _AIX */
|
||||
char *alloca ();
|
||||
#endif /* not _AIX */
|
||||
#endif /* not HAVE_ALLOCA_H */
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
#include "pathmax.h"
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#include <sys/wait.h>
|
||||
#else /* !_POSIX_VERSION */
|
||||
#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
|
||||
#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
|
||||
#define WIFEXITED(w) (((w) & 0xff) == 0)
|
||||
|
||||
#define WSTOPSIG(w) (((w) >> 8) & 0xff)
|
||||
#define WTERMSIG(w) ((w) & 0x7f)
|
||||
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
/* nonstandard */
|
||||
#ifndef WIFCOREDUMPED
|
||||
#define WIFCOREDUMPED(w) (((w) & 0x80) != 0)
|
||||
#endif
|
||||
|
||||
#ifdef __MSDOS__
|
||||
/* missing things from sys/stat.h */
|
||||
#define S_ISUID 0
|
||||
#define S_ISGID 0
|
||||
#define S_ISVTX 0
|
||||
|
||||
/* device stuff */
|
||||
#define makedev(ma, mi) ((ma << 8) | mi)
|
||||
#define major(dev) (dev)
|
||||
#define minor(dev) (dev)
|
||||
typedef long off_t;
|
||||
#endif /* __MSDOS__ */
|
||||
|
||||
#if defined(__STDC__) || defined(__TURBOC__)
|
||||
#define PTR void *
|
||||
#else
|
||||
#define PTR char *
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* Since major is a function on SVR4, we can't just use `ifndef major'. */
|
||||
#ifdef major /* Might be defined in sys/types.h. */
|
||||
#define HAVE_MAJOR
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_MKDEV)
|
||||
#include <sys/mkdev.h>
|
||||
#define HAVE_MAJOR
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_SYSMACROS)
|
||||
#include <sys/sysmacros.h>
|
||||
#define HAVE_MAJOR
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MAJOR
|
||||
#define major(dev) (((dev) >> 8) & 0xff)
|
||||
#define minor(dev) ((dev) & 0xff)
|
||||
#define makedev(maj, min) (((maj) << 8) | (min))
|
||||
#endif
|
||||
#undef HAVE_MAJOR
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
|
||||
#include <string.h>
|
||||
#if !defined(__MSDOS__) && !defined(STDC_HEADERS)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef index
|
||||
#undef index
|
||||
#endif
|
||||
#ifdef rindex
|
||||
#undef rindex
|
||||
#endif
|
||||
#define index strchr
|
||||
#define rindex strrchr
|
||||
#define bcopy(s, d, n) memcpy(d, s, n)
|
||||
#define bzero(s, n) memset(s, 0, n)
|
||||
#define bcmp memcmp
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#if defined(STDC_HEADERS)
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *malloc (), *realloc ();
|
||||
char *getenv ();
|
||||
#endif
|
||||
PTR ck_malloc ();
|
||||
PTR ck_realloc ();
|
||||
char *xmalloc ();
|
||||
|
||||
#ifndef _POSIX_VERSION
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#else /* !__MSDOS__ */
|
||||
off_t lseek ();
|
||||
#endif /* !__MSDOS__ */
|
||||
char *getcwd ();
|
||||
#endif /* !_POSIX_VERSION */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 0
|
||||
#endif
|
||||
#ifndef O_NDELAY
|
||||
#define O_NDELAY 0
|
||||
#endif
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY 0
|
||||
#endif
|
||||
#ifndef O_RDWR
|
||||
#define O_RDWR 2
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
|
||||
#define mode_t unsigned short
|
||||
#endif
|
||||
#if !defined(S_ISBLK) && defined(S_IFBLK)
|
||||
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||
#endif
|
||||
#if !defined(S_ISCHR) && defined(S_IFCHR)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#endif
|
||||
#if !defined(S_ISDIR) && defined(S_IFDIR)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
#if !defined(S_ISREG) && defined(S_IFREG)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#if !defined(S_ISFIFO) && defined(S_IFIFO)
|
||||
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||
#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
|
||||
#endif
|
||||
#if !defined(S_ISLNK) && defined(S_IFLNK)
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#endif
|
||||
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
#endif
|
||||
#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
|
||||
#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
|
||||
#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
|
||||
#endif
|
||||
#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
|
||||
#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
|
||||
#endif
|
||||
#if !defined(S_ISCTG) && defined(S_IFCTG) /* contiguous file */
|
||||
#define S_ISCTG(m) (((m) & S_IFMT) == S_IFCTG)
|
||||
#endif
|
||||
#if !defined(S_ISVTX)
|
||||
#define S_ISVTX 0001000
|
||||
#endif
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#include "msd_dir.h"
|
||||
#define NLENGTH(direct) ((direct)->d_namlen)
|
||||
|
||||
#else /* not __MSDOS__ */
|
||||
|
||||
#if defined(DIRENT) || defined(_POSIX_VERSION)
|
||||
#include <dirent.h>
|
||||
#define NLENGTH(direct) (strlen((direct)->d_name))
|
||||
#else /* not (DIRENT or _POSIX_VERSION) */
|
||||
#define dirent direct
|
||||
#define NLENGTH(direct) ((direct)->d_namlen)
|
||||
#ifdef SYSNDIR
|
||||
#include <sys/ndir.h>
|
||||
#endif /* SYSNDIR */
|
||||
#ifdef SYSDIR
|
||||
#include <sys/dir.h>
|
||||
#endif /* SYSDIR */
|
||||
#ifdef NDIR
|
||||
#include <ndir.h>
|
||||
#endif /* NDIR */
|
||||
#endif /* DIRENT or _POSIX_VERSION */
|
||||
|
||||
#endif /* not __MSDOS__ */
|
@ -1,87 +0,0 @@
|
||||
/* prepend_args.c - utilility programs for manpiulating argv[]
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <sys/param.h>
|
||||
#include "prepend_args.h"
|
||||
#include "port.h"
|
||||
|
||||
|
||||
/* Find the white-space-separated options specified by OPTIONS, and
|
||||
using BUF to store copies of these options, set ARGV[0], ARGV[1],
|
||||
etc. to the option copies. Return the number N of options found.
|
||||
Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0]
|
||||
etc. Backslash can be used to escape whitespace (and backslashes). */
|
||||
static int
|
||||
prepend_args (options, buf, argv)
|
||||
char const *options;
|
||||
char *buf;
|
||||
char **argv;
|
||||
{
|
||||
char const *o = options;
|
||||
char *b = buf;
|
||||
int n = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (isspace ((unsigned char) *o))
|
||||
o++;
|
||||
if (!*o)
|
||||
return n;
|
||||
if (argv)
|
||||
argv[n] = b;
|
||||
n++;
|
||||
|
||||
do
|
||||
if ((*b++ = *o++) == '\\' && *o)
|
||||
b[-1] = *o++;
|
||||
while (*o && ! isspace ((unsigned char) *o));
|
||||
|
||||
*b++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepend the whitespace-separated options in OPTIONS to the argument
|
||||
vector of a main program with argument count *PARGC and argument
|
||||
vector *PARGV. */
|
||||
void
|
||||
prepend_default_options (options, pargc, pargv)
|
||||
char const *options;
|
||||
int *pargc;
|
||||
char ***pargv;
|
||||
{
|
||||
if (options)
|
||||
{
|
||||
char *buf = xmalloc (strlen (options) + 1);
|
||||
int prepended = prepend_args (options, buf, (char **) NULL);
|
||||
int argc = *pargc;
|
||||
char * const *argv = *pargv;
|
||||
char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
|
||||
*pargc = prepended + argc;
|
||||
*pargv = pp;
|
||||
*pp++ = *argv++;
|
||||
pp += prepend_args (options, buf, pp);
|
||||
while ((*pp++ = *argv++))
|
||||
continue;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/* prepend_args.h - utilility programs for manpiulating argv[]
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/* This code, taken from GNU Grep, originally used the "PARAM" macro, as the
|
||||
current GNU coding standards requires. Older GNU code used the "PROTO"
|
||||
macro, before the GNU coding standards replaced it. We use the older
|
||||
form here to keep from having to include another file in cvs/src/main.c. */
|
||||
|
||||
void prepend_default_options __P((char const *, int *, char ***));
|
@ -1,98 +0,0 @@
|
||||
/* Definitions for communicating with a remote tape drive.
|
||||
Copyright (C) 1988, 1992 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_POSIX_VERSION)
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#else /* !__MSDOS__ */
|
||||
extern off_t lseek ();
|
||||
#endif /* __MSDOS__ */
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
#ifdef NO_REMOTE
|
||||
#define _isrmt(f) 0
|
||||
#define rmtopen open
|
||||
#define rmtaccess access
|
||||
#define rmtstat stat
|
||||
#define rmtcreat creat
|
||||
#define rmtlstat lstat
|
||||
#define rmtread read
|
||||
#define rmtwrite write
|
||||
#define rmtlseek lseek
|
||||
#define rmtclose close
|
||||
#define rmtioctl ioctl
|
||||
#define rmtdup dup
|
||||
#define rmtfstat fstat
|
||||
#define rmtfcntl fcntl
|
||||
#define rmtisatty isatty
|
||||
|
||||
#else /* !NO_REMOTE */
|
||||
|
||||
#define __REM_BIAS 128
|
||||
#define RMTIOCTL
|
||||
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 01000
|
||||
#endif
|
||||
|
||||
extern char *__rmt_path;
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
|
||||
#include <string.h>
|
||||
#ifndef index
|
||||
#define index strchr
|
||||
#endif
|
||||
#else
|
||||
extern char *index ();
|
||||
#endif
|
||||
|
||||
#define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':')))
|
||||
#define _isrmt(fd) ((fd) >= __REM_BIAS)
|
||||
|
||||
#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode))
|
||||
#define rmtaccess(path, amode) (_remdev(path) ? 0 : access(path, amode))
|
||||
#define rmtstat(path, buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf))
|
||||
#define rmtcreat(path, mode) (_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode))
|
||||
#define rmtlstat(path,buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf))
|
||||
|
||||
#define rmtread(fd, buf, n) (_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n))
|
||||
#define rmtwrite(fd, buf, n) (_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n))
|
||||
#define rmtlseek(fd, off, wh) (_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh))
|
||||
#define rmtclose(fd) (_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd))
|
||||
#ifdef RMTIOCTL
|
||||
#define rmtioctl(fd,req,arg) (_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg))
|
||||
#else
|
||||
#define rmtioctl(fd,req,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg))
|
||||
#endif
|
||||
#define rmtdup(fd) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd))
|
||||
#define rmtfstat(fd, buf) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf))
|
||||
#define rmtfcntl(fd,cmd,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg))
|
||||
#define rmtisatty(fd) (_isrmt(fd) ? 0 : isatty(fd))
|
||||
|
||||
#undef RMTIOCTL
|
||||
|
||||
int __rmt_open ();
|
||||
int __rmt_close ();
|
||||
int __rmt_read ();
|
||||
int __rmt_write ();
|
||||
long __rmt_lseek ();
|
||||
int __rmt_ioctl ();
|
||||
#endif /* !NO_REMOTE */
|
@ -1,585 +0,0 @@
|
||||
/* Functions for communicating with a remote tape drive.
|
||||
Copyright (C) 1988, 1992 Free Software Foundation, Inc.
|
||||
|
||||
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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* The man page rmt(8) for /etc/rmt documents the remote mag tape
|
||||
protocol which rdump and rrestore use. Unfortunately, the man
|
||||
page is *WRONG*. The author of the routines I'm including originally
|
||||
wrote his code just based on the man page, and it didn't work, so he
|
||||
went to the rdump source to figure out why. The only thing he had to
|
||||
change was to check for the 'F' return code in addition to the 'E',
|
||||
and to separate the various arguments with \n instead of a space. I
|
||||
personally don't think that this is much of a problem, but I wanted to
|
||||
point it out. -- Arnold Robbins
|
||||
|
||||
Originally written by Jeff Lee, modified some by Arnold Robbins.
|
||||
Redone as a library that can replace open, read, write, etc., by
|
||||
Fred Fish, with some additional work by Arnold Robbins.
|
||||
Modified to make all rmtXXX calls into macros for speed by Jay Fenlason.
|
||||
Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SYS_MTIO_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef STDC_HEADERS
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/* Maximum size of a fully qualified host name. */
|
||||
#define MAXHOSTLEN 257
|
||||
|
||||
/* Size of buffers for reading and writing commands to rmt.
|
||||
(An arbitrary limit.) */
|
||||
#define CMDBUFSIZE 64
|
||||
|
||||
#ifndef RETSIGTYPE
|
||||
#define RETSIGTYPE void
|
||||
#endif
|
||||
|
||||
/* Maximum number of simultaneous remote tape connections.
|
||||
(Another arbitrary limit.) */
|
||||
#define MAXUNIT 4
|
||||
|
||||
/* Return the parent's read side of remote tape connection FILDES. */
|
||||
#define READ(fildes) (from_rmt[fildes][0])
|
||||
|
||||
/* Return the parent's write side of remote tape connection FILDES. */
|
||||
#define WRITE(fildes) (to_rmt[fildes][1])
|
||||
|
||||
/* The pipes for receiving data from remote tape drives. */
|
||||
static int from_rmt[MAXUNIT][2] =
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
/* The pipes for sending data to remote tape drives. */
|
||||
static int to_rmt[MAXUNIT][2] =
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
/* Temporary variable used by macros in rmt.h. */
|
||||
char *__rmt_path;
|
||||
|
||||
/* Close remote tape connection FILDES. */
|
||||
|
||||
static void
|
||||
_rmt_shutdown (fildes)
|
||||
int fildes;
|
||||
{
|
||||
close (READ (fildes));
|
||||
close (WRITE (fildes));
|
||||
READ (fildes) = -1;
|
||||
WRITE (fildes) = -1;
|
||||
}
|
||||
|
||||
/* Attempt to perform the remote tape command specified in BUF
|
||||
on remote tape connection FILDES.
|
||||
Return 0 if successful, -1 on error. */
|
||||
|
||||
static int
|
||||
command (fildes, buf)
|
||||
int fildes;
|
||||
char *buf;
|
||||
{
|
||||
register int buflen;
|
||||
RETSIGTYPE (*pipe_handler) ();
|
||||
|
||||
/* Save the current pipe handler and try to make the request. */
|
||||
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
buflen = strlen (buf);
|
||||
if (write (WRITE (fildes), buf, buflen) == buflen)
|
||||
{
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Something went wrong. Close down and go home. */
|
||||
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read and return the status from remote tape connection FILDES.
|
||||
If an error occurred, return -1 and set errno. */
|
||||
|
||||
static int
|
||||
status (fildes)
|
||||
int fildes;
|
||||
{
|
||||
int i;
|
||||
char c, *cp;
|
||||
char buffer[CMDBUFSIZE];
|
||||
|
||||
/* Read the reply command line. */
|
||||
|
||||
for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++)
|
||||
{
|
||||
if (read (READ (fildes), cp, 1) != 1)
|
||||
{
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
{
|
||||
*cp = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == CMDBUFSIZE)
|
||||
{
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check the return status. */
|
||||
|
||||
for (cp = buffer; *cp; cp++)
|
||||
if (*cp != ' ')
|
||||
break;
|
||||
|
||||
if (*cp == 'E' || *cp == 'F')
|
||||
{
|
||||
errno = atoi (cp + 1);
|
||||
/* Skip the error message line. */
|
||||
while (read (READ (fildes), &c, 1) == 1)
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (*cp == 'F')
|
||||
_rmt_shutdown (fildes);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for mis-synced pipes. */
|
||||
|
||||
if (*cp != 'A')
|
||||
{
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Got an `A' (success) response. */
|
||||
return atoi (cp + 1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
/* Execute /etc/rmt as user USER on remote system HOST using rexec.
|
||||
Return a file descriptor of a bidirectional socket for stdin and stdout.
|
||||
If USER is NULL, or an empty string, use the current username.
|
||||
|
||||
By default, this code is not used, since it requires that
|
||||
the user have a .netrc file in his/her home directory, or that the
|
||||
application designer be willing to have rexec prompt for login and
|
||||
password info. This may be unacceptable, and .rhosts files for use
|
||||
with rsh are much more common on BSD systems. */
|
||||
|
||||
static int
|
||||
_rmt_rexec (host, user)
|
||||
char *host;
|
||||
char *user;
|
||||
{
|
||||
struct servent *rexecserv;
|
||||
int save_stdin = dup (fileno (stdin));
|
||||
int save_stdout = dup (fileno (stdout));
|
||||
int tape_fd; /* Return value. */
|
||||
|
||||
/* When using cpio -o < filename, stdin is no longer the tty.
|
||||
But the rexec subroutine reads the login and the passwd on stdin,
|
||||
to allow remote execution of the command.
|
||||
So, reopen stdin and stdout on /dev/tty before the rexec and
|
||||
give them back their original value after. */
|
||||
if (freopen ("/dev/tty", "r", stdin) == NULL)
|
||||
freopen ("/dev/null", "r", stdin);
|
||||
if (freopen ("/dev/tty", "w", stdout) == NULL)
|
||||
freopen ("/dev/null", "w", stdout);
|
||||
|
||||
rexecserv = getservbyname ("exec", "tcp");
|
||||
if (NULL == rexecserv)
|
||||
{
|
||||
fprintf (stderr, "exec/tcp: service not available");
|
||||
exit (1);
|
||||
}
|
||||
if (user != NULL && *user == '\0')
|
||||
user = NULL;
|
||||
tape_fd = rexec (&host, rexecserv->s_port, user, NULL,
|
||||
"/etc/rmt", (int *) NULL);
|
||||
fclose (stdin);
|
||||
fdopen (save_stdin, "r");
|
||||
fclose (stdout);
|
||||
fdopen (save_stdout, "w");
|
||||
|
||||
return tape_fd;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NETDB_H */
|
||||
|
||||
/* Open a magtape device on the system specified in PATH, as the given user.
|
||||
PATH has the form `[user@]system:/dev/????'.
|
||||
If COMPAT is defined, it can also have the form `system[.user]:/dev/????'.
|
||||
|
||||
OFLAG is O_RDONLY, O_WRONLY, etc.
|
||||
MODE is ignored; 0666 is always used.
|
||||
|
||||
If successful, return the remote tape pipe number plus BIAS.
|
||||
On error, return -1. */
|
||||
|
||||
int
|
||||
__rmt_open (path, oflag, mode, bias)
|
||||
char *path;
|
||||
int oflag;
|
||||
int mode;
|
||||
int bias;
|
||||
{
|
||||
int i, rc;
|
||||
char buffer[CMDBUFSIZE]; /* Command buffer. */
|
||||
char system[MAXHOSTLEN]; /* The remote host name. */
|
||||
char device[CMDBUFSIZE]; /* The remote device name. */
|
||||
char login[CMDBUFSIZE]; /* The remote user name. */
|
||||
char *sys, *dev, *user; /* For copying into the above buffers. */
|
||||
char *tar_rsh;
|
||||
|
||||
sys = system;
|
||||
dev = device;
|
||||
user = login;
|
||||
|
||||
/* Find an unused pair of file descriptors. */
|
||||
|
||||
for (i = 0; i < MAXUNIT; i++)
|
||||
if (READ (i) == -1 && WRITE (i) == -1)
|
||||
break;
|
||||
|
||||
if (i == MAXUNIT)
|
||||
{
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pull apart the system and device, and optional user.
|
||||
Don't munge the original string. */
|
||||
|
||||
while (*path != '@'
|
||||
#ifdef COMPAT
|
||||
&& *path != '.'
|
||||
#endif
|
||||
&& *path != ':')
|
||||
{
|
||||
*sys++ = *path++;
|
||||
}
|
||||
*sys = '\0';
|
||||
path++;
|
||||
|
||||
if (*(path - 1) == '@')
|
||||
{
|
||||
/* Saw user part of user@host. Start over. */
|
||||
strcpy (user, system);
|
||||
sys = system;
|
||||
while (*path != ':')
|
||||
{
|
||||
*sys++ = *path++;
|
||||
}
|
||||
*sys = '\0';
|
||||
path++;
|
||||
}
|
||||
#ifdef COMPAT
|
||||
else if (*(path - 1) == '.')
|
||||
{
|
||||
while (*path != ':')
|
||||
{
|
||||
*user++ = *path++;
|
||||
}
|
||||
*user = '\0';
|
||||
path++;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
*user = '\0';
|
||||
|
||||
while (*path)
|
||||
{
|
||||
*dev++ = *path++;
|
||||
}
|
||||
*dev = '\0';
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
/* Execute the remote command using rexec. */
|
||||
READ (i) = WRITE (i) = _rmt_rexec (system, login);
|
||||
if (READ (i) < 0)
|
||||
return -1;
|
||||
#else /* !HAVE_NETDB_H */
|
||||
/* Set up the pipes for the `rsh' command, and fork. */
|
||||
|
||||
if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1)
|
||||
return -1;
|
||||
|
||||
rc = fork ();
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
/* Child. */
|
||||
close (0);
|
||||
dup (to_rmt[i][0]);
|
||||
close (to_rmt[i][0]);
|
||||
close (to_rmt[i][1]);
|
||||
|
||||
close (1);
|
||||
dup (from_rmt[i][1]);
|
||||
close (from_rmt[i][0]);
|
||||
close (from_rmt[i][1]);
|
||||
|
||||
setuid (getuid ());
|
||||
setgid (getgid ());
|
||||
|
||||
tar_rsh = getenv("TAR_RSH");
|
||||
|
||||
if (*login)
|
||||
{
|
||||
if (tar_rsh) {
|
||||
execlp (tar_rsh, tar_rsh, "-l", login, system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
} else {
|
||||
execl ("/usr/bin/rsh", "rsh", "-l", login, system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
execlp ("rsh", "rsh", "-l", login, system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tar_rsh) {
|
||||
execlp (tar_rsh, tar_rsh, system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
} else {
|
||||
execl ("/usr/bin/rsh", "rsh", system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
execlp ("rsh", "rsh", system,
|
||||
"/etc/rmt", (char *) 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bad problems if we get here. */
|
||||
|
||||
perror ("cannot execute remote shell");
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
/* Parent. */
|
||||
close (to_rmt[i][0]);
|
||||
close (from_rmt[i][1]);
|
||||
#endif /* !HAVE_NETDB_H */
|
||||
|
||||
/* Attempt to open the tape device. */
|
||||
|
||||
sprintf (buffer, "O%s\n%d\n", device, oflag);
|
||||
if (command (i, buffer) == -1 || status (i) == -1)
|
||||
return -1;
|
||||
|
||||
return i + bias;
|
||||
}
|
||||
|
||||
/* Close remote tape connection FILDES and shut down.
|
||||
Return 0 if successful, -1 on error. */
|
||||
|
||||
int
|
||||
__rmt_close (fildes)
|
||||
int fildes;
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (command (fildes, "C\n") == -1)
|
||||
return -1;
|
||||
|
||||
rc = status (fildes);
|
||||
_rmt_shutdown (fildes);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Read up to NBYTE bytes into BUF from remote tape connection FILDES.
|
||||
Return the number of bytes read on success, -1 on error. */
|
||||
|
||||
int
|
||||
__rmt_read (fildes, buf, nbyte)
|
||||
int fildes;
|
||||
char *buf;
|
||||
unsigned int nbyte;
|
||||
{
|
||||
int rc, i;
|
||||
char buffer[CMDBUFSIZE];
|
||||
|
||||
sprintf (buffer, "R%d\n", nbyte);
|
||||
if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < rc; i += nbyte, buf += nbyte)
|
||||
{
|
||||
nbyte = read (READ (fildes), buf, rc - i);
|
||||
if (nbyte <= 0)
|
||||
{
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Write NBYTE bytes from BUF to remote tape connection FILDES.
|
||||
Return the number of bytes written on success, -1 on error. */
|
||||
|
||||
int
|
||||
__rmt_write (fildes, buf, nbyte)
|
||||
int fildes;
|
||||
char *buf;
|
||||
unsigned int nbyte;
|
||||
{
|
||||
char buffer[CMDBUFSIZE];
|
||||
RETSIGTYPE (*pipe_handler) ();
|
||||
|
||||
sprintf (buffer, "W%d\n", nbyte);
|
||||
if (command (fildes, buffer) == -1)
|
||||
return -1;
|
||||
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
if (write (WRITE (fildes), buf, nbyte) == nbyte)
|
||||
{
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
return status (fildes);
|
||||
}
|
||||
|
||||
/* Write error. */
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Perform an imitation lseek operation on remote tape connection FILDES.
|
||||
Return the new file offset if successful, -1 if on error. */
|
||||
|
||||
long
|
||||
__rmt_lseek (fildes, offset, whence)
|
||||
int fildes;
|
||||
long offset;
|
||||
int whence;
|
||||
{
|
||||
char buffer[CMDBUFSIZE];
|
||||
|
||||
sprintf (buffer, "L%ld\n%d\n", offset, whence);
|
||||
if (command (fildes, buffer) == -1)
|
||||
return -1;
|
||||
|
||||
return status (fildes);
|
||||
}
|
||||
|
||||
/* Perform a raw tape operation on remote tape connection FILDES.
|
||||
Return the results of the ioctl, or -1 on error. */
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
int
|
||||
__rmt_ioctl (fildes, op, arg)
|
||||
int fildes, op;
|
||||
char *arg;
|
||||
{
|
||||
char c;
|
||||
int rc, cnt;
|
||||
char buffer[CMDBUFSIZE];
|
||||
|
||||
switch (op)
|
||||
{
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
||||
case MTIOCTOP:
|
||||
/* MTIOCTOP is the easy one. Nothing is transfered in binary. */
|
||||
sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
|
||||
((struct mtop *) arg)->mt_count);
|
||||
if (command (fildes, buffer) == -1)
|
||||
return -1;
|
||||
return status (fildes); /* Return the count. */
|
||||
|
||||
case MTIOCGET:
|
||||
/* Grab the status and read it directly into the structure.
|
||||
This assumes that the status buffer is not padded
|
||||
and that 2 shorts fit in a long without any word
|
||||
alignment problems; i.e., the whole struct is contiguous.
|
||||
NOTE - this is probably NOT a good assumption. */
|
||||
|
||||
if (command (fildes, "S") == -1 || (rc = status (fildes)) == -1)
|
||||
return -1;
|
||||
|
||||
for (; rc > 0; rc -= cnt, arg += cnt)
|
||||
{
|
||||
cnt = read (READ (fildes), arg, rc);
|
||||
if (cnt <= 0)
|
||||
{
|
||||
_rmt_shutdown (fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for byte position. mt_type is a small integer field
|
||||
(normally) so we will check its magnitude. If it is larger than
|
||||
256, we will assume that the bytes are swapped and go through
|
||||
and reverse all the bytes. */
|
||||
|
||||
if (((struct mtget *) arg)->mt_type < 256)
|
||||
return 0;
|
||||
|
||||
for (cnt = 0; cnt < rc; cnt += 2)
|
||||
{
|
||||
c = arg[cnt];
|
||||
arg[cnt] = arg[cnt + 1];
|
||||
arg[cnt + 1] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,302 +0,0 @@
|
||||
/* Declarations for tar archives.
|
||||
Copyright (C) 1988, 1992, 1993 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* major() and minor() macros (among other things) defined here for hpux */
|
||||
#ifdef hpux
|
||||
#include <sys/mknod.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We need to include <sys/types.h> for the u_quad_t definition
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* Kludge for handling systems that can't cope with multiple
|
||||
* external definitions of a variable. In ONE routine (tar.c),
|
||||
* we #define TAR_EXTERN to null; here, we set it to "extern" if
|
||||
* it is not already set.
|
||||
*/
|
||||
#ifndef TAR_EXTERN
|
||||
#define TAR_EXTERN extern
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Header block on tape.
|
||||
*
|
||||
* I'm going to use traditional DP naming conventions here.
|
||||
* A "block" is a big chunk of stuff that we do I/O on.
|
||||
* A "record" is a piece of info that we care about.
|
||||
* Typically many "record"s fit into a "block".
|
||||
*/
|
||||
#define RECORDSIZE 512
|
||||
#define NAMSIZ 100
|
||||
#define TUNMLEN 32
|
||||
#define TGNMLEN 32
|
||||
#define SPARSE_EXT_HDR 21
|
||||
#define SPARSE_IN_HDR 4
|
||||
|
||||
struct sparse
|
||||
{
|
||||
char offset[12];
|
||||
char numbytes[12];
|
||||
};
|
||||
|
||||
struct sp_array
|
||||
{
|
||||
int offset;
|
||||
int numbytes;
|
||||
};
|
||||
|
||||
union record
|
||||
{
|
||||
char charptr[RECORDSIZE];
|
||||
struct header
|
||||
{
|
||||
char arch_name[NAMSIZ];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char chksum[8];
|
||||
char linkflag;
|
||||
char arch_linkname[NAMSIZ];
|
||||
char magic[8];
|
||||
char uname[TUNMLEN];
|
||||
char gname[TGNMLEN];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
/* these following fields were added by JF for gnu */
|
||||
/* and are NOT standard */
|
||||
char atime[12];
|
||||
char ctime[12];
|
||||
char offset[12];
|
||||
char longnames[4];
|
||||
#ifdef NEEDPAD
|
||||
char pad;
|
||||
#endif
|
||||
struct sparse sp[SPARSE_IN_HDR];
|
||||
char isextended;
|
||||
char realsize[12]; /* true size of the sparse file */
|
||||
/* char ending_blanks[12];*//* number of nulls at the
|
||||
end of the file, if any */
|
||||
}
|
||||
header;
|
||||
struct extended_header
|
||||
{
|
||||
struct sparse sp[21];
|
||||
char isextended;
|
||||
}
|
||||
ext_hdr;
|
||||
};
|
||||
|
||||
/* The checksum field is filled with this while the checksum is computed. */
|
||||
#define CHKBLANKS " " /* 8 blanks, no null */
|
||||
|
||||
/* The magic field is filled with this if uname and gname are valid. */
|
||||
#define TMAGIC "ustar " /* 7 chars and a null */
|
||||
|
||||
/* The linkflag defines the type of file */
|
||||
#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
|
||||
#define LF_NORMAL '0' /* Normal disk file */
|
||||
#define LF_LINK '1' /* Link to previously dumped file */
|
||||
#define LF_SYMLINK '2' /* Symbolic link */
|
||||
#define LF_CHR '3' /* Character special file */
|
||||
#define LF_BLK '4' /* Block special file */
|
||||
#define LF_DIR '5' /* Directory */
|
||||
#define LF_FIFO '6' /* FIFO special file */
|
||||
#define LF_CONTIG '7' /* Contiguous file */
|
||||
/* Further link types may be defined later. */
|
||||
|
||||
/* Note that the standards committee allows only capital A through
|
||||
capital Z for user-defined expansion. This means that defining something
|
||||
as, say '8' is a *bad* idea. */
|
||||
#define LF_DUMPDIR 'D' /* This is a dir entry that contains
|
||||
the names of files that were in
|
||||
the dir at the time the dump
|
||||
was made */
|
||||
#define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape
|
||||
as having a long linkname */
|
||||
#define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape
|
||||
as having a long name. */
|
||||
#define LF_MULTIVOL 'M' /* This is the continuation
|
||||
of a file that began on another
|
||||
volume */
|
||||
#define LF_NAMES 'N' /* For storing filenames that didn't
|
||||
fit in 100 characters */
|
||||
#define LF_SPARSE 'S' /* This is for sparse files */
|
||||
#define LF_VOLHDR 'V' /* This file is a tape/volume header */
|
||||
/* Ignore it on extraction */
|
||||
|
||||
/*
|
||||
* Exit codes from the "tar" program
|
||||
*/
|
||||
#define EX_SUCCESS 0 /* success! */
|
||||
#define EX_ARGSBAD 1 /* invalid args */
|
||||
#define EX_BADFILE 2 /* invalid filename */
|
||||
#define EX_BADARCH 3 /* bad archive */
|
||||
#define EX_SYSTEM 4 /* system gave unexpected error */
|
||||
#define EX_BADVOL 5 /* Special error code means
|
||||
Tape volume doesn't match the one
|
||||
specified on the command line */
|
||||
#define EX_BADDIR 6 /* bad directory name */
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
TAR_EXTERN union record *ar_block; /* Start of block of archive */
|
||||
TAR_EXTERN union record *ar_record; /* Current record of archive */
|
||||
TAR_EXTERN union record *ar_last; /* Last+1 record of archive block */
|
||||
TAR_EXTERN char ar_reading; /* 0 writing, !0 reading archive */
|
||||
TAR_EXTERN int blocking; /* Size of each block, in records */
|
||||
TAR_EXTERN int blocksize; /* Size of each block, in bytes */
|
||||
TAR_EXTERN char *info_script; /* Script to run at end of each tape change */
|
||||
TAR_EXTERN char *name_file; /* File containing names to work on */
|
||||
TAR_EXTERN char filename_terminator; /* \n or \0. */
|
||||
TAR_EXTERN char *tar; /* Name of this program */
|
||||
TAR_EXTERN struct sp_array *sparsearray; /* Pointer to the start of the scratch space */
|
||||
TAR_EXTERN int sp_array_size; /* Initial size of the sparsearray */
|
||||
TAR_EXTERN u_quad_t tot_written; /* Total written to output */
|
||||
TAR_EXTERN struct re_pattern_buffer
|
||||
*label_pattern; /* compiled regex for extract label */
|
||||
TAR_EXTERN char **ar_files; /* list of tape drive names */
|
||||
TAR_EXTERN int n_ar_files; /* number of tape drive names */
|
||||
TAR_EXTERN int cur_ar_file; /* tape drive currently being used */
|
||||
TAR_EXTERN int ar_files_len; /* malloced size of ar_files */
|
||||
TAR_EXTERN char *current_file_name, *current_link_name;
|
||||
|
||||
/*
|
||||
* Flags from the command line
|
||||
*/
|
||||
TAR_EXTERN int cmd_mode;
|
||||
#define CMD_NONE 0
|
||||
#define CMD_CAT 1 /* -A */
|
||||
#define CMD_CREATE 2 /* -c */
|
||||
#define CMD_DIFF 3 /* -d */
|
||||
#define CMD_APPEND 4 /* -r */
|
||||
#define CMD_LIST 5 /* -t */
|
||||
#define CMD_UPDATE 6 /* -u */
|
||||
#define CMD_EXTRACT 7 /* -x */
|
||||
#define CMD_DELETE 8 /* -D */
|
||||
#define CMD_VERSION 9 /* --version */
|
||||
|
||||
|
||||
TAR_EXTERN int f_reblock; /* -B */
|
||||
TAR_EXTERN int f_dironly; /* -n */
|
||||
TAR_EXTERN int f_run_script_at_end; /* -F */
|
||||
TAR_EXTERN int f_gnudump; /* -G */
|
||||
TAR_EXTERN int f_follow_links; /* -h */
|
||||
TAR_EXTERN int f_ignorez; /* -i */
|
||||
TAR_EXTERN int f_keep; /* -k */
|
||||
TAR_EXTERN int f_startfile; /* -K */
|
||||
TAR_EXTERN int f_local_filesys; /* -l */
|
||||
TAR_EXTERN int tape_length; /* -L */
|
||||
TAR_EXTERN int f_modified; /* -m */
|
||||
TAR_EXTERN int f_multivol; /* -M */
|
||||
TAR_EXTERN int f_new_files; /* -N */
|
||||
TAR_EXTERN int f_oldarch; /* -o */
|
||||
TAR_EXTERN int f_exstdout; /* -O */
|
||||
TAR_EXTERN int f_use_protection;/* -p */
|
||||
TAR_EXTERN int f_absolute_paths;/* -P */
|
||||
TAR_EXTERN int f_sayblock; /* -R */
|
||||
TAR_EXTERN int f_sorted_names; /* -s */
|
||||
TAR_EXTERN int f_sparse_files; /* -S ... JK */
|
||||
TAR_EXTERN int f_namefile; /* -T */
|
||||
TAR_EXTERN int f_verbose; /* -v */
|
||||
TAR_EXTERN char *f_volhdr; /* -V */
|
||||
TAR_EXTERN int f_confirm; /* -w */
|
||||
TAR_EXTERN int f_verify; /* -W */
|
||||
TAR_EXTERN int f_exclude; /* -X */
|
||||
TAR_EXTERN char *f_compressprog; /* -z and -Z */
|
||||
TAR_EXTERN int f_do_chown; /* --do-chown */
|
||||
TAR_EXTERN int f_totals; /* --totals */
|
||||
TAR_EXTERN int f_remove_files; /* --remove-files */
|
||||
TAR_EXTERN int f_ignore_failed_read; /* --ignore-failed-read */
|
||||
TAR_EXTERN int f_checkpoint; /* --checkpoint */
|
||||
TAR_EXTERN int f_show_omitted_dirs; /* --show-omitted-dirs */
|
||||
TAR_EXTERN char *f_volno_file; /* --volno-file */
|
||||
TAR_EXTERN int f_force_local; /* --force-local */
|
||||
TAR_EXTERN int f_atime_preserve;/* --atime-preserve */
|
||||
TAR_EXTERN int f_compress_block; /* --compress-block */
|
||||
TAR_EXTERN int f_unlink; /* --unlink */
|
||||
TAR_EXTERN int f_fast_read; /* --fast-read */
|
||||
|
||||
/*
|
||||
* We default to Unix Standard format rather than 4.2BSD tar format.
|
||||
* The code can actually produce all three:
|
||||
* f_standard ANSI standard
|
||||
* f_oldarch V7
|
||||
* neither 4.2BSD
|
||||
* but we don't bother, since 4.2BSD can read ANSI standard format anyway.
|
||||
* The only advantage to the "neither" option is that we can cmp our
|
||||
* output to the output of 4.2BSD tar, for debugging.
|
||||
*/
|
||||
#define f_standard (!f_oldarch)
|
||||
|
||||
/*
|
||||
* Structure for keeping track of filenames and lists thereof.
|
||||
*/
|
||||
struct name
|
||||
{
|
||||
struct name *next;
|
||||
short length; /* cached strlen(name) */
|
||||
char found; /* A matching file has been found */
|
||||
char firstch; /* First char is literally matched */
|
||||
char regexp; /* This name is a regexp, not literal */
|
||||
char *change_dir; /* JF set with the -C option */
|
||||
char *dir_contents; /* JF for f_gnudump */
|
||||
char fake; /* dummy entry */
|
||||
char name[1];
|
||||
};
|
||||
|
||||
TAR_EXTERN struct name *namelist; /* Points to first name in list */
|
||||
TAR_EXTERN struct name *namelast; /* Points to last name in list */
|
||||
|
||||
TAR_EXTERN int archive; /* File descriptor for archive file */
|
||||
TAR_EXTERN int errors; /* # of files in error */
|
||||
|
||||
TAR_EXTERN char *gnu_dumpfile;
|
||||
|
||||
/*
|
||||
* Error recovery stuff
|
||||
*/
|
||||
TAR_EXTERN char read_error_flag;
|
||||
|
||||
/*
|
||||
* global boolean, see name_match in tar.c
|
||||
*/
|
||||
extern int nlpsfreed;
|
||||
|
||||
/*
|
||||
* Declarations of functions available to the world.
|
||||
*/
|
||||
union record *findrec ();
|
||||
void userec ();
|
||||
union record *endofrecs ();
|
||||
void anno ();
|
||||
|
||||
#if defined (HAVE_VPRINTF) && __STDC__
|
||||
void msg (char *,...);
|
||||
void msg_perror (char *,...);
|
||||
#else
|
||||
void msg ();
|
||||
void msg_perror ();
|
||||
#endif
|
@ -1,585 +0,0 @@
|
||||
/* Update a tar archive.
|
||||
Copyright (C) 1988, 1992 Free Software Foundation
|
||||
|
||||
This file is part of GNU Tar.
|
||||
|
||||
GNU Tar 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Tar 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 GNU Tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* JF implement the 'r' 'u' and 'A' options for tar. */
|
||||
/* The 'A' option is my own invention: It means that the file-names are
|
||||
tar files, and they should simply be appended to the end of the archive.
|
||||
No attempt is made to block the reads from the args; if they're on raw
|
||||
tape or something like that, it'll probably lose. . . */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MTIO_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#ifdef BSD42
|
||||
#include <sys/file.h>
|
||||
#else
|
||||
#ifndef V7
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __MSDOS__
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
|
||||
#include "tar.h"
|
||||
#include "port.h"
|
||||
#include "rmt.h"
|
||||
|
||||
int time_to_start_writing = 0; /* We've hit the end of the old stuff,
|
||||
and its time to start writing new stuff
|
||||
to the tape. This involves seeking
|
||||
back one block and re-writing the current
|
||||
block (which has been changed). */
|
||||
|
||||
char *output_start; /* Pointer to where we started to write in
|
||||
the first block we write out. This is used
|
||||
if we can't backspace the output and have
|
||||
to null out the first part of the block */
|
||||
|
||||
extern void skip_file ();
|
||||
extern void skip_extended_headers ();
|
||||
|
||||
extern union record *head;
|
||||
extern struct stat hstat;
|
||||
|
||||
void append_file ();
|
||||
void close_archive ();
|
||||
int confirm ();
|
||||
void decode_header ();
|
||||
void fl_read ();
|
||||
void fl_write ();
|
||||
void flush_archive ();
|
||||
int move_arch ();
|
||||
struct name *name_scan ();
|
||||
char *name_from_list ();
|
||||
void name_expand ();
|
||||
void name_gather ();
|
||||
void names_notfound ();
|
||||
void open_archive ();
|
||||
int read_header ();
|
||||
void reset_eof ();
|
||||
void write_block ();
|
||||
void write_eot ();
|
||||
|
||||
/* Implement the 'r' (add files to end of archive), and 'u' (add files to
|
||||
end of archive if they arent there, or are more up to date than the
|
||||
version in the archive.) commands.*/
|
||||
void
|
||||
update_archive ()
|
||||
{
|
||||
int found_end = 0;
|
||||
int status = 3;
|
||||
int prev_status;
|
||||
char *p;
|
||||
struct name *name;
|
||||
extern void dump_file ();
|
||||
|
||||
name_gather ();
|
||||
if (cmd_mode == CMD_UPDATE)
|
||||
name_expand ();
|
||||
open_archive (2); /* Open for updating */
|
||||
|
||||
do
|
||||
{
|
||||
prev_status = status;
|
||||
status = read_header ();
|
||||
switch (status)
|
||||
{
|
||||
case EOF:
|
||||
found_end = 1;
|
||||
break;
|
||||
|
||||
case 0: /* A bad record */
|
||||
userec (head);
|
||||
switch (prev_status)
|
||||
{
|
||||
case 3:
|
||||
msg ("This doesn't look like a tar archive.");
|
||||
/* FALL THROUGH */
|
||||
case 2:
|
||||
case 1:
|
||||
msg ("Skipping to next header");
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* A good record */
|
||||
case 1:
|
||||
/* printf("File %s\n",head->header.name); */
|
||||
/* head->header.name[NAMSIZ-1]='\0'; */
|
||||
if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name)))
|
||||
{
|
||||
|
||||
/* struct stat hstat; */
|
||||
struct stat nstat;
|
||||
int head_standard;
|
||||
|
||||
decode_header (head, &hstat, &head_standard, 0);
|
||||
if (stat (current_file_name, &nstat) < 0)
|
||||
{
|
||||
msg_perror ("can't stat %s:", current_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hstat.st_mtime >= nstat.st_mtime)
|
||||
name->found++;
|
||||
}
|
||||
}
|
||||
userec (head);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) hstat.st_size);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ar_record = head;
|
||||
found_end = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!found_end);
|
||||
|
||||
reset_eof ();
|
||||
time_to_start_writing = 1;
|
||||
output_start = ar_record->charptr;
|
||||
|
||||
while (p = name_from_list ())
|
||||
{
|
||||
if (f_confirm && !confirm ("add", p))
|
||||
continue;
|
||||
if (cmd_mode == CMD_CAT)
|
||||
append_file (p);
|
||||
else
|
||||
dump_file (p, -1, 1);
|
||||
}
|
||||
|
||||
write_eot ();
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
}
|
||||
|
||||
/* Catenate file p to the archive without creating a header for it. It had
|
||||
better be a tar file or the archive is screwed */
|
||||
|
||||
void
|
||||
append_file (p)
|
||||
char *p;
|
||||
{
|
||||
int fd;
|
||||
struct stat statbuf;
|
||||
long bytes_left;
|
||||
union record *start;
|
||||
long bufsiz, count;
|
||||
|
||||
if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0)
|
||||
{
|
||||
msg_perror ("can't open file %s", p);
|
||||
errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_left = statbuf.st_size;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
start = findrec ();
|
||||
bufsiz = endofrecs ()->charptr - start->charptr;
|
||||
if (bytes_left < bufsiz)
|
||||
{
|
||||
bufsiz = bytes_left;
|
||||
count = bufsiz % RECORDSIZE;
|
||||
if (count)
|
||||
bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count));
|
||||
}
|
||||
count = read (fd, start->charptr, bufsiz);
|
||||
if (count < 0)
|
||||
{
|
||||
msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p);
|
||||
exit (EX_ARGSBAD); /* FOO */
|
||||
}
|
||||
bytes_left -= count;
|
||||
userec (start + (count - 1) / RECORDSIZE);
|
||||
if (count != bufsiz)
|
||||
{
|
||||
msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
(void) close (fd);
|
||||
}
|
||||
|
||||
#ifdef DONTDEF
|
||||
bprint (fp, buf, num)
|
||||
FILE *fp;
|
||||
char *buf;
|
||||
{
|
||||
int c;
|
||||
|
||||
if (num == 0 || num == -1)
|
||||
return;
|
||||
fputs (" '", fp);
|
||||
while (num--)
|
||||
{
|
||||
c = *buf++;
|
||||
if (c == '\\')
|
||||
fputs ("\\\\", fp);
|
||||
else if (c >= ' ' && c <= '~')
|
||||
putc (c, fp);
|
||||
else
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
fputs ("\\n", fp);
|
||||
break;
|
||||
case '\r':
|
||||
fputs ("\\r", fp);
|
||||
break;
|
||||
case '\b':
|
||||
fputs ("\\b", fp);
|
||||
break;
|
||||
case '\0':
|
||||
/* fputs("\\-",fp); */
|
||||
break;
|
||||
default:
|
||||
fprintf (fp, "\\%03o", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputs ("'\n", fp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int number_of_blocks_read = 0;
|
||||
|
||||
int number_of_new_records = 0;
|
||||
int number_of_records_needed = 0;
|
||||
|
||||
union record *new_block = 0;
|
||||
union record *save_block = 0;
|
||||
|
||||
void
|
||||
junk_archive ()
|
||||
{
|
||||
int found_stuff = 0;
|
||||
int status = 3;
|
||||
int prev_status;
|
||||
struct name *name;
|
||||
|
||||
/* int dummy_head; */
|
||||
int number_of_records_to_skip = 0;
|
||||
int number_of_records_to_keep = 0;
|
||||
int number_of_kept_records_in_block;
|
||||
int sub_status;
|
||||
extern int write_archive_to_stdout;
|
||||
|
||||
/* fprintf(stderr,"Junk files\n"); */
|
||||
name_gather ();
|
||||
open_archive (2);
|
||||
|
||||
while (!found_stuff)
|
||||
{
|
||||
prev_status = status;
|
||||
status = read_header ();
|
||||
switch (status)
|
||||
{
|
||||
case EOF:
|
||||
found_stuff = 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
userec (head);
|
||||
switch (prev_status)
|
||||
{
|
||||
case 3:
|
||||
msg ("This doesn't look like a tar archive.");
|
||||
/* FALL THROUGH */
|
||||
case 2:
|
||||
case 1:
|
||||
msg ("Skipping to next header");
|
||||
/* FALL THROUGH */
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* head->header.name[NAMSIZ-1] = '\0'; */
|
||||
/* fprintf(stderr,"file %s\n",head->header.name); */
|
||||
if ((name = name_scan (current_file_name)) == (struct name *) 0)
|
||||
{
|
||||
userec (head);
|
||||
/* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) (hstat.st_size));
|
||||
break;
|
||||
}
|
||||
name->found = 1;
|
||||
found_stuff = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
found_stuff = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* fprintf(stderr,"Out of first loop\n"); */
|
||||
|
||||
if (found_stuff != 2)
|
||||
{
|
||||
write_eot ();
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (write_archive_to_stdout)
|
||||
write_archive_to_stdout = 0;
|
||||
new_block = (union record *) malloc (blocksize);
|
||||
if (new_block == 0)
|
||||
{
|
||||
msg ("Can't allocate secondary block of %d bytes", blocksize);
|
||||
exit (EX_SYSTEM);
|
||||
}
|
||||
|
||||
/* Save away records before this one in this block */
|
||||
number_of_new_records = ar_record - ar_block;
|
||||
number_of_records_needed = blocking - number_of_new_records;
|
||||
if (number_of_new_records)
|
||||
bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE);
|
||||
|
||||
/* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */
|
||||
userec (head);
|
||||
if (head->header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) (hstat.st_size));
|
||||
found_stuff = 0;
|
||||
/* goto flush_file; */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Fill in a block */
|
||||
/* another_file: */
|
||||
if (ar_record == ar_last)
|
||||
{
|
||||
/* fprintf(stderr,"New block\n"); */
|
||||
flush_archive ();
|
||||
number_of_blocks_read++;
|
||||
}
|
||||
sub_status = read_header ();
|
||||
/* fprintf(stderr,"Header type %d\n",sub_status); */
|
||||
|
||||
if (sub_status == 2 && f_ignorez)
|
||||
{
|
||||
userec (head);
|
||||
continue;
|
||||
}
|
||||
if (sub_status == EOF || sub_status == 2)
|
||||
{
|
||||
found_stuff = 1;
|
||||
bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed);
|
||||
number_of_new_records += number_of_records_needed;
|
||||
number_of_records_needed = 0;
|
||||
write_block (0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sub_status == 0)
|
||||
{
|
||||
msg ("Deleting non-header from archive.");
|
||||
userec (head);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Found another header. Yipee! */
|
||||
/* head->header.name[NAMSIZ-1] = '\0'; */
|
||||
/* fprintf(stderr,"File %s ",head->header.name); */
|
||||
if (name = name_scan (current_file_name))
|
||||
{
|
||||
name->found = 1;
|
||||
/* fprintf(stderr,"Flush it\n"); */
|
||||
/* flush_file: */
|
||||
/* decode_header(head,&hstat,&dummy_head,0); */
|
||||
userec (head);
|
||||
number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
|
||||
/* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */
|
||||
|
||||
while (ar_last - ar_record <= number_of_records_to_skip)
|
||||
{
|
||||
|
||||
/* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */
|
||||
number_of_records_to_skip -= (ar_last - ar_record);
|
||||
flush_archive ();
|
||||
number_of_blocks_read++;
|
||||
/* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */
|
||||
}
|
||||
ar_record += number_of_records_to_skip;
|
||||
/* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */
|
||||
number_of_records_to_skip = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy_header: */
|
||||
new_block[number_of_new_records] = *head;
|
||||
number_of_new_records++;
|
||||
number_of_records_needed--;
|
||||
number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
|
||||
userec (head);
|
||||
if (number_of_records_needed == 0)
|
||||
write_block (1);
|
||||
/* copy_data: */
|
||||
number_of_kept_records_in_block = ar_last - ar_record;
|
||||
if (number_of_kept_records_in_block > number_of_records_to_keep)
|
||||
number_of_kept_records_in_block = number_of_records_to_keep;
|
||||
|
||||
/* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */
|
||||
|
||||
while (number_of_records_to_keep)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (ar_record == ar_last)
|
||||
{
|
||||
/* fprintf(stderr,"Flush. . .\n"); */
|
||||
fl_read ();
|
||||
number_of_blocks_read++;
|
||||
ar_record = ar_block;
|
||||
number_of_kept_records_in_block = blocking;
|
||||
if (number_of_kept_records_in_block > number_of_records_to_keep)
|
||||
number_of_kept_records_in_block = number_of_records_to_keep;
|
||||
}
|
||||
n = number_of_kept_records_in_block;
|
||||
if (n > number_of_records_needed)
|
||||
n = number_of_records_needed;
|
||||
|
||||
/* fprintf(stderr,"Copying %d\n",n); */
|
||||
bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE);
|
||||
number_of_new_records += n;
|
||||
number_of_records_needed -= n;
|
||||
ar_record += n;
|
||||
number_of_records_to_keep -= n;
|
||||
number_of_kept_records_in_block -= n;
|
||||
/* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n",
|
||||
number_of_new_records,number_of_records_needed,number_of_records_to_keep,
|
||||
number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */
|
||||
|
||||
if (number_of_records_needed == 0)
|
||||
{
|
||||
write_block (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_eot ();
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
}
|
||||
|
||||
void
|
||||
write_block (f)
|
||||
int f;
|
||||
{
|
||||
/* fprintf(stderr,"Write block\n"); */
|
||||
/* We've filled out a block. Write it out. */
|
||||
|
||||
/* Backspace back to where we started. . . */
|
||||
if (archive != STDIN)
|
||||
(void) move_arch (-(number_of_blocks_read + 1));
|
||||
|
||||
save_block = ar_block;
|
||||
ar_block = new_block;
|
||||
|
||||
if (archive == STDIN)
|
||||
archive = STDOUT;
|
||||
fl_write ();
|
||||
|
||||
if (archive == STDOUT)
|
||||
archive = STDIN;
|
||||
ar_block = save_block;
|
||||
|
||||
if (f)
|
||||
{
|
||||
/* Move the tape head back to where we were */
|
||||
if (archive != STDIN)
|
||||
(void) move_arch (number_of_blocks_read);
|
||||
number_of_blocks_read--;
|
||||
}
|
||||
|
||||
number_of_records_needed = blocking;
|
||||
number_of_new_records = 0;
|
||||
}
|
||||
|
||||
/* Move archive descriptor by n blocks worth. If n is positive we move
|
||||
forward, else we move negative. If its a tape, MTIOCTOP had better
|
||||
work. If its something else, we try to seek on it. If we can't
|
||||
seek, we lose! */
|
||||
int
|
||||
move_arch (n)
|
||||
int n;
|
||||
{
|
||||
long cur;
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
struct mtop t;
|
||||
int er;
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
t.mt_op = MTFSR;
|
||||
t.mt_count = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.mt_op = MTBSR;
|
||||
t.mt_count = -n;
|
||||
}
|
||||
if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
|
||||
return 1;
|
||||
if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
cur = rmtlseek (archive, 0L, 1);
|
||||
cur += blocksize * n;
|
||||
|
||||
/* fprintf(stderr,"Fore to %x\n",cur); */
|
||||
if (rmtlseek (archive, cur, 0) != cur)
|
||||
{
|
||||
/* Lseek failed. Try a different method */
|
||||
msg ("Couldn't re-position archive file.");
|
||||
exit (EX_BADARCH);
|
||||
}
|
||||
return 3;
|
||||
}
|
@ -1 +0,0 @@
|
||||
char version_string[] = "GNU tar version 1.11.2";
|
Loading…
Reference in New Issue
Block a user