Send our ancienv GNU tar into Attic.

Suggested by:	ps
This commit is contained in:
Maxim Sobolev 2002-06-04 11:14:06 +00:00
parent 0f4e165dc0
commit bf15d27233
31 changed files with 0 additions and 16129 deletions

View File

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

View File

@ -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:

View File

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

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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) */

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

@ -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';
}

View File

@ -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);
}
}

View File

@ -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 ();

View File

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

View File

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

View File

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

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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 ***));

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

@ -1 +0,0 @@
char version_string[] = "GNU tar version 1.11.2";