2 Commits

Author SHA1 Message Date
Paul Eggert
8225f274ff Add copyright notice.
(AC_FUNC_STRERROR_R): Always do char* test, so that it gets cached.
Merge changes from latest Autoconf CVS.
Rename ac_cv_func_strerror_r_works to ac_cv_func_strerror_r_char_p,
and rename HAVE_WORKING_STRERROR_R to STRERROR_R_CHAR_P, since
POSIX decided to standardize on the int flavor of strerror_r.
2001-10-20 18:10:52 +00:00
Paul Eggert
e439c9fe36 (jm_PREREQ_ERROR): Do not invoke AC_CHECK_FUNCS with strerror_r, as
AC_FUNC_STRERROR_R does that.
Check for strerror declaration.
2001-10-20 18:10:52 +00:00
119 changed files with 8102 additions and 17281 deletions

View File

@@ -1,21 +0,0 @@
config
configure
aclocal.m4
ABOUT-NLS
autom4te.cache
config.hin
COPYING
INSTALL
Makefile.in
config.log
config.status
Makefile
config.h
stamp-h1
*.tar
*.tar.gz
*.tar.bz2
*.shar.gz
gnulib
gnulib/*
gnulib/*/*

View File

@@ -3,12 +3,6 @@ Authors of GNU tar.
The following contributions warranted legal paper exchanges with the
Free Software Foundation. Also see files ChangeLog and THANKS.
TAR Sergey Poznyakoff 2003-10
Assigns his past and future changes.
TAR Paul Eggert 2000-10
Assigns his past and future changes.
TAR Jay Fenlason
Assigns his changes.

1654
ChangeLog

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,60 @@
# Main Makefile for GNU tar.
# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 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 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.
## 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.
## 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.
AUTOMAKE_OPTIONS = gnits dist-shar
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = ChangeLog.1 PORTS
SUBDIRS = doc lib src scripts po tests
BABYL = rmail/* admin/*/RMAIL
EXTRA_DIST = AC-PATCHES AM-PATCHES BI-PATCHES PORTS rebox.el
SUBDIRS = doc lib intl src scripts po tests
all-local: $(CONFIG_HEADER)
id: ID
ID:
cd lib && $(MAKE) $@
cd src && $(MAKE) $@
dist-zoo: $(DISTFILES)
rm -rf $(distdir)
mkdir $(distdir)
distdir=`cd $(distdir) && pwd` \
&& cd $(srcdir) \
&& automake --include-deps --output-dir=$$distdir
@for file in $(DISTFILES); do \
test -f $(distdir)/$$file \
|| cp -p $(srcdir)/$$file $(distdir)/$$file; \
done
for subdir in $(SUBDIRS); do \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
|| exit 1; \
chmod 777 $(distdir)/$$subdir; \
(cd $$subdir && $(MAKE) dist) || exit 1; \
done
@sublist="$(DIST_SUBDIRS)"; \
for dir in $$sublist; do \
echo copying directory $$dir; \
tar -chf - $$dir | (cd $(distdir) && tar -xBpf -); \
done
chmod -R a+r $(distdir)
find $(distdir) -type f | xargs dosfn
# find $(distdir) -type f | xargs recode :ibmpc
mv $(distdir) $(PACKAGE)
find $(PACKAGE) -type f | zoo ahIq $(PACKAGE).zoo
rm -rf $(PACKAGE)

101
NEWS
View File

@@ -1,85 +1,4 @@
GNU tar NEWS - User visible changes.
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
Free Software Foundation, Inc.
See the end for copying conditions.
Please send GNU tar bug reports to <bug-tar@gnu.org>
version 1.14 - Sergey Poznyakoff, 2004-05-11
* Added support for POSIX.1-2001 and ustar archive formats.
* New option --format allows to select the output archive format
* The default output format can be selected at configuration time
by presetting the environment variable DEFAULT_ARCHIVE_FORMAT.
Allowed values are GNU, V7, OLDGNU and POSIX.
* New option --strip-path allows to cut off a given number of
path elements from the name of the file being extracted.
* New options --index-file, --no-overwrite-dir. The --overwrite-dir
option is now the default; use --no-overwrite-dir if you prefer
the previous default behavior.
* The semantics of -o option is changed. When extracting, it
does the same as --no-same-owner GNU tar option. This is compatible
with UNIX98 tar. Otherwise, its effect is the same as that of
--old-archive option. This latter is deprecated and will be removed
in future.
* New option --check-links prints a message if not all links are dumped
for a file being archived. This corresponds to the UNIX98 -l option.
The current semantics of the -l option is retained for compatibility
with previous releases, however such usage is strongly deprecated as
the option will change to its UNIX98 semantics in the future releases.
* New option --occurrence[=N] can be used in conjunction with one of
the subcommands --delete, --diff, --extract or --list when a list of
files is given either on the command line or via -T option. This
option instructs tar to process only the Nth occurrence of each named
file. N defaults to 1, so `tar -x -f archive --occurrence filename'
extracts the first occurrence of `filename' from `archive'
and terminates without scanning to the end of the archive.
* New option --pax-option allows to control the handling of POSIX
keywords in `pax' extended headers. It is equivalent to `pax'
-o option.
* --incremental and --listed-incremental options work correctly on
individual files, as well as on directories.
* New scripts: backup (replaces old level-0 and level-1) and restore.
The scripts are compiled and installed if --enable-backup-scripts
option is given to configure.
* By default tar searches "rmt" utility in "$prefix/libexec/rmt",
which is consistent with the location where the version of "rmt"
included in the package is installed. Previous versions of tar
used "/etc/rmt". To install "rmt" to its traditional location,
run configure with option --libexecdir=/etc. Otherwise, if you
already have rmt installed and wish to use it, instead of the
shipped in version, set the variable DEFAULT_RMT_COMMAND to
the full path name of the utility, e.g. ./configure
DEFAULT_RMT_COMMAND=/etc/rmt.
Notice also that the full path name of the "rmt" utility to
use can be set at runtime, by giving option --rmt-command to
tar.
* Removed obsolete command line options:
** --absolute-paths superseded by --absolute-names
** --block-compress is not needed any longer
** --block-size superseded by --blocking-factor
** --modification-time superseded by --touch
** --read-full-blocks superseded by --read-full-records
** --record-number superseded by --block-number
** --version-control superseded by --backup
* New message translations fi (Finnish), gl (Galician), hr (Croatian),
hu (Hungarian), ms (Malaysian), nb (Norwegian), ro (Romanian), sk
(Slovak), zh_CN (Chinese simplified), zh_TW (Chinese traditional).
The code 'no' for Norwegian (Bokm<6B>l) has been withdrawn; use 'nb' instead.
* Bug fixes.
version 1.13.25 - Paul Eggert, 2001-09-26
@@ -89,7 +8,6 @@ version 1.13.24 - Paul Eggert, 2001-09-22
* New option --overwrite-dir.
* Fixes for buffer overrun, porting, and copyright notice problems.
* The message translations for Korean are available again.
version 1.13.23 - Paul Eggert, 2001-09-13
@@ -195,7 +113,7 @@ version 1.13.16 - Paul Eggert, 1999-12-13.
To enable the old behavior, use the -P or --absolute-names option.
* Tar now handles file names with multibyte encodings (e.g. UTF-8, Shift-JIS)
correctly. It relies on the mbrtowc function to handle multibyte characters.
correctly. It relies on the mbrtowc function to handle multibytes.
* The file generated by -g or --listed-incremental now uses a format
that is independent of locale, so that users need not worry about
@@ -388,7 +306,7 @@ version 1.13 - Paul Eggert, 1999-07-08.
but they have been removed to maintain compatibility with paxutils.
Please try --use=bzip2 instead of --bzip2.
Version 1.12 - François Pinard, 1997-04.
Version 1.12 - Fran<EFBFBD>ois Pinard, 1997-04.
Sensitive matters
* Use shell globbing patterns for --label, instead of regular expressions.
@@ -431,7 +349,7 @@ Various changes
Many bugs are squashed, while others still run free.
Version 1.11.8 - François Pinard, 1995-06.
Version 1.11.8 - Fran<EFBFBD>ois Pinard, 1995-06.
* Messages available in French, German, Portuguese and Swedish.
* The distribution provides a rudimentary Texinfo manual.
@@ -567,8 +485,8 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003
Free Software Foundation, Inc.
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free
Software Foundation, Inc.
This file is part of GNU tar.
@@ -586,8 +504,9 @@ You should have received a copy of the GNU General Public License
along with tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Local variables:
mode: outline
paragraph-separate: "[ ]*$"
end:
Local Variables:
coding: iso-latin-1
End:

46
PORTS
View File

@@ -1,45 +1,17 @@
* Ports of GNU tar and other tars -*- outline -*-
* Ports of GNU tar and other micro-tars -*- outline -*-
Many entries in this file are out of date, unfortunately.
Please write bug-tar@gnu.org if you are aware of various ports of GNU tar
to non-GNU and non-Unix systems not listed here, or for corrections.
Please write tar-bugs@gnu.ai.mit.edu if you are aware of various ports
of GNU tar to non-Unix systems not listed here, or for corrections.
Please provide the goal system, a complete and stable URL, the maintainer
name and address, the tar version used as a base, and your comments.
.* Copyright notice
Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc.
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, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
.* GNU/Linux and Unix
. + Star is a tape archiver similar to tar.
<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/star.html>
.* Amiga
. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/GNUtar-1.11.8.lha
maintained by Enrico Forestieri <enrico@com.unipr.it>
Based on tar 1.11.8.
. + [This link seems to be dead:]
ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
. + ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
maintained by the ADE group <fnf@fishpond.ninemoons.com>
Based on tar 1.11.8, needs ixemul.library.
@@ -48,14 +20,12 @@
.* DEC alpha (NT)
. + [This link seems to be dead:]
ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
maintained by Drew Bliss & Geoff Voelker
.* DEC VAX (VMS)
. + [This link seems to be dead:]
http://www.lp.se/free/vmstar/
. + http://www.lp.se/free/vmstar/
maintained by Richard Levitte <levitte@lp.se>
This is not GNU tar, but a separate implementation.
@@ -154,10 +124,6 @@
.* Macintosh
. + Paulo Abreu (paulotex at yahoo dot com) did a
limited port of GNU tar to Darwin, with support for resource forks
and finder info, but this no longer seems to be available.
. + There is a tar in Stuffit Expander which is available many places and
comes with MacOS. It creates some spurious files but works on average.

177
README
View File

@@ -1,7 +1,25 @@
README for GNU tar
See the end of file for copying conditions.
* Introduction
Copyright 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
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 tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Please glance through *all* sections of this
`README' file before starting configuration. Also make sure you read files
@@ -30,15 +48,9 @@ See file `THANKS' for a list of contributors.
Besides those configure options documented in files `INSTALL' and
`ABOUT-NLS', an extra option may be accepted after `./configure':
* Install
** Selecting the default archive format.
The default archive format is GNU, this can be overridden by
presetting DEFAULT_ARCHIVE_FORMAT while configuring. The allowed
values are GNU, V7, OLDGNU, USTAR and POSIX.
** Selecting the default archive device
* `--disable-largefile' omits support for large files, even if the
operating system supports large files. Typically, large files are
those larger on 2 GB on a 32-bit host.
The default archive device is now `stdin' on read and `stdout' on write.
The installer can still override this by presetting `DEFAULT_ARCHIVE'
@@ -46,37 +58,34 @@ in the environment before configuring (the behavior of `-[0-7]' or
`-[0-7]lmh' options in `tar' are then derived automatically). Similarly,
`DEFAULT_BLOCKING' can be preset to something else than 20.
** Selecting full pathname of the "rmt" binary.
For comprehensive modifications to GNU tar, you might need tools beyond
those used in simple installations. Fully install GNU m4 1.4 first,
and only then, Autoconf 2.13 or later. Install Perl, then Automake
1.4 or later. You might need Bison 1.28 or later, and GNU tar itself.
All are available on GNU archive sites, like in
ftp://ftp.gnu.org/pub/gnu/.
Previous versions of tar always looked for "rmt" binary using
hardcoded path "/etc/rmt". However, the "rmt" program included
in the distribution was installed under "$prefix/libexec/rmt".
To fix this discrepancy, tar now looks for "$prefix/libexec/rmt".
If you do not want this behavior, specify full path name of
"rmt" binary using DEFAULT_RMT_COMMAND variable, e.g.:
Send bug reports to `bug-tar@gnu.org'. (Beware, old-timers: it is
`@gnu', not `@prep'; and not `bug-gnu-utils' anymore.) A bug report is
an adequate description of the problem: your input, what you expected,
what you got, and why this is wrong. Diffs are welcome, but they only
describe a solution, from which the problem might be uneasy to infer.
If needed, submit actual data files with your report. Small data files
are preferred. Big files may sometimes be necessary, but do not send them
to the report address; rather take special arrangement with the maintainer.
./configure DEFAULT_RMT_COMMAND=/etc/rmt
Your feedback will help us to make a better and more portable package.
Consider documentation errors as bugs, and report them as such. If you
develop anything pertaining to `tar' or have suggestions, let us know
and share your findings by writing to <bug-tar@gnu.org>.
** Installing backup scripts.
This version of tar is shipped with the shell scripts for producing
incremental backups (dumps) and restoring filesystems from them.
The name of the backup script is "backup". The name of the
restore script is "restore". They are installed in "$prefix/sbin"
directory.
Use option --enable-backup-scripts to compile and install these
scripts.
** `--disable-largefile' omits support for large files, even if the
operating system supports large files. Typically, large files are
those larger on 2 GB on a 32-bit host.
* Installation hints
Installation hints
------------------
Here are a few hints which might help installing `tar' on some systems.
** gzip and bzip2.
* gzip and bzip2.
GNU tar uses the gzip and bzip2 programs to read and write compressed
archives. If you don't have these programs already, you need to
@@ -97,7 +106,7 @@ in gzip test version 1.3, which as of this writing is available at
incompatibility by using a shell command like
`gzip -d <file.tar.gz | tar -xzf -'.
** Solaris issues.
* Solaris issues.
GNU tar exercises many features that can cause problems with older GCC
versions. In particular, GCC 2.8.1 (sparc, -O1 or -O2) is known to
@@ -108,7 +117,7 @@ Recent versions of Solaris tar sport a new -E option to generate
extended headers in an undocumented format. GNU tar does not
understand these headers.
** Static linking.
* Static linking.
Some platform will, by default, prepare a smaller `tar' executable
which depends on shared libraries. Since GNU `tar' may be used for
@@ -129,32 +138,34 @@ to a value from the table below, before configuration (see `INSTALL').
Solaris (vendor) -Bstatic
SunOS (vendor) -Bstatic
** Failed tests `ignfail.sh' or `incremen.sh'.
* Failed tests `ignfail.sh' or `incremen.sh'.
In an NFS environment, lack of synchronization between machine clocks
might create difficulties to any tool comparing dates and file time stamps,
like `tar' in incremental dumps. This has been a recurrent problem with
GNU Make for the last few years. We would like a general solution.
** BSD compatibility matters.
* BSD compatibility matters.
Set LIBS to `-lbsd' before configuration (see `INSTALL') if the linker
complains about `bsd_ioctl' (Slackware). Also set CPPFLAGS to
`-I/usr/include/bsd' if <sgtty.h> is not found (Slackware).
** OPENStep 4.2 swap files
* OPENStep 4.2 swap files
Tar cannot read the file /private/vm/swapfile.front (even as root).
This file is not a real file, but some kind of uncompressed view of
the real compressed swap file; there is no reason to back it up, so
the simplest workaround is to avoid tarring this file.
* Special topics
Special topics
--------------
Here are a few special matters about GNU `tar', not related to build
matters. See previous section for such.
** File attributes.
* File attributes.
About *security*, it is probable that future releases of `tar' will have
some behavior changed. There are many pending suggestions to choose from.
@@ -167,77 +178,19 @@ implement flavors of symbolic links showing different behavior and
properties. We did not successfully sorted all these out yet. Currently,
the `lchown' call will be used if available, but that's all.
** POSIX compliance.
* POSIX compliance.
GNU `tar' is able to create archive in the following formats:
*** The format of UNIX version 7
*** POSIX.1-1988 format, also known as "ustar format"
*** POSIX.1-2001 format, also known as "pax format"
*** Old GNU format (described below)
In addition to those, GNU `tar' is also able to read archives
produced by `star' archiver.
A so called `Old GNU' format is based on an early draft of the
POSIX 1003.1 `ustar' standard which is different from the final
standard. It defines its extensions (such as incremental backups
and handling of the long file names) in a way incompatible with
any existing tar archive format, therefore the use of old GNU
format is strongly discouraged.
Please read the file NEWS for more information about POSIX compliance
and new `tar' features.
GNU `tar' implements an early draft of the POSIX 1003.1 `ustar' standard
which is different from the final standard. This will be progressively
corrected over the incoming few years. Don't be mislead by the mere
existence of the --posix option. Later releases will become able to
read truly POSIX archives, and also to produce them under option. (Also,
if you look at the internals, don't take the GNU extensions you see for
granted, as they are planned to change.) GNU tar 2.0 will produce POSIX
archives by default, but there is a long way before we get there.
* What's next?
GNU tar will be merged into GNU paxutils: a project containing
several utilities related to creating and handling archives in
various formats. The project will include tar, cpio and pax
utilities.
* Bug reporting.
Send bug reports to <bug-tar@gnu.org>. A bug report should contain
an adequate description of the problem, your input, what you expected,
what you got, and why this is wrong. Diffs are welcome, but they only
describe a solution, from which the problem might be uneasy to infer.
If needed, submit actual data files with your report. Small data files
are preferred. Big files may sometimes be necessary, but do not send them
to the report address; rather take special arrangement with the maintainer.
Your feedback will help us to make a better and more portable package.
Consider documentation errors as bugs, and report them as such. If you
develop anything pertaining to `tar' or have suggestions, let us know
and share your findings by writing to <bug-tar@gnu.org>.
* Copying
Copyright (C) 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000,
2001, 2003, 2004 Free Software Foundation, Inc.
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 tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Local Variables:
mode: outline
paragraph-separate: "[ ]*$"
version-control: never
End:
In the future we will try to release tar-1.14 as soon as possible and
start merging with paxutils afterwards. We'll also try to rewrite
some parts of the documentation after paxutils has been merged.

View File

@@ -1,72 +1,242 @@
This is GNU tar.
This is a test release of GNU tar.
This is a *pre-release* version, and not ready for production use yet.
Please send comments and problem reports to <bug-tar@gnu.org>.
If you have taken the sources from CVS you will need the following
packages (or later) to build GNU tar. We don't make any extra effort
to accommodate older versions of these packages. If we discover that
newer versions are needed to bootstrap, we'll update the version
numbers in this list.
Copyright 2001 Free Software Foundation, Inc.
autoconf 2.59
automake 1.8
bison 1.875
gettext 0.12.1
m4 1.4
wget 1.7
This file is part of GNU tar.
For GNU m4 1.4, we recommend also installing the `translit' patch; see
Debian bug 211477 <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=211477>.
This patch is bundled into Debian m4 1.4-17 or later.
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.
Before building the package, run "bootstrap". It obtains various
additional files from the CVS repository and the Translation Project
site and prepares the source directory for building.
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.
When run without arguments, bootstrap will try to obtain gnulib files
from CVS repository on savannah using anonymous SSH access. Then, it
will fetch the po files from tar page at Translation Project, and,
finally, it will start autoconfiguration process. Simply running
it without arguments should do in most cases. Several options
allow to control the behavior of bootstrap:
You should have received a copy of the GNU General Public License
along with tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
This release was built with GNU automake 1.5 patched as follows:
2001-09-24 Paul Eggert <eggert@twinsun.com>
* m4/header.m4 (_AM_Config_Header_Index): Remove.
(AM_CONFIG_HEADER): Don't use it. It wasn't working, and was
causing needless rebuilds.
2001-09-14 Paul Eggert <eggert@twinsun.com>
* lib/am/distdir.am (REMOVE_DISTDIR):
New macro. Do not change permission of non-directories.
(distdir, dist, dist-bzip2, dist-tarZ, dist-shar, dist-zip, dist-all,
distcheck): Use it.
===================================================================
RCS file: lib/am/distdir.am,v
retrieving revision 1.5
retrieving revision 1.5.0.1
diff -pu -r1.5 -r1.5.0.1
--- lib/am/distdir.am 2001/07/14 20:12:52 1.5
+++ lib/am/distdir.am 2001/09/15 05:12:18 1.5.0.1
@@ -29,6 +29,11 @@ else !%?TOPDIR_P%
?DISTDIR?distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
endif !%?TOPDIR_P%
+REMOVE_DISTDIR = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+
distdir: $(DISTFILES)
##
## For Gnits users, this is pretty handy. Look at 15 lines
@@ -47,7 +52,7 @@ endif %?TOPDIR_P%
## Only for the top dir.
##
if %?TOPDIR_P%
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
mkdir $(distdir)
endif %?TOPDIR_P%
##
@@ -168,13 +173,13 @@ GZIP_ENV = --best
.PHONY: dist
dist: distdir
$(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
if %?BZIP2%
.PHONY: dist-bzip2
dist-bzip2: distdir
$(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
endif %?BZIP2%
@@ -182,7 +187,7 @@ if %?COMPRESS%
.PHONY: dist-tarZ
dist-tarZ: distdir
$(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
endif %?COMPRESS%
@@ -190,7 +195,7 @@ if %?SHAR%
.PHONY: dist-shar
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
endif %?SHAR%
@@ -199,7 +204,7 @@ if %?ZIP%
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
endif %?ZIP%
endif %?TOPDIR_P%
@@ -223,7 +228,7 @@ dist-all: distdir
?SHAR? shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
?ZIP? -rm -f $(distdir).zip
?ZIP? zip -rq $(distdir).zip $(distdir)
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
endif %?TOPDIR_P%
@@ -239,8 +244,7 @@ if %?TOPDIR_P%
# tarfile.
.PHONY: distcheck
distcheck: dist
-## Make sure we can remove distdir before trying to remove it.
- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
## Make the new source tree read-only. Distributions ought to work in
## this case. However, make the top-level directory writable so we
@@ -273,7 +277,7 @@ distcheck: dist
&& (test `find . -type f -print | wc -l` -eq 0 \
|| (echo "Error: files left after distclean" 1>&2; \
exit 1) )
- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
+ $(REMOVE_DISTDIR)
@echo "$(distdir).tar.gz is ready for distribution" | \
sed 'h;s/./=/g;p;x;p;x'
endif %?TOPDIR_P%
===================================================================
RCS file: m4/header.m4,v
retrieving revision 1.5
retrieving revision 1.5.0.1
diff -pu -r1.5 -r1.5.0.1
--- m4/header.m4 2001/07/21 05:27:26 1.5
+++ m4/header.m4 2001/09/24 18:29:30 1.5.0.1
@@ -11,18 +11,16 @@ AC_PREREQ([2.12])
AC_DEFUN([AM_CONFIG_HEADER],
[ifdef([AC_FOREACH],dnl
- [dnl init our file count if it isn't already
- m4_ifndef([_AM_Config_Header_Index], m4_define([_AM_Config_Header_Index], [0]))
+ [
dnl prepare to store our destination file list for use in config.status
AC_FOREACH([_AM_File], [$1],
[m4_pushdef([_AM_Dest], m4_patsubst(_AM_File, [:.*]))
- m4_define([_AM_Config_Header_Index], m4_incr(_AM_Config_Header_Index))
dnl and add it to the list of files AC keeps track of, along
dnl with our hook
AC_CONFIG_HEADERS(_AM_File,
dnl COMMANDS, [, INIT-CMDS]
[# update the timestamp
-echo timestamp >"AS_ESCAPE(_AM_DIRNAME(]_AM_Dest[))/stamp-h]_AM_Config_Header_Index["
+echo timestamp >"AS_ESCAPE(_AM_DIRNAME(]_AM_Dest[))/stamp-h"
][$2]m4_ifval([$3], [, [$3]]))dnl AC_CONFIG_HEADERS
m4_popdef([_AM_Dest])])],dnl
[AC_CONFIG_HEADER([$1])
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
sources reside. Use this if you already
have gnulib sources on your machine, and
do not want to waste your bandwidth dowloading
them again.
--cvs-auth=METHOD Set the CVS access method used for downloading
gnulib files. METHOD is one of the keywords
accepted by cvs -d option (see info cvs
repository).
--cvs-user=USERNAME Set the CVS username to be used when accessing
the gnulib repository.
--no-po Do not download po files.
Notice also that when using CVS authentication method "ext", bootstrap
will set the variable CVS_RSH to "ssh", unless it is already set to
some other value.
and with GNU autoconf 2.52 patched as follows:
2001-09-15 Paul Eggert <eggert@twinsun.com>
Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
Fix bug reported by Paul Townsend on AIX 4.3.3.0 with
CFLAGS=-O4 or CFLAGS=-O5. In that case, the linker has a
relaxed view of fatal errors, and AC_CHECK_LIB causes it to
include libraries even when they don't exist.
This file is part of GNU tar.
* acheaders.m4 (AC_HEADER_DIRENT): Use AC_SEARCH_LIBS, not
AC_CHECK_LIB, so that we don't use -ldir or -lx if we don't
need it.
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 tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
* acspecific.m4 (AC_ISC_POSIX): Replace the old, crufty
version with the version used by fileutils 4.1, except use
AC_SEARCH_LIBS, not AC_CHECK_LIB, so that we don't use
-lcposix if we don't need it.
===================================================================
RCS file: acheaders.m4,v
retrieving revision 2.52
retrieving revision 2.52.0.1
diff -pu -r2.52 -r2.52.0.1
--- acheaders.m4 2001/07/03 14:19:09 2.52
+++ acheaders.m4 2001/09/16 02:53:51 2.52.0.1
@@ -158,9 +158,9 @@ ac_header_dirent=$ac_hdr; break])
done
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
if test $ac_header_dirent = dirent.h; then
- AC_CHECK_LIB(dir, opendir, LIBS="$LIBS -ldir")
+ AC_SEARCH_LIBS(opendir, dir)
else
- AC_CHECK_LIB(x, opendir, LIBS="$LIBS -lx")
+ AC_SEARCH_LIBS(opendir, x)
fi
])# AC_HEADER_DIRENT
===================================================================
RCS file: acspecific.m4,v
retrieving revision 2.52
retrieving revision 2.52.0.1
diff -pu -r2.52 -r2.52.0.1
--- acspecific.m4 2001/06/15 17:46:01 2.52
+++ acspecific.m4 2001/09/16 02:53:51 2.52.0.1
@@ -993,28 +993,7 @@ fi
# AC_ISC_POSIX
# ------------
AC_DEFUN([AC_ISC_POSIX],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-AC_MSG_CHECKING([for POSIXized ISC])
-if test -d /etc/conf/kconfig.d &&
- grep _POSIX_VERSION [/usr/include/sys/unistd.h] >/dev/null 2>&1
-then
- AC_MSG_RESULT([yes])
- ISC=yes # If later tests want to check for ISC.
- AC_DEFINE(_POSIX_SOURCE, 1,
- [Define if you need to in order for stat and other things to
- work.])
- if test "$GCC" = yes; then
- CC="$CC -posix"
- else
- CC="$CC -Xp"
- fi
-else
- AC_MSG_RESULT([no])
- ISC=
-fi
-])# AC_ISC_POSIX
+[AC_SEARCH_LIBS(strerror, cposix)])
# AC_XENIX_DIR

104
THANKS
View File

@@ -1,16 +1,9 @@
GNU tar THANKS file
Public domain tar was written by John Gilmore, with contributions
from Henry Spencer, Fred Fish, Ian Darwin, Geoff Collyer, Stan Barber,
Guy Harris, Dave Brower, Richard Todd, Michael Rendell, Stu Heiss and
Rich $alz. The FSF version, named GNU tar, was derived from PDTAR by
Jay Fenlason and Joy Kendall, and was maintained in turn by Fran<61>§ois
Pinard and Paul Eggert.
Many people further contributed to GNU tar by reporting problems,
suggesting various improvements or submitting actual code. Here is a
list of these people. Help me keep it complete and exempt of errors.
See various ChangeLogs for a detailed description of contributions.
GNU tar has originally been written by Graham Todd. Many people
further contributed to GNU tar by reporting problems, suggesting
various improvements or submitting actual code. Here is a list of
these people. Help me keep it complete and exempt of errors.
Aage Robeck aagero@ifi.uio.no
Akiko Matsushita matusita@sra.co.jp
@@ -32,7 +25,6 @@ Andreas Haumer andreas@vlsivie.tuwien.ac.at
Andreas Jaeger aj@arthur.pfalz.de
Andreas Koppenhoefer koppenh@trick.informatik.uni-stuttgart.de
Andreas Reuter ar205@bonzo.geowiss.nat.tu-bs.de
Andreas Schuldei andreas@schuldei.org
Andreas Schwab schwab@issan.informatik.uni-dortmund.de
Andrew A. Ivanov ivanov@mics.msu.su
Andrew J. Schorr schorr@ead.dsa.com
@@ -42,7 +34,7 @@ Andy Gay andy@rdl.co.uk
Antonio Jose Coutinho ajc@di.uminho.pt
Ariel Faigon ariel@engr.sgi.com
Arne Wichmann aw@math.uni-sb.de
Arnold Robbins arnold@gnu.org
Arnold Robbins arnold@gnu.ai.mit.edu
Art Isbell aisbell@cubicsol.com
Axel Boldt boldt@math.ucsb.edu
Axel Habermann kiwi@belly.in-berlin.de
@@ -55,7 +47,6 @@ Bennett Todd bet@mordor.com
Benny Holmgren benny@hgs.se
Bernard Chen bern@cs.ucla.edu
Bernard Derval derval@iro.umontreal.ca
Bernhard Rosenkraenzer bero@redhat.de
Bo Nygaard Bai bai@iesd.auc.dk
Bob Kaehms kaehms@was.archive.org
Bob Mende Pie mende@piecomputer.rutgers.edu
@@ -66,22 +57,21 @@ Brian Perkins bperkins@netspace.org
Brian R. Smith brian@cygnus.com
Bruce Evans bde@runx.oz.au
Bruce Jerrick bruce@cse.ogi.edu
Bruno Haible haible@ilog.fr
Bruno Haible haible@ma2s2.mathematik.uni-karlsruhe.de
Bryant Fujimoto fujimoto@denali.chem.washington.edu
Burkhard Plache plache@krusty.optimax.ns.ca
Calvin Cliff cliff@trifid.astro.ucla.edu
Cameron Elliott cam@mvbms.mvbms.com
Carl Streeter streeter@cae.wisc.edu
Carsten Heyl heyl@nads.de
Catrin Urbanneck cur@gppc.de
Cesar Romani romani@ifm.uni-hamburg.de
Chad Hurwitz churritz@cts.com
Chance Reschke creschke@usra.edu
Charles Fu ccwf@klab.caltech.edu
Charles Lopes Charles.Lopes@infm.ulst.ac.uk
Charles M. Hannum mycroft@gnu.org
Charles M. Hannum mycroft@gnu.ai.mit.edu
Chip Salzenberg tct!chip
Chris Arthur csa@gnu.org
Chris Arthur csa@gnu.ai.mit.edu
Chris F.M. Verberne verberne@prl.philips.nl
Chris G. Demetriou cgd@sun-lamp.cs.berkeley.edu
Chris Hopps sycom.mi.org!ro-chp!chopps
@@ -89,12 +79,10 @@ Chris Metcalf metcalf@catfish.lcs.mit.edu
Chris Ransom chris@quests.com
Christian Callsen Christian.Callsen@eng.sun.com
Christian Kirsch ck@held.mind.de
Christian Laubscher <christian.laubscher@tiscalinet.ch>
Christian T. Dum ctd@mpe-garching.mpg.de
Christian von Roques roques@pond.sub.org
Christoph Litauer litauer@mailhost.uni-koblenz.de
Christophe Colle colle@krtkg1.rug.ac.be
Christophe Kalt Christophe.Kalt@kbcfp.com
Christopher T. Johnson cjohnson@camelot.com
Christopher Vickery vickery@ipc1.cs.qc.edu
Claude Scarpelli claude@genethon.fr
@@ -108,7 +96,7 @@ Dale R. Worley worley@world.std.com
Dale Wiles wiles@geordi.calspan.com
Dan Bloch dan@transarc.com
Dan Reish dreish@izzy.net
Daniel Hagerty hag@gnu.org
Daniel Hagerty hag@gnu.ai.mit.edu
Daniel Quinlan quinlan@pathname.com
Daniel R. Guilderson d.guilderson@ma30.bull.com
Daniel S. Barclay daniel@compass-da.com
@@ -139,7 +127,7 @@ Dimitri Bougoulias opus@hol.gr
Dimitris Fousekis dfousek@leon.nrcps.ariadne-t.gr
Dirk Herr-Hoyman hoymand@gate.net
Don Bennett dpb@netcom.com
Donald B Gordon dbgordon@gnu.org
Donald B Gordon dbgordon@gnu.ai.mit.edu
Donald H. Locker dhl@spuf1d83.lcp.chrysler.com
Douglas Scott doug@foxtrot.ccmrc.ucsb.edu
Drew Sullivan drew@sni.ca
@@ -164,12 +152,11 @@ Ezra Peisach epeisach@mit.edu
Fabio d'Alessi cars@civ.bio.unipd.it
Frank Koenen koenfr@lidp.com
Franz-Werner Gergen gergen@edvulx.mpi-stuttgart.mpg.de
Fran<EFBFBD>§ois Pinard pinard@iro.umontreal.ca
Fran<EFBFBD>ois Pinard pinard@iro.umontreal.ca
Fritz Elfert fritz@fsun.triltsch.de
George Chyu gschyu@ccgate.dp.beckman.com
Gerben Wierda gerben@rna.indiv.nluug.nl
Gerd Knorr kraxel@cs.tu-berlin.de
Gerhard Poul gpoul@gnu.org
Giorgio Signorini signo@chim.unifi.it
Graham Whitted gbw@sgrail.com
Grant McDorman grant@isgtec.com
@@ -178,9 +165,9 @@ Greg Chung gchung@caip.rutgers.edu
Greg Hudson ghudson@mit.edu
Greg Maples greg@clari.net
Greg McGary gkm@cstone.net
G<EFBFBD>ran Uddeborg gvran@uddeborg.pp.se
G<EFBFBD>ran Uddeborg gvran@uddeborg.pp.se
Hans Guerth 100664.3101@compuserve.com
Harald K<>nig koenig@tat.physik.uni-tuebingen.de
Harald K<>nig koenig@tat.physik.uni-tuebingen.de
Harald Milz hm@seneca.ix.de
Heiko Schinke mdqac@biochemtech.uni-halle.de
Heiko Schlichting heiko@fu-berlin.de
@@ -190,7 +177,7 @@ Hiroyuki Bessho bsh@grotto.iijnet.or.jp
Holger Teutsch holger@hotbso.rhein-main.de
Hugh Secker-Walker hugh@ear.mit.edu
Hunyue Yau hunyue.yau@picksys.com
Ian Jackson ijackson@gnu.org
Ian Jackson ijackson@gnu.ai.mit.edu
Ian Lance Taylor ian@cygnus.com
Ian T. Zimmerman itz@crl.com
Indra Singhal indra@synoptics.com
@@ -209,7 +196,7 @@ Jan Djarv jan.djarv@mbox200.swipnet.se
Janice Burton r06a165@bcc25.kodak.com
Janne Snabb snabb@niksula.hut.fi
Jason R. Mastaler jason@webmaster.net
Jay Fenlason hack@gnu.org
Jay Fenlason hack@gnu.ai.mit.edu
Jean-Michel Soenen soenen@lectra.fr
Jean-Ph. Martin-Flatin syj@ecmwf.int
Jean-loup Gailly jloup@chorus.fr
@@ -251,16 +238,15 @@ Joy Kendall jak8@world.std.com
Judy Ricker jricker@gdstech.grumman.com
Juha Sarlin juha@tds.kth.se
Jurgen Botz jbotz@orixa.mtholyoke.edu
J<EFBFBD>¼rgen L<>¼ters jlueters@t-online.de
J<EFBFBD>¼rgen Reiss reiss@psychologie.uni-wuerzburg.de
J<EFBFBD>rgen L<>ters jlueters@t-online.de
J<EFBFBD>rgen Reiss reiss@psychologie.uni-wuerzburg.de
Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
J<EFBFBD>rg Weule weule@cs.uni-duesseldorf.de
J<EFBFBD>rgen H<>¤gg Jorgen.Hagg@axis.se
J<EFBFBD>¶rgen Weigert jw@suse.de
J<EFBFBD>rg Weule weule@cs.uni-duesseldorf.de
J<EFBFBD>rgen H<>gg Jorgen.Hagg@axis.se
Kai Petzke wpp@marie.physik.tu-berlin.de
Kai Schlichting kai@computel.com
Karl Berry karl@cs.umb.edu
Karl Heuer kwzh@gnu.org
Karl Heuer kwzh@gnu.ai.mit.edu
Karl Vogel vogelke@c-17igp.wpafb.af.mil
Karlos Z. Smith kazen@viptx.net
Karsten Thygesen karthy@kom.auc.dk
@@ -280,13 +266,10 @@ Larry Creech lcreech@lonestar.rcclub.org
Larry Schwimmer rosebud@cyclone.stanford.edu
Laurent Caillat-Vallet caillat@noe.lyon.cemagref.fr
Laurent Sainte-Marthe smarthe@genethon.fr
Leland Lucius llucius@tiny.net
Les Mikesell les@mcs.com
Loren J. Rittle rittle@comm.mot.com
Lo<EFBFBD>¯c Prylli Loic.Prylli@lip.ens-lyon.fr
Lo<EFBFBD>c Prylli Loic.Prylli@lip.ens-lyon.fr
Luke Mewburn lukem@connect.com.au
Mads Martin Joergensen mmj@suse.de
Machael Stone mstone@cs.loyola.edu
Manfred Weichel Manfred.Weichel@mch.sni.de
Manuel Munier Manuel.Munier@loria.fr
Marc Boucher marc@cam.org
@@ -300,7 +283,7 @@ Mark Kollert Mark.Kollert@oi42.kwu.siemens.de
Mark W. Eichin eichin@cygnus.com
Markus Kuhn mskuhn@cip.informatik.uni-erlangen.de
Martin Bellenberg sunsoft@ifm.uni-hamburg.de
Martin Goik goik@HDM-Stuttgart.de
Martin Goik goma0002@fh-karlsruhe.de
Martin Mares mj@k332.feld.cvut.cz
Marty Leisner leisner@eso.mc.xerox.com
Massimo Dal Zotto dz@cs.unitn.it
@@ -310,8 +293,7 @@ Matthew J. D'Errico doc@deathstar.lis.cch.com
Matti Aarnio mea@utu.fi
Max Hailperin max@nic.gac.edu
Maxime Taksar mmt@redbrick.com
Melissa O'Neill oneill@cs.sfu.ca
Melissa Weisshaus melissa@gnu.org
Melissa Weisshaus melissa@gnu.ai.mit.edu
Michael Dietrich mdt@is.in-berlin.de
Michael Ellis bosun@aquarius.seaoar.uvic.ca
Michael Giddings giddings@whitewater.chem.wisc.edu
@@ -335,12 +317,11 @@ Mike Walker M.D.Walker@larc.nasa.gov
Milan Hodoscek milan@kihp6.ki.si
Minh Tran-Le tranle@intellicorp.com
Mitsuaki Masuhara masuhara@mcprv.mec.mei.co.jp
Nate Eldredge nate@cs.hmc.edu
Neil Faulks neil@dcs.kcl.ac.uk
Neil Jerram nj104@cus.cam.ac.uk
Nelson H.F. Beebe beebe@math.utah.edu
Nick Barron nikb@cix.compulink.co.uk
Noah Friedman friedman@gnu.org
Noah Friedman friedman@prep.ai.mit.edu
Noel Cragg noel@red-bean.com
Norbert Kiesel norbert@rwthi3.informatik.rwth-aachen.de
Olaf Schlueter olaf@toppoint.de
@@ -373,7 +354,7 @@ Piercarlo Grandi piercarl@sabi.demon.co.uk
Pierce Cantrell cantrell@ee.tamu.edu
R. Kent Dybvig dyb@cadence.bloomington.in.us
R. Scott Butler butler@prism.es.dupont.com
Rainer Orth ro@TechFak.Uni-Bielefeld.DE
Rainer Orth ro@thp.uni-koeln.de
Ralf Suckow suckow@contrib.de
Ralph Schleicher rs@purple.ul.bawue.de
Randy Bias randyb@edge.edge.net
@@ -382,11 +363,11 @@ Reuben J. Ravago reuben@asti.dost.gov.ph
Reuben Sumner rasumner@undergrad.math.uwaterloo.ca
Ricardo Marek ricky@ornet.co.il
Richard Deal deal@xi.cs.fsu.edu
Richard J. Kettlewell rjk@greenend.org.uk
Richard J. Kettlewell richard@elmail.co.uk
Richard Lloyd R.K.Lloyd@csc.liv.ac.uk
Richard O'Neill richard@nexus.vnus.bc.ca
Richard Sims rbs@acs.bu.edu
Richard Stallman rms@gnu.org
Richard Stallman rms@gnu.ai.mit.edu
Richard Westerik richardw@bssi.nl
Rick Emerson rick@ssg.com
Rob Parry rparry@hydrolab.arsusda.gov
@@ -405,7 +386,7 @@ Rod Buchanan rod.buchanan@kratos.co.uk
Rod Thompson rodt@synopsys.com
Roderich Schupp roderich@syntec.m.eunet.de
Rodney Brown RBrown@cocam.com.au
Roland McGrath roland@gnu.org
Roland McGrath roland@gnu.ai.mit.edu
Roland Schemers III schemers@vela.acs.oakland.edu
Rolf Niepraschk niepraschk@chbrb.berlin.ptb.de
Roman Gollent roman@portal.stwing.upenn.edu
@@ -430,9 +411,8 @@ Seth Robertson seth@ctr.columbia.edu
Sherwood Botsford sherwood@space.ualberta.ca
Simon Wright simon.j.wright@gecm.com
Sisira Jayasinghe sisira.jayasinghe@sdrc.com
Skip Montanaro skip@mojam.com http://www.musi-cal.com/~skip/
Skip Montanaro skip@automatrix.com
Simon Wright simon@pogner.demon.co.uk
Solar Designer solar@openwall.com
Stefan Skoglund sp2stes1@ida.his.se
Steffen Stempel stempel@ira.uka.de
Stephen Gildea gildea@intouchsys.com
@@ -441,12 +421,12 @@ Stephen Saroff saroff@msc.edu
Stuart Kemp skemp@bmc.com
Stuart Poulin stuart@indsys.com
Sven Verdoolaege skimo@breughel.ufsia.ac.be
Sylvain Rougier un@grolier.fr
Sylvain ROUGIER un@grolier.fr
Tarang Kumar Patel mombasa@ptolemy.arc.nasa.gov
Ted Rule Ted_Rule@flextech.co.uk
The King elvis@gnu.org
Thomas Bushnell n/BSG thomas@gnu.org
Thomas K<>nig Thomas.Koenig@ciw.uni-karlsruhe.de
The King elvis@gnu.ai.mit.edu
Thomas Bushnell n/BSG thomas@gnu.ai.mit.edu
Thomas K<>nig Thomas.Koenig@ciw.uni-karlsruhe.de
Thomas Krebs krebs@faps.uni-erlangen.de
Thomas M. Browder Jr. browder@use1.eglin.af.mil
Thomas Priesner priesner@flo.sh.bosch.de
@@ -469,34 +449,28 @@ Tom Tromey tromey@drip.colorado.edu
Tor Lillqvist tml@hemuli.tte.vtt.fi
Torbjorn Granlund tege@sics.se
Torkel Hasle torkel@bibsyst.no
Torsten Lull tlupi@gppc.de
Toshiaki Nishi toshi@sss.osa.sharp.co.jp
Travis L. Priest T.L.Priest@larc.nasa.gov
Troy Rudolph rudtr01@cai.com
Tsutomu Yamada tsutomu@sra.co.jp
Ulrich Drepper drepper@gnu.org
Ulrich Drepper drepper@gnu.ai.mit.edu
Van Snyder vsnyder@math.jpl.nasa.gov
Vic Abell abe@cc.purdue.edu
Victor J. Griswold vgris@aironet.com
Ville Herva v@iki.fi
Vince Del Vecchio vdelvecc@inmet.com
W. Phillip Moore wpm@morgan.com
Warner Losh imp@boulder.parcplace.com
Warren Dodge warrend@sptekwv3.wv.tek.com
Wayne Christopher wayne@icemcfd.com
Werner Almesberger werner.almesberger@lrc.di.epfl.ch
William Bader william@nscs.fast.net
William Bader wbader@pluto.csee.lehigh.edu
William J. Eaton wje@hoffman.rstnu.bcm.tmc.edu
William Kucharski kucharsk@netcom.com
Włodzimierz Jan Martin wjm@pg.gda.pl
Wojciech Polak polak@gnu.org
Wlodzimierz Jan Martin wjm@pg.gda.pl
Wolfgang Rupprecht wolfgang@wsrcc.com
Wolfram Gloger Wolfram.Gloger@dent.med.uni-muenchen.de
Wolfram Wagner ww@mpi-sb.mpg.de
Yasushi Suzudo SGR00413@niftyserve.or.jp
Yasushi Suzudo ysuzudo@mail.asiandevbank.org
Yu-Min Liang min@taz.ho.att.com
;;;; Local variables:
;;;; mode: Fundamental
;;;; buffer-file-coding-system: utf-8
;;;; End:
maximum entropy entropy@zippy.bernstein.com

79
TODO
View File

@@ -1,76 +1,5 @@
Suggestions for improving GNU tar.
From: Roesinger Eric <ROESINGE@tce.com>
Date: Sat, 28 Jul 2001 18:43:43 -0500
* Incorporate fixes from major distributions, e.g., Debian GNU/Linux.
* Add support for GNU private keywords in POSIX 1003.1-2001 headers,
so that the GNU extensions (--incremental, --label and
--multi-volume) may be used with POSIX archives.
* Add support for a 'pax' command that conforms to POSIX 1003.1-2001.
This would unify paxutils with tar.
* Remove command-line incompatibilities between GNU tar and UNIX tar
as specified by UNIX98. The main problem is:
l GNU tar doesn't cross filesystem boundaries.
UNIX98 tar warns if all links cannot be resolved.
(GNU tar --check-links option)
Perhaps we could announce a phase-in period where "l" changes in semantics.
In the meanwhile we could make the "l" semantics to be determined by the
value of POSIXLY_CORRECT variable.
* Interoperate better with Joerg Schilling's star implementation.
* Add an option to remove files that compare successfully.
From: Roesinger Eric <ROESINGE@tce.com>
Date: Sat, 28 Jul 2001 18:43:43 -0500
It would be useful to be able to use '--remove-files' with '--diff',
to remove all files that compare successfully, when verifying a backup.
* Add tests for testing the added functonality.
* Consider this:
From: Dennis Pund
Subject: TAR suggestion...
Date: Wed, 1 May 2002 18:26:36 -0500 (EST)
What I would like to do is:
foo my.tar.gz | tar -xzOf - | tar -cMf - -L 650000 - | bar
where 'foo' is a program that retrieves the archive and streams it
to stdout and bar is a program that streams the stdin to CDR.
(http://mail.gnu.org/archive/html/bug-gnu-utils/2002-05/msg00022.html)
* Copyright notice
Copyright (C) 2003 Free Software Foundation, Inc.
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 tar; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Local variables:
mode: outline
paragraph-separate: "[ ]*$"
end:
It would be useful to be able to use '--remove-files' with '--diff',
to remove all files that compare successfully, when verifying a backup.

239
bootstrap
View File

@@ -1,239 +0,0 @@
#! /bin/sh
# Bootstrap 'tar' from CVS.
# Copyright (C) 2003, 2004 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.
# Written by Paul Eggert.
# URL of our text domain page in Translation Project
TP_URL="http://www2.iro.umontreal.ca/~gnutra/po/maint/tar/"
usage() {
cat <<EOF
usage: $0 [--gnulib-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
Options are:
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
sources reside. Use this if you already
have gnulib sources on your machine, and
do not want to waste your bandwidth dowloading
them again.
--cvs-auth=METHOD Set the CVS access method used for downloading
gnulib files. METHOD is one of the keywords
accepted by cvs -d option (see info cvs
repository).
--cvs-user=USERNAME Set the CVS username to be used when accessing
the gnulib repository.
--no-po Do not download po files.
Running without arguments will suffice in most cases. It is equivalent
to
./bootstrap --cvs-auth=ext --cvs-user=anoncvs
EOF
}
# Parse options.
DOWNLOAD_PO=yes
for option
do
case $option in
--help)
usage
exit;;
--gnulib-srcdir=*)
GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
--cvs-auth=*)
CVS_AUTH=`expr "$option" : '--cvs-auth=\(.*\)'`;;
--cvs-user=*)
CVS_USER=`expr "$option" : '--cvs-user=\(.*\)'`;;
--no-po)
DOWNLOAD_PO=no;;
*)
echo >&2 "$0: $option: unknown option"
exit 1;;
esac
done
echo "$0: Bootstrapping CVS tar..."
build_cvs_prefix() {
CVS_PREFIX=:${1}:
if [ "${2}" != - ]; then
CVS_PREFIX=${CVS_PREFIX}${2}@
fi
if [ "$1" = "ext" ]; then
if [ -z "${CVS_RSH}" ]; then
CVS_RSH=ssh
export CVS_RSH
fi
fi
}
# Get gnulib files.
case ${GNULIB_SRCDIR--} in
-)
if [ ! -d gnulib ]; then
echo "$0: getting gnulib files..."
trap exit 1 2 13 15
trap 'rm -fr gnulib; exit 1' 0
case "${CVS_AUTH--}" in
-) build_cvs_prefix ext anoncvs;;
pserver) build_cvs_prefix $CVS_AUTH ${CVS_USER:-anoncvs};;
gserver|server)
build_cvs_prefix $CVS_AUTH ${CVS_USER--};;
ext) build_cvs_prefix $CVS_AUTH ${CVS_USER--};;
*) echo "$0: Unknown CVS access method" >&2
exit 1;;
esac
if [ "${CVS_AUTH--}" = "pserver" ]; then
cvs -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/gnulib login || exit
fi
cvs -q -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/gnulib co gnulib || exit
trap 0
fi
GNULIB_SRCDIR=gnulib
esac
<$GNULIB_SRCDIR/gnulib-tool || exit
gnulib_modules='
alloca
argmatch
backupfile
dirname
error
exclude
fileblocks
fnmatch-gnu
ftruncate
full-write
getdate
getline
getopt
gettext
gettime
hash
human
lchown
memset
modechange
obstack
quote
quotearg
rmdir
safe-read
save-cwd
savedir
stdbool
stpcpy
strtol
strtoul
timespec
unlocked-io
utime
xalloc
xgetcwd
xstrtoumax
'
previous_gnulib_modules=
while [ "$gnulib_modules" != "$previous_gnulib_modules" ]; do
previous_gnulib_modules=$gnulib_modules
gnulib_modules=`
(echo "$gnulib_modules"
for gnulib_module in $gnulib_modules; do
$GNULIB_SRCDIR/gnulib-tool --extract-dependencies $gnulib_module
done) | sort -u
`
done
gnulib_files=`
(for gnulib_module in $gnulib_modules; do
$GNULIB_SRCDIR/gnulib-tool --extract-filelist $gnulib_module
done) | sort -u
`
gnulib_dirs=`echo "$gnulib_files" | sed 's,/[^/]*$,,' | sort -u`
mkdir -p $gnulib_dirs || exit
for gnulib_file in $gnulib_files; do
dest=$gnulib_file
case $gnulib_file in
m4/codeset.m4) continue;;
m4/intdiv0.m4) continue;;
m4/inttypes-pri.m4) continue;;
m4/isc-posix.m4) continue;;
m4/lcmessage.m4) continue;;
m4/onceonly_2_57.m4) dest=m4/onceonly.m4;;
# These will be overwritten by autopoint, which still uses
# old jm_.* macro names, so we have to keep both copies.
m4/ulonglong.m4) dest=m4/ulonglong_gl.m4;;
m4/inttypes_h.m4) dest=m4/inttypes_h_gl.m4;;
m4/stdint_h.m4) dest=m4/stdint_h_gl.m4;;
m4/uintmax_t.m4) dest=m4/uintmax_t_gl.m4;;
esac
rm -f $dest &&
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
done
echo "$0: Creating m4/gnulib.m4"
(echo "# This file is generated automatically. Please, do not edit."
echo "#"
echo "AC_DEFUN([tar_GNULIB],["
for gnulib_module in $gnulib_modules; do
echo "# $gnulib_module"
$GNULIB_SRCDIR/gnulib-tool --extract-autoconf-snippet $gnulib_module
done | sed '/AM_GNU_GETTEXT/d'
echo "])") > ./m4/gnulib.m4
echo "$0: Creating lib/Makefile.am"
(cat lib/Makefile.tmpl
for gnulib_module in $gnulib_modules; do
echo "# $gnulib_module"
$GNULIB_SRCDIR/gnulib-tool --extract-automake-snippet $gnulib_module
done | sed 's/lib_SOURCES/libtar_a_SOURCES/g' ) > lib/Makefile.am
# Get translations.
if test "$DOWNLOAD_PO" = "yes"; then
echo "$0: getting translations into po..."
(cd po &&
rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'` &&
wget -nv -nd -r -l 1 -A .po -C off $TP_URL &&
ls *.po | sed 's/\.po$//' >LINGUAS
) || exit
fi
# Reconfigure, getting other files.
echo "$0: autoreconf --verbose --install --force ..."
autoreconf --verbose --install --force
echo "$0: done. Now you can run './configure'."

View File

@@ -1,53 +1,47 @@
# Configure template for GNU tar.
# Copyright (C) 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# Process this file with autoconf to produce a configure script.
# Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004 Free Software Foundation, Inc.
AC_INIT(src/tar.c)
AM_CONFIG_HEADER(config.h)
AC_PREREQ(2.12)
AM_INIT_AUTOMAKE(tar, 1.12)
AC_DEFINE(_GNU_SOURCE)
ALL_LINGUAS="de fr it ko nl no pl pt sl sv"
# 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.
AC_INIT([GNU tar], [1.14], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_HEADERS([config.h:config.hin])
AC_PREREQ([2.59])
AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2 dist-shar std-options])
gl_USE_SYSTEM_EXTENSIONS
fp_PROG_ECHO
test $fp_cv_prog_echo_nonl = no \
&& echo 2>&1 "WARNING: \`echo' not powerful enough for \`make check'"
AC_PROG_CC
AC_EXEEXT
AC_PROG_GCC_TRADITIONAL
AC_AIX
AC_MINIX
AC_PROG_RANLIB
AC_PROG_YACC
AC_SYS_LARGEFILE
AC_ISC_POSIX
AM_C_PROTOTYPES
AC_C_CONST
AC_C_INLINE
AC_CHECK_SIZEOF(unsigned long, 4)
AC_CHECK_SIZEOF(long long, 0)
AC_CHECK_HEADERS(fcntl.h linux/fd.h memory.h net/errno.h \
sgtty.h string.h \
sys/param.h sys/device.h sys/gentape.h \
sys/inet.h sys/io/trioctl.h \
sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
unistd.h)
AC_CHECK_HEADERS(fcntl.h limits.h linux/fd.h memory.h net/errno.h poll.h \
sgtty.h string.h stropts.h \
sys/buf.h sys/device.h sys/gentape.h sys/inet.h sys/io/trioctl.h sys/ioccom.h \
sys/mtio.h sys/param.h sys/tprintf.h sys/tape.h sys/time.h sys/timeb.h \
sys/wait.h unistd.h)
AC_CHECK_HEADERS([sys/buf.h], [], [],
[#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif])
# It seems that that many machines where <utime.h> seems to be
# broken just require something like -D_XXX_SOURCE, where XXX might
# be POSIX, POSIX_C, ALL, HPUX or whatever, depending on the machine.
AC_HEADER_SYS_WAIT
AM_STDBOOL_H
AC_CACHE_CHECK(for utime.h, tar_cv_header_utime_h,
[AC_TRY_COMPILE([
#include <sys/types.h>
#include <utime.h>], [struct utimbuf foo],
tar_cv_header_utime_h=yes, tar_cv_header_utime_h=no)])
test $tar_cv_header_utime_h = yes && AC_DEFINE(HAVE_UTIME_H)
if test $ac_cv_header_sys_mtio_h = yes; then
AC_CACHE_CHECK(for remote tape header files, tar_cv_header_rmt,
@@ -57,98 +51,103 @@ if test $ac_cv_header_sys_mtio_h = yes; then
#endif
#include <sys/socket.h>],
tar_cv_header_rmt=yes, tar_cv_header_rmt=no)])
test $tar_cv_header_rmt = yes && RMT='rmt$(EXEEXT)'
test $tar_cv_header_rmt = yes && RMT=rmt
AC_SUBST(RMT)
fi
AC_CACHE_CHECK(for getgrgid declaration, tar_cv_header_getgrgid,
[AC_EGREP_HEADER(getgrgid, grp.h,
tar_cv_header_getgrgid=yes, tar_cv_header_getgrgid=no)])
test $tar_cv_header_getgrgid = yes && AC_DEFINE(HAVE_GETGRGID)
AC_CACHE_CHECK(for getpwuid declaration, tar_cv_header_getpwuid,
[AC_EGREP_HEADER(getpwuid, pwd.h,
tar_cv_header_getpwuid=yes, tar_cv_header_getpwuid=no)])
test $tar_cv_header_getpwuid = yes && AC_DEFINE(HAVE_GETPWUID)
AC_CACHE_CHECK(which ioctl field to test for reversed bytes,
tar_cv_header_mtio_check_field,
[AC_EGREP_HEADER(mt_model, sys/mtio.h,
tar_cv_header_mtio_check_field=mt_model,
tar_cv_header_mtio_check_field=mt_type)])
AC_DEFINE_UNQUOTED(MTIO_CHECK_FIELD, $tar_cv_header_mtio_check_field,
[Define to mt_model (v.g., for DG/UX), else to mt_type.])
AC_DEFINE_UNQUOTED(MTIO_CHECK_FIELD, $tar_cv_header_mtio_check_field)
AC_HEADER_DIRENT
AC_HEADER_MAJOR
AC_HEADER_STAT
AC_HEADER_STDC
AC_HEADER_TIME
AC_STRUCT_ST_BLKSIZE
AC_STRUCT_ST_BLOCKS
AC_MSG_CHECKING([for st_fstype string in struct stat])
AC_CACHE_VAL(diff_cv_st_fstype_string,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/stat.h>], [struct stat s; s.st_fstype[0] = 'x';],
diff_cv_st_fstype_string=yes,
diff_cv_st_fstype_string=no)])
AC_MSG_RESULT($diff_cv_st_fstype_string)
if test $diff_cv_st_fstype_string = yes; then
AC_DEFINE(HAVE_ST_FSTYPE_STRING, 1,
[Define if struct stat has a char st_fstype[] member.])
fi
AC_TYPE_SIGNAL
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_UID_T
AC_CHECK_TYPE(major_t, , AC_DEFINE(major_t, int,
[Type of major device numbers.]))
AC_CHECK_TYPE(minor_t, , AC_DEFINE(minor_t, int,
[Type of minor device numbers.]))
AC_CHECK_TYPE(dev_t, unsigned)
AC_CHECK_TYPE(ino_t, unsigned)
gt_TYPE_SSIZE_T
gl_AC_TYPE_INTMAX_T
jm_AC_TYPE_UINTMAX_T
AC_CHECK_FUNCS(fsync ftime getcwd isascii lchown mkfifo nap napms poll \
select strerror strstr usleep)
# gnulib modules
tar_GNULIB
AC_CHECK_MEMBERS([struct stat.st_spare1, struct stat.st_atim.tv_nsec, struct stat.st_atimespec.tv_nsec, struct stat.st_atimensec], , ,
[
AC_CACHE_CHECK(for mknod, tar_cv_func_mknod,
[AC_TRY_LINK([
#include <sys/types.h>
#include <sys/stat.h>])
#include <sys/stat.h>],
[mknod (0, 0, 0)],
tar_cv_func_mknod=yes, tar_cv_func_mknod=no)])
test $tar_cv_func_mknod = yes && AC_DEFINE(HAVE_MKNOD)
# Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
# programs in the package would end up linked with that potentially-shared
# library, inducing unnecessary run-time overhead.
# Whenever both -lsocket and -lnsl are needed, it seems to be always the
# case that gethostbyname requires -lnsl. So, check -lnsl first, for it
# to be in LIBS before the setsockopt checks are performed. *However*,
# on SINIX-N 5.43, this is false, and gethostent seems to be a better
# candidate. So, let's use it below instead of gethostbyname, and see.
# Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
# Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
tar_save_LIBS=$LIBS
LIB_CLOCK_GETTIME=
AC_SEARCH_LIBS(clock_gettime, [rt posix4])
case "$ac_cv_search_clock_gettime" in
-l*) LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime;;
esac
AC_SUBST(LIB_CLOCK_GETTIME)
AC_CHECK_FUNCS(clock_gettime)
LIBS=$tar_save_LIBS
AC_CHECK_FUNC(gethostent)
if test $ac_cv_func_gethostent = no; then
AC_CHECK_LIB(nsl, gethostent)
fi
AC_CHECK_FUNC(setsockopt)
if test $ac_cv_func_setsockopt = no; then
AC_CHECK_LIB(socket, setsockopt)
fi
AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
AC_CHECK_DECLS([valloc])
AC_CHECK_DECLS([time],,, [#include <time.h>])
AC_FUNC_ALLOCA
AC_FUNC_FNMATCH
test $ac_cv_func_fnmatch_works = yes || LIBOBJS="$LIBOBJS fnmatch.o"
AC_FUNC_VPRINTF
AC_REPLACE_FUNCS(basename dirname execlp ftruncate memset mkdir rename rmdir)
test "$ac_cv_func_strstr" = yes || LIBOBJS="$LIBOBJS strstr.o"
# Set LIB_SETSOCKOPT to -lnsl -lsocket if necessary.
tar_save_LIBS=$LIBS
LIB_SETSOCKOPT=
AC_SEARCH_LIBS(setsockopt, [socket], ,
[AC_SEARCH_LIBS(setsockopt, [socket], , , [-lnsl])])
AC_SEARCH_LIBS(setsockopt, [nsl])
# The 3-argument open happens to go along with the O_* defines, which
# are easier to check for.
case "$ac_cv_search_setsockopt" in
-l*) LIB_SETSOCKOPT=$ac_cv_search_setsockopt
esac
AC_SUBST(LIB_SETSOCKOPT)
LIBS=$tar_save_LIBS
AC_CACHE_CHECK(for 3-argument open, tar_cv_func_open3,
[AC_TRY_COMPILE([
#if HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif],
[int x = O_RDONLY],
tar_cv_func_open3=yes, tar_cv_func_open3=no)])
if test $tar_cv_func_open3 = no; then
AC_DEFINE(EMUL_OPEN3)
fi
AC_REPLACE_FUNCS(waitpid)
# `union wait' is preferrably avoided. We merely assume below
# that if `int pid;' fails, `union wait pid;' would have worked.
# Directly trying `union wait pid;' is seeking for trouble, as
# some POSIX systems are offering compatibility hacks generating
# ugly diagnostics. Also, on some systems, WEXITSTATUS exists,
# but fails when called on `union wait' variables.
AC_CACHE_CHECK(for union wait, tar_cv_header_union_wait,
[AC_TRY_COMPILE([
#include <sys/types.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif],
[int status; int pid; pid = wait (&status);],
tar_cv_header_union_wait=no, tar_cv_header_union_wait=yes)])
test $tar_cv_header_union_wait = yes && AC_DEFINE(HAVE_UNION_WAIT)
AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
[if test -n "$RSH"; then
@@ -156,48 +155,22 @@ AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
else
tar_cv_path_RSH=no
for ac_file in /usr/ucb/rsh /usr/bin/remsh /usr/bin/rsh /usr/bsd/rsh \
/usr/bin/nsh /usr/bin/rcmd
/usr/bin/nsh /usr/bin/rcmd
do
# Prefer a non-symlink rsh to a symlink one, so that binaries built
# on AIX 4.1.4, where /usr/ucb/rsh is a symlink to /usr/bin/rsh
# will run on AIX 4.3.0, which has only /usr/bin/rsh.
if test -f $ac_file; then
if (test -h $ac_file) 2>/dev/null; then
test $tar_cv_path_RSH = no && tar_cv_path_RSH=$ac_file
else
tar_cv_path_RSH=$ac_file
break
fi
tar_cv_path_RSH=$ac_file
break
fi
done
fi])
if test $tar_cv_path_RSH = no; then
AC_CHECK_HEADERS(netdb.h)
else
AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH",
[Define to the full path of your rsh, if any.])
AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH")
fi
AC_MSG_CHECKING(for default archive format)
AC_ARG_VAR([DEFAULT_ARCHIVE_FORMAT],
[Set the default archive format. Allowed values are: V7, OLDGNU, USTAR, POSIX, GNU. Default is GNU])
if test -z "$DEFAULT_ARCHIVE_FORMAT"; then
DEFAULT_ARCHIVE_FORMAT="GNU"
fi
case $DEFAULT_ARCHIVE_FORMAT in
V7|OLDGNU|USTAR|POSIX|GNU) ;;
*) AC_MSG_ERROR(Invalid format name);;
esac
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE_FORMAT, ${DEFAULT_ARCHIVE_FORMAT}_FORMAT,
[By default produce archives of this format])
AC_MSG_RESULT($DEFAULT_ARCHIVE_FORMAT)
AC_MSG_CHECKING(for default archive)
AC_ARG_VAR([DEFAULT_ARCHIVE],
[Set the name of the default archive (default: -)])
if test -z "$DEFAULT_ARCHIVE"; then
DEFAULT_ARCHIVE=-
else
@@ -208,84 +181,35 @@ else
# FIXME: Let DEVICE_PREFIX be configured from the environment.
# FIXME: Rearrange, here.
case $DEFAULT_ARCHIVE in
*[[0-7][lmh]])
AC_DEFINE(DENSITY_LETTER, 1,
[[Define to 1 if density may be indicated by [lmh] at end of device.]])
changequote(, )dnl
*[0-7][lmh])
device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7][lmh]$//'`
changequote([, ])dnl
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix")
AC_DEFINE(DENSITY_LETTER)
;;
*[[0-7]])
changequote(, )dnl
*[0-7])
device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7]$//'`
;;
*)
device_prefix=
;;
esac
case "$device_prefix" in
?*)
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix",
[Define to a string giving the prefix of the default device, without the part specifying the unit and density.])
changequote([, ])dnl
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix")
;;
esac
fi
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE, "$DEFAULT_ARCHIVE",
[Define to a string giving the full name of the default archive file.])
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE, "$DEFAULT_ARCHIVE")
AC_MSG_RESULT($DEFAULT_ARCHIVE)
AC_ARG_VAR([DEFAULT_BLOCKING],
[Define default blocking factor (default: 20)])
AC_MSG_CHECKING(for default blocking)
DEFAULT_BLOCKING=${DEFAULT_BLOCKING-20}
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING,
[Define to a number giving the default blocking size for archives.])
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING)
AC_MSG_RESULT($DEFAULT_BLOCKING)
AC_ARG_VAR([DEFAULT_RMT_COMMAND],
[Define full pathname of rmt program.])
if test "x$DEFAULT_RMT_COMMAND" != x; then
AC_DEFINE_UNQUOTED(DEFAULT_RMT_COMMAND, "$DEFAULT_RMT_COMMAND",
[Define full pathname of rmt program.])
fi
fp_WITH_INCLUDED_MALLOC
AM_WITH_DMALLOC
# Gettext.
AM_GNU_GETTEXT([external], [need-ngettext])
AM_GNU_GETTEXT_VERSION(0.12.1)
AM_GNU_GETTEXT
AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
# Iconv
AM_ICONV
AC_CHECK_HEADERS(iconv.h)
AC_CHECK_TYPE(iconv_t,:,
AC_DEFINE(iconv_t, int,
[Conversion descriptor type]),
[
#ifdef HAVE_ICONV_H
# include <iconv.h>
#endif
])
AC_SUBST(BACKUP_LIBEXEC_SCRIPTS)
AC_SUBST(BACKUP_SBIN_SCRIPTS)
AC_ARG_ENABLE(backup-scripts,
AC_HELP_STRING([--enable-backup-scripts],
[Create and install backup and restore scripts]),
[case $enableval in
yes) BACKUP_LIBEXEC_SCRIPTS='$(BACKUP_LIBEXEC_SCRIPTS_LIST)'
BACKUP_SBIN_SCRIPTS='$(BACKUP_SBIN_SCRIPTS_LIST)'
;;
esac])
AC_SUBST(BACKUP_SED_COND)
if date +%Y-%m-%d 2>/dev/null >&2; then
BACKUP_SED_COND='/^\#ELSE_DATE_FORMAT_OK/,/^\#ENDIF_DATE_FORMAT_OK/d;/^\#IF_DATE_FORMAT_OK/d'
else
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
fi
AC_OUTPUT([Makefile\
doc/Makefile\
lib/Makefile\
po/Makefile.in\
scripts/Makefile\
src/Makefile\
tests/Makefile\
tests/preset])
AC_OUTPUT([Makefile doc/Makefile intl/Makefile lib/Makefile po/Makefile.in \
scripts/Makefile src/Makefile tests/Makefile tests/preset],
[sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile])

View File

@@ -1,29 +0,0 @@
Makefile.in
Makefile
header.texi
tar.info
version.texi
stamp-vti
tar.html
tar.log
tar.dvi
tar.aux
tar.toc
tar.cp
tar.fn
tar.vr
tar.tp
tar.ky
tar.pg
tar.ps
tar.cps
tar.fns
tar.pgs
tar.vrs
tar.at
tar.kw
tar.ex
tar.ats
tar.exs
tar.kws
tmp-tar.*

View File

@@ -1,25 +1,24 @@
# Makefile for GNU tar documentation.
# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 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 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.
## 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.
# 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.
AUTOMAKE_OPTIONS = gnits
info_TEXINFOS = tar.texi
EXTRA_DIST = convtexi.pl fdl.texi freemanuals.texi getdate.texi header.texi
EXTRA_DIST = convtexi.pl getdate.texi header.texi
CLEANFILES = tmp-*
@@ -27,11 +26,16 @@ CLEANFILES = tmp-*
# Just call `make dvi RENDITION=PROOF' if you want PROOF rendition.
RENDITION = DISTRIB
$(srcdir)/tar.info: tar.texi fdl.texi freemanuals.texi getdate.texi \
$(srcdir)/header.texi version.texi
$(MAKEINFO) --no-split -D$(RENDITION) -I$(srcdir) tar.texi -o $@
tar.info: tar.texi getdate.texi header.texi version.texi
@echo "WARNING: \`makeinfo' will not preprocess Texinfo input properly"
@echo " for expanding Texinfo macros, if it comes from a"
@echo " Texinfo distribution which is earlier than version 3.7."
cd $(srcdir) && $(MAKEINFO) -D$(RENDITION) tar.texi
tar.dvi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
tar.dvi: tar.texi getdate.texi header.texi version.texi
@echo "WARNING: \`makeinfo' will not preprocess Texinfo input properly"
@echo " for expanding Texinfo macros, if it comes from a"
@echo " Texinfo distribution which is earlier than version 3.7."
$(MAKEINFO) -D$(RENDITION) -Etmp-tar.tmp -otmp-tar.info \
-I$(srcdir) tar.texi
rm -f tmp-tar.sed tmp-tar.info*
@@ -41,11 +45,9 @@ tar.dvi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
|| echo >>tmp-tar.sed '/^@smallbook/d'
sed -f tmp-tar.sed tmp-tar.tmp > tmp-tar.texi
rm -f tmp-tar.sed tmp-tar.tmp
TEXINPUTS=$(top_srcdir)/config:$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2DVI) tmp-tar.texi
TEXINPUTS=$(srcdir):$$TEXINPUTS $(TEXI2DVI) tmp-tar.texi
mv tmp-tar.dvi $@
$(srcdir)/header.texi: $(top_srcdir)/src/tar.h
header.texi: $(top_srcdir)/src/tar.h
sed -n '/Archive Format/,/End of Format/p' $(top_srcdir)/src/tar.h \
| expand | sed 's/\([{}]\)/@\1/g' >$@
| expand | sed 's/\([{}]\)/@\1/g' > $(srcdir)/header.texi

View File

@@ -3,24 +3,8 @@ eval "exec /usr/local/bin/perl -S $0 $*"
if 0;
# Copy a Texinfo file, replacing @value's, @FIXME's and other gooddies.
# Copyright (C) 1996, 2001 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.
# François Pinard <pinard@iro.umontreal.ca>, 1996.
# Copyright <20> 1996 Free Software Foundation, Inc.
# Fran<EFBFBD>ois Pinard <pinard@iro.umontreal.ca>, 1996.
$_ = <>;
while ($_)

View File

@@ -1,452 +0,0 @@
@node GNU Free Documentation License
@appendixsec GNU Free Documentation License
@cindex FDL, GNU Free Documentation License
@center Version 1.2, November 2002
@display
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@end display
@enumerate 0
@item
PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document @dfn{free} in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of ``copyleft'', which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
@item
APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The ``Document'', below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as ``you''. You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A ``Modified Version'' of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A ``Secondary Section'' is a named appendix or a front-matter section
of the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall
subject (or to related matters) and contains nothing that could fall
directly within that overall subject. (Thus, if the Document is in
part a textbook of mathematics, a Secondary Section may not explain
any mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The ``Invariant Sections'' are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The ``Cover Texts'' are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A ``Transparent'' copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not ``Transparent'' is called ``Opaque''.
Examples of suitable formats for Transparent copies include plain
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
format, @acronym{SGML} or @acronym{XML} using a publicly available
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
PostScript or @acronym{PDF} designed for human modification. Examples
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
@acronym{JPG}. Opaque formats include proprietary formats that can be
read and edited only by proprietary word processors, @acronym{SGML} or
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
not generally available, and the machine-generated @acronym{HTML},
PostScript or @acronym{PDF} produced by some word processors for
output purposes only.
The ``Title Page'' means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, ``Title Page'' means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section ``Entitled XYZ'' means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as ``Acknowledgements'',
``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
of such a section when you modify the Document means that it remains a
section ``Entitled XYZ'' according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
@item
VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
@item
COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
@item
MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
@enumerate A
@item
Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
@item
List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
@item
State on the Title page the name of the publisher of the
Modified Version, as the publisher.
@item
Preserve all the copyright notices of the Document.
@item
Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
@item
Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
@item
Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
@item
Include an unaltered copy of this License.
@item
Preserve the section Entitled ``History'', Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled ``History'' in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
@item
Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the ``History'' section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
@item
For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
the Title of the section, and preserve in the section all the
substance and tone of each of the contributor acknowledgements and/or
dedications given therein.
@item
Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
@item
Delete any section Entitled ``Endorsements''. Such a section
may not be included in the Modified Version.
@item
Do not retitle any existing section to be Entitled ``Endorsements'' or
to conflict in title with any Invariant Section.
@item
Preserve any Warranty Disclaimers.
@end enumerate
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled ``Endorsements'', provided it contains
nothing but endorsements of your Modified Version by various
parties---for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
@item
COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled ``History''
in the various original documents, forming one section Entitled
``History''; likewise combine any sections Entitled ``Acknowledgements'',
and any sections Entitled ``Dedications''. You must delete all
sections Entitled ``Endorsements.''
@item
COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
@item
AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an ``aggregate'' if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
@item
TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled ``Acknowledgements'',
``Dedications'', or ``History'', the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
@item
TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document 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.
@item
FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation 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. See
@uref{http://www.gnu.org/copyleft/}.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License ``or any later version'' applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
@end enumerate
@page
@appendixsubsec ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
@smallexample
@group
Copyright (C) @var{year} @var{your name}.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
@end group
@end smallexample
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the ``with...Texts.'' line with this:
@smallexample
@group
with the Invariant Sections being @var{list their titles}, with
the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
being @var{list}.
@end group
@end smallexample
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.
@c Local Variables:
@c ispell-local-pdict: "ispell-dict"
@c End:

View File

@@ -1,20 +1,19 @@
@c GNU date syntax documentation
@c Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@c 2003, 2004 Free Software Foundation, Inc.
@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.1 or
@c any later version published by the Free Software Foundation; with no
@c Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
@c Texts. A copy of the license is included in the ``GNU Free
@c Documentation License'' file as part of this distribution.
@node Date input formats
@chapter Date input formats
@c Copyright 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
@c Foundation, Inc.
@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.1
@c or any later version published by the Free Software Foundation;
@c with no Invariant Sections, with no
@c Front-Cover Texts, and with no Back-Cover Texts.
@c A copy of the license is included in the section entitled ``GNU
@c Free Documentation License''.
@cindex date input formats
@findex get_date
@findex getdate
First, a quote:
@@ -45,7 +44,19 @@ or a week from Sunday, with feelings of helpless confusion. @dots{}
This section describes the textual date representations that @sc{gnu}
programs accept. These are the strings you, as a user, can supply as
arguments to the various programs. The C interface (via the
@code{get_date} function) is not described here.
@code{getdate} function) is not described here.
@cindex beginning of time, for @sc{posix}
@cindex epoch, for @sc{posix}
Although the date syntax here can represent any possible time since the
year zero, computer integers often cannot represent such a wide range of
time. On @sc{posix} systems, the clock starts at 1970-01-01 00:00:00
@sc{utc}: @sc{posix} does not require support for times before the
@sc{posix} Epoch and times far in the future. Traditional Unix systems
have 32-bit signed @code{time_t} and can represent times from 1901-12-13
20:45:52 through 2038-01-19 03:14:07 @sc{utc}. Systems with 64-bit
signed @code{time_t} can represent all the times in the known
lifetime of the universe.
@menu
* General date syntax:: Common rules.
@@ -55,8 +66,7 @@ arguments to the various programs. The C interface (via the
* Day of week items:: Monday and others.
* Relative items in date strings:: next tuesday, 2 years ago.
* Pure numbers in date strings:: 19931219, 1440.
* Seconds since the Epoch:: @@1078100502.
* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al.
* Authors of getdate:: Bellovin, Eggert, Salz, Berets, et al.
@end menu
@@ -118,17 +128,15 @@ ways to do this:
@example
$ LC_ALL=C TZ=UTC0 date
Mon Mar 1 00:21:42 UTC 2004
$ TZ=UTC0 date +'%Y-%m-%d %H:%M:%SZ'
2004-03-01 00:21:42Z
$ date --iso-8601=ns # a GNU extension
2004-02-29T16:21:42,692722128-0800
$ date --rfc-2822 # a GNU extension
Sun, 29 Feb 2004 16:21:42 -0800
$ date +'%Y-%m-%d %H:%M:%S %z' # %z is a GNU extension.
2004-02-29 16:21:42 -0800
$ date +'@@%s.%N' # %s and %N are GNU extensions.
@@1078100502.692722128
Fri Dec 15 19:48:05 UTC 2000
$ TZ=UTC0 date +"%Y-%m-%d %H:%M:%SZ"
2000-12-15 19:48:05Z
$ date --iso-8601=seconds # a GNU extension
2000-12-15T11:48:05-0800
$ date --rfc-822 # a GNU extension
Fri, 15 Dec 2000 11:48:05 -0800
$ date +"%Y-%m-%d %H:%M:%S %z" # %z is a GNU extension.
2000-12-15 11:48:05 -0800
@end example
@cindex case, ignored in dates
@@ -219,7 +227,7 @@ A @dfn{time of day item} in date strings specifies the time on a given
day. Here are some examples, all of which represent the same time:
@example
20:02:00.000000
20:02:0
20:02
8:02pm
20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
@@ -228,9 +236,7 @@ day. Here are some examples, all of which represent the same time:
More generally, the time of the day may be given as
@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
a number between 0 and 23, @var{minute} is a number between 0 and
59, and @var{second} is a number between 0 and 59 possibly followed by
@samp{.} or @samp{,} and a fraction containing one or more digits.
Alternatively,
59, and @var{second} is a number between 0 and 59. Alternatively,
@samp{:@var{second}} can be omitted, in which case it is taken to
be zero.
@@ -375,26 +381,6 @@ When a relative item causes the resulting date to cross a boundary
where the clocks were adjusted, typically for daylight-saving time,
the resulting date and time are adjusted accordingly.
The fuzz in units can cause problems with relative items. For
example, @samp{2003-07-31 -1 month} might evaluate to 2003-07-01,
because 2003-06-31 is an invalid date. To determine the previous
month more reliably, you can ask for the month before the 15th of the
current month. For example:
@example
$ date -R
Thu, 31 Jul 2003 13:02:39 -0700
$ date --date='-1 month' +'Last month was %B?'
Last month was July?
$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
Last month was June!
@end example
Also, take care when manipulating dates around clock changes such as
daylight saving leaps. In a few cases these have added or subtracted
as much as 24 hours from the clock, so it is often wise to adopt
universal time by setting the @env{TZ} environment variable to
@samp{UTC0} before embarking on calendrical calculations.
@node Pure numbers in date strings
@section Pure numbers in date strings
@@ -420,42 +406,10 @@ in the date string, but no relative item, then the number overrides the
year.
@node Seconds since the Epoch
@section Seconds since the Epoch
@node Authors of getdate
@section Authors of @code{getdate}
If you precede a number with @samp{@@}, it represents an internal time
stamp as a count of seconds. The number can contain an internal
decimal point (either @samp{.} or @samp{,}); any excess precision not
supported by the internal representation is truncated toward minus
infinity.
@cindex beginning of time, for @acronym{POSIX}
@cindex epoch, for @acronym{POSIX}
Internally, computer times are represented as a count of seconds since
an epoch---a well-defined point of time. On @acronym{GNU} and
@acronym{POSIX} systems, the epoch is 1970-01-01 00:00:00 @sc{utc}, so
@samp{@@0} represents this time, @samp{@@1} represents 1970-01-01
00:00:01 @sc{utc}, and so forth. @acronym{GNU} and most other
@acronym{POSIX}-compliant systems support such times as an extension
to @acronym{POSIX}, using negative counts, so that @samp{@@-1}
represents 1969-12-31 23:59:59 @sc{utc}.
Traditional Unix systems count seconds with 32-bit two's-complement
integers and can represent times from 1901-12-13 20:45:52 through
2038-01-19 03:14:07 @sc{utc}. More modern systems use 64-bit counts
of seconds with nanosecond subcounts, and can represent all the times
in the known lifetime of the universe to a resolution of 1 nanosecond.
On most systems, these counts ignore the presence of leap seconds.
For example, on most systems @samp{@@915148799} represents 1998-12-31
23:59:59 @sc{utc}, @samp{@@915148800} represents 1999-01-01 00:00:00
@sc{utc}, and there is no way to represent the intervening leap second
1998-12-31 23:59:60 @sc{utc}.
@node Authors of get_date
@section Authors of @code{get_date}
@cindex authors of @code{get_date}
@cindex authors of @code{getdate}
@cindex Bellovin, Steven M.
@cindex Salz, Rich
@@ -463,7 +417,7 @@ For example, on most systems @samp{@@915148799} represents 1998-12-31
@cindex MacKenzie, David
@cindex Meyering, Jim
@cindex Eggert, Paul
@code{get_date} was originally implemented by Steven M. Bellovin
@code{getdate} was originally implemented by Steven M. Bellovin
(@email{smb@@research.att.com}) while at the University of North Carolina
at Chapel Hill. The code was later tweaked by a couple of people on
Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})

File diff suppressed because it is too large Load Diff

View File

@@ -1,100 +0,0 @@
.deps
Makefile
Makefile.am
Makefile.in
addext.c
alloca.c
alloca.h
alloca_.h
argmatch.c
argmatch.h
backupfile.c
backupfile.h
basename.c
chown.c
dirname.c
dirname.h
error.c
error.h
exclude.c
exclude.h
exit.h
exitfail.c
exitfail.h
fileblocks.c
fnmatch.c
fnmatch_.h
fnmatch_loop.c
ftruncate.c
full-write.c
full-write.h
getdate.c
getdate.h
getdate.y
getline.c
getline.h
getndelim2.c
getndelim2.h
getopt.c
getopt.h
getopt1.c
getopt_int.h
gettext.h
gettime.c
gettimeofday.c
hash.c
hash.h
human.c
human.h
lchown.c
lchown.h
malloc.c
memset.c
mktime.c
modechange.c
modechange.h
obstack.c
obstack.h
pathmax.h
quote.c
quote.h
quotearg.c
quotearg.h
realloc.c
rmdir.c
safe-read.c
safe-read.h
safe-write.c
safe-write.h
save-cwd.c
save-cwd.h
savedir.c
savedir.h
stdbool.h
stdbool_.h
stpcpy.c
stpcpy.h
strcase.h
strcasecmp.c
stripslash.c
strncasecmp.c
strtoimax.c
strtol.c
strtoll.c
strtoul.c
strtoull.c
strtoumax.c
time_r.c
time_r.h
timespec.h
unlocked-io.h
utime.c
xalloc.h
xgetcwd.c
xgetcwd.h
xmalloc.c
xstrdup.c
xstrtol.c
xstrtol.h
xstrtoul.c
xstrtoumax.c

45
lib/Makefile.am Normal file
View File

@@ -0,0 +1,45 @@
# Makefile for GNU tar library.
# Copyright (C) 1994, 1995, 1996, 1997 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.
AUTOMAKE_OPTIONS = gnits
noinst_LIBRARIES = libtar.a
EXTRA_DIST = \
alloca.c fileblocks.c fnmatch.c ftruncate.c execlp.c gmalloc.c \
memset.c mkdir.c modechange.h rename.c rmdir.c stpcpy.c strstr.c
noinst_HEADERS = \
argmatch.h backupfile.h error.h fnmatch.h getopt.h getdate.h getpagesize.h \
pathmax.h
libtar_a_SOURCES = \
argmatch.c backupfile.c error.c getdate.y getopt.c getopt1.c getversion.c \
modechange.c msleep.c xgetcwd.c xmalloc.c xstrdup.c
INCLUDES = -I.. -I$(srcdir) -I../intl
libtar_a_LIBADD = @ALLOCA@ @LIBOBJS@
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule.
$(srcdir)/getdate.c: getdate.y
@echo Expect 13 shift/reduce conflicts...
cd $(srcdir) && \
$(YACC) $(YFLAGS) getdate.y; \
mv -f y.tab.c getdate.c

View File

@@ -1,43 +0,0 @@
# Makefile for GNU tar library.
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004
# 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.
noinst_LIBRARIES = libtar.a
libtar_a_SOURCES = prepargs.c prepargs.h
libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
BUILT_SOURCES =
EXTRA_DIST = Makefile.tmpl
MAINTAINERCLEANFILES =
MOSTLYCLEANFILES =
lib_OBJECTS = $(libtar_a_OBJECTS)
# Special rule for getdate
#
# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule.
$(srcdir)/getdate.c: getdate.y
cd $(srcdir) && \
$(YACC) $(YFLAGS) getdate.y && \
mv -f y.tab.c getdate.c
# gnulib modules

View File

@@ -33,15 +33,7 @@
#endif
#ifdef emacs
# include "lisp.h"
# include "blockinput.h"
# define xalloc_die() memory_full ()
# ifdef EMACS_FREE
# undef free
# define free EMACS_FREE
# endif
#else
# include <xalloc.h>
#endif
/* If compiling with GCC 2, this file's not needed. */
@@ -61,8 +53,6 @@
you
lose
-- must know STACK_DIRECTION at compile-time
/* Using #error here is not wise since this file should work for
old and obscure compilers. */
# endif /* STACK_DIRECTION undefined */
# endif /* static */
# endif /* emacs */
@@ -77,19 +67,32 @@ long i00afunc ();
# define ADDRESS_FUNCTION(arg) &(arg)
# endif
# ifndef POINTER_TYPE
# ifdef __STDC__
# define POINTER_TYPE void
# else
# define POINTER_TYPE char
# endif
# if __STDC__
typedef void *pointer;
# else
typedef char *pointer;
# endif
typedef POINTER_TYPE *pointer;
# ifndef NULL
# define NULL 0
# endif
/* Different portions of Emacs need to call different versions of
malloc. The Emacs executable needs alloca to call xmalloc, because
ordinary malloc isn't protected from input signals. On the other
hand, the utilities in lib-src need alloca to call malloc; some of
them are very simple, and don't have an xmalloc routine.
Non-Emacs programs expect this to call xmalloc.
Callers below should use malloc. */
# ifndef emacs
# undef malloc
# define malloc xmalloc
# endif
extern pointer malloc ();
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
@@ -166,8 +169,7 @@ static header *last_alloca_header = NULL; /* -> last alloca header. */
implementations of C, for example under Gould's UTX/32. */
pointer
alloca (size)
size_t size;
alloca (size_t size)
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION (probe);
@@ -213,14 +215,8 @@ alloca (size)
/* Allocate combined header + user data storage. */
{
register pointer new = malloc (sizeof (header) + size);
/* Address of header. */
register pointer new;
size_t combined_size = sizeof (header) + size;
if (combined_size < sizeof (header))
xalloc_die ();
new = xmalloc (combined_size);
if (new == 0)
abort();

View File

@@ -1,7 +1,5 @@
/* argmatch.c -- find a match for a string in an array
Copyright (C) 1990, 1998, 1999, 2001, 2002, 2003 Free Software
Foundation, Inc.
Copyright (C) 1990, 1998, 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
@@ -20,33 +18,39 @@
/* Written by David MacKenzie <djm@ai.mit.edu>
Modified by Akim Demaille <demaille@inf.enst.fr> */
#if HAVE_CONFIG_H
# include <config.h>
#endif
/* Specification. */
#include "argmatch.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef STDC_HEADERS
# include <string.h>
#endif
#include "gettext.h"
#define _(msgid) gettext (msgid)
#if HAVE_LOCALE_H
# include <locale.h>
#endif
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
#else
# define _(Text) Text
#endif
#include "error.h"
#include "quotearg.h"
#include "quote.h"
#include "unlocked-io.h"
/* When reporting an invalid argument, show nonprinting characters
by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
literal_quoting_style. */
#ifndef ARGMATCH_QUOTING_STYLE
# define ARGMATCH_QUOTING_STYLE locale_quoting_style
# define ARGMATCH_QUOTING_STYLE escape_quoting_style
#endif
#ifndef EXIT_FAILURE
/* The following test is to work around the gross typo in
systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
is defined to 0, not 1. */
#if !EXIT_FAILURE
# undef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
@@ -74,6 +78,7 @@ argmatch_exit_fn argmatch_die = __argmatch_die;
null-terminated array ARGLIST, return the index in ARGLIST
of the matched element, else -1 if it does not match any element
or -2 if it is ambiguous (is a prefix of more than one element).
If SENSITIVE, comparison is case sensitive.
If VALLIST is none null, use it to resolve ambiguities limited to
synonyms, i.e., for
@@ -81,9 +86,10 @@ argmatch_exit_fn argmatch_die = __argmatch_die;
"no", "nope" -> 1
"y" is a valid argument, for `0', and "n" for `1'. */
int
argmatch (const char *arg, const char *const *arglist,
const char *vallist, size_t valsize)
static int
__argmatch_internal (const char *arg, const char *const *arglist,
const char *vallist, size_t valsize,
int case_sensitive)
{
int i; /* Temporary index in ARGLIST. */
size_t arglen; /* Length of ARG. */
@@ -95,7 +101,9 @@ argmatch (const char *arg, const char *const *arglist,
/* Test all elements for either exact match or abbreviated matches. */
for (i = 0; arglist[i]; i++)
{
if (!strncmp (arglist[i], arg, arglen))
if (case_sensitive
? !strncmp (arglist[i], arg, arglen)
: !strncasecmp (arglist[i], arg, arglen))
{
if (strlen (arglist[i]) == arglen)
/* Exact match found. */
@@ -123,6 +131,22 @@ argmatch (const char *arg, const char *const *arglist,
return matchind;
}
/* argmatch - case sensitive version */
int
argmatch (const char *arg, const char *const *arglist,
const char *vallist, size_t valsize)
{
return __argmatch_internal (arg, arglist, vallist, valsize, 1);
}
/* argcasematch - case insensitive version */
int
argcasematch (const char *arg, const char *const *arglist,
const char *vallist, size_t valsize)
{
return __argmatch_internal (arg, arglist, vallist, valsize, 0);
}
/* Error reporting for argmatch.
CONTEXT is a description of the type of entity that was being matched.
VALUE is the invalid value that was given.
@@ -131,12 +155,21 @@ argmatch (const char *arg, const char *const *arglist,
void
argmatch_invalid (const char *context, const char *value, int problem)
{
char const *format = (problem == -1
? _("invalid argument %s for %s")
: _("ambiguous argument %s for %s"));
enum quoting_style saved_quoting_style;
char const *format;
error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
quote_n (1, context));
/* Make sure to have a good quoting style to report errors.
literal is insane here. */
saved_quoting_style = get_quoting_style (NULL);
set_quoting_style (NULL, ARGMATCH_QUOTING_STYLE);
format = (problem == -1
? _("invalid argument `%s' for `%s'")
: _("ambiguous argument `%s' for `%s'"));
error (0, 0, format, quotearg (value), context);
set_quoting_style (NULL, saved_quoting_style);
}
/* List the valid arguments for argmatch.
@@ -177,9 +210,12 @@ int
__xargmatch_internal (const char *context,
const char *arg, const char *const *arglist,
const char *vallist, size_t valsize,
int case_sensitive,
argmatch_exit_fn exit_fn)
{
int res = argmatch (arg, arglist, vallist, valsize);
int res = __argmatch_internal (arg, arglist,
vallist, valsize,
case_sensitive);
if (res >= 0)
/* Success. */
return res;
@@ -265,12 +301,12 @@ main (int argc, const char *const *argv)
}
if ((cp = getenv ("VERSION_CONTROL")))
backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
backup_args, backup_vals);
backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
backup_args, backup_vals);
if (argc == 2)
backup_type = XARGMATCH (program_name, argv[1],
backup_args, backup_vals);
backup_type = XARGCASEMATCH (program_name, argv[1],
backup_args, backup_vals);
printf ("The version control is `%s'\n",
ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));

View File

@@ -1,18 +1,22 @@
/* Error handler for noninteractive utilities
Copyright (C) 1990-1998, 2000, 2001, 2002 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.
Copyright (C) 1990-1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
This program is distributed in the hope that it will be useful,
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser 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. */
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
@@ -21,13 +25,7 @@
#endif
#include <stdio.h>
#ifdef _LIBC
# include <libintl.h>
#else
# include "gettext.h"
#endif
#include <libintl.h>
#ifdef _LIBC
# include <wchar.h>
# define mbsrtowcs __mbsrtowcs
@@ -55,10 +53,6 @@ void exit ();
#include "error.h"
#if !_LIBC
# include "unlocked-io.h"
#endif
#ifndef _
# define _(String) String
#endif
@@ -80,7 +74,6 @@ unsigned int error_message_count;
# define program_name program_invocation_name
# include <errno.h>
# include <libio/libioP.h>
/* In GNU libc we want do not want to use the common name `error' directly.
Instead make it a weak alias. */
@@ -94,38 +87,27 @@ extern void __error_at_line (int status, int errnum, const char *file_name,
# define error_at_line __error_at_line
# ifdef USE_IN_LIBIO
# include <libio/iolibio.h>
# define fflush(s) INTUSE(_IO_fflush) (s)
# undef putc
# define putc(c, fp) INTUSE(_IO_putc) (c, fp)
# include <libio/iolibio.h>
# define fflush(s) _IO_fflush (s)
# endif
#else /* not _LIBC */
# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
# ifndef HAVE_DECL_STRERROR_R
"this configure-time declaration test was not run"
# endif
char *strerror_r ();
# endif
/* The calling program should define program_name and set it to the
name of the executing program. */
extern char *program_name;
# if HAVE_STRERROR_R || defined strerror_r
# ifdef HAVE_STRERROR_R
# define __strerror_r strerror_r
# else
# if HAVE_STRERROR
# ifndef HAVE_DECL_STRERROR
"this configure-time declaration test was not run"
# endif
# if !HAVE_DECL_STRERROR
# ifndef strerror /* On some systems, strerror is a macro */
char *strerror ();
# endif
# else
static char *
private_strerror (int errnum)
private_strerror (errnum)
int errnum;
{
extern char *sys_errlist[];
extern int sys_nerr;
@@ -136,43 +118,9 @@ private_strerror (int errnum)
}
# define strerror private_strerror
# endif /* HAVE_STRERROR */
# endif /* HAVE_STRERROR_R || defined strerror_r */
# endif /* HAVE_STRERROR_R */
#endif /* not _LIBC */
static void
print_errno_message (int errnum)
{
char const *s;
#if defined HAVE_STRERROR_R || _LIBC
char errbuf[1024];
# if STRERROR_R_CHAR_P || _LIBC
s = __strerror_r (errnum, errbuf, sizeof errbuf);
# else
if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
s = errbuf;
else
s = 0;
# endif
#else
s = strerror (errnum);
#endif
#if !_LIBC
if (! s)
s = _("Unknown system error");
#endif
#if _LIBC && USE_IN_LIBIO
if (_IO_fwide (stderr, 0) > 0)
{
__fwprintf (stderr, L": %s", s);
return;
}
#endif
fprintf (stderr, ": %s", s);
}
#ifdef VA_START
static void
@@ -229,12 +177,25 @@ error_tail (int status, int errnum, const char *message, va_list args)
++error_message_count;
if (errnum)
print_errno_message (errnum);
{
#if defined HAVE_STRERROR_R || _LIBC
char errbuf[1024];
char *s = __strerror_r (errnum, errbuf, sizeof errbuf);
# if _LIBC && USE_IN_LIBIO
if (_IO_fwide (stderr, 0) > 0)
__fwprintf (stderr, L": %s", s);
else
# endif
fprintf (stderr, ": %s", s);
#else
fprintf (stderr, ": %s", strerror (errnum));
#endif
}
#if _LIBC && USE_IN_LIBIO
if (_IO_fwide (stderr, 0) > 0)
putwc (L'\n', stderr);
else
# endif
#endif
putc ('\n', stderr);
fflush (stderr);
if (status)
@@ -291,7 +252,7 @@ error (status, errnum, message, va_alist)
++error_message_count;
if (errnum)
print_errno_message (errnum);
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
fflush (stderr);
if (status)
@@ -382,7 +343,7 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
++error_message_count;
if (errnum)
print_errno_message (errnum);
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
fflush (stderr);
if (status)

View File

@@ -1,7 +1,5 @@
/* exclude.c -- exclude file names
Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003 Free
Software Foundation, Inc.
Copyright 1992, 1993, 1994, 1997 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
@@ -24,205 +22,72 @@
# include <config.h>
#endif
#include <stdbool.h>
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#include <stddef.h>
#include <exclude.h>
#include <fnmatch.h>
#include <stdio.h>
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if HAVE_STRING_H
# include <string.h>
#endif
#if HAVE_STRINGS_H
# include <strings.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#else
# if HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#include <sys/types.h>
#include "exclude.h"
#include "fnmatch.h"
#include "unlocked-io.h"
#include "xalloc.h"
void *xmalloc PARAMS ((size_t));
void *xrealloc PARAMS ((void *, size_t));
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
/* Non-GNU systems lack these options, so we don't need to check them. */
#ifndef FNM_CASEFOLD
# define FNM_CASEFOLD 0
#endif
#ifndef FNM_LEADING_DIR
# define FNM_LEADING_DIR 0
#endif
verify (EXCLUDE_macros_do_not_collide_with_FNM_macros,
(((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
& (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
| FNM_CASEFOLD))
== 0));
/* An exclude pattern-options pair. The options are fnmatch options
ORed with EXCLUDE_* options. */
struct patopts
{
char const *pattern;
int options;
};
/* An exclude list, of pattern-options pairs. */
/* Keep track of excluded file name patterns. */
struct exclude
{
struct patopts *exclude;
size_t exclude_alloc;
size_t exclude_count;
char const **exclude;
int exclude_alloc;
int exclude_count;
};
/* Return a newly allocated and empty exclude list. */
struct exclude *
new_exclude (void)
{
struct exclude *ex = xmalloc (sizeof *ex);
struct exclude *ex = (struct exclude *) xmalloc (sizeof (struct exclude));
ex->exclude_count = 0;
ex->exclude_alloc = (1 << 6); /* This must be a power of 2. */
ex->exclude = xmalloc (ex->exclude_alloc * sizeof ex->exclude[0]);
ex->exclude_alloc = 64;
ex->exclude = (char const **) xmalloc (ex->exclude_alloc * sizeof (char *));
return ex;
}
/* Free the storage associated with an exclude list. */
void
free_exclude (struct exclude *ex)
{
free (ex->exclude);
free (ex);
}
/* Return zero if PATTERN matches F, obeying OPTIONS, except that
(unlike fnmatch) wildcards are disabled in PATTERN. */
static int
fnmatch_no_wildcards (char const *pattern, char const *f, int options)
{
if (! (options & FNM_LEADING_DIR))
return ((options & FNM_CASEFOLD)
? strcasecmp (pattern, f)
: strcmp (pattern, f));
else
{
size_t patlen = strlen (pattern);
int r = ((options & FNM_CASEFOLD)
? strncasecmp (pattern, f, patlen)
: strncmp (pattern, f, patlen));
if (! r)
{
r = f[patlen];
if (r == '/')
r = 0;
}
return r;
}
}
/* Return true if EX excludes F. */
bool
int
excluded_filename (struct exclude const *ex, char const *f)
{
size_t exclude_count = ex->exclude_count;
char const * const *exclude = ex->exclude;
int exclude_count = ex->exclude_count;
int i;
/* If no options are given, the default is to include. */
if (exclude_count == 0)
return false;
else
{
struct patopts const *exclude = ex->exclude;
size_t i;
for (i = 0; i < exclude_count; i++)
if (fnmatch (exclude[i], f, 0) == 0)
return 1;
/* Otherwise, the default is the opposite of the first option. */
bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
/* Scan through the options, seeing whether they change F from
excluded to included or vice versa. */
for (i = 0; i < exclude_count; i++)
{
char const *pattern = exclude[i].pattern;
int options = exclude[i].options;
if (excluded == !! (options & EXCLUDE_INCLUDE))
{
int (*matcher) (char const *, char const *, int) =
(options & EXCLUDE_WILDCARDS
? fnmatch
: fnmatch_no_wildcards);
bool matched = ((*matcher) (pattern, f, options) == 0);
char const *p;
if (! (options & EXCLUDE_ANCHORED))
for (p = f; *p && ! matched; p++)
if (*p == '/' && p[1] != '/')
matched = ((*matcher) (pattern, p + 1, options) == 0);
excluded ^= matched;
}
}
return excluded;
}
return 0;
}
/* Append to EX the exclusion PATTERN with OPTIONS. */
void
add_exclude (struct exclude *ex, char const *pattern, int options)
add_exclude (struct exclude *ex, char const *pattern)
{
struct patopts *patopts;
if (ex->exclude_alloc <= ex->exclude_count)
{
size_t s = 2 * ex->exclude_alloc;
if (! (0 < s && s <= SIZE_MAX / sizeof ex->exclude[0]))
xalloc_die ();
ex->exclude_alloc = s;
ex->exclude = xrealloc (ex->exclude, s * sizeof ex->exclude[0]);
}
ex->exclude = (char const **) xrealloc (ex->exclude,
((ex->exclude_alloc *= 2)
* sizeof (char *)));
patopts = &ex->exclude[ex->exclude_count++];
patopts->pattern = pattern;
patopts->options = options;
ex->exclude[ex->exclude_count++] = pattern;
}
/* Use ADD_FUNC to append to EX the patterns in FILENAME, each with
OPTIONS. LINE_END terminates each pattern in the file. Return -1
on failure, 0 on success. */
int
add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
struct exclude *ex, char const *filename, int options,
char line_end)
add_exclude_file (struct exclude *ex, char const *filename, char line_end)
{
bool use_stdin = filename[0] == '-' && !filename[1];
int use_stdin = filename[0] == '-' && !filename[1];
FILE *in;
char *buf;
char *p;
char const *pattern;
char const *lim;
size_t buf_alloc = (1 << 10); /* This must be a power of two. */
size_t buf_alloc = 1024;
size_t buf_count = 0;
int c;
int e = 0;
@@ -238,27 +103,22 @@ add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
{
buf[buf_count++] = c;
if (buf_count == buf_alloc)
{
buf_alloc *= 2;
if (! buf_alloc)
xalloc_die ();
buf = xrealloc (buf, buf_alloc);
}
buf = xrealloc (buf, buf_alloc *= 2);
}
buf = xrealloc (buf, buf_count + 1);
if (ferror (in))
e = errno;
if (!use_stdin && fclose (in) != 0)
e = errno;
buf = xrealloc (buf, buf_count + 1);
for (pattern = p = buf, lim = buf + buf_count; p <= lim; p++)
if (p < lim ? *p == line_end : buf < p && p[-1])
{
*p = '\0';
(*add_func) (ex, pattern, options);
add_exclude (ex, pattern);
pattern = p + 1;
}

View File

@@ -1,7 +1,5 @@
/* exclude.h -- declarations for excluding file names
Copyright (C) 1992, 1993, 1994, 1997, 1999, 2001, 2002, 2003 Free
Software Foundation, Inc.
Copyright 1992, 1993, 1994, 1997 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
@@ -20,24 +18,17 @@
/* Written by Paul Eggert <eggert@twinsun.com> */
/* Exclude options, which can be ORed with fnmatch options. */
/* Patterns must match the start of file names, instead of matching
anywhere after a '/'. */
#define EXCLUDE_ANCHORED (1 << 30)
/* Include instead of exclude. */
#define EXCLUDE_INCLUDE (1 << 29)
/* '?', '*', '[', and '\\' are special in patterns. Without this
option, these characters are ordinary and fnmatch is not used. */
#define EXCLUDE_WILDCARDS (1 << 28)
#ifndef PARAMS
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
# define PARAMS(Args) Args
# else
# define PARAMS(Args) ()
# endif
#endif
struct exclude;
struct exclude *new_exclude (void);
void free_exclude (struct exclude *);
void add_exclude (struct exclude *, char const *, int);
int add_exclude_file (void (*) (struct exclude *, char const *, int),
struct exclude *, char const *, int, char);
bool excluded_filename (struct exclude const *, char const *);
struct exclude *new_exclude PARAMS ((void));
void add_exclude PARAMS ((struct exclude *, char const *));
int add_exclude_file PARAMS ((struct exclude *, char const *, char));
int excluded_filename PARAMS ((struct exclude const *, char const *));

View File

@@ -1,5 +1,4 @@
/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2000, 2001,
2002 Free Software Foundation, Inc.
/* Copyright 1991, 1992, 1993, 1996, 1997, 2000 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
@@ -11,9 +10,9 @@
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. */
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. */
#if HAVE_CONFIG_H
# include <config.h>
@@ -24,362 +23,208 @@
# define _GNU_SOURCE 1
#endif
#ifdef __GNUC__
# define alloca __builtin_alloca
# define HAVE_ALLOCA 1
#else
# if defined HAVE_ALLOCA_H || defined _LIBC
# include <alloca.h>
# else
# ifdef _AIX
# pragma alloca
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
#endif
#if ! defined __builtin_expect && __GNUC__ < 3
# define __builtin_expect(expr, expected) (expr)
#endif
#include <assert.h>
#include <errno.h>
#include <fnmatch.h>
#include <ctype.h>
#if HAVE_STRING_H || defined _LIBC
# include <string.h>
#if defined STDC_HEADERS || !defined isascii
# define IN_CTYPE_DOMAIN(c) 1
#else
# if HAVE_STRINGS_H
# include <strings.h>
# endif
# define IN_CTYPE_DOMAIN(c) isascii (c)
#endif
#if defined STDC_HEADERS || defined _LIBC
# include <stddef.h>
# include <stdlib.h>
#endif
#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
/* For platform which support the ISO C amendement 1 functionality we
support user defined character classes. */
#if defined _LIBC || WIDE_CHAR_SUPPORT
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
# include <wchar.h>
# include <wctype.h>
#endif
/* We need some of the locale data (the collation sequence information)
but there is no interface to get this information in general. Therefore
we support a correct implementation only in glibc. */
#ifdef _LIBC
# include "../locale/localeinfo.h"
# include "../locale/elem-hash.h"
# include "../locale/coll-lookup.h"
# include <shlib-compat.h>
# define CONCAT(a,b) __CONCAT(a,b)
# define mbsinit __mbsinit
# define mbsrtowcs __mbsrtowcs
# define fnmatch __fnmatch
extern int fnmatch (const char *pattern, const char *string, int flags);
#endif
/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
#define NO_LEADING_PERIOD(flags) \
((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
/* Comment out all this code if we are using the GNU C Library, are not
actually compiling the library itself, and have not detected a bug
in the library. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined _LIBC || !defined __GNU_LIBRARY__ || !HAVE_FNMATCH_GNU
#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif
# ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
# else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
# endif
# ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
# else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
# endif
# define ISPRINT(c) (ISASCII (c) && isprint (c))
# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
# define ISALNUM(c) (ISASCII (c) && isalnum (c))
# define ISALPHA(c) (ISASCII (c) && isalpha (c))
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
# define ISLOWER(c) (ISASCII (c) && islower (c))
# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
# define ISSPACE(c) (ISASCII (c) && isspace (c))
# define ISUPPER(c) (ISASCII (c) && isupper (c))
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
# if defined _LIBC || WIDE_CHAR_SUPPORT
/* The GNU C library provides support for user-defined character classes
and the functions from ISO C amendement 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
/* This shouldn't happen but some implementation might still have this
problem. Use a reasonable default value. */
# define CHAR_CLASS_MAX_LENGTH 256
# endif
# ifdef _LIBC
# define IS_CHAR_CLASS(string) __wctype (string)
# else
# define IS_CHAR_CLASS(string) wctype (string)
# endif
# ifdef _LIBC
# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
# else
# define ISWCTYPE(WC, WT) iswctype (WC, WT)
# endif
# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
/* In this case we are implementing the multibyte character handling. */
# define HANDLE_MULTIBYTE 1
# endif
# else
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
# define IS_CHAR_CLASS(string) \
(STREQ (string, "alpha") || STREQ (string, "upper") \
|| STREQ (string, "lower") || STREQ (string, "digit") \
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|| STREQ (string, "space") || STREQ (string, "print") \
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
# if !defined _LIBC && !defined getenv && !HAVE_DECL_GETENV
extern char *getenv ();
# endif
# ifndef errno
#ifndef errno
extern int errno;
# endif
#endif
/* Global variable. */
static int posixly_correct;
# ifndef internal_function
/* Inside GNU libc we mark some function in a special way. In other
environments simply ignore the marking. */
# define internal_function
# endif
/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
int
fnmatch (const char *pattern, const char *string, int flags)
{
register const char *p = pattern, *n = string;
register char c;
/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
# endif
# define CHAR char
# define UCHAR unsigned char
# define INT int
# define FCT internal_fnmatch
# define EXT ext_match
# define END end_pattern
# define L(CS) CS
# ifdef _LIBC
# define BTOWC(C) __btowc (C)
# else
# define BTOWC(C) btowc (C)
# endif
# define STRLEN(S) strlen (S)
# define STRCAT(D, S) strcat (D, S)
# ifdef _LIBC
# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
# else
# if HAVE_MEMPCPY
# define MEMPCPY(D, S, N) mempcpy (D, S, N)
# else
# define MEMPCPY(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
# endif
# endif
# define MEMCHR(S, C, N) memchr (S, C, N)
# define STRCOLL(S1, S2) strcoll (S1, S2)
# include "fnmatch_loop.c"
#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
? tolower ((unsigned char) (c)) \
: (c))
# if HANDLE_MULTIBYTE
# define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
# define CHAR wchar_t
# define UCHAR wint_t
# define INT wint_t
# define FCT internal_fnwmatch
# define EXT ext_wmatch
# define END end_wpattern
# define L(CS) L##CS
# define BTOWC(C) (C)
# ifdef _LIBC
# define STRLEN(S) __wcslen (S)
# define STRCAT(D, S) __wcscat (D, S)
# define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
# else
# define STRLEN(S) wcslen (S)
# define STRCAT(D, S) wcscat (D, S)
# if HAVE_WMEMPCPY
# define MEMPCPY(D, S, N) wmempcpy (D, S, N)
# else
# define MEMPCPY(D, S, N) (wmemcpy (D, S, N) + (N))
# endif
# endif
# define MEMCHR(S, C, N) wmemchr (S, C, N)
# define STRCOLL(S1, S2) wcscoll (S1, S2)
# define WIDE_CHAR_VERSION 1
# undef IS_CHAR_CLASS
/* We have to convert the wide character string in a multibyte string. But
we know that the character class names consist of alphanumeric characters
from the portable character set, and since the wide character encoding
for a member of the portable character set is the same code point as
its single-byte encoding, we can use a simplified method to convert the
string to a multibyte character string. */
static wctype_t
is_char_class (const wchar_t *wcs)
{
char s[CHAR_CLASS_MAX_LENGTH + 1];
char *cp = s;
do
while ((c = *p++) != '\0')
{
/* Test for a printable character from the portable character set. */
# ifdef _LIBC
if (*wcs < 0x20 || *wcs > 0x7e
|| *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
return (wctype_t) 0;
# else
switch (*wcs)
c = FOLD (c);
switch (c)
{
case L' ': case L'!': case L'"': case L'#': case L'%':
case L'&': case L'\'': case L'(': case L')': case L'*':
case L'+': case L',': case L'-': case L'.': case L'/':
case L'0': case L'1': case L'2': case L'3': case L'4':
case L'5': case L'6': case L'7': case L'8': case L'9':
case L':': case L';': case L'<': case L'=': case L'>':
case L'?':
case L'A': case L'B': case L'C': case L'D': case L'E':
case L'F': case L'G': case L'H': case L'I': case L'J':
case L'K': case L'L': case L'M': case L'N': case L'O':
case L'P': case L'Q': case L'R': case L'S': case L'T':
case L'U': case L'V': case L'W': case L'X': case L'Y':
case L'Z':
case L'[': case L'\\': case L']': case L'^': case L'_':
case L'a': case L'b': case L'c': case L'd': case L'e':
case L'f': case L'g': case L'h': case L'i': case L'j':
case L'k': case L'l': case L'm': case L'n': case L'o':
case L'p': case L'q': case L'r': case L's': case L't':
case L'u': case L'v': case L'w': case L'x': case L'y':
case L'z': case L'{': case L'|': case L'}': case L'~':
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if ((flags & FNM_FILE_NAME) && *n == '/')
return FNM_NOMATCH;
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
return FNM_NOMATCH;
break;
case '\\':
if (!(flags & FNM_NOESCAPE))
{
c = *p++;
if (c == '\0')
/* Trailing \ loses. */
return FNM_NOMATCH;
c = FOLD (c);
}
if (FOLD (*n) != c)
return FNM_NOMATCH;
break;
case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if (c == '?')
{
/* A ? needs to match one character. */
if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
/* There isn't another character; no match. */
return FNM_NOMATCH;
else
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
less than three characters. */
++n;
}
}
if (c == '\0')
{
if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
for (; *n != '\0'; n++)
if (*n == '/')
return FNM_NOMATCH;
return 0;
}
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
c1 = FOLD (c1);
for (--p; *n != '\0'; ++n)
if ((c == '[' || FOLD (*n) == c1) &&
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
return 0;
else if (*n == '/' && (flags & FNM_FILE_NAME))
break;
return FNM_NOMATCH;
}
case '[':
{
/* Nonzero if the sense of the character class is inverted. */
register int not;
if (*n == '\0')
return FNM_NOMATCH;
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
return FNM_NOMATCH;
not = (*p == '!' || *p == '^');
if (not)
++p;
c = *p++;
for (;;)
{
register char cstart = c, cend = c;
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
cstart = cend = *p++;
}
cstart = cend = FOLD (cstart);
if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
c = FOLD (c);
if ((flags & FNM_FILE_NAME) && c == '/')
/* [/] can never match. */
return FNM_NOMATCH;
if (c == '-' && *p != ']')
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
cend = FOLD (cend);
c = *p++;
}
if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
goto matched;
if (c == ']')
break;
}
if (!not)
return FNM_NOMATCH;
break;
matched:;
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
if (c == '\0')
/* [... (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
}
if (not)
return FNM_NOMATCH;
}
break;
default:
return (wctype_t) 0;
if (c != FOLD (*n))
return FNM_NOMATCH;
}
# endif
/* Avoid overrunning the buffer. */
if (cp == s + CHAR_CLASS_MAX_LENGTH)
return (wctype_t) 0;
*cp++ = (char) *wcs++;
++n;
}
while (*wcs != L'\0');
*cp = '\0';
if (*n == '\0')
return 0;
# ifdef _LIBC
return __wctype (s);
# else
return wctype (s);
# endif
if ((flags & FNM_LEADING_DIR) && *n == '/')
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
return 0;
return FNM_NOMATCH;
#undef FOLD
}
# define IS_CHAR_CLASS(string) is_char_class (string)
# include "fnmatch_loop.c"
# endif
int
fnmatch (pattern, string, flags)
const char *pattern;
const char *string;
int flags;
{
# if HANDLE_MULTIBYTE
if (__builtin_expect (MB_CUR_MAX, 1) != 1)
{
mbstate_t ps;
size_t n;
wchar_t *wpattern;
wchar_t *wstring;
/* Convert the strings into wide characters. */
memset (&ps, '\0', sizeof (ps));
n = mbsrtowcs (NULL, &pattern, 0, &ps);
if (__builtin_expect (n, 0) == (size_t) -1)
/* Something wrong.
XXX Do we have to set `errno' to something which mbsrtows hasn't
already done? */
return -1;
wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
assert (mbsinit (&ps));
(void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
assert (mbsinit (&ps));
n = mbsrtowcs (NULL, &string, 0, &ps);
if (__builtin_expect (n, 0) == (size_t) -1)
/* Something wrong.
XXX Do we have to set `errno' to something which mbsrtows hasn't
already done? */
return -1;
wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
assert (mbsinit (&ps));
(void) mbsrtowcs (wstring, &string, n + 1, &ps);
return internal_fnwmatch (wpattern, wstring, wstring + n,
flags & FNM_PERIOD, flags);
}
# endif /* mbstate_t and mbsrtowcs or _LIBC. */
return internal_fnmatch (pattern, string, string + strlen (string),
flags & FNM_PERIOD, flags);
}
# ifdef _LIBC
# undef fnmatch
versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
strong_alias (__fnmatch, __fnmatch_old)
compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
# endif
# endif
#endif /* _LIBC or not __GNU_LIBRARY__. */

View File

@@ -1,6 +1,7 @@
/* An interface to read and write that retries (if necessary) until complete.
/* full-write.c -- an interface to write that retries after interrupts
Copyright (C) 1993, 1994, 1997-2003 Free Software Foundation, Inc.
Copyright 1993, 1994, 1997, 1998, 1999, 2000, 2001 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
@@ -14,17 +15,20 @@
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. */
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Paul Eggert. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
/* Specification. */
#ifdef FULL_READ
# include "full-read.h"
#else
# include "full-write.h"
#include <sys/types.h>
#include "full-write.h"
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
@@ -32,54 +36,32 @@
extern int errno;
#endif
#ifdef FULL_READ
# include "safe-read.h"
# define safe_rw safe_read
# define full_rw full_read
# undef const
# define const /* empty */
#else
# include "safe-write.h"
# define safe_rw safe_write
# define full_rw full_write
#endif
/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted
or if partial writes occur. Return the number of bytes successfully
written, setting errno if that is less than LEN. */
#ifdef FULL_READ
/* Set errno to zero upon EOF. */
# define ZERO_BYTE_TRANSFER_ERRNO 0
#else
/* Some buggy drivers return 0 when one tries to write beyond
a device's end. (Example: Linux 1.2.13 on /dev/fd0.)
Set errno to ENOSPC so they get a sensible diagnostic. */
# define ZERO_BYTE_TRANSFER_ERRNO ENOSPC
#endif
/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if
interrupted or if a partial write(read) occurs. Return the number
of bytes transferred.
When writing, set errno if fewer than COUNT bytes are written.
When reading, if fewer than COUNT bytes are read, you must examine
errno to distinguish failure from EOF (errno == 0). */
size_t
full_rw (int fd, const void *buf, size_t count)
full_write (int desc, const char *ptr, size_t len)
{
size_t total = 0;
const char *ptr = buf;
size_t total_written = 0;
while (count > 0)
while (len > 0)
{
size_t n_rw = safe_rw (fd, ptr, count);
if (n_rw == (size_t) -1)
break;
if (n_rw == 0)
ssize_t written = write (desc, ptr, len);
if (written <= 0)
{
errno = ZERO_BYTE_TRANSFER_ERRNO;
/* Some buggy drivers return 0 when you fall off a device's end. */
if (written == 0)
errno = ENOSPC;
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
break;
}
total += n_rw;
ptr += n_rw;
count -= n_rw;
total_written += written;
ptr += written;
len -= written;
}
return total;
return total_written;
}

View File

@@ -1,24 +1,9 @@
/* An interface to write() that writes all it is asked to write.
#ifndef PARAMS
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
# define PARAMS(Args) Args
# else
# define PARAMS(Args) ()
# endif
#endif
Copyright (C) 2002 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. */
#include <stddef.h>
/* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted
or if partial writes occur. Return the number of bytes successfully
written, setting errno if that is less than COUNT. */
extern size_t full_write (int fd, const void *buf, size_t count);
size_t full_write PARAMS ((int, const char *, size_t));

View File

@@ -1,6 +1,6 @@
%{
/* Parse a string into an internal time stamp.
Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
Copyright 1999, 2000 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
@@ -27,10 +27,11 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
#include <alloca.h>
/* Since the code of getdate.y is not included in the Emacs executable
itself, there is no need to #define static in this file. Even if
the code were included in the Emacs executable, it probably
@@ -62,9 +63,10 @@
- Its arg may be any int or unsigned int; it need not be an unsigned char.
- It's guaranteed to evaluate its argument exactly once.
- It's typically faster.
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
ISDIGIT_LOCALE unless it's important to use the locale's definition
of `digit' even when the host does not conform to POSIX. */
Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
it's important to use the locale's definition of `digit' even when the
host does not conform to Posix. */
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
#if STDC_HEADERS || HAVE_STRING_H
@@ -376,19 +378,19 @@ relunit:
| tSNUMBER tDAY_UNIT
{ PC.rel_day += $1.value * $2; }
| tDAY_UNIT
{ PC.rel_day += $1; }
{ PC.rel_day += $1 }
| tUNUMBER tHOUR_UNIT
{ PC.rel_hour += $1.value * $2; }
| tSNUMBER tHOUR_UNIT
{ PC.rel_hour += $1.value * $2; }
| tHOUR_UNIT
{ PC.rel_hour += $1; }
{ PC.rel_hour += $1 }
| tUNUMBER tMINUTE_UNIT
{ PC.rel_minutes += $1.value * $2; }
| tSNUMBER tMINUTE_UNIT
{ PC.rel_minutes += $1.value * $2; }
| tMINUTE_UNIT
{ PC.rel_minutes += $1; }
{ PC.rel_minutes += $1 }
| tUNUMBER tSEC_UNIT
{ PC.rel_seconds += $1.value * $2; }
| tSNUMBER tSEC_UNIT
@@ -446,7 +448,6 @@ o_merid:
may define-away `const'. We want the prototype for get_date to have
the same signature as the function definition. */
#include "getdate.h"
#include "unlocked-io.h"
#ifndef gmtime
struct tm *gmtime ();
@@ -907,7 +908,7 @@ get_date (const char *p, const time_t *now)
pc.local_zones_seen = 0;
pc.zones_seen = 0;
#if HAVE_STRUCT_TM_TM_ZONE
#if HAVE_TM_ZONE
pc.local_time_zone_table[0].name = tmp->tm_zone;
pc.local_time_zone_table[0].type = tLOCAL_ZONE;
pc.local_time_zone_table[0].value = tmp->tm_isdst;

View File

@@ -1,7 +1,5 @@
/* human.c -- print human readable file size
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software
Foundation, Inc.
Copyright (C) 1996, 1997, 1998, 1999, 2000 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
@@ -28,19 +26,12 @@
#include <sys/types.h>
#include <stdio.h>
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#if HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
@@ -68,34 +59,16 @@ char *getenv ();
static const char suffixes[] =
{
0, /* not used */
'K', /* kibi ('k' for kilo is a special case) */
'M', /* mega or mebi */
'G', /* giga or gibi */
'T', /* tera or tebi */
'P', /* peta or pebi */
'E', /* exa or exbi */
'Z', /* zetta or 2**70 */
'Y' /* yotta or 2**80 */
'k', /* kilo */
'M', /* Mega */
'G', /* Giga */
'T', /* Tera */
'P', /* Peta */
'E', /* Exa */
'Z', /* Zetta */
'Y' /* Yotta */
};
/* Generate into P[-1] (and possibly P[-2]) the proper suffix for
POWER and BASE. Return the address of the generated suffix. */
static char *
generate_suffix_backwards (char *p, int power, int base)
{
char letter = suffixes[power];
if (base == 1000)
{
*--p = 'B';
if (power == 1)
letter = 'k';
}
*--p = letter;
return p;
}
/* If INEXACT_STYLE is not human_round_to_even, and if easily
possible, adjust VALUE according to the style. */
static double
@@ -133,7 +106,7 @@ human_readable (uintmax_t n, char *buf,
Use INEXACT_STYLE to determine whether to take the ceiling or floor
of any result that cannot be expressed exactly.
If OUTPUT_BLOCK_SIZE is negative, use a format like "127K" if
If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
1000 or 1024; it must be at least 2. Most people visually process
@@ -141,10 +114,9 @@ human_readable (uintmax_t n, char *buf,
more prone to misinterpretation. Hence, converting to an
abbreviated form usually improves readability. Use a suffix
indicating which power is being used. For example, assuming
-OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3K,
-OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
than -OUTPUT_BLOCK_SIZE aren't modified. If -OUTPUT_BLOCK_SIZE is
1024, append a "B" after any size letter. */
than -OUTPUT_BLOCK_SIZE aren't modified. */
char *
human_readable_inexact (uintmax_t n, char *buf,
@@ -214,8 +186,6 @@ human_readable_inexact (uintmax_t n, char *buf,
sprintf (buf, "%.0f", adjust_value (inexact_style, damt));
else
{
char suffix[3];
char const *psuffix;
double e = 1;
power = 0;
@@ -228,13 +198,12 @@ human_readable_inexact (uintmax_t n, char *buf,
damt /= e;
suffix[2] = '\0';
psuffix = generate_suffix_backwards (suffix + 2, power, base);
sprintf (buf, "%.1f%s",
adjust_value (inexact_style, damt), psuffix);
if (4 + (base == 1000) < strlen (buf))
sprintf (buf, "%.0f%s",
adjust_value (inexact_style, damt * 10) / 10, psuffix);
sprintf (buf, "%.1f%c", adjust_value (inexact_style, damt),
suffixes[power]);
if (4 < strlen (buf))
sprintf (buf, "%.0f%c",
adjust_value (inexact_style, damt * 10) / 10,
suffixes[power]);
}
return buf;
@@ -260,7 +229,7 @@ human_readable_inexact (uintmax_t n, char *buf,
}
while (base <= amt && power < sizeof suffixes - 1);
p = generate_suffix_backwards (p, power, base);
*--p = suffixes[power];
if (amt < 10)
{

View File

@@ -21,15 +21,10 @@
# include <config.h>
#endif
#include "unicodeio.h"
#include "print-copyr.h"
#include <stdio.h>
#if ENABLE_NLS
# include "unicodeio.h"
#else
# define unicode_to_mb(code, callback, error_callback, callback_arg) \
error_callback (code, callback_arg)
#endif
#include <stdio.h>
#define COPYRIGHT_SIGN 0x00A9
@@ -50,7 +45,7 @@ void
print_copyright (char const *notice)
{
fputs ("Copyright ", stdout);
unicode_to_mb (COPYRIGHT_SIGN, print_unicode_char, print_parenthesized_c,
unicode_to_mb (COPYRIGHT_SIGN, print_unicode_success, print_parenthesized_c,
stdout);
fputc (' ', stdout);
puts (notice);

View File

@@ -1,5 +1,5 @@
/* quotearg.c - quote arguments for output
Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 1998, 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
@@ -21,22 +21,21 @@
# include <config.h>
#endif
#if HAVE_STDDEF_H
# include <stddef.h> /* For the definition of size_t on windows w/MSVC. */
#endif
#include <sys/types.h>
#include <quotearg.h>
#include <xalloc.h>
#include <ctype.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(text) gettext (text)
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
# define ISASCII(c) 1
#else
# define _(text) text
# define ISASCII(c) isascii (c)
#endif
#ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
#else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
#endif
#define N_(text) text
#if HAVE_LIMITS_H
# include <limits.h>
@@ -44,21 +43,9 @@
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif
#ifndef UCHAR_MAX
# define UCHAR_MAX ((unsigned char) -1)
#endif
#ifndef UINT_MAX
# define UINT_MAX ((unsigned int) -1)
#endif
#if HAVE_C_BACKSLASH_A
# define ALERT_CHAR '\a'
#else
# define ALERT_CHAR '\7'
#endif
#if HAVE_STDLIB_H
# include <stdlib.h>
@@ -68,55 +55,17 @@
# include <string.h>
#endif
#if HAVE_WCHAR_H
/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */
# include <stdio.h>
# include <time.h>
# include <wchar.h>
#endif
#if !HAVE_MBRTOWC
/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the
other macros are defined only for documentation and to satisfy C
syntax. */
# undef MB_CUR_MAX
# define MB_CUR_MAX 1
# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
# define mbsinit(ps) 1
# define iswprint(wc) ISPRINT ((unsigned char) (wc))
#endif
#ifndef iswprint
# if HAVE_WCTYPE_H
# include <wctype.h>
# endif
# if !defined iswprint && !HAVE_ISWPRINT
# define iswprint(wc) 1
# endif
#endif
#define INT_BITS (sizeof (int) * CHAR_BIT)
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
# define IN_CTYPE_DOMAIN(c) 1
#else
# define IN_CTYPE_DOMAIN(c) isascii(c)
#endif
/* Undefine to protect against the definition in wctype.h of solaris2.6. */
#undef ISPRINT
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
struct quoting_options
{
/* Basic quoting style. */
enum quoting_style style;
/* Quote the characters indicated by this bit vector even if the
/* Quote the chararacters indicated by this bit vector even if the
quoting style would not normally require them to be quoted. */
int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
int quote_these_too[((UCHAR_MAX + 1) / INT_BITS
+ ((UCHAR_MAX + 1) % INT_BITS != 0))];
};
/* Names of quoting styles. */
@@ -127,21 +76,17 @@ char const *const quoting_style_args[] =
"shell-always",
"c",
"escape",
"locale",
"clocale",
0
};
/* Correspondences to quoting style names. */
/* Correspondances to quoting style names. */
enum quoting_style const quoting_style_vals[] =
{
literal_quoting_style,
shell_quoting_style,
shell_always_quoting_style,
c_quoting_style,
escape_quoting_style,
locale_quoting_style,
clocale_quoting_style
escape_quoting_style
};
/* The default quoting options. */
@@ -190,335 +135,6 @@ set_char_quoting (struct quoting_options *o, char c, int i)
return r;
}
/* MSGID approximates a quotation mark. Return its translation if it
has one; otherwise, return either it or "\"", depending on S. */
static char const *
gettext_quote (char const *msgid, enum quoting_style s)
{
char const *translation = _(msgid);
if (translation == msgid && s == clocale_quoting_style)
translation = "\"";
return translation;
}
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
non-quoting-style part of O to control quoting.
Terminate the output with a null character, and return the written
size of the output, not counting the terminating null.
If BUFFERSIZE is too small to store the output string, return the
value that would have been returned had BUFFERSIZE been large enough.
If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
style specified by O, and O may not be null. */
static size_t
quotearg_buffer_restyled (char *buffer, size_t buffersize,
char const *arg, size_t argsize,
enum quoting_style quoting_style,
struct quoting_options const *o)
{
size_t i;
size_t len = 0;
char const *quote_string = 0;
size_t quote_string_len = 0;
int backslash_escapes = 0;
int unibyte_locale = MB_CUR_MAX == 1;
#define STORE(c) \
do \
{ \
if (len < buffersize) \
buffer[len] = (c); \
len++; \
} \
while (0)
switch (quoting_style)
{
case c_quoting_style:
STORE ('"');
backslash_escapes = 1;
quote_string = "\"";
quote_string_len = 1;
break;
case escape_quoting_style:
backslash_escapes = 1;
break;
case locale_quoting_style:
case clocale_quoting_style:
{
/* Get translations for open and closing quotation marks.
The message catalog should translate "`" to a left
quotation mark suitable for the locale, and similarly for
"'". If the catalog has no translation,
locale_quoting_style quotes `like this', and
clocale_quoting_style quotes "like this".
For example, an American English Unicode locale should
translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
MARK). A British English Unicode locale should instead
translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. */
char const *left = gettext_quote (N_("`"), quoting_style);
char const *right = gettext_quote (N_("'"), quoting_style);
for (quote_string = left; *quote_string; quote_string++)
STORE (*quote_string);
backslash_escapes = 1;
quote_string = right;
quote_string_len = strlen (quote_string);
}
break;
case shell_always_quoting_style:
STORE ('\'');
quote_string = "'";
quote_string_len = 1;
break;
default:
break;
}
for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
{
unsigned char c;
unsigned char esc;
if (backslash_escapes
&& quote_string_len
&& i + quote_string_len <= argsize
&& memcmp (arg + i, quote_string, quote_string_len) == 0)
STORE ('\\');
c = arg[i];
switch (c)
{
case '\0':
if (backslash_escapes)
{
STORE ('\\');
STORE ('0');
STORE ('0');
c = '0';
}
break;
case '?':
switch (quoting_style)
{
case shell_quoting_style:
goto use_shell_always_quoting_style;
case c_quoting_style:
if (i + 2 < argsize && arg[i + 1] == '?')
switch (arg[i + 2])
{
case '!': case '\'':
case '(': case ')': case '-': case '/':
case '<': case '=': case '>':
/* Escape the second '?' in what would otherwise be
a trigraph. */
i += 2;
c = arg[i + 2];
STORE ('?');
STORE ('\\');
STORE ('?');
break;
}
break;
default:
break;
}
break;
case ALERT_CHAR: esc = 'a'; goto c_escape;
case '\b': esc = 'b'; goto c_escape;
case '\f': esc = 'f'; goto c_escape;
case '\n': esc = 'n'; goto c_and_shell_escape;
case '\r': esc = 'r'; goto c_and_shell_escape;
case '\t': esc = 't'; goto c_and_shell_escape;
case '\v': esc = 'v'; goto c_escape;
case '\\': esc = c; goto c_and_shell_escape;
c_and_shell_escape:
if (quoting_style == shell_quoting_style)
goto use_shell_always_quoting_style;
c_escape:
if (backslash_escapes)
{
c = esc;
goto store_escape;
}
break;
case '#': case '~':
if (i != 0)
break;
/* Fall through. */
case ' ':
case '!': /* special in bash */
case '"': case '$': case '&':
case '(': case ')': case '*': case ';':
case '<': case '>': case '[':
case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
case '`': case '|':
/* A shell special character. In theory, '$' and '`' could
be the first bytes of multibyte characters, which means
we should check them with mbrtowc, but in practice this
doesn't happen so it's not worth worrying about. */
if (quoting_style == shell_quoting_style)
goto use_shell_always_quoting_style;
break;
case '\'':
switch (quoting_style)
{
case shell_quoting_style:
goto use_shell_always_quoting_style;
case shell_always_quoting_style:
STORE ('\'');
STORE ('\\');
STORE ('\'');
break;
default:
break;
}
break;
case '%': case '+': case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case ':': case '=':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
case '{': case '}':
/* These characters don't cause problems, no matter what the
quoting style is. They cannot start multibyte sequences. */
break;
default:
/* If we have a multibyte sequence, copy it until we reach
its end, find an error, or come back to the initial shift
state. For C-like styles, if the sequence has
unprintable characters, escape the whole sequence, since
we can't easily escape single characters within it. */
{
/* Length of multibyte sequence found so far. */
size_t m;
int printable;
if (unibyte_locale)
{
m = 1;
printable = ISPRINT (c);
}
else
{
mbstate_t mbstate;
memset (&mbstate, 0, sizeof mbstate);
m = 0;
printable = 1;
if (argsize == (size_t) -1)
argsize = strlen (arg);
do
{
wchar_t w;
size_t bytes = mbrtowc (&w, &arg[i + m],
argsize - (i + m), &mbstate);
if (bytes == 0)
break;
else if (bytes == (size_t) -1)
{
printable = 0;
break;
}
else if (bytes == (size_t) -2)
{
printable = 0;
while (i + m < argsize && arg[i + m])
m++;
break;
}
else
{
if (! iswprint (w))
printable = 0;
m += bytes;
}
}
while (! mbsinit (&mbstate));
}
if (1 < m || (backslash_escapes && ! printable))
{
/* Output a multibyte sequence, or an escaped
unprintable unibyte character. */
size_t ilim = i + m;
for (;;)
{
if (backslash_escapes && ! printable)
{
STORE ('\\');
STORE ('0' + (c >> 6));
STORE ('0' + ((c >> 3) & 7));
c = '0' + (c & 7);
}
if (ilim <= i + 1)
break;
STORE (c);
c = arg[++i];
}
goto store_c;
}
}
}
if (! (backslash_escapes
&& o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
goto store_c;
store_escape:
STORE ('\\');
store_c:
STORE (c);
}
if (quote_string)
for (; *quote_string; quote_string++)
STORE (*quote_string);
if (len < buffersize)
buffer[len] = '\0';
return len;
use_shell_always_quoting_style:
return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
shell_always_quoting_style, o);
}
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
argument ARG (of size ARGSIZE), using O to control quoting.
If O is null, use the default.
@@ -532,67 +148,191 @@ quotearg_buffer (char *buffer, size_t buffersize,
char const *arg, size_t argsize,
struct quoting_options const *o)
{
unsigned char c;
size_t i;
size_t len;
int quote_mark;
struct quoting_options const *p = o ? o : &default_quoting_options;
return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
p->style, p);
enum quoting_style quoting_style = p->style;
#define STORE(c) \
do \
{ \
if (len < buffersize) \
buffer[len] = (c); \
len++; \
} \
while (0)
switch (quoting_style)
{
case shell_quoting_style:
if (! (argsize == (size_t) -1 ? arg[0] == '\0' : argsize == 0))
{
switch (arg[0])
{
case '#': case '~':
break;
default:
len = 0;
for (i = 0; ; i++)
{
if (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize)
goto done;
c = arg[i];
switch (c)
{
case '\t': case '\n': case ' ':
case '!': /* special in csh */
case '"': case '$': case '&': case '\'':
case '(': case ')': case '*': case ';':
case '<': case '>': case '?': case '[': case '\\':
case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
case '`': case '|':
goto needs_quoting;
}
if (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))
goto needs_quoting;
STORE (c);
}
needs_quoting:;
break;
}
}
/* Fall through. */
case shell_always_quoting_style:
quote_mark = '\'';
break;
case c_quoting_style:
quote_mark = '"';
break;
default:
quote_mark = 0;
break;
}
len = 0;
if (quote_mark)
STORE (quote_mark);
for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
{
c = arg[i];
switch (quoting_style)
{
case literal_quoting_style:
break;
case shell_quoting_style:
case shell_always_quoting_style:
if (c == '\'')
{
STORE ('\'');
STORE ('\\');
STORE ('\'');
}
break;
case c_quoting_style:
case escape_quoting_style:
switch (c)
{
case '?': /* Do not generate trigraphs. */
case '\\': goto store_escape;
/* Not all C compilers know what \a means. */
case 7 : c = 'a'; goto store_escape;
case '\b': c = 'b'; goto store_escape;
case '\f': c = 'f'; goto store_escape;
case '\n': c = 'n'; goto store_escape;
case '\r': c = 'r'; goto store_escape;
case '\t': c = 't'; goto store_escape;
case '\v': c = 'v'; goto store_escape;
case '"':
if (quoting_style == c_quoting_style)
goto store_escape;
break;
default:
if (!ISGRAPH (c))
{
STORE ('\\');
STORE ('0' + (c >> 6));
STORE ('0' + ((c >> 3) & 7));
c = '0' + (c & 7);
goto store_c;
}
break;
}
if (! (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
goto store_c;
store_escape:
STORE ('\\');
}
store_c:
STORE (c);
}
if (quote_mark)
STORE (quote_mark);
done:
if (len < buffersize)
buffer[len] = '\0';
return len;
}
/* Use storage slot N to return a quoted version of argument ARG.
ARG is of size ARGSIZE, but if that is -1, ARG is a null-terminated string.
/* Use storage slot N to return a quoted version of the string ARG.
OPTIONS specifies the quoting options.
The returned value points to static storage that can be
reused by the next call to this function with the same value of N.
N must be nonnegative. N is deliberately declared with type "int"
N must be nonnegative. N is deliberately declared with type `int'
to allow for future extensions (using negative values). */
static char *
quotearg_n_options (int n, char const *arg, size_t argsize,
quotearg_n_options (int n, char const *arg,
struct quoting_options const *options)
{
/* Preallocate a slot 0 buffer, so that the caller can always quote
one small component of a "memory exhausted" message in slot 0. */
static char slot0[256];
static unsigned int nslots = 1;
unsigned int n0 = n;
struct slotvec
static unsigned int nslots;
static struct slotvec
{
size_t size;
char *val;
};
static struct slotvec slotvec0 = {sizeof slot0, slot0};
static struct slotvec *slotvec = &slotvec0;
} *slotvec;
if (n < 0)
abort ();
if (nslots <= n0)
if (nslots <= n)
{
unsigned int n1 = n0 + 1;
size_t s = n1 * sizeof *slotvec;
if (SIZE_MAX / UINT_MAX <= sizeof *slotvec
&& n1 != s / sizeof *slotvec)
xalloc_die ();
if (slotvec == &slotvec0)
{
slotvec = (struct slotvec *) xmalloc (sizeof *slotvec);
*slotvec = slotvec0;
}
int n1 = n + 1;
size_t s = n1 * sizeof (struct slotvec);
if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
abort ();
slotvec = (struct slotvec *) xrealloc (slotvec, s);
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec);
nslots = n1;
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
nslots = n;
}
{
size_t size = slotvec[n].size;
char *val = slotvec[n].val;
size_t qsize = quotearg_buffer (val, size, arg, argsize, options);
size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
if (size <= qsize)
{
slotvec[n].size = size = qsize + 1;
slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
quotearg_buffer (val, size, arg, argsize, options);
slotvec[n].val = val = xrealloc (val, size);
quotearg_buffer (val, size, arg, (size_t) -1, options);
}
return val;
@@ -600,9 +340,9 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
}
char *
quotearg_n (int n, char const *arg)
quotearg_n (unsigned int n, char const *arg)
{
return quotearg_n_options (n, arg, (size_t) -1, &default_quoting_options);
return quotearg_n_options (n, arg, &default_quoting_options);
}
char *
@@ -611,44 +351,13 @@ quotearg (char const *arg)
return quotearg_n (0, arg);
}
/* Return quoting options for STYLE, with no extra quoting. */
static struct quoting_options
quoting_options_from_style (enum quoting_style style)
{
struct quoting_options o;
o.style = style;
memset (o.quote_these_too, 0, sizeof o.quote_these_too);
return o;
}
char *
quotearg_n_style (int n, enum quoting_style s, char const *arg)
{
struct quoting_options const o = quoting_options_from_style (s);
return quotearg_n_options (n, arg, (size_t) -1, &o);
}
char *
quotearg_n_style_mem (int n, enum quoting_style s,
char const *arg, size_t argsize)
{
struct quoting_options const o = quoting_options_from_style (s);
return quotearg_n_options (n, arg, argsize, &o);
}
char *
quotearg_style (enum quoting_style s, char const *arg)
{
return quotearg_n_style (0, s, arg);
}
char *
quotearg_char (char const *arg, char ch)
{
struct quoting_options options;
options = default_quoting_options;
set_char_quoting (&options, ch, 1);
return quotearg_n_options (0, arg, (size_t) -1, &options);
return quotearg_n_options (0, arg, &options);
}
char *

View File

@@ -1,6 +1,5 @@
/* Convert string representation of a number into an intmax_t value.
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
Copyright 1999, 2001 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
@@ -66,7 +65,7 @@ long strtol PARAMS ((char const *, char **, int));
# ifndef HAVE_DECL_STRTOLL
"this configure-time declaration test was not run"
# endif
# if !HAVE_DECL_STRTOLL && HAVE_LONG_LONG
# if !HAVE_DECL_STRTOLL && HAVE_UNSIGNED_LONG_LONG
long long strtoll PARAMS ((char const *, char **, int));
# endif
#endif

View File

@@ -1,27 +1,23 @@
/* Unicode character output to streams with locale dependent encoding.
Copyright (C) 2000-2002 Free Software Foundation, Inc.
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2, or (at your option)
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
Library General Public License for more details.
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 Library 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. */
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. */
/* Written by Bruno Haible <haible@clisp.cons.org>. */
/* Note: This file requires the locale_charset() function. See in
libiconv-1.7/libcharset/INTEGRATE for how to obtain it. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -46,17 +42,20 @@ extern int errno;
# include <iconv.h>
#endif
#include <error.h>
#if ENABLE_NLS
# include <libintl.h>
#else
# define gettext(Text) Text
/* Some systems, like SunOS 4, don't have EILSEQ. On these systems,
define EILSEQ to some value other than EINVAL, because our invokers
may want to distinguish EINVAL from EILSEQ. */
#ifndef EILSEQ
# define EILSEQ ENOENT
#endif
#ifndef ENOTSUP
# define ENOTSUP EINVAL
#endif
#if HAVE_LANGINFO_CODESET && ! USE_INCLUDED_LIBINTL
# include <langinfo.h>
#endif
#define _(Text) gettext (Text)
#define N_(Text) Text
/* Specification. */
#include "unicodeio.h"
/* When we pass a Unicode character to iconv(), we must pass it in a
@@ -111,17 +110,17 @@ utf8_wctomb (unsigned char *r, unsigned int wc)
#define UTF8_NAME "UTF-8"
/* Converts the Unicode character CODE to its multibyte representation
in the current locale and calls the SUCCESS callback on the resulting
byte sequence. If an error occurs, invokes the FAILURE callback instead,
passing it CODE and an English error string.
Returns whatever the callback returned.
Assumes that the locale doesn't change between two calls. */
long
in the current locale and calls SUCCESS on the resulting byte
sequence. If an error occurs, invoke FAILURE instead,
passing it CODE with errno set appropriately.
Assumes that the locale doesn't change between two calls.
Return whatever the SUCCESS or FAILURE returns. */
int
unicode_to_mb (unsigned int code,
long (*success) PARAMS ((const char *buf, size_t buflen,
void *callback_arg)),
long (*failure) PARAMS ((unsigned int code, const char *msg,
void *callback_arg)),
int (*success) PARAMS((const char *buf, size_t buflen,
void *callback_arg)),
int (*failure) PARAMS((unsigned int code,
void *callback_arg)),
void *callback_arg)
{
static int initialized;
@@ -135,8 +134,18 @@ unicode_to_mb (unsigned int code,
if (!initialized)
{
const char *charset;
#if USE_INCLUDED_LIBINTL
extern const char *locale_charset PARAMS ((void));
const char *charset = locale_charset ();
charset = locale_charset ();
#else
# if HAVE_LANGINFO_CODESET
charset = nl_langinfo (CODESET);
# else
charset = "";
# endif
#endif
is_utf8 = !strcmp (charset, UTF8_NAME);
#if HAVE_ICONV
@@ -144,32 +153,32 @@ unicode_to_mb (unsigned int code,
{
utf8_to_local = iconv_open (charset, UTF8_NAME);
if (utf8_to_local == (iconv_t)(-1))
/* For an unknown encoding, assume ASCII. */
utf8_to_local = iconv_open ("ASCII", UTF8_NAME);
{
/* For an unknown encoding, assume ASCII. */
utf8_to_local = iconv_open ("ASCII", UTF8_NAME);
if (utf8_to_local == (iconv_t)(-1))
return failure (code, callback_arg);
}
}
#endif
initialized = 1;
}
/* Test whether the utf8_to_local converter is available at all. */
if (!is_utf8)
{
#if HAVE_ICONV
if (utf8_to_local == (iconv_t)(-1))
return failure (code, N_("iconv function not usable"), callback_arg);
#else
return failure (code, N_("iconv function not available"), callback_arg);
#endif
}
/* Convert the character to UTF-8. */
count = utf8_wctomb ((unsigned char *) inbuf, code);
if (count < 0)
return failure (code, N_("character out of range"), callback_arg);
#if HAVE_ICONV
if (!is_utf8)
{
errno = EILSEQ;
return failure (code, callback_arg);
}
if (is_utf8)
{
return success (inbuf, count, callback_arg);
}
else
{
#if HAVE_ICONV
char outbuf[25];
const char *inptr;
size_t inbytesleft;
@@ -192,7 +201,11 @@ unicode_to_mb (unsigned int code,
|| (res > 0 && code != 0 && outptr - outbuf == 1 && *outbuf == '\0')
# endif
)
return failure (code, NULL, callback_arg);
{
if (res != (size_t)(-1))
errno = EILSEQ;
return failure (code, callback_arg);
}
/* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
# if defined _LIBICONV_VERSION \
@@ -201,63 +214,46 @@ unicode_to_mb (unsigned int code,
/* Get back to the initial shift state. */
res = iconv (utf8_to_local, NULL, NULL, &outptr, &outbytesleft);
if (res == (size_t)(-1))
return failure (code, NULL, callback_arg);
return failure (code, callback_arg);
# endif
return success (outbuf, outptr - outbuf, callback_arg);
}
#else
errno = ENOTSUP;
return failure (code, callback_arg);
#endif
/* At this point, is_utf8 is true, so no conversion is needed. */
return success (inbuf, count, callback_arg);
}
}
/* Simple success callback that outputs the converted string.
The STREAM is passed as callback_arg. */
long
fwrite_success_callback (const char *buf, size_t buflen, void *callback_arg)
int
print_unicode_success (const char *buf, size_t buflen, void *callback_arg)
{
FILE *stream = (FILE *) callback_arg;
fwrite (buf, 1, buflen, stream);
return 0;
return fwrite (buf, 1, buflen, stream) == 0 ? -1 : 0;
}
/* Simple failure callback that displays an error and exits. */
static long
exit_failure_callback (unsigned int code, const char *msg, void *callback_arg)
/* Simple failure callback that prints an ASCII representation, using
the same notation as C99 strings. */
int
print_unicode_failure (unsigned int code, void *callback_arg)
{
if (msg == NULL)
error (1, 0, _("cannot convert U+%04X to local character set"), code);
else
error (1, 0, _("cannot convert U+%04X to local character set: %s"), code,
gettext (msg));
return -1;
}
/* Simple failure callback that displays a fallback representation in plain
ASCII, using the same notation as ISO C99 strings. */
static long
fallback_failure_callback (unsigned int code, const char *msg, void *callback_arg)
{
FILE *stream = (FILE *) callback_arg;
if (code < 0x10000)
fprintf (stream, "\\u%04X", code);
else
fprintf (stream, "\\U%08X", code);
int e = errno;
FILE *stream = callback_arg;
fprintf (stream, code < 0x10000 ? "\\u%04X" : "\\U%08X", code);
errno = e;
return -1;
}
/* Outputs the Unicode character CODE to the output stream STREAM.
Upon failure, exit if exit_on_error is true, otherwise output a fallback
notation. */
void
print_unicode_char (FILE *stream, unsigned int code, int exit_on_error)
Returns zero if successful, -1 (setting errno) otherwise.
Assumes that the locale doesn't change between two calls. */
int
print_unicode_char (FILE *stream, unsigned int code)
{
unicode_to_mb (code, fwrite_success_callback,
exit_on_error
? exit_failure_callback
: fallback_failure_callback,
stream);
return unicode_to_mb (code, print_unicode_success, print_unicode_failure,
stream);
}

View File

@@ -1,21 +1,20 @@
/* Unicode character output to streams with locale dependent encoding.
Copyright (C) 2000-2002 Free Software Foundation, Inc.
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2, or (at your option)
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
Library General Public License for more details.
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 Library 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. */
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. */
#ifndef UNICODEIO_H
# define UNICODEIO_H
@@ -30,15 +29,29 @@
# endif
# endif
/* Outputs the Unicode character CODE to the output stream STREAM.
Upon failure, exit if exit_on_error is true, otherwise output a fallback
notation. */
extern void print_unicode_char PARAMS ((FILE *stream, unsigned int code,
int exit_on_error));
/* Converts the Unicode character CODE to its multibyte representation
in the current locale and calls the CALLBACK on the resulting byte
sequence. If an error occurs, invokes ERROR_CALLBACK instead,
passing it CODE with errno set appropriately. Returns whatever the
callback returns. */
extern int unicode_to_mb
PARAMS ((unsigned int code,
int (*callback) PARAMS ((const char *buf, size_t buflen,
void *callback_arg)),
int (*error_callback) PARAMS ((unsigned int code,
void * callback_arg)),
void *callback_arg));
/* Simple success callback that outputs the converted string.
The STREAM is passed as callback_arg. */
extern long fwrite_success_callback PARAMS ((const char *buf, size_t buflen,
void *callback_arg));
/* Success callback that outputs the conversion of the character. */
extern int print_unicode_success PARAMS((const char *buf, size_t buflen,
void *callback_arg));
/* Failure callback that outputs an ASCII representation. */
extern int print_unicode_failure PARAMS((unsigned int code,
void *callback_arg));
/* Outputs the Unicode character CODE to the output stream STREAM.
Returns -1 (setting errno) if unsuccessful. */
extern int print_unicode_char PARAMS((FILE *stream, unsigned int code));
#endif

View File

@@ -20,9 +20,6 @@
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef errno
extern int errno;

View File

@@ -1,100 +0,0 @@
Makefile
Makefile.in
alloca.m4
backupfile.m4
bison.m4
chown.m4
clock_time.m4
codeset.m4
d-ino.m4
dirname.m4
dos.m4
error.m4
exclude.m4
exitfail.m4
extensions.m4
fileblocks.m4
fnmatch.m4
ftruncate.m4
getcwd.m4
getdate.m4
getline.m4
getndelim2.m4
getopt.m4
gettext.m4
gettime.m4
gettimeofday.m4
glibc21.m4
hash.m4
human.m4
iconv.m4
intdiv0.m4
intmax.m4
intmax_t.m4
inttypes-pri.m4
inttypes.m4
inttypes_h.m4
isc-posix.m4
lchown.m4
lcmessage.m4
lib-ld.m4
lib-link.m4
lib-prefix.m4
longdouble.m4
longlong.m4
mbrtowc.m4
mbstate_t.m4
memset.m4
mktime.m4
modechange.m4
nls.m4
obstack.m4
onceonly.m4
pathmax.m4
po.m4
printf-posix.m4
progtest.m4
quote.m4
quotearg.m4
restrict.m4
rmdir.m4
safe-read.m4
safe-write.m4
save-cwd.m4
savedir.m4
signed.m4
size_max.m4
ssize_t.m4
st_mtim.m4
stdbool.m4
stdint_h.m4
stpcpy.m4
strcase.m4
strerror_r.m4
strtoimax.m4
strtol.m4
strtoll.m4
strtoul.m4
strtoull.m4
strtoumax.m4
time_r.m4
timespec.m4
tm_gmtoff.m4
uintmax_t.m4
ulonglong.m4
unlocked-io.m4
utimbuf.m4
utime.m4
utimes-null.m4
utimes.m4
wchar_t.m4
wint_t.m4
xalloc.m4
xgetcwd.m4
xsize.m4
xstrtol.m4
xstrtoumax.m4
*_gl.m4
gnulib.m4
malloc.m4
realloc.m4

33
m4/Makefile.am Normal file
View File

@@ -0,0 +1,33 @@
## Process this file with automake to produce Makefile.in -*-Makefile-*-
EXTRA_DIST = \
c-bs-a.m4 \
ccstdc.m4 \
check-decl.m4 \
codeset.m4 \
d-ino.m4 \
decl.m4 \
error.m4 \
fnmatch.m4 \
getcwd.m4 \
getline.m4 \
gettext.m4 \
glibc21.m4 \
iconv.m4 \
inttypes.m4 \
jm-mktime.m4 \
lcmessage.m4 \
longlong.m4 \
malloc.m4 \
mbrtowc.m4 \
mbstate_t.m4 \
prereq.m4 \
progtest.m4 \
realloc.m4 \
strerror_r.m4 \
ulonglong.m4 \
utimbuf.m4 \
utime.m4 \
utimes.m4 \
xstrtoimax.m4 \
xstrtoumax.m4

View File

@@ -1,4 +1,4 @@
#serial 3
#serial 4
dnl FIXME: put these prerequisite-only *.m4 files in a separate
dnl directory -- otherwise, they'll conflict with existing files.
@@ -6,7 +6,8 @@ dnl directory -- otherwise, they'll conflict with existing files.
dnl These are the prerequisite macros for GNU's error.c file.
AC_DEFUN([jm_PREREQ_ERROR],
[
AC_CHECK_FUNCS(strerror strerror_r vprintf doprnt)
AC_CHECK_FUNCS(strerror vprintf doprnt)
AC_CHECK_DECLS([strerror])
AC_FUNC_STRERROR_R
AC_HEADER_STDC
])

View File

@@ -1,9 +1,23 @@
#serial 1002
#serial 1003
# Experimental replacement for the function in the latest CVS autoconf.
# If the compile-test says strerror_r doesn't work, then resort to a
# `run'-test that works on BeOS and segfaults on DEC Unix.
# Use with the error.c file in ../lib.
# Copyright 2001 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. */
undefine([AC_FUNC_STRERROR_R])
# AC_FUNC_STRERROR_R
@@ -11,56 +25,35 @@ undefine([AC_FUNC_STRERROR_R])
AC_DEFUN([AC_FUNC_STRERROR_R],
[AC_CHECK_DECLS([strerror_r])
AC_CHECK_FUNCS([strerror_r])
if test $ac_cv_func_strerror_r = yes; then
AC_CHECK_HEADERS(string.h)
AC_CACHE_CHECK([for working strerror_r],
ac_cv_func_strerror_r_works,
AC_CACHE_CHECK([whether strerror_r returns char *],
ac_cv_func_strerror_r_char_p,
[
AC_TRY_COMPILE(
[
# include <stdio.h>
# if HAVE_STRING_H
# include <string.h>
# endif
],
[
char buf[100];
char x = *strerror_r (0, buf, sizeof buf);
],
ac_cv_func_strerror_r_works=yes,
ac_cv_func_strerror_r_works=no
)
if test $ac_cv_func_strerror_r_works = no; then
# strerror_r seems not to work, but now we have to choose between
ac_cv_func_strerror_r_char_p=no
if test $ac_cv_have_decl_strerror_r = yes; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[[
char buf[100];
char x = *strerror_r (0, buf, sizeof buf);
char *p = strerror_r (0, buf, sizeof buf);
]])],
ac_cv_func_strerror_r_char_p=yes)
else
# strerror_r is not declared. Choose between
# systems that have relatively inaccessible declarations for the
# function. BeOS and DEC UNIX 4.0 fall in this category, but the
# former has a strerror_r that returns char*, while the latter
# has a strerror_r that returns `int'.
# This test should segfault on the DEC system.
AC_TRY_RUN(
[
# include <stdio.h>
# include <string.h>
# include <ctype.h>
extern char *strerror_r ();
int
main ()
{
char buf[100];
AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
extern char *strerror_r ();],
[[char buf[100];
char x = *strerror_r (0, buf, sizeof buf);
exit (!isalpha (x));
}
],
ac_cv_func_strerror_r_works=yes,
ac_cv_func_strerror_r_works=no,
ac_cv_func_strerror_r_works=no)
exit (!isalpha (x));]])],
ac_cv_func_strerror_r_char_p=yes, , :)
fi
])
if test $ac_cv_func_strerror_r_works = yes; then
AC_DEFINE(HAVE_WORKING_STRERROR_R, 1,
[Define to 1 if `strerror_r' returns a string.])
fi
if test $ac_cv_func_strerror_r_char_p = yes; then
AC_DEFINE([STRERROR_R_CHAR_P], 1,
[Define to 1 if strerror_r returns char *.])
fi
])# AC_FUNC_STRERROR_R

View File

@@ -1,20 +0,0 @@
index.html
*.po
LINGUAS
Makefile.in.in
Makevars.template
Rules-quot
boldquot.sed
en@boldquot.header
en@quot.header
insert-header.sin
quot.sed
remove-potcdate.sin
Makefile.in
POTFILES
Makefile
tar.pot
remove-potcdate.sed
*.gmo
*.mo
stamp-po

View File

@@ -1,41 +0,0 @@
# Makefile variables for PO directory in any package using GNU gettext.
# Usually the message domain is the same as the package name.
DOMAIN = $(PACKAGE)
# These two variables depend on the location of this directory.
subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
# package. (Note that the msgstr strings, extracted from the package's
# sources, belong to the copyright holder of the package.) Translators are
# expected to transfer the copyright for their translations to this person
# or entity, or to disclaim their copyright. The empty string stands for
# the public domain; in this case the translators are expected to disclaim
# their copyright.
COPYRIGHT_HOLDER = Free Software Foundation, Inc.
# This is the email address or URL to which the translators shall report
# bugs in the untranslated strings:
# - Strings which are not entire sentences, see the maintainer guidelines
# in the GNU gettext documentation, section 'Preparing Strings'.
# - Strings which use unclear terms or require additional context to be
# understood.
# - Strings which make invalid assumptions about notation of date, time or
# money.
# - Pluralisation problems.
# - Incorrect English spelling.
# - Incorrect formatting.
# It can be your email address, or a mailing list address where translators
# can write to without being subscribed, or the URL of a web page through
# which the translators can contact you.
MSGID_BUGS_ADDRESS = bug-tar@gnu.org
# This is the list of locale categories, beyond LC_MESSAGES, for which the
# message catalogs shall be used. It is usually empty.
EXTRA_LOCALE_CATEGORIES =

View File

@@ -1,31 +1,14 @@
# List of files which contain translatable strings.
# Copyright (C) 1996, 1999, 2000, 2003 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.
# Copyright 1996, 1999 Free Software Foundation, Inc.
# Library files
lib/argmatch.c
lib/error.c
lib/getopt.c
lib/human.c
lib/quotearg.c
lib/xmalloc.c
# Package source files
src/arith.c
src/buffer.c
src/common.h
src/compare.c
@@ -41,4 +24,6 @@ src/rmt.c
src/rtapelib.c
src/tar.c
src/update.c
src/xheader.c
# Checking tools
tests/genfile.c

View File

@@ -1,6 +0,0 @@
Makefile.in
Makefile
backup.sh
backup
restore
dump-remind

View File

@@ -1,4 +1,5 @@
# Copyright (C) 2004 Free Software Foundation, Inc.
# Makefile for GNU tar scripts.
# Copyright (C) 1994 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
@@ -11,39 +12,9 @@
## 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.
## along with this program; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
BACKUP_LIBEXEC_SCRIPTS_LIST=backup.sh dump-remind
BACKUP_SBIN_SCRIPTS_LIST=backup restore
libexec_SCRIPTS=@BACKUP_LIBEXEC_SCRIPTS@
AM_INSTALLCHECK_STD_OPTIONS_EXEMPT=backup.sh dump-remind
sbin_SCRIPTS=@BACKUP_SBIN_SCRIPTS@
EXTRA_SCRIPTS=
EXTRA_DIST=\
backup.sh.in\
backup.in\
restore.in\
dump-remind.in\
backup-specs
CLEANFILES=backup.sh backup restore dump-remind
AUTOMAKE_OPTIONS = gnits
SED_CMD="s,\@libexecdir\@,$(libexecdir),;\
s,\@sysconfdir\@,$(sysconfdir),;\
s,\@PACKAGE\@,$(PACKAGE),;\
s,\@VERSION\@,$(VERSION),;\
s,\@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),;\
s,\@DATE_FORMAT_OK\@,$(DATE_FORMAT_OK),;@BACKUP_SED_COND@"
backup.sh: $(srcdir)/backup.sh.in
sed $(SED_CMD) $? > $@
backup: $(srcdir)/backup.in
sed $(SED_CMD) $? > $@
restore: $(srcdir)/restore.in
sed $(SED_CMD) $? > $@
dump-remind: $(srcdir)/dump-remind.in
sed $(SED_CMD) $? > $@
EXTRA_DIST = WARNING backup-specs dump-remind level-0 level-1 weekly.new

3
scripts/WARNING Normal file
View File

@@ -0,0 +1,3 @@
GNU tar scripts have not been updated in a long while. make will
not not install them. Please consider the contents of this directory
are provided as indicative for the time being.

View File

@@ -1,68 +1,34 @@
# This is a sample configuration file for GNU tar backup script.
# See end of file for copying conditions
# site-specific parameters for file system backup.
# User name or email address of the administrator of backups. A report
# will be sent to this address when the backup terminates
ADMINISTRATOR="root@localhost"
# User name of administrator of backups.
ADMINISTRATOR=backup-reports
# (Optional) Path to tar binary.
TAR=/bin/tar
# Hour at which backups are normally done.
# This should be a number from 0 to 23.
BACKUP_HOUR=1
# (Optional) Path to rsh binary or its equivalent. You may wish to
# set it to ssh as shown in the example below, to improve security.
# In this case you will have to use public key authentication.
RSH=/usr/local/bin/ssh
# (Optional) Path to rsh binary on remote mashines. This will be
# passed via --rsh-command option to the remote invocation of
# tar
RSH_COMMAND=/usr/local/bin/ssh
# Name of temporary file to hold volume numbers. This needs to be accessible
# by all the machines which have filesystems to be dumped.
VOLNO_FILE=/root/volume
# Location of GNU tar. This must be the same for all hosts.
TAR=/usr/local/gnubin/tar
# Device to use for dumping. It should be on the host
# on which the dump scripts are run.
TAPE_FILE=/dev/rmt0
TAPE_FILE=/dev/nrsmt0
# Command to obtain status of tape drive, including error count.
# On some tape drives there may not be such a command;
# then simply use `TAPE_STATUS=false'.
#
# Might also consider
# TAPE_STATUS="mt -f ${TAPE_FILE} status"
# if `mts' is missing, though this alternative is rather verbose.
TAPE_STATUS="mts -t ${TAPE_FILE}"
# Blocking factor to use for writing the dump.
BLOCKING=124
# List of file systems to be dumped. If prefixed with a HOST:
# the filesystem is accessed on the given HOST, unless it
# coincides with the local machine name.
# If a file system starts with a slash, it is handled as a local
# one.
BACKUP_DIRS='remote1:/etc remote1:/var/spool/crontab'
# Alternatively, you may leave this variable unassigned, and
# keep the list of filesystems to be dumped in file
# $SYSCONFDIR/backup/dirs, one filesystem per line. Empty
# lines and shell comments are allowed in this file. The location
# of this file may be overridden using DIRLIST variable, e.g.:
# DIRLIST=/etc/my-backup/dirlist
# List of individual files to be dumped.
# These should be accesible from the machine on which the dump is run.
BACKUP_FILES=''
# This list may also be kept in file $SYSCONFDIR/backup/files, the
# format of which is the same as described above. The location of
# this file may be overridden by setting FILELIST variable:
# FILELIST=/etc/my-backup/filelist
# Name of 'exclude file list'. It is searched under $SYSCONFDIR/tar-backup
# on remote machines
XLIST=exclude_files
# Default directory for storing incremental listings on remote
# machines is $SYSCONFDIR/tar-backup. It can be overridden using
# REMOTEBACKUPDIR variable
# Default directory for storing backup logs is $SYSCONFDIR/backup/log.
# It can also be overridden via LOGPATH variable.
# Time to sleep between dumps of any two successive filesystems
SLEEP_TIME=15
# Name of temporary file to hold volume numbers. This needs to be accessible
# by all the machines which have filesystems to be dumped.
VOLNO_FILE=/home/gd2/dump/volnofile
# Script to be run when it's time to insert a new tape in for the next
# volume. Administrators may want to tailor this script for their site.
@@ -70,6 +36,37 @@ SLEEP_TIME=15
# probably defined in the manual.
#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
# List of file systems to be dumped.
# Actually, any directory may be used, but if it has subdirectories on
# other file systems, they are not included.
# The host name specifies which host to run tar on.
# It should normally be the host that actually has the file system.
# If GNU tar is not installed on that machine, then you can specify some
# other host which can access the file system through NFS.
# Although these are arranged one per line, that is not mandatory.
# It does not work to use # for comments within the string.
BACKUP_DIRS='
albert:/fs/fsf
sugar-bombs:/fs/gd
albert:/fs/gd2
churchy:/fs/gd3
nutrimat:/fs/gp
nutrimat:/fs/gp2
albert:/fs/mailer
placebo:/archive
nutrimat:/fs/dist
albert:/
albert:/usr
nutrimat:/
placebo:/
ernst:/usr1
'
# List of individual files to be dumped.
# These should be accesible from the machine on which the dump is run.
BACKUP_FILES=''
# Message to display on the terminal while waiting for dump time. Usually
# this will just be some literal text, preferably something more
# entertaining than this. The awk script here saves some redundant
@@ -81,20 +78,5 @@ SLEEP_MESSAGE="`awk '
\"D O N O T T O U C H T H I S T E R M I N A L !!!!!\"
}' /dev/null`"
# Copyright (C) 2004 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.
# eof

View File

@@ -1,253 +0,0 @@
#! /bin/sh
# This program is part of GNU tar
# Copyright 2004, Free Software Foundation
#
# 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 1, 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.
# Load library routines
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
. ${LIBPATH-@libexecdir@}/backup.sh
DUMP_LEVEL=0
TIME=
NOW=`now`
usage() {
cat - <<EOF
usage: $PROGNAME [OPTIONS] [WHEN]
Options are:
-l, --level=LEVEL Do backup level LEVEL (default $DUMP_LEVEL).
-f, --force Force backup even if today's log file already
exists.
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
-t, --time=TIME Wait till TIME, then do backup.
Informational options:
-h, --help Display this help message.
-L, --license Display program license.
-V, --version Display program version.
Optional argument WHEN is for backward compatibility only. It has been
superseded by --time option.
TIME argument can be one of:
now -- do backup immediately.
HH -- do backup at HH hours.
HH:MM -- do backup at HH:MM.
Send bug reports to @PACKAGE_BUGREPORT@.
EOF
}
# For compatibility with previous versions, deduce the backup level
# from the command name
case "$PROGNAME" in
level-[0-9]) DUMP_LEVEL=`expr $PROGNAME : 'level-\([0-9][0-9]*\)'`;;
esac
for opt
do
if [ -z "$prev" ]; then
option=$opt
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
else
option="${prev}=$opt"
prev=""
optarg=$opt
fi
case $option in
--l=*|--le=*|--lev=*|--leve=*|--level=*)
DUMP_LEVEL=$optarg
;;
-l|--l|--le|--lev|--leve|--level)
prev=$option
;;
--verb=*|--verbo=*|--verbos=*|--verbose=*)
VERBOSE=$optarg
;;
-v|--verb|--verbo|--verbos|--verbose)
VERBOSE=100
;;
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
--t=*|--ti=*|--tim=*|--time=*)
TIME=$optarg
;;
-t) prev=--t;;
-t*) TIME=`expr $option : "-t\(.*\)"`;;
--t|--ti|--tim|--time)
prev=$option
;;
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "backup (@PACKAGE@ @VERSION@)"
exit 0;;
-L|--li|--lic|--lice|--licen|--licens|--license)
license
exit;;
-h|--h|--he|--hel|--help)
usage
exit;;
-f|--f|--fo|--for|--forc|--force)
FORCE=yes
;;
*) if [ "x$TIME" != "x" ]; then
bailout "Extra argument. Try $PROGNAME --help for more info."
else
TIME=$option
fi;;
esac
done
if [ "x$TIME" = x ]; then
bailout "No backup time specified. Try $PROGNAME --help for more info."
exit 1
fi
init_backup
# Maybe sleep until around specified or default hour.
wait_time $TIME
if [ $DUMP_LEVEL -ne 0 ]; then
PREV_LEVEL=`expr $DUMP_LEVEL - 1`
PREV_DATE=`ls -t ${LOGPATH}/log-*-level-$PREV_LEVEL|
head -1|
sed "s,${LOGPATH}/log-\(.*\)-level.*,\1,"`
if [ "x$PREV_DATE" = x ]; then
bailout "Can't determine date of the previous backup"
fi
message 0 "Backup from $PREV_DATE to $NOW"
fi
# start doing things
# Make sure the log file did not already exist. Create it.
if [ "x$FORCE" = "xyes" ]; then
rm ${LOGFILE}
fi
if [ -f "${LOGFILE}" ] ; then
bailout "Log file ${LOGFILE} already exists."
else
touch "${LOGFILE}"
fi
message 1 "Ready for backup."
message 10 "TAR invocation: $TAR_PART1"
message 20 "Variables:"
message 20 "BACKUP_DIRS=$BACKUP_DIRS"
message 20 "BACKUP_FILES=$BACKUP_FILES"
# The buch of commands below is run in a subshell for which all output is
# piped through `tee' to the logfile. Doing this, instead of having
# multiple pipelines all over the place, is cleaner and allows access to
# the exit value from various commands more easily.
(
message 1 "preparing tapes"
$MT_BEGIN "${TAPE_FILE}"
rm -f "${VOLNO_FILE}"
message 1 "processing backup directories"
set - ${BACKUP_DIRS}
while [ $# -ne 0 ] ; do
date="`date`"
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
if [ -z "$remotehost" ]; then
remotehost=$localhost
fi
echo "Backing up ${1} at ${date}"
message 10 "fs=$fs"
message 10 "fsname=$fsname"
message 10 "remotehost=$remotehost"
if [ $DUMP_LEVEL -eq 0 ]; then
make_level_log ${remotehost}
else
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
remote_run "${remotehost}" cp "`level_log_name ${fsname} $PREV_LEVEL`" "`level_log_name temp`"
fi
${DUMP_BEGIN-:} $DUMP_LEVEL $remotehost $fs $fsname
backup_host ${remotehost} \
"--listed=`level_log_name temp`" \
"--label='`print_level` backup of ${fs} on ${remotehost} at ${NOW}'" \
-C ${fs} .
# `rsh' doesn't exit with the exit status of the remote command. What
# stupid lossage. TODO: think of a reliable workaround.
if [ $? -ne 0 ] ; then
echo "Backup of ${1} failed." 1>&2
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
flush_level_log ${remotehost} ${fsname}
fi
${MT_STATUS}
${DUMP_END-:} $DUMP_LEVEL $remotehost $fs $fsname
echo "sleeping ${SLEEP_TIME} seconds"
sleep ${SLEEP_TIME}
shift
done
# Dump any individual files requested.
if [ "x${BACKUP_FILES}" != "x" ] ; then
message 1 "processing individual files"
date="`date`"
if [ $DUMP_LEVEL -eq 0 ]; then
make_level_log $localhost
else
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
remote_run "${localhost}" cp "`level_log_name MISC $PREV_LEVEL`" "`level_log_name temp`"
fi
echo "Backing up miscellaneous files at ${date}"
${DUMP_BEGIN-:} $DUMP_LEVEL $localhost MISC MISC
backup_host $localhost \
"--listed=`level_log_name temp`"\
"--label='`print_level` backup of miscellaneous files at ${NOW}'" \
${BACKUP_FILES}
if [ $? -ne 0 ] ; then
echo "Backup of miscellaneous files failed."
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
flush_level_log $localhost MISC
fi
${MT_STATUS}
${DUMP_END-:} $DUMP_LEVEL $localhost MISC MISC
else
echo "No miscellaneous files specified"
fi
message 1 "final cleanup"
$MT_REWIND "${TAPE_FILE}"
$MT_OFFLINE "${TAPE_FILE}"
echo "."
) 2>&1 | tee -a "${LOGFILE}"
echo "Sending the dump log to ${ADMINISTRATOR}"
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
# EOF

View File

@@ -1,342 +0,0 @@
#! /bin/sh
# This program is part of GNU tar
# Copyright 2004, Free Software Foundation
#
# 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 1, 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.
PROGNAME=`basename $0`
CONFIGPATH="$SYSCONFDIR/backup"
REMOTEBACKUPDIR="$SYSCONFDIR/tar-backup"
CONFIGFILE=${CONFIGPATH}/backup-specs
DIRLIST=${CONFIGPATH}/dirs
FILELIST=${CONFIGPATH}/files
LOGPATH=${CONFIGPATH}/log
# Default functions for running various magnetic tape commands
mt_begin() {
mt -f "$1" retension
}
mt_rewind() {
mt -f "$1" rewind
}
mt_offline() {
mt -f "$1" offl
}
mt_status() {
mt -f "$1" status
}
# The main configuration file may override any of these variables
MT_BEGIN=mt_begin
MT_REWIND=mt_rewind
MT_OFFLINE=mt_offl
MT_STATUS=mt_status
# Insure `mail' is in PATH.
PATH="/usr/ucb:${PATH}"
export PATH
# Put startdate in the subject line of mailed report, since if it happens
# to run longer than 24 hours (as may be the case if someone forgets to put
# in the next volume of the tape in adequate time), the backup date won't
# appear too misleading.
startdate="`date`"
here="`pwd`"
# Save local hostname
localhost="`hostname | sed -e 's/\..*//' | tr A-Z a-z`"
# Produce a diagnostic output
message() {
if [ "$VERBOSE" != "" ]; then
if [ $VERBOSE -ge $1 ]; then
shift
echo "$@" >&2
fi
fi
}
# Bail out and exit.
bailout() {
echo "$PROGNAME: $*" >&2
exit 1
}
# Return current date
now() {
#IF_DATE_FORMAT_OK
date +%Y-%m-%d
#ELSE_DATE_FORMAT_OK
LC_ALL=C date | \
sed 's/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
/-[0-9]$/s/\([0-9]\)$/0\1/
/Jan/{s/Jan/01/p;q;}
/Feb/{s/Feb/02/p;q;}
/Mar/{s/Mar/03/p;q;}
/Apr/{s/Apr/04/p;q;}
/May/{s/May/05/p;q;}
/Jun/{s/Jun/06/p;q;}
/Jul/{s/Jul/07/p;q;}
/Aug/{s/Aug/08/p;q;}
/Sep/{s/Sep/09/p;q;}
/Oct/{s/Oct/10/p;q;}
/Nov/{s/Nov/11/p;q;}
/Dec/{s/Dec/12/p;q;}'
#ENDIF_DATE_FORMAT_OK
}
# Bail out if we don't have root privileges.
test_root() {
if [ ! -w ${ROOT_FS-/} ]; then
bailout "The backup must be run as root or else some files will fail to be dumped."
fi
}
advice() {
echo "Directory $1 is not found." >&2
cat >&2 <<EOF
The following directories and files are needed for the backup to function:
1. Directory with configuration files and file lists:
$CONFIGPATH
2. Directory for backup log files
$LOGPATH
3. Main configuration file
$CONFIGFILE
Please, create these and invoke the script again.
EOF
}
init_common() {
# Check if the necessary directories exist
if [ ! -d $CONFIGPATH ]; then
advice $CONFIGPATH
exit 1
fi
if [ ! -d $LOGPATH ]; then
if mkdir $LOGPATH; then
:
else
advice $LOGPATH
exit 1
fi
fi
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
if [ ! -r $CONFIGFILE ]; then
echo "$PROGNAME: cannot read $CONFIGFILE. Stop." >&2
exit 1
fi
. $CONFIGFILE
# Environment sanity check
test_root
if [ x"${ADMINISTRATOR}" = x ]; then
bailout "ADMINISTRATOR not defined"
fi
[ x"$TAR" = x ] && TAR=tar
[ x"$SLEEP_TIME" = x ] && SLEEP_TIME=60
if [ x$VOLNO_FILE = x ]; then
bailout "VOLNO_FILE not specified"
fi
if [ -r $DIRLIST ]; then
BACKUP_DIRS="$BACKUP_DIRS `cat $DIRLIST`"
fi
if [ -r $FILELIST ]; then
BACKUP_FILES="$BACKUP_FILES `cat $FILELIST`"
fi
if [ \( x"$BACKUP_DIRS" = x \) -a \( x"$BACKUP_FILES" = x \) ]; then
bailout "Neither BACKUP_DIRS nor BACKUP_FILES specified"
fi
if [ "$RSH" = "" ]; then
RSH=rsh
fi
POSIXLY_CORRECT=1
export POSIXLY_CORRECT
}
init_backup() {
init_common
TAR_PART1="${TAR} -c --format=gnu --multi-volume --one-file-system --sparse --volno-file=${VOLNO_FILE}"
if [ "x$XLIST" != x ]; then
TAR_PART1="${TAR_PART1} \`test -r $REMOTEBACKUPDIR/$XLIST && echo \"--exclude-from $REMOTEBACKUPDIR/$XLIST\"\`"
fi
if [ "$RSH_COMMAND" != "" ]; then
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
fi
if [ x$BLOCKING != x ]; then
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
fi
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
fi
# Set logfile name
# Logfile name should be in the form ``log-1993-03-18-level-0''
# They go in the directory `@sysconfdir@/log'.
# i.e. year-month-date. This format is useful for sorting by name, since
# logfiles are intentionally kept online for future reference.
LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
}
init_restore() {
init_common
# FIXME: Replace --list with --extract
TAR_PART1="${TAR} --extract --multi-volume"
if [ "$RSH_COMMAND" != "" ]; then
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
fi
if [ x$BLOCKING != x ]; then
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
fi
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
fi
LOGFILE="${LOGPATH}/restore-`now`"
}
wait_time() {
if [ "${1}" != "now" ]; then
if [ "${1}x" != "x" ]; then
spec="${1}"
else
spec="${BACKUP_HOUR}"
fi
pausetime="`date | awk -v spec=\"${spec}\" '
BEGIN {
split(spec, time, ":")
}
{
split($4, now, ":")
diff = 3600 * (time[1] - now[1]) + 60 * (time[2] - now[2]);
if (diff < 0)
diff += 3600 * 24
print diff
}'`"
clear
echo "${SLEEP_MESSAGE}"
sleep "${pausetime}"
fi
}
level_log_name() {
echo "$REMOTEBACKUPDIR/${1}.level-${2-$DUMP_LEVEL}"
}
# Prepare a temporary level logfile
# usage: make_level_log HOSTNAME
make_level_log() {
if [ "z${localhost}" != "z$1" ] ; then
$RSH "$1" mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
$RSH "$1" rm -f `level_log_name temp`
else
mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
rm -f `level_log_name temp`
fi
}
# Rename temporary log
# usage: flush_level_log HOSTNAME FSNAME
flush_level_log() {
message 10 "RENAME: `level_log_name temp` --> `level_log_name $2`"
if [ "z${localhost}" != "z$1" ] ; then
$RSH "$1" mv -f `level_log_name temp` "`level_log_name $2`"
else
mv -f `level_log_name temp` "`level_log_name $2`"
fi
}
# Return the timestamp of the last backup.
# usage: get_dump_time LEVEL
get_dump_time() {
ls -r ${LOGPATH}/log-*-level-$1 \
| head -1 \
| sed "s,.*log-\(.*\)-level-$1,\1,"
}
# Do actual backup on a host
# usage: backup_host HOSTNAME [TAR_ARGUMENTS]
backup_host() {
message 10 "ARGS: $@"
rhost=$1
shift
if [ "z${localhost}" != "z$rhost" ] ; then
$RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
else
# Using `sh -c exec' causes nested quoting and shell substitution
# to be handled here in the same way rsh handles it.
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
message 10 "CMD: $CMD"
sh -c "$CMD"
message 10 "RC: $?"
fi
}
print_level() {
if [ ${1-$DUMP_LEVEL} -eq 0 ]; then
echo "Full"
else
echo "Level ${1-$DUMP_LEVEL}"
fi
}
prev_level() {
print_level `expr $DUMP_LEVEL - 1` | tr A-Z a-z
}
remote_run() {
rhost=$1
shift
message 10 "REMOTE $rhost: $@"
if [ "x$rhost" != "x${localhost}" ] ; then
$RSH "${rhost}" "$@"
else
$*
fi
}
license() {
cat - <<EOF
This program is part of GNU tar
Copyright 2004, Free Software Foundation
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 1, 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.
EOF
}

9
scripts/dump-remind.in → scripts/dump-remind Normal file → Executable file
View File

@@ -13,12 +13,11 @@
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
export PATH
# Load library routines
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
. ${LIBPATH-@libexecdir@}/backup.sh
# Get definition of TAPE_FILE, VOLNO_FILE, and so on.
. /home/gd2/dump/backup-specs
MT_REWIND
MT_OFFLINE
mt -f "${TAPE_FILE}" rewind
mt -f "${TAPE_FILE}" offl
volno="`cat \"${VOLNO_FILE}\" 2> /dev/null`"
if [ $? -ne 0 ]; then

200
scripts/level-0 Normal file
View File

@@ -0,0 +1,200 @@
#!/bin/sh
#
# Run this script as root on the machine that has the tape drive, to make a
# full (level-0) dump.
#
# If you give `now' as an argument, the dump is done immediately.
# Otherwise, it waits until 1am, or until the hour given as argument.
# Specify the hour as a number from 0 to 23.
#
# You must edit the file `backup-specs' to set the parameters for your site.
# Useful for backup-specs, in case things have to be done slightly
# differently for different dump levels.
DUMP_LEVEL=0
# Insure `mail' is in PATH.
PATH="/usr/ucb:${PATH}"
export PATH
# This is not the most reliable test in the world. The following might be
# more predictable:
#
# whoami="`whoami`"
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
# if [ "${euid}" != 0 ]; then ...
#
if [ ! -w / ]; then
echo "The backup must be run as root or else some files will fail to be dumped."
exit 1
fi
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
. ./backup-specs
# Maybe sleep until around specified or default hour.
if [ "${1}" != "now" ]; then
if [ "${1}x" != "x" ]; then
spec="${1}"
else
spec="${BACKUP_HOUR}"
fi
pausetime="`date | awk '
{
hr = substr($4, 1, 2);
mn = substr($4, 4, 2);
if((hr + 0) < (spec + 0))
print 3600 * (spec - hr) - 60 * mn;
else
print 3600 * (spec + (24 - hr)) - 60 * mn;
}' spec=\"${spec}\"`"
clear
echo "${SLEEP_MESSAGE}"
sleep "${pausetime}"
fi
# start doing things
# Put startdate in the subject line of mailed report, since if it happens
# to run longer than 24 hours (as may be the case if someone forgets to put
# in the next volume of the tape in adequate time), the backup date won't
# appear too misleading.
startdate="`date`"
here="`pwd`"
# Logfile name should be in the form ``log-1993-03-18-level-0''
# They go in the subdirectory `log' of the current directory.
# i.e. year-month-date. This format is useful for sorting by name, since
# logfiles are intentionally kept online for future reference.
LOGFILE="log/log-`date | sed -ne '
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
/-[0-9]$/s/\([0-9]\)$/0\1/
/Jan/{s/Jan/01/p;q;}
/Feb/{s/Feb/02/p;q;}
/Mar/{s/Mar/03/p;q;}
/Apr/{s/Apr/04/p;q;}
/May/{s/May/05/p;q;}
/Jun/{s/Jun/06/p;q;}
/Jul/{s/Jul/07/p;q;}
/Aug/{s/Aug/08/p;q;}
/Sep/{s/Sep/09/p;q;}
/Oct/{s/Oct/10/p;q;}
/Nov/{s/Nov/11/p;q;}
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
localhost="`hostname | sed -e 's/\..*//'`"
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
fi
# Make sure the log file did not already exist. Create it.
if [ -f "${LOGFILE}" ] ; then
echo "Log file ${LOGFILE} already exists." 1>&2
exit 1
else
touch "${LOGFILE}"
fi
# Most everything below here is run in a subshell for which all output is
# piped through `tee' to the logfile. Doing this, instead of having
# multiple pipelines all over the place, is cleaner and allows access to
# the exit value from various commands more easily.
(
# Caveat: Some version of `mt' require `-t', not `-f'.
mt -f "${TAPE_FILE}" rewind
rm -f "${VOLNO_FILE}"
set - ${BACKUP_DIRS}
while [ $# -ne 0 ] ; do
date="`date`"
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
# This filename must be absolute; it is opened on the machine that runs tar.
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
TAR_PART3="--label='Full backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
echo "Backing up ${1} at ${date}"
# Actually back things up.
if [ "z${localhost}" != "z${remotehost}" ] ; then
rsh "${remotehost}" mkdir /etc/tar-backup > /dev/null 2>&1
rsh "${remotehost}" rm -f /etc/tar-backup/temp.level-0
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
else
mkdir /etc/tar-backup > /dev/null 2>&1
rm -f /etc/tar-backup/temp.level-0
# Using `sh -c exec' causes nested quoting and shell substitution
# to be handled here in the same way rsh handles it.
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
fi
# `rsh' doesn't exit with the exit status of the remote command. What
# stupid lossage. TODO: think of a reliable workaround.
if [ $? -ne 0 ] ; then
echo "Backup of ${1} failed." 1>&2
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
if [ "z${localhost}" != "z${remotehost}" ] ; then
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
else
mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
fi
fi
${TAPE_STATUS}
sleep 60
shift
done
# Dump any individual files requested.
if [ "x${BACKUP_FILES}" != "x" ] ; then
date="`date`"
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
TAR_PART3="--label='Full backup of miscellaneous files at ${date}'"
mkdir /etc/tar-backup > /dev/null 2>&1
rm -f /etc/tar-backup/temp.level-0
echo "Backing up miscellaneous files at ${date}"
# Using `sh -c exec' causes nested quoting and shell substitution
# to be handled here in the same way rsh handles it.
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
# `rsh' doesn't exit with the exit status of the remote command. What
# lossage. TODO: think of a reliable workaround.
if [ $? -ne 0 ] ; then
echo "Backup of miscellaneous files failed."
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0
fi
${TAPE_STATUS}
else
echo "No miscellaneous files specified"
fi
# Caveat: some versions of `mt' use `-t' instead of `-f'.
mt -f "${TAPE_FILE}" rewind
mt -f "${TAPE_FILE}" offl
) 2>&1 | tee -a "${LOGFILE}"
echo "Sending the dump log to ${ADMINISTRATOR}"
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
# eof

203
scripts/level-1 Normal file
View File

@@ -0,0 +1,203 @@
#!/bin/sh
#
# Run this script as root on the machine that has the tape drive, to make a
# level-1 dump containing all files changed since the last full dump.
#
# If you give `now' as an argument, the dump is done immediately.
# Otherwise, it waits until 1am.
#
# You must edit the file `backup-specs' to set the parameters for your site.
# Useful for backup-specs, in case things have to be done slightly
# differently for different dump levels.
DUMP_LEVEL=1
# Insure `mail' is in PATH.
PATH="/usr/ucb:${PATH}"
export PATH
# This is not the most reliable test in the world. The following might be
# more predictable:
#
# whoami="`whoami`"
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
# if [ "${euid}" != 0 ]; then ...
#
if [ ! -w / ]; then
echo "The backup must be run as root or else some files will fail to be dumped."
exit 1
fi
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
. ./backup-specs
# Maybe sleep until around specified or default hour.
if [ "z${1}" != "znow" ]; then
if [ "${1}x" != "x" ]; then
spec="${1}"
else
spec="${BACKUP_HOUR}"
fi
pausetime="`date | awk '
{
hr = substr($4, 1, 2);
mn = substr($4, 4, 2);
if((hr + 0) < (spec + 0))
print 3600 * (spec - hr) - 60 * mn;
else
print 3600 * (spec + (24 - hr)) - 60 * mn;
}' spec=\"${spec}\"`"
clear
echo "${SLEEP_MESSAGE}"
sleep "${pausetime}"
fi
# start doing things
# Put startdate in the subject line of mailed report, since if it happens
# to run longer than 24 hours (as may be the case if someone forgets to put
# in the next volume of the tape in adequate time), the backup date won't
# appear too misleading.
startdate="`date`"
here="`pwd`"
# Logfile name should be in the form ``log-1993-03-18-level-1''
# They go in the subdirectory `log' of the current directory.
# i.e. year-month-date. This format is useful for sorting by name, since
# logfiles are intentionally kept online for future reference.
LOGFILE="log/log-`date | sed -ne '
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
/-[0-9]$/s/\([0-9]\)$/0\1/
/Jan/{s/Jan/01/p;q;}
/Feb/{s/Feb/02/p;q;}
/Mar/{s/Mar/03/p;q;}
/Apr/{s/Apr/04/p;q;}
/May/{s/May/05/p;q;}
/Jun/{s/Jun/06/p;q;}
/Jul/{s/Jul/07/p;q;}
/Aug/{s/Aug/08/p;q;}
/Sep/{s/Sep/09/p;q;}
/Oct/{s/Oct/10/p;q;}
/Nov/{s/Nov/11/p;q;}
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
localhost="`hostname | sed -e 's/\..*//'`"
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
fi
# Make sure the log file did not already exist. Create it.
if [ -f "${LOGFILE}" ] ; then
echo "Log file ${LOGFILE} already exists." 1>&2
exit 1
else
touch "${LOGFILE}"
fi
# Most everything below here is run in a subshell for which all output is
# piped through `tee' to the logfile. Doing this, instead of having
# multiple pipelines all over the place, is cleaner and allows access to
# the exit value from various commands more easily.
(
# Caveat: Some version of `mt' require `-t', not `-f'.
mt -f "${TAPE_FILE}" rewind
rm -f "${VOLNO_FILE}"
set - ${BACKUP_DIRS}
while [ $# -ne 0 ] ; do
date="`date`"
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
# This filename must be absolute; it is opened on the machine that runs tar.
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
TAR_PART3="--label='level 1 backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
echo "Backing up ${1} at ${date}"
echo "Last full dump on this filesystem:"
if [ "z${remotehost}" != "z${localhost}" ] ; then
rsh "${remotehost}" "ls -l /etc/tar-backup/${fsname}.level-0; \
cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1"
else
ls -l "/etc/tar-backup/${fsname}.level-0"
cp "/etc/tar-backup/${fsname}.level-0" /etc/tar-backup/temp.level-1
fi
# Actually back things up.
if [ "z${remotehost}" != "z${localhost}" ] ; then
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
else
# Using `sh -c exec' causes nested quoting and shell substitution
# to be handled here in the same way rsh handles it.
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
fi
# `rsh' doesn't exit with the exit status of the remote command. What
# stupid lossage. TODO: think of a reliable workaround.
if [ $? -ne 0 ] ; then
echo "Backup of ${1} failed."
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
if [ "z${localhost}" != "z${remotehost}" ] ; then
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
else
mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
fi
fi
${TAPE_STATUS}
sleep 60
shift
done
# Dump any individual files requested.
if [ "x${BACKUP_FILES}" != "x" ] ; then
date="`date`"
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'"
echo "Backing up miscellaneous files at ${date}"
echo "Last full dump of these files:"
ls -l /etc/tar-backup/misc.level-0
rm -f /etc/tar-backup/temp.level-1
cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1
# Using `sh -c exec' causes nested quoting and shell substitution
# to be handled here in the same way rsh handles it.
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
if [ $? -ne 0 ] ; then
echo "Backup of miscellaneous files failed." 1>&2
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1
fi
${TAPE_STATUS}
else
echo "No miscellaneous files specified"
fi
# Caveat: some versions of `mt' use `-t' instead of `-f'.
mt -f "${TAPE_FILE}" rewind
mt -f "${TAPE_FILE}" offl
) 2>&1 | tee -a "${LOGFILE}"
echo "Sending the dump log to ${ADMINISTRATOR}"
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
# eof

View File

@@ -1,224 +0,0 @@
#! /bin/sh
# This program is part of GNU tar
# Copyright 2004, Free Software Foundation
#
# 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 1, 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.
# Load library routines
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
. ${LIBPATH-@libexecdir@}/backup.sh
usage() {
cat - <<EOF
usage: $PROGNAME [OPTIONS] [PATTERN [PATTERN...]]
Options are:
-l, --level=LEVEL Start restoring from backup level LEVEL (default $DUMP_LEVEL).
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
Informational options:
-h, --help Display this help message.
-L, --license Display program license.
-V, --version Display program version.
Send bug reports to @PACKAGE_BUGREPORT@.
EOF
}
unset PATTERN
DUMP_LEVEL=0
CMDLINE="$0 $@"
for opt
do
if [ -z "$prev" ]; then
option=$opt
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
else
option="${prev}=$opt"
prev=""
optarg=$opt
fi
case $option in
--l=*|--le=*|--lev=*|--leve=*|--level=*)
DUMP_LEVEL=$optarg
;;
-l|--l|--le|--lev|--leve|--level)
prev=$option
;;
--verb=*|--verbo=*|--verbos=*|--verbose=*)
VERBOSE=$optarg
;;
-v|--verb|--verbo|--verbos|--verbose)
VERBOSE=100
;;
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "restore (@PACKAGE@ @VERSION@)"
exit 0;;
-L|--li|--lic|--lice|--licen|--licens|--license)
license
exit;;
-h|--h|--he|--hel|--help)
usage
exit;;
-*) bailout "Unknown option $opt. Try $PROGNAME --help for more info.";;
*) if [ -z "$PATTERN" ]; then
PATTERN=$opt
else
PATTERN="$PATTERN|$opt"
fi
;;
esac
done
init_restore
cat > $LOGFILE <<EOF
This file contains any messages produced by $PROGNAME.
It was created by GNU $PROGNAME, from @PACKAGE@ (@VERSION@).
Invocation command line was
\$ $CMDLINE
EOF
restore_fs()
{
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
if [ -z "$remotehost" ]; then
remotehost=$localhost
fi
message 10 "fs=$fs"
message 10 "fsname=$fsname"
message 10 "remotehost=$remotehost"
LOGPAT="`level_log_name ${fsname} '[0-9]'`"
PREFIX="`level_log_name ${fsname} ''`"
message 10 LOGPAT=$LOGPAT
message 10 PREFIX=$PREFIX
LEVELS=`remote_run "${remotehost}" ls $LOGPAT |
sed "s,$PREFIX,," | sort -n`
message 10 "LEVELS=$LEVELS"
echo "Starting restore of ${1} at level $DUMP_LEVEL."
for level in $LEVELS
do
if [ $level -lt $DUMP_LEVEL ]; then
message 10 "Skipping level $level"
continue;
fi
message 10 "Restoring level $level"
DATE=`get_dump_time $level`
FILE="`level_log_name ${fsname} ${level}`"
message 10 "FILE=$FILE"
LABEL="`print_level $level` backup of ${fs} on ${remotehost} at ${DATE}"
${RESTORE_BEGIN-:} $level $remotehost $fs $fsname
backup_host ${remotehost} \
"--listed=`level_log_name $fs $level`" \
"--label=\"$LABEL\"" \
-C ${ROOT_FS-/}$fs
${RESTORE_END-:} $level $remotehost $fs $fsname
done
}
restore_files()
{
LOGPAT="`level_log_name MISC '[0-9]'`"
PREFIX="`level_log_name MISC ''`"
message 10 LOGPAT=$LOGPAT
message 10 PREFIX=$PREFIX
LEVELS=`remote_run "${localhost}" ls $LOGPAT | sed "s,$PREFIX,," | sort -n`
message 10 "LEVELS=$LEVELS"
echo "Starting restore of miscellaneous files at level $DUMP_LEVEL."
for level in $LEVELS
do
if [ $level -lt $DUMP_LEVEL ]; then
message 10 "Skipping level $level"
continue;
fi
message 10 "Restoring level $level"
DATE=`get_dump_time $level`
FILE="`level_log_name MISC ${level}`"
message 10 "FILE=$FILE"
LABEL="`print_level $level` backup of miscellaneous files at ${DATE}"
${RESTORE_BEGIN-:} $level $localhost MISC MISC
backup_host ${localhost} \
"--listed=`level_log_name MISC $level`" \
"--label=\"$LABEL\"" \
-C ${ROOT_FS-/} $@
${RESTORE_END-:} $level $localhost MISC MISC
done
}
# Operation Overwiew:
#
# 1. Determine the time of the last backup
# 2. Create list of incremental listings to process
# 3. For each filesystem:
# 3.1. Start at the requested dump level (default 0) and proceed up to
# the last available level:
# 3.1.1 Deduce the volume label
# 3.1.2. Invoke [rsh] tar --listed=FILE --label=LABEL [opts] -xf $TAPE_FILE
# 4. End
(message 1 "Preparing for restore"
message 1 "processing backup directories"
for dir in ${BACKUP_DIRS}
do
message 1 "Processing $dir"
case $dir in
${PATTERN-*}) restore_fs $dir;;
esac
done
if [ "x${BACKUP_FILES}" != "x" ] ; then
message 1 "processing miscellaneous files"
if [ -z "$PATTERN" ]; then
restore_files
else
RESTORE_FILES=""
for file in ${BACKUP_FILES}
do
rel_file=`expr $file : '/\(.*\)'`
case $file in
$PATTERN) if [ -z "$RESTORE_FILES" ]; then
RESTORE_FILES="$rel_file"
else
RESTORE_FILES="$RESTORE_FILES $rel_file"
fi;;
esac
done
[ -z "$RESTORE_FILES" ] || restore_files $RESTORE_FILES
fi
fi) 2>&1 | tee -a "${LOGFILE}"
# EOF

42
scripts/weekly.new Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh
# start doing things
TOBACKUP="albert:/"
HOST=`hostname | sed 's/\..*//'`
TAPEFILE=/dev/rfd0a
LOGFILE=tar-out
BLOCKING=20
TAR_PART1="/usr/local/bin/tar clbfVM $BLOCKING"
rm -f $LOGFILE
mt -f $TAPEFILE rewind
host=`echo $TOBACKUP | sed 's/:.*$//'`;
fs=`echo $TOBACKUP | sed 's/^.*://'`;
date=`date`;
fsname=`echo $TOBACKUP | sed 's/\//:/g'`
TAR_PART2="'Weekly backup of $fs on $host at $date' -C $fs ."
echo Backing up $TOBACKUP at $date | tee -a $LOGFILE
# Actually back things up.
if [ $HOST != $host ] ; then
rsh $host $TAR_PART1 $HOST:$TAPEFILE $TAR_PART2
else
sh -c "exec $TAR_PART1 $TAPEFILE $TAR_PART2"
fi
if [ $? -ne 0 ] ; then
echo Backup of $TOBACKUP failed. | tee -a $LOGFILE
echo mts at time of failure | tee -a $LOGFILE
mts -t $TAPEFILE | tee -a $LOGFILE
# I'm assuming that the tar will have written an empty
# file to the tape, otherwise I should do a cat here.
else
echo $date > $fsname.lasttar
fi
sleep 60;
mt -f $TAPEFILE rewind
mt -f $TAPEFILE offl

View File

@@ -1,7 +0,0 @@
Makefile.in
Makefile
localedir.h
rmt
tar
.deps
.gdbinit

View File

@@ -1,61 +1,51 @@
# Makefile for GNU tar sources.
# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 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 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.
## 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.
# 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.
AUTOMAKE_OPTIONS = gnits ansi2knr
bin_PROGRAMS = tar
libexec_PROGRAMS = @RMT@
EXTRA_PROGRAMS = rmt
noinst_HEADERS = arith.h common.h rmt.h system.h tar.h
rmt_SOURCES = rmt.c
tar_SOURCES = \
buffer.c\
compare.c\
create.c\
delete.c\
extract.c\
xheader.c\
incremen.c\
list.c\
mangle.c\
misc.c\
names.c\
rtapelib.c\
sparse.c\
system.c\
tar.c\
update.c\
utf8.c
tar_SOURCES = arith.c buffer.c compare.c create.c delete.c extract.c \
incremen.c list.c mangle.c misc.c names.c open3.c rtapelib.c tar.c update.c
localedir = $(datadir)/locale
INCLUDES = -I$(top_srcdir)/lib -I../lib
INCLUDES = -I../intl -I$(top_srcdir)/lib
LDADD = ../lib/libtar.a @INTLLIBS@
localedir = $(prefix)/@DATADIRNAME@/locale
DISTCLEANFILES = localedir.h
localedir.h : Makefile
echo '#define LOCALEDIR "$(localedir)"' >$@
echo "#ifndef DEFAULT_RMT_COMMAND" >> $@
echo "# define DEFAULT_RMT_COMMAND \"$(libexecdir)/`echo \"rmt\" | sed 's,^.*/,,;$(transform)'`$(EXEEXT)\"" >> $@
echo "#endif" >> $@
tar.o: tar.c
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c $(srcdir)/tar.c
rmt.o tar.o : localedir.h
tar._o: tar._c
@rm -f _tar.c
@ln tar._c _tar.c
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c _tar.c
@mv _tar.o $@
@rm _tar.c
LDADD = ../lib/libtar.a $(LIBINTL)
rmt.o: rmt.c
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c $(srcdir)/rmt.c
rmt_LDADD = $(LDADD) $(LIB_SETSOCKOPT)
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
rmt._o: rmt._c
@rm -f _rmt.c
@ln rmt._c _rmt.c
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c _rmt.c
@mv _rmt.o $@
@rm _rmt.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,5 @@
/* Common declarations for the tar program.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
2003, 2004 Free Software Foundation, Inc.
Copyright (C) 1988, 92, 93, 94, 96, 97 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
@@ -15,7 +13,7 @@
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. */
59 Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Declare the GNU tar archive format. */
#include "tar.h"
@@ -29,11 +27,19 @@
#define UNAME_FIELD_SIZE 32
#define GNAME_FIELD_SIZE 32
/* FIXME */
#define MAXOCTAL11 017777777777L
#define MAXOCTAL7 07777777
/* POSIX specified symbols currently unused are undefined here. */
#undef TSUID
#undef TSGID
#undef TSVTX
#undef TUREAD
#undef TUWRITE
#undef TUEXEC
#undef TGREAD
#undef TGWRITE
#undef TGEXEC
#undef TOREAD
#undef TOWRITE
#undef TOEXEC
/* Some various global definitions. */
@@ -44,10 +50,10 @@
# define TTY_NAME "/dev/tty"
#endif
/* GLOBAL is defined to empty in tar.c only, and left alone in other *.c
/* GLOBAL is defined to empty in `tar.c' only, and left alone in other `*.c'
modules. Here, we merely set it to "extern" if it is not already set.
GNU tar does depend on the system loader to preset all GLOBAL variables to
neutral (or zero) values, explicit initialization is usually not done. */
neutral (or zero) values, explicit initialisation is usually not done. */
#ifndef GLOBAL
# define GLOBAL extern
#endif
@@ -66,34 +72,24 @@ GLOBAL int exit_status;
writes a message on stderr and aborts immediately, with another message
line telling so. USAGE_ERROR works like FATAL_ERROR except that the
other message line suggests trying --help. All four macros accept a
single argument of the form ((0, errno, _("FORMAT"), Args...)). errno
is zero when the error is not being detected by the system. */
single argument of the form ((0, errno, _("FORMAT"), Args...)). `errno'
is `0' when the error is not being detected by the system. */
#define WARN(Args) \
error Args
#define ERROR(Args) \
(error Args, exit_status = TAREXIT_FAILURE)
#define FATAL_ERROR(Args) \
(error Args, fatal_exit ())
(error Args, error (TAREXIT_FAILURE, 0, \
_("Error is not recoverable: exiting now")), 0)
#define USAGE_ERROR(Args) \
(error Args, usage (TAREXIT_FAILURE))
#include "arith.h"
#include <backupfile.h>
#include <exclude.h>
#include <full-write.h>
#include <modechange.h>
#include <quote.h>
#include <safe-read.h>
#include <timespec.h>
/* Log base 2 of common values. */
#define LG_8 3
#define LG_64 6
#define LG_256 8
(error Args, usage (TAREXIT_FAILURE), 0)
/* Information gleaned from the command line. */
#include "arith.h"
#include "modechange.h"
/* Name of this program. */
GLOBAL const char *program_name;
@@ -125,12 +121,10 @@ GLOBAL char filename_terminator;
not have _option in their name, even if their values is derived from
option decoding, as these are especially important in tar. */
GLOBAL int blocking_factor;
GLOBAL size_t record_size;
GLOBAL int record_size;
GLOBAL bool absolute_names_option;
/* Display file times in UTC */
GLOBAL bool utc_option;
/* Boolean value. */
GLOBAL int absolute_names_option;
/* This variable tells how to interpret newer_mtime_option, below. If zero,
files get archived if their mtime is not less than newer_mtime_option.
@@ -138,61 +132,54 @@ GLOBAL bool utc_option;
than newer_mtime_option. */
GLOBAL int after_date_option;
GLOBAL bool atime_preserve_option;
/* Boolean value. */
GLOBAL int atime_preserve_option;
GLOBAL bool backup_option;
/* Boolean value. */
GLOBAL int backup_option;
/* Type of backups being made. */
GLOBAL enum backup_type backup_type;
/* Boolean value. */
GLOBAL int block_number_option;
GLOBAL bool block_number_option;
GLOBAL bool checkpoint_option;
/* Boolean value. */
GLOBAL int checkpoint_option;
/* Specified name of compression program, or "gzip" as implied by -z. */
GLOBAL const char *use_compress_program_option;
GLOBAL bool dereference_option;
/* Boolean value. */
GLOBAL int dereference_option;
/* Print a message if not all links are dumped */
GLOBAL int check_links_option;
/* Patterns that match file names to be excluded. */
GLOBAL struct exclude *excluded;
/* Boolean value. */
GLOBAL int exclude_option;
/* Specified file containing names to work on. */
GLOBAL const char *files_from_option;
GLOBAL bool force_local_option;
/* Boolean value. */
GLOBAL int force_local_option;
/* Specified value to be put into tar file in place of stat () results, or
just -1 if such an override should not take place. */
GLOBAL gid_t group_option;
GLOBAL bool ignore_failed_read_option;
/* Boolean value. */
GLOBAL int ignore_failed_read_option;
GLOBAL bool ignore_zeros_option;
/* Boolean value. */
GLOBAL int ignore_zeros_option;
GLOBAL bool incremental_option;
/* Boolean value. */
GLOBAL int incremental_option;
/* Specified name of script to run at end of each tape change. */
GLOBAL const char *info_script_option;
GLOBAL bool interactive_option;
/* Boolean value. */
GLOBAL int interactive_option;
/* If nonzero, extract only Nth occurrence of each named file */
GLOBAL uintmax_t occurrence_option;
enum old_files
{
DEFAULT_OLD_FILES, /* default */
NO_OVERWRITE_DIR_OLD_FILES, /* --no-overwrite-dir */
OVERWRITE_OLD_FILES, /* --overwrite */
UNLINK_FIRST_OLD_FILES, /* --unlink-first */
KEEP_OLD_FILES, /* --keep-old-files */
KEEP_NEWER_FILES /* --keep-newer-files */
};
GLOBAL enum old_files old_files_option;
/* Boolean value. */
GLOBAL int keep_old_files_option;
/* Specified file name for incremental list. */
GLOBAL const char *listed_incremental_option;
@@ -200,82 +187,83 @@ GLOBAL const char *listed_incremental_option;
/* Specified mode change string. */
GLOBAL struct mode_change *mode_option;
GLOBAL bool multi_volume_option;
/* Boolean value. */
GLOBAL int multi_volume_option;
/* The same variable holds the time, whether mtime or ctime. Just fake a
/* The same variable hold the time, whether mtime or ctime. Just fake a
non-existing option, for making the code clearer, elsewhere. */
#define newer_ctime_option newer_mtime_option
/* Specified threshold date and time. Files having an older time stamp
do not get archived (also see after_date_option above). */
GLOBAL struct timespec newer_mtime_option;
/* Specified threshold date and time. Files having a more recent timestamp
get archived (also see after_date_option above). If left to zero, it may
be interpreted as very low threshold, just usable as such. */
GLOBAL time_t newer_mtime_option;
/* Return true if newer_mtime_option is initialized. */
#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
/* Boolean value. */
GLOBAL int no_recurse_option;
/* Return true if the struct stat ST's M time is less than
newer_mtime_option. */
#define OLDER_STAT_TIME(st, m) \
((st).st_##m##time < newer_mtime_option.tv_sec \
|| ((st).st_##m##time == newer_mtime_option.tv_sec \
&& TIMESPEC_NS ((st).st_##m##tim) < newer_mtime_option.tv_nsec))
/* Boolean value. */
GLOBAL int numeric_owner_option;
/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
GLOBAL int recursion_option;
GLOBAL bool numeric_owner_option;
GLOBAL bool one_file_system_option;
/* Boolean value. */
GLOBAL int one_file_system_option;
/* Specified value to be put into tar file in place of stat () results, or
just -1 if such an override should not take place. */
GLOBAL uid_t owner_option;
GLOBAL bool recursive_unlink_option;
/* Boolean value. */
GLOBAL int recursive_unlink_option;
GLOBAL bool read_full_records_option;
/* Boolean value. */
GLOBAL int read_full_records_option;
GLOBAL bool remove_files_option;
/* Specified rmt command. */
GLOBAL const char *rmt_command_option;
/* Boolean value. */
GLOBAL int remove_files_option;
/* Specified remote shell command. */
GLOBAL const char *rsh_command_option;
GLOBAL bool same_order_option;
/* Boolean value. */
GLOBAL int same_order_option;
/* If positive, preserve ownership when extracting. */
/* Boolean value. */
GLOBAL int same_owner_option;
/* If positive, preserve permissions when extracting. */
/* Boolean value. */
GLOBAL int same_permissions_option;
/* When set, strip the given number of path elements from the file name
before extracting */
GLOBAL size_t strip_path_elements;
/* Boolean value. */
GLOBAL int show_omitted_dirs_option;
GLOBAL bool show_omitted_dirs_option;
/* Boolean value. */
GLOBAL int sparse_option;
GLOBAL bool sparse_option;
GLOBAL bool starting_file_option;
/* Boolean value. */
GLOBAL int starting_file_option;
/* Specified maximum byte length of each tape volume (multiple of 1024). */
GLOBAL tarlong tape_length_option;
GLOBAL bool to_stdout_option;
/* Boolean value. */
GLOBAL int to_stdout_option;
GLOBAL bool totals_option;
/* Boolean value. */
GLOBAL int totals_option;
GLOBAL bool touch_option;
/* Boolean value. */
GLOBAL int touch_option;
/* Boolean value. */
GLOBAL int unlink_first_option;
/* Count how many times the option has been set, multiple setting yields
more verbose behavior. Value 0 means no verbosity, 1 means file name
only, 2 means file name and all attributes. More than 2 is just like 2. */
GLOBAL int verbose_option;
GLOBAL bool verify_option;
/* Boolean value. */
GLOBAL int verify_option;
/* Specified name of file containing the volume number. */
GLOBAL const char *volno_file_option;
@@ -289,17 +277,13 @@ GLOBAL const char *volume_label_option;
GLOBAL int archive;
/* Nonzero when outputting to /dev/null. */
GLOBAL bool dev_null_output;
GLOBAL int dev_null_output;
/* Timestamp for when we started execution. */
#if HAVE_CLOCK_GETTIME
GLOBAL struct timespec start_timespec;
# define start_time (start_timespec.tv_sec)
#else
GLOBAL time_t start_time;
#endif
/* Name of file for the current archive entry. */
GLOBAL char *current_file_name;
GLOBAL struct tar_stat_info current_stat_info;
/* Name of link for the current archive entry. */
GLOBAL char *current_link_name;
/* List of tape drive names, number of such tape drives, allocated number,
and current cursor in list. */
@@ -308,29 +292,32 @@ GLOBAL int archive_names;
GLOBAL int allocated_archive_names;
GLOBAL const char **archive_name_cursor;
/* Output index file name. */
GLOBAL char const *index_file_name;
/* Structure for keeping track of filenames and lists thereof. */
struct name
{
struct name *next;
size_t length; /* cached strlen(name) */
uintmax_t found_count; /* number of times a matching file has
been found */
int isdir;
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 */
int change_dir; /* set with the -C option */
char const *dir_contents; /* for incremental_option */
char *change_dir; /* set with the -C option */
char *dir_contents; /* for incremental_option */
char fake; /* dummy entry */
char name[1];
};
GLOBAL struct name *namelist; /* points to first name in list */
GLOBAL struct name *namelast; /* points to last name in list */
/* Obnoxious test to see if dimwit is trying to dump the archive. */
GLOBAL dev_t ar_dev;
GLOBAL ino_t ar_ino;
/* Pointer to the start of the scratch space. */
struct sp_array
{
off_t offset;
int numbytes;
};
GLOBAL struct sp_array *sparsearray;
/* Initial size of the sparsearray. */
GLOBAL int sp_array_size;
/* Declarations for each module. */
@@ -349,98 +336,58 @@ extern enum access_mode access_mode;
extern FILE *stdlis;
extern char *save_name;
extern off_t save_sizeleft;
extern off_t save_totsize;
extern bool write_archive_to_stdout;
extern long save_sizeleft;
extern long save_totsize;
extern int write_archive_to_stdout;
size_t available_space_after (union block *);
off_t current_block_ordinal (void);
void close_archive (void);
void closeout_volume_number (void);
union block *find_next_block (void);
void flush_read (void);
void flush_write (void);
void flush_archive (void);
void init_volume_number (void);
void open_archive (enum access_mode);
void print_total_written (void);
void reset_eof (void);
void set_next_block_after (union block *);
void clear_read_error_count (void);
void xclose (int fd);
void archive_write_error (ssize_t) __attribute__ ((noreturn));
void archive_read_error (void);
int available_space_after PARAMS ((union block *));
long current_block_ordinal PARAMS ((void));
void close_archive PARAMS ((void));
void closeout_volume_number PARAMS ((void));
union block *find_next_block PARAMS ((void));
void flush_read PARAMS ((void));
void flush_write PARAMS ((void));
void flush_archive PARAMS ((void));
void init_total_written PARAMS ((void));
void init_volume_number PARAMS ((void));
void open_archive PARAMS ((enum access_mode));
void print_total_written PARAMS ((void));
void reset_eof PARAMS ((void));
void set_next_block_after PARAMS ((union block *));
/* Module create.c. */
enum dump_status
{
dump_status_ok,
dump_status_short,
dump_status_fail,
dump_status_not_implemented
};
bool file_dumpable_p (struct tar_stat_info *);
void create_archive (void);
void pad_archive (off_t size_left);
void dump_file (char *, int, dev_t);
union block *start_header (struct tar_stat_info *st);
void finish_header (struct tar_stat_info *, union block *, off_t);
void simple_finish_header (union block *header);
union block *start_private_header (const char *name, size_t size);
void write_eot (void);
void check_links (void);
#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
void gid_to_chars (gid_t, char *, size_t);
void major_to_chars (major_t, char *, size_t);
void minor_to_chars (minor_t, char *, size_t);
void mode_to_chars (mode_t, char *, size_t);
void off_to_chars (off_t, char *, size_t);
void size_to_chars (size_t, char *, size_t);
void time_to_chars (time_t, char *, size_t);
void uid_to_chars (uid_t, char *, size_t);
void uintmax_to_chars (uintmax_t, char *, size_t);
void string_to_chars (char *, char *, size_t);
void create_archive PARAMS ((void));
void dump_file PARAMS ((char *, int, int));
void finish_header PARAMS ((union block *));
void to_oct PARAMS ((long, int, char *));
void write_eot PARAMS ((void));
/* Module diffarch.c. */
extern bool now_verifying;
extern int now_verifying;
void diff_archive (void);
void diff_init (void);
void verify_volume (void);
void diff_archive PARAMS ((void));
void diff_init PARAMS ((void));
void verify_volume PARAMS ((void));
/* Module extract.c. */
extern bool we_are_root;
void extr_init (void);
void extract_archive (void);
void extract_finish (void);
void fatal_exit (void) __attribute__ ((noreturn));
void extr_init PARAMS ((void));
void extract_archive PARAMS ((void));
void apply_delayed_set_stat PARAMS ((void));
/* Module delete.c. */
void delete_archive_members (void);
void delete_archive_members PARAMS ((void));
/* Module incremen.c. */
char *get_directory_contents (char *, dev_t);
void read_directory_file (void);
void write_directory_file (void);
void gnu_restore (char const *);
void collect_and_sort_names PARAMS ((void));
char *get_directory_contents PARAMS ((char *, int));
void write_dir_file PARAMS ((void));
void gnu_restore PARAMS ((int));
void write_directory_file PARAMS ((void));
/* Module list.c. */
@@ -448,245 +395,77 @@ enum read_header
{
HEADER_STILL_UNREAD, /* for when read_header has not been called */
HEADER_SUCCESS, /* header successfully read and checksummed */
HEADER_SUCCESS_EXTENDED, /* likewise, but we got an extended header */
HEADER_ZERO_BLOCK, /* zero block where header expected */
HEADER_END_OF_FILE, /* true end of file while header expected */
HEADER_FAILURE /* ill-formed header, or bad checksum */
};
struct xheader
{
struct obstack *stk;
size_t size;
char *buffer;
};
GLOBAL struct xheader extended_header;
extern union block *current_header;
extern struct stat current_stat;
extern enum archive_format current_format;
extern size_t recent_long_name_blocks;
extern size_t recent_long_link_blocks;
void decode_header (union block *, struct tar_stat_info *,
enum archive_format *, int);
#define STRINGIFY_BIGINT(i, b) \
stringify_uintmax_t_backwards ((uintmax_t) (i), (b) + UINTMAX_STRSIZE_BOUND)
char *stringify_uintmax_t_backwards (uintmax_t, char *);
char const *tartime (time_t);
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
#define MODE_FROM_HEADER(where) mode_from_header (where, sizeof (where))
#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
gid_t gid_from_header (const char *, size_t);
major_t major_from_header (const char *, size_t);
minor_t minor_from_header (const char *, size_t);
mode_t mode_from_header (const char *, size_t);
off_t off_from_header (const char *, size_t);
size_t size_from_header (const char *, size_t);
time_t time_from_header (const char *, size_t);
uid_t uid_from_header (const char *, size_t);
uintmax_t uintmax_from_header (const char *, size_t);
void list_archive (void);
void print_for_mkdir (char *, int, mode_t);
void print_header (struct tar_stat_info *, off_t);
void read_and (void (*) (void));
enum read_header read_header (bool);
void skip_file (off_t);
void skip_member (void);
void decode_header PARAMS ((union block *, struct stat *,
enum archive_format *, int));
long from_oct PARAMS ((int, char *));
void list_archive PARAMS ((void));
void print_for_mkdir PARAMS ((char *, int, int));
void print_header PARAMS ((void));
void read_and PARAMS ((void (*do_) ()));
enum read_header read_header PARAMS ((void));
void skip_extended_headers PARAMS ((void));
void skip_file PARAMS ((long));
/* Module mangle.c. */
void extract_mangle (void);
void extract_mangle PARAMS ((void));
/* Module misc.c. */
void assign_string (char **, const char *);
char *quote_copy_string (const char *);
int unquote_string (char *);
void assign_string PARAMS ((char **, const char *));
char *quote_copy_string PARAMS ((const char *));
int unquote_string PARAMS ((char *));
size_t dot_dot_prefix_len (char const *);
char *merge_sort PARAMS ((char *, int, int, int (*) (char *, char *)));
enum remove_option
{
ORDINARY_REMOVE_OPTION,
RECURSIVE_REMOVE_OPTION,
WANT_DIRECTORY_REMOVE_OPTION
};
int remove_any_file (const char *, enum remove_option);
bool maybe_backup_file (const char *, int);
void undo_last_backup (void);
int deref_stat (bool, char const *, struct stat *);
int chdir_arg (char const *);
void chdir_do (int);
void decode_mode (mode_t, char *);
void chdir_fatal (char const *) __attribute__ ((noreturn));
void chmod_error_details (char const *, mode_t);
void chown_error_details (char const *, uid_t, gid_t);
void close_error (char const *);
void close_warn (char const *);
void close_diag (char const *name);
void exec_fatal (char const *) __attribute__ ((noreturn));
void link_error (char const *, char const *);
void mkdir_error (char const *);
void mkfifo_error (char const *);
void mknod_error (char const *);
void open_error (char const *);
void open_fatal (char const *) __attribute__ ((noreturn));
void open_warn (char const *);
void open_diag (char const *name);
void read_error (char const *);
void read_error_details (char const *, off_t, size_t);
void read_fatal (char const *) __attribute__ ((noreturn));
void read_fatal_details (char const *, off_t, size_t) __attribute__ ((noreturn));
void read_warn_details (char const *, off_t, size_t);
void read_diag_details (char const *name, off_t offset, size_t size);
void readlink_error (char const *);
void readlink_warn (char const *);
void readlink_diag (char const *name);
void savedir_error (char const *);
void savedir_warn (char const *);
void savedir_diag (char const *name);
void seek_error (char const *);
void seek_error_details (char const *, off_t);
void seek_warn (char const *);
void seek_warn_details (char const *, off_t);
void seek_diag_details (char const *, off_t);
void stat_error (char const *);
void stat_warn (char const *);
void stat_diag (char const *name);
void symlink_error (char const *, char const *);
void truncate_error (char const *);
void truncate_warn (char const *);
void unlink_error (char const *);
void utime_error (char const *);
void waitpid_error (char const *);
void write_error (char const *);
void write_error_details (char const *, size_t, size_t);
void write_fatal (char const *) __attribute__ ((noreturn));
void write_fatal_details (char const *, ssize_t, size_t)
__attribute__ ((noreturn));
pid_t xfork (void);
void xpipe (int[2]);
int is_dot_or_dotdot PARAMS ((const char *));
int remove_any_file PARAMS ((const char *, int));
int maybe_backup_file PARAMS ((const char *, int));
void undo_last_backup PARAMS ((void));
/* Module names.c. */
extern struct name *gnu_list_name;
void gid_to_gname PARAMS ((gid_t, char gname[GNAME_FIELD_SIZE]));
int gname_to_gid PARAMS ((char gname[GNAME_FIELD_SIZE], gid_t *));
void uid_to_uname PARAMS ((uid_t, char uname[UNAME_FIELD_SIZE]));
int uname_to_uid PARAMS ((char uname[UNAME_FIELD_SIZE], uid_t *));
void gid_to_gname (gid_t, char **gname);
int gname_to_gid (char const *, gid_t *);
void uid_to_uname (uid_t, char **uname);
int uname_to_uid (char const *, uid_t *);
void init_names PARAMS ((void));
void name_add PARAMS ((const char *));
void name_init PARAMS ((int, char *const *));
void name_term PARAMS ((void));
char *name_next PARAMS ((int change_));
void name_close PARAMS ((void));
void name_gather PARAMS ((void));
void addname PARAMS ((const char *));
int name_match PARAMS ((const char *));
void names_notfound PARAMS ((void));
void name_expand PARAMS ((void));
struct name *name_scan PARAMS ((const char *));
char *name_from_list PARAMS ((void));
void blank_name_list PARAMS ((void));
char *new_name PARAMS ((const char *, const char *));
void init_names (void);
void name_add (const char *);
void name_init (void);
void name_term (void);
char *name_next (int);
void name_close (void);
void name_gather (void);
struct name *addname (char const *, int);
int name_match (const char *);
void names_notfound (void);
void collect_and_sort_names (void);
struct name *name_scan (const char *);
char *name_from_list (void);
void blank_name_list (void);
char *new_name (const char *, const char *);
char *safer_name_suffix (char const *, bool);
size_t stripped_prefix_len (char const *file_name, size_t num);
bool all_names_found (struct tar_stat_info *);
bool excluded_name (char const *);
void add_avoided_name (char const *);
bool is_avoided_name (char const *);
bool contains_dot_dot (char const *);
#define ISFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
(c)->found_count == occurrence_option)
#define WASFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
(c)->found_count >= occurrence_option)
void add_exclude PARAMS ((char *));
void add_exclude_file PARAMS ((const char *));
int check_exclude PARAMS ((const char *));
/* Module tar.c. */
void usage (int);
int confirm (const char *, const char *);
void request_stdin (const char *);
void tar_stat_init (struct tar_stat_info *st);
void tar_stat_destroy (struct tar_stat_info *st);
void usage (int) __attribute__ ((noreturn));
int confirm PARAMS ((const char *, const char *));
void request_stdin PARAMS ((const char *));
/* Module update.c. */
extern char *output_start;
void update_archive (void);
/* Module xheader.c. */
void xheader_decode (struct tar_stat_info *);
void xheader_decode_global (void);
void xheader_store (char const *, struct tar_stat_info const *, void *);
void xheader_read (union block *, size_t);
void xheader_write (char type, char *name, struct xheader *xhdr);
void xheader_write_global (void);
void xheader_finish (struct xheader *);
void xheader_destroy (struct xheader *);
char *xheader_xhdr_name (struct tar_stat_info *st);
char *xheader_ghdr_name (void);
void xheader_write (char, char *, struct xheader *);
void xheader_write_global (void);
void xheader_set_option (char *string);
/* Module system.c */
void sys_stat_nanoseconds (struct tar_stat_info *);
void sys_detect_dev_null_output (void);
void sys_save_archive_dev_ino (void);
void sys_drain_input_pipe (void);
void sys_wait_for_child (pid_t);
void sys_spawn_shell (void);
bool sys_compare_uid (struct stat *a, struct stat *b);
bool sys_compare_gid (struct stat *a, struct stat *b);
bool sys_file_is_archive (struct tar_stat_info *p);
bool sys_compare_links (struct stat *link_data, struct stat *stat_data);
int sys_truncate (int fd);
void sys_reset_uid_gid (void);
pid_t sys_child_open_for_compress (void);
pid_t sys_child_open_for_uncompress (void);
void sys_reset_uid_gid (void);
size_t sys_write_archive_buffer (void);
bool sys_get_archive_stat (void);
void sys_reset_uid_gid (void);
/* Module compare.c */
void report_difference (struct tar_stat_info *st, const char *message, ...);
/* Module sparse.c */
bool sparse_file_p (struct tar_stat_info *);
bool sparse_member_p (struct tar_stat_info *);
bool sparse_fixup_header (struct tar_stat_info *);
enum dump_status sparse_dump_file (int, struct tar_stat_info *);
enum dump_status sparse_extract_file (int, struct tar_stat_info *, off_t *);
enum dump_status sparse_skip_file (struct tar_stat_info *);
bool sparse_diff_file (int, struct tar_stat_info *);
/* Module utf8.c */
bool string_ascii_p (const char *str);
bool utf8_convert (bool to_utf, char const *input, char **output);
void update_archive PARAMS ((void));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,5 @@
/* Delete entries from a tar archive.
Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001, 2003 Free
Software Foundation, Inc.
Copyright (C) 1988, 1992, 1994, 1996, 1997 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
@@ -15,95 +13,97 @@
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. */
59 Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "system.h"
#define STDIN 0
#define STDOUT 1
#include "common.h"
#include "rmt.h"
static union block *new_record;
static int new_blocks;
static bool acting_as_filter;
static union block *new_record = NULL;
static union block *save_record = NULL;
static int records_read = 0;
static int new_blocks = 0;
static int blocks_needed = 0;
/* FIXME: This module should not directly handle the following
variables, instead, the interface should be cleaned up. */
/* FIXME: This module should not directly handle the following three
variables, instead, this should be done in buffer.c only. */
extern union block *record_start;
extern union block *record_end;
extern union block *current_block;
extern union block *recent_long_name;
extern union block *recent_long_link;
extern off_t records_read;
extern off_t records_written;
/* The number of records skipped at the start of the archive, when
passing over members that are not deleted. */
static off_t records_skipped;
/*-------------------------------------------------------------------------.
| Move archive descriptor by COUNT records worth. If COUNT 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 loose! |
`-------------------------------------------------------------------------*/
/* Move archive descriptor by COUNT records worth. If COUNT is
positive we move forward, else we move negative. If it's a tape,
MTIOCTOP had better work. If it's something else, we try to seek
on it. If we can't seek, we lose! */
static void
move_archive (off_t count)
move_archive (int count)
{
if (count == 0)
return;
#ifdef MTIOCTOP
{
struct mtop operation;
int status;
if (count < 0
? (operation.mt_op = MTBSR,
operation.mt_count = -count,
operation.mt_count == -count)
: (operation.mt_op = MTFSR,
operation.mt_count = count,
operation.mt_count == count))
if (count > 0)
{
if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
return;
if (errno == EIO
&& 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
return;
operation.mt_op = MTFSR;
operation.mt_count = count;
}
else
{
operation.mt_op = MTBSR;
operation.mt_count = -count;
}
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
status >= 0)
return;
if (errno == EIO)
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
status >= 0)
return;
}
#endif /* MTIOCTOP */
{
off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
off_t increment = record_size * (off_t) count;
off_t position = position0 + increment;
off_t position = rmtlseek (archive, 0L, 1);
if (increment / count != record_size
|| (position < position0) != (increment < 0)
|| (position = position < 0 ? 0 : position,
rmtlseek (archive, position, SEEK_SET) != position))
seek_error_details (archive_name_array[0], position);
position += record_size * count;
if (rmtlseek (archive, position, 0) != position)
FATAL_ERROR ((0, 0, _("Could not re-position archive file")));
return;
}
}
/* Write out the record which has been filled. If MOVE_BACK_FLAG,
backspace to where we started. */
/*----------------------------------------------------------------.
| Write out the record which has been filled. If MOVE_BACK_FLAG, |
| backspace to where we started. |
`----------------------------------------------------------------*/
static void
write_record (int move_back_flag)
{
union block *save_record = record_start;
save_record = record_start;
record_start = new_record;
if (acting_as_filter)
if (archive == STDIN)
{
archive = STDOUT_FILENO;
archive = STDOUT;
flush_write ();
archive = STDIN_FILENO;
archive = STDIN;
}
else
{
move_archive ((records_written + records_skipped) - records_read);
move_archive (-(records_read + 1));
flush_write ();
}
@@ -113,39 +113,19 @@ write_record (int move_back_flag)
{
/* Move the tape head back to where we were. */
if (! acting_as_filter)
move_archive (records_read - (records_written + records_skipped));
if (archive != STDIN)
move_archive (records_read);
records_read--;
}
blocks_needed = blocking_factor;
new_blocks = 0;
}
static void
write_recent_blocks (union block *h, size_t blocks)
{
size_t i;
for (i = 0; i < blocks; i++)
{
new_record[new_blocks++] = h[i];
if (new_blocks == blocking_factor)
write_record (1);
}
}
static void
write_recent_bytes (char *data, size_t bytes)
{
size_t blocks = bytes / BLOCKSIZE;
size_t rest = bytes - blocks * BLOCKSIZE;
write_recent_blocks ((union block *)data, blocks);
memcpy (new_record[new_blocks].buffer, data + blocks * BLOCKSIZE, rest);
if (rest < BLOCKSIZE)
memset (new_record[new_blocks].buffer + rest, 0, BLOCKSIZE - rest);
new_blocks++;
if (new_blocks == blocking_factor)
write_record (1);
}
/*---.
| ? |
`---*/
void
delete_archive_members (void)
@@ -155,17 +135,16 @@ delete_archive_members (void)
/* FIXME: Should clean the routine before cleaning these variables :-( */
struct name *name;
off_t blocks_to_skip = 0;
off_t blocks_to_keep = 0;
int blocks_to_skip = 0;
int blocks_to_keep = 0;
int kept_blocks_in_record;
name_gather ();
open_archive (ACCESS_UPDATE);
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
do
while (logical_status == HEADER_STILL_UNREAD)
{
enum read_header status = read_header (true);
enum read_header status = read_header ();
switch (status)
{
@@ -173,30 +152,19 @@ delete_archive_members (void)
abort ();
case HEADER_SUCCESS:
if ((name = name_scan (current_stat_info.file_name)) == NULL)
if (name = name_scan (current_file_name), !name)
{
skip_member ();
set_next_block_after (current_header);
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) (current_stat.st_size));
break;
}
name->found_count++;
if (!ISFOUND(name))
{
skip_member ();
break;
}
/* Fall through. */
case HEADER_SUCCESS_EXTENDED:
logical_status = status;
name->found = 1;
logical_status = HEADER_SUCCESS;
break;
case HEADER_ZERO_BLOCK:
if (ignore_zeros_option)
{
set_next_block_after (current_header);
break;
}
/* Fall through. */
case HEADER_END_OF_FILE:
logical_status = HEADER_END_OF_FILE;
break;
@@ -210,7 +178,6 @@ delete_archive_members (void)
/* Fall through. */
case HEADER_SUCCESS:
case HEADER_SUCCESS_EXTENDED:
case HEADER_ZERO_BLOCK:
ERROR ((0, 0, _("Skipping to next header")));
/* Fall through. */
@@ -226,166 +193,144 @@ delete_archive_members (void)
previous_status = status;
}
while (logical_status == HEADER_STILL_UNREAD);
records_skipped = records_read - 1;
new_record = xmalloc (record_size);
if (logical_status == HEADER_SUCCESS
|| logical_status == HEADER_SUCCESS_EXTENDED)
if (logical_status != HEADER_SUCCESS)
{
write_archive_to_stdout = false;
write_eot ();
close_archive ();
names_notfound ();
return;
}
/* Save away blocks before this one in this record. */
write_archive_to_stdout = 0;
new_record = (union block *) xmalloc ((size_t) record_size);
new_blocks = current_block - record_start;
if (new_blocks)
memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
/* Save away blocks before this one in this record. */
if (logical_status == HEADER_SUCCESS)
new_blocks = current_block - record_start;
blocks_needed = blocking_factor - new_blocks;
if (new_blocks)
memcpy ((void *) new_record, (void *) record_start,
(size_t) (new_blocks * BLOCKSIZE));
#if 0
/* FIXME: Old code, before the goto was inserted. To be redesigned. */
set_next_block_after (current_header);
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) (current_stat.st_size));
#endif
logical_status = HEADER_STILL_UNREAD;
goto flush_file;
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
"delete.c", line 223: warning: loop not entered at top
Reported by Bruno Haible. */
while (1)
{
enum read_header status;
/* Fill in a record. */
if (current_block == record_end)
{
/* FIXME: Pheew! This is crufty code! */
logical_status = HEADER_STILL_UNREAD;
goto flush_file;
flush_archive ();
records_read++;
}
status = read_header ();
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
{
set_next_block_after (current_header);
continue;
}
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
{
logical_status = HEADER_END_OF_FILE;
memset (new_record[new_blocks].buffer, 0,
(size_t) (BLOCKSIZE * blocks_needed));
new_blocks += blocks_needed;
blocks_needed = 0;
write_record (0);
break;
}
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
"delete.c", line 223: warning: loop not entered at top
Reported by Bruno Haible. */
while (1)
if (status == HEADER_FAILURE)
{
enum read_header status;
ERROR ((0, 0, _("Deleting non-header from archive")));
set_next_block_after (current_header);
continue;
}
/* Fill in a record. */
/* Found another header. */
if (name = name_scan (current_file_name), name)
{
name->found = 1;
flush_file:
set_next_block_after (current_header);
blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
while (record_end - current_block <= blocks_to_skip)
{
blocks_to_skip -= (record_end - current_block);
flush_archive ();
records_read++;
}
current_block += blocks_to_skip;
blocks_to_skip = 0;
continue;
}
/* Copy header. */
new_record[new_blocks] = *current_header;
new_blocks++;
blocks_needed--;
blocks_to_keep
= (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
set_next_block_after (current_header);
if (blocks_needed == 0)
write_record (1);
/* Copy data. */
kept_blocks_in_record = record_end - current_block;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
while (blocks_to_keep)
{
int count;
if (current_block == record_end)
flush_archive ();
status = read_header (false);
xheader_decode (&current_stat_info);
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
{
set_next_block_after (current_header);
continue;
}
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
{
logical_status = HEADER_END_OF_FILE;
break;
flush_read ();
records_read++;
current_block = record_start;
kept_blocks_in_record = blocking_factor;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
}
count = kept_blocks_in_record;
if (count > blocks_needed)
count = blocks_needed;
if (status == HEADER_FAILURE)
{
ERROR ((0, 0, _("Deleting non-header from archive")));
set_next_block_after (current_header);
continue;
}
memcpy ((void *) (new_record + new_blocks),
(void *) current_block,
(size_t) (count * BLOCKSIZE));
new_blocks += count;
blocks_needed -= count;
current_block += count;
blocks_to_keep -= count;
kept_blocks_in_record -= count;
/* Found another header. */
if ((name = name_scan (current_stat_info.file_name)) != NULL)
{
name->found_count++;
if (ISFOUND(name))
{
flush_file:
set_next_block_after (current_header);
blocks_to_skip = (current_stat_info.stat.st_size
+ BLOCKSIZE - 1) / BLOCKSIZE;
while (record_end - current_block <= blocks_to_skip)
{
blocks_to_skip -= (record_end - current_block);
flush_archive ();
}
current_block += blocks_to_skip;
blocks_to_skip = 0;
continue;
}
}
/* Copy header. */
if (extended_header.size)
{
write_recent_bytes (extended_header.buffer,
extended_header.size);
}
else
{
write_recent_blocks (recent_long_name, recent_long_name_blocks);
write_recent_blocks (recent_long_link, recent_long_link_blocks);
}
new_record[new_blocks] = *current_header;
new_blocks++;
blocks_to_keep
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
set_next_block_after (current_header);
if (new_blocks == blocking_factor)
if (blocks_needed == 0)
write_record (1);
/* Copy data. */
kept_blocks_in_record = record_end - current_block;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
while (blocks_to_keep)
{
int count;
if (current_block == record_end)
{
flush_read ();
current_block = record_start;
kept_blocks_in_record = blocking_factor;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
}
count = kept_blocks_in_record;
if (blocking_factor - new_blocks < count)
count = blocking_factor - new_blocks;
if (! count)
abort ();
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
new_blocks += count;
current_block += count;
blocks_to_keep -= count;
kept_blocks_in_record -= count;
if (new_blocks == blocking_factor)
write_record (1);
}
}
}
if (logical_status == HEADER_END_OF_FILE)
{
/* Write the end of tape. FIXME: we can't use write_eot here,
as it gets confused when the input is at end of file. */
int total_zero_blocks = 0;
do
{
int zero_blocks = blocking_factor - new_blocks;
memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
total_zero_blocks += zero_blocks;
write_record (total_zero_blocks < 2);
}
while (total_zero_blocks < 2);
}
free (new_record);
if (! acting_as_filter && ! _isrmt (archive))
{
if (sys_truncate (archive))
truncate_warn (archive_name_array[0]);
}
write_eot ();
close_archive ();
names_notfound ();
}

View File

@@ -1,7 +1,7 @@
/* Extract files from a tar archive.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
2001, 2003, 2004 Free Software Foundation, Inc.
Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
2001 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-11-19.
@@ -21,7 +21,6 @@
#include "system.h"
#include <quotearg.h>
#include <errno.h>
#if HAVE_UTIME_H
# include <utime.h>
@@ -35,7 +34,7 @@ struct utimbuf
#include "common.h"
bool we_are_root; /* true if our effective uid == 0 */
int we_are_root; /* true if our effective uid == 0 */
static mode_t newdir_umask; /* umask when creating new directories */
static mode_t current_umask; /* current umask (which is set to 0 if -p) */
@@ -130,15 +129,14 @@ extr_init (void)
}
/* If restoring permissions, restore the mode for FILE_NAME from
information given in *STAT_INFO (where *CUR_INFO gives
the current status if CUR_INFO is nonzero); otherwise invert the
information given in *STAT_INFO (where *CURRENT_STAT_INFO gives
the current status if CURRENT_STAT_INFO is nonzero); otherwise invert the
INVERT_PERMISSIONS bits from the file's current permissions.
PERMSTATUS specifies the status of the file's permissions.
TYPEFLAG specifies the type of the file. */
static void
set_mode (char const *file_name,
struct stat const *stat_info,
struct stat const *cur_info,
set_mode (char const *file_name, struct stat const *stat_info,
struct stat const *current_stat_info,
mode_t invert_permissions, enum permstatus permstatus,
char typeflag)
{
@@ -170,16 +168,16 @@ set_mode (char const *file_name,
that we created, so there's no point optimizing this code for
other cases. */
struct stat st;
if (! cur_info)
if (! current_stat_info)
{
if (stat (file_name, &st) != 0)
{
stat_error (file_name);
return;
}
cur_info = &st;
current_stat_info = &st;
}
mode = cur_info->st_mode ^ invert_permissions;
mode = current_stat_info->st_mode ^ invert_permissions;
}
if (chmod (file_name, mode) != 0)
@@ -191,17 +189,14 @@ static void
check_time (char const *file_name, time_t t)
{
time_t now;
if (t <= 0)
WARN ((0, 0, _("%s: implausibly old time stamp %s"),
file_name, tartime (t)));
else if (start_time < t && (now = time (0)) < t)
if (start_time < t && (now = time (0)) < t)
WARN ((0, 0, _("%s: time stamp %s is %lu s in the future"),
file_name, tartime (t), (unsigned long) (t - now)));
}
/* Restore stat attributes (owner, group, mode and times) for
FILE_NAME, using information given in *STAT_INFO.
If CUR_INFO is nonzero, *CUR_INFO is the
If CURRENT_STAT_INFO is nonzero, *CURRENT_STAT_INFO is the
file's currernt status.
If not restoring permissions, invert the
INVERT_PERMISSIONS bits from the file's current permissions.
@@ -214,9 +209,8 @@ check_time (char const *file_name, time_t t)
punt for the rest. Sigh! */
static void
set_stat (char const *file_name,
struct stat const *stat_info,
struct stat const *cur_info,
set_stat (char const *file_name, struct stat const *stat_info,
struct stat const *current_stat_info,
mode_t invert_permissions, enum permstatus permstatus,
char typeflag)
{
@@ -246,8 +240,8 @@ set_stat (char const *file_name,
utime_error (file_name);
else
{
check_time (file_name, utimbuf.actime);
check_time (file_name, utimbuf.modtime);
check_time (file_name, stat_info->st_atime);
check_time (file_name, stat_info->st_mtime);
}
}
@@ -255,7 +249,7 @@ set_stat (char const *file_name,
done, it is not possible anymore to change file permissions, so we
have to set permissions prior to possibly giving files away. */
set_mode (file_name, stat_info, cur_info,
set_mode (file_name, stat_info, current_stat_info,
invert_permissions, permstatus, typeflag);
}
@@ -315,11 +309,11 @@ delay_set_stat (char const *file_name, struct stat const *stat_info,
}
/* Update the delayed_set_stat info for an intermediate directory
created on the path to DIR. The intermediate directory turned
created on the path to DIR_NAME. The intermediate directory turned
out to be the same as this directory, e.g. due to ".." or symbolic
links. *DIR_STAT_INFO is the status of the directory. */
static void
repair_delayed_set_stat (char const *dir,
repair_delayed_set_stat (char const *dir_name,
struct stat const *dir_stat_info)
{
struct delayed_set_stat *data;
@@ -335,16 +329,16 @@ repair_delayed_set_stat (char const *dir,
if (st.st_dev == dir_stat_info->st_dev
&& st.st_ino == dir_stat_info->st_ino)
{
data->stat_info = current_stat_info.stat;
data->invert_permissions =
(MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
data->stat_info = current_stat;
data->invert_permissions = (MODE_RWX
& (current_stat.st_mode ^ st.st_mode));
data->permstatus = ARCHIVED_PERMSTATUS;
return;
}
}
ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
quotearg_colon (dir)));
quotearg_colon (dir_name)));
}
/* After a file/link/symlink/directory creation has failed, see if
@@ -361,7 +355,7 @@ make_directories (char *file_name)
int invert_permissions;
int status;
for (cursor = cursor0; *cursor; cursor++)
{
if (! ISSLASH (*cursor))
@@ -391,7 +385,7 @@ make_directories (char *file_name)
invert_permissions is zero, because
repair_delayed_set_stat may need to update the struct. */
delay_set_stat (file_name,
&current_stat_info.stat /* ignored */,
&current_stat /* ignored */,
invert_permissions, INTERDIR_PERMSTATUS);
print_for_mkdir (file_name, cursor - file_name, mode);
@@ -403,13 +397,13 @@ make_directories (char *file_name)
*cursor = '/';
if (errno == EEXIST)
continue; /* Directory already exists. */
else if ((errno == ENOSYS /* Automounted dirs on Solaris return
this. Reported by Warren Hyde
<Warren.Hyde@motorola.com> */
|| ERRNO_IS_EACCES) /* Turbo C mkdir gives a funny errno. */
&& access (file_name, W_OK) == 0)
if (errno == EEXIST
#if MSDOS
/* Turbo C mkdir gives a funny errno. */
|| errno == EACCES
#endif
)
/* Directory already exists. */
continue;
/* Some other error in the mkdir. We return to the caller. */
@@ -419,24 +413,6 @@ make_directories (char *file_name)
return did_something; /* tell them to retry if we made one */
}
static bool
file_newer_p (const char *file_name, struct tar_stat_info *tar_stat)
{
struct stat st;
if (stat (file_name, &st))
{
stat_warn (file_name);
return true; /* Be on the safe side */
}
if (!S_ISDIR (st.st_mode)
&& st.st_mtime >= tar_stat->stat.st_mtime)
{
return true;
}
return false;
}
/* Prepare to extract a file.
Return zero if extraction should not proceed. */
@@ -446,27 +422,12 @@ prepare_to_extract (char const *file_name)
if (to_stdout_option)
return 0;
switch (old_files_option)
if (old_files_option == UNLINK_FIRST_OLD_FILES
&& !remove_any_file (file_name, recursive_unlink_option)
&& errno && errno != ENOENT)
{
case UNLINK_FIRST_OLD_FILES:
if (!remove_any_file (file_name, recursive_unlink_option)
&& errno && errno != ENOENT)
{
unlink_error (file_name);
return 0;
}
break;
case KEEP_NEWER_FILES:
if (file_newer_p (file_name, &current_stat_info))
{
WARN ((0, 0, _("Current `%s' is newer"), file_name));
return 0;
}
break;
default:
break;
unlink_error (file_name);
return 0;
}
return 1;
@@ -479,8 +440,6 @@ prepare_to_extract (char const *file_name)
static int
maybe_recoverable (char *file_name, int *interdir_made)
{
int e = errno;
if (*interdir_made)
return 0;
@@ -491,28 +450,17 @@ maybe_recoverable (char *file_name, int *interdir_made)
switch (old_files_option)
{
case KEEP_OLD_FILES:
default:
return 0;
case KEEP_NEWER_FILES:
if (file_newer_p (file_name, &current_stat_info))
{
errno = e;
return 0;
}
/* FALL THROUGH */
case DEFAULT_OLD_FILES:
case NO_OVERWRITE_DIR_OLD_FILES:
case OVERWRITE_OLD_DIRS:
case OVERWRITE_OLD_FILES:
{
int r = remove_any_file (file_name, 0);
errno = EEXIST;
return r;
}
case UNLINK_FIRST_OLD_FILES:
break;
}
case ENOENT:
@@ -532,6 +480,61 @@ maybe_recoverable (char *file_name, int *interdir_made)
}
}
static void
extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name)
{
int sparse_ind = 0;
/* assuming sizeleft is initially totalsize */
while (*sizeleft > 0)
{
size_t written;
size_t count;
union block *data_block = find_next_block ();
if (! data_block)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return;
}
if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0)
{
seek_error_details (name, sparsearray[sparse_ind].offset);
return;
}
written = sparsearray[sparse_ind++].numbytes;
while (written > BLOCKSIZE)
{
count = full_write (fd, data_block->buffer, BLOCKSIZE);
written -= count;
*sizeleft -= count;
if (count != BLOCKSIZE)
{
write_error_details (name, count, BLOCKSIZE);
return;
}
set_next_block_after (data_block);
data_block = find_next_block ();
if (! data_block)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return;
}
}
count = full_write (fd, data_block->buffer, written);
*sizeleft -= count;
if (count != written)
{
write_error_details (name, count, written);
return;
}
set_next_block_after (data_block);
}
}
/* Fix the statuses of all directories whose statuses need fixing, and
which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is
nonzero, do this for all such directories; otherwise, stop at the
@@ -548,7 +551,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
struct delayed_set_stat *data = delayed_set_stat_head;
bool skip_this_one = 0;
struct stat st;
struct stat const *cur_info = 0;
struct stat const *current_stat_info = 0;
check_for_renamed_directories |= data->after_symlinks;
@@ -562,7 +565,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
if (check_for_renamed_directories)
{
cur_info = &st;
current_stat_info = &st;
if (stat (data->file_name, &st) != 0)
{
stat_error (data->file_name);
@@ -579,7 +582,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
}
if (! skip_this_one)
set_stat (data->file_name, &data->stat_info, cur_info,
set_stat (data->file_name, &data->stat_info, current_stat_info,
data->invert_permissions, data->permstatus, DIRTYPE);
delayed_set_stat_head = data->next;
@@ -595,18 +598,23 @@ extract_archive (void)
int fd;
int status;
size_t count;
size_t name_length;
size_t written;
int openflag;
mode_t mode;
off_t size;
size_t skipcrud;
int counter;
int interdir_made = 0;
char typeflag;
char *file_name;
union block *exhdr;
#define CURRENT_FILE_NAME (skipcrud + current_file_name)
set_next_block_after (current_header);
decode_header (current_header, &current_stat_info, &current_format, 1);
decode_header (current_header, &current_stat, &current_format, 1);
if (interactive_option && !confirm ("extract", current_stat_info.file_name))
if (interactive_option && !confirm ("extract", current_file_name))
{
skip_member ();
return;
@@ -615,43 +623,131 @@ extract_archive (void)
/* Print the block from current_header and current_stat. */
if (verbose_option)
print_header (&current_stat_info, -1);
print_header ();
file_name = safer_name_suffix (current_stat_info.file_name, false);
if (strip_path_elements)
/* Check for fully specified file names and other atrocities. */
skipcrud = 0;
if (! absolute_names_option)
{
size_t prefix_len = stripped_prefix_len (file_name, strip_path_elements);
if (prefix_len == (size_t) -1)
if (contains_dot_dot (CURRENT_FILE_NAME))
{
ERROR ((0, 0, _("%s: Member name contains `..'"),
quotearg_colon (CURRENT_FILE_NAME)));
skip_member ();
return;
}
file_name += prefix_len;
skipcrud = FILESYSTEM_PREFIX_LEN (current_file_name);
while (ISSLASH (CURRENT_FILE_NAME[0]))
skipcrud++;
if (skipcrud)
{
static int warned_once;
if (!warned_once)
{
warned_once = 1;
WARN ((0, 0, _("Removing leading `%.*s' from member names"),
(int) skipcrud, current_file_name));
}
}
}
apply_nonancestor_delayed_set_stat (file_name, 0);
apply_nonancestor_delayed_set_stat (CURRENT_FILE_NAME, 0);
/* Take a safety backup of a previously existing file. */
if (backup_option && !to_stdout_option)
if (!maybe_backup_file (file_name, 0))
if (!maybe_backup_file (CURRENT_FILE_NAME, 0))
{
int e = errno;
ERROR ((0, e, _("%s: Was unable to backup this file"),
quotearg_colon (file_name)));
quotearg_colon (CURRENT_FILE_NAME)));
skip_member ();
return;
}
/* Extract the archive entry according to its type. */
/* KLUDGE */
typeflag = sparse_member_p (&current_stat_info) ?
GNUTYPE_SPARSE : current_header->header.typeflag;
typeflag = current_header->header.typeflag;
switch (typeflag)
{
/* 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 GNUTYPE_SPARSE:
sp_array_size = 10;
sparsearray =
xmalloc (sp_array_size * sizeof (struct sp_array));
for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
{
struct sparse const *s = &current_header->oldgnu_header.sp[counter];
sparsearray[counter].offset = OFF_FROM_HEADER (s->offset);
sparsearray[counter].numbytes = SIZE_FROM_HEADER (s->numbytes);
if (!sparsearray[counter].numbytes)
break;
}
if (current_header->oldgnu_header.isextended)
{
/* Read in the list of extended headers and translate them
into the sparsearray as before. Note that this
invalidates current_header. */
/* static */ int ind = SPARSES_IN_OLDGNU_HEADER;
while (1)
{
exhdr = find_next_block ();
if (! exhdr)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return;
}
for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
{
struct sparse const *s = &exhdr->sparse_header.sp[counter];
if (counter + ind > sp_array_size - 1)
{
/* Realloc the scratch area since we've run out of
room. */
sp_array_size *= 2;
sparsearray =
xrealloc (sparsearray,
sp_array_size * sizeof (struct sp_array));
}
if (s->numbytes[0] == 0)
break;
sparsearray[counter + ind].offset =
OFF_FROM_HEADER (s->offset);
sparsearray[counter + ind].numbytes =
SIZE_FROM_HEADER (s->numbytes);
}
if (!exhdr->sparse_header.isextended)
break;
else
{
ind += SPARSES_IN_SPARSE_HEADER;
set_next_block_after (exhdr);
}
}
set_next_block_after (exhdr);
}
/* Fall through. */
case AREGTYPE:
@@ -661,7 +757,9 @@ extract_archive (void)
/* Appears to be a file. But BSD tar uses the convention that a slash
suffix means a directory. */
if (current_stat_info.had_trailing_slash)
name_length = strlen (CURRENT_FILE_NAME);
if (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
&& CURRENT_FILE_NAME[name_length - 1] == '/')
goto really_dir;
/* FIXME: deal with protection issues. */
@@ -671,7 +769,7 @@ extract_archive (void)
| (old_files_option == OVERWRITE_OLD_FILES
? O_TRUNC
: O_EXCL));
mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
if (to_stdout_option)
{
@@ -679,7 +777,7 @@ extract_archive (void)
goto extract_file;
}
if (! prepare_to_extract (file_name))
if (! prepare_to_extract (CURRENT_FILE_NAME))
{
skip_member ();
if (backup_option)
@@ -692,9 +790,10 @@ extract_archive (void)
the open call that creates them. */
if (typeflag == CONTTYPE)
fd = open (file_name, openflag | O_CTG, mode, current_stat_info.stat.st_size);
fd = open (CURRENT_FILE_NAME, openflag | O_CTG,
mode, current_stat.st_size);
else
fd = open (file_name, openflag, mode);
fd = open (CURRENT_FILE_NAME, openflag, mode);
#else /* not O_CTG */
if (typeflag == CONTTYPE)
@@ -707,16 +806,16 @@ extract_archive (void)
WARN ((0, 0, _("Extracting contiguous files as regular files")));
}
}
fd = open (file_name, openflag, mode);
fd = open (CURRENT_FILE_NAME, openflag, mode);
#endif /* not O_CTG */
if (fd < 0)
{
if (maybe_recoverable (file_name, &interdir_made))
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
goto again_file;
open_error (file_name);
open_error (CURRENT_FILE_NAME);
skip_member ();
if (backup_option)
undo_last_backup ();
@@ -724,17 +823,31 @@ extract_archive (void)
}
extract_file:
if (current_stat_info.is_sparse)
if (typeflag == GNUTYPE_SPARSE)
{
sparse_extract_file (fd, &current_stat_info, &size);
char *name;
size_t name_length_bis;
/* 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. */
name_length_bis = strlen (CURRENT_FILE_NAME) + 1;
name = xmalloc (name_length_bis);
memcpy (name, CURRENT_FILE_NAME, name_length_bis);
size = current_stat.st_size;
extract_sparse_file (fd, &size, current_stat.st_size, name);
free (sparsearray);
}
else
for (size = current_stat_info.stat.st_size; size > 0; )
for (size = current_stat.st_size; size > 0; )
{
if (multi_volume_option)
{
assign_string (&save_name, current_stat_info.file_name);
save_totsize = current_stat_info.stat.st_size;
assign_string (&save_name, current_file_name);
save_totsize = current_stat.st_size;
save_sizeleft = size;
}
@@ -761,7 +874,7 @@ extract_archive (void)
(data_block->buffer + written - 1));
if (count != written)
{
write_error_details (file_name, count, written);
write_error_details (CURRENT_FILE_NAME, count, written);
break;
}
}
@@ -780,12 +893,12 @@ extract_archive (void)
status = close (fd);
if (status < 0)
{
close_error (file_name);
close_error (CURRENT_FILE_NAME);
if (backup_option)
undo_last_backup ();
}
set_stat (file_name, &current_stat_info.stat, 0, 0,
set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
(old_files_option == OVERWRITE_OLD_FILES
? UNKNOWN_PERMSTATUS
: ARCHIVED_PERMSTATUS),
@@ -794,23 +907,23 @@ extract_archive (void)
case SYMTYPE:
#ifdef HAVE_SYMLINK
if (! prepare_to_extract (file_name))
if (! prepare_to_extract (CURRENT_FILE_NAME))
break;
if (absolute_names_option
|| ! (ISSLASH (current_stat_info.link_name
[FILESYSTEM_PREFIX_LEN (current_stat_info.link_name)])
|| contains_dot_dot (current_stat_info.link_name)))
|| ! (ISSLASH (current_link_name
[FILESYSTEM_PREFIX_LEN (current_link_name)])
|| contains_dot_dot (current_link_name)))
{
while (status = symlink (current_stat_info.link_name, file_name),
while (status = symlink (current_link_name, CURRENT_FILE_NAME),
status != 0)
if (!maybe_recoverable (file_name, &interdir_made))
if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
break;
if (status == 0)
set_stat (file_name, &current_stat_info.stat, 0, 0, 0, SYMTYPE);
set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0, 0, SYMTYPE);
else
symlink_error (current_stat_info.link_name, file_name);
symlink_error (current_link_name, CURRENT_FILE_NAME);
}
else
{
@@ -819,46 +932,46 @@ extract_archive (void)
will be replaced after other extraction is done. */
struct stat st;
while (fd = open (file_name, O_WRONLY | O_CREAT | O_EXCL, 0),
while (fd = open (CURRENT_FILE_NAME, O_WRONLY | O_CREAT | O_EXCL, 0),
fd < 0)
if (! maybe_recoverable (file_name, &interdir_made))
if (! maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
break;
status = -1;
if (fd < 0)
open_error (file_name);
open_error (CURRENT_FILE_NAME);
else if (fstat (fd, &st) != 0)
{
stat_error (file_name);
stat_error (CURRENT_FILE_NAME);
close (fd);
}
else if (close (fd) != 0)
close_error (file_name);
close_error (CURRENT_FILE_NAME);
else
{
struct delayed_set_stat *h;
struct delayed_symlink *p =
xmalloc (offsetof (struct delayed_symlink, target)
+ strlen (current_stat_info.link_name) + 1);
+ strlen (current_link_name) + 1);
p->next = delayed_symlink_head;
delayed_symlink_head = p;
p->dev = st.st_dev;
p->ino = st.st_ino;
p->mtime = st.st_mtime;
p->uid = current_stat_info.stat.st_uid;
p->gid = current_stat_info.stat.st_gid;
p->uid = current_stat.st_uid;
p->gid = current_stat.st_gid;
p->sources = xmalloc (offsetof (struct string_list, string)
+ strlen (file_name) + 1);
+ strlen (CURRENT_FILE_NAME) + 1);
p->sources->next = 0;
strcpy (p->sources->string, file_name);
strcpy (p->target, current_stat_info.link_name);
strcpy (p->sources->string, CURRENT_FILE_NAME);
strcpy (p->target, current_link_name);
h = delayed_set_stat_head;
if (h && ! h->after_symlinks
&& strncmp (file_name, h->file_name, h->file_name_len) == 0
&& ISSLASH (file_name[h->file_name_len])
&& (base_name (file_name)
== file_name + h->file_name_len + 1))
&& strncmp (CURRENT_FILE_NAME, h->file_name, h->file_name_len) == 0
&& ISSLASH (CURRENT_FILE_NAME[h->file_name_len])
&& (base_name (CURRENT_FILE_NAME)
== CURRENT_FILE_NAME + h->file_name_len + 1))
{
do
{
@@ -878,7 +991,7 @@ extract_archive (void)
status = 0;
}
}
if (status != 0 && backup_option)
undo_last_backup ();
break;
@@ -899,52 +1012,50 @@ extract_archive (void)
#endif
case LNKTYPE:
if (! prepare_to_extract (file_name))
if (! prepare_to_extract (CURRENT_FILE_NAME))
break;
again_link:
{
char const *link_name = safer_name_suffix (current_stat_info.link_name,
true);
struct stat st1, st2;
int e;
/* MSDOS does not implement links. However, djgpp's link() actually
copies the file. */
status = link (link_name, file_name);
status = link (current_link_name, CURRENT_FILE_NAME);
if (status == 0)
{
struct delayed_symlink *ds = delayed_symlink_head;
if (ds && stat (link_name, &st1) == 0)
if (ds && stat (current_link_name, &st1) == 0)
for (; ds; ds = ds->next)
if (ds->dev == st1.st_dev
&& ds->ino == st1.st_ino
&& ds->mtime == st1.st_mtime)
{
struct string_list *p =
struct string_list *p =
xmalloc (offsetof (struct string_list, string)
+ strlen (file_name) + 1);
strcpy (p->string, file_name);
+ strlen (CURRENT_FILE_NAME) + 1);
strcpy (p->string, CURRENT_FILE_NAME);
p->next = ds->sources;
ds->sources = p;
break;
}
break;
}
if (maybe_recoverable (file_name, &interdir_made))
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
goto again_link;
if (incremental_option && errno == EEXIST)
break;
e = errno;
if (stat (link_name, &st1) == 0
&& stat (file_name, &st2) == 0
if (stat (current_link_name, &st1) == 0
&& stat (CURRENT_FILE_NAME, &st2) == 0
&& st1.st_dev == st2.st_dev
&& st1.st_ino == st2.st_ino)
break;
link_error (link_name, file_name);
link_error (current_link_name, CURRENT_FILE_NAME);
if (backup_option)
undo_last_backup ();
}
@@ -952,52 +1063,52 @@ extract_archive (void)
#if S_IFCHR
case CHRTYPE:
current_stat_info.stat.st_mode |= S_IFCHR;
current_stat.st_mode |= S_IFCHR;
goto make_node;
#endif
#if S_IFBLK
case BLKTYPE:
current_stat_info.stat.st_mode |= S_IFBLK;
current_stat.st_mode |= S_IFBLK;
#endif
#if S_IFCHR || S_IFBLK
make_node:
if (! prepare_to_extract (file_name))
if (! prepare_to_extract (CURRENT_FILE_NAME))
break;
status = mknod (file_name, current_stat_info.stat.st_mode,
current_stat_info.stat.st_rdev);
status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
current_stat.st_rdev);
if (status != 0)
{
if (maybe_recoverable (file_name, &interdir_made))
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
goto make_node;
mknod_error (file_name);
mknod_error (CURRENT_FILE_NAME);
if (backup_option)
undo_last_backup ();
break;
};
set_stat (file_name, &current_stat_info.stat, 0, 0,
set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
ARCHIVED_PERMSTATUS, typeflag);
break;
#endif
#if HAVE_MKFIFO || defined mkfifo
case FIFOTYPE:
if (! prepare_to_extract (file_name))
if (! prepare_to_extract (CURRENT_FILE_NAME))
break;
while (status = mkfifo (file_name, current_stat_info.stat.st_mode),
while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
status != 0)
if (!maybe_recoverable (file_name, &interdir_made))
if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
break;
if (status == 0)
set_stat (file_name, &current_stat_info.stat, NULL, 0,
set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
ARCHIVED_PERMSTATUS, typeflag);
else
{
mkfifo_error (file_name);
mkfifo_error (CURRENT_FILE_NAME);
if (backup_option)
undo_last_backup ();
}
@@ -1006,43 +1117,48 @@ extract_archive (void)
case DIRTYPE:
case GNUTYPE_DUMPDIR:
name_length = strlen (CURRENT_FILE_NAME);
really_dir:
/* Remove any redundant trailing "/"s. */
while (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
&& CURRENT_FILE_NAME[name_length - 1] == '/')
name_length--;
CURRENT_FILE_NAME[name_length] = '\0';
if (incremental_option)
{
/* Read the entry and delete files that aren't listed in the
archive. */
gnu_restore (file_name);
gnu_restore (skipcrud);
}
else if (typeflag == GNUTYPE_DUMPDIR)
skip_member ();
mode = ((current_stat_info.stat.st_mode
if (! prepare_to_extract (CURRENT_FILE_NAME))
break;
mode = ((current_stat.st_mode
| (we_are_root ? 0 : MODE_WXUSR))
& MODE_RWX);
status = prepare_to_extract (file_name);
if (status == 0)
break;
if (status < 0)
goto directory_exists;
again_dir:
status = mkdir (file_name, mode);
status = mkdir (CURRENT_FILE_NAME, mode);
if (status != 0)
{
if (errno == EEXIST
&& (interdir_made
|| old_files_option == DEFAULT_OLD_FILES
|| old_files_option == OVERWRITE_OLD_DIRS
|| old_files_option == OVERWRITE_OLD_FILES))
{
struct stat st;
if (stat (file_name, &st) == 0)
if (stat (CURRENT_FILE_NAME, &st) == 0)
{
if (interdir_made)
{
repair_delayed_set_stat (file_name, &st);
repair_delayed_set_stat (CURRENT_FILE_NAME, &st);
break;
}
if (S_ISDIR (st.st_mode))
@@ -1053,13 +1169,13 @@ extract_archive (void)
}
errno = EEXIST;
}
if (maybe_recoverable (file_name, &interdir_made))
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
goto again_dir;
if (errno != EEXIST)
{
mkdir_error (file_name);
mkdir_error (CURRENT_FILE_NAME);
if (backup_option)
undo_last_backup ();
break;
@@ -1068,10 +1184,10 @@ extract_archive (void)
directory_exists:
if (status == 0
|| old_files_option == DEFAULT_OLD_FILES
|| old_files_option == OVERWRITE_OLD_DIRS
|| old_files_option == OVERWRITE_OLD_FILES)
delay_set_stat (file_name, &current_stat_info.stat,
MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
delay_set_stat (CURRENT_FILE_NAME, &current_stat,
MODE_RWX & (mode ^ current_stat.st_mode),
(status == 0
? ARCHIVED_PERMSTATUS
: UNKNOWN_PERMSTATUS));
@@ -1079,7 +1195,7 @@ extract_archive (void)
case GNUTYPE_VOLHDR:
if (verbose_option)
fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
fprintf (stdlis, _("Reading %s\n"), quote (current_file_name));
break;
case GNUTYPE_NAMES:
@@ -1089,7 +1205,7 @@ extract_archive (void)
case GNUTYPE_MULTIVOL:
ERROR ((0, 0,
_("%s: Cannot extract -- file is continued from another volume"),
quotearg_colon (current_stat_info.file_name)));
quotearg_colon (current_file_name)));
skip_member ();
if (backup_option)
undo_last_backup ();
@@ -1106,9 +1222,11 @@ extract_archive (void)
default:
WARN ((0, 0,
_("%s: Unknown file type '%c', extracted as normal file"),
quotearg_colon (file_name), typeflag));
quotearg_colon (CURRENT_FILE_NAME), typeflag));
goto again_file;
}
#undef CURRENT_FILE_NAME
}
/* Extract the symbolic links whose final extraction were delayed. */

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* List a tar archive, with support routines for reading a tar archive.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
2001, 2003, 2004 Free Software Foundation, Inc.
Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
2001 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-08-26.
@@ -30,14 +30,15 @@
#define max(a, b) ((a) < (b) ? (b) : (a))
union block *current_header; /* points to current archive header */
struct stat current_stat; /* stat struct corresponding */
enum archive_format current_format; /* recognized format */
union block *recent_long_name; /* recent long name header and contents */
union block *recent_long_link; /* likewise, for long link */
size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
size_t recent_long_link_blocks; /* likewise, for long link */
static uintmax_t from_header (const char *, size_t, const char *,
uintmax_t, uintmax_t);
static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
uintmax_t, uintmax_t));
/* Base 64 digits; see Internet RFC 2045 Table 1. */
static char const base_64_digits[64] =
@@ -64,7 +65,7 @@ base64_init (void)
/* Main loop for reading an archive. */
void
read_and (void (*do_something) (void))
read_and (void (*do_something) ())
{
enum read_header status = HEADER_STILL_UNREAD;
enum read_header prev_status;
@@ -73,17 +74,13 @@ read_and (void (*do_something) (void))
name_gather ();
open_archive (ACCESS_READ);
do
while (1)
{
prev_status = status;
tar_stat_destroy (&current_stat_info);
xheader_destroy (&extended_header);
status = read_header (false);
status = read_header (0);
switch (status)
{
case HEADER_STILL_UNREAD:
case HEADER_SUCCESS_EXTENDED:
abort ();
case HEADER_SUCCESS:
@@ -91,19 +88,14 @@ read_and (void (*do_something) (void))
/* Valid header. We should decode next field (mode) first.
Ensure incoming names are null terminated. */
if (! name_match (current_stat_info.file_name)
|| (NEWER_OPTION_INITIALIZED (newer_mtime_option)
if (! name_match (current_file_name)
|| (newer_mtime_option != TYPE_MINIMUM (time_t)
/* FIXME: We get mtime now, and again later; this causes
duplicate diagnostics if header.mtime is bogus. */
&& ((current_stat_info.stat.st_mtime
= TIME_FROM_HEADER (current_header->header.mtime)),
#ifdef ST_MTIM_NSEC
/* FIXME: Grab fractional time stamps from
extended header. */
current_stat_info.stat.st_mtim.ST_MTIM_NSEC = 0,
#endif
OLDER_STAT_TIME (current_stat_info.stat, m)))
|| excluded_name (current_stat_info.file_name))
&& ((current_stat.st_mtime
= TIME_FROM_HEADER (current_header->header.mtime))
< newer_mtime_option))
|| excluded_name (current_file_name))
{
switch (current_header->header.typeflag)
{
@@ -111,17 +103,17 @@ read_and (void (*do_something) (void))
case GNUTYPE_MULTIVOL:
case GNUTYPE_NAMES:
break;
case DIRTYPE:
if (show_omitted_dirs_option)
WARN ((0, 0, _("%s: Omitting"),
quotearg_colon (current_stat_info.file_name)));
quotearg_colon (current_file_name)));
/* Fall through. */
default:
skip_member ();
continue;
}
}
}
(*do_something) ();
continue;
@@ -135,20 +127,10 @@ read_and (void (*do_something) (void))
}
set_next_block_after (current_header);
if (!ignore_zeros_option)
{
char buf[UINTMAX_STRSIZE_BOUND];
status = read_header (false);
if (status == HEADER_ZERO_BLOCK)
break;
WARN ((0, 0, _("A lone zero block at %s"),
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
break;
}
status = prev_status;
continue;
if (ignore_zeros_option)
continue;
break;
case HEADER_END_OF_FILE:
if (block_number_option)
@@ -171,15 +153,6 @@ read_and (void (*do_something) (void))
case HEADER_ZERO_BLOCK:
case HEADER_SUCCESS:
if (block_number_option)
{
char buf[UINTMAX_STRSIZE_BOUND];
off_t block_ordinal = current_block_ordinal ();
block_ordinal -= recent_long_name_blocks;
block_ordinal -= recent_long_link_blocks;
fprintf (stdlis, _("block %s: "),
STRINGIFY_BIGINT (block_ordinal, buf));
}
ERROR ((0, 0, _("Skipping to next header")));
break;
@@ -187,15 +160,11 @@ read_and (void (*do_something) (void))
case HEADER_FAILURE:
/* We are in the middle of a cascade of errors. */
break;
case HEADER_SUCCESS_EXTENDED:
abort ();
}
continue;
}
break;
}
while (!all_names_found (&current_stat_info));
close_archive ();
names_notfound (); /* print names not found */
@@ -207,9 +176,12 @@ list_archive (void)
{
/* Print the header block. */
decode_header (current_header, &current_stat_info, &current_format, 0);
if (verbose_option)
print_header (&current_stat_info, -1);
{
if (verbose_option > 1)
decode_header (current_header, &current_stat, &current_format, 0);
print_header ();
}
if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
{
@@ -220,10 +192,10 @@ list_archive (void)
set_next_block_after (current_header);
if (multi_volume_option)
{
assign_string (&save_name, current_stat_info.file_name);
save_totsize = current_stat_info.stat.st_size;
assign_string (&save_name, current_file_name);
save_totsize = current_stat.st_size;
}
for (size = current_stat_info.stat.st_size; size > 0; size -= written)
for (size = current_stat.st_size; size > 0; size -= written)
{
if (multi_volume_option)
save_sizeleft = size;
@@ -242,7 +214,7 @@ list_archive (void)
(data_block->buffer + written - 1));
if (check != written)
{
write_error_details (current_stat_info.file_name, check, written);
write_error_details (current_file_name, check, written);
skip_file (size - written);
break;
}
@@ -256,7 +228,7 @@ list_archive (void)
}
if (multi_volume_option)
assign_string (&save_name, current_stat_info.file_name);
assign_string (&save_name, current_file_name);
skip_member ();
@@ -266,7 +238,7 @@ list_archive (void)
/* Read a block that's supposed to be a header block. Return its
address in "current_header", and if it is good, the file's size in
current_stat_info.stat.st_size.
current_stat.st_size.
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
block full of zeros (EOF marker).
@@ -349,74 +321,63 @@ read_header (bool raw_extended_headers)
/* Good block. Decode file size and return. */
if (header->header.typeflag == LNKTYPE)
current_stat_info.stat.st_size = 0; /* links 0 size on tape */
current_stat.st_size = 0; /* links 0 size on tape */
else
current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size);
current_stat.st_size = OFF_FROM_HEADER (header->header.size);
if (header->header.typeflag == GNUTYPE_LONGNAME
|| header->header.typeflag == GNUTYPE_LONGLINK
|| header->header.typeflag == XHDTYPE
|| header->header.typeflag == XGLTYPE)
|| header->header.typeflag == GNUTYPE_LONGLINK)
{
if (raw_extended_headers)
return HEADER_SUCCESS_EXTENDED;
else if (header->header.typeflag == GNUTYPE_LONGNAME
|| header->header.typeflag == GNUTYPE_LONGLINK)
else
{
size_t name_size = current_stat_info.stat.st_size;
size_t name_size = current_stat.st_size;
size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE;
if (name_size != current_stat_info.stat.st_size
|| size < name_size)
if (name_size != current_stat.st_size || size < name_size)
xalloc_die ();
header_copy = xmalloc (size + 1);
if (header->header.typeflag == GNUTYPE_LONGNAME)
{
if (next_long_name)
free (next_long_name);
next_long_name = header_copy;
next_long_name_blocks = size / BLOCKSIZE;
}
else
{
if (next_long_link)
free (next_long_link);
next_long_link = header_copy;
next_long_link_blocks = size / BLOCKSIZE;
}
set_next_block_after (header);
*header_copy = *header;
bp = header_copy->buffer + BLOCKSIZE;
for (size -= BLOCKSIZE; size > 0; size -= written)
{
data_block = find_next_block ();
if (! data_block)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
break;
}
written = available_space_after (data_block);
if (written > size)
written = size;
memcpy (bp, data_block->buffer, written);
bp += written;
set_next_block_after ((union block *)
(data_block->buffer + written - 1));
}
*bp = '\0';
}
else if (header->header.typeflag == XHDTYPE)
xheader_read (header, OFF_FROM_HEADER (header->header.size));
else if (header->header.typeflag == XGLTYPE)
header_copy = xmalloc (size + 1);
if (header->header.typeflag == GNUTYPE_LONGNAME)
{
xheader_read (header, OFF_FROM_HEADER (header->header.size));
xheader_decode_global ();
if (next_long_name)
free (next_long_name);
next_long_name = header_copy;
next_long_name_blocks = size / BLOCKSIZE;
}
else
{
if (next_long_link)
free (next_long_link);
next_long_link = header_copy;
next_long_link_blocks = size / BLOCKSIZE;
}
set_next_block_after (header);
*header_copy = *header;
bp = header_copy->buffer + BLOCKSIZE;
for (size -= BLOCKSIZE; size > 0; size -= written)
{
data_block = find_next_block ();
if (! data_block)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
break;
}
written = available_space_after (data_block);
if (written > size)
written = size;
memcpy (bp, data_block->buffer, written);
bp += written;
set_next_block_after ((union block *)
(data_block->buffer + written - 1));
}
*bp = '\0';
/* Loop! */
@@ -460,9 +421,7 @@ read_header (bool raw_extended_headers)
recent_long_name = 0;
recent_long_name_blocks = 0;
}
assign_string (&current_stat_info.orig_file_name, name);
assign_string (&current_stat_info.file_name, name);
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name);
assign_string (&current_file_name, name);
if (recent_long_link)
free (recent_long_link);
@@ -481,15 +440,13 @@ read_header (bool raw_extended_headers)
recent_long_link = 0;
recent_long_link_blocks = 0;
}
assign_string (&current_stat_info.link_name, name);
assign_string (&current_link_name, name);
return HEADER_SUCCESS;
}
}
}
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
/* Decode things from a file HEADER block into STAT_INFO, also setting
*FORMAT_POINTER depending on the header block format. If
DO_USER_GROUP, decode the user/group information (this is useful
@@ -504,97 +461,68 @@ read_header (bool raw_extended_headers)
should decode it without uid/gid before calling a routine,
e.g. print_header, that assumes decoded data. */
void
decode_header (union block *header, struct tar_stat_info *stat_info,
decode_header (union block *header, struct stat *stat_info,
enum archive_format *format_pointer, int do_user_group)
{
enum archive_format format;
if (strcmp (header->header.magic, TMAGIC) == 0)
{
if (header->star_header.prefix[130] == 0
&& ISOCTAL (header->star_header.atime[0])
&& header->star_header.atime[11] == ' '
&& ISOCTAL (header->star_header.ctime[0])
&& header->star_header.ctime[11] == ' ')
format = STAR_FORMAT;
else if (extended_header.size)
format = POSIX_FORMAT;
else
format = USTAR_FORMAT;
}
format = POSIX_FORMAT;
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
format = OLDGNU_FORMAT;
else
format = V7_FORMAT;
*format_pointer = format;
stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime);
assign_string (&stat_info->uname, header->header.uname);
assign_string (&stat_info->gname, header->header.gname);
stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
stat_info->stat.st_atime = start_time;
stat_info->stat.st_ctime = start_time;
stat_info->st_mode = MODE_FROM_HEADER (header->header.mode);
stat_info->st_mtime = TIME_FROM_HEADER (header->header.mtime);
if (format == OLDGNU_FORMAT && incremental_option)
{
stat_info->stat.st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
stat_info->st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
stat_info->st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
}
if (format == V7_FORMAT)
{
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
stat_info->stat.st_rdev = 0;
stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
stat_info->st_rdev = 0;
}
else
{
if (format == STAR_FORMAT)
{
stat_info->stat.st_atime = TIME_FROM_HEADER (header->star_header.atime);
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->star_header.ctime);
}
if (do_user_group)
{
/* FIXME: Decide if this should somewhat depend on -p. */
if (numeric_owner_option
|| !*header->header.uname
|| !uname_to_uid (header->header.uname, &stat_info->stat.st_uid))
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
|| !uname_to_uid (header->header.uname, &stat_info->st_uid))
stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
if (numeric_owner_option
|| !*header->header.gname
|| !gname_to_gid (header->header.gname, &stat_info->stat.st_gid))
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
|| !gname_to_gid (header->header.gname, &stat_info->st_gid))
stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
}
switch (header->header.typeflag)
{
case BLKTYPE:
stat_info->st_rdev
= makedev (MAJOR_FROM_HEADER (header->header.devmajor),
MINOR_FROM_HEADER (header->header.devminor));
break;
case CHRTYPE:
stat_info->stat.st_rdev = makedev (stat_info->devmajor,
stat_info->devminor);
stat_info->st_rdev
= makedev (MAJOR_FROM_HEADER (header->header.devmajor),
MINOR_FROM_HEADER (header->header.devminor));
break;
default:
stat_info->stat.st_rdev = 0;
stat_info->st_rdev = 0;
}
}
stat_info->archive_file_size = stat_info->stat.st_size;
xheader_decode (stat_info);
if (sparse_member_p (stat_info))
{
sparse_fixup_header (stat_info);
stat_info->is_sparse = true;
}
}
/* Convert buffer at WHERE0 of size DIGS from external format to
@@ -793,7 +721,7 @@ from_header (char const *where0, size_t digs, char const *type,
*--value_string = '-';
if (minus_minval)
*--minval_string = '-';
ERROR ((0, 0, _("Archive value %s is out of %s range %s.%s"),
ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"),
value_string, type,
minval_string, STRINGIFY_BIGINT (maxval, maxval_buf)));
}
@@ -858,7 +786,7 @@ off_from_header (const char *p, size_t s)
size_t
size_from_header (const char *p, size_t s)
{
return from_header (p, s, "size_t", (uintmax_t) 0,
return from_header (p, s, "size_t", (uintmax_t) 0,
(uintmax_t) TYPE_MAXIMUM (size_t));
}
@@ -921,11 +849,11 @@ tartime (time_t t)
#else
/* Use ISO 8610 format. See:
http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
struct tm *tm = utc_option ? gmtime (&t) : localtime (&t);
struct tm *tm = localtime (&t);
if (tm)
{
sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return buffer;
}
@@ -955,7 +883,7 @@ tartime (time_t t)
/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
HEAD_STANDARD, which must be set up in advance. Not very clean.. */
HEAD_STANDARD, which must be set up in advance. Not very clean... */
/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the
columns never shift during the listing. */
@@ -970,12 +898,10 @@ static int ugswidth = UGSWIDTH; /* maximum width encountered so far */
#endif
void
print_header (struct tar_stat_info *st, off_t block_ordinal)
print_header (void)
{
char modes[11];
char const *time_stamp;
char *temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
/* These hold formatted ints. */
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
char *user, *group;
@@ -987,18 +913,14 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
if (block_number_option)
{
char buf[UINTMAX_STRSIZE_BOUND];
if (block_ordinal < 0)
block_ordinal = current_block_ordinal ();
block_ordinal -= recent_long_name_blocks;
block_ordinal -= recent_long_link_blocks;
fprintf (stdlis, _("block %s: "),
STRINGIFY_BIGINT (block_ordinal, buf));
STRINGIFY_BIGINT (current_block_ordinal (), buf));
}
if (verbose_option <= 1)
{
/* Just the fax, mam. */
fprintf (stdlis, "%s\n", quotearg (temp_name));
fprintf (stdlis, "%s\n", quotearg (current_file_name));
}
else
{
@@ -1021,19 +943,16 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
case GNUTYPE_LONGNAME:
case GNUTYPE_LONGLINK:
modes[0] = 'L';
ERROR ((0, 0, _("Visible longname error")));
break;
case GNUTYPE_SPARSE:
case REGTYPE:
case AREGTYPE:
modes[0] = '-';
if (temp_name[strlen (temp_name) - 1] == '/')
modes[0] = 'd';
break;
case LNKTYPE:
modes[0] = 'h';
modes[0] = '-';
if (current_file_name[strlen (current_file_name) - 1] == '/')
modes[0] = 'd';
break;
case GNUTYPE_DUMPDIR:
modes[0] = 'd';
@@ -1058,17 +977,17 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
break;
}
decode_mode (st->stat.st_mode, modes + 1);
decode_mode (current_stat.st_mode, modes + 1);
/* Time stamp. */
time_stamp = tartime (st->stat.st_mtime);
time_stamp = tartime (current_stat.st_mtime);
/* User and group names. */
if (st->uname && current_format != V7_FORMAT
if (*current_header->header.uname && current_format != V7_FORMAT
&& !numeric_owner_option)
user = st->uname;
user = current_header->header.uname;
else
{
/* Try parsing it as an unsigned integer first, and as a
@@ -1088,9 +1007,9 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
}
}
if (st->gname && current_format != V7_FORMAT
if (*current_header->header.gname && current_format != V7_FORMAT
&& !numeric_owner_option)
group = st->gname;
group = current_header->header.gname;
else
{
/* Try parsing it as an unsigned integer first, and as a
@@ -1117,15 +1036,20 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
case CHRTYPE:
case BLKTYPE:
strcpy (size,
STRINGIFY_BIGINT (major (st->stat.st_rdev), uintbuf));
STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf));
strcat (size, ",");
strcat (size,
STRINGIFY_BIGINT (minor (st->stat.st_rdev), uintbuf));
STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf));
break;
case GNUTYPE_SPARSE:
strcpy (size,
STRINGIFY_BIGINT
(UINTMAX_FROM_HEADER (current_header
->oldgnu_header.realsize),
uintbuf));
break;
default:
/* st->stat.st_size keeps stored file size */
strcpy (size, STRINGIFY_BIGINT (st->stat.st_size, uintbuf));
strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf));
break;
}
@@ -1138,16 +1062,16 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
fprintf (stdlis, "%s %s/%s %*s%s %s",
modes, user, group, ugswidth - pad, "", size, time_stamp);
fprintf (stdlis, " %s", quotearg (temp_name));
fprintf (stdlis, " %s", quotearg (current_file_name));
switch (current_header->header.typeflag)
{
case SYMTYPE:
fprintf (stdlis, " -> %s\n", quotearg (st->link_name));
fprintf (stdlis, " -> %s\n", quotearg (current_link_name));
break;
case LNKTYPE:
fprintf (stdlis, _(" link to %s\n"), quotearg (st->link_name));
fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name));
break;
default:
@@ -1172,14 +1096,6 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
putc ('\n', stdlis);
break;
case GNUTYPE_LONGLINK:
fprintf (stdlis, _("--Long Link--\n"));
break;
case GNUTYPE_LONGNAME:
fprintf (stdlis, _("--Long Name--\n"));
break;
case GNUTYPE_VOLHDR:
fprintf (stdlis, _("--Volume Header--\n"));
break;
@@ -1257,10 +1173,19 @@ skip_member (void)
char save_typeflag = current_header->header.typeflag;
set_next_block_after (current_header);
assign_string (&save_name, current_stat_info.file_name);
if (current_header->oldgnu_header.isextended)
{
union block *exhdr;
do
{
exhdr = find_next_block ();
if (!exhdr)
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
set_next_block_after (exhdr);
}
while (exhdr->sparse_header.isextended);
}
if (sparse_member_p (&current_stat_info))
sparse_skip_file (&current_stat_info);
else if (save_typeflag != DIRTYPE)
skip_file (current_stat_info.stat.st_size);
if (save_typeflag != DIRTYPE)
skip_file (current_stat.st_size);
}

View File

@@ -34,7 +34,7 @@ struct mangled
void
extract_mangle (void)
{
off_t size = current_stat_info.stat.st_size;
off_t size = current_stat.st_size;
char *buffer = xmalloc ((size_t) (size + 1));
char *copy = buffer;
char *cursor = buffer;

1023
src/misc.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* Various processing of names.
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
2003, 2004 Free Software Foundation, Inc.
Copyright 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 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
@@ -20,7 +20,9 @@
#include "system.h"
#include <fnmatch.h>
#include <grp.h>
#include <hash.h>
#include <pwd.h>
#include <quotearg.h>
#include "common.h"
@@ -41,15 +43,15 @@ struct group *getgrgid ();
This code should also be modified for non-UNIX systems to do something
reasonable. */
static char *cached_uname;
static char *cached_gname;
static char cached_uname[UNAME_FIELD_SIZE];
static char cached_gname[GNAME_FIELD_SIZE];
static uid_t cached_uid; /* valid only if cached_uname is not empty */
static gid_t cached_gid; /* valid only if cached_gname is not empty */
/* These variables are valid only if nonempty. */
static char *cached_no_such_uname;
static char *cached_no_such_gname;
static char cached_no_such_uname[UNAME_FIELD_SIZE];
static char cached_no_such_gname[GNAME_FIELD_SIZE];
/* These variables are valid only if nonzero. It's not worth optimizing
the case for weird systems where 0 is not a valid uid or gid. */
@@ -58,87 +60,87 @@ static gid_t cached_no_such_gid;
/* Given UID, find the corresponding UNAME. */
void
uid_to_uname (uid_t uid, char **uname)
uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
{
struct passwd *passwd;
if (uid != 0 && uid == cached_no_such_uid)
{
*uname = strdup ("");
*uname = '\0';
return;
}
if (!cached_uname || uid != cached_uid)
if (!cached_uname[0] || uid != cached_uid)
{
passwd = getpwuid (uid);
if (passwd)
{
cached_uid = uid;
assign_string (&cached_uname, passwd->pw_name);
strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
}
else
{
cached_no_such_uid = uid;
*uname = strdup ("");
*uname = '\0';
return;
}
}
*uname = strdup (cached_uname);
strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
}
/* Given GID, find the corresponding GNAME. */
void
gid_to_gname (gid_t gid, char **gname)
gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
{
struct group *group;
if (gid != 0 && gid == cached_no_such_gid)
{
*gname = strdup ("");
*gname = '\0';
return;
}
if (!cached_gname || gid != cached_gid)
if (!cached_gname[0] || gid != cached_gid)
{
group = getgrgid (gid);
if (group)
{
cached_gid = gid;
assign_string (&cached_gname, group->gr_name);
strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
}
else
{
cached_no_such_gid = gid;
*gname = strdup ("");
*gname = '\0';
return;
}
}
*gname = strdup (cached_gname);
strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
}
/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
int
uname_to_uid (char const *uname, uid_t *uidp)
uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
{
struct passwd *passwd;
if (cached_no_such_uname
&& strcmp (uname, cached_no_such_uname) == 0)
if (cached_no_such_uname[0]
&& strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
return 0;
if (!cached_uname
if (!cached_uname[0]
|| uname[0] != cached_uname[0]
|| strcmp (uname, cached_uname) != 0)
|| strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
{
passwd = getpwnam (uname);
if (passwd)
{
cached_uid = passwd->pw_uid;
assign_string (&cached_uname, passwd->pw_name);
strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
}
else
{
assign_string (&cached_no_such_uname, uname);
strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
return 0;
}
}
@@ -148,34 +150,33 @@ uname_to_uid (char const *uname, uid_t *uidp)
/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
int
gname_to_gid (char const *gname, gid_t *gidp)
gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
{
struct group *group;
if (cached_no_such_gname
&& strcmp (gname, cached_no_such_gname) == 0)
if (cached_no_such_gname[0]
&& strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
return 0;
if (!cached_gname
if (!cached_gname[0]
|| gname[0] != cached_gname[0]
|| strcmp (gname, cached_gname) != 0)
|| strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
{
group = getgrnam (gname);
if (group)
{
cached_gid = group->gr_gid;
assign_string (&cached_gname, gname);
strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
}
else
{
assign_string (&cached_no_such_gname, gname);
strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
return 0;
}
}
*gidp = cached_gid;
return 1;
}
/* Names from the command call. */
@@ -227,7 +228,7 @@ is_pattern (const char *string)
/* Set up to gather file names for tar. They can either come from a
file or were saved from decoding arguments. */
void
name_init (void)
name_init (int argc, char *const *argv)
{
name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
name_buffer_length = NAME_FIELD_SIZE;
@@ -438,13 +439,11 @@ name_gather (void)
buffer->change_dir = change_dir;
strcpy (buffer->name, name);
buffer->next = 0;
buffer->found_count = 0;
buffer->found = 0;
namelist = buffer;
nametail = &namelist->next;
}
else if (change_dir)
addname (0, change_dir);
}
else
{
@@ -497,7 +496,7 @@ addname (char const *string, int change_dir)
name->next = 0;
name->length = length;
name->found_count = 0;
name->found = 0;
name->regexp = 0; /* assume not a regular expression */
name->firstch = 1; /* assume first char is literal */
name->change_dir = change_dir;
@@ -532,8 +531,7 @@ namelist_match (char const *path, size_t length)
if (p->regexp
? fnmatch (p->name, path, recursion_option) == 0
: (p->length <= length
&& (path[p->length] == '\0'
|| (ISSLASH (path[p->length]) && recursion_option))
&& (path[p->length] == '\0' || ISSLASH (path[p->length]))
&& memcmp (path, p->name, p->length) == 0))
return p;
}
@@ -566,9 +564,7 @@ name_match (const char *path)
cursor = namelist_match (path, length);
if (cursor)
{
if (!(ISSLASH (path[cursor->length]) && recursion_option)
|| cursor->found_count == 0)
cursor->found_count++; /* remember it matched */
cursor->found = 1; /* remember it matched */
if (starting_file_option)
{
free (namelist);
@@ -576,20 +572,20 @@ name_match (const char *path)
nametail = &namelist;
}
chdir_do (cursor->change_dir);
/* We got a match. */
return ISFOUND (cursor);
return 1;
}
/* Filename from archive not found in namelist. If we have the whole
namelist here, just return 0. Otherwise, read the next name in and
compare it. If this was the last name, namelist->found_count will
remain on. If not, we loop to compare the newly read name. */
compare it. If this was the last name, namelist->found will remain
on. If not, we loop to compare the newly read name. */
if (same_order_option && namelist->found_count)
if (same_order_option && namelist->found)
{
name_gather (); /* read one more */
if (namelist->found_count)
if (namelist->found)
return 0;
}
else
@@ -597,34 +593,6 @@ name_match (const char *path)
}
}
/* Returns true if all names from the namelist were processed.
P is the stat_info of the most recently processed entry.
The decision is postponed until the next entry is read if:
1) P ended with a slash (i.e. it was a directory)
2) P matches any entry from the namelist *and* represents a subdirectory
or a file lying under this entry (in the terms of directory structure).
This is necessary to handle contents of directories. */
bool
all_names_found (struct tar_stat_info *p)
{
struct name const *cursor;
size_t len;
if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
return false;
len = strlen (p->file_name);
for (cursor = namelist; cursor; cursor = cursor->next)
{
if (cursor->regexp
|| (!WASFOUND(cursor) && !cursor->fake)
|| (len >= cursor->length && ISSLASH (p->file_name[cursor->length])))
return false;
}
return true;
}
/* Print the names of things in the namelist that were not matched. */
void
names_notfound (void)
@@ -632,15 +600,9 @@ names_notfound (void)
struct name const *cursor;
for (cursor = namelist; cursor; cursor = cursor->next)
if (!WASFOUND(cursor) && !cursor->fake)
{
if (cursor->found_count == 0)
ERROR ((0, 0, _("%s: Not found in archive"),
quotearg_colon (cursor->name)));
else
ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
quotearg_colon (cursor->name)));
}
if (!cursor->found && !cursor->fake)
ERROR ((0, 0, _("%s: Not found in archive"),
quotearg_colon (cursor->name)));
/* Don't bother freeing the name list; we're about to exit. */
namelist = 0;
@@ -650,7 +612,7 @@ names_notfound (void)
{
char *name;
while ((name = name_next (1)) != NULL)
while (name = name_next (1), name)
ERROR ((0, 0, _("%s: Not found in archive"),
quotearg_colon (name)));
}
@@ -739,7 +701,7 @@ merge_sort (struct name *list, int length,
static int
compare_names (struct name const *n1, struct name const *n2)
{
int found_diff = WASFOUND(n2) - WASFOUND(n1);
int found_diff = n2->found - n1->found;
return found_diff ? found_diff : strcmp (n1->name, n2->name);
}
@@ -761,18 +723,18 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
size_t allocated_length = (name_length >= NAME_FIELD_SIZE
? name_length + NAME_FIELD_SIZE
: NAME_FIELD_SIZE);
char *namebuf = xmalloc (allocated_length + 1);
char *name_buffer = xmalloc (allocated_length + 1);
/* FIXME: + 2 above? */
char *string;
size_t string_length;
int change_dir = name->change_dir;
name->dir_contents = buffer;
strcpy (namebuf, path);
if (! ISSLASH (namebuf[name_length - 1]))
strcpy (name_buffer, path);
if (! ISSLASH (name_buffer[name_length - 1]))
{
namebuf[name_length++] = '/';
namebuf[name_length] = '\0';
name_buffer[name_length++] = '/';
name_buffer[name_length] = '\0';
}
for (string = buffer; *string; string += string_length + 1)
@@ -790,15 +752,15 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
}
while (allocated_length <= name_length + string_length);
namebuf = xrealloc (namebuf, allocated_length + 1);
name_buffer = xrealloc (name_buffer, allocated_length + 1);
}
strcpy (namebuf + name_length, string + 1);
add_hierarchy_to_namelist (addname (namebuf, change_dir),
strcpy (name_buffer + name_length, string + 1);
add_hierarchy_to_namelist (addname (name_buffer, change_dir),
device);
}
}
free (namebuf);
free (name_buffer);
}
}
@@ -825,7 +787,7 @@ collect_and_sort_names (void)
for (name = namelist; name; name = next_name)
{
next_name = name->next;
if (name->found_count || name->dir_contents)
if (name->found || name->dir_contents)
continue;
if (name->regexp) /* FIXME: just skip regexps for now */
continue;
@@ -835,12 +797,15 @@ collect_and_sort_names (void)
if (deref_stat (dereference_option, name->name, &statbuf) != 0)
{
stat_diag (name->name);
if (ignore_failed_read_option)
stat_warn (name->name);
else
stat_error (name->name);
continue;
}
if (S_ISDIR (statbuf.st_mode))
{
name->found_count++;
name->found = 1;
add_hierarchy_to_namelist (name, statbuf.st_dev);
}
}
@@ -851,7 +816,7 @@ collect_and_sort_names (void)
namelist = merge_sort (namelist, num_names, compare_names);
for (name = namelist; name; name = name->next)
name->found_count = 0;
name->found = 0;
}
/* This is like name_match, except that it returns a pointer to the
@@ -871,13 +836,13 @@ name_scan (const char *path)
/* Filename from archive not found in namelist. If we have the whole
namelist here, just return 0. Otherwise, read the next name in and
compare it. If this was the last name, namelist->found_count will
remain on. If not, we loop to compare the newly read name. */
compare it. If this was the last name, namelist->found will remain
on. If not, we loop to compare the newly read name. */
if (same_order_option && namelist && namelist->found_count)
if (same_order_option && namelist && namelist->found)
{
name_gather (); /* read one more */
if (namelist->found_count)
if (namelist->found)
return 0;
}
else
@@ -895,11 +860,11 @@ name_from_list (void)
{
if (!gnu_list_name)
gnu_list_name = namelist;
while (gnu_list_name && (gnu_list_name->found_count || gnu_list_name->fake))
while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
gnu_list_name = gnu_list_name->next;
if (gnu_list_name)
{
gnu_list_name->found_count++;
gnu_list_name->found = 1;
chdir_do (gnu_list_name->change_dir);
return gnu_list_name->name;
}
@@ -913,7 +878,7 @@ blank_name_list (void)
gnu_list_name = 0;
for (name = namelist; name; name = name->next)
name->found_count = 0;
name->found = 0;
}
/* Yield a newly allocated file name consisting of PATH concatenated to
@@ -931,192 +896,46 @@ new_name (const char *path, const char *name)
return buffer;
}
/* Return nonzero if file NAME is excluded. */
/* Return nonzero if file NAME is excluded. Exclude a name if its
prefix matches a pattern that contains slashes, or if one of its
components matches a pattern that contains no slashes. */
bool
excluded_name (char const *name)
{
return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
}
/* Hash tables of strings. */
/* Names to avoid dumping. */
static Hash_table *avoided_name_table;
/* Calculate the hash of a string. */
/* Calculate the hash of an avoided name. */
static unsigned
hash_string_hasher (void const *name, unsigned n_buckets)
hash_avoided_name (void const *name, unsigned n_buckets)
{
return hash_string (name, n_buckets);
}
/* Compare two strings for equality. */
/* Compare two avoided names for equality. */
static bool
hash_string_compare (void const *name1, void const *name2)
compare_avoided_names (void const *name1, void const *name2)
{
return strcmp (name1, name2) == 0;
}
/* Return zero if TABLE contains a copy of STRING; otherwise, insert a
copy of STRING to TABLE and return 1. */
static bool
hash_string_insert (Hash_table **table, char const *string)
{
Hash_table *t = *table;
char *s = xstrdup (string);
char *e;
if (! ((t
|| (*table = t = hash_initialize (0, 0, hash_string_hasher,
hash_string_compare, 0)))
&& (e = hash_insert (t, s))))
xalloc_die ();
if (e == s)
return 1;
else
{
free (s);
return 0;
}
}
/* Return 1 if TABLE contains STRING. */
static bool
hash_string_lookup (Hash_table const *table, char const *string)
{
return table && hash_lookup (table, string);
}
/* Names to avoid dumping. */
static Hash_table *avoided_name_table;
/* Remember to not archive NAME. */
void
add_avoided_name (char const *name)
{
hash_string_insert (&avoided_name_table, name);
if (! ((avoided_name_table
|| (avoided_name_table = hash_initialize (0, 0, hash_avoided_name,
compare_avoided_names, 0)))
&& hash_insert (avoided_name_table, xstrdup (name))))
xalloc_die ();
}
/* Should NAME be avoided when archiving? */
bool
int
is_avoided_name (char const *name)
{
return hash_string_lookup (avoided_name_table, name);
}
/* Return a safer suffix of FILE_NAME, or "." if it has no safer
suffix. Check for fully specified file names and other atrocities.
Warn the user if we do not return NAME. If LINK_TARGET is 1,
FILE_NAME is the target of a hard link, not a member name. */
char *
safer_name_suffix (char const *file_name, bool link_target)
{
char const *p;
if (absolute_names_option)
p = file_name;
else
{
/* Skip file system prefixes, leading pathnames that contain
"..", and leading slashes. */
size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name);
for (p = file_name + prefix_len; *p; )
{
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
prefix_len = p + 2 - file_name;
do
{
char c = *p++;
if (ISSLASH (c))
break;
}
while (*p);
}
for (p = file_name + prefix_len; ISSLASH (*p); p++)
continue;
prefix_len = p - file_name;
if (prefix_len)
{
static Hash_table *prefix_table[2];
char *prefix = alloca (prefix_len + 1);
memcpy (prefix, file_name, prefix_len);
prefix[prefix_len] = '\0';
if (hash_string_insert (&prefix_table[link_target], prefix))
{
static char const *const diagnostic[] =
{
N_("Removing leading `%s' from member names"),
N_("Removing leading `%s' from hard link targets")
};
WARN ((0, 0, _(diagnostic[link_target]), prefix));
}
}
}
if (! *p)
{
if (p == file_name)
{
static char const *const diagnostic[] =
{
N_("Substituting `.' for empty member name"),
N_("Substituting `.' for empty hard link target")
};
WARN ((0, 0, _(diagnostic[link_target])));
}
p = ".";
}
return (char *) p;
}
/* Return the size of the prefix of FILE_NAME that is removed after
stripping NUM leading path name components. NUM must be
positive. */
size_t
stripped_prefix_len (char const *file_name, size_t num)
{
char const *p = file_name + FILESYSTEM_PREFIX_LEN (file_name);
while (ISSLASH (*p))
p++;
while (*p)
{
bool slash = ISSLASH (*p);
p++;
if (slash)
{
if (--num == 0)
return p - file_name;
while (ISSLASH (*p))
p++;
}
}
return -1;
}
/* Return nonzero if NAME contains ".." as a path name component. */
bool
contains_dot_dot (char const *name)
{
char const *p = name + FILESYSTEM_PREFIX_LEN (name);
for (;; p++)
{
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
return 1;
do
{
if (! *p++)
return 0;
}
while (! ISSLASH (*p));
}
return avoided_name_table && hash_lookup (avoided_name_table, name);
}

View File

@@ -1,7 +1,7 @@
/* Remote connection server.
Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004
Free Software Foundation, Inc.
Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001 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
@@ -32,6 +32,7 @@
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
#include "system.h"
#include <print-copyr.h>
#include <localedir.h>
#include <safe-read.h>
#include <full-write.h>
@@ -117,19 +118,19 @@ get_string (char *string)
{
int counter;
for (counter = 0; ; counter++)
for (counter = 0; counter < STRING_SIZE; counter++)
{
if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
exit (EXIT_SUCCESS);
if (string[counter] == '\n' || counter == STRING_SIZE - 1)
if (string[counter] == '\n')
break;
}
string[counter] = '\0';
}
static void
prepare_input_buffer (int fd, size_t size)
prepare_record_buffer (size_t size)
{
if (size <= allocated_size)
return;
@@ -150,14 +151,14 @@ prepare_input_buffer (int fd, size_t size)
allocated_size = size;
#ifdef SO_RCVBUF
if (0 <= fd)
{
int isize = size < INT_MAX ? size : INT_MAX;
while (setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
(char *) &isize, sizeof isize)
&& 1024 < isize)
isize >>= 1;
}
while (size > 1024 &&
(setsockopt (STDIN_FILENO, SOL_SOCKET, SO_RCVBUF,
(char *) &size, sizeof size)
< 0))
size -= 1024;
#else
/* FIXME: I do not see any purpose to the following line... Sigh! */
size = 1 + ((size - 1) % 1024);
#endif
}
@@ -179,11 +180,11 @@ decode_oflag (char const *oflag_string)
char *oflag_num_end;
int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
int symbolic_oflag = 0;
oflag_string = oflag_num_end;
while (ISSPACE ((unsigned char) *oflag_string))
oflag_string++;
do
{
struct name_value_pair { char const *name; int value; };
@@ -247,8 +248,6 @@ static struct option const long_opts[] =
{0, 0, 0, 0}
};
static void usage (int) __attribute__ ((noreturn));
static void
usage (int status)
{
@@ -264,7 +263,7 @@ Manipulate a tape drive, accepting commands from a remote process.\n\
--version Output version info.\n\
--help Output this help.\n"),
program_name);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
}
exit (status);
@@ -274,7 +273,7 @@ int
main (int argc, char *const *argv)
{
char command;
size_t status;
ssize_t status;
/* FIXME: Localization is meaningless, unless --help and --version are
locally used. Localization would be best accomplished by the calling
@@ -289,14 +288,14 @@ main (int argc, char *const *argv)
{
default:
usage (EXIT_FAILURE);
case 'h':
usage (EXIT_SUCCESS);
case 'v':
{
printf ("rmt (%s) %s\n%s\n", PACKAGE_NAME, PACKAGE_VERSION,
"Copyright (C) 2004 Free Software Foundation, Inc.");
printf ("rmt (GNU %s) %s\n", PACKAGE, VERSION);
print_copyright ("2001 Free Software Foundation, Inc.");
puts (_("\
This program comes with NO WARRANTY, to the extent permitted by law.\n\
You may redistribute it under the terms of the GNU General Public License;\n\
@@ -316,7 +315,7 @@ see the file named COPYING for details."));
if (debug_file == 0)
{
report_numbered_error (errno);
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
setbuf (debug_file, 0);
}
@@ -397,7 +396,7 @@ top:
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
{
report_error_message (N_("Seek offset out of range"));
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
count = nc;
}
@@ -410,7 +409,7 @@ top:
case 2: whence = SEEK_END; break;
default:
report_error_message (N_("Seek direction out of range"));
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
count = lseek (tape, count, whence);
if (count < 0)
@@ -423,7 +422,7 @@ top:
do
*--p = '0' + (int) (count % 10);
while ((count /= 10) != 0);
DEBUG1 ("rmtd: A %s\n", p);
sprintf (reply_buffer, "A%s\n", p);
@@ -441,21 +440,21 @@ top:
size = atol (count_string);
DEBUG1 ("rmtd: W %s\n", count_string);
prepare_input_buffer (STDIN_FILENO, size);
prepare_record_buffer (size);
for (counter = 0; counter < size; counter += status)
{
status = safe_read (STDIN_FILENO, &record_buffer[counter],
size - counter);
if (status == SAFE_READ_ERROR || status == 0)
if (status <= 0)
{
DEBUG (_("rmtd: Premature eof\n"));
report_error_message (N_("Premature end of file"));
return EXIT_FAILURE; /* exit status used to be 2 */
exit (EXIT_FAILURE); /* exit status used to be 2 */
}
}
status = full_write (tape, record_buffer, size);
if (status != size)
if (status < 0)
goto ioerror;
goto respond;
}
@@ -469,11 +468,11 @@ top:
DEBUG1 ("rmtd: R %s\n", count_string);
size = atol (count_string);
prepare_input_buffer (-1, size);
prepare_record_buffer (size);
status = safe_read (tape, record_buffer, size);
if (status == SAFE_READ_ERROR)
if (status < 0)
goto ioerror;
sprintf (reply_buffer, "A%lu\n", (unsigned long int) status);
sprintf (reply_buffer, "A%ld\n", (long) status);
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
full_write (STDOUT_FILENO, record_buffer, status);
goto top;
@@ -498,13 +497,13 @@ top:
/* Parse count_string, taking care to check for overflow.
We can't use standard functions,
since off_t might be longer than long. */
for (p = count_string; *p == ' ' || *p == '\t'; p++)
continue;
negative = *p == '-';
p += negative || *p == '+';
for (;;)
{
int digit = *p++ - '0';
@@ -517,7 +516,7 @@ top:
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
{
report_error_message (N_("Seek offset out of range"));
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
count = nc;
}
@@ -527,7 +526,7 @@ top:
if (mtop.mt_count != count)
{
report_error_message (N_("Seek offset out of range"));
return EXIT_FAILURE;
exit (EXIT_FAILURE);
}
mtop.mt_op = atoi (operation_string);
@@ -561,7 +560,7 @@ top:
DEBUG1 (_("rmtd: Garbage command %c\n"), command);
report_error_message (N_("Garbage command"));
return EXIT_FAILURE; /* exit status used to be 3 */
exit (EXIT_FAILURE); /* exit status used to be 3 */
}
respond:

View File

@@ -1,7 +1,5 @@
/* Definitions for communicating with a remote tape drive.
Copyright (C) 1988, 1992, 1996, 1997, 2001, 2003, 2004 Free
Software Foundation, Inc.
Copyright 1988, 1992, 1996, 1997, 2001 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
@@ -19,12 +17,12 @@
extern char *rmt_path__;
int rmt_open__ (const char *, int, int, const char *);
int rmt_close__ (int);
size_t rmt_read__ (int, char *, size_t);
size_t rmt_write__ (int, char *, size_t);
off_t rmt_lseek__ (int, off_t, int);
int rmt_ioctl__ (int, int, char *);
int rmt_open__ PARAMS ((const char *, int, int, const char *));
int rmt_close__ PARAMS ((int));
ssize_t rmt_read__ PARAMS ((int, char *, size_t));
ssize_t rmt_write__ PARAMS ((int, char *, size_t));
off_t rmt_lseek__ PARAMS ((int, off_t, int));
int rmt_ioctl__ PARAMS ((int, int, char *));
/* A filename is remote if it contains a colon not preceded by a slash,
to take care of `/:/' which is a shorthand for `/.../<CELL-NAME>/fs'
@@ -34,7 +32,7 @@ int rmt_ioctl__ (int, int, char *);
#define _remdev(Path) \
(!force_local_option && (rmt_path__ = strchr (Path, ':')) \
&& rmt_path__ > (Path) && ! memchr (Path, '/', rmt_path__ - (Path)))
&& rmt_path__ > (Path) && ! memchr (Path, rmt_path__ - (Path), '/'))
#define _isrmt(Fd) \
((Fd) >= __REM_BIAS)

View File

@@ -1,7 +1,7 @@
/* Functions for communicating with a remote tape drive.
Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004 Free
Software Foundation, Inc.
Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 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
@@ -33,7 +33,7 @@
code, courtesy of Dan Kegel. */
#include "system.h"
#include "common.h"
#include <safe-read.h>
#include <full-write.h>
@@ -88,8 +88,6 @@ static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
/* The pipes for sending data to remote tape drives. */
static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
#define RMT_COMMAND (rmt_command_option ? rmt_command_option : "/etc/rmt")
/* Temporary variable used by macros in rmt.h. */
char *rmt_path__;
@@ -165,6 +163,8 @@ get_status_string (int handle, char *command_buffer)
if (*cursor == 'E' || *cursor == 'F')
{
errno = atoi (cursor + 1);
/* Skip the error message line. */
/* FIXME: there is better to do than merely ignoring error messages
@@ -178,8 +178,6 @@ get_status_string (int handle, char *command_buffer)
break;
}
errno = atoi (cursor + 1);
if (*cursor == 'F')
_rmt_shutdown (handle, errno);
@@ -201,19 +199,12 @@ get_status_string (int handle, char *command_buffer)
/* Read and return the status from remote tape connection HANDLE. If
an error occurred, return -1 and set errno. */
static long int
static long
get_status (int handle)
{
char command_buffer[COMMAND_BUFFER_SIZE];
const char *status = get_status_string (handle, command_buffer);
if (status)
{
long int result = atol (status);
if (0 <= result)
return result;
errno = EIO;
}
return -1;
return status ? atol (status) : -1L;
}
static off_t
@@ -235,10 +226,10 @@ get_status_off (int handle)
for (; *status == ' ' || *status == '\t'; status++)
continue;
negative = *status == '-';
status += negative || *status == '+';
for (;;)
{
int digit = *status++ - '0';
@@ -291,7 +282,7 @@ _rmt_rexec (char *host, char *user)
if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
result = rexec (&host, rexecserv->s_port, user, 0, RMT_COMMAND, 0);
result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
if (fclose (stdin) == EOF)
error (0, errno, _("stdin"));
fdopen (saved_stdin, "r");
@@ -491,14 +482,17 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
close (from_remote[remote_pipe_number][PREAD]);
close (from_remote[remote_pipe_number][PWRITE]);
sys_reset_uid_gid ();
#if !MSDOS
setuid (getuid ());
setgid (getgid ());
#endif
if (remote_user)
execl (remote_shell, remote_shell_basename, remote_host,
"-l", remote_user, RMT_COMMAND, (char *) 0);
"-l", remote_user, "/etc/rmt", (char *) 0);
else
execl (remote_shell, remote_shell_basename, remote_host,
RMT_COMMAND, (char *) 0);
"/etc/rmt", (char *) 0);
/* Bad problems if we get here. */
@@ -542,7 +536,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
int
rmt_close__ (int handle)
{
long int status;
int status;
if (do_command (handle, "C\n") == -1)
return -1;
@@ -553,27 +547,26 @@ rmt_close__ (int handle)
}
/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
Return the number of bytes read on success, SAFE_READ_ERROR on error. */
size_t
Return the number of bytes read on success, -1 on error. */
ssize_t
rmt_read__ (int handle, char *buffer, size_t length)
{
char command_buffer[COMMAND_BUFFER_SIZE];
size_t status;
size_t rlen;
ssize_t status, rlen;
size_t counter;
sprintf (command_buffer, "R%lu\n", (unsigned long) length);
if (do_command (handle, command_buffer) == -1
|| (status = get_status (handle)) == SAFE_READ_ERROR)
return SAFE_READ_ERROR;
|| (status = get_status (handle)) == -1)
return -1;
for (counter = 0; counter < status; counter += rlen, buffer += rlen)
{
rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
if (rlen == SAFE_READ_ERROR || rlen == 0)
if (rlen <= 0)
{
_rmt_shutdown (handle, EIO);
return SAFE_READ_ERROR;
return -1;
}
}
@@ -581,8 +574,8 @@ rmt_read__ (int handle, char *buffer, size_t length)
}
/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
Return the number of bytes written. */
size_t
Return the number of bytes written on success, -1 on error. */
ssize_t
rmt_write__ (int handle, char *buffer, size_t length)
{
char command_buffer[COMMAND_BUFFER_SIZE];
@@ -591,25 +584,18 @@ rmt_write__ (int handle, char *buffer, size_t length)
sprintf (command_buffer, "W%lu\n", (unsigned long) length);
if (do_command (handle, command_buffer) == -1)
return 0;
return -1;
pipe_handler = signal (SIGPIPE, SIG_IGN);
written = full_write (WRITE_SIDE (handle), buffer, length);
signal (SIGPIPE, pipe_handler);
if (written == length)
{
long int r = get_status (handle);
if (r < 0)
return 0;
if (r == length)
return length;
written = r;
}
return get_status (handle);
/* Write error. */
_rmt_shutdown (handle, EIO);
return written;
return -1;
}
/* Perform an imitation lseek operation on remote tape connection
@@ -622,7 +608,6 @@ rmt_lseek__ (int handle, off_t offset, int whence)
uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
char *p = operand_buffer + sizeof operand_buffer;
*--p = 0;
do
*--p = '0' + (int) (u % 10);
while ((u /= 10) != 0);
@@ -665,8 +650,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
? - (uintmax_t) ((struct mtop *) argument)->mt_count
: (uintmax_t) ((struct mtop *) argument)->mt_count);
char *p = operand_buffer + sizeof operand_buffer;
*--p = 0;
do
*--p = '0' + (int) (u % 10);
while ((u /= 10) != 0);
@@ -688,7 +672,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
case MTIOCGET:
{
ssize_t status;
size_t counter;
ssize_t counter;
/* Grab the status and read it directly into the structure. This
assumes that the status buffer is not padded and that 2 shorts
@@ -703,7 +687,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
for (; status > 0; status -= counter, argument += counter)
{
counter = safe_read (READ_SIDE (handle), argument, status);
if (counter == SAFE_READ_ERROR || counter == 0)
if (counter <= 0)
{
_rmt_shutdown (handle, EIO);
return -1;

View File

@@ -1,859 +0,0 @@
/* Functions for dealing with sparse files
Copyright (C) 2003, 2004 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. */
#include "system.h"
#include <quotearg.h>
#include "common.h"
struct tar_sparse_file;
enum sparse_scan_state
{
scan_begin,
scan_block,
scan_end
};
struct tar_sparse_optab
{
bool (*init) (struct tar_sparse_file *);
bool (*done) (struct tar_sparse_file *);
bool (*sparse_member_p) (struct tar_sparse_file *);
bool (*dump_header) (struct tar_sparse_file *);
bool (*fixup_header) (struct tar_sparse_file *);
bool (*decode_header) (struct tar_sparse_file *);
bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
void *);
bool (*dump_region) (struct tar_sparse_file *, size_t);
bool (*extract_region) (struct tar_sparse_file *, size_t);
};
struct tar_sparse_file
{
int fd; /* File descriptor */
size_t dumped_size; /* Number of bytes actually written
to the archive */
struct tar_stat_info *stat_info; /* Information about the file */
struct tar_sparse_optab *optab;
void *closure; /* Any additional data optab calls might
reqiure */
};
static bool
tar_sparse_member_p (struct tar_sparse_file *file)
{
if (file->optab->sparse_member_p)
return file->optab->sparse_member_p (file);
return false;
}
static bool
tar_sparse_init (struct tar_sparse_file *file)
{
file->dumped_size = 0;
if (file->optab->init)
return file->optab->init (file);
return true;
}
static bool
tar_sparse_done (struct tar_sparse_file *file)
{
if (file->optab->done)
return file->optab->done (file);
return true;
}
static bool
tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
void *block)
{
if (file->optab->scan_block)
return file->optab->scan_block (file, state, block);
return true;
}
static bool
tar_sparse_dump_region (struct tar_sparse_file *file, size_t i)
{
if (file->optab->dump_region)
return file->optab->dump_region (file, i);
return false;
}
static bool
tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
{
if (file->optab->extract_region)
return file->optab->extract_region (file, i);
return false;
}
static bool
tar_sparse_dump_header (struct tar_sparse_file *file)
{
if (file->optab->dump_header)
return file->optab->dump_header (file);
return false;
}
static bool
tar_sparse_decode_header (struct tar_sparse_file *file)
{
if (file->optab->decode_header)
return file->optab->decode_header (file);
return true;
}
static bool
tar_sparse_fixup_header (struct tar_sparse_file *file)
{
if (file->optab->fixup_header)
return file->optab->fixup_header (file);
return true;
}
static bool
lseek_or_error (struct tar_sparse_file *file, off_t offset, int whence)
{
if (lseek (file->fd, offset, whence) < 0)
{
seek_diag_details (file->stat_info->orig_file_name, offset);
return false;
}
return true;
}
/* Takes a blockful of data and basically cruises through it to see if
it's made *entirely* of zeros, returning a 0 the instant it finds
something that is a nonzero, i.e., useful data. */
static bool
zero_block_p (char *buffer, size_t size)
{
while (size--)
if (*buffer++)
return false;
return true;
}
#define clear_block(p) memset (p, 0, BLOCKSIZE);
#define SPARSES_INIT_COUNT SPARSES_IN_SPARSE_HEADER
static void
sparse_add_map (struct tar_sparse_file *file, struct sp_array *sp)
{
if (file->stat_info->sparse_map == NULL)
{
file->stat_info->sparse_map =
xmalloc (SPARSES_INIT_COUNT * sizeof file->stat_info->sparse_map[0]);
file->stat_info->sparse_map_size = SPARSES_INIT_COUNT;
}
else if (file->stat_info->sparse_map_avail == file->stat_info->sparse_map_size)
{
file->stat_info->sparse_map_size *= 2;
file->stat_info->sparse_map =
xrealloc (file->stat_info->sparse_map,
file->stat_info->sparse_map_size
* sizeof file->stat_info->sparse_map[0]);
}
file->stat_info->sparse_map[file->stat_info->sparse_map_avail++] = *sp;
}
/* Scan the sparse file and create its map */
static bool
sparse_scan_file (struct tar_sparse_file *file)
{
static char buffer[BLOCKSIZE];
size_t count;
size_t offset = 0;
struct sp_array sp = {0, 0};
if (!lseek_or_error (file, 0, SEEK_SET))
return false;
clear_block (buffer);
file->stat_info->sparse_map_size = 0;
file->stat_info->archive_file_size = 0;
if (!tar_sparse_scan (file, scan_begin, NULL))
return false;
while ((count = safe_read (file->fd, buffer, sizeof buffer)) != 0
&& count != SAFE_READ_ERROR)
{
/* Analize the block */
if (zero_block_p (buffer, count))
{
if (sp.numbytes)
{
sparse_add_map (file, &sp);
sp.numbytes = 0;
if (!tar_sparse_scan (file, scan_block, NULL))
return false;
}
}
else
{
if (sp.numbytes == 0)
sp.offset = offset;
sp.numbytes += count;
file->stat_info->archive_file_size += count;
if (!tar_sparse_scan (file, scan_block, buffer))
return false;
}
offset += count;
clear_block (buffer);
}
if (sp.numbytes == 0)
sp.offset = offset;
sparse_add_map (file, &sp);
file->stat_info->archive_file_size += count;
return tar_sparse_scan (file, scan_end, NULL);
}
static struct tar_sparse_optab oldgnu_optab;
static struct tar_sparse_optab star_optab;
static struct tar_sparse_optab pax_optab;
static bool
sparse_select_optab (struct tar_sparse_file *file)
{
switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)
{
case V7_FORMAT:
case USTAR_FORMAT:
return false;
case OLDGNU_FORMAT:
case GNU_FORMAT: /*FIXME: This one should disappear? */
file->optab = &oldgnu_optab;
break;
case POSIX_FORMAT:
file->optab = &pax_optab;
break;
case STAR_FORMAT:
file->optab = &star_optab;
break;
default:
return false;
}
return true;
}
static bool
sparse_dump_region (struct tar_sparse_file *file, size_t i)
{
union block *blk;
off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
SEEK_SET))
return false;
while (bytes_left > 0)
{
size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
size_t bytes_read;
blk = find_next_block ();
memset (blk->buffer, 0, BLOCKSIZE);
bytes_read = safe_read (file->fd, blk->buffer, bufsize);
if (bytes_read == SAFE_READ_ERROR)
{
read_diag_details (file->stat_info->orig_file_name,
file->stat_info->sparse_map[i].offset
+ file->stat_info->sparse_map[i].numbytes
- bytes_left,
bufsize);
return false;
}
bytes_left -= bytes_read;
file->dumped_size += bytes_read;
set_next_block_after (blk);
}
return true;
}
static bool
sparse_extract_region (struct tar_sparse_file *file, size_t i)
{
size_t write_size;
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
SEEK_SET))
return false;
write_size = file->stat_info->sparse_map[i].numbytes;
if (write_size == 0)
{
/* Last block of the file is a hole */
if (sys_truncate (file->fd))
truncate_warn (file->stat_info->orig_file_name);
}
else while (write_size > 0)
{
size_t count;
size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
union block *blk = find_next_block ();
if (!blk)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return false;
}
set_next_block_after (blk);
count = full_write (file->fd, blk->buffer, wrbytes);
write_size -= count;
file->dumped_size += count;
if (count != wrbytes)
{
write_error_details (file->stat_info->orig_file_name,
count, wrbytes);
return false;
}
}
return true;
}
/* Interface functions */
enum dump_status
sparse_dump_file (int fd, struct tar_stat_info *st)
{
bool rc;
struct tar_sparse_file file;
file.stat_info = st;
file.fd = fd;
if (!sparse_select_optab (&file)
|| !tar_sparse_init (&file))
return dump_status_not_implemented;
rc = sparse_scan_file (&file);
if (rc && file.optab->dump_region)
{
tar_sparse_dump_header (&file);
if (fd >= 0)
{
size_t i;
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
rc = tar_sparse_dump_region (&file, i);
}
}
pad_archive(file.stat_info->archive_file_size - file.dumped_size);
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
}
/* Returns true if the file represented by stat is a sparse one */
bool
sparse_file_p (struct tar_stat_info *st)
{
return (ST_NBLOCKS (st->stat)
< (st->stat.st_size / ST_NBLOCKSIZE
+ (st->stat.st_size % ST_NBLOCKSIZE != 0)));
}
bool
sparse_member_p (struct tar_stat_info *st)
{
struct tar_sparse_file file;
if (!sparse_select_optab (&file))
return false;
file.stat_info = st;
return tar_sparse_member_p (&file);
}
bool
sparse_fixup_header (struct tar_stat_info *st)
{
struct tar_sparse_file file;
if (!sparse_select_optab (&file))
return false;
file.stat_info = st;
return tar_sparse_fixup_header (&file);
}
enum dump_status
sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
{
bool rc = true;
struct tar_sparse_file file;
size_t i;
file.stat_info = st;
file.fd = fd;
if (!sparse_select_optab (&file)
|| !tar_sparse_init (&file))
return dump_status_not_implemented;
rc = tar_sparse_decode_header (&file);
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
rc = tar_sparse_extract_region (&file, i);
*size = file.stat_info->archive_file_size - file.dumped_size;
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
}
enum dump_status
sparse_skip_file (struct tar_stat_info *st)
{
bool rc = true;
struct tar_sparse_file file;
file.stat_info = st;
file.fd = -1;
if (!sparse_select_optab (&file)
|| !tar_sparse_init (&file))
return dump_status_not_implemented;
rc = tar_sparse_decode_header (&file);
skip_file (file.stat_info->archive_file_size);
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
}
static char diff_buffer[BLOCKSIZE];
static bool
check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
{
if (!lseek_or_error (file, beg, SEEK_SET))
return false;
while (beg < end)
{
size_t bytes_read;
size_t rdsize = end - beg;
if (rdsize > BLOCKSIZE)
rdsize = BLOCKSIZE;
clear_block (diff_buffer);
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
if (bytes_read == SAFE_READ_ERROR)
{
read_diag_details (file->stat_info->orig_file_name,
beg,
rdsize);
return false;
}
if (!zero_block_p (diff_buffer, bytes_read))
{
report_difference (file->stat_info,
_("File fragment at %lu is not a hole"), beg);
return false;
}
beg += bytes_read;
}
return true;
}
static bool
check_data_region (struct tar_sparse_file *file, size_t i)
{
size_t size_left;
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
SEEK_SET))
return false;
size_left = file->stat_info->sparse_map[i].numbytes;
while (size_left > 0)
{
size_t bytes_read;
size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
union block *blk = find_next_block ();
if (!blk)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return false;
}
set_next_block_after (blk);
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
if (bytes_read == SAFE_READ_ERROR)
{
read_diag_details (file->stat_info->orig_file_name,
file->stat_info->sparse_map[i].offset
+ file->stat_info->sparse_map[i].numbytes
- size_left,
rdsize);
return false;
}
file->dumped_size += bytes_read;
size_left -= bytes_read;
if (memcmp (blk->buffer, diff_buffer, rdsize))
{
report_difference (file->stat_info, _("Contents differ"));
return false;
}
}
return true;
}
bool
sparse_diff_file (int fd, struct tar_stat_info *st)
{
bool rc = true;
struct tar_sparse_file file;
size_t i;
off_t offset = 0;
file.stat_info = st;
file.fd = fd;
if (!sparse_select_optab (&file)
|| !tar_sparse_init (&file))
return dump_status_not_implemented;
rc = tar_sparse_decode_header (&file);
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
{
rc = check_sparse_region (&file,
offset, file.stat_info->sparse_map[i].offset)
&& check_data_region (&file, i);
offset = file.stat_info->sparse_map[i].offset
+ file.stat_info->sparse_map[i].numbytes;
}
if (!rc)
skip_file (file.stat_info->archive_file_size - file.dumped_size);
tar_sparse_done (&file);
return rc;
}
/* Old GNU Format. The sparse file information is stored in the
oldgnu_header in the following manner:
The header is marked with type 'S'. Its `size' field contains
the cumulative size of all non-empty blocks of the file. The
actual file size is stored in `realsize' member of oldgnu_header.
The map of the file is stored in a list of `struct sparse'.
Each struct contains offset to the block of data and its
size (both as octal numbers). The first file header contains
at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
contains more structs, then the field `isextended' of the main
header is set to 1 (binary) and the `struct sparse_header'
header follows, containing at most 21 following structs
(SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
field of the extended header is set and next next extension header
follows, etc... */
enum oldgnu_add_status
{
add_ok,
add_finish,
add_fail
};
static bool
oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
{
return current_header->header.typeflag == GNUTYPE_SPARSE;
}
/* Add a sparse item to the sparse file and its obstack */
static enum oldgnu_add_status
oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
{
struct sp_array sp;
if (s->numbytes[0] == '\0')
return add_finish;
sp.offset = OFF_FROM_HEADER (s->offset);
sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
if (sp.offset < 0
|| file->stat_info->stat.st_size < sp.offset + sp.numbytes
|| file->stat_info->archive_file_size < 0)
return add_fail;
sparse_add_map (file, &sp);
return add_ok;
}
static bool
oldgnu_fixup_header (struct tar_sparse_file *file)
{
/* NOTE! st_size was initialized from the header
which actually contains archived size. The following fixes it */
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
file->stat_info->stat.st_size =
OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
return true;
}
/* Convert old GNU format sparse data to internal representation */
static bool
oldgnu_get_sparse_info (struct tar_sparse_file *file)
{
size_t i;
union block *h = current_header;
int ext_p;
static enum oldgnu_add_status rc;
file->stat_info->sparse_map_size = 0;
for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
{
rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
if (rc != add_ok)
break;
}
for (ext_p = h->oldgnu_header.isextended;
rc == add_ok && ext_p; ext_p = h->sparse_header.isextended)
{
h = find_next_block ();
if (!h)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return false;
}
set_next_block_after (h);
for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
}
if (rc == add_fail)
{
ERROR ((0, 0, _("%s: invalid sparse archive member"),
file->stat_info->orig_file_name));
return false;
}
return true;
}
static void
oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
struct sparse *sp, size_t sparse_size)
{
for (; *pindex < file->stat_info->sparse_map_avail
&& sparse_size > 0; sparse_size--, sp++, ++*pindex)
{
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
sp->offset);
SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
sp->numbytes);
}
}
static bool
oldgnu_dump_header (struct tar_sparse_file *file)
{
off_t block_ordinal = current_block_ordinal ();
union block *blk;
size_t i;
blk = start_header (file->stat_info);
blk->header.typeflag = GNUTYPE_SPARSE;
if (file->stat_info->sparse_map_avail > SPARSES_IN_OLDGNU_HEADER)
blk->oldgnu_header.isextended = 1;
/* Store the real file size */
OFF_TO_CHARS (file->stat_info->stat.st_size, blk->oldgnu_header.realsize);
/* Store the effective (shrunken) file size */
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
i = 0;
oldgnu_store_sparse_info (file, &i,
blk->oldgnu_header.sp,
SPARSES_IN_OLDGNU_HEADER);
blk->oldgnu_header.isextended = i < file->stat_info->sparse_map_avail;
finish_header (file->stat_info, blk, block_ordinal);
while (i < file->stat_info->sparse_map_avail)
{
blk = find_next_block ();
memset (blk->buffer, 0, BLOCKSIZE);
oldgnu_store_sparse_info (file, &i,
blk->sparse_header.sp,
SPARSES_IN_SPARSE_HEADER);
set_next_block_after (blk);
if (i < file->stat_info->sparse_map_avail)
blk->sparse_header.isextended = 1;
else
break;
}
return true;
}
static struct tar_sparse_optab oldgnu_optab = {
NULL, /* No init function */
NULL, /* No done function */
oldgnu_sparse_member_p,
oldgnu_dump_header,
oldgnu_fixup_header,
oldgnu_get_sparse_info,
NULL, /* No scan_block function */
sparse_dump_region,
sparse_extract_region,
};
/* Star */
static bool
star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
{
return current_header->header.typeflag == GNUTYPE_SPARSE;
}
static bool
star_fixup_header (struct tar_sparse_file *file)
{
/* NOTE! st_size was initialized from the header
which actually contains archived size. The following fixes it */
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
file->stat_info->stat.st_size =
OFF_FROM_HEADER (current_header->star_in_header.realsize);
return true;
}
/* Convert STAR format sparse data to internal representation */
static bool
star_get_sparse_info (struct tar_sparse_file *file)
{
size_t i;
union block *h = current_header;
int ext_p;
static enum oldgnu_add_status rc;
file->stat_info->sparse_map_size = 0;
if (h->star_in_header.prefix[0] == '\0'
&& h->star_in_header.sp[0].offset[10] != '\0')
{
/* Old star format */
for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
{
rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
if (rc != add_ok)
break;
}
ext_p = h->star_in_header.isextended;
}
else
ext_p = 1;
for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended)
{
h = find_next_block ();
if (!h)
{
ERROR ((0, 0, _("Unexpected EOF in archive")));
return false;
}
set_next_block_after (h);
for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
}
if (rc == add_fail)
{
ERROR ((0, 0, _("%s: invalid sparse archive member"),
file->stat_info->orig_file_name));
return false;
}
return true;
}
static struct tar_sparse_optab star_optab = {
NULL, /* No init function */
NULL, /* No done function */
star_sparse_member_p,
NULL,
star_fixup_header,
star_get_sparse_info,
NULL, /* No scan_block function */
NULL, /* No dump region function */
sparse_extract_region,
};
/* GNU PAX sparse file format. The sparse file map is stored in
x header:
GNU.sparse.size Real size of the stored file
GNU.sparse.numblocks Number of blocks in the sparse map
repeat numblocks time
GNU.sparse.offset Offset of the next data block
GNU.sparse.numbytes Size of the next data block
end repeat
*/
static bool
pax_sparse_member_p (struct tar_sparse_file *file)
{
return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
}
static bool
pax_dump_header (struct tar_sparse_file *file)
{
off_t block_ordinal = current_block_ordinal ();
union block *blk;
size_t i;
/* Store the real file size */
xheader_store ("GNU.sparse.size", file->stat_info, NULL);
xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
{
xheader_store ("GNU.sparse.offset", file->stat_info, &i);
xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
}
blk = start_header (file->stat_info);
/* Store the effective (shrunken) file size */
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
finish_header (file->stat_info, blk, block_ordinal);
return true;
}
static struct tar_sparse_optab pax_optab = {
NULL, /* No init function */
NULL, /* No done function */
pax_sparse_member_p,
pax_dump_header,
NULL, /* No decode_header function */
NULL, /* No fixup_header function */
NULL, /* No scan_block function */
sparse_dump_region,
sparse_extract_region,
};

View File

@@ -1,643 +0,0 @@
/* System-dependent calls for tar.
Copyright (C) 2003, 2004 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. */
#include "system.h"
#include "common.h"
#include "rmt.h"
#include <signal.h>
void
sys_stat_nanoseconds (struct tar_stat_info *st)
{
#if defined(HAVE_STRUCT_STAT_ST_SPARE1)
st->atime_nsec = st->stat.st_spare1 * 1000;
st->mtime_nsec = st->stat.st_spare2 * 1000;
st->ctime_nsec = st->stat.st_spare3 * 1000;
#elif defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
st->atime_nsec = st->stat.st_atim.tv_nsec;
st->mtime_nsec = st->stat.st_mtim.tv_nsec;
st->ctime_nsec = st->stat.st_ctim.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
st->atime_nsec = st->stat.st_atimespec.tv_nsec;
st->mtime_nsec = st->stat.st_mtimespec.tv_nsec;
st->ctime_nsec = st->stat.st_ctimespec.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
st->atime_nsec = st->stat.st_atimensec;
st->mtime_nsec = st->stat.st_mtimensec;
st->ctime_nsec = st->stat.st_ctimensec;
#else
st->atime_nsec = st->mtime_nsec = st->ctime_nsec = 0;
#endif
}
#if MSDOS
bool
sys_get_archive_stat (void)
{
return 0;
}
bool
sys_file_is_archive (struct tar_stat_info *p)
{
return false;
}
void
sys_save_archive_dev_ino (void)
{
}
void
sys_detect_dev_null_output (void)
{
static char const dev_null[] = "nul";
dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
|| (! _isrmt (archive)));
}
void
sys_drain_input_pipe (void)
{
}
void
sys_wait_for_child (pid_t child_pid)
{
}
void
sys_spawn_shell (void)
{
spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
}
/* stat() in djgpp's C library gives a constant number of 42 as the
uid and gid of a file. So, comparing an FTP'ed archive just after
unpack would fail on MSDOS. */
bool
sys_compare_uid (struct stat *a, struct stat *b)
{
return true;
}
bool
sys_compare_gid (struct stat *a, struct stat *b)
{
return true;
}
void
sys_compare_links (struct stat *link_data, struct stat *stat_data)
{
return true;
}
int
sys_truncate (int fd)
{
return write (fd, "", 0);
}
void
sys_reset_uid_gid (void)
{
}
size_t
sys_write_archive_buffer (void)
{
return full_write (archive, record_start->buffer, record_size);
}
/* Set ARCHIVE for writing, then compressing an archive. */
void
sys_child_open_for_compress (void)
{
FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
}
/* Set ARCHIVE for uncompressing, then reading an archive. */
void
sys_child_open_for_uncompress (void)
{
FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
}
#else
extern union block *record_start; /* FIXME */
static struct stat archive_stat; /* stat block for archive file */
bool
sys_get_archive_stat (void)
{
return fstat (archive, &archive_stat) == 0;
}
bool
sys_file_is_archive (struct tar_stat_info *p)
{
return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
}
/* Save archive file inode and device numbers */
void
sys_save_archive_dev_ino (void)
{
if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
{
ar_dev = archive_stat.st_dev;
ar_ino = archive_stat.st_ino;
}
else
ar_dev = 0;
}
/* Detect if outputting to "/dev/null". */
void
sys_detect_dev_null_output (void)
{
static char const dev_null[] = "/dev/null";
struct stat dev_null_stat;
dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
|| (! _isrmt (archive)
&& S_ISCHR (archive_stat.st_mode)
&& stat (dev_null, &dev_null_stat) == 0
&& archive_stat.st_dev == dev_null_stat.st_dev
&& archive_stat.st_ino == dev_null_stat.st_ino));
}
/* Manage to fully drain a pipe we might be reading, so to not break it on
the producer after the EOF block. FIXME: one of these days, GNU tar
might become clever enough to just stop working, once there is no more
work to do, we might have to revise this area in such time. */
void
sys_drain_input_pipe (void)
{
size_t r;
if (access_mode == ACCESS_READ
&& ! _isrmt (archive)
&& (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
&& r != SAFE_READ_ERROR)
continue;
}
void
sys_wait_for_child (pid_t child_pid)
{
if (child_pid)
{
int wait_status;
while (waitpid (child_pid, &wait_status, 0) == -1)
if (errno != EINTR)
{
waitpid_error (use_compress_program_option);
break;
}
if (WIFSIGNALED (wait_status))
ERROR ((0, 0, _("Child died with signal %d"),
WTERMSIG (wait_status)));
else if (WEXITSTATUS (wait_status) != 0)
ERROR ((0, 0, _("Child returned status %d"),
WEXITSTATUS (wait_status)));
}
}
void
sys_spawn_shell (void)
{
pid_t child;
const char *shell = getenv ("SHELL");
if (! shell)
shell = "/bin/sh";
child = xfork ();
if (child == 0)
{
execlp (shell, "-sh", "-i", (char *) 0);
exec_fatal (shell);
}
else
{
int wait_status;
while (waitpid (child, &wait_status, 0) == -1)
if (errno != EINTR)
{
waitpid_error (shell);
break;
}
}
}
bool
sys_compare_uid (struct stat *a, struct stat *b)
{
return a->st_uid == b->st_uid;
}
bool
sys_compare_gid (struct stat *a, struct stat *b)
{
return a->st_gid == b->st_gid;
}
bool
sys_compare_links (struct stat *link_data, struct stat *stat_data)
{
return stat_data->st_dev == link_data->st_dev
&& stat_data->st_ino == link_data->st_ino;
}
int
sys_truncate (int fd)
{
off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
return pos < 0 ? -1 : ftruncate (fd, pos);
}
void
sys_reset_uid_gid (void)
{
setuid (getuid ());
setgid (getgid ());
}
/* Return nonzero if NAME is the name of a regular file, or if the file
does not exist (so it would be created as a regular file). */
static int
is_regular_file (const char *name)
{
struct stat stbuf;
if (stat (name, &stbuf) == 0)
return S_ISREG (stbuf.st_mode);
else
return errno == ENOENT;
}
size_t
sys_write_archive_buffer (void)
{
return rmtwrite (archive, record_start->buffer, record_size);
}
#define PREAD 0 /* read file descriptor from pipe() */
#define PWRITE 1 /* write file descriptor from pipe() */
/* Duplicate file descriptor FROM into becoming INTO.
INTO is closed first and has to be the next available slot. */
static void
xdup2 (int from, int into)
{
if (from != into)
{
int status = close (into);
if (status != 0 && errno != EBADF)
{
int e = errno;
FATAL_ERROR ((0, e, _("Cannot close")));
}
status = dup (from);
if (status != into)
{
if (status < 0)
{
int e = errno;
FATAL_ERROR ((0, e, _("Cannot dup")));
}
abort ();
}
xclose (from);
}
}
/* Set ARCHIVE for writing, then compressing an archive. */
pid_t
sys_child_open_for_compress (void)
{
int parent_pipe[2];
int child_pipe[2];
pid_t grandchild_pid;
pid_t child_pid;
int wait_status;
xpipe (parent_pipe);
child_pid = xfork ();
if (child_pid > 0)
{
/* The parent tar is still here! Just clean up. */
archive = parent_pipe[PWRITE];
xclose (parent_pipe[PREAD]);
return child_pid;
}
/* The new born child tar is here! */
program_name = _("tar (child)");
xdup2 (parent_pipe[PREAD], STDIN_FILENO);
xclose (parent_pipe[PWRITE]);
/* Check if we need a grandchild tar. This happens only if either:
a) we are writing stdout: to force reblocking;
b) the file is to be accessed by rmt: compressor doesn't know how;
c) the file is not a plain file. */
if (strcmp (archive_name_array[0], "-") != 0
&& !_remdev (archive_name_array[0])
&& is_regular_file (archive_name_array[0]))
{
if (backup_option)
maybe_backup_file (archive_name_array[0], 1);
/* We don't need a grandchild tar. Open the archive and launch the
compressor. */
archive = creat (archive_name_array[0], MODE_RW);
if (archive < 0)
{
int saved_errno = errno;
if (backup_option)
undo_last_backup ();
errno = saved_errno;
open_fatal (archive_name_array[0]);
}
xdup2 (archive, STDOUT_FILENO);
execlp (use_compress_program_option, use_compress_program_option,
(char *) 0);
exec_fatal (use_compress_program_option);
}
/* We do need a grandchild tar. */
xpipe (child_pipe);
grandchild_pid = xfork ();
if (grandchild_pid == 0)
{
/* The newborn grandchild tar is here! Launch the compressor. */
program_name = _("tar (grandchild)");
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
xclose (child_pipe[PREAD]);
execlp (use_compress_program_option, use_compress_program_option,
(char *) 0);
exec_fatal (use_compress_program_option);
}
/* The child tar is still here! */
/* Prepare for reblocking the data from the compressor into the archive. */
xdup2 (child_pipe[PREAD], STDIN_FILENO);
xclose (child_pipe[PWRITE]);
if (strcmp (archive_name_array[0], "-") == 0)
archive = STDOUT_FILENO;
else
{
archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
if (archive < 0)
open_fatal (archive_name_array[0]);
}
/* Let's read out of the stdin pipe and write an archive. */
while (1)
{
size_t status = 0;
char *cursor;
size_t length;
/* Assemble a record. */
for (length = 0, cursor = record_start->buffer;
length < record_size;
length += status, cursor += status)
{
size_t size = record_size - length;
status = safe_read (STDIN_FILENO, cursor, size);
if (status == SAFE_READ_ERROR)
read_fatal (use_compress_program_option);
if (status == 0)
break;
}
/* Copy the record. */
if (status == 0)
{
/* We hit the end of the file. Write last record at
full length, as the only role of the grandchild is
doing proper reblocking. */
if (length > 0)
{
memset (record_start->buffer + length, 0, record_size - length);
status = sys_write_archive_buffer ();
if (status != record_size)
archive_write_error (status);
}
/* There is nothing else to read, break out. */
break;
}
status = sys_write_archive_buffer ();
if (status != record_size)
archive_write_error (status);
}
/* Propagate any failure of the grandchild back to the parent. */
while (waitpid (grandchild_pid, &wait_status, 0) == -1)
if (errno != EINTR)
{
waitpid_error (use_compress_program_option);
break;
}
if (WIFSIGNALED (wait_status))
{
kill (child_pid, WTERMSIG (wait_status));
exit_status = TAREXIT_FAILURE;
}
else if (WEXITSTATUS (wait_status) != 0)
exit_status = WEXITSTATUS (wait_status);
exit (exit_status);
}
/* Set ARCHIVE for uncompressing, then reading an archive. */
pid_t
sys_child_open_for_uncompress (void)
{
int parent_pipe[2];
int child_pipe[2];
pid_t grandchild_pid;
pid_t child_pid;
int wait_status;
xpipe (parent_pipe);
child_pid = xfork ();
if (child_pid > 0)
{
/* The parent tar is still here! Just clean up. */
read_full_records_option = true;
archive = parent_pipe[PREAD];
xclose (parent_pipe[PWRITE]);
return child_pid;
}
/* The newborn child tar is here! */
program_name = _("tar (child)");
xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
xclose (parent_pipe[PREAD]);
/* Check if we need a grandchild tar. This happens only if either:
a) we're reading stdin: to force unblocking;
b) the file is to be accessed by rmt: compressor doesn't know how;
c) the file is not a plain file. */
if (strcmp (archive_name_array[0], "-") != 0
&& !_remdev (archive_name_array[0])
&& is_regular_file (archive_name_array[0]))
{
/* We don't need a grandchild tar. Open the archive and lauch the
uncompressor. */
archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
if (archive < 0)
open_fatal (archive_name_array[0]);
xdup2 (archive, STDIN_FILENO);
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
}
/* We do need a grandchild tar. */
xpipe (child_pipe);
grandchild_pid = xfork ();
if (grandchild_pid == 0)
{
/* The newborn grandchild tar is here! Launch the uncompressor. */
program_name = _("tar (grandchild)");
xdup2 (child_pipe[PREAD], STDIN_FILENO);
xclose (child_pipe[PWRITE]);
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
}
/* The child tar is still here! */
/* Prepare for unblocking the data from the archive into the
uncompressor. */
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
xclose (child_pipe[PREAD]);
if (strcmp (archive_name_array[0], "-") == 0)
archive = STDIN_FILENO;
else
archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
MODE_RW, rsh_command_option);
if (archive < 0)
open_fatal (archive_name_array[0]);
/* Let's read the archive and pipe it into stdout. */
while (1)
{
char *cursor;
size_t maximum;
size_t count;
size_t status;
clear_read_error_count ();
error_loop:
status = rmtread (archive, record_start->buffer, record_size);
if (status == SAFE_READ_ERROR)
{
archive_read_error ();
goto error_loop;
}
if (status == 0)
break;
cursor = record_start->buffer;
maximum = status;
while (maximum)
{
count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
if (full_write (STDOUT_FILENO, cursor, count) != count)
write_error (use_compress_program_option);
cursor += count;
maximum -= count;
}
}
xclose (STDOUT_FILENO);
/* Propagate any failure of the grandchild back to the parent. */
while (waitpid (grandchild_pid, &wait_status, 0) == -1)
if (errno != EINTR)
{
waitpid_error (use_compress_program_option);
break;
}
if (WIFSIGNALED (wait_status))
{
kill (child_pid, WTERMSIG (wait_status));
exit_status = TAREXIT_FAILURE;
}
else if (WEXITSTATUS (wait_status) != 0)
exit_status = WEXITSTATUS (wait_status);
exit (exit_status);
}
#endif /* not MSDOS */

View File

@@ -1,7 +1,5 @@
/* System dependent definitions for GNU tar.
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003
Free Software Foundation, Inc.
Copyright (C) 1994, 1995, 1996, 1997 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
@@ -22,30 +20,50 @@
# include <config.h>
#endif
#include <alloca.h>
/* Declare alloca. AIX requires this to be the first thing in the file. */
#ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
# define __attribute__(Spec) /* empty */
#if __GNUC__
# define alloca __builtin_alloca
#else
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
#endif
#include <sys/types.h>
#include <ctype.h>
/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
as an argument to <ctype.h> macros like `isspace'. */
#if STDC_HEADERS
# define IN_CTYPE_DOMAIN(c) 1
/* Declare a generic pointer type. */
#if __STDC__ || defined(__TURBOC__)
# define voidstar void *
#else
# define IN_CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
# define voidstar char *
#endif
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
#define ISODIGIT(c) ((unsigned) (c) - '0' <= 7)
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
/* Declare ISASCII. */
#include <ctype.h>
#if STDC_HEADERS
# define ISASCII(Char) 1
#else
# ifdef isascii
# define ISASCII(Char) isascii (Char)
# else
# if HAVE_ISASCII
# define ISASCII(Char) isascii (Char)
# else
# define ISASCII(Char) 1
# endif
# endif
#endif
/* Declare string and memory handling routines. Take care that an ANSI
string.h and pre-ANSI memory.h might conflict, and that memory.h and
@@ -65,10 +83,10 @@
# define strrchr rindex
# endif
# ifndef memcpy
# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n)
# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
# endif
# ifndef memcmp
# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n)
# define memcmp(Src1, Src2, Num) bcmp (Src1, Src2, Num)
# endif
#endif
@@ -95,11 +113,11 @@ extern int errno;
#endif
#ifndef O_RDWR
# define O_RDWR 2 /* both are allowed */
#endif
#ifndef O_ACCMODE
# define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY)
#endif
/* The rest can be OR-ed in to the above: */
#ifndef O_NDELAY
# define O_NDELAY 4 /* don't block on opening devices */
#endif
#ifndef O_CREAT
# define O_CREAT 8 /* create file if needed */
#endif
@@ -108,38 +126,36 @@ extern int errno;
#endif
#ifndef O_TRUNC
# define O_TRUNC 32 /* truncate file on open */
#endif
#ifndef O_APPEND
# define O_APPEND 64 /* always write at end of file */
#endif
/* MS-DOG forever, with my love! */
#ifndef O_BINARY
# define O_BINARY 0
#endif
/* Emulate System V 3-argument open call */
#if EMUL_OPEN3
# define open open3
#endif
/* Declare file status routines and bits. */
#include <sys/stat.h>
#if !HAVE_LSTAT && !defined lstat
#ifndef S_ISLNK
# define lstat stat
#endif
#if STX_HIDDEN && !_LARGE_FILES /* AIX */
# ifdef stat
# undef stat
# endif
# define stat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN)
# ifdef lstat
# undef lstat
# endif
# define lstat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN | STX_LINK)
#endif
#if STAT_MACROS_BROKEN
# undef S_ISBLK
# undef S_ISCHR
# undef S_ISCTG
# undef S_ISDIR
# undef S_ISFIFO
# undef S_ISLNK
# undef S_ISMPB
# undef S_ISMPC
# undef S_ISNWK
# undef S_ISREG
# undef S_ISSOCK
#endif
@@ -151,131 +167,58 @@ extern int errno;
# define S_ISVTX 0
#endif
#ifndef S_ISDIR
#ifndef S_ISREG /* POSIX.1 stat stuff missing */
# define mode_t unsigned short
#endif
#if !defined(S_ISBLK) && defined(S_IFBLK)
# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
#endif
#if !defined(S_ISCHR) && defined(S_IFCHR)
# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
#endif
#if !defined(S_ISDIR) && defined(S_IFDIR)
# define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
#endif
#ifndef S_ISREG
#if !defined(S_ISREG) && defined(S_IFREG)
# define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISBLK
# ifdef S_IFBLK
# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
# else
# define S_ISBLK(Mode) 0
# endif
#if !defined(S_ISFIFO) && defined(S_IFIFO)
# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
#endif
#ifndef S_ISCHR
# ifdef S_IFCHR
# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
# else
# define S_ISCHR(Mode) 0
# endif
#if !defined(S_ISLNK) && defined(S_IFLNK)
# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
#endif
#ifndef S_ISCTG
# ifdef S_IFCTG
# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
# else
# define S_ISCTG(Mode) 0
# endif
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
#endif
#ifndef S_ISDOOR
# define S_ISDOOR(Mode) 0
#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
# define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
# define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
#endif
#ifndef S_ISFIFO
# ifdef S_IFIFO
# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
# else
# define S_ISFIFO(Mode) 0
# endif
#endif
#ifndef S_ISLNK
# ifdef S_IFLNK
# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
# else
# define S_ISLNK(Mode) 0
# endif
#endif
#ifndef S_ISSOCK
# ifdef S_IFSOCK
# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
# else
# define S_ISSOCK(Mode) 0
# endif
#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
# define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
#endif
#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO
#if !HAVE_MKFIFO
# define mkfifo(Path, Mode) (mknod (Path, (Mode) | S_IFIFO, 0))
#endif
#ifndef S_ISUID
# define S_ISUID 0004000
#if !defined(S_ISCTG) && defined(S_IFCTG) /* contiguous file */
# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
#endif
#ifndef S_ISGID
# define S_ISGID 0002000
#endif
#ifndef S_ISVTX
#if !defined(S_ISVTX)
# define S_ISVTX 0001000
#endif
#ifndef S_IRUSR
# define S_IRUSR 0000400
#endif
#ifndef S_IWUSR
# define S_IWUSR 0000200
#endif
#ifndef S_IXUSR
# define S_IXUSR 0000100
#endif
#ifndef S_IRGRP
# define S_IRGRP 0000040
#endif
#ifndef S_IWGRP
# define S_IWGRP 0000020
#endif
#ifndef S_IXGRP
# define S_IXGRP 0000010
#endif
#ifndef S_IROTH
# define S_IROTH 0000004
#endif
#ifndef S_IWOTH
# define S_IWOTH 0000002
#endif
#ifndef S_IXOTH
# define S_IXOTH 0000001
#endif
#define MODE_WXUSR (S_IWUSR | S_IXUSR)
#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH)
#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
#ifndef _POSIX_SOURCE
# include <sys/param.h>
#endif
/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
#ifndef SEEK_CUR
# define SEEK_CUR 1
#endif
#ifndef SEEK_END
# define SEEK_END 2
#endif
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
/* Declare make device, major and minor. Since major is a function on
SVR4, we have to resort to GOT_MAJOR instead of just testing if
major is #define'd. */
@@ -320,66 +263,122 @@ extern int errno;
#undef GOT_MAJOR
/* Declare directory reading routines and structures. */
#if __TURBOC__
# include "msd_dir.h"
# define NAMLEN(dirent) ((dirent)->d_namlen)
#else
# if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) (strlen((dirent)->d_name))
# else
# define dirent direct
# define NAMLEN(dirent) ((dirent)->d_namlen)
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
# endif
#endif
/* Declare wait status. */
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
#if HAVE_UNION_WAIT
# define WAIT_T union wait
# ifndef WTERMSIG
# define WTERMSIG(Status) ((Status).w_termsig)
# endif
# ifndef WCOREDUMP
# define WCOREDUMP(Status) ((Status).w_coredump)
# endif
# ifndef WEXITSTATUS
# define WEXITSTATUS(Status) ((Status).w_retcode)
# endif
#else
# define WAIT_T int
# ifndef WTERMSIG
# define WTERMSIG(Status) ((Status) & 0x7f)
# endif
# ifndef WCOREDUMP
# define WCOREDUMP(Status) ((Status) & 0x80)
# endif
# ifndef WEXITSTATUS
# define WEXITSTATUS(Status) (((Status) >> 8) & 0xff)
# endif
#endif
#ifndef WIFSTOPPED
# define WIFSTOPPED(Status) (WTERMSIG(Status) == 0x7f)
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff)
# define WIFSIGNALED(Status) (WTERMSIG(Status) != 0)
#endif
#ifndef WTERMSIG
# define WTERMSIG(s) ((s) & 0x7f)
#ifndef WIFEXITED
# define WIFEXITED(Status) (WTERMSIG(Status) == 0)
#endif
/* FIXME: It is wrong to use BLOCKSIZE for buffers when the logical block
size is greater than 512 bytes; so ST_BLKSIZE code below, in preparation
for some cleanup in this area, later. */
/* Get or fake the disk device blocksize. Usually defined by sys/param.h
(if at all). */
#if !defined(DEV_BSIZE) && defined(BSIZE)
# define DEV_BSIZE BSIZE
#endif
#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
# define DEV_BSIZE BBSIZE
#endif
#ifndef DEV_BSIZE
# define DEV_BSIZE 4096
#endif
/* Extract or fake data from a `struct stat'. ST_BLKSIZE gives the
optimal I/O blocksize for the file, in bytes. Some systems, like
Sequents, return st_blksize of 0 on pipes. */
#define DEFAULT_ST_BLKSIZE 512
#if !HAVE_ST_BLKSIZE
# define ST_BLKSIZE(Statbuf) DEFAULT_ST_BLKSIZE
# define ST_BLKSIZE(Statbuf) DEV_BSIZE
#else
# define ST_BLKSIZE(Statbuf) \
((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEFAULT_ST_BLKSIZE)
((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEV_BSIZE)
#endif
/* Extract or fake data from a `struct stat'. ST_NBLOCKS gives the
number of ST_NBLOCKSIZE-byte blocks in the file (including indirect blocks).
HP-UX counts st_blocks in 1024-byte units,
number of 512-byte blocks in the file (including indirect blocks).
fileblocks.c uses BSIZE. HP-UX counts st_blocks in 1024-byte units,
this loses when mixing HP-UX and BSD filesystems with NFS. AIX PS/2
counts st_blocks in 4K units. */
#if !HAVE_ST_BLOCKS
# if defined(_POSIX_SOURCE) || !defined(BSIZE)
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_size / ST_NBLOCKSIZE + ((Statbuf).st_size % ST_NBLOCKSIZE != 0))
# define ST_NBLOCKS(Statbuf) (((Statbuf).st_size + 512 - 1) / 512)
# else
off_t st_blocks ();
# define ST_NBLOCKS(Statbuf) (st_blocks ((Statbuf).st_size))
# endif
#else
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
# if defined(hpux) || defined(__hpux__) || defined(__hpux)
# define ST_NBLOCKSIZE 1024
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks * 2)
# else
# if defined(_AIX) && defined(_I386)
# define ST_NBLOCKSIZE (4 * 1024)
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks * 8)
# else
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
# endif
# endif
#endif
#ifndef ST_NBLOCKSIZE
#define ST_NBLOCKSIZE 512
#endif
/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses
<sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires
<sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It
@@ -393,9 +392,6 @@ extern int errno;
# if HAVE_SYS_DEVICE_H
# include <sys/device.h>
# endif
# if HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
# if HAVE_SYS_BUF_H
# include <sys/buf.h>
# endif
@@ -422,102 +418,75 @@ extern int errno;
#if STDC_HEADERS
# include <stdlib.h>
#else
void *malloc ();
voidstar malloc ();
voidstar realloc ();
# if HAVE_GETCWD
char *getcwd ();
# endif
char *getenv ();
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#if !defined _POSIX_VERSION && MSDOS
# include <io.h>
#ifndef _POSIX_VERSION
# if MSDOS
# include <io.h>
# else
off_t lseek ();
# endif
#endif
#include <pathmax.h>
#if WITH_DMALLOC
# undef HAVE_DECL_VALLOC
# undef HAVE_VALLOC
# define DMALLOC_FUNC_CHECK
# include <dmalloc.h>
#endif
#include <limits.h>
#ifndef MB_LEN_MAX
# define MB_LEN_MAX 1
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
/* These macros work even on ones'-complement hosts (!).
The extra casts work around common compiler bugs. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \
? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
: (t) 0)
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
/* Bound on length of the string representing an integer value of type t.
Subtract one for the sign bit if t is signed;
302 / 1000 is log10 (2) rounded up;
add one for integer division truncation;
add one more for a minus sign if t is signed. */
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
+ 1 + TYPE_SIGNED (t))
#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1)
/* Prototypes for external functions. */
#ifndef PARAMS
# if PROTOTYPES
# define PARAMS(Args) Args
# else
# define PARAMS(Args) ()
# endif
#endif
#if HAVE_LOCALE_H
# include <locale.h>
#endif
#if !HAVE_SETLOCALE
# define setlocale(Category, Locale) /* empty */
# define setlocale(Category, Locale)
#endif
#include <time.h>
#if defined(HAVE_SYS_TIME_H) && defined(TIME_WITH_SYS_TIME)
# include <sys/time.h>
#endif
#if ! HAVE_DECL_TIME
time_t time ();
#endif
#ifdef HAVE_UTIME_H
# include <utime.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
#else
# define bindtextdomain(Domain, Directory)
# define textdomain(Domain)
# define _(Text) Text
#endif
#define N_(Text) Text
/* Library modules. */
#include <dirname.h>
#include <error.h>
#include <savedir.h>
#include <unlocked-io.h>
#include <xalloc.h>
#include "error.h"
#include <gettext.h>
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
#if !HAVE_STRSTR
char *strstr PARAMS ((const char *, const char *));
#endif
#if ! defined valloc && ! HAVE_DECL_VALLOC
#if HAVE_VALLOC
# ifndef valloc
voidstar valloc PARAMS ((size_t));
# endif
#else
# define valloc(Size) malloc (Size)
#endif
#if MSDOS
# include <process.h>
# define SET_BINARY_MODE(arc) setmode(arc, O_BINARY)
# define ERRNO_IS_EACCES errno == EACCES
# define mkdir(file, mode) (mkdir) (file)
#else
# include <pwd.h>
# include <grp.h>
# define SET_BINARY_MODE(arc)
# define ERRNO_IS_EACCES 0
#endif
#if XENIX
# include <sys/inode.h>
#endif
voidstar xmalloc PARAMS ((size_t));
voidstar xrealloc PARAMS ((voidstar, size_t));
char *xstrdup PARAMS ((const char *));

566
src/tar.c

File diff suppressed because it is too large Load Diff

162
src/tar.h
View File

@@ -1,7 +1,7 @@
/* GNU tar Archive Format description.
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
2000, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 2000, 2001 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
@@ -17,6 +17,17 @@
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* If OLDGNU_COMPATIBILITY is not zero, tar produces archives which, by
default, are readable by older versions of GNU tar. This can be
overriden by using --posix; in this case, POSIXLY_CORRECT in environment
may be set for enforcing stricter conformance. If OLDGNU_COMPATIBILITY
is zero or undefined, tar will eventually produces archives which, by
default, POSIX compatible; then either using --posix or defining
POSIXLY_CORRECT enforces stricter conformance.
This #define will disappear in a few years. FP, June 1995. */
#define OLDGNU_COMPATIBILITY 1
/* tar Header Block, from POSIX 1003.1-1990. */
/* POSIX header. */
@@ -58,10 +69,6 @@ struct posix_header
#define FIFOTYPE '6' /* FIFO special */
#define CONTTYPE '7' /* reserved */
#define XHDTYPE 'x' /* Extended header referring to the
next file in the archive */
#define XGLTYPE 'g' /* Global extended header */
/* Bits used in the mode field, values in octal. */
#define TSUID 04000 /* set UID on execution */
#define TSGID 02000 /* set GID on execution */
@@ -115,6 +122,26 @@ struct sparse
#define SPARSES_IN_OLDGNU_HEADER 4
#define SPARSES_IN_SPARSE_HEADER 21
/* The GNU extra header contains some information GNU tar needs, but not
foreseen in POSIX header format. It is only used after a POSIX header
(and never with old GNU headers), and immediately follows this POSIX
header, when typeflag is a letter rather than a digit, so signaling a GNU
extension. */
struct extra_header
{ /* byte offset */
char atime[12]; /* 0 */
char ctime[12]; /* 12 */
char offset[12]; /* 24 */
char realsize[12]; /* 36 */
char longnames[4]; /* 48 */
char unused_pad1[68]; /* 52 */
struct sparse sp[SPARSES_IN_EXTRA_HEADER];
/* 120 */
char isextended; /* 504 */
/* 505 */
};
/* Extension header for sparse files, used immediately after the GNU extra
header, and used only if all sparse information cannot fit into that
extra header. There might even be many such extension headers, one after
@@ -139,17 +166,15 @@ struct sparse_header
struct oldgnu_header
{ /* byte offset */
char unused_pad1[345]; /* 0 */
char atime[12]; /* 345 Incr. archive: atime of the file */
char ctime[12]; /* 357 Incr. archive: ctime of the file */
char offset[12]; /* 369 Multivolume archive: the offset of
the start of this volume */
char longnames[4]; /* 381 Not used */
char atime[12]; /* 345 */
char ctime[12]; /* 357 */
char offset[12]; /* 369 */
char longnames[4]; /* 381 */
char unused_pad2; /* 385 */
struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
/* 386 */
char isextended; /* 482 Sparse file: Extension sparse header
follows */
char realsize[12]; /* 483 Sparse file: Real size*/
char isextended; /* 482 */
char realsize[12]; /* 483 */
/* 495 */
};
@@ -160,12 +185,7 @@ struct oldgnu_header
#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
/* The standards committee allows only capital A through capital Z for
user-defined expansion. Other letters in use include:
'A' Solaris Access Control List
'E' Solaris Extended Attribute File
'I' Inode only, as in 'star'
'X' POSIX 1003.1-2001 eXtended (VU version) */
user-defined expansion. */
/* This is a dir entry that contains the names of files that were in the
dir at the time the dump was made. */
@@ -189,57 +209,6 @@ struct oldgnu_header
/* This file is a tape/volume header. Ignore it on extraction. */
#define GNUTYPE_VOLHDR 'V'
/* J<>rg Schilling star header */
struct star_header
{ /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[131]; /* 345 */
char atime[12]; /* 476 */
char ctime[12]; /* 488 */
/* 500 */
};
#define SPARSES_IN_STAR_HEADER 4
#define SPARSES_IN_STAR_EXT_HEADER 21
struct star_in_header {
char fill[345]; /* 0 Everything that is before t_prefix */
char prefix[1]; /* 345 t_name prefix */
char fill2; /* 346 */
char fill3[8]; /* 347 */
char isextended; /* 355 */
struct sparse sp[SPARSES_IN_STAR_HEADER]; /* 356 */
char realsize[12]; /* 452 Actual size of the file */
char offset[12]; /* 464 Offset of multivolume contents */
char atime[12]; /* 476 */
char ctime[12]; /* 488 */
char mfill[8]; /* 500 */
char xmagic[4]; /* 508 "tar" */
};
struct star_ext_header {
struct sparse sp[SPARSES_IN_STAR_EXT_HEADER];
char isextended;
};
/* tar Header Block, overall structure. */
/* tar files are made in basic blocks of this size. */
@@ -250,62 +219,17 @@ enum archive_format
DEFAULT_FORMAT, /* format to be decided later */
V7_FORMAT, /* old V7 tar format */
OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
USTAR_FORMAT, /* POSIX.1-1988 (ustar) format */
POSIX_FORMAT, /* POSIX.1-2001 format */
STAR_FORMAT, /* Star format defined in 1994 */
GNU_FORMAT /* Same as OLDGNU_FORMAT with one exception:
see FIXME note for to_chars() function
(create.c:189) */
};
/* Information about a sparse file. */
struct sp_array
{
off_t offset;
size_t numbytes;
};
struct tar_stat_info
{
char *orig_file_name; /* name of file read from the archive header */
char *file_name; /* name of file for the current archive entry
after being normalized. */
int had_trailing_slash; /* nonzero if the current archive entry had a
trailing slash before it was normalized. */
char *link_name; /* name of link for the current archive entry. */
unsigned int devminor; /* device minor number */
unsigned int devmajor; /* device major number */
char *uname; /* user name of owner */
char *gname; /* group name of owner */
struct stat stat; /* regular filesystem stat */
/* Nanosecond parts of file timestamps (if available) */
unsigned long atime_nsec;
unsigned long mtime_nsec;
unsigned long ctime_nsec;
off_t archive_file_size; /* Size of file as stored in the archive.
Equals stat.st_size for non-sparse files */
bool is_sparse; /* Is the file sparse */
size_t sparse_map_avail; /* Index to the first unused element in
sparse_map array. Zero if the file is
not sparse */
size_t sparse_map_size; /* Size of the sparse map */
struct sp_array *sparse_map;
POSIX_FORMAT, /* restricted, pure POSIX format */
GNU_FORMAT /* POSIX format with GNU extensions */
};
union block
{
char buffer[BLOCKSIZE];
struct posix_header header;
struct star_header star_header;
struct extra_header extra_header;
struct oldgnu_header oldgnu_header;
struct sparse_header sparse_header;
struct star_in_header star_in_header;
struct star_ext_header star_ext_header;
};
/* End of Format description. */

View File

@@ -1,7 +1,7 @@
/* Update a tar archive.
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003,
2004 Free Software Foundation, Inc.
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 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
@@ -32,10 +32,8 @@ extern union block *current_block;
/* 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 record and
re-writing the current record (which has been changed).
FIXME: Either eliminate it or move it to common.h.
*/
bool time_to_start_writing;
re-writing the current record (which has been changed). */
int time_to_start_writing;
/* Pointer to where we started to write in the first record we write out.
This is used if we can't backspace the output and have to null out the
@@ -66,7 +64,7 @@ append_file (char *path)
{
union block *start = find_next_block ();
size_t buffer_size = available_space_after (start);
size_t status;
ssize_t status;
char buf[UINTMAX_STRSIZE_BOUND];
if (bytes_left < buffer_size)
@@ -78,14 +76,11 @@ append_file (char *path)
}
status = safe_read (handle, start->buffer, buffer_size);
if (status == SAFE_READ_ERROR)
if (status < 0)
read_fatal_details (path, stat_data.st_size - bytes_left,
buffer_size);
if (status == 0)
FATAL_ERROR ((0, 0,
ngettext ("%s: File shrank by %s byte",
"%s: File shrank by %s bytes",
bytes_left),
FATAL_ERROR ((0, 0, _("%s: File shrank by %s bytes"),
quotearg_colon (path),
STRINGIFY_BIGINT (bytes_left, buf)));
@@ -110,16 +105,14 @@ update_archive (void)
name_gather ();
open_archive (ACCESS_UPDATE);
xheader_write_global ();
while (!found_end)
{
enum read_header status = read_header (false);
enum read_header status = read_header (0);
switch (status)
{
case HEADER_STILL_UNREAD:
case HEADER_SUCCESS_EXTENDED:
abort ();
case HEADER_SUCCESS:
@@ -127,17 +120,16 @@ update_archive (void)
struct name *name;
if (subcommand_option == UPDATE_SUBCOMMAND
&& (name = name_scan (current_stat_info.file_name)) != NULL)
&& (name = name_scan (current_file_name), name))
{
struct stat s;
enum archive_format unused;
decode_header (current_header, &current_stat_info, &unused, 0);
decode_header (current_header, &current_stat, &unused, 0);
chdir_do (name->change_dir);
if (deref_stat (dereference_option,
current_stat_info.file_name, &s) == 0
&& s.st_mtime <= current_stat_info.stat.st_mtime)
add_avoided_name (current_stat_info.file_name);
if (deref_stat (dereference_option, current_file_name, &s) == 0
&& s.st_mtime <= current_stat.st_mtime)
add_avoided_name (current_file_name);
}
skip_member ();
break;
@@ -169,7 +161,6 @@ update_archive (void)
break;
case HEADER_END_OF_FILE:
case HEADER_SUCCESS_EXTENDED:
abort ();
}
break;
@@ -179,13 +170,13 @@ update_archive (void)
}
reset_eof ();
time_to_start_writing = true;
time_to_start_writing = 1;
output_start = current_block->buffer;
{
char *path;
while ((path = name_from_list ()) != NULL)
while (path = name_from_list (), path)
{
if (excluded_name (path))
continue;

View File

@@ -1,344 +0,0 @@
/* Charset handling for GNU tar.
Copyright (C) 2004 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. */
#include "system.h"
#include <quotearg.h>
#include "common.h"
#ifdef HAVE_ICONV_H
# include <iconv.h>
#endif
#ifndef ICONV_CONST
# define ICONV_CONST
#endif
#ifdef HAVE_LIBICONV
struct langtab
{
char const *lang; /* Language code */
char const *terr; /* Territory code */
char const *charset; /* Corresponding charset */
};
/* The list of language codes defined in ISO 639 with the corresponding
default character sets.
NOTES:
1) The list must be ordered by:
a) lang field in ascending order
b) terr field in descending order.
NULL fields are considered less than non-null ones.
2) Many entries have NULL charset fields. Please help fill them!
3) The "default" character set for a given language is a matter
of preference. Possibly the table should contain a *list* of
possible character sets.
4) LC_ALL "modifier" field is not taken into account */
static struct langtab langtab[] = {
{ "C", NULL, "ASCII"},
{ "POSIX", NULL, "ASCII" },
{ "aa", NULL, NULL}, /* Afar */
{ "ab", NULL, NULL}, /* Abkhazian */
{ "ae", NULL, NULL}, /* Avestan */
{ "af", NULL, "iso-8859-1"}, /* Afrikaans */
{ "am", NULL, "UTF-8"}, /* Amharic */
{ "ar", NULL, "iso-8859-6"}, /* Arabic */
{ "as", NULL, NULL}, /* Assamese */
{ "ay", NULL, "iso-8859-1"}, /* Aymara */
{ "az", NULL, NULL}, /* Azerbaijani */
{ "ba", NULL, NULL}, /* Bashkir */
{ "be", NULL, "UTF-8"}, /* Byelorussian; Belarusian */
{ "bg", NULL, "iso-8859-5"}, /* Bulgarian */
{ "bh", NULL, NULL}, /* Bihari */
{ "bi", NULL, NULL}, /* Bislama */
{ "bn", NULL, NULL}, /* Bengali; Bangla */
{ "bo", NULL, NULL}, /* Tibetan */
{ "br", NULL, "iso-8859-1"}, /* Breton: 1,5,8,9 */
{ "bs", NULL, NULL}, /* Bosnian */
{ "ca", NULL, "iso-8859-1"}, /* Catalan: 1,5,8,9 */
{ "ce", NULL, NULL}, /* Chechen */
{ "ch", NULL, NULL}, /* Chamorro */
{ "co", NULL, "iso-8859-1"}, /* Corsican */
{ "cs", NULL, "iso-8859-2"}, /* Czech */
{ "cu", NULL, NULL }, /* Church Slavic */
{ "cv", NULL, NULL}, /* Chuvash */
{ "cy", NULL, "iso-8859-1"}, /* Welsh */
{ "da", NULL, "iso-8859-1"}, /* Danish: 4-9 */
{ "de", NULL, "iso-8859-1"}, /* German */
{ "dz", NULL, NULL }, /* Dzongkha; Bhutani */
{ "el", NULL, "iso-8859-7"}, /* Greek */
{ "en", NULL, "iso-8859-1"}, /* English */
{ "eo", NULL, "iso-8859-3"}, /* Esperanto */
{ "es", NULL, "iso-8859-1"}, /* Spanish */
{ "et", NULL, "iso-8859-15"}, /* Estonian: 6,7,9 */
{ "eu", NULL, "iso-8859-1"}, /* Basque: 5,8,9 */
{ "fa", NULL, "UTF-8"}, /* Persian */
{ "fi", NULL, "iso-8859-15"}, /* Finnish */
{ "fj", NULL, NULL }, /* Fijian; Fiji */
{ "fo", NULL, "iso-8859-1"}, /* Faroese: 6,9 */
{ "fr", NULL, "iso-8859-1"}, /* French */
{ "fy", NULL, "iso-8859-1"}, /* Frisian */
{ "ga", NULL, "iso-8859-14"}, /* Irish */
{ "gd", NULL, "iso-8859-14" }, /* Scots; Gaelic */
{ "gl", NULL, NULL }, /* Gallegan; Galician */
{ "gn", NULL, NULL}, /* Guarani */
{ "gu", NULL, NULL}, /* Gujarati */
{ "gv", NULL, "iso-8859-14"}, /* Manx */
{ "ha", NULL, NULL }, /* Hausa (?) */
{ "he", NULL, "iso-8859-8" }, /* Hebrew */
{ "hi", NULL, NULL}, /* Hindi */
{ "ho", NULL, NULL}, /* Hiri Motu */
{ "hr", NULL, "iso-8859-2"}, /* Croatian: 10 */
{ "hu", NULL, "iso-8859-2"}, /* Hungarian */
{ "hy", NULL, NULL}, /* Armenian */
{ "hz", NULL, NULL}, /* Herero */
{ "id", NULL, "iso-8859-1"}, /* Indonesian (formerly in) */
{ "ia", NULL, NULL}, /* Interlingua */
{ "ie", NULL, NULL}, /* Interlingue */
{ "ik", NULL, NULL}, /* Inupiak */
{ "io", NULL, NULL}, /* Ido */
{ "is", NULL, "iso-8859-1"}, /* Icelandic */
{ "it", NULL, "iso-8859-1"}, /* Italian */
{ "iu", NULL, NULL}, /* Inuktitut */
{ "ja", NULL, "EUC-JP"}, /* Japanese */
{ "jv", NULL, NULL}, /* Javanese */
{ "ka", NULL, NULL}, /* Georgian */
{ "ki", NULL, NULL}, /* Kikuyu */
{ "kj", NULL, NULL}, /* Kuanyama */
{ "kk", NULL, NULL}, /* Kazakh */
{ "kl", NULL, "iso-8859-1"}, /* Kalaallisut; Greenlandic */
{ "km", NULL, NULL}, /* Khmer; Cambodian */
{ "kn", NULL, NULL}, /* Kannada */
{ "ko", NULL, "EUC-KR"}, /* Korean */
{ "ks", NULL, NULL}, /* Kashmiri */
{ "ku", NULL, NULL}, /* Kurdish */
{ "kv", NULL, NULL}, /* Komi */
{ "kw", NULL, "iso-8859-14"}, /* Cornish: 1,5,8 */
{ "ky", NULL, NULL}, /* Kirghiz */
{ "la", NULL, "iso-8859-1"}, /* Latin */
{ "lb", NULL, "iso-8859-1"}, /* Letzeburgesch */
{ "ln", NULL, NULL}, /* Lingala */
{ "lo", NULL, NULL}, /* Lao; Laotian */
{ "lt", NULL, "iso-8859-4"}, /* Lithuanian */
{ "lv", NULL, "iso-8859-4"}, /* Latvian; Lettish */
{ "mg", NULL, NULL}, /* Malagasy */
{ "mh", NULL, NULL}, /* Marshall */
{ "mi", NULL, NULL}, /* Maori */
{ "mk", NULL, NULL}, /* Macedonian */
{ "ml", NULL, NULL}, /* Malayalam */
{ "mn", NULL, NULL}, /* Mongolian */
{ "mo", NULL, "iso-8859-2"}, /* Moldavian */
{ "mr", NULL, NULL}, /* Marathi */
{ "ms", NULL, NULL}, /* Malay */
{ "mt", NULL, "iso-8859-3"}, /* Maltese */
{ "my", NULL, NULL}, /* Burmese */
{ "na", NULL, NULL}, /* Nauru */
{ "nb", NULL, "iso-8859-1"}, /* Norwegian Bokm<6B>l; Bokm@aa{}l */
{ "nd", NULL, NULL}, /* Ndebele, North */
{ "ne", NULL, NULL}, /* Nepali */
{ "ng", NULL, NULL}, /* Ndonga */
{ "nl", NULL, "iso-8859-1"}, /* Dutch: 5,9 */
{ "nn", NULL, "iso-8859-1"}, /* Norwegian Nynorsk */
{ "no", NULL, "iso-8859-1"}, /* Norwegian */
{ "nr", NULL, NULL}, /* Ndebele, South */
{ "nv", NULL, NULL}, /* Navajo */
{ "ny", NULL, NULL}, /* Chichewa; Nyanja */
{ "oc", NULL, NULL}, /* Occitan; Proven<65>al; Proven@,{c}al */
{ "om", NULL, NULL}, /* (Afan) Oromo */
{ "or", NULL, NULL}, /* Oriya */
{ "os", NULL, NULL}, /* Ossetian; Ossetic */
{ "pa", NULL, NULL}, /* Panjabi; Punjabi */
{ "pi", NULL, NULL}, /* Pali */
{ "pl", NULL, "iso-8859-2"}, /* Polish */
{ "ps", NULL, NULL}, /* Pashto, Pushto */
{ "pt", NULL, "iso-8859-1"}, /* Portuguese */
{ "qu", NULL, "iso-8859-1"}, /* Quechua */
{ "rm", NULL, "iso-8859-1"}, /* Rhaeto-Romance */
{ "rn", NULL, NULL }, /* Rundi; Kirundi */
{ "ro", NULL, "iso-8859-2"}, /* Romanian */
{ "ru", NULL, "koi8-r"}, /* Russian */
{ "rw", NULL, NULL}, /* Kinyarwanda */
{ "sa", NULL, NULL}, /* Sanskrit */
{ "sc", NULL, "iso-8859-1"}, /* Sardinian */
{ "sd", NULL, NULL}, /* Sindhi */
{ "se", NULL, "iso-8859-10"}, /* Northern Sami */
{ "sg", NULL, NULL}, /* Sango; Sangro */
{ "si", NULL, NULL}, /* Sinhalese */
{ "sk", NULL, "iso-8859-2"}, /* Slovak */
{ "sl", NULL, "iso-8859-1"}, /* Slovenian */
{ "sm", NULL, NULL}, /* Samoan */
{ "sn", NULL, NULL}, /* Shona */
{ "so", NULL, NULL}, /* Somali */
{ "sq", NULL, "iso-8859-1"}, /* Albanian: 2,5,8,9,10 */
{ "sr", NULL, "iso-8859-2"}, /* Serbian */
{ "ss", NULL, NULL}, /* Swati; Siswati */
{ "st", NULL, NULL}, /* Sesotho; Sotho, Southern */
{ "su", NULL, NULL}, /* Sundanese */
{ "sv", NULL, "iso-8859-1"}, /* Swedish */
{ "sw", NULL, NULL}, /* Swahili */
{ "ta", NULL, NULL}, /* Tamil */
{ "te", NULL, NULL}, /* Telugu */
{ "tg", NULL, NULL}, /* Tajik */
{ "th", NULL, "iso-8859-11"}, /* Thai */
{ "ti", NULL, NULL}, /* Tigrinya */
{ "tk", NULL, NULL}, /* Turkmen */
{ "tl", NULL, "iso-8859-1"}, /* Tagalog */
{ "tn", NULL, NULL}, /* Tswana; Setswana */
{ "to", NULL, NULL}, /* Tonga (?) */
{ "tr", NULL, "iso-8859-9"}, /* Turkish */
{ "ts", NULL, NULL}, /* Tsonga */
{ "tt", NULL, NULL}, /* Tatar */
{ "tw", NULL, NULL}, /* Twi */
{ "ty", NULL, NULL}, /* Tahitian */
{ "ug", NULL, NULL}, /* Uighur */
{ "uk", NULL, "koi8-u"}, /* Ukrainian */
{ "ur", NULL, NULL}, /* Urdu */
{ "uz", NULL, NULL}, /* Uzbek */
{ "vi", NULL, NULL}, /* Vietnamese */
{ "vo", NULL, NULL}, /* Volap<61>k; Volap@"{u}k; Volapuk */
{ "wa", NULL, "iso-8859-1"}, /* Walloon */
{ "wo", NULL, NULL}, /* Wolof */
{ "xh", NULL, NULL}, /* Xhosa */
{ "yi", NULL, "iso-8859-8"}, /* Yiddish (formerly ji) */
{ "yo", NULL, NULL}, /* Yoruba */
{ "za", NULL, NULL}, /* Zhuang */
{ "zh", "TW", "big5"}, /* Chinese */
{ "zh", NULL, "gb2312"}, /* Chinese */
{ "zu", NULL, NULL}, /* Zulu */
{ NULL, NULL, NULL}
};
/* Given the language and (optionally) territory code, return the
default character set for that language. See notes above. */
static char const *
charset_lookup (char const *lang, char const *terr)
{
struct langtab const *p;
if (!lang)
return NULL;
for (p = langtab; p->lang; p++)
if (strcasecmp (p->lang, lang) == 0
&& (terr == NULL
|| p->terr == NULL
|| !strcasecmp (p->terr, terr) == 0))
return p->charset;
return NULL;
}
static const char *
get_input_charset (void)
{
const char *charset = NULL;
char *tmp;
/* Try to deduce the charset from LC_ALL or LANG variables */
tmp = getenv ("LC_ALL");
if (!tmp)
tmp = getenv ("LANG");
if (tmp)
{
char *lang;
char *terr;
lang = strtok (tmp, "_");
terr = strtok (NULL, ".");
charset = strtok (NULL, "@");
if (!charset)
charset = charset_lookup (lang, terr);
}
if (!charset)
charset = "iso-8859-1";
return charset;
}
#else /* !defined HAVE_LIBICONV */
# undef iconv_open
# define iconv_open(tocode, fromcode) ((iconv_t) -1)
# undef iconv
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ((size_t) 0)
# undef iconv_close
# define iconv_close(cd) 0
#endif /* !defined HAVE_LIBICONV */
static iconv_t conv_desc[2] = { (iconv_t) -1, (iconv_t) -1 };
static iconv_t
utf8_init (bool to_utf)
{
if (conv_desc[(int) to_utf] == (iconv_t) -1)
{
if (to_utf)
conv_desc[(int) to_utf] = iconv_open ("UTF-8", get_input_charset ());
else
conv_desc[(int) to_utf] = iconv_open (get_input_charset (), "UTF-8");
}
return conv_desc[(int) to_utf];
}
bool
utf8_convert (bool to_utf, char const *input, char **output)
{
char ICONV_CONST *ib;
char *ob;
size_t inlen;
size_t outlen;
size_t rc;
iconv_t cd = utf8_init (to_utf);
if (cd == 0)
{
*output = xstrdup (input);
return true;
}
else if (cd == (iconv_t)-1)
return false;
inlen = strlen (input) + 1;
outlen = inlen * MB_LEN_MAX + 1;
ob = *output = xmalloc (outlen);
ib = (char ICONV_CONST *) input;
rc = iconv (cd, &ib, &inlen, &ob, &outlen);
*ob = 0;
return rc != -1;
}
bool
string_ascii_p (const char *str)
{
const unsigned char *p = (const unsigned char *)str;
for (; *p; p++)
if (*p > 127)
return false;
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
Makefile.in
Makefile
preset
.deps
genfile
mksparse
tmp-*
directory
archive

View File

@@ -1,71 +1,41 @@
# Makefile for GNU tar regression tests.
# Copyright <20> 1996, 1997 Free Software Foundation, Inc.
# Fran<61>ois Pinard <pinard@iro.umontreal.ca>, 1988.
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003 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.
# François Pinard <pinard@iro.umontreal.ca>, 1988.
# 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.
## 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.
# 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.
## 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.
check_PROGRAMS = genfile mksparse
AUTOMAKE_OPTIONS = gnits ../src/ansi2knr
check_PROGRAMS = genfile
BUILT_SOURCES = preset
TESTS = \
version.sh\
append.sh\
delete01.sh\
delete02.sh\
delete03.sh\
delete04.sh\
extrac01.sh\
extrac02.sh\
extrac03.sh\
extrac04.sh\
gzip.sh\
incremen.sh\
ignfail.sh\
listed01.sh\
longv7.sh\
multiv01.sh\
multiv02.sh\
old.sh\
options.sh\
same-order01.sh\
same-order02.sh\
volume.sh\
recurse.sh\
sparse01.sh\
star/gtarfail.sh\
star/gtarfail2.sh\
star/multi-fail.sh\
star/ustar-big-2g.sh\
star/ustar-big-8g.sh\
star/pax-big-10g.sh\
star/qucktest.sh
TESTS = version.sh ignfail.sh extrac01.sh extrac02.sh extrac03.sh \
old.sh volume.sh gzip.sh append.sh delete01.sh incremen.sh
# Postponed until after the 1.12 release.
POSTPONED_TESTS = delete02.sh
genfile_SOURCES = genfile.c
mksparse_SOURCES = mksparse.c
EXTRA_DIST = after before preset.in $(TESTS) star/README
EXTRA_DIST = after before preset.in $(TESTS) $(POSTPONED_TESTS)
localedir = $(datadir)/locale
INCLUDES = -I$(top_srcdir)/lib -I../lib -I$(top_srcdir)/src
LDADD = ../lib/libtar.a $(LIBINTL)
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
INCLUDES = -I.. -I../intl -I$(top_srcdir)/src -I$(top_srcdir)/lib
LDADD = ../lib/libtar.a @INTLLIBS@
localedir = $(prefix)/@DATADIRNAME@/locale
mostlyclean:
rm -rf tmp-*
$(TESTS): genfile mksparse
$(TESTS): genfile

View File

@@ -1,55 +1,9 @@
#! /bin/sh
# Do common operations after a particular test.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
cd ..
exec 1> /dev/null
exec 2> /dev/null
compare() {
eval tempfile=tmp-$$/std${1}
eval echo \""\${$1}"\" | sed '$d' > ${tempfile}0
sedscript=tmp-$$/${1}.sed
if eval test \".\${${1}_ignore}\" = .; then
:
else
eval echo \"\${${1}_ignore}\" | sed 's,^.*$,/&/d,;' > $sedscript
sed -f $sedscript ${tempfile} > ${tempfile}.1
mv ${tempfile}.1 ${tempfile}
fi
if eval test -z \"\${${1}_regex}\" ; then
cmp -s ${tempfile}0 ${tempfile} || exit 1
else
awk '{print NR " " $0}' ${tempfile}0 > ${tempfile}.1
awk '{print NR " " $0}' ${tempfile} | join ${tempfile}.1 - |
while read NUM RE LINE
do
echo "$LINE" | grep -- "$RE" >/dev/null || exit 1
done
fi
}
compare out
compare err
echo $echo_n "$out$echo_c" | cmp -s - tmp-$$/stdout || exit 1
echo $echo_n "$err$echo_c" | cmp -s - tmp-$$/stderr || exit 1
rm -rf tmp-$$

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# Append was just not working.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before

View File

@@ -1,53 +1,19 @@
#! /bin/sh
# Do common operations before a particular test.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
case $# in
0) TAR_ARCHIVE_FORMATS="${TAR_ARCHIVE_FORMATS:-v7 oldgnu ustar posix gnu}"
for format in $TAR_ARCHIVE_FORMATS
do
$0 $format
R=$?
test $R -eq 0 || exit $R
done
exit 0;;
1) if test "x$1" = xauto; then
TAR_OPTIONS=
else
TAR_OPTIONS="--format=$1"
fi;;
*) echo "Too many arguments" >&2
exit 2;;
esac
mkdir tmp-$$
cd tmp-$$
case $srcdir in
/*|~*) ;;
*) srcdir=../$srcdir ;;
esac
out=
err=
export TAR_OPTIONS
#echo "$0 $1"
echo "$0 $1" > checking
echo $0 > checking
exec 1> stdout
exec 2> stderr
PATH=..:../../src:$PATH

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# Deleting a member after a big one was destroying the archive.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# Deleting a member with the archive from stdin was not working correctly.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before
@@ -31,7 +12,7 @@ tar cf archive 1 2 3
tar tf archive
cat archive | tar f - --delete 2 > archive2
echo -----
tar tf archive2
tar tf archive
out="\
1

View File

@@ -19,8 +19,7 @@
# 02111-1307, USA.
. ./preset
TAR_ARCHIVE_FORMATS="gnu oldgnu posix"
. $srcdir/before
. $srcdir/before
set -e
prefix=This_is_a_very_long_file_name_prefix_that_is_designed_to_cause_problems_with_file_names_that_run_into_a_limit_of_the_posix_tar_formatXX

View File

@@ -1,53 +0,0 @@
#! /bin/sh
# Deleting a large last member was destroying earlier members.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before
set -e
genfile -l 3 >file1
genfile -l 5 >file2
genfile -l 3 >file3
genfile -l 6 >file4
genfile -l 24 >file5
genfile -l 13 >file6
genfile -l 1385 >file7
genfile -l 30 >file8
genfile -l 10 >file9
genfile -l 256000 >file10
tar cf archive file1 file2 file3 file4 file5 file6 file7 file8 file9 file10
tar f archive --delete file10
tar tf archive
out="\
file1
file2
file3
file4
file5
file6
file7
file8
file9
"
. $srcdir/after

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# There was a diagnostic when directory already exists.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# Could not extract symlinks over an existing file.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before

View File

@@ -1,33 +1,14 @@
#! /bin/sh
# Paths going up and down were inducing extraction loops.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before
set -e
mkdir directory
tar -cPvf archive directory/../directory
tar cfv archive directory/../directory
echo -----
tar -xPvf archive
tar xfv archive
out="\
directory/../directory/

View File

@@ -1,25 +1,6 @@
#! /bin/sh
# Check for fnmatch problems in glibc 2.1.95.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before

View File

@@ -1,9 +1,6 @@
/* Generate a file containing some preset patterns.
Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004 Free Software
Foundation, Inc.
François Pinard <pinard@iro.umontreal.ca>, 1995.
Copyright <20> 1995, 1996, 1997 Free Software Foundation, Inc.
Fran<EFBFBD>ois Pinard <pinard@iro.umontreal.ca>, 1995.
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
@@ -22,7 +19,6 @@
#include "system.h"
#include <argmatch.h>
#include <getopt.h>
#ifndef EXIT_SUCCESS
@@ -34,8 +30,8 @@
enum pattern
{
DEFAULT_PATTERN,
ZEROS_PATTERN
DEFAULT,
ZEROS
};
/* The name this program was run with. */
@@ -51,11 +47,13 @@ static int show_version = 0;
static int file_length = 0;
/* Pattern to generate. */
static enum pattern pattern = DEFAULT_PATTERN;
static enum pattern pattern = DEFAULT;
/* Explain how to use the program, then get out. */
static void usage (int) __attribute__ ((noreturn));
static void
/*-----------------------------------------------.
| Explain how to use the program, then get out. |
`-----------------------------------------------*/
void
usage (int status)
{
if (status != EXIT_SUCCESS)
@@ -80,8 +78,10 @@ for the equivalent short option also.\n\
exit (status);
}
/* Main program. Decode ARGC arguments passed through the ARGV array
of strings, then launch execution. */
/*----------------------------------------------------------------------.
| Main program. Decode ARGC arguments passed through the ARGV array of |
| strings, then launch execution. |
`----------------------------------------------------------------------*/
/* Long options equivalences. */
static const struct option long_options[] =
@@ -93,8 +93,13 @@ static const struct option long_options[] =
{0, 0, 0, 0},
};
static char const * const pattern_args[] = { "default", "zeros", 0 };
static enum pattern const pattern_types[] = {DEFAULT_PATTERN, ZEROS_PATTERN};
const char *pattern_strings[] =
{
"default", /* 0 */
"zeros", /* 1 */
NULL
};
int
main (int argc, char *const *argv)
@@ -122,8 +127,25 @@ main (int argc, char *const *argv)
break;
case 'p':
pattern = XARGMATCH ("--pattern", optarg,
pattern_args, pattern_types);
switch (argmatch (optarg, pattern_strings))
{
case -2:
error (0, 0, _("Ambiguous pattern `%s'"), optarg);
usage (EXIT_FAILURE);
case -1:
error (0, 0, _("Unknown pattern `%s'"), optarg);
usage (EXIT_FAILURE);
case 0:
pattern = DEFAULT;
break;
case 1:
pattern = ZEROS;
break;
}
break;
}
@@ -132,17 +154,18 @@ main (int argc, char *const *argv)
if (show_version)
{
printf ("genfile (GNU %s) %s\n", PACKAGE, VERSION);
printf (_("Copyright (C) %d Free Software Foundation, Inc.\n"), 2003);
puts (_("\
This program comes with NO WARRANTY, to the extent permitted by law.\n\
You may redistribute it under the terms of the GNU General Public License;\n\
see the file named COPYING for details."));
/* Note to translator: Please translate "F. Pinard" to "François
Pinard" if "ç" (c-with-cedilla) is available in the
translation's character set and encoding. */
puts (_("Written by F. Pinard."));
fputs (_("\
\n\
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.\n"),
stdout);
fputs (_("\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"),
stdout);
fputs (_("\
\n\
Written by Fran<61>ois Pinard <pinard@iro.umontreal.ca>.\n"),
stdout);
exit (EXIT_SUCCESS);
}
@@ -156,12 +179,12 @@ see the file named COPYING for details."));
switch (pattern)
{
case DEFAULT_PATTERN:
case DEFAULT:
for (counter = 0; counter < file_length; counter++)
putchar (counter & 255);
break;
case ZEROS_PATTERN:
case ZEROS:
for (counter = 0; counter < file_length; counter++)
putchar (0);
break;

View File

@@ -1,27 +1,7 @@
#! /bin/sh
# tar should detect that its gzip child failed.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
TAR_ARCHIVE_FORMATS=auto
. $srcdir/before
tar xfvz /dev/null

View File

@@ -1,34 +1,12 @@
#! /bin/sh
# Unreadable directories yielded error despite --ignore-failed-read.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
. $srcdir/before
> check-uid
set - x`ls -l check-uid`
uid_name="$3"
set - x`ls -ln check-uid`
uid_number="$3"
if test "$uid_name" = root || test "$uid_number" = 0; then
if test $3 = root; then
# The test is meaningless for super-user.
rm check-uid
@@ -69,15 +47,15 @@ else
err="\
-----
tar: file: Cannot open: Permission denied
tar: Cannot add file file: Permission denied
tar: Error exit delayed from previous errors
-----
tar: file: Warning: Cannot open: Permission denied
tar: Cannot add file file: Permission denied
-----
tar: directory: Cannot savedir: Permission denied
tar: Cannot add directory directory: Permission denied
tar: Error exit delayed from previous errors
-----
tar: directory: Warning: Cannot savedir: Permission denied
tar: Cannot add directory directory: Permission denied
"
fi

View File

@@ -1,52 +1,18 @@
#! /bin/sh
# A directory older than the listed entry was skipped completely.
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
TAR_ARCHIVE_FORMATS="gnu oldgnu"
. $srcdir/before
set -e
mkdir structure
echo x >structure/file
# On Nextstep (and perhaps other 4.3BSD systems),
# a newly created file's ctime isn't updated
# until the next sync or stat operation on the file.
ls -l structure/file >/dev/null
# If the time of an initial backup and the creation time of a file contained
# in that backup are the same, the file will be backed up again when an
# incremental backup is done, because the incremental backup backs up
# files created `on or after' the initial backup time. Without the sleep
# command, behaviour of tar becomes variable, depending whether the system
# clock ticked over to the next second between creating the file and
# backing it up.
touch structure/file
# FIXME: The sleep is necessary for the second tar to work. Exactly why?
sleep 1
tar cf archive --listed=list structure
tar cfv archive --listed=list structure
echo -----
sleep 1
echo y >structure/file
touch structure/file
tar cfv archive --listed=list structure
out="\

View File

@@ -1,57 +0,0 @@
#! /bin/sh
# Check if listed-incremental backups work for individual files.
# Script proposed by Andreas Schuldei <andreas@schuldei.org>
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
TAR_ARCHIVE_FORMATS="gnu oldgnu"
. $srcdir/before
mkdir directory
genfile --length 10240 --pattern zeros > directory/file1
# Let the things settle
sleep 1
tar --create \
--file=archive.1 \
--listed-incremental=listing \
directory/file*
tar tf archive.1
dd if=/dev/zero of=directory/file2 bs=1024 count=20 2>/dev/null
echo "separator"
tar --create \
--file=archive.2 \
--listed-incremental=listing \
directory/file*
tar tf archive.2
out="\
directory/file1
separator
directory/file2
"
. $srcdir/after

View File

@@ -1,47 +0,0 @@
#! /bin/sh
# Old format (V7) archives should not accept file names longer than
# 99 characters
# This file is part of GNU tar testsuite.
# Copyright (C) 2004 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.
. ./preset
TAR_ARCHIVE_FORMATS="v7"
. $srcdir/before
DIR=this_is_a_very_long_name_for_a_directory_which_causes_problems
FILE=this_is_a_very_long_file_name_which_raises_issues.c
mkdir $DIR
touch $DIR/$FILE
tar cf archive $DIR
echo separator
tar tf archive
err="\
tar: $DIR/$FILE: file name is too long (max 99); not dumped
tar: Error exit delayed from previous errors
"
out="\
separator
$DIR/
"
. $srcdir/after

View File

@@ -1,161 +0,0 @@
/* This file is part of GNU tar test suite
Copyright (C) 2004 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. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#include <string.h>
char *progname;
char *buffer;
size_t buffer_size;
static void die (char const *, ...) __attribute__ ((noreturn,
format (printf, 1, 2)));
static void
die (char const *fmt, ...)
{
va_list ap;
fprintf (stderr, "%s: ", progname);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
fprintf (stderr, "\n");
exit (1);
}
static void
mkhole (int fd, off_t displ)
{
if (lseek (fd, displ, SEEK_CUR) == -1)
{
perror ("lseek");
exit (1);
}
ftruncate (fd, lseek (fd, 0, SEEK_CUR));
}
static void
mksparse (int fd, off_t displ, char *marks)
{
for (; *marks; marks++)
{
memset (buffer, *marks, buffer_size);
if (write(fd, buffer, buffer_size) != buffer_size)
{
perror ("write");
exit (1);
}
if (lseek (fd, displ, SEEK_CUR) == -1)
{
perror ("lseek");
exit (1);
}
}
}
static void usage (void) __attribute__ ((noreturn));
static void
usage (void)
{
printf ("Usage: mksparse filename blocksize disp letters [disp letters...] [disp]\n");
exit (1);
}
static int
xlat_suffix (off_t *vp, char *p)
{
if (p[1])
return 1;
switch (p[0])
{
case 'g':
case 'G':
*vp *= 1024;
case 'm':
case 'M':
*vp *= 1024;
case 'k':
case 'K':
*vp *= 1024;
break;
default:
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int i;
int fd;
char *p;
off_t n;
progname = strrchr (argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
if (argc < 4)
usage ();
fd = open (argv[1], O_CREAT|O_TRUNC|O_RDWR, 0644);
if (fd < 0)
die ("cannot open %s", argv[1]);
n = strtoul (argv[2], &p, 0);
if (n <= 0 || (*p && xlat_suffix (&n, p)))
die ("Invalid buffer size: %s", argv[2]);
buffer_size = n;
buffer = malloc (buffer_size);
if (!buffer)
die ("Not enough memory");
for (i = 3; i < argc; i += 2)
{
off_t displ;
displ = strtoul (argv[i], &p, 0);
if (displ < 0 || (*p && xlat_suffix (&displ, p)))
die ("Invalid displacement: %s", argv[i]);
if (i == argc-1)
{
mkhole (fd, displ);
break;
}
else
mksparse (fd, displ, argv[i+1]);
}
close(fd);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More